diff --git a/core/.DS_Store b/core/.DS_Store new file mode 100644 index 0000000..7796e2e Binary files /dev/null and b/core/.DS_Store differ diff --git a/core/.core/CMakeFiles/CMakeDirectoryInformation.cmake b/core/.core/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000..18abf29 --- /dev/null +++ b/core/.core/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Relative path conversion top directories. +SET(CMAKE_RELATIVE_PATH_TOP_SOURCE "/Users/beau/Documents/workspace/OpenCV/opencv") +SET(CMAKE_RELATIVE_PATH_TOP_BINARY "/Users/beau/Documents/workspace/OpenCV/opencv") + +# Force unix paths in dependencies. +SET(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +SET(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +SET(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +SET(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +SET(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/core/.core/CMakeFiles/progress.marks b/core/.core/CMakeFiles/progress.marks new file mode 100644 index 0000000..573541a --- /dev/null +++ b/core/.core/CMakeFiles/progress.marks @@ -0,0 +1 @@ +0 diff --git a/core/.core/Makefile b/core/.core/Makefile new file mode 100644 index 0000000..163ef09 --- /dev/null +++ b/core/.core/Makefile @@ -0,0 +1,167 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." + /opt/local/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /opt/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: install/local +.PHONY : install/local/fast + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /opt/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: install/strip +.PHONY : install/strip/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\" \"main\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /opt/local/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_progress_start /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/.core/CMakeFiles/progress.marks + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/core/.core/all + $(CMAKE_COMMAND) -E cmake_progress_start /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/core/.core/clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/core/.core/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/core/.core/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... rebuild_cache" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/core/.core/cmake_install.cmake b/core/.core/cmake_install.cmake new file mode 100644 index 0000000..3f9fc96 --- /dev/null +++ b/core/.core/cmake_install.cmake @@ -0,0 +1,29 @@ +# Install script for directory: /Users/beau/Documents/workspace/OpenCV/opencv/modules/core + +# Set the install prefix +IF(NOT DEFINED CMAKE_INSTALL_PREFIX) + SET(CMAKE_INSTALL_PREFIX "/usr/local") +ENDIF(NOT DEFINED CMAKE_INSTALL_PREFIX) +STRING(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +IF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + IF(BUILD_TYPE) + STRING(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + ELSE(BUILD_TYPE) + SET(CMAKE_INSTALL_CONFIG_NAME "Release") + ENDIF(BUILD_TYPE) + MESSAGE(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +ENDIF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + +# Set the component getting installed. +IF(NOT CMAKE_INSTALL_COMPONENT) + IF(COMPONENT) + MESSAGE(STATUS "Install component: \"${COMPONENT}\"") + SET(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + ELSE(COMPONENT) + SET(CMAKE_INSTALL_COMPONENT) + ENDIF(COMPONENT) +ENDIF(NOT CMAKE_INSTALL_COMPONENT) + diff --git a/core/CMakeFiles/CMakeDirectoryInformation.cmake b/core/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000..18abf29 --- /dev/null +++ b/core/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Relative path conversion top directories. +SET(CMAKE_RELATIVE_PATH_TOP_SOURCE "/Users/beau/Documents/workspace/OpenCV/opencv") +SET(CMAKE_RELATIVE_PATH_TOP_BINARY "/Users/beau/Documents/workspace/OpenCV/opencv") + +# Force unix paths in dependencies. +SET(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +SET(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +SET(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +SET(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +SET(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/core/CMakeFiles/opencv_core.dir/DependInfo.cmake b/core/CMakeFiles/opencv_core.dir/DependInfo.cmake new file mode 100644 index 0000000..ce4b6bd --- /dev/null +++ b/core/CMakeFiles/opencv_core.dir/DependInfo.cmake @@ -0,0 +1,73 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/algorithm.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/alloc.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/arithm.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/array.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/cmdparser.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/convert.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/copy.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/datastructs.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/drawing.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/dxt.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/gpumat.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/lapack.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/mathfuncs.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/matmul.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/matop.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/matrix.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/opengl_interop.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/out.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/parallel.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/persistence.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/precomp.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/rand.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/stat.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/system.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/tables.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "Clang") + +# Preprocessor definitions for this target. +SET(CMAKE_TARGET_DEFINITIONS + "HAVE_CVCONFIG_H" + "HAVE_ALLOCA" + "HAVE_ALLOCA_H" + "HAVE_LIBPTHREAD" + "HAVE_UNISTD_H" + "CVAPI_EXPORTS" + ) + +# Pairs of files generated by the same build rule. +SET(CMAKE_MULTIPLE_OUTPUT_PAIRS + "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_core.2.4.dylib" "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_core.2.4.9.dylib" + "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_core.dylib" "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_core.2.4.9.dylib" + ) + + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + "/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib/CMakeFiles/zlib.dir/DependInfo.cmake" + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "modules/core/perf" + "modules/highgui/include" + "modules/ts/include" + "modules/core/include" + "modules/core" + "modules/core/src" + "modules/core/test" + "3rdparty/zlib" + "." + "/opt/local/include" + "/opt/local/include/eigen3" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/core/CMakeFiles/opencv_core.dir/build.make b/core/CMakeFiles/opencv_core.dir/build.make new file mode 100644 index 0000000..d4408fd --- /dev/null +++ b/core/CMakeFiles/opencv_core.dir/build.make @@ -0,0 +1,732 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# Include any dependencies generated for this target. +include modules/core/CMakeFiles/opencv_core.dir/depend.make + +# Include the progress variables for this target. +include modules/core/CMakeFiles/opencv_core.dir/progress.make + +# Include the compile flags for this target's objects. +include modules/core/CMakeFiles/opencv_core.dir/flags.make + +modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o: modules/core/src/algorithm.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/algorithm.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/algorithm.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/algorithm.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/algorithm.cpp > CMakeFiles/opencv_core.dir/src/algorithm.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/algorithm.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/algorithm.cpp -o CMakeFiles/opencv_core.dir/src/algorithm.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o: modules/core/src/alloc.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_2) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/alloc.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/alloc.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/alloc.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/alloc.cpp > CMakeFiles/opencv_core.dir/src/alloc.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/alloc.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/alloc.cpp -o CMakeFiles/opencv_core.dir/src/alloc.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o: modules/core/src/arithm.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_3) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/arithm.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/arithm.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/arithm.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/arithm.cpp > CMakeFiles/opencv_core.dir/src/arithm.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/arithm.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/arithm.cpp -o CMakeFiles/opencv_core.dir/src/arithm.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o: modules/core/src/array.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_4) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/array.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/array.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/array.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/array.cpp > CMakeFiles/opencv_core.dir/src/array.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/array.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/array.cpp -o CMakeFiles/opencv_core.dir/src/array.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o: modules/core/src/cmdparser.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_5) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/cmdparser.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/cmdparser.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/cmdparser.cpp > CMakeFiles/opencv_core.dir/src/cmdparser.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/cmdparser.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/cmdparser.cpp -o CMakeFiles/opencv_core.dir/src/cmdparser.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o: modules/core/src/convert.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_6) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/convert.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/convert.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/convert.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/convert.cpp > CMakeFiles/opencv_core.dir/src/convert.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/convert.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/convert.cpp -o CMakeFiles/opencv_core.dir/src/convert.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o: modules/core/src/copy.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_7) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/copy.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/copy.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/copy.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/copy.cpp > CMakeFiles/opencv_core.dir/src/copy.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/copy.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/copy.cpp -o CMakeFiles/opencv_core.dir/src/copy.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o: modules/core/src/datastructs.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_8) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/datastructs.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/datastructs.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/datastructs.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/datastructs.cpp > CMakeFiles/opencv_core.dir/src/datastructs.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/datastructs.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/datastructs.cpp -o CMakeFiles/opencv_core.dir/src/datastructs.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o: modules/core/src/drawing.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_9) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/drawing.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/drawing.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/drawing.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/drawing.cpp > CMakeFiles/opencv_core.dir/src/drawing.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/drawing.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/drawing.cpp -o CMakeFiles/opencv_core.dir/src/drawing.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o: modules/core/src/dxt.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_10) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/dxt.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/dxt.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/dxt.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/dxt.cpp > CMakeFiles/opencv_core.dir/src/dxt.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/dxt.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/dxt.cpp -o CMakeFiles/opencv_core.dir/src/dxt.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o: modules/core/src/gpumat.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_11) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/gpumat.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/gpumat.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/gpumat.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/gpumat.cpp > CMakeFiles/opencv_core.dir/src/gpumat.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/gpumat.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/gpumat.cpp -o CMakeFiles/opencv_core.dir/src/gpumat.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o: modules/core/src/lapack.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_12) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/lapack.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/lapack.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/lapack.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/lapack.cpp > CMakeFiles/opencv_core.dir/src/lapack.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/lapack.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/lapack.cpp -o CMakeFiles/opencv_core.dir/src/lapack.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o: modules/core/src/mathfuncs.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_13) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/mathfuncs.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/mathfuncs.cpp > CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/mathfuncs.cpp -o CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o: modules/core/src/matmul.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_14) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/matmul.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/matmul.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/matmul.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/matmul.cpp > CMakeFiles/opencv_core.dir/src/matmul.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/matmul.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/matmul.cpp -o CMakeFiles/opencv_core.dir/src/matmul.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o: modules/core/src/matop.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_15) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/matop.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/matop.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/matop.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/matop.cpp > CMakeFiles/opencv_core.dir/src/matop.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/matop.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/matop.cpp -o CMakeFiles/opencv_core.dir/src/matop.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o: modules/core/src/matrix.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_16) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/matrix.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/matrix.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/matrix.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/matrix.cpp > CMakeFiles/opencv_core.dir/src/matrix.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/matrix.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/matrix.cpp -o CMakeFiles/opencv_core.dir/src/matrix.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o: modules/core/src/opengl_interop.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_17) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/opengl_interop.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/opengl_interop.cpp > CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/opengl_interop.cpp -o CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o: modules/core/src/out.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_18) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/out.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/out.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/out.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/out.cpp > CMakeFiles/opencv_core.dir/src/out.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/out.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/out.cpp -o CMakeFiles/opencv_core.dir/src/out.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o: modules/core/src/parallel.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_19) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/parallel.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/parallel.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/parallel.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/parallel.cpp > CMakeFiles/opencv_core.dir/src/parallel.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/parallel.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/parallel.cpp -o CMakeFiles/opencv_core.dir/src/parallel.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o: modules/core/src/persistence.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_20) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/persistence.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/persistence.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/persistence.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/persistence.cpp > CMakeFiles/opencv_core.dir/src/persistence.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/persistence.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/persistence.cpp -o CMakeFiles/opencv_core.dir/src/persistence.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o: modules/core/src/precomp.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_21) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/precomp.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/precomp.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/precomp.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/precomp.cpp > CMakeFiles/opencv_core.dir/src/precomp.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/precomp.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/precomp.cpp -o CMakeFiles/opencv_core.dir/src/precomp.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o: modules/core/src/rand.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_22) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/rand.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/rand.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/rand.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/rand.cpp > CMakeFiles/opencv_core.dir/src/rand.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/rand.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/rand.cpp -o CMakeFiles/opencv_core.dir/src/rand.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o: modules/core/src/stat.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_23) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/stat.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/stat.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/stat.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/stat.cpp > CMakeFiles/opencv_core.dir/src/stat.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/stat.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/stat.cpp -o CMakeFiles/opencv_core.dir/src/stat.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o: modules/core/src/system.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_24) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/system.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/system.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/system.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/system.cpp > CMakeFiles/opencv_core.dir/src/system.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/system.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/system.cpp -o CMakeFiles/opencv_core.dir/src/system.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o + +modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o: modules/core/CMakeFiles/opencv_core.dir/flags.make +modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o: modules/core/src/tables.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_25) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_core.dir/src/tables.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/tables.cpp + +modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_core.dir/src/tables.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/tables.cpp > CMakeFiles/opencv_core.dir/src/tables.cpp.i + +modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_core.dir/src/tables.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src/tables.cpp -o CMakeFiles/opencv_core.dir/src/tables.cpp.s + +modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o.requires + +modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o.provides: modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_core.dir/build.make modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o.provides + +modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o.provides.build: modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o + +# Object files for target opencv_core +opencv_core_OBJECTS = \ +"CMakeFiles/opencv_core.dir/src/algorithm.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/alloc.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/arithm.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/array.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/convert.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/copy.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/datastructs.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/drawing.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/dxt.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/gpumat.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/lapack.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/matmul.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/matop.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/matrix.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/out.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/parallel.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/persistence.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/precomp.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/rand.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/stat.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/system.cpp.o" \ +"CMakeFiles/opencv_core.dir/src/tables.cpp.o" + +# External object files for target opencv_core +opencv_core_EXTERNAL_OBJECTS = + +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/build.make +lib/libopencv_core.2.4.9.dylib: 3rdparty/lib/libzlib.a +lib/libopencv_core.2.4.9.dylib: modules/core/CMakeFiles/opencv_core.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX shared library ../../lib/libopencv_core.dylib" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/opencv_core.dir/link.txt --verbose=$(VERBOSE) + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && $(CMAKE_COMMAND) -E cmake_symlink_library ../../lib/libopencv_core.2.4.9.dylib ../../lib/libopencv_core.2.4.dylib ../../lib/libopencv_core.dylib + +lib/libopencv_core.2.4.dylib: lib/libopencv_core.2.4.9.dylib + +lib/libopencv_core.dylib: lib/libopencv_core.2.4.9.dylib + +# Rule to build all files generated by this target. +modules/core/CMakeFiles/opencv_core.dir/build: lib/libopencv_core.dylib +.PHONY : modules/core/CMakeFiles/opencv_core.dir/build + +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/arithm.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/array.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/convert.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/copy.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/datastructs.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/drawing.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/dxt.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/gpumat.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/lapack.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/matmul.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/matop.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/matrix.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/out.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/parallel.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/persistence.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/precomp.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/rand.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/stat.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o.requires +modules/core/CMakeFiles/opencv_core.dir/requires: modules/core/CMakeFiles/opencv_core.dir/src/tables.cpp.o.requires +.PHONY : modules/core/CMakeFiles/opencv_core.dir/requires + +modules/core/CMakeFiles/opencv_core.dir/clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && $(CMAKE_COMMAND) -P CMakeFiles/opencv_core.dir/cmake_clean.cmake +.PHONY : modules/core/CMakeFiles/opencv_core.dir/clean + +modules/core/CMakeFiles/opencv_core.dir/depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/core /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/core /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : modules/core/CMakeFiles/opencv_core.dir/depend + diff --git a/core/CMakeFiles/opencv_core.dir/cmake_clean.cmake b/core/CMakeFiles/opencv_core.dir/cmake_clean.cmake new file mode 100644 index 0000000..8b4d6a0 --- /dev/null +++ b/core/CMakeFiles/opencv_core.dir/cmake_clean.cmake @@ -0,0 +1,36 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/opencv_core.dir/src/algorithm.cpp.o" + "CMakeFiles/opencv_core.dir/src/alloc.cpp.o" + "CMakeFiles/opencv_core.dir/src/arithm.cpp.o" + "CMakeFiles/opencv_core.dir/src/array.cpp.o" + "CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o" + "CMakeFiles/opencv_core.dir/src/convert.cpp.o" + "CMakeFiles/opencv_core.dir/src/copy.cpp.o" + "CMakeFiles/opencv_core.dir/src/datastructs.cpp.o" + "CMakeFiles/opencv_core.dir/src/drawing.cpp.o" + "CMakeFiles/opencv_core.dir/src/dxt.cpp.o" + "CMakeFiles/opencv_core.dir/src/gpumat.cpp.o" + "CMakeFiles/opencv_core.dir/src/lapack.cpp.o" + "CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o" + "CMakeFiles/opencv_core.dir/src/matmul.cpp.o" + "CMakeFiles/opencv_core.dir/src/matop.cpp.o" + "CMakeFiles/opencv_core.dir/src/matrix.cpp.o" + "CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o" + "CMakeFiles/opencv_core.dir/src/out.cpp.o" + "CMakeFiles/opencv_core.dir/src/parallel.cpp.o" + "CMakeFiles/opencv_core.dir/src/persistence.cpp.o" + "CMakeFiles/opencv_core.dir/src/precomp.cpp.o" + "CMakeFiles/opencv_core.dir/src/rand.cpp.o" + "CMakeFiles/opencv_core.dir/src/stat.cpp.o" + "CMakeFiles/opencv_core.dir/src/system.cpp.o" + "CMakeFiles/opencv_core.dir/src/tables.cpp.o" + "../../lib/libopencv_core.pdb" + "../../lib/libopencv_core.dylib" + "../../lib/libopencv_core.2.4.9.dylib" + "../../lib/libopencv_core.2.4.dylib" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/opencv_core.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/core/CMakeFiles/opencv_core.dir/depend.make b/core/CMakeFiles/opencv_core.dir/depend.make new file mode 100644 index 0000000..188f02a --- /dev/null +++ b/core/CMakeFiles/opencv_core.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for opencv_core. +# This may be replaced when dependencies are built. diff --git a/core/CMakeFiles/opencv_core.dir/flags.make b/core/CMakeFiles/opencv_core.dir/flags.make new file mode 100644 index 0000000..f8fc8a3 --- /dev/null +++ b/core/CMakeFiles/opencv_core.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -O3 -DNDEBUG -fPIC -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib -I/Users/beau/Documents/workspace/OpenCV/opencv -I/opt/local/include -I/opt/local/include/eigen3 + +CXX_DEFINES = -Dopencv_core_EXPORTS -DHAVE_CVCONFIG_H -DHAVE_ALLOCA -DHAVE_ALLOCA_H -DHAVE_LIBPTHREAD -DHAVE_UNISTD_H -DCVAPI_EXPORTS + diff --git a/core/CMakeFiles/opencv_core.dir/link.txt b/core/CMakeFiles/opencv_core.dir/link.txt new file mode 100644 index 0000000..d2bd2b0 --- /dev/null +++ b/core/CMakeFiles/opencv_core.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -O3 -DNDEBUG -shared -compatibility_version 2.4.0 -current_version 2.4.9 -o ../../lib/libopencv_core.2.4.9.dylib -install_name /Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_core.2.4.dylib CMakeFiles/opencv_core.dir/src/algorithm.cpp.o CMakeFiles/opencv_core.dir/src/alloc.cpp.o CMakeFiles/opencv_core.dir/src/arithm.cpp.o CMakeFiles/opencv_core.dir/src/array.cpp.o CMakeFiles/opencv_core.dir/src/cmdparser.cpp.o CMakeFiles/opencv_core.dir/src/convert.cpp.o CMakeFiles/opencv_core.dir/src/copy.cpp.o CMakeFiles/opencv_core.dir/src/datastructs.cpp.o CMakeFiles/opencv_core.dir/src/drawing.cpp.o CMakeFiles/opencv_core.dir/src/dxt.cpp.o CMakeFiles/opencv_core.dir/src/gpumat.cpp.o CMakeFiles/opencv_core.dir/src/lapack.cpp.o CMakeFiles/opencv_core.dir/src/mathfuncs.cpp.o CMakeFiles/opencv_core.dir/src/matmul.cpp.o CMakeFiles/opencv_core.dir/src/matop.cpp.o CMakeFiles/opencv_core.dir/src/matrix.cpp.o CMakeFiles/opencv_core.dir/src/opengl_interop.cpp.o CMakeFiles/opencv_core.dir/src/out.cpp.o CMakeFiles/opencv_core.dir/src/parallel.cpp.o CMakeFiles/opencv_core.dir/src/persistence.cpp.o CMakeFiles/opencv_core.dir/src/precomp.cpp.o CMakeFiles/opencv_core.dir/src/rand.cpp.o CMakeFiles/opencv_core.dir/src/stat.cpp.o CMakeFiles/opencv_core.dir/src/system.cpp.o CMakeFiles/opencv_core.dir/src/tables.cpp.o -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib/gcc -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib ../../3rdparty/lib/libzlib.a diff --git a/core/CMakeFiles/opencv_core.dir/progress.make b/core/CMakeFiles/opencv_core.dir/progress.make new file mode 100644 index 0000000..cfdfd33 --- /dev/null +++ b/core/CMakeFiles/opencv_core.dir/progress.make @@ -0,0 +1,26 @@ +CMAKE_PROGRESS_1 = +CMAKE_PROGRESS_2 = +CMAKE_PROGRESS_3 = 24 +CMAKE_PROGRESS_4 = +CMAKE_PROGRESS_5 = +CMAKE_PROGRESS_6 = +CMAKE_PROGRESS_7 = +CMAKE_PROGRESS_8 = +CMAKE_PROGRESS_9 = +CMAKE_PROGRESS_10 = 25 +CMAKE_PROGRESS_11 = +CMAKE_PROGRESS_12 = +CMAKE_PROGRESS_13 = +CMAKE_PROGRESS_14 = +CMAKE_PROGRESS_15 = +CMAKE_PROGRESS_16 = +CMAKE_PROGRESS_17 = +CMAKE_PROGRESS_18 = 26 +CMAKE_PROGRESS_19 = +CMAKE_PROGRESS_20 = +CMAKE_PROGRESS_21 = +CMAKE_PROGRESS_22 = +CMAKE_PROGRESS_23 = +CMAKE_PROGRESS_24 = +CMAKE_PROGRESS_25 = + diff --git a/core/CMakeFiles/opencv_perf_core.dir/DependInfo.cmake b/core/CMakeFiles/opencv_perf_core.dir/DependInfo.cmake new file mode 100644 index 0000000..20bfe7e --- /dev/null +++ b/core/CMakeFiles/opencv_perf_core.dir/DependInfo.cmake @@ -0,0 +1,63 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_abs.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_addWeighted.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_arithm.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_bitwise.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_compare.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_convertTo.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_dft.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_dot.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_inRange.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_main.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_mat.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_math.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_merge.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_minmaxloc.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_norm.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_precomp.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_reduce.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_split.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_stat.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "Clang") + +# Preprocessor definitions for this target. +SET(CMAKE_TARGET_DEFINITIONS + "HAVE_CVCONFIG_H" + "HAVE_ALLOCA" + "HAVE_ALLOCA_H" + "HAVE_LIBPTHREAD" + "HAVE_UNISTD_H" + "CVAPI_EXPORTS" + ) + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/CMakeFiles/opencv_ts.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib/CMakeFiles/zlib.dir/DependInfo.cmake" + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "modules/core/perf" + "modules/highgui/include" + "modules/ts/include" + "modules/core/include" + "modules/core" + "modules/core/src" + "modules/core/test" + "3rdparty/zlib" + "." + "/opt/local/include" + "/opt/local/include/eigen3" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/core/CMakeFiles/opencv_perf_core.dir/build.make b/core/CMakeFiles/opencv_perf_core.dir/build.make new file mode 100644 index 0000000..e622b3a --- /dev/null +++ b/core/CMakeFiles/opencv_perf_core.dir/build.make @@ -0,0 +1,575 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# Include any dependencies generated for this target. +include modules/core/CMakeFiles/opencv_perf_core.dir/depend.make + +# Include the progress variables for this target. +include modules/core/CMakeFiles/opencv_perf_core.dir/progress.make + +# Include the compile flags for this target's objects. +include modules/core/CMakeFiles/opencv_perf_core.dir/flags.make + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o: modules/core/perf/perf_abs.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_abs.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_abs.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_abs.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o: modules/core/perf/perf_addWeighted.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_2) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_addWeighted.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_addWeighted.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_addWeighted.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o: modules/core/perf/perf_arithm.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_3) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_arithm.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_arithm.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_arithm.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o: modules/core/perf/perf_bitwise.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_4) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_bitwise.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_bitwise.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_bitwise.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o: modules/core/perf/perf_compare.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_5) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_compare.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_compare.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_compare.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o: modules/core/perf/perf_convertTo.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_6) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_convertTo.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_convertTo.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_convertTo.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o: modules/core/perf/perf_dft.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_7) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_dft.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_dft.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_dft.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o: modules/core/perf/perf_dot.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_8) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_dot.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_dot.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_dot.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o: modules/core/perf/perf_inRange.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_9) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_inRange.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_inRange.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_inRange.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o: modules/core/perf/perf_main.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_10) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_main.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_main.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_main.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o: modules/core/perf/perf_mat.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_11) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_mat.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_mat.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_mat.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o: modules/core/perf/perf_math.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_12) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_math.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_math.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_math.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o: modules/core/perf/perf_merge.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_13) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_merge.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_merge.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_merge.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o: modules/core/perf/perf_minmaxloc.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_14) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_minmaxloc.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_minmaxloc.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_minmaxloc.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o: modules/core/perf/perf_norm.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_15) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_norm.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_norm.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_norm.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o: modules/core/perf/perf_precomp.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_16) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_precomp.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_precomp.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_precomp.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o: modules/core/perf/perf_reduce.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_17) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_reduce.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_reduce.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_reduce.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o: modules/core/perf/perf_split.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_18) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_split.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_split.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_split.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o: modules/core/CMakeFiles/opencv_perf_core.dir/flags.make +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o: modules/core/perf/perf_stat.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_19) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_stat.cpp + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_stat.cpp > CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.i + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf/perf_stat.cpp -o CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.s + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o.requires + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o.provides: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_perf_core.dir/build.make modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o.provides + +modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o.provides.build: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o + +# Object files for target opencv_perf_core +opencv_perf_core_OBJECTS = \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o" \ +"CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o" + +# External object files for target opencv_perf_core +opencv_perf_core_EXTERNAL_OBJECTS = + +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/build.make +bin/opencv_perf_core: lib/libopencv_core.2.4.9.dylib +bin/opencv_perf_core: lib/libopencv_ts.2.4.9.dylib +bin/opencv_perf_core: lib/libopencv_highgui.2.4.9.dylib +bin/opencv_perf_core: lib/libopencv_core.2.4.9.dylib +bin/opencv_perf_core: 3rdparty/lib/libzlib.a +bin/opencv_perf_core: modules/core/CMakeFiles/opencv_perf_core.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX executable ../../bin/opencv_perf_core" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/opencv_perf_core.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +modules/core/CMakeFiles/opencv_perf_core.dir/build: bin/opencv_perf_core +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/build + +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o.requires +modules/core/CMakeFiles/opencv_perf_core.dir/requires: modules/core/CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o.requires +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/requires + +modules/core/CMakeFiles/opencv_perf_core.dir/clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && $(CMAKE_COMMAND) -P CMakeFiles/opencv_perf_core.dir/cmake_clean.cmake +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/clean + +modules/core/CMakeFiles/opencv_perf_core.dir/depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/core /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/core /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_perf_core.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : modules/core/CMakeFiles/opencv_perf_core.dir/depend + diff --git a/core/CMakeFiles/opencv_perf_core.dir/cmake_clean.cmake b/core/CMakeFiles/opencv_perf_core.dir/cmake_clean.cmake new file mode 100644 index 0000000..a122202 --- /dev/null +++ b/core/CMakeFiles/opencv_perf_core.dir/cmake_clean.cmake @@ -0,0 +1,28 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o" + "CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o" + "../../bin/opencv_perf_core.pdb" + "../../bin/opencv_perf_core" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/opencv_perf_core.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/core/CMakeFiles/opencv_perf_core.dir/depend.make b/core/CMakeFiles/opencv_perf_core.dir/depend.make new file mode 100644 index 0000000..a5c7cd5 --- /dev/null +++ b/core/CMakeFiles/opencv_perf_core.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for opencv_perf_core. +# This may be replaced when dependencies are built. diff --git a/core/CMakeFiles/opencv_perf_core.dir/flags.make b/core/CMakeFiles/opencv_perf_core.dir/flags.make new file mode 100644 index 0000000..7ca9134 --- /dev/null +++ b/core/CMakeFiles/opencv_perf_core.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -O3 -DNDEBUG -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib -I/Users/beau/Documents/workspace/OpenCV/opencv -I/opt/local/include -I/opt/local/include/eigen3 + +CXX_DEFINES = -DHAVE_CVCONFIG_H -DHAVE_ALLOCA -DHAVE_ALLOCA_H -DHAVE_LIBPTHREAD -DHAVE_UNISTD_H -DCVAPI_EXPORTS + diff --git a/core/CMakeFiles/opencv_perf_core.dir/link.txt b/core/CMakeFiles/opencv_perf_core.dir/link.txt new file mode 100644 index 0000000..5d9f236 --- /dev/null +++ b/core/CMakeFiles/opencv_perf_core.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -O3 -DNDEBUG -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/opencv_perf_core.dir/perf/perf_abs.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_addWeighted.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_arithm.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_bitwise.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_compare.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_convertTo.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_dft.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_dot.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_inRange.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_main.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_mat.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_math.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_merge.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_minmaxloc.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_norm.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_precomp.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_reduce.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_split.cpp.o CMakeFiles/opencv_perf_core.dir/perf/perf_stat.cpp.o -o ../../bin/opencv_perf_core -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib/gcc -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib ../../lib/libopencv_core.2.4.9.dylib ../../lib/libopencv_ts.2.4.9.dylib ../../lib/libopencv_highgui.2.4.9.dylib ../../lib/libopencv_core.2.4.9.dylib ../../3rdparty/lib/libzlib.a diff --git a/core/CMakeFiles/opencv_perf_core.dir/progress.make b/core/CMakeFiles/opencv_perf_core.dir/progress.make new file mode 100644 index 0000000..bfdd75e --- /dev/null +++ b/core/CMakeFiles/opencv_perf_core.dir/progress.make @@ -0,0 +1,20 @@ +CMAKE_PROGRESS_1 = 62 +CMAKE_PROGRESS_2 = +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = +CMAKE_PROGRESS_5 = +CMAKE_PROGRESS_6 = +CMAKE_PROGRESS_7 = +CMAKE_PROGRESS_8 = +CMAKE_PROGRESS_9 = 63 +CMAKE_PROGRESS_10 = +CMAKE_PROGRESS_11 = +CMAKE_PROGRESS_12 = +CMAKE_PROGRESS_13 = +CMAKE_PROGRESS_14 = +CMAKE_PROGRESS_15 = +CMAKE_PROGRESS_16 = 64 +CMAKE_PROGRESS_17 = +CMAKE_PROGRESS_18 = +CMAKE_PROGRESS_19 = + diff --git a/core/CMakeFiles/opencv_test_core.dir/DependInfo.cmake b/core/CMakeFiles/opencv_test_core.dir/DependInfo.cmake new file mode 100644 index 0000000..3f0641d --- /dev/null +++ b/core/CMakeFiles/opencv_test_core.dir/DependInfo.cmake @@ -0,0 +1,57 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_arithm.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_countnonzero.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_ds.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_dxt.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_eigen.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_io.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_main.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_mat.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_math.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_misc.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_operations.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_precomp.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_rand.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "Clang") + +# Preprocessor definitions for this target. +SET(CMAKE_TARGET_DEFINITIONS + "HAVE_CVCONFIG_H" + "HAVE_ALLOCA" + "HAVE_ALLOCA_H" + "HAVE_LIBPTHREAD" + "HAVE_UNISTD_H" + "CVAPI_EXPORTS" + ) + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/CMakeFiles/opencv_ts.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib/CMakeFiles/zlib.dir/DependInfo.cmake" + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "modules/core/perf" + "modules/highgui/include" + "modules/ts/include" + "modules/core/include" + "modules/core" + "modules/core/src" + "modules/core/test" + "3rdparty/zlib" + "." + "/opt/local/include" + "/opt/local/include/eigen3" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/core/CMakeFiles/opencv_test_core.dir/build.make b/core/CMakeFiles/opencv_test_core.dir/build.make new file mode 100644 index 0000000..5a802b6 --- /dev/null +++ b/core/CMakeFiles/opencv_test_core.dir/build.make @@ -0,0 +1,419 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# Include any dependencies generated for this target. +include modules/core/CMakeFiles/opencv_test_core.dir/depend.make + +# Include the progress variables for this target. +include modules/core/CMakeFiles/opencv_test_core.dir/progress.make + +# Include the compile flags for this target's objects. +include modules/core/CMakeFiles/opencv_test_core.dir/flags.make + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o: modules/core/CMakeFiles/opencv_test_core.dir/flags.make +modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o: modules/core/test/test_arithm.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_arithm.cpp + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_arithm.cpp > CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.i + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_arithm.cpp -o CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.s + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o.requires + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o.provides: modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_test_core.dir/build.make modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o.provides + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o.provides.build: modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o: modules/core/CMakeFiles/opencv_test_core.dir/flags.make +modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o: modules/core/test/test_countnonzero.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_2) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_countnonzero.cpp + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_countnonzero.cpp > CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.i + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_countnonzero.cpp -o CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.s + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o.requires + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o.provides: modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_test_core.dir/build.make modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o.provides + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o.provides.build: modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o: modules/core/CMakeFiles/opencv_test_core.dir/flags.make +modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o: modules/core/test/test_ds.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_3) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_ds.cpp + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_ds.cpp > CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.i + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_ds.cpp -o CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.s + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o.requires + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o.provides: modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_test_core.dir/build.make modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o.provides + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o.provides.build: modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o: modules/core/CMakeFiles/opencv_test_core.dir/flags.make +modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o: modules/core/test/test_dxt.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_4) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_dxt.cpp + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_dxt.cpp > CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.i + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_dxt.cpp -o CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.s + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o.requires + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o.provides: modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_test_core.dir/build.make modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o.provides + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o.provides.build: modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o: modules/core/CMakeFiles/opencv_test_core.dir/flags.make +modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o: modules/core/test/test_eigen.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_5) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_eigen.cpp + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_eigen.cpp > CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.i + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_eigen.cpp -o CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.s + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o.requires + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o.provides: modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_test_core.dir/build.make modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o.provides + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o.provides.build: modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o: modules/core/CMakeFiles/opencv_test_core.dir/flags.make +modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o: modules/core/test/test_io.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_6) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_io.cpp + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_core.dir/test/test_io.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_io.cpp > CMakeFiles/opencv_test_core.dir/test/test_io.cpp.i + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_core.dir/test/test_io.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_io.cpp -o CMakeFiles/opencv_test_core.dir/test/test_io.cpp.s + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o.requires + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o.provides: modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_test_core.dir/build.make modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o.provides + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o.provides.build: modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o: modules/core/CMakeFiles/opencv_test_core.dir/flags.make +modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o: modules/core/test/test_main.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_7) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_main.cpp + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_core.dir/test/test_main.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_main.cpp > CMakeFiles/opencv_test_core.dir/test/test_main.cpp.i + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_core.dir/test/test_main.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_main.cpp -o CMakeFiles/opencv_test_core.dir/test/test_main.cpp.s + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o.requires + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o.provides: modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_test_core.dir/build.make modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o.provides + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o.provides.build: modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o: modules/core/CMakeFiles/opencv_test_core.dir/flags.make +modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o: modules/core/test/test_mat.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_8) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_mat.cpp + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_mat.cpp > CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.i + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_mat.cpp -o CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.s + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o.requires + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o.provides: modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_test_core.dir/build.make modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o.provides + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o.provides.build: modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o: modules/core/CMakeFiles/opencv_test_core.dir/flags.make +modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o: modules/core/test/test_math.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_9) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_math.cpp + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_core.dir/test/test_math.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_math.cpp > CMakeFiles/opencv_test_core.dir/test/test_math.cpp.i + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_core.dir/test/test_math.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_math.cpp -o CMakeFiles/opencv_test_core.dir/test/test_math.cpp.s + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o.requires + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o.provides: modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_test_core.dir/build.make modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o.provides + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o.provides.build: modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o: modules/core/CMakeFiles/opencv_test_core.dir/flags.make +modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o: modules/core/test/test_misc.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_10) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_misc.cpp + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_misc.cpp > CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.i + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_misc.cpp -o CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.s + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o.requires + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o.provides: modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_test_core.dir/build.make modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o.provides + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o.provides.build: modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o: modules/core/CMakeFiles/opencv_test_core.dir/flags.make +modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o: modules/core/test/test_operations.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_11) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_operations.cpp + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_operations.cpp > CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.i + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_operations.cpp -o CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.s + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o.requires + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o.provides: modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_test_core.dir/build.make modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o.provides + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o.provides.build: modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o: modules/core/CMakeFiles/opencv_test_core.dir/flags.make +modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o: modules/core/test/test_precomp.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_12) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_precomp.cpp + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_precomp.cpp > CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.i + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_precomp.cpp -o CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.s + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o.requires + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o.provides: modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_test_core.dir/build.make modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o.provides + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o.provides.build: modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o: modules/core/CMakeFiles/opencv_test_core.dir/flags.make +modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o: modules/core/test/test_rand.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_13) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_rand.cpp + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_rand.cpp > CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.i + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test/test_rand.cpp -o CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.s + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o.requires: +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o.requires + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o.provides: modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o.requires + $(MAKE) -f modules/core/CMakeFiles/opencv_test_core.dir/build.make modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o.provides.build +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o.provides + +modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o.provides.build: modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o + +# Object files for target opencv_test_core +opencv_test_core_OBJECTS = \ +"CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o" \ +"CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o" \ +"CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o" \ +"CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o" \ +"CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o" \ +"CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o" \ +"CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o" \ +"CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o" \ +"CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o" \ +"CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o" \ +"CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o" \ +"CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o" \ +"CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o" + +# External object files for target opencv_test_core +opencv_test_core_EXTERNAL_OBJECTS = + +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/build.make +bin/opencv_test_core: lib/libopencv_core.2.4.9.dylib +bin/opencv_test_core: lib/libopencv_ts.2.4.9.dylib +bin/opencv_test_core: lib/libopencv_highgui.2.4.9.dylib +bin/opencv_test_core: lib/libopencv_core.2.4.9.dylib +bin/opencv_test_core: 3rdparty/lib/libzlib.a +bin/opencv_test_core: modules/core/CMakeFiles/opencv_test_core.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX executable ../../bin/opencv_test_core" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/opencv_test_core.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +modules/core/CMakeFiles/opencv_test_core.dir/build: bin/opencv_test_core +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/build + +modules/core/CMakeFiles/opencv_test_core.dir/requires: modules/core/CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o.requires +modules/core/CMakeFiles/opencv_test_core.dir/requires: modules/core/CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o.requires +modules/core/CMakeFiles/opencv_test_core.dir/requires: modules/core/CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o.requires +modules/core/CMakeFiles/opencv_test_core.dir/requires: modules/core/CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o.requires +modules/core/CMakeFiles/opencv_test_core.dir/requires: modules/core/CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o.requires +modules/core/CMakeFiles/opencv_test_core.dir/requires: modules/core/CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o.requires +modules/core/CMakeFiles/opencv_test_core.dir/requires: modules/core/CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o.requires +modules/core/CMakeFiles/opencv_test_core.dir/requires: modules/core/CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o.requires +modules/core/CMakeFiles/opencv_test_core.dir/requires: modules/core/CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o.requires +modules/core/CMakeFiles/opencv_test_core.dir/requires: modules/core/CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o.requires +modules/core/CMakeFiles/opencv_test_core.dir/requires: modules/core/CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o.requires +modules/core/CMakeFiles/opencv_test_core.dir/requires: modules/core/CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o.requires +modules/core/CMakeFiles/opencv_test_core.dir/requires: modules/core/CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o.requires +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/requires + +modules/core/CMakeFiles/opencv_test_core.dir/clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/core && $(CMAKE_COMMAND) -P CMakeFiles/opencv_test_core.dir/cmake_clean.cmake +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/clean + +modules/core/CMakeFiles/opencv_test_core.dir/depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/core /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/core /Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_test_core.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : modules/core/CMakeFiles/opencv_test_core.dir/depend + diff --git a/core/CMakeFiles/opencv_test_core.dir/cmake_clean.cmake b/core/CMakeFiles/opencv_test_core.dir/cmake_clean.cmake new file mode 100644 index 0000000..52900bf --- /dev/null +++ b/core/CMakeFiles/opencv_test_core.dir/cmake_clean.cmake @@ -0,0 +1,22 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o" + "CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o" + "CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o" + "CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o" + "CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o" + "CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o" + "CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o" + "CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o" + "CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o" + "CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o" + "CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o" + "CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o" + "CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o" + "../../bin/opencv_test_core.pdb" + "../../bin/opencv_test_core" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/opencv_test_core.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/core/CMakeFiles/opencv_test_core.dir/depend.make b/core/CMakeFiles/opencv_test_core.dir/depend.make new file mode 100644 index 0000000..49b3940 --- /dev/null +++ b/core/CMakeFiles/opencv_test_core.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for opencv_test_core. +# This may be replaced when dependencies are built. diff --git a/core/CMakeFiles/opencv_test_core.dir/flags.make b/core/CMakeFiles/opencv_test_core.dir/flags.make new file mode 100644 index 0000000..7ca9134 --- /dev/null +++ b/core/CMakeFiles/opencv_test_core.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -O3 -DNDEBUG -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/perf -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/src -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/test -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib -I/Users/beau/Documents/workspace/OpenCV/opencv -I/opt/local/include -I/opt/local/include/eigen3 + +CXX_DEFINES = -DHAVE_CVCONFIG_H -DHAVE_ALLOCA -DHAVE_ALLOCA_H -DHAVE_LIBPTHREAD -DHAVE_UNISTD_H -DCVAPI_EXPORTS + diff --git a/core/CMakeFiles/opencv_test_core.dir/link.txt b/core/CMakeFiles/opencv_test_core.dir/link.txt new file mode 100644 index 0000000..f946047 --- /dev/null +++ b/core/CMakeFiles/opencv_test_core.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -O3 -DNDEBUG -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/opencv_test_core.dir/test/test_arithm.cpp.o CMakeFiles/opencv_test_core.dir/test/test_countnonzero.cpp.o CMakeFiles/opencv_test_core.dir/test/test_ds.cpp.o CMakeFiles/opencv_test_core.dir/test/test_dxt.cpp.o CMakeFiles/opencv_test_core.dir/test/test_eigen.cpp.o CMakeFiles/opencv_test_core.dir/test/test_io.cpp.o CMakeFiles/opencv_test_core.dir/test/test_main.cpp.o CMakeFiles/opencv_test_core.dir/test/test_mat.cpp.o CMakeFiles/opencv_test_core.dir/test/test_math.cpp.o CMakeFiles/opencv_test_core.dir/test/test_misc.cpp.o CMakeFiles/opencv_test_core.dir/test/test_operations.cpp.o CMakeFiles/opencv_test_core.dir/test/test_precomp.cpp.o CMakeFiles/opencv_test_core.dir/test/test_rand.cpp.o -o ../../bin/opencv_test_core -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib/gcc -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib ../../lib/libopencv_core.2.4.9.dylib ../../lib/libopencv_ts.2.4.9.dylib ../../lib/libopencv_highgui.2.4.9.dylib ../../lib/libopencv_core.2.4.9.dylib ../../3rdparty/lib/libzlib.a diff --git a/core/CMakeFiles/opencv_test_core.dir/progress.make b/core/CMakeFiles/opencv_test_core.dir/progress.make new file mode 100644 index 0000000..222fcb6 --- /dev/null +++ b/core/CMakeFiles/opencv_test_core.dir/progress.make @@ -0,0 +1,14 @@ +CMAKE_PROGRESS_1 = +CMAKE_PROGRESS_2 = +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = +CMAKE_PROGRESS_5 = +CMAKE_PROGRESS_6 = 78 +CMAKE_PROGRESS_7 = +CMAKE_PROGRESS_8 = +CMAKE_PROGRESS_9 = +CMAKE_PROGRESS_10 = +CMAKE_PROGRESS_11 = +CMAKE_PROGRESS_12 = +CMAKE_PROGRESS_13 = 79 + diff --git a/core/CMakeFiles/progress.marks b/core/CMakeFiles/progress.marks new file mode 100644 index 0000000..7facc89 --- /dev/null +++ b/core/CMakeFiles/progress.marks @@ -0,0 +1 @@ +36 diff --git a/core/doc/basic_structures.rst b/core/doc/basic_structures.rst new file mode 100644 index 0000000..e77ee4f --- /dev/null +++ b/core/doc/basic_structures.rst @@ -0,0 +1,2451 @@ +Basic Structures +================ + +.. highlight:: cpp + +DataType +-------- +.. ocv:class:: DataType + +Template "trait" class for OpenCV primitive data types. A primitive OpenCV data type is one of ``unsigned char``, ``bool``, ``signed char``, ``unsigned short``, ``signed short``, ``int``, ``float``, ``double``, or a tuple of values of one of these types, where all the values in the tuple have the same type. Any primitive type from the list can be defined by an identifier in the form ``CV_{U|S|F}C()``, for example: ``uchar`` ~ ``CV_8UC1``, 3-element floating-point tuple ~ ``CV_32FC3``, and so on. A universal OpenCV structure that is able to store a single instance of such a primitive data type is +:ocv:class:`Vec`. Multiple instances of such a type can be stored in a ``std::vector``, ``Mat``, ``Mat_``, ``SparseMat``, ``SparseMat_``, or any other container that is able to store ``Vec`` instances. + +The ``DataType`` class is basically used to provide a description of such primitive data types without adding any fields or methods to the corresponding classes (and it is actually impossible to add anything to primitive C/C++ data types). This technique is known in C++ as class traits. It is not ``DataType`` itself that is used but its specialized versions, such as: :: + + template<> class DataType + { + typedef uchar value_type; + typedef int work_type; + typedef uchar channel_type; + enum { channel_type = CV_8U, channels = 1, fmt='u', type = CV_8U }; + }; + ... + template DataType > + { + typedef std::complex<_Tp> value_type; + typedef std::complex<_Tp> work_type; + typedef _Tp channel_type; + // DataDepth is another helper trait class + enum { depth = DataDepth<_Tp>::value, channels=2, + fmt=(channels-1)*256+DataDepth<_Tp>::fmt, + type=CV_MAKETYPE(depth, channels) }; + }; + ... + +The main purpose of this class is to convert compilation-time type information to an OpenCV-compatible data type identifier, for example: :: + + // allocates a 30x40 floating-point matrix + Mat A(30, 40, DataType::type); + + Mat B = Mat_ >(3, 3); + // the statement below will print 6, 2 /*, that is depth == CV_64F, channels == 2 */ + cout << B.depth() << ", " << B.channels() << endl; + + +So, such traits are used to tell OpenCV which data type you are working with, even if such a type is not native to OpenCV. For example, the matrix ``B`` initialization above is compiled because OpenCV defines the proper specialized template class ``DataType >`` . This mechanism is also useful (and used in OpenCV this way) for generic algorithms implementations. + + +Point\_ +------- +.. ocv:class:: Point_ + +Template class for 2D points specified by its coordinates +:math:`x` and +:math:`y` . +An instance of the class is interchangeable with C structures, ``CvPoint`` and ``CvPoint2D32f`` . There is also a cast operator to convert point coordinates to the specified type. The conversion from floating-point coordinates to integer coordinates is done by rounding. Commonly, the conversion uses this +operation for each of the coordinates. Besides the class members listed in the declaration above, the following operations on points are implemented: :: + + pt1 = pt2 + pt3; + pt1 = pt2 - pt3; + pt1 = pt2 * a; + pt1 = a * pt2; + pt1 += pt2; + pt1 -= pt2; + pt1 *= a; + double value = norm(pt); // L2 norm + pt1 == pt2; + pt1 != pt2; + +For your convenience, the following type aliases are defined: :: + + typedef Point_ Point2i; + typedef Point2i Point; + typedef Point_ Point2f; + typedef Point_ Point2d; + +Example: :: + + Point2f a(0.3f, 0.f), b(0.f, 0.4f); + Point pt = (a + b)*10.f; + cout << pt.x << ", " << pt.y << endl; + + +Point3\_ +-------- +.. ocv:class:: Point3_ + +Template class for 3D points specified by its coordinates +:math:`x`, +:math:`y` and +:math:`z` . +An instance of the class is interchangeable with the C structure ``CvPoint2D32f`` . Similarly to ``Point_`` , the coordinates of 3D points can be converted to another type. The vector arithmetic and comparison operations are also supported. + +The following ``Point3_<>`` aliases are available: :: + + typedef Point3_ Point3i; + typedef Point3_ Point3f; + typedef Point3_ Point3d; + +Size\_ +------ +.. ocv:class:: Size_ + +Template class for specifying the size of an image or rectangle. The class includes two members called ``width`` and ``height``. The structure can be converted to and from the old OpenCV structures +``CvSize`` and ``CvSize2D32f`` . The same set of arithmetic and comparison operations as for ``Point_`` is available. + +OpenCV defines the following ``Size_<>`` aliases: :: + + typedef Size_ Size2i; + typedef Size2i Size; + typedef Size_ Size2f; + +Rect\_ +------ +.. ocv:class:: Rect_ + +Template class for 2D rectangles, described by the following parameters: + +* Coordinates of the top-left corner. This is a default interpretation of ``Rect_::x`` and ``Rect_::y`` in OpenCV. Though, in your algorithms you may count ``x`` and ``y`` from the bottom-left corner. +* Rectangle width and height. + +OpenCV typically assumes that the top and left boundary of the rectangle are inclusive, while the right and bottom boundaries are not. For example, the method ``Rect_::contains`` returns ``true`` if + +.. math:: + + x \leq pt.x < x+width, + y \leq pt.y < y+height + +Virtually every loop over an image +ROI in OpenCV (where ROI is specified by ``Rect_`` ) is implemented as: :: + + for(int y = roi.y; y < roi.y + rect.height; y++) + for(int x = roi.x; x < roi.x + rect.width; x++) + { + // ... + } + + +In addition to the class members, the following operations on rectangles are implemented: + +* + :math:`\texttt{rect} = \texttt{rect} \pm \texttt{point}` (shifting a rectangle by a certain offset) + +* + :math:`\texttt{rect} = \texttt{rect} \pm \texttt{size}` (expanding or shrinking a rectangle by a certain amount) + +* ``rect += point, rect -= point, rect += size, rect -= size`` (augmenting operations) + +* ``rect = rect1 & rect2`` (rectangle intersection) + +* ``rect = rect1 | rect2`` (minimum area rectangle containing ``rect2`` and ``rect3`` ) + +* ``rect &= rect1, rect |= rect1`` (and the corresponding augmenting operations) + +* ``rect == rect1, rect != rect1`` (rectangle comparison) + +This is an example how the partial ordering on rectangles can be established (rect1 +:math:`\subseteq` rect2): :: + + template inline bool + operator <= (const Rect_<_Tp>& r1, const Rect_<_Tp>& r2) + { + return (r1 & r2) == r1; + } + + +For your convenience, the ``Rect_<>`` alias is available: :: + + typedef Rect_ Rect; + +RotatedRect +----------- +.. ocv:class:: RotatedRect + +The class represents rotated (i.e. not up-right) rectangles on a plane. Each rectangle is specified by the center point (mass center), length of each side (represented by cv::Size2f structure) and the rotation angle in degrees. + + .. ocv:function:: RotatedRect::RotatedRect() + .. ocv:function:: RotatedRect::RotatedRect(const Point2f& center, const Size2f& size, float angle) + .. ocv:function:: RotatedRect::RotatedRect(const CvBox2D& box) + + :param center: The rectangle mass center. + :param size: Width and height of the rectangle. + :param angle: The rotation angle in a clockwise direction. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle. + :param box: The rotated rectangle parameters as the obsolete CvBox2D structure. + + .. ocv:function:: void RotatedRect::points( Point2f pts[] ) const + .. ocv:function:: Rect RotatedRect::boundingRect() const + .. ocv:function:: RotatedRect::operator CvBox2D() const + + :param pts: The points array for storing rectangle vertices. + +The sample below demonstrates how to use RotatedRect: + +:: + + Mat image(200, 200, CV_8UC3, Scalar(0)); + RotatedRect rRect = RotatedRect(Point2f(100,100), Size2f(100,50), 30); + + Point2f vertices[4]; + rRect.points(vertices); + for (int i = 0; i < 4; i++) + line(image, vertices[i], vertices[(i+1)%4], Scalar(0,255,0)); + + Rect brect = rRect.boundingRect(); + rectangle(image, brect, Scalar(255,0,0)); + + imshow("rectangles", image); + waitKey(0); + +.. image:: pics/rotatedrect.png + +.. seealso:: + + :ocv:cfunc:`CamShift`, + :ocv:func:`fitEllipse`, + :ocv:func:`minAreaRect`, + :ocv:struct:`CvBox2D` + +TermCriteria +------------ +.. ocv:class:: TermCriteria + +Template class defining termination criteria for iterative algorithms. + +Matx +---- +.. ocv:class:: Matx + +Template class for small matrices whose type and size are known at compilation time: :: + + template class Matx {...}; + + typedef Matx Matx12f; + typedef Matx Matx12d; + ... + typedef Matx Matx16f; + typedef Matx Matx16d; + + typedef Matx Matx21f; + typedef Matx Matx21d; + ... + typedef Matx Matx61f; + typedef Matx Matx61d; + + typedef Matx Matx22f; + typedef Matx Matx22d; + ... + typedef Matx Matx66f; + typedef Matx Matx66d; + +If you need a more flexible type, use :ocv:class:`Mat` . The elements of the matrix ``M`` are accessible using the ``M(i,j)`` notation. Most of the common matrix operations (see also +:ref:`MatrixExpressions` ) are available. To do an operation on ``Matx`` that is not implemented, you can easily convert the matrix to +``Mat`` and backwards. :: + + Matx33f m(1, 2, 3, + 4, 5, 6, + 7, 8, 9); + cout << sum(Mat(m*m.t())) << endl; + + +Vec +--- +.. ocv:class:: Vec + +Template class for short numerical vectors, a partial case of :ocv:class:`Matx`: :: + + template class Vec : public Matx<_Tp, n, 1> {...}; + + typedef Vec Vec2b; + typedef Vec Vec3b; + typedef Vec Vec4b; + + typedef Vec Vec2s; + typedef Vec Vec3s; + typedef Vec Vec4s; + + typedef Vec Vec2i; + typedef Vec Vec3i; + typedef Vec Vec4i; + + typedef Vec Vec2f; + typedef Vec Vec3f; + typedef Vec Vec4f; + typedef Vec Vec6f; + + typedef Vec Vec2d; + typedef Vec Vec3d; + typedef Vec Vec4d; + typedef Vec Vec6d; + +It is possible to convert ``Vec`` to/from ``Point_``, ``Vec`` to/from ``Point3_`` , and ``Vec`` to :ocv:struct:`CvScalar` or :ocv:class:`Scalar_`. Use ``operator[]`` to access the elements of ``Vec``. + +All the expected vector operations are also implemented: + +* ``v1 = v2 + v3`` +* ``v1 = v2 - v3`` +* ``v1 = v2 * scale`` +* ``v1 = scale * v2`` +* ``v1 = -v2`` +* ``v1 += v2`` and other augmenting operations +* ``v1 == v2, v1 != v2`` +* ``norm(v1)`` (euclidean norm) + +The ``Vec`` class is commonly used to describe pixel types of multi-channel arrays. See :ocv:class:`Mat` for details. + +Scalar\_ +-------- +.. ocv:class:: Scalar_ + +Template class for a 4-element vector derived from Vec. :: + + template class Scalar_ : public Vec<_Tp, 4> { ... }; + + typedef Scalar_ Scalar; + +Being derived from ``Vec<_Tp, 4>`` , ``Scalar_`` and ``Scalar`` can be used just as typical 4-element vectors. In addition, they can be converted to/from ``CvScalar`` . The type ``Scalar`` is widely used in OpenCV to pass pixel values. + +Range +----- +.. ocv:class:: Range + +Template class specifying a continuous subsequence (slice) of a sequence. :: + + class Range + { + public: + ... + int start, end; + }; + +The class is used to specify a row or a column span in a matrix ( +:ocv:class:`Mat` ) and for many other purposes. ``Range(a,b)`` is basically the same as ``a:b`` in Matlab or ``a..b`` in Python. As in Python, ``start`` is an inclusive left boundary of the range and ``end`` is an exclusive right boundary of the range. Such a half-opened interval is usually denoted as +:math:`[start,end)` . + +The static method ``Range::all()`` returns a special variable that means "the whole sequence" or "the whole range", just like " ``:`` " in Matlab or " ``...`` " in Python. All the methods and functions in OpenCV that take ``Range`` support this special ``Range::all()`` value. But, of course, in case of your own custom processing, you will probably have to check and handle it explicitly: :: + + void my_function(..., const Range& r, ....) + { + if(r == Range::all()) { + // process all the data + } + else { + // process [r.start, r.end) + } + } + + +.. _Ptr: + +Ptr +--- +.. ocv:class:: Ptr + +Template class for smart reference-counting pointers :: + + template class Ptr + { + public: + // default constructor + Ptr(); + // constructor that wraps the object pointer + Ptr(_Tp* _obj); + // destructor: calls release() + ~Ptr(); + // copy constructor; increments ptr's reference counter + Ptr(const Ptr& ptr); + // assignment operator; decrements own reference counter + // (with release()) and increments ptr's reference counter + Ptr& operator = (const Ptr& ptr); + // increments reference counter + void addref(); + // decrements reference counter; when it becomes 0, + // delete_obj() is called + void release(); + // user-specified custom object deletion operation. + // by default, "delete obj;" is called + void delete_obj(); + // returns true if obj == 0; + bool empty() const; + + // provide access to the object fields and methods + _Tp* operator -> (); + const _Tp* operator -> () const; + + // return the underlying object pointer; + // thanks to the methods, the Ptr<_Tp> can be + // used instead of _Tp* + operator _Tp* (); + operator const _Tp*() const; + protected: + // the encapsulated object pointer + _Tp* obj; + // the associated reference counter + int* refcount; + }; + + +The ``Ptr<_Tp>`` class is a template class that wraps pointers of the corresponding type. It is similar to ``shared_ptr`` that is part of the Boost library ( +http://www.boost.org/doc/libs/1_40_0/libs/smart_ptr/shared_ptr.htm +) and also part of the `C++0x `_ +standard. + +This class provides the following options: + +* + Default constructor, copy constructor, and assignment operator for an arbitrary C++ class or a C structure. For some objects, like files, windows, mutexes, sockets, and others, a copy constructor or an assignment operator are difficult to define. For some other objects, like complex classifiers in OpenCV, copy constructors are absent and not easy to implement. Finally, some of complex OpenCV and your own data structures may be written in C. However, copy constructors and default constructors can simplify programming a lot. Besides, they are often required (for example, by STL containers). By wrapping a pointer to such a complex object ``TObj`` to ``Ptr`` , you automatically get all of the necessary constructors and the assignment operator. + +* + *O(1)* complexity of the above-mentioned operations. While some structures, like ``std::vector``, provide a copy constructor and an assignment operator, the operations may take a considerable amount of time if the data structures are large. But if the structures are put into ``Ptr<>`` , the overhead is small and independent of the data size. + +* + Automatic destruction, even for C structures. See the example below with ``FILE*`` . + +* + Heterogeneous collections of objects. The standard STL and most other C++ and OpenCV containers can store only objects of the same type and the same size. The classical solution to store objects of different types in the same container is to store pointers to the base class ``base_class_t*`` instead but then you loose the automatic memory management. Again, by using ``Ptr()`` instead of the raw pointers, you can solve the problem. + +The ``Ptr`` class treats the wrapped object as a black box. The reference counter is allocated and managed separately. The only thing the pointer class needs to know about the object is how to deallocate it. This knowledge is encapsulated in the ``Ptr::delete_obj()`` method that is called when the reference counter becomes 0. If the object is a C++ class instance, no additional coding is needed, because the default implementation of this method calls ``delete obj;`` . +However, if the object is deallocated in a different way, the specialized method should be created. For example, if you want to wrap ``FILE`` , the ``delete_obj`` may be implemented as follows: :: + + template<> inline void Ptr::delete_obj() + { + fclose(obj); // no need to clear the pointer afterwards, + // it is done externally. + } + ... + + // now use it: + Ptr f(fopen("myfile.txt", "r")); + if(f.empty()) + throw ...; + fprintf(f, ....); + ... + // the file will be closed automatically by the Ptr destructor. + + +.. note:: The reference increment/decrement operations are implemented as atomic operations, and therefore it is normally safe to use the classes in multi-threaded applications. The same is true for :ocv:class:`Mat` and other C++ OpenCV classes that operate on the reference counters. + +Mat +--- +.. ocv:class:: Mat + +OpenCV C++ n-dimensional dense array class :: + + class CV_EXPORTS Mat + { + public: + // ... a lot of methods ... + ... + + /*! includes several bit-fields: + - the magic signature + - continuity flag + - depth + - number of channels + */ + int flags; + //! the array dimensionality, >= 2 + int dims; + //! the number of rows and columns or (-1, -1) when the array has more than 2 dimensions + int rows, cols; + //! pointer to the data + uchar* data; + + //! pointer to the reference counter; + // when array points to user-allocated data, the pointer is NULL + int* refcount; + + // other members + ... + }; + + +The class ``Mat`` represents an n-dimensional dense numerical single-channel or multi-channel array. It can be used to store real or complex-valued vectors and matrices, grayscale or color images, voxel volumes, vector fields, point clouds, tensors, histograms (though, very high-dimensional histograms may be better stored in a ``SparseMat`` ). The data layout of the array +:math:`M` is defined by the array ``M.step[]`` , so that the address of element +:math:`(i_0,...,i_{M.dims-1})` , where +:math:`0\leq i_k= M.step[i+1]`` (in fact, ``M.step[i] >= M.step[i+1]*M.size[i+1]`` ). This means that 2-dimensional matrices are stored row-by-row, 3-dimensional matrices are stored plane-by-plane, and so on. ``M.step[M.dims-1]`` is minimal and always equal to the element size ``M.elemSize()`` . + +So, the data layout in ``Mat`` is fully compatible with ``CvMat``, ``IplImage``, and ``CvMatND`` types from OpenCV 1.x. It is also compatible with the majority of dense array types from the standard toolkits and SDKs, such as Numpy (ndarray), Win32 (independent device bitmaps), and others, that is, with any array that uses *steps* (or *strides*) to compute the position of a pixel. Due to this compatibility, it is possible to make a ``Mat`` header for user-allocated data and process it in-place using OpenCV functions. + +There are many different ways to create a ``Mat`` object. The most popular options are listed below: + +* + + Use the ``create(nrows, ncols, type)`` method or the similar ``Mat(nrows, ncols, type[, fillValue])`` constructor. A new array of the specified size and type is allocated. ``type`` has the same meaning as in the ``cvCreateMat`` method. + For example, ``CV_8UC1`` means a 8-bit single-channel array, ``CV_32FC2`` means a 2-channel (complex) floating-point array, and so on. + + :: + + // make a 7x7 complex matrix filled with 1+3j. + Mat M(7,7,CV_32FC2,Scalar(1,3)); + // and now turn M to a 100x60 15-channel 8-bit matrix. + // The old content will be deallocated + M.create(100,60,CV_8UC(15)); + + .. + + As noted in the introduction to this chapter, ``create()`` allocates only a new array when the shape or type of the current array are different from the specified ones. + +* + + Create a multi-dimensional array: + + :: + + // create a 100x100x100 8-bit array + int sz[] = {100, 100, 100}; + Mat bigCube(3, sz, CV_8U, Scalar::all(0)); + + .. + + It passes the number of dimensions =1 to the ``Mat`` constructor but the created array will be 2-dimensional with the number of columns set to 1. So, ``Mat::dims`` is always >= 2 (can also be 0 when the array is empty). + +* + + Use a copy constructor or assignment operator where there can be an array or expression on the right side (see below). As noted in the introduction, the array assignment is an O(1) operation because it only copies the header and increases the reference counter. The ``Mat::clone()`` method can be used to get a full (deep) copy of the array when you need it. + +* + + Construct a header for a part of another array. It can be a single row, single column, several rows, several columns, rectangular region in the array (called a *minor* in algebra) or a diagonal. Such operations are also O(1) because the new header references the same data. You can actually modify a part of the array using this feature, for example: + + :: + + // add the 5-th row, multiplied by 3 to the 3rd row + M.row(3) = M.row(3) + M.row(5)*3; + + // now copy the 7-th column to the 1-st column + // M.col(1) = M.col(7); // this will not work + Mat M1 = M.col(1); + M.col(7).copyTo(M1); + + // create a new 320x240 image + Mat img(Size(320,240),CV_8UC3); + // select a ROI + Mat roi(img, Rect(10,10,100,100)); + // fill the ROI with (0,255,0) (which is green in RGB space); + // the original 320x240 image will be modified + roi = Scalar(0,255,0); + + .. + + Due to the additional ``datastart`` and ``dataend`` members, it is possible to compute a relative sub-array position in the main *container* array using ``locateROI()``: + + :: + + Mat A = Mat::eye(10, 10, CV_32S); + // extracts A columns, 1 (inclusive) to 3 (exclusive). + Mat B = A(Range::all(), Range(1, 3)); + // extracts B rows, 5 (inclusive) to 9 (exclusive). + // that is, C ~ A(Range(5, 9), Range(1, 3)) + Mat C = B(Range(5, 9), Range::all()); + Size size; Point ofs; + C.locateROI(size, ofs); + // size will be (width=10,height=10) and the ofs will be (x=1, y=5) + + .. + + As in case of whole matrices, if you need a deep copy, use the ``clone()`` method of the extracted sub-matrices. + +* + + Make a header for user-allocated data. It can be useful to do the following: + + #. + Process "foreign" data using OpenCV (for example, when you implement a DirectShow* filter or a processing module for ``gstreamer``, and so on). For example: + + :: + + void process_video_frame(const unsigned char* pixels, + int width, int height, int step) + { + Mat img(height, width, CV_8UC3, pixels, step); + GaussianBlur(img, img, Size(7,7), 1.5, 1.5); + } + + .. + + #. + Quickly initialize small matrices and/or get a super-fast element access. + + :: + + double m[3][3] = {{a, b, c}, {d, e, f}, {g, h, i}}; + Mat M = Mat(3, 3, CV_64F, m).inv(); + + .. + + Partial yet very common cases of this *user-allocated data* case are conversions from ``CvMat`` and ``IplImage`` to ``Mat``. For this purpose, there are special constructors taking pointers to ``CvMat`` or ``IplImage`` and the optional flag indicating whether to copy the data or not. + + Backward conversion from ``Mat`` to ``CvMat`` or ``IplImage`` is provided via cast operators ``Mat::operator CvMat() const`` and ``Mat::operator IplImage()``. The operators do NOT copy the data. + + :: + + IplImage* img = cvLoadImage("greatwave.jpg", 1); + Mat mtx(img); // convert IplImage* -> Mat + CvMat oldmat = mtx; // convert Mat -> CvMat + CV_Assert(oldmat.cols == img->width && oldmat.rows == img->height && + oldmat.data.ptr == (uchar*)img->imageData && oldmat.step == img->widthStep); + + .. + +* + + Use MATLAB-style array initializers, ``zeros(), ones(), eye()``, for example: + + :: + + // create a double-precision identity martix and add it to M. + M += Mat::eye(M.rows, M.cols, CV_64F); + + .. + +* + + Use a comma-separated initializer: + + :: + + // create a 3x3 double-precision identity matrix + Mat M = (Mat_(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1); + + .. + + With this approach, you first call a constructor of the :ocv:class:`Mat_` class with the proper parameters, and then you just put ``<<`` operator followed by comma-separated values that can be constants, variables, expressions, and so on. Also, note the extra parentheses required to avoid compilation errors. + +Once the array is created, it is automatically managed via a reference-counting mechanism. If the array header is built on top of user-allocated data, you should handle the data by yourself. +The array data is deallocated when no one points to it. If you want to release the data pointed by a array header before the array destructor is called, use ``Mat::release()`` . + +The next important thing to learn about the array class is element access. This manual already described how to compute an address of each array element. Normally, you are not required to use the formula directly in the code. If you know the array element type (which can be retrieved using the method ``Mat::type()`` ), you can access the element +:math:`M_{ij}` of a 2-dimensional array as: :: + + M.at(i,j) += 1.f; + + +assuming that M is a double-precision floating-point array. There are several variants of the method ``at`` for a different number of dimensions. + +If you need to process a whole row of a 2D array, the most efficient way is to get the pointer to the row first, and then just use the plain C operator ``[]`` : :: + + // compute sum of positive matrix elements + // (assuming that M isa double-precision matrix) + double sum=0; + for(int i = 0; i < M.rows; i++) + { + const double* Mi = M.ptr(i); + for(int j = 0; j < M.cols; j++) + sum += std::max(Mi[j], 0.); + } + + +Some operations, like the one above, do not actually depend on the array shape. They just process elements of an array one by one (or elements from multiple arrays that have the same coordinates, for example, array addition). Such operations are called *element-wise*. It makes sense to check whether all the input/output arrays are continuous, namely, have no gaps at the end of each row. If yes, process them as a long single row: :: + + // compute the sum of positive matrix elements, optimized variant + double sum=0; + int cols = M.cols, rows = M.rows; + if(M.isContinuous()) + { + cols *= rows; + rows = 1; + } + for(int i = 0; i < rows; i++) + { + const double* Mi = M.ptr(i); + for(int j = 0; j < cols; j++) + sum += std::max(Mi[j], 0.); + } + + +In case of the continuous matrix, the outer loop body is executed just once. So, the overhead is smaller, which is especially noticeable in case of small matrices. + +Finally, there are STL-style iterators that are smart enough to skip gaps between successive rows: :: + + // compute sum of positive matrix elements, iterator-based variant + double sum=0; + MatConstIterator_ it = M.begin(), it_end = M.end(); + for(; it != it_end; ++it) + sum += std::max(*it, 0.); + + +The matrix iterators are random-access iterators, so they can be passed to any STL algorithm, including ``std::sort()`` . + + +.. _MatrixExpressions: + +Matrix Expressions +------------------ + +This is a list of implemented matrix operations that can be combined in arbitrary complex expressions +(here ``A``, ``B`` stand for matrices ( ``Mat`` ), ``s`` for a scalar ( ``Scalar`` ), +``alpha`` for a real-valued scalar ( ``double`` )): + +* + Addition, subtraction, negation: + ``A+B, A-B, A+s, A-s, s+A, s-A, -A`` + +* + Scaling: + ``A*alpha`` + +* + Per-element multiplication and division: + ``A.mul(B), A/B, alpha/A`` + +* + Matrix multiplication: + ``A*B`` + +* + Transposition: + ``A.t()`` (means ``A``\ :sup:`T`) + +* + Matrix inversion and pseudo-inversion, solving linear systems and least-squares problems: + + ``A.inv([method])`` (~ ``A``\ :sup:`-1`) ``, A.inv([method])*B`` (~ ``X: AX=B``) + +* + Comparison: + ``A cmpop B, A cmpop alpha, alpha cmpop A``, where ``cmpop`` is one of ``: >, >=, ==, !=, <=, <``. The result of comparison is an 8-bit single channel mask whose elements are set to 255 (if the particular element or pair of elements satisfy the condition) or 0. + +* + Bitwise logical operations: ``A logicop B, A logicop s, s logicop A, ~A``, where ``logicop`` is one of ``: &, |, ^``. + +* + Element-wise minimum and maximum: + ``min(A, B), min(A, alpha), max(A, B), max(A, alpha)`` + +* + Element-wise absolute value: + ``abs(A)`` + +* + Cross-product, dot-product: + ``A.cross(B)`` + ``A.dot(B)`` + +* + Any function of matrix or matrices and scalars that returns a matrix or a scalar, such as ``norm``, ``mean``, ``sum``, ``countNonZero``, ``trace``, ``determinant``, ``repeat``, and others. + +* + Matrix initializers ( ``Mat::eye(), Mat::zeros(), Mat::ones()`` ), matrix comma-separated initializers, matrix constructors and operators that extract sub-matrices (see :ocv:class:`Mat` description). + +* + ``Mat_()`` constructors to cast the result to the proper type. + +.. note:: Comma-separated initializers and probably some other operations may require additional explicit ``Mat()`` or ``Mat_()`` constructor calls to resolve a possible ambiguity. + +Here are examples of matrix expressions: + +:: + + // compute pseudo-inverse of A, equivalent to A.inv(DECOMP_SVD) + SVD svd(A); + Mat pinvA = svd.vt.t()*Mat::diag(1./svd.w)*svd.u.t(); + + // compute the new vector of parameters in the Levenberg-Marquardt algorithm + x -= (A.t()*A + lambda*Mat::eye(A.cols,A.cols,A.type())).inv(DECOMP_CHOLESKY)*(A.t()*err); + + // sharpen image using "unsharp mask" algorithm + Mat blurred; double sigma = 1, threshold = 5, amount = 1; + GaussianBlur(img, blurred, Size(), sigma, sigma); + Mat lowConstrastMask = abs(img - blurred) < threshold; + Mat sharpened = img*(1+amount) + blurred*(-amount); + img.copyTo(sharpened, lowContrastMask); + +.. + + +Below is the formal description of the ``Mat`` methods. + +Mat::Mat +-------- +Various Mat constructors + +.. ocv:function:: Mat::Mat() + +.. ocv:function:: Mat::Mat(int rows, int cols, int type) + +.. ocv:function:: Mat::Mat(Size size, int type) + +.. ocv:function:: Mat::Mat(int rows, int cols, int type, const Scalar& s) + +.. ocv:function:: Mat::Mat(Size size, int type, const Scalar& s) + +.. ocv:function:: Mat::Mat(const Mat& m) + +.. ocv:function:: Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP) + +.. ocv:function:: Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP) + +.. ocv:function:: Mat::Mat( const Mat& m, const Range& rowRange, const Range& colRange=Range::all() ) + +.. ocv:function:: Mat::Mat(const Mat& m, const Rect& roi) + +.. ocv:function:: Mat::Mat(const CvMat* m, bool copyData=false) + +.. ocv:function:: Mat::Mat(const IplImage* img, bool copyData=false) + +.. ocv:function:: template explicit Mat::Mat(const Vec& vec, bool copyData=true) + +.. ocv:function:: template explicit Mat::Mat(const Matx& vec, bool copyData=true) + +.. ocv:function:: template explicit Mat::Mat(const vector& vec, bool copyData=false) + +.. ocv:function:: Mat::Mat(int ndims, const int* sizes, int type) + +.. ocv:function:: Mat::Mat(int ndims, const int* sizes, int type, const Scalar& s) + +.. ocv:function:: Mat::Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0) + +.. ocv:function:: Mat::Mat(const Mat& m, const Range* ranges) + + :param ndims: Array dimensionality. + + :param rows: Number of rows in a 2D array. + + :param cols: Number of columns in a 2D array. + + :param roi: Region of interest. + + :param size: 2D array size: ``Size(cols, rows)`` . In the ``Size()`` constructor, the number of rows and the number of columns go in the reverse order. + + :param sizes: Array of integers specifying an n-dimensional array shape. + + :param type: Array type. Use ``CV_8UC1, ..., CV_64FC4`` to create 1-4 channel matrices, or ``CV_8UC(n), ..., CV_64FC(n)`` to create multi-channel (up to ``CV_MAX_CN`` channels) matrices. + + :param s: An optional value to initialize each matrix element with. To set all the matrix elements to the particular value after the construction, use the assignment operator ``Mat::operator=(const Scalar& value)`` . + + :param data: Pointer to the user data. Matrix constructors that take ``data`` and ``step`` parameters do not allocate matrix data. Instead, they just initialize the matrix header that points to the specified data, which means that no data is copied. This operation is very efficient and can be used to process external data using OpenCV functions. The external data is not automatically deallocated, so you should take care of it. + + :param step: Number of bytes each matrix row occupies. The value should include the padding bytes at the end of each row, if any. If the parameter is missing (set to ``AUTO_STEP`` ), no padding is assumed and the actual step is calculated as ``cols*elemSize()`` . See :ocv:func:`Mat::elemSize` . + + :param steps: Array of ``ndims-1`` steps in case of a multi-dimensional array (the last step is always set to the element size). If not specified, the matrix is assumed to be continuous. + + :param m: Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied by these constructors. Instead, the header pointing to ``m`` data or its sub-array is constructed and associated with it. The reference counter, if any, is incremented. So, when you modify the matrix formed using such a constructor, you also modify the corresponding elements of ``m`` . If you want to have an independent copy of the sub-array, use ``Mat::clone()`` . + + :param img: Pointer to the old-style ``IplImage`` image structure. By default, the data is shared between the original image and the new matrix. But when ``copyData`` is set, the full copy of the image data is created. + + :param vec: STL vector whose elements form the matrix. The matrix has a single column and the number of rows equal to the number of vector elements. Type of the matrix matches the type of vector elements. The constructor can handle arbitrary types, for which there is a properly declared :ocv:class:`DataType` . This means that the vector elements must be primitive numbers or uni-type numerical tuples of numbers. Mixed-type structures are not supported. The corresponding constructor is explicit. Since STL vectors are not automatically converted to ``Mat`` instances, you should write ``Mat(vec)`` explicitly. Unless you copy the data into the matrix ( ``copyData=true`` ), no new elements will be added to the vector because it can potentially yield vector data reallocation, and, thus, the matrix data pointer will be invalid. + + :param copyData: Flag to specify whether the underlying data of the STL vector or the old-style ``CvMat`` or ``IplImage`` should be copied to (``true``) or shared with (``false``) the newly constructed matrix. When the data is copied, the allocated buffer is managed using ``Mat`` reference counting mechanism. While the data is shared, the reference counter is NULL, and you should not deallocate the data until the matrix is not destructed. + + :param rowRange: Range of the ``m`` rows to take. As usual, the range start is inclusive and the range end is exclusive. Use ``Range::all()`` to take all the rows. + + :param colRange: Range of the ``m`` columns to take. Use ``Range::all()`` to take all the columns. + + :param ranges: Array of selected ranges of ``m`` along each dimensionality. + +These are various constructors that form a matrix. As noted in the :ref:`AutomaticAllocation`, +often the default constructor is enough, and the proper matrix will be allocated by an OpenCV function. The constructed matrix can further be assigned to another matrix or matrix expression or can be allocated with +:ocv:func:`Mat::create` . In the former case, the old content is de-referenced. + + +Mat::~Mat +--------- +The Mat destructor. + +.. ocv:function:: Mat::~Mat() + +The matrix destructor calls :ocv:func:`Mat::release` . + + +Mat::operator = +--------------- +Provides matrix assignment operators. + +.. ocv:function:: Mat& Mat::operator = (const Mat& m) + +.. ocv:function:: Mat& Mat::operator =( const MatExpr& expr ) + +.. ocv:function:: Mat& Mat::operator = (const Scalar& s) + + :param m: Assigned, right-hand-side matrix. Matrix assignment is an O(1) operation. This means that no data is copied but the data is shared and the reference counter, if any, is incremented. Before assigning new data, the old data is de-referenced via :ocv:func:`Mat::release` . + + :param expr: Assigned matrix expression object. As opposite to the first form of the assignment operation, the second form can reuse already allocated matrix if it has the right size and type to fit the matrix expression result. It is automatically handled by the real function that the matrix expressions is expanded to. For example, ``C=A+B`` is expanded to ``add(A, B, C)`` , and :func:`add` takes care of automatic ``C`` reallocation. + + :param s: Scalar assigned to each matrix element. The matrix size or type is not changed. + +These are available assignment operators. Since they all are very different, make sure to read the operator parameters description. + +Mat::row +-------- +Creates a matrix header for the specified matrix row. + +.. ocv:function:: Mat Mat::row(int y) const + + :param y: A 0-based row index. + +The method makes a new header for the specified matrix row and returns it. This is an O(1) operation, regardless of the matrix size. The underlying data of the new matrix is shared with the original matrix. Here is the example of one of the classical basic matrix processing operations, ``axpy``, used by LU and many other algorithms: :: + + inline void matrix_axpy(Mat& A, int i, int j, double alpha) + { + A.row(i) += A.row(j)*alpha; + } + + +.. note:: + + In the current implementation, the following code does not work as expected: :: + + Mat A; + ... + A.row(i) = A.row(j); // will not work + + + This happens because ``A.row(i)`` forms a temporary header that is further assigned to another header. Remember that each of these operations is O(1), that is, no data is copied. Thus, the above assignment is not true if you may have expected the j-th row to be copied to the i-th row. To achieve that, you should either turn this simple assignment into an expression or use the :ocv:func:`Mat::copyTo` method: :: + + Mat A; + ... + // works, but looks a bit obscure. + A.row(i) = A.row(j) + 0; + + // this is a bit longer, but the recommended method. + A.row(j).copyTo(A.row(i)); + +Mat::col +-------- +Creates a matrix header for the specified matrix column. + +.. ocv:function:: Mat Mat::col(int x) const + + :param x: A 0-based column index. + +The method makes a new header for the specified matrix column and returns it. This is an O(1) operation, regardless of the matrix size. The underlying data of the new matrix is shared with the original matrix. See also the +:ocv:func:`Mat::row` description. + + +Mat::rowRange +------------- +Creates a matrix header for the specified row span. + +.. ocv:function:: Mat Mat::rowRange(int startrow, int endrow) const + +.. ocv:function:: Mat Mat::rowRange(const Range& r) const + + :param startrow: An inclusive 0-based start index of the row span. + + :param endrow: An exclusive 0-based ending index of the row span. + + :param r: :ocv:class:`Range` structure containing both the start and the end indices. + +The method makes a new header for the specified row span of the matrix. Similarly to +:ocv:func:`Mat::row` and +:ocv:func:`Mat::col` , this is an O(1) operation. + +Mat::colRange +------------- +Creates a matrix header for the specified row span. + +.. ocv:function:: Mat Mat::colRange(int startcol, int endcol) const + +.. ocv:function:: Mat Mat::colRange(const Range& r) const + + :param startcol: An inclusive 0-based start index of the column span. + + :param endcol: An exclusive 0-based ending index of the column span. + + :param r: :ocv:class:`Range` structure containing both the start and the end indices. + +The method makes a new header for the specified column span of the matrix. Similarly to +:ocv:func:`Mat::row` and +:ocv:func:`Mat::col` , this is an O(1) operation. + +Mat::diag +--------- +Extracts a diagonal from a matrix, or creates a diagonal matrix. + +.. ocv:function:: Mat Mat::diag( int d=0 ) const + +.. ocv:function:: static Mat Mat::diag( const Mat& d ) + + :param d: Single-column matrix that forms a diagonal matrix or index of the diagonal, with the following values: + + * **d=0** is the main diagonal. + + * **d>0** is a diagonal from the lower half. For example, ``d=1`` means the diagonal is set immediately below the main one. + + * **d<0** is a diagonal from the upper half. For example, ``d=1`` means the diagonal is set immediately above the main one. + +The method makes a new header for the specified matrix diagonal. The new matrix is represented as a single-column matrix. Similarly to +:ocv:func:`Mat::row` and +:ocv:func:`Mat::col` , this is an O(1) operation. + +Mat::clone +---------- +Creates a full copy of the array and the underlying data. + +.. ocv:function:: Mat Mat::clone() const + +The method creates a full copy of the array. The original ``step[]`` is not taken into account. So, the array copy is a continuous array occupying ``total()*elemSize()`` bytes. + + +Mat::copyTo +----------- +Copies the matrix to another one. + +.. ocv:function:: void Mat::copyTo( OutputArray m ) const +.. ocv:function:: void Mat::copyTo( OutputArray m, InputArray mask ) const + + :param m: Destination matrix. If it does not have a proper size or type before the operation, it is reallocated. + + :param mask: Operation mask. Its non-zero elements indicate which matrix elements need to be copied. + +The method copies the matrix data to another matrix. Before copying the data, the method invokes :: + + m.create(this->size(), this->type); + + +so that the destination matrix is reallocated if needed. While ``m.copyTo(m);`` works flawlessly, the function does not handle the case of a partial overlap between the source and the destination matrices. + +When the operation mask is specified, and the ``Mat::create`` call shown above reallocated the matrix, the newly allocated matrix is initialized with all zeros before copying the data. + +.. _Mat::convertTo: + +Mat::convertTo +-------------- +Converts an array to another data type with optional scaling. + +.. ocv:function:: void Mat::convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const + + :param m: output matrix; if it does not have a proper size or type before the operation, it is reallocated. + + :param rtype: desired output matrix type or, rather, the depth since the number of channels are the same as the input has; if ``rtype`` is negative, the output matrix will have the same type as the input. + + :param alpha: optional scale factor. + + :param beta: optional delta added to the scaled values. + +The method converts source pixel values to the target data type. ``saturate_cast<>`` is applied at the end to avoid possible overflows: + +.. math:: + + m(x,y) = saturate \_ cast( \alpha (*this)(x,y) + \beta ) + + +Mat::assignTo +------------- +Provides a functional form of ``convertTo``. + +.. ocv:function:: void Mat::assignTo( Mat& m, int type=-1 ) const + + :param m: Destination array. + + :param type: Desired destination array depth (or -1 if it should be the same as the source type). + +This is an internally used method called by the +:ref:`MatrixExpressions` engine. + +Mat::setTo +---------- +Sets all or some of the array elements to the specified value. + +.. ocv:function:: Mat& Mat::setTo( InputArray value, InputArray mask=noArray() ) + + :param value: Assigned scalar converted to the actual array type. + + :param mask: Operation mask of the same size as ``*this``. This is an advanced variant of the ``Mat::operator=(const Scalar& s)`` operator. + + +Mat::reshape +------------ +Changes the shape and/or the number of channels of a 2D matrix without copying the data. + +.. ocv:function:: Mat Mat::reshape(int cn, int rows=0) const + + :param cn: New number of channels. If the parameter is 0, the number of channels remains the same. + + :param rows: New number of rows. If the parameter is 0, the number of rows remains the same. + +The method makes a new matrix header for ``*this`` elements. The new matrix may have a different size and/or different number of channels. Any combination is possible if: + +* + No extra elements are included into the new matrix and no elements are excluded. Consequently, the product ``rows*cols*channels()`` must stay the same after the transformation. + +* + No data is copied. That is, this is an O(1) operation. Consequently, if you change the number of rows, or the operation changes the indices of elements row in some other way, the matrix must be continuous. See + :ocv:func:`Mat::isContinuous` . + +For example, if there is a set of 3D points stored as an STL vector, and you want to represent the points as a ``3xN`` matrix, do the following: :: + + std::vector vec; + ... + + Mat pointMat = Mat(vec). // convert vector to Mat, O(1) operation + reshape(1). // make Nx3 1-channel matrix out of Nx1 3-channel. + // Also, an O(1) operation + t(); // finally, transpose the Nx3 matrix. + // This involves copying all the elements + + + + +Mat::t +------ +Transposes a matrix. + +.. ocv:function:: MatExpr Mat::t() const + +The method performs matrix transposition by means of matrix expressions. It does not perform the actual transposition but returns a temporary matrix transposition object that can be further used as a part of more complex matrix expressions or can be assigned to a matrix: :: + + Mat A1 = A + Mat::eye(A.size(), A.type)*lambda; + Mat C = A1.t()*A1; // compute (A + lambda*I)^t * (A + lamda*I) + + +Mat::inv +-------- +Inverses a matrix. + +.. ocv:function:: MatExpr Mat::inv(int method=DECOMP_LU) const + + :param method: Matrix inversion method. Possible values are the following: + + * **DECOMP_LU** is the LU decomposition. The matrix must be non-singular. + + * **DECOMP_CHOLESKY** is the Cholesky :math:`LL^T` decomposition for symmetrical positively defined matrices only. This type is about twice faster than LU on big matrices. + + * **DECOMP_SVD** is the SVD decomposition. If the matrix is singular or even non-square, the pseudo inversion is computed. + +The method performs a matrix inversion by means of matrix expressions. This means that a temporary matrix inversion object is returned by the method and can be used further as a part of more complex matrix expressions or can be assigned to a matrix. + + +Mat::mul +-------- +Performs an element-wise multiplication or division of the two matrices. + +.. ocv:function:: MatExpr Mat::mul(InputArray m, double scale=1) const + + :param m: Another array of the same type and the same size as ``*this``, or a matrix expression. + + :param scale: Optional scale factor. + +The method returns a temporary object encoding per-element array multiplication, with optional scale. Note that this is not a matrix multiplication that corresponds to a simpler "*" operator. + +Example: :: + + Mat C = A.mul(5/B); // equivalent to divide(A, B, C, 5) + + +Mat::cross +---------- +Computes a cross-product of two 3-element vectors. + +.. ocv:function:: Mat Mat::cross(InputArray m) const + + :param m: Another cross-product operand. + +The method computes a cross-product of two 3-element vectors. The vectors must be 3-element floating-point vectors of the same shape and size. The result is another 3-element vector of the same shape and type as operands. + + +Mat::dot +-------- +Computes a dot-product of two vectors. + +.. ocv:function:: double Mat::dot(InputArray m) const + + :param m: another dot-product operand. + +The method computes a dot-product of two matrices. If the matrices are not single-column or single-row vectors, the top-to-bottom left-to-right scan ordering is used to treat them as 1D vectors. The vectors must have the same size and type. If the matrices have more than one channel, the dot products from all the channels are summed together. + + +Mat::zeros +---------- +Returns a zero array of the specified size and type. + +.. ocv:function:: static MatExpr Mat::zeros(int rows, int cols, int type) +.. ocv:function:: static MatExpr Mat::zeros(Size size, int type) +.. ocv:function:: static MatExpr Mat::zeros( int ndims, const int* sz, int type ) + + :param ndims: Array dimensionality. + + :param rows: Number of rows. + + :param cols: Number of columns. + + :param size: Alternative to the matrix size specification ``Size(cols, rows)`` . + + :param sz: Array of integers specifying the array shape. + + :param type: Created matrix type. + +The method returns a Matlab-style zero array initializer. It can be used to quickly form a constant array as a function parameter, part of a matrix expression, or as a matrix initializer. :: + + Mat A; + A = Mat::zeros(3, 3, CV_32F); + + +In the example above, a new matrix is allocated only if ``A`` is not a 3x3 floating-point matrix. Otherwise, the existing matrix ``A`` is filled with zeros. + + +Mat::ones +------------- +Returns an array of all 1's of the specified size and type. + +.. ocv:function:: static MatExpr Mat::ones(int rows, int cols, int type) +.. ocv:function:: static MatExpr Mat::ones(Size size, int type) +.. ocv:function:: static MatExpr Mat::ones( int ndims, const int* sz, int type ) + + :param ndims: Array dimensionality. + + :param rows: Number of rows. + + :param cols: Number of columns. + + :param size: Alternative to the matrix size specification ``Size(cols, rows)`` . + + :param sz: Array of integers specifying the array shape. + + :param type: Created matrix type. + +The method returns a Matlab-style 1's array initializer, similarly to +:ocv:func:`Mat::zeros`. Note that using this method you can initialize an array with an arbitrary value, using the following Matlab idiom: :: + + Mat A = Mat::ones(100, 100, CV_8U)*3; // make 100x100 matrix filled with 3. + + +The above operation does not form a 100x100 matrix of 1's and then multiply it by 3. Instead, it just remembers the scale factor (3 in this case) and use it when actually invoking the matrix initializer. + + +Mat::eye +------------ +Returns an identity matrix of the specified size and type. + +.. ocv:function:: static MatExpr Mat::eye(int rows, int cols, int type) +.. ocv:function:: static MatExpr Mat::eye(Size size, int type) + + :param rows: Number of rows. + + :param cols: Number of columns. + + :param size: Alternative matrix size specification as ``Size(cols, rows)`` . + + :param type: Created matrix type. + +The method returns a Matlab-style identity matrix initializer, similarly to +:ocv:func:`Mat::zeros`. Similarly to +:ocv:func:`Mat::ones`, you can use a scale operation to create a scaled identity matrix efficiently: :: + + // make a 4x4 diagonal matrix with 0.1's on the diagonal. + Mat A = Mat::eye(4, 4, CV_32F)*0.1; + + +Mat::create +--------------- +Allocates new array data if needed. + +.. ocv:function:: void Mat::create(int rows, int cols, int type) +.. ocv:function:: void Mat::create(Size size, int type) +.. ocv:function:: void Mat::create(int ndims, const int* sizes, int type) + + :param ndims: New array dimensionality. + + :param rows: New number of rows. + + :param cols: New number of columns. + + :param size: Alternative new matrix size specification: ``Size(cols, rows)`` + + :param sizes: Array of integers specifying a new array shape. + + :param type: New matrix type. + +This is one of the key ``Mat`` methods. Most new-style OpenCV functions and methods that produce arrays call this method for each output array. The method uses the following algorithm: + +#. + If the current array shape and the type match the new ones, return immediately. Otherwise, de-reference the previous data by calling + :ocv:func:`Mat::release`. + +#. + Initialize the new header. + +#. + Allocate the new data of ``total()*elemSize()`` bytes. + +#. + Allocate the new, associated with the data, reference counter and set it to 1. + +Such a scheme makes the memory management robust and efficient at the same time and helps avoid extra typing for you. This means that usually there is no need to explicitly allocate output arrays. That is, instead of writing: :: + + Mat color; + ... + Mat gray(color.rows, color.cols, color.depth()); + cvtColor(color, gray, CV_BGR2GRAY); + + +you can simply write: :: + + Mat color; + ... + Mat gray; + cvtColor(color, gray, CV_BGR2GRAY); + + +because ``cvtColor`` , as well as the most of OpenCV functions, calls ``Mat::create()`` for the output array internally. + + +Mat::addref +--------------- +Increments the reference counter. + +.. ocv:function:: void Mat::addref() + +The method increments the reference counter associated with the matrix data. If the matrix header points to an external data set (see +:ocv:func:`Mat::Mat` ), the reference counter is NULL, and the method has no effect in this case. Normally, to avoid memory leaks, the method should not be called explicitly. It is called implicitly by the matrix assignment operator. The reference counter increment is an atomic operation on the platforms that support it. Thus, it is safe to operate on the same matrices asynchronously in different threads. + + +Mat::release +---------------- +Decrements the reference counter and deallocates the matrix if needed. + +.. ocv:function:: void Mat::release() + +The method decrements the reference counter associated with the matrix data. When the reference counter reaches 0, the matrix data is deallocated and the data and the reference counter pointers are set to NULL's. If the matrix header points to an external data set (see +:ocv:func:`Mat::Mat` ), the reference counter is NULL, and the method has no effect in this case. + +This method can be called manually to force the matrix data deallocation. But since this method is automatically called in the destructor, or by any other method that changes the data pointer, it is usually not needed. The reference counter decrement and check for 0 is an atomic operation on the platforms that support it. Thus, it is safe to operate on the same matrices asynchronously in different threads. + +Mat::resize +--------------- +Changes the number of matrix rows. + +.. ocv:function:: void Mat::resize( size_t sz ) +.. ocv:function:: void Mat::resize( size_t sz, const Scalar& s ) + + :param sz: New number of rows. + :param s: Value assigned to the newly added elements. + +The methods change the number of matrix rows. If the matrix is reallocated, the first ``min(Mat::rows, sz)`` rows are preserved. The methods emulate the corresponding methods of the STL vector class. + + +Mat::reserve +--------------- +Reserves space for the certain number of rows. + +.. ocv:function:: void Mat::reserve( size_t sz ) + + :param sz: Number of rows. + +The method reserves space for ``sz`` rows. If the matrix already has enough space to store ``sz`` rows, nothing happens. If the matrix is reallocated, the first ``Mat::rows`` rows are preserved. The method emulates the corresponding method of the STL vector class. + +Mat::push_back +-------------- +Adds elements to the bottom of the matrix. + +.. ocv:function:: template void Mat::push_back(const T& elem) + +.. ocv:function:: void Mat::push_back( const Mat& m ) + + :param elem: Added element(s). + +The methods add one or more elements to the bottom of the matrix. They emulate the corresponding method of the STL vector class. When ``elem`` is ``Mat`` , its type and the number of columns must be the same as in the container matrix. + +Mat::pop_back +------------- +Removes elements from the bottom of the matrix. + +.. ocv:function:: template void Mat::pop_back(size_t nelems=1) + + :param nelems: Number of removed rows. If it is greater than the total number of rows, an exception is thrown. + +The method removes one or more rows from the bottom of the matrix. + + +Mat::locateROI +------------------ +Locates the matrix header within a parent matrix. + +.. ocv:function:: void Mat::locateROI( Size& wholeSize, Point& ofs ) const + + :param wholeSize: Output parameter that contains the size of the whole matrix containing ``*this`` as a part. + + :param ofs: Output parameter that contains an offset of ``*this`` inside the whole matrix. + +After you extracted a submatrix from a matrix using +:ocv:func:`Mat::row`, +:ocv:func:`Mat::col`, +:ocv:func:`Mat::rowRange`, +:ocv:func:`Mat::colRange` , and others, the resultant submatrix points just to the part of the original big matrix. However, each submatrix contains information (represented by ``datastart`` and ``dataend`` fields) that helps reconstruct the original matrix size and the position of the extracted submatrix within the original matrix. The method ``locateROI`` does exactly that. + + +Mat::adjustROI +------------------ +Adjusts a submatrix size and position within the parent matrix. + +.. ocv:function:: Mat& Mat::adjustROI( int dtop, int dbottom, int dleft, int dright ) + + :param dtop: Shift of the top submatrix boundary upwards. + + :param dbottom: Shift of the bottom submatrix boundary downwards. + + :param dleft: Shift of the left submatrix boundary to the left. + + :param dright: Shift of the right submatrix boundary to the right. + +The method is complimentary to +:ocv:func:`Mat::locateROI` . The typical use of these functions is to determine the submatrix position within the parent matrix and then shift the position somehow. Typically, it can be required for filtering operations when pixels outside of the ROI should be taken into account. When all the method parameters are positive, the ROI needs to grow in all directions by the specified amount, for example: :: + + A.adjustROI(2, 2, 2, 2); + + +In this example, the matrix size is increased by 4 elements in each direction. The matrix is shifted by 2 elements to the left and 2 elements up, which brings in all the necessary pixels for the filtering with the 5x5 kernel. + +``adjustROI`` forces the adjusted ROI to be inside of the parent matrix that is boundaries of the adjusted ROI are constrained by boundaries of the parent matrix. For example, if the submatrix ``A`` is located in the first row of a parent matrix and you called ``A.adjustROI(2, 2, 2, 2)`` then ``A`` will not be increased in the upward direction. + +The function is used internally by the OpenCV filtering functions, like +:ocv:func:`filter2D` , morphological operations, and so on. + +.. seealso:: :ocv:func:`copyMakeBorder` + + +Mat::operator() +------------------- +Extracts a rectangular submatrix. + +.. ocv:function:: Mat Mat::operator()( Range rowRange, Range colRange ) const + +.. ocv:function:: Mat Mat::operator()( const Rect& roi ) const + +.. ocv:function:: Mat Mat::operator()( const Range* ranges ) const + + + :param rowRange: Start and end row of the extracted submatrix. The upper boundary is not included. To select all the rows, use ``Range::all()``. + + :param colRange: Start and end column of the extracted submatrix. The upper boundary is not included. To select all the columns, use ``Range::all()``. + + :param roi: Extracted submatrix specified as a rectangle. + + :param ranges: Array of selected ranges along each array dimension. + +The operators make a new header for the specified sub-array of ``*this`` . They are the most generalized forms of +:ocv:func:`Mat::row`, +:ocv:func:`Mat::col`, +:ocv:func:`Mat::rowRange`, and +:ocv:func:`Mat::colRange` . For example, ``A(Range(0, 10), Range::all())`` is equivalent to ``A.rowRange(0, 10)`` . Similarly to all of the above, the operators are O(1) operations, that is, no matrix data is copied. + + +Mat::operator CvMat +------------------- +Creates the ``CvMat`` header for the matrix. + +.. ocv:function:: Mat::operator CvMat() const + + +The operator creates the ``CvMat`` header for the matrix without copying the underlying data. The reference counter is not taken into account by this operation. Thus, you should make sure than the original matrix is not deallocated while the ``CvMat`` header is used. The operator is useful for intermixing the new and the old OpenCV API's, for example: :: + + Mat img(Size(320, 240), CV_8UC3); + ... + + CvMat cvimg = img; + mycvOldFunc( &cvimg, ...); + + +where ``mycvOldFunc`` is a function written to work with OpenCV 1.x data structures. + + +Mat::operator IplImage +---------------------- +Creates the ``IplImage`` header for the matrix. + +.. ocv:function:: Mat::operator IplImage() const + +The operator creates the ``IplImage`` header for the matrix without copying the underlying data. You should make sure than the original matrix is not deallocated while the ``IplImage`` header is used. Similarly to ``Mat::operator CvMat`` , the operator is useful for intermixing the new and the old OpenCV API's. + +Mat::total +---------- +Returns the total number of array elements. + +.. ocv:function:: size_t Mat::total() const + +The method returns the number of array elements (a number of pixels if the array represents an image). + +Mat::isContinuous +----------------- +Reports whether the matrix is continuous or not. + +.. ocv:function:: bool Mat::isContinuous() const + +The method returns ``true`` if the matrix elements are stored continuously without gaps at the end of each row. Otherwise, it returns ``false``. Obviously, ``1x1`` or ``1xN`` matrices are always continuous. Matrices created with +:ocv:func:`Mat::create` are always continuous. But if you extract a part of the matrix using +:ocv:func:`Mat::col`, +:ocv:func:`Mat::diag` , and so on, or constructed a matrix header for externally allocated data, such matrices may no longer have this property. + +The continuity flag is stored as a bit in the ``Mat::flags`` field and is computed automatically when you construct a matrix header. Thus, the continuity check is a very fast operation, though theoretically it could be done as follows: :: + + // alternative implementation of Mat::isContinuous() + bool myCheckMatContinuity(const Mat& m) + { + //return (m.flags & Mat::CONTINUOUS_FLAG) != 0; + return m.rows == 1 || m.step == m.cols*m.elemSize(); + } + + +The method is used in quite a few of OpenCV functions. The point is that element-wise operations (such as arithmetic and logical operations, math functions, alpha blending, color space transformations, and others) do not depend on the image geometry. Thus, if all the input and output arrays are continuous, the functions can process them as very long single-row vectors. The example below illustrates how an alpha-blending function can be implemented. :: + + template + void alphaBlendRGBA(const Mat& src1, const Mat& src2, Mat& dst) + { + const float alpha_scale = (float)std::numeric_limits::max(), + inv_scale = 1.f/alpha_scale; + + CV_Assert( src1.type() == src2.type() && + src1.type() == CV_MAKETYPE(DataType::depth, 4) && + src1.size() == src2.size()); + Size size = src1.size(); + dst.create(size, src1.type()); + + // here is the idiom: check the arrays for continuity and, + // if this is the case, + // treat the arrays as 1D vectors + if( src1.isContinuous() && src2.isContinuous() && dst.isContinuous() ) + { + size.width *= size.height; + size.height = 1; + } + size.width *= 4; + + for( int i = 0; i < size.height; i++ ) + { + // when the arrays are continuous, + // the outer loop is executed only once + const T* ptr1 = src1.ptr(i); + const T* ptr2 = src2.ptr(i); + T* dptr = dst.ptr(i); + + for( int j = 0; j < size.width; j += 4 ) + { + float alpha = ptr1[j+3]*inv_scale, beta = ptr2[j+3]*inv_scale; + dptr[j] = saturate_cast(ptr1[j]*alpha + ptr2[j]*beta); + dptr[j+1] = saturate_cast(ptr1[j+1]*alpha + ptr2[j+1]*beta); + dptr[j+2] = saturate_cast(ptr1[j+2]*alpha + ptr2[j+2]*beta); + dptr[j+3] = saturate_cast((1 - (1-alpha)*(1-beta))*alpha_scale); + } + } + } + + +This approach, while being very simple, can boost the performance of a simple element-operation by 10-20 percents, especially if the image is rather small and the operation is quite simple. + +Another OpenCV idiom in this function, a call of +:ocv:func:`Mat::create` for the destination array, that allocates the destination array unless it already has the proper size and type. And while the newly allocated arrays are always continuous, you still need to check the destination array because :ocv:func:`Mat::create` does not always allocate a new matrix. + + +Mat::elemSize +------------- +Returns the matrix element size in bytes. + +.. ocv:function:: size_t Mat::elemSize() const + +The method returns the matrix element size in bytes. For example, if the matrix type is ``CV_16SC3`` , the method returns ``3*sizeof(short)`` or 6. + + +Mat::elemSize1 +-------------- +Returns the size of each matrix element channel in bytes. + +.. ocv:function:: size_t Mat::elemSize1() const + +The method returns the matrix element channel size in bytes, that is, it ignores the number of channels. For example, if the matrix type is ``CV_16SC3`` , the method returns ``sizeof(short)`` or 2. + + +Mat::type +--------- +Returns the type of a matrix element. + +.. ocv:function:: int Mat::type() const + +The method returns a matrix element type. This is an identifier compatible with the ``CvMat`` type system, like ``CV_16SC3`` or 16-bit signed 3-channel array, and so on. + + +Mat::depth +---------- +Returns the depth of a matrix element. + +.. ocv:function:: int Mat::depth() const + +The method returns the identifier of the matrix element depth (the type of each individual channel). For example, for a 16-bit signed 3-channel array, the method returns ``CV_16S`` . A complete list of matrix types contains the following values: + +* ``CV_8U`` - 8-bit unsigned integers ( ``0..255`` ) + +* ``CV_8S`` - 8-bit signed integers ( ``-128..127`` ) + +* ``CV_16U`` - 16-bit unsigned integers ( ``0..65535`` ) + +* ``CV_16S`` - 16-bit signed integers ( ``-32768..32767`` ) + +* ``CV_32S`` - 32-bit signed integers ( ``-2147483648..2147483647`` ) + +* ``CV_32F`` - 32-bit floating-point numbers ( ``-FLT_MAX..FLT_MAX, INF, NAN`` ) + +* ``CV_64F`` - 64-bit floating-point numbers ( ``-DBL_MAX..DBL_MAX, INF, NAN`` ) + + +Mat::channels +------------- +Returns the number of matrix channels. + +.. ocv:function:: int Mat::channels() const + +The method returns the number of matrix channels. + + +Mat::step1 +---------- +Returns a normalized step. + +.. ocv:function:: size_t Mat::step1( int i=0 ) const + +The method returns a matrix step divided by +:ocv:func:`Mat::elemSize1()` . It can be useful to quickly access an arbitrary matrix element. + + +Mat::size +--------- +Returns a matrix size. + +.. ocv:function:: Size Mat::size() const + +The method returns a matrix size: ``Size(cols, rows)`` . When the matrix is more than 2-dimensional, the returned size is (-1, -1). + + +Mat::empty +---------- +Returns ``true`` if the array has no elements. + +.. ocv:function:: bool Mat::empty() const + +The method returns ``true`` if ``Mat::total()`` is 0 or if ``Mat::data`` is NULL. Because of ``pop_back()`` and ``resize()`` methods ``M.total() == 0`` does not imply that ``M.data == NULL`` . + + +Mat::ptr +-------- +Returns a pointer to the specified matrix row. + +.. ocv:function:: uchar* Mat::ptr(int i0=0) + +.. ocv:function:: const uchar* Mat::ptr(int i0=0) const + +.. ocv:function:: template _Tp* Mat::ptr(int i0=0) + +.. ocv:function:: template const _Tp* Mat::ptr(int i0=0) const + + :param i0: A 0-based row index. + +The methods return ``uchar*`` or typed pointer to the specified matrix row. See the sample in +:ocv:func:`Mat::isContinuous` to know how to use these methods. + + +Mat::at +------- +Returns a reference to the specified array element. + +.. ocv:function:: template T& Mat::at(int i) const + +.. ocv:function:: template const T& Mat::at(int i) const + +.. ocv:function:: template T& Mat::at(int i, int j) + +.. ocv:function:: template const T& Mat::at(int i, int j) const + +.. ocv:function:: template T& Mat::at(Point pt) + +.. ocv:function:: template const T& Mat::at(Point pt) const + +.. ocv:function:: template T& Mat::at(int i, int j, int k) + +.. ocv:function:: template const T& Mat::at(int i, int j, int k) const + +.. ocv:function:: template T& Mat::at(const int* idx) + +.. ocv:function:: template const T& Mat::at(const int* idx) const + + :param i: Index along the dimension 0 + :param j: Index along the dimension 1 + :param k: Index along the dimension 2 + + :param pt: Element position specified as ``Point(j,i)`` . + + :param idx: Array of ``Mat::dims`` indices. + +The template methods return a reference to the specified array element. For the sake of higher performance, the index range checks are only performed in the Debug configuration. + +Note that the variants with a single index (i) can be used to access elements of single-row or single-column 2-dimensional arrays. That is, if, for example, ``A`` is a ``1 x N`` floating-point matrix and ``B`` is an ``M x 1`` integer matrix, you can simply write ``A.at(k+4)`` and ``B.at(2*i+1)`` instead of ``A.at(0,k+4)`` and ``B.at(2*i+1,0)`` , respectively. + +The example below initializes a Hilbert matrix: :: + + Mat H(100, 100, CV_64F); + for(int i = 0; i < H.rows; i++) + for(int j = 0; j < H.cols; j++) + H.at(i,j)=1./(i+j+1); + + + +Mat::begin +-------------- +Returns the matrix iterator and sets it to the first matrix element. + +.. ocv:function:: template MatIterator_<_Tp> Mat::begin() + +.. ocv:function:: template MatConstIterator_<_Tp> Mat::begin() const + +The methods return the matrix read-only or read-write iterators. The use of matrix iterators is very similar to the use of bi-directional STL iterators. In the example below, the alpha blending function is rewritten using the matrix iterators: :: + + template + void alphaBlendRGBA(const Mat& src1, const Mat& src2, Mat& dst) + { + typedef Vec VT; + + const float alpha_scale = (float)std::numeric_limits::max(), + inv_scale = 1.f/alpha_scale; + + CV_Assert( src1.type() == src2.type() && + src1.type() == DataType::type && + src1.size() == src2.size()); + Size size = src1.size(); + dst.create(size, src1.type()); + + MatConstIterator_ it1 = src1.begin(), it1_end = src1.end(); + MatConstIterator_ it2 = src2.begin(); + MatIterator_ dst_it = dst.begin(); + + for( ; it1 != it1_end; ++it1, ++it2, ++dst_it ) + { + VT pix1 = *it1, pix2 = *it2; + float alpha = pix1[3]*inv_scale, beta = pix2[3]*inv_scale; + *dst_it = VT(saturate_cast(pix1[0]*alpha + pix2[0]*beta), + saturate_cast(pix1[1]*alpha + pix2[1]*beta), + saturate_cast(pix1[2]*alpha + pix2[2]*beta), + saturate_cast((1 - (1-alpha)*(1-beta))*alpha_scale)); + } + } + + + +Mat::end +------------ +Returns the matrix iterator and sets it to the after-last matrix element. + +.. ocv:function:: template MatIterator_<_Tp> Mat::end() + +.. ocv:function:: template MatConstIterator_<_Tp> Mat::end() const + +The methods return the matrix read-only or read-write iterators, set to the point following the last matrix element. + +Mat\_ +----- +.. ocv:class:: Mat_ + +Template matrix class derived from +:ocv:class:`Mat` . :: + + template class Mat_ : public Mat + { + public: + // ... some specific methods + // and + // no new extra fields + }; + + +The class ``Mat_<_Tp>`` is a "thin" template wrapper on top of the ``Mat`` class. It does not have any extra data fields. Nor this class nor ``Mat`` has any virtual methods. Thus, references or pointers to these two classes can be freely but carefully converted one to another. For example: :: + + // create a 100x100 8-bit matrix + Mat M(100,100,CV_8U); + // this will be compiled fine. no any data conversion will be done. + Mat_& M1 = (Mat_&)M; + // the program is likely to crash at the statement below + M1(99,99) = 1.f; + + +While ``Mat`` is sufficient in most cases, ``Mat_`` can be more convenient if you use a lot of element access operations and if you know matrix type at the compilation time. Note that ``Mat::at<_Tp>(int y, int x)`` and ``Mat_<_Tp>::operator ()(int y, int x)`` do absolutely the same and run at the same speed, but the latter is certainly shorter: :: + + Mat_ M(20,20); + for(int i = 0; i < M.rows; i++) + for(int j = 0; j < M.cols; j++) + M(i,j) = 1./(i+j+1); + Mat E, V; + eigen(M,E,V); + cout << E.at(0,0)/E.at(M.rows-1,0); + + +To use ``Mat_`` for multi-channel images/matrices, pass ``Vec`` as a ``Mat_`` parameter: :: + + // allocate a 320x240 color image and fill it with green (in RGB space) + Mat_ img(240, 320, Vec3b(0,255,0)); + // now draw a diagonal white line + for(int i = 0; i < 100; i++) + img(i,i)=Vec3b(255,255,255); + // and now scramble the 2nd (red) channel of each pixel + for(int i = 0; i < img.rows; i++) + for(int j = 0; j < img.cols; j++) + img(i,j)[2] ^= (uchar)(i ^ j); + + +InputArray +---------- +.. ocv:class:: InputArray + +This is the proxy class for passing read-only input arrays into OpenCV functions. It is defined as :: + + typedef const _InputArray& InputArray; + +where ``_InputArray`` is a class that can be constructed from ``Mat``, ``Mat_``, ``Matx``, ``std::vector``, ``std::vector >`` or ``std::vector``. It can also be constructed from a matrix expression. + +Since this is mostly implementation-level class, and its interface may change in future versions, we do not describe it in details. There are a few key things, though, that should be kept in mind: + + * When you see in the reference manual or in OpenCV source code a function that takes ``InputArray``, it means that you can actually pass ``Mat``, ``Matx``, ``vector`` etc. (see above the complete list). + + * Optional input arguments: If some of the input arrays may be empty, pass ``cv::noArray()`` (or simply ``cv::Mat()`` as you probably did before). + + * The class is designed solely for passing parameters. That is, normally you *should not* declare class members, local and global variables of this type. + + * If you want to design your own function or a class method that can operate of arrays of multiple types, you can use ``InputArray`` (or ``OutputArray``) for the respective parameters. Inside a function you should use ``_InputArray::getMat()`` method to construct a matrix header for the array (without copying data). ``_InputArray::kind()`` can be used to distinguish ``Mat`` from ``vector<>`` etc., but normally it is not needed. + +Here is how you can use a function that takes ``InputArray`` :: + + std::vector vec; + // points or a circle + for( int i = 0; i < 30; i++ ) + vec.push_back(Point2f((float)(100 + 30*cos(i*CV_PI*2/5)), + (float)(100 - 30*sin(i*CV_PI*2/5)))); + cv::transform(vec, vec, cv::Matx23f(0.707, -0.707, 10, 0.707, 0.707, 20)); + +That is, we form an STL vector containing points, and apply in-place affine transformation to the vector using the 2x3 matrix created inline as ``Matx`` instance. + +Here is how such a function can be implemented (for simplicity, we implement a very specific case of it, according to the assertion statement inside) :: + + void myAffineTransform(InputArray _src, OutputArray _dst, InputArray _m) + { + // get Mat headers for input arrays. This is O(1) operation, + // unless _src and/or _m are matrix expressions. + Mat src = _src.getMat(), m = _m.getMat(); + CV_Assert( src.type() == CV_32FC2 && m.type() == CV_32F && m.size() == Size(3, 2) ); + + // [re]create the output array so that it has the proper size and type. + // In case of Mat it calls Mat::create, in case of STL vector it calls vector::resize. + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + + for( int i = 0; i < src.rows; i++ ) + for( int j = 0; j < src.cols; j++ ) + { + Point2f pt = src.at(i, j); + dst.at(i, j) = Point2f(m.at(0, 0)*pt.x + + m.at(0, 1)*pt.y + + m.at(0, 2), + m.at(1, 0)*pt.x + + m.at(1, 1)*pt.y + + m.at(1, 2)); + } + } + +There is another related type, ``InputArrayOfArrays``, which is currently defined as a synonym for ``InputArray``: :: + + typedef InputArray InputArrayOfArrays; + +It denotes function arguments that are either vectors of vectors or vectors of matrices. A separate synonym is needed to generate Python/Java etc. wrappers properly. At the function implementation level their use is similar, but ``_InputArray::getMat(idx)`` should be used to get header for the idx-th component of the outer vector and ``_InputArray::size().area()`` should be used to find the number of components (vectors/matrices) of the outer vector. + + +OutputArray +----------- +.. ocv:class:: OutputArray : public InputArray + +This type is very similar to ``InputArray`` except that it is used for input/output and output function parameters. Just like with ``InputArray``, OpenCV users should not care about ``OutputArray``, they just pass ``Mat``, ``vector`` etc. to the functions. The same limitation as for ``InputArray``: **Do not explicitly create OutputArray instances** applies here too. + +If you want to make your function polymorphic (i.e. accept different arrays as output parameters), it is also not very difficult. Take the sample above as the reference. Note that ``_OutputArray::create()`` needs to be called before ``_OutputArray::getMat()``. This way you guarantee that the output array is properly allocated. + +Optional output parameters. If you do not need certain output array to be computed and returned to you, pass ``cv::noArray()``, just like you would in the case of optional input array. At the implementation level, use ``_OutputArray::needed()`` to check if certain output array needs to be computed or not. + +There are several synonyms for ``OutputArray`` that are used to assist automatic Python/Java/... wrapper generators: :: + + typedef OutputArray OutputArrayOfArrays; + typedef OutputArray InputOutputArray; + typedef OutputArray InputOutputArrayOfArrays; + +NAryMatIterator +--------------- +.. ocv:class:: NAryMatIterator + +n-ary multi-dimensional array iterator. :: + + class CV_EXPORTS NAryMatIterator + { + public: + //! the default constructor + NAryMatIterator(); + //! the full constructor taking arbitrary number of n-dim matrices + NAryMatIterator(const Mat** arrays, Mat* planes, int narrays=-1); + //! the separate iterator initialization method + void init(const Mat** arrays, Mat* planes, int narrays=-1); + + //! proceeds to the next plane of every iterated matrix + NAryMatIterator& operator ++(); + //! proceeds to the next plane of every iterated matrix (postfix increment operator) + NAryMatIterator operator ++(int); + + ... + int nplanes; // the total number of planes + }; + + +Use the class to implement unary, binary, and, generally, n-ary element-wise operations on multi-dimensional arrays. Some of the arguments of an n-ary function may be continuous arrays, some may be not. It is possible to use conventional +``MatIterator`` 's for each array but incrementing all of the iterators after each small operations may be a big overhead. In this case consider using ``NAryMatIterator`` to iterate through several matrices simultaneously as long as they have the same geometry (dimensionality and all the dimension sizes are the same). On each iteration ``it.planes[0]``, ``it.planes[1]`` , ... will be the slices of the corresponding matrices. + +The example below illustrates how you can compute a normalized and threshold 3D color histogram: :: + + void computeNormalizedColorHist(const Mat& image, Mat& hist, int N, double minProb) + { + const int histSize[] = {N, N, N}; + + // make sure that the histogram has a proper size and type + hist.create(3, histSize, CV_32F); + + // and clear it + hist = Scalar(0); + + // the loop below assumes that the image + // is a 8-bit 3-channel. check it. + CV_Assert(image.type() == CV_8UC3); + MatConstIterator_ it = image.begin(), + it_end = image.end(); + for( ; it != it_end; ++it ) + { + const Vec3b& pix = *it; + hist.at(pix[0]*N/256, pix[1]*N/256, pix[2]*N/256) += 1.f; + } + + minProb *= image.rows*image.cols; + Mat plane; + NAryMatIterator it(&hist, &plane, 1); + double s = 0; + // iterate through the matrix. on each iteration + // it.planes[*] (of type Mat) will be set to the current plane. + for(int p = 0; p < it.nplanes; p++, ++it) + { + threshold(it.planes[0], it.planes[0], minProb, 0, THRESH_TOZERO); + s += sum(it.planes[0])[0]; + } + + s = 1./s; + it = NAryMatIterator(&hist, &plane, 1); + for(int p = 0; p < it.nplanes; p++, ++it) + it.planes[0] *= s; + } + + +SparseMat +--------- +.. ocv:class:: SparseMat + +Sparse n-dimensional array. :: + + class SparseMat + { + public: + typedef SparseMatIterator iterator; + typedef SparseMatConstIterator const_iterator; + + // internal structure - sparse matrix header + struct Hdr + { + ... + }; + + // sparse matrix node - element of a hash table + struct Node + { + size_t hashval; + size_t next; + int idx[CV_MAX_DIM]; + }; + + ////////// constructors and destructor ////////// + // default constructor + SparseMat(); + // creates matrix of the specified size and type + SparseMat(int dims, const int* _sizes, int _type); + // copy constructor + SparseMat(const SparseMat& m); + // converts dense array to the sparse form, + // if try1d is true and matrix is a single-column matrix (Nx1), + // then the sparse matrix will be 1-dimensional. + SparseMat(const Mat& m, bool try1d=false); + // converts an old-style sparse matrix to the new style. + // all the data is copied so that "m" can be safely + // deleted after the conversion + SparseMat(const CvSparseMat* m); + // destructor + ~SparseMat(); + + ///////// assignment operations /////////// + + // this is an O(1) operation; no data is copied + SparseMat& operator = (const SparseMat& m); + // (equivalent to the corresponding constructor with try1d=false) + SparseMat& operator = (const Mat& m); + + // creates a full copy of the matrix + SparseMat clone() const; + + // copy all the data to the destination matrix. + // the destination will be reallocated if needed. + void copyTo( SparseMat& m ) const; + // converts 1D or 2D sparse matrix to dense 2D matrix. + // If the sparse matrix is 1D, the result will + // be a single-column matrix. + void copyTo( Mat& m ) const; + // converts arbitrary sparse matrix to dense matrix. + // multiplies all the matrix elements by the specified scalar + void convertTo( SparseMat& m, int rtype, double alpha=1 ) const; + // converts sparse matrix to dense matrix with optional type conversion and scaling. + // When rtype=-1, the destination element type will be the same + // as the sparse matrix element type. + // Otherwise, rtype will specify the depth and + // the number of channels will remain the same as in the sparse matrix + void convertTo( Mat& m, int rtype, double alpha=1, double beta=0 ) const; + + // not used now + void assignTo( SparseMat& m, int type=-1 ) const; + + // reallocates sparse matrix. If it was already of the proper size and type, + // it is simply cleared with clear(), otherwise, + // the old matrix is released (using release()) and the new one is allocated. + void create(int dims, const int* _sizes, int _type); + // sets all the matrix elements to 0, which means clearing the hash table. + void clear(); + // manually increases reference counter to the header. + void addref(); + // decreses the header reference counter when it reaches 0. + // the header and all the underlying data are deallocated. + void release(); + + // converts sparse matrix to the old-style representation. + // all the elements are copied. + operator CvSparseMat*() const; + // size of each element in bytes + // (the matrix nodes will be bigger because of + // element indices and other SparseMat::Node elements). + size_t elemSize() const; + // elemSize()/channels() + size_t elemSize1() const; + + // the same is in Mat + int type() const; + int depth() const; + int channels() const; + + // returns the array of sizes and 0 if the matrix is not allocated + const int* size() const; + // returns i-th size (or 0) + int size(int i) const; + // returns the matrix dimensionality + int dims() const; + // returns the number of non-zero elements + size_t nzcount() const; + + // compute element hash value from the element indices: + // 1D case + size_t hash(int i0) const; + // 2D case + size_t hash(int i0, int i1) const; + // 3D case + size_t hash(int i0, int i1, int i2) const; + // n-D case + size_t hash(const int* idx) const; + + // low-level element-access functions, + // special variants for 1D, 2D, 3D cases, and the generic one for n-D case. + // + // return pointer to the matrix element. + // if the element is there (it is non-zero), the pointer to it is returned + // if it is not there and createMissing=false, NULL pointer is returned + // if it is not there and createMissing=true, the new element + // is created and initialized with 0. Pointer to it is returned. + // If the optional hashval pointer is not NULL, the element hash value is + // not computed but *hashval is taken instead. + uchar* ptr(int i0, bool createMissing, size_t* hashval=0); + uchar* ptr(int i0, int i1, bool createMissing, size_t* hashval=0); + uchar* ptr(int i0, int i1, int i2, bool createMissing, size_t* hashval=0); + uchar* ptr(const int* idx, bool createMissing, size_t* hashval=0); + + // higher-level element access functions: + // ref<_Tp>(i0,...[,hashval]) - equivalent to *(_Tp*)ptr(i0,...true[,hashval]). + // always return valid reference to the element. + // If it does not exist, it is created. + // find<_Tp>(i0,...[,hashval]) - equivalent to (_const Tp*)ptr(i0,...false[,hashval]). + // return pointer to the element or NULL pointer if the element is not there. + // value<_Tp>(i0,...[,hashval]) - equivalent to + // { const _Tp* p = find<_Tp>(i0,...[,hashval]); return p ? *p : _Tp(); } + // that is, 0 is returned when the element is not there. + // note that _Tp must match the actual matrix type - + // the functions do not do any on-fly type conversion + + // 1D case + template _Tp& ref(int i0, size_t* hashval=0); + template _Tp value(int i0, size_t* hashval=0) const; + template const _Tp* find(int i0, size_t* hashval=0) const; + + // 2D case + template _Tp& ref(int i0, int i1, size_t* hashval=0); + template _Tp value(int i0, int i1, size_t* hashval=0) const; + template const _Tp* find(int i0, int i1, size_t* hashval=0) const; + + // 3D case + template _Tp& ref(int i0, int i1, int i2, size_t* hashval=0); + template _Tp value(int i0, int i1, int i2, size_t* hashval=0) const; + template const _Tp* find(int i0, int i1, int i2, size_t* hashval=0) const; + + // n-D case + template _Tp& ref(const int* idx, size_t* hashval=0); + template _Tp value(const int* idx, size_t* hashval=0) const; + template const _Tp* find(const int* idx, size_t* hashval=0) const; + + // erase the specified matrix element. + // when there is no such an element, the methods do nothing + void erase(int i0, int i1, size_t* hashval=0); + void erase(int i0, int i1, int i2, size_t* hashval=0); + void erase(const int* idx, size_t* hashval=0); + + // return the matrix iterators, + // pointing to the first sparse matrix element, + SparseMatIterator begin(); + SparseMatConstIterator begin() const; + // ... or to the point after the last sparse matrix element + SparseMatIterator end(); + SparseMatConstIterator end() const; + + // and the template forms of the above methods. + // _Tp must match the actual matrix type. + template SparseMatIterator_<_Tp> begin(); + template SparseMatConstIterator_<_Tp> begin() const; + template SparseMatIterator_<_Tp> end(); + template SparseMatConstIterator_<_Tp> end() const; + + // return value stored in the sparse martix node + template _Tp& value(Node* n); + template const _Tp& value(const Node* n) const; + + ////////////// some internally used methods /////////////// + ... + + // pointer to the sparse matrix header + Hdr* hdr; + }; + + +The class ``SparseMat`` represents multi-dimensional sparse numerical arrays. Such a sparse array can store elements of any type that +:ocv:class:`Mat` can store. *Sparse* means that only non-zero elements are stored (though, as a result of operations on a sparse matrix, some of its stored elements can actually become 0. It is up to you to detect such elements and delete them using ``SparseMat::erase`` ). The non-zero elements are stored in a hash table that grows when it is filled so that the search time is O(1) in average (regardless of whether element is there or not). Elements can be accessed using the following methods: + +* + Query operations ( ``SparseMat::ptr`` and the higher-level ``SparseMat::ref``, ``SparseMat::value`` and ``SparseMat::find`` ), for example: + + :: + + const int dims = 5; + int size[] = {10, 10, 10, 10, 10}; + SparseMat sparse_mat(dims, size, CV_32F); + for(int i = 0; i < 1000; i++) + { + int idx[dims]; + for(int k = 0; k < dims; k++) + idx[k] = rand() + sparse_mat.ref(idx) += 1.f; + } + + .. + +* + Sparse matrix iterators. They are similar to ``MatIterator`` but different from :ocv:class:`NAryMatIterator`. That is, the iteration loop is familiar to STL users: + + :: + + // prints elements of a sparse floating-point matrix + // and the sum of elements. + SparseMatConstIterator_ + it = sparse_mat.begin(), + it_end = sparse_mat.end(); + double s = 0; + int dims = sparse_mat.dims(); + for(; it != it_end; ++it) + { + // print element indices and the element value + const Node* n = it.node(); + printf("(") + for(int i = 0; i < dims; i++) + printf(" + printf(": + s += *it; + } + printf("Element sum is + + .. + + If you run this loop, you will notice that elements are not enumerated in a logical order (lexicographical, and so on). They come in the same order as they are stored in the hash table (semi-randomly). You may collect pointers to the nodes and sort them to get the proper ordering. Note, however, that pointers to the nodes may become invalid when you add more elements to the matrix. This may happen due to possible buffer reallocation. + +* + Combination of the above 2 methods when you need to process 2 or more sparse matrices simultaneously. For example, this is how you can compute unnormalized cross-correlation of the 2 floating-point sparse matrices: + + :: + + double cross_corr(const SparseMat& a, const SparseMat& b) + { + const SparseMat *_a = &a, *_b = &b; + // if b contains less elements than a, + // it is faster to iterate through b + if(_a->nzcount() > _b->nzcount()) + std::swap(_a, _b); + SparseMatConstIterator_ it = _a->begin(), + it_end = _a->end(); + double ccorr = 0; + for(; it != it_end; ++it) + { + // take the next element from the first matrix + float avalue = *it; + const Node* anode = it.node(); + // and try to find an element with the same index in the second matrix. + // since the hash value depends only on the element index, + // reuse the hash value stored in the node + float bvalue = _b->value(anode->idx,&anode->hashval); + ccorr += avalue*bvalue; + } + return ccorr; + } + + .. + +SparseMat\_ +----------- +.. ocv:class:: SparseMat_ + +Template sparse n-dimensional array class derived from +:ocv:class:`SparseMat` :: + + template class SparseMat_ : public SparseMat + { + public: + typedef SparseMatIterator_<_Tp> iterator; + typedef SparseMatConstIterator_<_Tp> const_iterator; + + // constructors; + // the created matrix will have data type = DataType<_Tp>::type + SparseMat_(); + SparseMat_(int dims, const int* _sizes); + SparseMat_(const SparseMat& m); + SparseMat_(const SparseMat_& m); + SparseMat_(const Mat& m); + SparseMat_(const CvSparseMat* m); + // assignment operators; data type conversion is done when necessary + SparseMat_& operator = (const SparseMat& m); + SparseMat_& operator = (const SparseMat_& m); + SparseMat_& operator = (const Mat& m); + + // equivalent to the correspoding parent class methods + SparseMat_ clone() const; + void create(int dims, const int* _sizes); + operator CvSparseMat*() const; + + // overriden methods that do extra checks for the data type + int type() const; + int depth() const; + int channels() const; + + // more convenient element access operations. + // ref() is retained (but <_Tp> specification is not needed anymore); + // operator () is equivalent to SparseMat::value<_Tp> + _Tp& ref(int i0, size_t* hashval=0); + _Tp operator()(int i0, size_t* hashval=0) const; + _Tp& ref(int i0, int i1, size_t* hashval=0); + _Tp operator()(int i0, int i1, size_t* hashval=0) const; + _Tp& ref(int i0, int i1, int i2, size_t* hashval=0); + _Tp operator()(int i0, int i1, int i2, size_t* hashval=0) const; + _Tp& ref(const int* idx, size_t* hashval=0); + _Tp operator()(const int* idx, size_t* hashval=0) const; + + // iterators + SparseMatIterator_<_Tp> begin(); + SparseMatConstIterator_<_Tp> begin() const; + SparseMatIterator_<_Tp> end(); + SparseMatConstIterator_<_Tp> end() const; + }; + +``SparseMat_`` is a thin wrapper on top of :ocv:class:`SparseMat` created in the same way as ``Mat_`` . +It simplifies notation of some operations. :: + + int sz[] = {10, 20, 30}; + SparseMat_ M(3, sz); + ... + M.ref(1, 2, 3) = M(4, 5, 6) + M(7, 8, 9); + + +Algorithm +--------- +.. ocv:class:: Algorithm + +This is a base class for all more or less complex algorithms in OpenCV, especially for classes of algorithms, for which there can be multiple implementations. The examples are stereo correspondence (for which there are algorithms like block matching, semi-global block matching, graph-cut etc.), background subtraction (which can be done using mixture-of-gaussians models, codebook-based algorithm etc.), optical flow (block matching, Lucas-Kanade, Horn-Schunck etc.). + +The class provides the following features for all derived classes: + + * so called "virtual constructor". That is, each Algorithm derivative is registered at program start and you can get the list of registered algorithms and create instance of a particular algorithm by its name (see ``Algorithm::create``). If you plan to add your own algorithms, it is good practice to add a unique prefix to your algorithms to distinguish them from other algorithms. + + * setting/retrieving algorithm parameters by name. If you used video capturing functionality from OpenCV highgui module, you are probably familar with ``cvSetCaptureProperty()``, ``cvGetCaptureProperty()``, ``VideoCapture::set()`` and ``VideoCapture::get()``. ``Algorithm`` provides similar method where instead of integer id's you specify the parameter names as text strings. See ``Algorithm::set`` and ``Algorithm::get`` for details. + + * reading and writing parameters from/to XML or YAML files. Every Algorithm derivative can store all its parameters and then read them back. There is no need to re-implement it each time. + +Here is example of SIFT use in your application via Algorithm interface: :: + + #include "opencv2/opencv.hpp" + #include "opencv2/nonfree/nonfree.hpp" + + ... + + initModule_nonfree(); // to load SURF/SIFT etc. + + Ptr sift = Algorithm::create("Feature2D.SIFT"); + + FileStorage fs("sift_params.xml", FileStorage::READ); + if( fs.isOpened() ) // if we have file with parameters, read them + { + sift->read(fs["sift_params"]); + fs.release(); + } + else // else modify the parameters and store them; user can later edit the file to use different parameters + { + sift->set("contrastThreshold", 0.01f); // lower the contrast threshold, compared to the default value + + { + WriteStructContext ws(fs, "sift_params", CV_NODE_MAP); + sift->write(fs); + } + } + + Mat image = imread("myimage.png", 0), descriptors; + vector keypoints; + (*sift)(image, noArray(), keypoints, descriptors); + + +Algorithm::get +-------------- +Returns the algorithm parameter + +.. ocv:function:: template typename ParamType<_Tp>::member_type Algorithm::get(const string& name) const + + :param name: The parameter name. + +The method returns value of the particular parameter. Since the compiler can not deduce the type of the returned parameter, you should specify it explicitly in angle brackets. Here are the allowed forms of get: + + * myalgo.get("param_name") + * myalgo.get("param_name") + * myalgo.get("param_name") + * myalgo.get("param_name") + * myalgo.get("param_name") + * myalgo.get >("param_name") + * myalgo.get("param_name") (it returns Ptr). + +In some cases the actual type of the parameter can be cast to the specified type, e.g. integer parameter can be cast to double, ``bool`` can be cast to ``int``. But "dangerous" transformations (string<->number, double->int, 1x1 Mat<->number, ...) are not performed and the method will throw an exception. In the case of ``Mat`` or ``vector`` parameters the method does not clone the matrix data, so do not modify the matrices. Use ``Algorithm::set`` instead - slower, but more safe. + + +Algorithm::set +-------------- +Sets the algorithm parameter + +.. ocv:function:: void Algorithm::set(const string& name, int value) +.. ocv:function:: void Algorithm::set(const string& name, double value) +.. ocv:function:: void Algorithm::set(const string& name, bool value) +.. ocv:function:: void Algorithm::set(const string& name, const string& value) +.. ocv:function:: void Algorithm::set(const string& name, const Mat& value) +.. ocv:function:: void Algorithm::set(const string& name, const vector& value) +.. ocv:function:: void Algorithm::set(const string& name, const Ptr& value) + + :param name: The parameter name. + :param value: The parameter value. + +The method sets value of the particular parameter. Some of the algorithm parameters may be declared as read-only. If you try to set such a parameter, you will get exception with the corresponding error message. + + +Algorithm::write +---------------- +Stores algorithm parameters in a file storage + +.. ocv:function:: void Algorithm::write(FileStorage& fs) const + + :param fs: File storage. + +The method stores all the algorithm parameters (in alphabetic order) to the file storage. The method is virtual. If you define your own Algorithm derivative, your can override the method and store some extra information. However, it's rarely needed. Here are some examples: + + * SIFT feature detector (from nonfree module). The class only stores algorithm parameters and no keypoints or their descriptors. Therefore, it's enough to store the algorithm parameters, which is what ``Algorithm::write()`` does. Therefore, there is no dedicated ``SIFT::write()``. + + * Background subtractor (from video module). It has the algorithm parameters and also it has the current background model. However, the background model is not stored. First, it's rather big. Then, if you have stored the background model, it would likely become irrelevant on the next run (because of shifted camera, changed background, different lighting etc.). Therefore, ``BackgroundSubtractorMOG`` and ``BackgroundSubtractorMOG2`` also rely on the standard ``Algorithm::write()`` to store just the algorithm parameters. + + * Expectation Maximization (from ml module). The algorithm finds mixture of gaussians that approximates user data best of all. In this case the model may be re-used on the next run to test new data against the trained statistical model. So EM needs to store the model. However, since the model is described by a few parameters that are available as read-only algorithm parameters (i.e. they are available via ``EM::get()``), EM also relies on ``Algorithm::write()`` to store both EM parameters and the model (represented by read-only algorithm parameters). + + +Algorithm::read +--------------- +Reads algorithm parameters from a file storage + +.. ocv:function:: void Algorithm::read(const FileNode& fn) + + :param fn: File node of the file storage. + +The method reads all the algorithm parameters from the specified node of a file storage. Similarly to ``Algorithm::write()``, if you implement an algorithm that needs to read some extra data and/or re-compute some internal data, you may override the method. + +Algorithm::getList +------------------ +Returns the list of registered algorithms + +.. ocv:function:: void Algorithm::getList(vector& algorithms) + + :param algorithms: The output vector of algorithm names. + +This static method returns the list of registered algorithms in alphabetical order. Here is how to use it :: + + vector algorithms; + Algorithm::getList(algorithms); + cout << "Algorithms: " << algorithms.size() << endl; + for (size_t i=0; i < algorithms.size(); i++) + cout << algorithms[i] << endl; + + +Algorithm::create +----------------- +Creates algorithm instance by name + +.. ocv:function:: template Ptr<_Tp> Algorithm::create(const string& name) + + :param name: The algorithm name, one of the names returned by ``Algorithm::getList()``. + +This static method creates a new instance of the specified algorithm. If there is no such algorithm, the method will silently return null pointer (that can be checked by ``Ptr::empty()`` method). Also, you should specify the particular ``Algorithm`` subclass as ``_Tp`` (or simply ``Algorithm`` if you do not know it at that point). :: + + Ptr bgfg = Algorithm::create("BackgroundSubtractor.MOG2"); + +.. note:: This is important note about seemingly mysterious behavior of ``Algorithm::create()`` when it returns NULL while it should not. The reason is simple - ``Algorithm::create()`` resides in OpenCV`s core module and the algorithms are implemented in other modules. If you create algorithms dynamically, C++ linker may decide to throw away the modules where the actual algorithms are implemented, since you do not call any functions from the modules. To avoid this problem, you need to call ``initModule_();`` somewhere in the beginning of the program before ``Algorithm::create()``. For example, call ``initModule_nonfree()`` in order to use SURF/SIFT, call ``initModule_ml()`` to use expectation maximization etc. + +Creating Own Algorithms +----------------------- + +The above methods are usually enough for users. If you want to make your own algorithm, derived from ``Algorithm``, you should basically follow a few conventions and add a little semi-standard piece of code to your class: + + * Make a class and specify ``Algorithm`` as its base class. + * The algorithm parameters should be the class members. See ``Algorithm::get()`` for the list of possible types of the parameters. + * Add public virtual method ``AlgorithmInfo* info() const;`` to your class. + * Add constructor function, ``AlgorithmInfo`` instance and implement the ``info()`` method. The simplest way is to take http://code.opencv.org/projects/opencv/repository/revisions/master/entry/modules/ml/src/ml_init.cpp as the reference and modify it according to the list of your parameters. + * Add some public function (e.g. ``initModule_()``) that calls info() of your algorithm and put it into the same source file as ``info()`` implementation. This is to force C++ linker to include this object file into the target application. See ``Algorithm::create()`` for details. + diff --git a/core/doc/clustering.rst b/core/doc/clustering.rst new file mode 100644 index 0000000..46130bc --- /dev/null +++ b/core/doc/clustering.rst @@ -0,0 +1,81 @@ +Clustering +========== + +.. highlight:: cpp + +kmeans +------ +Finds centers of clusters and groups input samples around the clusters. + +.. ocv:function:: double kmeans( InputArray data, int K, InputOutputArray bestLabels, TermCriteria criteria, int attempts, int flags, OutputArray centers=noArray() ) + +.. ocv:pyfunction:: cv2.kmeans(data, K, criteria, attempts, flags[, bestLabels[, centers]]) -> retval, bestLabels, centers + +.. ocv:cfunction:: int cvKMeans2( const CvArr* samples, int cluster_count, CvArr* labels, CvTermCriteria termcrit, int attempts=1, CvRNG* rng=0, int flags=0, CvArr* _centers=0, double* compactness=0 ) + +.. ocv:pyoldfunction:: cv.KMeans2(samples, nclusters, labels, termcrit, attempts=1, flags=0, centers=None) -> float + + :param samples: Floating-point matrix of input samples, one row per sample. + + :param cluster_count: Number of clusters to split the set by. + + :param labels: Input/output integer array that stores the cluster indices for every sample. + + :param criteria: The algorithm termination criteria, that is, the maximum number of iterations and/or the desired accuracy. The accuracy is specified as ``criteria.epsilon``. As soon as each of the cluster centers moves by less than ``criteria.epsilon`` on some iteration, the algorithm stops. + + :param attempts: Flag to specify the number of times the algorithm is executed using different initial labellings. The algorithm returns the labels that yield the best compactness (see the last function parameter). + + :param rng: CvRNG state initialized by RNG(). + + :param flags: Flag that can take the following values: + + * **KMEANS_RANDOM_CENTERS** Select random initial centers in each attempt. + + * **KMEANS_PP_CENTERS** Use ``kmeans++`` center initialization by Arthur and Vassilvitskii [Arthur2007]. + + * **KMEANS_USE_INITIAL_LABELS** During the first (and possibly the only) attempt, use the user-supplied labels instead of computing them from the initial centers. For the second and further attempts, use the random or semi-random centers. Use one of ``KMEANS_*_CENTERS`` flag to specify the exact method. + + :param centers: Output matrix of the cluster centers, one row per each cluster center. + + :param compactness: The returned value that is described below. + +The function ``kmeans`` implements a k-means algorithm that finds the +centers of ``cluster_count`` clusters and groups the input samples +around the clusters. As an output, +:math:`\texttt{labels}_i` contains a 0-based cluster index for +the sample stored in the +:math:`i^{th}` row of the ``samples`` matrix. + +The function returns the compactness measure that is computed as + +.. math:: + + \sum _i \| \texttt{samples} _i - \texttt{centers} _{ \texttt{labels} _i} \| ^2 + +after every attempt. The best (minimum) value is chosen and the +corresponding labels and the compactness value are returned by the function. +Basically, you can use only the core of the function, set the number of +attempts to 1, initialize labels each time using a custom algorithm, pass them with the +( ``flags`` = ``KMEANS_USE_INITIAL_LABELS`` ) flag, and then choose the best (most-compact) clustering. + +partition +------------- +Splits an element set into equivalency classes. + +.. ocv:function:: template int partition( const vector<_Tp>& vec, vector& labels, _EqPredicate predicate=_EqPredicate()) + + :param vec: Set of elements stored as a vector. + + :param labels: Output vector of labels. It contains as many elements as ``vec``. Each label ``labels[i]`` is a 0-based cluster index of ``vec[i]`` . + + :param predicate: Equivalence predicate (pointer to a boolean function of two arguments or an instance of the class that has the method ``bool operator()(const _Tp& a, const _Tp& b)`` ). The predicate returns ``true`` when the elements are certainly in the same class, and returns ``false`` if they may or may not be in the same class. + +The generic function ``partition`` implements an +:math:`O(N^2)` algorithm for +splitting a set of +:math:`N` elements into one or more equivalency classes, as described in +http://en.wikipedia.org/wiki/Disjoint-set_data_structure +. The function +returns the number of equivalency classes. + +.. [Arthur2007] Arthur and S. Vassilvitskii. k-means++: the advantages of careful seeding, Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms, 2007 diff --git a/core/doc/core.rst b/core/doc/core.rst new file mode 100644 index 0000000..7eb4e3e --- /dev/null +++ b/core/doc/core.rst @@ -0,0 +1,17 @@ +**************************** +core. The Core Functionality +**************************** + +.. toctree:: + :maxdepth: 2 + + basic_structures + old_basic_structures + dynamic_structures + operations_on_arrays + drawing_functions + xml_yaml_persistence + old_xml_yaml_persistence + clustering + utility_and_system_functions_and_macros + diff --git a/core/doc/drawing_functions.rst b/core/doc/drawing_functions.rst new file mode 100644 index 0000000..71ff175 --- /dev/null +++ b/core/doc/drawing_functions.rst @@ -0,0 +1,597 @@ +Drawing Functions +================= + +.. highlight:: cpp + +Drawing functions work with matrices/images of arbitrary depth. +The boundaries of the shapes can be rendered with antialiasing (implemented only for 8-bit images for now). +All the functions include the parameter ``color`` that uses an RGB value (that may be constructed +with ``CV_RGB`` or the :ocv:class:`Scalar_` constructor +) for color +images and brightness for grayscale images. For color images, the channel ordering +is normally *Blue, Green, Red*. +This is what :ocv:func:`imshow`, :ocv:func:`imread`, and :ocv:func:`imwrite` expect. +So, if you form a color using the +``Scalar`` constructor, it should look like: + +.. math:: + + \texttt{Scalar} (blue \_ component, green \_ component, red \_ component[, alpha \_ component]) + +If you are using your own image rendering and I/O functions, you can use any channel ordering. The drawing functions process each channel independently and do not depend on the channel order or even on the used color space. The whole image can be converted from BGR to RGB or to a different color space using +:ocv:func:`cvtColor` . + +If a drawn figure is partially or completely outside the image, the drawing functions clip it. Also, many drawing functions can handle pixel coordinates specified with sub-pixel accuracy. This means that the coordinates can be passed as fixed-point numbers encoded as integers. The number of fractional bits is specified by the ``shift`` parameter and the real point coordinates are calculated as +:math:`\texttt{Point}(x,y)\rightarrow\texttt{Point2f}(x*2^{-shift},y*2^{-shift})` . This feature is especially effective when rendering antialiased shapes. + +.. note:: The functions do not support alpha-transparency when the target image is 4-channel. In this case, the ``color[3]`` is simply copied to the repainted pixels. Thus, if you want to paint semi-transparent shapes, you can paint them in a separate buffer and then blend it with the main image. + +circle +---------- +Draws a circle. + +.. ocv:function:: void circle(Mat& img, Point center, int radius, const Scalar& color, int thickness=1, int lineType=8, int shift=0) + +.. ocv:pyfunction:: cv2.circle(img, center, radius, color[, thickness[, lineType[, shift]]]) -> None + +.. ocv:cfunction:: void cvCircle( CvArr* img, CvPoint center, int radius, CvScalar color, int thickness=1, int line_type=8, int shift=0 ) + +.. ocv:pyoldfunction:: cv.Circle(img, center, radius, color, thickness=1, lineType=8, shift=0)-> None + + :param img: Image where the circle is drawn. + + :param center: Center of the circle. + + :param radius: Radius of the circle. + + :param color: Circle color. + + :param thickness: Thickness of the circle outline, if positive. Negative thickness means that a filled circle is to be drawn. + + :param lineType: Type of the circle boundary. See the :ocv:func:`line` description. + + :param shift: Number of fractional bits in the coordinates of the center and in the radius value. + +The function ``circle`` draws a simple or filled circle with a given center and radius. + +clipLine +------------ +Clips the line against the image rectangle. + +.. ocv:function:: bool clipLine(Size imgSize, Point& pt1, Point& pt2) + +.. ocv:function:: bool clipLine(Rect imgRect, Point& pt1, Point& pt2) + +.. ocv:pyfunction:: cv2.clipLine(imgRect, pt1, pt2) -> retval, pt1, pt2 + +.. ocv:cfunction:: int cvClipLine( CvSize img_size, CvPoint* pt1, CvPoint* pt2 ) + +.. ocv:pyoldfunction:: cv.ClipLine(imgSize, pt1, pt2) -> (point1, point2) + + :param imgSize: Image size. The image rectangle is ``Rect(0, 0, imgSize.width, imgSize.height)`` . + + :param imgRect: Image rectangle. + + :param pt1: First line point. + + :param pt2: Second line point. + +The functions ``clipLine`` calculate a part of the line segment that is entirely within the specified rectangle. +They return ``false`` if the line segment is completely outside the rectangle. Otherwise, they return ``true`` . + +ellipse +----------- +Draws a simple or thick elliptic arc or fills an ellipse sector. + +.. ocv:function:: void ellipse(Mat& img, Point center, Size axes, double angle, double startAngle, double endAngle, const Scalar& color, int thickness=1, int lineType=8, int shift=0) + +.. ocv:function:: void ellipse(Mat& img, const RotatedRect& box, const Scalar& color, int thickness=1, int lineType=8) + +.. ocv:pyfunction:: cv2.ellipse(img, center, axes, angle, startAngle, endAngle, color[, thickness[, lineType[, shift]]]) -> None +.. ocv:pyfunction:: cv2.ellipse(img, box, color[, thickness[, lineType]]) -> None + +.. ocv:cfunction:: void cvEllipse( CvArr* img, CvPoint center, CvSize axes, double angle, double start_angle, double end_angle, CvScalar color, int thickness=1, int line_type=8, int shift=0 ) + +.. ocv:pyoldfunction:: cv.Ellipse(img, center, axes, angle, start_angle, end_angle, color, thickness=1, lineType=8, shift=0)-> None + +.. ocv:cfunction:: void cvEllipseBox( CvArr* img, CvBox2D box, CvScalar color, int thickness=1, int line_type=8, int shift=0 ) + +.. ocv:pyoldfunction:: cv.EllipseBox(img, box, color, thickness=1, lineType=8, shift=0)-> None + + :param img: Image. + + :param center: Center of the ellipse. + + :param axes: Length of the ellipse axes. + + :param angle: Ellipse rotation angle in degrees. + + :param startAngle: Starting angle of the elliptic arc in degrees. + + :param endAngle: Ending angle of the elliptic arc in degrees. + + :param box: Alternative ellipse representation via :ocv:class:`RotatedRect` or ``CvBox2D``. This means that the function draws an ellipse inscribed in the rotated rectangle. + + :param color: Ellipse color. + + :param thickness: Thickness of the ellipse arc outline, if positive. Otherwise, this indicates that a filled ellipse sector is to be drawn. + + :param lineType: Type of the ellipse boundary. See the :ocv:func:`line` description. + + :param shift: Number of fractional bits in the coordinates of the center and values of axes. + +The functions ``ellipse`` with less parameters draw an ellipse outline, a filled ellipse, an elliptic arc, or a filled ellipse sector. +A piecewise-linear curve is used to approximate the elliptic arc boundary. If you need more control of the ellipse rendering, you can retrieve the curve using +:ocv:func:`ellipse2Poly` and then render it with +:ocv:func:`polylines` or fill it with +:ocv:func:`fillPoly` . If you use the first variant of the function and want to draw the whole ellipse, not an arc, pass ``startAngle=0`` and ``endAngle=360`` . The figure below explains the meaning of the parameters. + +**Figure 1. Parameters of Elliptic Arc** + +.. image:: pics/ellipse.png + +ellipse2Poly +---------------- +Approximates an elliptic arc with a polyline. + +.. ocv:function:: void ellipse2Poly( Point center, Size axes, int angle, int arcStart, int arcEnd, int delta, vector& pts ) + +.. ocv:pyfunction:: cv2.ellipse2Poly(center, axes, angle, arcStart, arcEnd, delta) -> pts + + :param center: Center of the arc. + + :param axes: Half-sizes of the arc. See the :ocv:func:`ellipse` for details. + + :param angle: Rotation angle of the ellipse in degrees. See the :ocv:func:`ellipse` for details. + + :param arcStart: Starting angle of the elliptic arc in degrees. + + :param arcEnd: Ending angle of the elliptic arc in degrees. + + :param delta: Angle between the subsequent polyline vertices. It defines the approximation accuracy. + + :param pts: Output vector of polyline vertices. + +The function ``ellipse2Poly`` computes the vertices of a polyline that approximates the specified elliptic arc. It is used by +:ocv:func:`ellipse` . + + + +fillConvexPoly +------------------ +Fills a convex polygon. + +.. ocv:function:: void fillConvexPoly(Mat& img, const Point* pts, int npts, const Scalar& color, int lineType=8, int shift=0) + +.. ocv:pyfunction:: cv2.fillConvexPoly(img, points, color[, lineType[, shift]]) -> None + +.. ocv:cfunction:: void cvFillConvexPoly( CvArr* img, const CvPoint* pts, int npts, CvScalar color, int line_type=8, int shift=0 ) + +.. ocv:pyoldfunction:: cv.FillConvexPoly(img, pn, color, lineType=8, shift=0)-> None + + :param img: Image. + + :param pts: Polygon vertices. + + :param npts: Number of polygon vertices. + + :param color: Polygon color. + + :param lineType: Type of the polygon boundaries. See the :ocv:func:`line` description. + + :param shift: Number of fractional bits in the vertex coordinates. + +The function ``fillConvexPoly`` draws a filled convex polygon. +This function is much faster than the function ``fillPoly`` . It can fill not only convex polygons but any monotonic polygon without self-intersections, +that is, a polygon whose contour intersects every horizontal line (scan line) twice at the most (though, its top-most and/or the bottom edge could be horizontal). + + + +fillPoly +------------ +Fills the area bounded by one or more polygons. + +.. ocv:function:: void fillPoly(Mat& img, const Point** pts, const int* npts, int ncontours, const Scalar& color, int lineType=8, int shift=0, Point offset=Point() ) + +.. ocv:pyfunction:: cv2.fillPoly(img, pts, color[, lineType[, shift[, offset]]]) -> None + +.. ocv:cfunction:: void cvFillPoly( CvArr* img, CvPoint** pts, const int* npts, int contours, CvScalar color, int line_type=8, int shift=0 ) + +.. ocv:pyoldfunction:: cv.FillPoly(img, polys, color, lineType=8, shift=0)-> None + + :param img: Image. + + :param pts: Array of polygons where each polygon is represented as an array of points. + + :param npts: Array of polygon vertex counters. + + :param ncontours: Number of contours that bind the filled region. + + :param color: Polygon color. + + :param lineType: Type of the polygon boundaries. See the :ocv:func:`line` description. + + :param shift: Number of fractional bits in the vertex coordinates. + + :param offset: Optional offset of all points of the contours. + +The function ``fillPoly`` fills an area bounded by several polygonal contours. The function can fill complex areas, for example, +areas with holes, contours with self-intersections (some of their parts), and so forth. + + + +getTextSize +--------------- +Calculates the width and height of a text string. + +.. ocv:function:: Size getTextSize(const string& text, int fontFace, double fontScale, int thickness, int* baseLine) + +.. ocv:pyfunction:: cv2.getTextSize(text, fontFace, fontScale, thickness) -> retval, baseLine + +.. ocv:cfunction:: void cvGetTextSize( const char* text_string, const CvFont* font, CvSize* text_size, int* baseline ) + +.. ocv:pyoldfunction:: cv.GetTextSize(textString, font)-> (textSize, baseline) + + :param text: Input text string. + + :param fontFace: Font to use. See the :ocv:func:`putText` for details. + + :param fontScale: Font scale. See the :ocv:func:`putText` for details. + + :param thickness: Thickness of lines used to render the text. See :ocv:func:`putText` for details. + + :param baseLine: Output parameter - y-coordinate of the baseline relative to the bottom-most text point. + +The function ``getTextSize`` calculates and returns the size of a box that contains the specified text. +That is, the following code renders some text, the tight box surrounding it, and the baseline: :: + + // Use "y" to show that the baseLine is about + string text = "Funny text inside the box"; + int fontFace = FONT_HERSHEY_SCRIPT_SIMPLEX; + double fontScale = 2; + int thickness = 3; + + Mat img(600, 800, CV_8UC3, Scalar::all(0)); + + int baseline=0; + Size textSize = getTextSize(text, fontFace, + fontScale, thickness, &baseline); + baseline += thickness; + + // center the text + Point textOrg((img.cols - textSize.width)/2, + (img.rows + textSize.height)/2); + + // draw the box + rectangle(img, textOrg + Point(0, baseline), + textOrg + Point(textSize.width, -textSize.height), + Scalar(0,0,255)); + // ... and the baseline first + line(img, textOrg + Point(0, thickness), + textOrg + Point(textSize.width, thickness), + Scalar(0, 0, 255)); + + // then put the text itself + putText(img, text, textOrg, fontFace, fontScale, + Scalar::all(255), thickness, 8); + + +InitFont +-------- +Initializes font structure (OpenCV 1.x API). + +.. ocv:cfunction:: void cvInitFont( CvFont* font, int font_face, double hscale, double vscale, double shear=0, int thickness=1, int line_type=8 ) + + :param font: Pointer to the font structure initialized by the function + + :param font_face: Font name identifier. Only a subset of Hershey fonts http://sources.isc.org/utils/misc/hershey-font.txt are supported now: + + * **CV_FONT_HERSHEY_SIMPLEX** normal size sans-serif font + + * **CV_FONT_HERSHEY_PLAIN** small size sans-serif font + + * **CV_FONT_HERSHEY_DUPLEX** normal size sans-serif font (more complex than ``CV_FONT_HERSHEY_SIMPLEX`` ) + + * **CV_FONT_HERSHEY_COMPLEX** normal size serif font + + * **CV_FONT_HERSHEY_TRIPLEX** normal size serif font (more complex than ``CV_FONT_HERSHEY_COMPLEX`` ) + + * **CV_FONT_HERSHEY_COMPLEX_SMALL** smaller version of ``CV_FONT_HERSHEY_COMPLEX`` + + * **CV_FONT_HERSHEY_SCRIPT_SIMPLEX** hand-writing style font + + * **CV_FONT_HERSHEY_SCRIPT_COMPLEX** more complex variant of ``CV_FONT_HERSHEY_SCRIPT_SIMPLEX`` + + The parameter can be composited from one of the values above and an optional ``CV_FONT_ITALIC`` flag, which indicates italic or oblique font. + + + :param hscale: Horizontal scale. If equal to ``1.0f`` , the characters have the original width depending on the font type. If equal to ``0.5f`` , the characters are of half the original width. + + + :param vscale: Vertical scale. If equal to ``1.0f`` , the characters have the original height depending on the font type. If equal to ``0.5f`` , the characters are of half the original height. + + + :param shear: Approximate tangent of the character slope relative to the vertical line. A zero value means a non-italic font, ``1.0f`` means about a 45 degree slope, etc. + + + :param thickness: Thickness of the text strokes + + + :param line_type: Type of the strokes, see :ocv:func:`line` description + + +The function initializes the font structure that can be passed to text rendering functions. + +.. seealso:: :ocv:cfunc:`PutText` + +.. _Line: + +line +-------- +Draws a line segment connecting two points. + +.. ocv:function:: void line(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8, int shift=0) + +.. ocv:pyfunction:: cv2.line(img, pt1, pt2, color[, thickness[, lineType[, shift]]]) -> None + +.. ocv:cfunction:: void cvLine( CvArr* img, CvPoint pt1, CvPoint pt2, CvScalar color, int thickness=1, int line_type=8, int shift=0 ) + +.. ocv:pyoldfunction:: cv.Line(img, pt1, pt2, color, thickness=1, lineType=8, shift=0)-> None + + :param img: Image. + + :param pt1: First point of the line segment. + + :param pt2: Second point of the line segment. + + :param color: Line color. + + :param thickness: Line thickness. + + :param lineType: Type of the line: + + * **8** (or omitted) - 8-connected line. + + * **4** - 4-connected line. + + * **CV_AA** - antialiased line. + + :param shift: Number of fractional bits in the point coordinates. + +The function ``line`` draws the line segment between ``pt1`` and ``pt2`` points in the image. The line is clipped by the image boundaries. For non-antialiased lines with integer coordinates, the 8-connected or 4-connected Bresenham algorithm is used. Thick lines are drawn with rounding endings. +Antialiased lines are drawn using Gaussian filtering. To specify the line color, you may use the macro ``CV_RGB(r, g, b)`` . + + +LineIterator +------------ +.. ocv:class:: LineIterator + +Class for iterating pixels on a raster line. :: + + class LineIterator + { + public: + // creates iterators for the line connecting pt1 and pt2 + // the line will be clipped on the image boundaries + // the line is 8-connected or 4-connected + // If leftToRight=true, then the iteration is always done + // from the left-most point to the right most, + // not to depend on the ordering of pt1 and pt2 parameters + LineIterator(const Mat& img, Point pt1, Point pt2, + int connectivity=8, bool leftToRight=false); + // returns pointer to the current line pixel + uchar* operator *(); + // move the iterator to the next pixel + LineIterator& operator ++(); + LineIterator operator ++(int); + + // internal state of the iterator + uchar* ptr; + int err, count; + int minusDelta, plusDelta; + int minusStep, plusStep; + }; + +The class ``LineIterator`` is used to get each pixel of a raster line. It can be treated as versatile implementation of the Bresenham algorithm where you can stop at each pixel and do some extra processing, for example, grab pixel values along the line or draw a line with an effect (for example, with XOR operation). + +The number of pixels along the line is stored in ``LineIterator::count`` . :: + + // grabs pixels along the line (pt1, pt2) + // from 8-bit 3-channel image to the buffer + LineIterator it(img, pt1, pt2, 8); + vector buf(it.count); + + for(int i = 0; i < it.count; i++, ++it) + buf[i] = *(const Vec3b)*it; + + + +rectangle +------------- +Draws a simple, thick, or filled up-right rectangle. + +.. ocv:function:: void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8, int shift=0) + +.. ocv:function:: void rectangle( Mat& img, Rect rec, const Scalar& color, int thickness=1, int lineType=8, int shift=0 ) + +.. ocv:pyfunction:: cv2.rectangle(img, pt1, pt2, color[, thickness[, lineType[, shift]]]) -> None + +.. ocv:cfunction:: void cvRectangle( CvArr* img, CvPoint pt1, CvPoint pt2, CvScalar color, int thickness=1, int line_type=8, int shift=0 ) + +.. ocv:pyoldfunction:: cv.Rectangle(img, pt1, pt2, color, thickness=1, lineType=8, shift=0)-> None + + :param img: Image. + + :param pt1: Vertex of the rectangle. + + :param pt2: Vertex of the rectangle opposite to ``pt1`` . + + :param rec: Alternative specification of the drawn rectangle. + + :param color: Rectangle color or brightness (grayscale image). + + :param thickness: Thickness of lines that make up the rectangle. Negative values, like ``CV_FILLED`` , mean that the function has to draw a filled rectangle. + + :param lineType: Type of the line. See the :ocv:func:`line` description. + + :param shift: Number of fractional bits in the point coordinates. + +The function ``rectangle`` draws a rectangle outline or a filled rectangle whose two opposite corners are ``pt1`` and ``pt2``, or ``r.tl()`` and ``r.br()-Point(1,1)``. + + + +polylines +------------- +Draws several polygonal curves. + +.. ocv:function:: void polylines( Mat& img, const Point* const* pts, const int* npts, int ncontours, bool isClosed, const Scalar& color, int thickness=1, int lineType=8, int shift=0 ) + +.. ocv:function:: void polylines( InputOutputArray img, InputArrayOfArrays pts, bool isClosed, const Scalar& color, int thickness=1, int lineType=8, int shift=0 ) + +.. ocv:pyfunction:: cv2.polylines(img, pts, isClosed, color[, thickness[, lineType[, shift]]]) -> None + +.. ocv:cfunction:: void cvPolyLine( CvArr* img, CvPoint** pts, const int* npts, int contours, int is_closed, CvScalar color, int thickness=1, int line_type=8, int shift=0 ) + +.. ocv:pyoldfunction:: cv.PolyLine(img, polys, is_closed, color, thickness=1, lineType=8, shift=0) -> None + + :param img: Image. + + :param pts: Array of polygonal curves. + + :param npts: Array of polygon vertex counters. + + :param ncontours: Number of curves. + + :param isClosed: Flag indicating whether the drawn polylines are closed or not. If they are closed, the function draws a line from the last vertex of each curve to its first vertex. + + :param color: Polyline color. + + :param thickness: Thickness of the polyline edges. + + :param lineType: Type of the line segments. See the :ocv:func:`line` description. + + :param shift: Number of fractional bits in the vertex coordinates. + +The function ``polylines`` draws one or more polygonal curves. + + +drawContours +---------------- +Draws contours outlines or filled contours. + +.. ocv:function:: void drawContours( InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() ) + +.. ocv:pyfunction:: cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) -> None + +.. ocv:cfunction:: void cvDrawContours( CvArr * img, CvSeq* contour, CvScalar external_color, CvScalar hole_color, int max_level, int thickness=1, int line_type=8, CvPoint offset=cvPoint(0,0) ) + +.. ocv:pyoldfunction:: cv.DrawContours(img, contour, external_color, hole_color, max_level, thickness=1, lineType=8, offset=(0, 0))-> None + + :param image: Destination image. + + :param contours: All the input contours. Each contour is stored as a point vector. + + :param contourIdx: Parameter indicating a contour to draw. If it is negative, all the contours are drawn. + + :param color: Color of the contours. + + :param thickness: Thickness of lines the contours are drawn with. If it is negative (for example, ``thickness=CV_FILLED`` ), the contour interiors are + drawn. + + :param lineType: Line connectivity. See :ocv:func:`line` for details. + + :param hierarchy: Optional information about hierarchy. It is only needed if you want to draw only some of the contours (see ``maxLevel`` ). + + :param maxLevel: Maximal level for drawn contours. If it is 0, only + the specified contour is drawn. If it is 1, the function draws the contour(s) and all the nested contours. If it is 2, the function draws the contours, all the nested contours, all the nested-to-nested contours, and so on. This parameter is only taken into account when there is ``hierarchy`` available. + + :param offset: Optional contour shift parameter. Shift all the drawn contours by the specified :math:`\texttt{offset}=(dx,dy)` . + + :param contour: Pointer to the first contour. + + :param external_color: Color of external contours. + + :param hole_color: Color of internal contours (holes). + +The function draws contour outlines in the image if +:math:`\texttt{thickness} \ge 0` or fills the area bounded by the contours if +:math:`\texttt{thickness}<0` . The example below shows how to retrieve connected components from the binary image and label them: :: + + #include "cv.h" + #include "highgui.h" + + using namespace cv; + + int main( int argc, char** argv ) + { + Mat src; + // the first command-line parameter must be a filename of the binary + // (black-n-white) image + if( argc != 2 || !(src=imread(argv[1], 0)).data) + return -1; + + Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3); + + src = src > 1; + namedWindow( "Source", 1 ); + imshow( "Source", src ); + + vector > contours; + vector hierarchy; + + findContours( src, contours, hierarchy, + CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); + + // iterate through all the top-level contours, + // draw each connected component with its own random color + int idx = 0; + for( ; idx >= 0; idx = hierarchy[idx][0] ) + { + Scalar color( rand()&255, rand()&255, rand()&255 ); + drawContours( dst, contours, idx, color, CV_FILLED, 8, hierarchy ); + } + + namedWindow( "Components", 1 ); + imshow( "Components", dst ); + waitKey(0); + } + + + +putText +----------- +Draws a text string. + +.. ocv:function:: void putText( Mat& img, const string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness=1, int lineType=8, bool bottomLeftOrigin=false ) + +.. ocv:pyfunction:: cv2.putText(img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]]) -> None + +.. ocv:cfunction:: void cvPutText( CvArr* img, const char* text, CvPoint org, const CvFont* font, CvScalar color ) +.. ocv:pyoldfunction:: cv.PutText(img, text, org, font, color)-> None + + :param img: Image. + + :param text: Text string to be drawn. + + :param org: Bottom-left corner of the text string in the image. + + :param font: ``CvFont`` structure initialized using :ocv:cfunc:`InitFont`. + + :param fontFace: Font type. One of ``FONT_HERSHEY_SIMPLEX``, ``FONT_HERSHEY_PLAIN``, ``FONT_HERSHEY_DUPLEX``, ``FONT_HERSHEY_COMPLEX``, ``FONT_HERSHEY_TRIPLEX``, ``FONT_HERSHEY_COMPLEX_SMALL``, ``FONT_HERSHEY_SCRIPT_SIMPLEX``, or ``FONT_HERSHEY_SCRIPT_COMPLEX``, + where each of the font ID's can be combined with ``FONT_HERSHEY_ITALIC`` to get the slanted letters. + + :param fontScale: Font scale factor that is multiplied by the font-specific base size. + + :param color: Text color. + + :param thickness: Thickness of the lines used to draw a text. + + :param lineType: Line type. See the ``line`` for details. + + :param bottomLeftOrigin: When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner. + +The function ``putText`` renders the specified text string in the image. +Symbols that cannot be rendered using the specified font are +replaced by question marks. See +:ocv:func:`getTextSize` for a text rendering code example. + diff --git a/core/doc/dynamic_structures.rst b/core/doc/dynamic_structures.rst new file mode 100644 index 0000000..df20690 --- /dev/null +++ b/core/doc/dynamic_structures.rst @@ -0,0 +1,1563 @@ +Dynamic Structures +================== + +.. highlight:: c + +The section describes OpenCV 1.x API for creating growable sequences and other dynamic data structures allocated in ``CvMemStorage``. If you use the new C++, Python, Java etc interface, you will unlikely need this functionality. Use ``std::vector`` or other high-level data structures. + +CvMemStorage +------------ + +.. ocv:struct:: CvMemStorage + + A storage for various OpenCV dynamic data structures, such as ``CvSeq``, ``CvSet`` etc. + + .. ocv:member:: CvMemBlock* bottom + + the first memory block in the double-linked list of blocks + + .. ocv:member:: CvMemBlock* top + + the current partially allocated memory block in the list of blocks + + .. ocv:member:: CvMemStorage* parent + + the parent storage (if any) from which the new memory blocks are borrowed. + + .. ocv:member:: int free_space + + number of free bytes in the ``top`` block + + .. ocv:member:: int block_size + + the total size of the memory blocks + +Memory storage is a low-level structure used to store dynamically growing data structures such as sequences, contours, graphs, subdivisions, etc. It is organized as a list of memory blocks of equal size - +``bottom`` field is the beginning of the list of blocks and ``top`` is the currently used block, but not necessarily the last block of the list. All blocks between ``bottom`` and ``top``, not including the +latter, are considered fully occupied; all blocks between ``top`` and the last block, not including ``top``, are considered free and ``top`` itself is partly occupied - ``free_space`` contains the number of free bytes left in the end of ``top``. + +A new memory buffer that may be allocated explicitly by :ocv:cfunc:`MemStorageAlloc` function or implicitly by higher-level functions, such as :ocv:cfunc:`SeqPush`, :ocv:cfunc:`GraphAddEdge` etc. + +The buffer is put in the end of already allocated space in the ``top`` memory block, if there is enough free space. After allocation, ``free_space`` is decreased by the size of the allocated buffer plus some padding to keep the proper alignment. When the allocated buffer does not fit into the available portion of +``top``, the next storage block from the list is taken as ``top`` and ``free_space`` is reset to the whole block size prior to the allocation. + +If there are no more free blocks, a new block is allocated (or borrowed from the parent, see :ocv:cfunc:`CreateChildMemStorage`) and added to the end of list. Thus, the storage behaves as a stack with ``bottom`` indicating bottom of the stack and the pair (``top``, ``free_space``) +indicating top of the stack. The stack top may be saved via :ocv:cfunc:`SaveMemStoragePos`, restored via +:ocv:cfunc:`RestoreMemStoragePos`, or reset via :ocv:cfunc:`ClearMemStorage`. + +CvMemBlock +---------- + +.. ocv:struct:: CvMemBlock + +The structure :ocv:struct:`CvMemBlock` represents a single block of memory storage. The actual data in the memory blocks follows the header. + +CvMemStoragePos +--------------- + +.. ocv:struct:: CvMemStoragePos + +The structure stores the position in the memory storage. It is used by :ocv:cfunc:`SaveMemStoragePos` and :ocv:cfunc:`RestoreMemStoragePos`. + +CvSeq +----- + +.. ocv:struct:: CvSeq + + Dynamically growing sequence. + + .. ocv:member:: int flags + + sequence flags, including the sequence signature (CV_SEQ_MAGIC_VAL or CV_SET_MAGIC_VAL), type of the elements and some other information about the sequence. + + .. ocv:member:: int header_size + + size of the sequence header. It should be sizeof(CvSeq) at minimum. See :ocv:cfunc:`CreateSeq`. + + .. ocv:member:: CvSeq* h_prev + .. ocv:member:: CvSeq* h_next + .. ocv:member:: CvSeq* v_prev + .. ocv:member:: CvSeq* v_next + + pointers to another sequences in a sequence tree. Sequence trees are used to store hierarchical contour structures, retrieved by :ocv:cfunc:`FindContours` + + .. ocv:member:: int total + + the number of sequence elements + + .. ocv:member:: int elem_size + + size of each sequence element in bytes + + .. ocv:member:: CvMemStorage* storage + + memory storage where the sequence resides. It can be a NULL pointer. + + .. ocv:member:: CvSeqBlock* first + + pointer to the first data block + +The structure ``CvSeq`` is a base for all of OpenCV dynamic data structures. +There are two types of sequences - dense and sparse. The base type for dense +sequences is :ocv:struct:`CvSeq` and such sequences are used to represent +growable 1d arrays - vectors, stacks, queues, and deques. They have no gaps +in the middle - if an element is removed from the middle or inserted +into the middle of the sequence, the elements from the closer end are +shifted. Sparse sequences have :ocv:struct:`CvSet` as a base class and they are +discussed later in more detail. They are sequences of nodes; each may be either occupied or free as indicated by the node flag. Such sequences are used for unordered data structures such as sets of elements, graphs, hash tables and so forth. + + +CvSlice +------- + +.. ocv:struct:: CvSlice + + A sequence slice. In C++ interface the class :ocv:class:`Range` should be used instead. + + .. ocv:member:: int start_index + + inclusive start index of the sequence slice + + .. ocv:member:: int end_index + + exclusive end index of the sequence slice + +There are helper functions to construct the slice and to compute its length: + +.. ocv:cfunction:: CvSlice cvSlice( int start, int end ) + + :param start: Inclusive left boundary. + + :param end: Exclusive right boundary. + +:: + + #define CV_WHOLE_SEQ_END_INDEX 0x3fffffff + #define CV_WHOLE_SEQ cvSlice(0, CV_WHOLE_SEQ_END_INDEX) + +.. ocv:cfunction:: int cvSliceLength( CvSlice slice, const CvSeq* seq ) + + :param slice: The slice of sequence. + + :param seq: Source sequence. + +Calculates the sequence slice length. + +Some of functions that operate on sequences take a ``CvSlice slice`` parameter that is often set to the whole sequence (CV_WHOLE_SEQ) by default. Either of the ``start_index`` and ``end_index`` may be negative or exceed the sequence length. If they are equal, the slice is considered empty (i.e., contains no elements). Because sequences are treated as circular structures, the slice may select a +few elements in the end of a sequence followed by a few elements at the beginning of the sequence. For example, ``cvSlice(-2, 3)`` in the case of a 10-element sequence will select a 5-element slice, containing the pre-last (8th), last (9th), the very first (0th), second (1th) and third (2nd) +elements. The functions normalize the slice argument in the following way: + + #. :ocv:cfunc:`SliceLength` is called to determine the length of the slice, + #. ``start_index`` of the slice is normalized similarly to the argument of :ocv:cfunc:`GetSeqElem` (i.e., negative indices are allowed). The actual slice to process starts at the normalized ``start_index`` and lasts :ocv:cfunc:`SliceLength` elements (again, assuming the sequence is a circular structure). + +If a function does not accept a slice argument, but you want to process only a part of the sequence, the sub-sequence may be extracted using the :ocv:cfunc:`SeqSlice` function, or stored into a continuous +buffer with :ocv:cfunc:`CvtSeqToArray` (optionally, followed by :ocv:cfunc:`MakeSeqHeaderForArray`). + +CvSet +----- + +.. ocv:struct:: CvSet + +The structure ``CvSet`` is a base for OpenCV 1.x sparse data structures. It is derived from :ocv:struct:`CvSeq` and includes an additional member ``free_elems`` - a list of free nodes. Every node of the set, whether free or not, is an element of the underlying sequence. While there are no restrictions on elements of dense sequences, the set (and derived structures) elements must start with an integer field and be able to fit CvSetElem structure, because these two fields (an integer followed by a pointer) are required for the organization of a node set with the list of free nodes. If a node is free, the ``flags`` +field is negative (the most-significant bit, or MSB, of the field is set), and the ``next_free`` points to the next free node (the first free node is referenced by the ``free_elems`` field of :ocv:struct:`CvSet`). And if a node is occupied, the ``flags`` field is positive and contains the node index that may be retrieved using the (``set_elem->flags & CV_SET_ELEM_IDX_MASK``) expressions, the rest of the node content is determined by the user. In particular, the occupied nodes are not linked as the free nodes are, so the second field can be used for such a link as well as for some different purpose. The macro ``CV_IS_SET_ELEM(set_elem_ptr)`` can be used to determined whether the specified node is occupied or not. + +Initially the set and the free node list are empty. When a new node is requested from the set, it is taken from the list of free nodes, which is then updated. If the list appears to be empty, a new sequence block is allocated and all the nodes within the block are joined in the list of free nodes. Thus, the ``total`` +field of the set is the total number of nodes both occupied and free. When an occupied node is released, it is added to the list of free nodes. The node released last will be occupied first. + +``CvSet`` is used to represent graphs (:ocv:struct:`CvGraph`), sparse multi-dimensional arrays (:ocv:struct:`CvSparseMat`), and planar subdivisions (:ocv:struct:`CvSubdiv2D`). + + +CvGraph +------- +.. ocv:struct:: CvGraph + +The structure ``CvGraph`` is a base for graphs used in OpenCV 1.x. It inherits from +:ocv:struct:`CvSet`, that is, it is considered as a set of vertices. Besides, it contains another set as a member, a set of graph edges. Graphs in OpenCV are represented using adjacency lists format. + + +CvGraphScanner +-------------- + +.. ocv:struct:: CvGraphScanner + +The structure ``CvGraphScanner`` is used for depth-first graph traversal. See discussion of the functions below. + + +CvTreeNodeIterator +------------------ + +.. ocv:struct:: CvTreeNodeIterator + +The structure ``CvTreeNodeIterator`` is used to traverse trees of sequences. + +ClearGraph +---------- +Clears a graph. + +.. ocv:cfunction:: void cvClearGraph( CvGraph* graph ) + + :param graph: Graph + +The function removes all vertices and edges from a graph. The function has O(1) time complexity. + +ClearMemStorage +--------------- +Clears memory storage. + +.. ocv:cfunction:: void cvClearMemStorage( CvMemStorage* storage ) + + :param storage: Memory storage + +The function resets the top (free space boundary) of the storage to the very beginning. This function does not deallocate any memory. If the storage has a parent, the function returns +all blocks to the parent. + +ClearSeq +-------- +Clears a sequence. + +.. ocv:cfunction:: void cvClearSeq( CvSeq* seq ) + + :param seq: Sequence + +The function removes all elements from a sequence. The function does not return the memory to the storage block, but this memory is reused later when new elements are added to the sequence. The function has +'O(1)' time complexity. + +.. note:: It is impossible to deallocate a sequence, i.e. free space in the memory storage occupied by the sequence. Instead, call :ocv:cfunc:`ClearMemStorage` or :ocv:cfunc:`ReleaseMemStorage` from time to time somewhere in a top-level processing loop. + +ClearSet +-------- +Clears a set. + +.. ocv:cfunction:: void cvClearSet( CvSet* set_header ) + + :param set_header: Cleared set + +The function removes all elements from set. It has O(1) time complexity. + +CloneGraph +---------- +Clones a graph. + +.. ocv:cfunction:: CvGraph* cvCloneGraph( const CvGraph* graph, CvMemStorage* storage ) + + :param graph: The graph to copy + + :param storage: Container for the copy + +The function creates a full copy of the specified graph. If the +graph vertices or edges have pointers to some external data, it can still be +shared between the copies. The vertex and edge indices in the new graph +may be different from the original because the function defragments +the vertex and edge sets. + +CloneSeq +-------- +Creates a copy of a sequence. + +.. ocv:cfunction:: CvSeq* cvCloneSeq( const CvSeq* seq, CvMemStorage* storage=NULL ) +.. ocv:pyoldfunction:: cv.CloneSeq(seq, storage)-> None + + :param seq: Sequence + + :param storage: The destination storage block to hold the new sequence header and the copied data, if any. If it is NULL, the function uses the storage block containing the input sequence. + +The function makes a complete copy of the input sequence and returns it. + +The call ``cvCloneSeq( seq, storage )`` is equivalent to ``cvSeqSlice( seq, CV_WHOLE_SEQ, storage, 1 )``. + + +CreateChildMemStorage +--------------------- +Creates child memory storage. + +.. ocv:cfunction:: CvMemStorage* cvCreateChildMemStorage(CvMemStorage* parent) + + :param parent: Parent memory storage + +The function creates a child memory +storage that is similar to simple memory storage except for the +differences in the memory allocation/deallocation mechanism. When a +child storage needs a new block to add to the block list, it tries +to get this block from the parent. The first unoccupied parent block +available is taken and excluded from the parent block list. If no blocks +are available, the parent either allocates a block or borrows one from +its own parent, if any. In other words, the chain, or a more complex +structure, of memory storages where every storage is a child/parent of +another is possible. When a child storage is released or even cleared, +it returns all blocks to the parent. In other aspects, child storage +is the same as simple storage. + +Child storage is useful in the following situation. Imagine +that the user needs to process dynamic data residing in a given storage area and +put the result back to that same storage area. With the simplest approach, +when temporary data is resided in the same storage area as the input and +output data, the storage area will look as follows after processing: + +Dynamic data processing without using child storage + +.. image:: pics/memstorage1.png + +That is, garbage appears in the middle of the storage. However, if +one creates a child memory storage at the beginning of processing, +writes temporary data there, and releases the child storage at the end, +no garbage will appear in the source/destination storage: + +Dynamic data processing using a child storage + +.. image:: pics/memstorage2.png + +CreateGraph +----------- +Creates an empty graph. + +.. ocv:cfunction:: CvGraph* cvCreateGraph( int graph_flags, int header_size, int vtx_size, int edge_size, CvMemStorage* storage ) + + + :param graph_flags: Type of the created graph. Usually, it is either ``CV_SEQ_KIND_GRAPH`` for generic unoriented graphs and ``CV_SEQ_KIND_GRAPH | CV_GRAPH_FLAG_ORIENTED`` for generic oriented graphs. + + :param header_size: Graph header size; may not be less than ``sizeof(CvGraph)`` + + :param vtx_size: Graph vertex size; the custom vertex structure must start with :ocv:struct:`CvGraphVtx` (use ``CV_GRAPH_VERTEX_FIELDS()`` ) + + :param edge_size: Graph edge size; the custom edge structure must start with :ocv:struct:`CvGraphEdge` (use ``CV_GRAPH_EDGE_FIELDS()`` ) + + :param storage: The graph container + +The function creates an empty graph and returns a pointer to it. + +CreateGraphScanner +------------------ +Creates structure for depth-first graph traversal. + +.. ocv:cfunction:: CvGraphScanner* cvCreateGraphScanner( CvGraph* graph, CvGraphVtx* vtx=NULL, int mask=CV_GRAPH_ALL_ITEMS ) + + + :param graph: Graph + + :param vtx: Initial vertex to start from. If NULL, the traversal starts from the first vertex (a vertex with the minimal index in the sequence of vertices). + + :param mask: Event mask indicating which events are of interest to the user (where :ocv:cfunc:`NextGraphItem` function returns control to the user) It can be ``CV_GRAPH_ALL_ITEMS`` (all events are of interest) or a combination of the following flags: + + * **CV_GRAPH_VERTEX** stop at the graph vertices visited for the first time + + * **CV_GRAPH_TREE_EDGE** stop at tree edges ( ``tree edge`` is the edge connecting the last visited vertex and the vertex to be visited next) + + * **CV_GRAPH_BACK_EDGE** stop at back edges ( ``back edge`` is an edge connecting the last visited vertex with some of its ancestors in the search tree) + + * **CV_GRAPH_FORWARD_EDGE** stop at forward edges ( ``forward edge`` is an edge connecting the last visited vertex with some of its descendants in the search tree. The forward edges are only possible during oriented graph traversal) + + * **CV_GRAPH_CROSS_EDGE** stop at cross edges ( ``cross edge`` is an edge connecting different search trees or branches of the same tree. The ``cross edges`` are only possible during oriented graph traversal) + + * **CV_GRAPH_ANY_EDGE** stop at any edge ( ``tree, back, forward`` , and ``cross edges`` ) + + * **CV_GRAPH_NEW_TREE** stop in the beginning of every new search tree. When the traversal procedure visits all vertices and edges reachable from the initial vertex (the visited vertices together with tree edges make up a tree), it searches for some unvisited vertex in the graph and resumes the traversal process from that vertex. Before starting a new tree (including the very first tree when ``cvNextGraphItem`` is called for the first time) it generates a ``CV_GRAPH_NEW_TREE`` event. For unoriented graphs, each search tree corresponds to a connected component of the graph. + + * **CV_GRAPH_BACKTRACKING** stop at every already visited vertex during backtracking - returning to already visited vertexes of the traversal tree. + +The function creates a structure for depth-first graph traversal/search. The initialized structure is used in the +:ocv:cfunc:`NextGraphItem` +function - the incremental traversal procedure. + +CreateMemStorage +---------------- +Creates memory storage. + +.. ocv:cfunction:: CvMemStorage* cvCreateMemStorage( int block_size=0 ) + +.. ocv:pyoldfunction:: cv.CreateMemStorage(blockSize=0) -> memstorage + + + :param block_size: Size of the storage blocks in bytes. If it is 0, the block size is set to a default value - currently it is about 64K. + +The function creates an empty memory storage. See +:ocv:struct:`CvMemStorage` +description. + +CreateSeq +--------- +Creates a sequence. + +.. ocv:cfunction:: CvSeq* cvCreateSeq( int seq_flags, size_t header_size, size_t elem_size, CvMemStorage* storage ) + + + :param seq_flags: Flags of the created sequence. If the sequence is not passed to any function working with a specific type of sequences, the sequence value may be set to 0, otherwise the appropriate type must be selected from the list of predefined sequence types. + + :param header_size: Size of the sequence header; must be greater than or equal to ``sizeof(CvSeq)`` . If a specific type or its extension is indicated, this type must fit the base type header. + + :param elem_size: Size of the sequence elements in bytes. The size must be consistent with the sequence type. For example, for a sequence of points to be created, the element type ``CV_SEQ_ELTYPE_POINT`` should be specified and the parameter ``elem_size`` must be equal to ``sizeof(CvPoint)`` . + + :param storage: Sequence location + +The function creates a sequence and returns +the pointer to it. The function allocates the sequence header in +the storage block as one continuous chunk and sets the structure +fields +``flags`` +, +``elemSize`` +, +``headerSize`` +, and +``storage`` +to passed values, sets +``delta_elems`` +to the +default value (that may be reassigned using the +:ocv:cfunc:`SetSeqBlockSize` +function), and clears other header fields, including the space following +the first +``sizeof(CvSeq)`` +bytes. + +CreateSet +--------- +Creates an empty set. + +.. ocv:cfunction:: CvSet* cvCreateSet( int set_flags, int header_size, int elem_size, CvMemStorage* storage ) + + :param set_flags: Type of the created set + + :param header_size: Set header size; may not be less than ``sizeof(CvSet)`` + + :param elem_size: Set element size; may not be less than :ocv:struct:`CvSetElem` + + :param storage: Container for the set + +The function creates an empty set with a specified header size and element size, and returns the pointer to the set. This function is just a thin layer on top of +:ocv:cfunc:`CreateSeq`. + +CvtSeqToArray +------------- +Copies a sequence to one continuous block of memory. + +.. ocv:cfunction:: void* cvCvtSeqToArray( const CvSeq* seq, void* elements, CvSlice slice=CV_WHOLE_SEQ ) + + :param seq: Sequence + + :param elements: Pointer to the destination array that must be large enough. It should be a pointer to data, not a matrix header. + + :param slice: The sequence portion to copy to the array + +The function copies the entire sequence or subsequence to the specified buffer and returns the pointer to the buffer. + +EndWriteSeq +----------- +Finishes the process of writing a sequence. + +.. ocv:cfunction:: CvSeq* cvEndWriteSeq( CvSeqWriter* writer ) + + :param writer: Writer state + +The function finishes the writing process and +returns the pointer to the written sequence. The function also truncates +the last incomplete sequence block to return the remaining part of the +block to memory storage. After that, the sequence can be read and +modified safely. See +:ocv:cfunc:`StartWriteSeq` +and +:ocv:cfunc:`StartAppendToSeq` + +FindGraphEdge +------------- +Finds an edge in a graph. + +.. ocv:cfunction:: CvGraphEdge* cvFindGraphEdge( const CvGraph* graph, int start_idx, int end_idx ) + + :param graph: Graph + + :param start_idx: Index of the starting vertex of the edge + + :param end_idx: Index of the ending vertex of the edge. For an unoriented graph, the order of the vertex parameters does not matter. + +:: + + #define cvGraphFindEdge cvFindGraphEdge + +.. + +The function finds the graph edge connecting two specified vertices and returns a pointer to it or NULL if the edge does not exist. + +FindGraphEdgeByPtr +------------------ +Finds an edge in a graph by using its pointer. + +.. ocv:cfunction:: CvGraphEdge* cvFindGraphEdgeByPtr( const CvGraph* graph, const CvGraphVtx* start_vtx, const CvGraphVtx* end_vtx ) + + :param graph: Graph + + :param start_vtx: Pointer to the starting vertex of the edge + + :param end_vtx: Pointer to the ending vertex of the edge. For an unoriented graph, the order of the vertex parameters does not matter. + +:: + + #define cvGraphFindEdgeByPtr cvFindGraphEdgeByPtr + +.. + +The function finds the graph edge connecting two specified vertices and returns pointer to it or NULL if the edge does not exists. + +FlushSeqWriter +-------------- +Updates sequence headers from the writer. + +.. ocv:cfunction:: void cvFlushSeqWriter( CvSeqWriter* writer ) + + :param writer: Writer state + +The function is intended to enable the user to +read sequence elements, whenever required, during the writing process, +e.g., in order to check specific conditions. The function updates the +sequence headers to make reading from the sequence possible. The writer +is not closed, however, so that the writing process can be continued at +any time. If an algorithm requires frequent flushes, consider using +:ocv:cfunc:`SeqPush` +instead. + +GetGraphVtx +----------- +Finds a graph vertex by using its index. + +.. ocv:cfunction:: CvGraphVtx* cvGetGraphVtx( CvGraph* graph, int vtx_idx ) + + :param graph: Graph + + :param vtx_idx: Index of the vertex + +The function finds the graph vertex by using its index and returns the pointer to it or NULL if the vertex does not belong to the graph. + +GetSeqElem +---------- +Returns a pointer to a sequence element according to its index. + +.. ocv:cfunction:: schar* cvGetSeqElem( const CvSeq* seq, int index ) + + :param seq: Sequence + + :param index: Index of element + +:: + + #define CV_GET_SEQ_ELEM( TYPE, seq, index ) (TYPE*)cvGetSeqElem( (CvSeq*)(seq), (index) ) + +.. + + +The function finds the element with the given +index in the sequence and returns the pointer to it. If the element +is not found, the function returns 0. The function supports negative +indices, where -1 stands for the last sequence element, -2 stands for +the one before last, etc. If the sequence is most likely to consist of +a single sequence block or the desired element is likely to be located +in the first block, then the macro +``CV_GET_SEQ_ELEM( elemType, seq, index )`` +should be used, where the parameter +``elemType`` +is the +type of sequence elements ( +:ocv:struct:`CvPoint` +for example), the parameter +``seq`` +is a sequence, and the parameter +``index`` +is the index +of the desired element. The macro checks first whether the desired element +belongs to the first block of the sequence and returns it if it does; +otherwise the macro calls the main function +``GetSeqElem`` +. Negative +indices always cause the +:ocv:cfunc:`GetSeqElem` +call. The function has O(1) +time complexity assuming that the number of blocks is much smaller than the +number of elements. + +GetSeqReaderPos +--------------- +Returns the current reader position. + +.. ocv:cfunction:: int cvGetSeqReaderPos( CvSeqReader* reader ) + + :param reader: Reader state + +The function returns the current reader position (within 0 ... +``reader->seq->total`` +- 1). + +GetSetElem +---------- +Finds a set element by its index. + +.. ocv:cfunction:: CvSetElem* cvGetSetElem( const CvSet* set_header, int idx ) + + :param set_header: Set + + :param idx: Index of the set element within a sequence + +The function finds a set element by its index. The function returns the pointer to it or 0 if the index is invalid or the corresponding node is free. The function supports negative indices as it uses +:ocv:cfunc:`GetSeqElem` +to locate the node. + +GraphAddEdge +------------ +Adds an edge to a graph. + +.. ocv:cfunction:: int cvGraphAddEdge( CvGraph* graph, int start_idx, int end_idx, const CvGraphEdge* edge=NULL, CvGraphEdge** inserted_edge=NULL ) + + :param graph: Graph + + :param start_idx: Index of the starting vertex of the edge + + :param end_idx: Index of the ending vertex of the edge. For an unoriented graph, the order of the vertex parameters does not matter. + + :param edge: Optional input parameter, initialization data for the edge + + :param inserted_edge: Optional output parameter to contain the address of the inserted edge + +The function connects two specified vertices. The function returns 1 if the edge has been added successfully, 0 if the edge connecting the two vertices exists already and -1 if either of the vertices was not found, the starting and the ending vertex are the same, or there is some other critical situation. In the latter case (i.e., when the result is negative), the function also reports an error by default. + +GraphAddEdgeByPtr +----------------- +Adds an edge to a graph by using its pointer. + +.. ocv:cfunction:: int cvGraphAddEdgeByPtr( CvGraph* graph, CvGraphVtx* start_vtx, CvGraphVtx* end_vtx, const CvGraphEdge* edge=NULL, CvGraphEdge** inserted_edge=NULL ) + + :param graph: Graph + + :param start_vtx: Pointer to the starting vertex of the edge + + :param end_vtx: Pointer to the ending vertex of the edge. For an unoriented graph, the order of the vertex parameters does not matter. + + :param edge: Optional input parameter, initialization data for the edge + + :param inserted_edge: Optional output parameter to contain the address of the inserted edge within the edge set + +The function connects two specified vertices. The +function returns 1 if the edge has been added successfully, 0 if the +edge connecting the two vertices exists already, and -1 if either of the +vertices was not found, the starting and the ending vertex are the same +or there is some other critical situation. In the latter case (i.e., when +the result is negative), the function also reports an error by default. + +GraphAddVtx +----------- +Adds a vertex to a graph. + +.. ocv:cfunction:: int cvGraphAddVtx( CvGraph* graph, const CvGraphVtx* vtx=NULL, CvGraphVtx** inserted_vtx=NULL ) + + :param graph: Graph + + :param vtx: Optional input argument used to initialize the added vertex (only user-defined fields beyond ``sizeof(CvGraphVtx)`` are copied) + + :param inserted_vtx: Optional output argument. If not ``NULL`` , the address of the new vertex is written here. + +The function adds a vertex to the graph and returns the vertex index. + +GraphEdgeIdx +------------ +Returns the index of a graph edge. + +.. ocv:cfunction:: int cvGraphEdgeIdx( CvGraph* graph, CvGraphEdge* edge ) + + :param graph: Graph + + :param edge: Pointer to the graph edge + +The function returns the index of a graph edge. + +GraphRemoveEdge +--------------- +Removes an edge from a graph. + +.. ocv:cfunction:: void cvGraphRemoveEdge( CvGraph* graph, int start_idx, int end_idx ) + + :param graph: Graph + + :param start_idx: Index of the starting vertex of the edge + + :param end_idx: Index of the ending vertex of the edge. For an unoriented graph, the order of the vertex parameters does not matter. + +The function removes the edge connecting two specified vertices. If the vertices are not connected [in that order], the function does nothing. + +GraphRemoveEdgeByPtr +-------------------- +Removes an edge from a graph by using its pointer. + +.. ocv:cfunction:: void cvGraphRemoveEdgeByPtr( CvGraph* graph, CvGraphVtx* start_vtx, CvGraphVtx* end_vtx ) + + :param graph: Graph + + :param start_vtx: Pointer to the starting vertex of the edge + + :param end_vtx: Pointer to the ending vertex of the edge. For an unoriented graph, the order of the vertex parameters does not matter. + +The function removes the edge connecting two specified vertices. If the vertices are not connected [in that order], the function does nothing. + +GraphRemoveVtx +-------------- +Removes a vertex from a graph. + +.. ocv:cfunction:: int cvGraphRemoveVtx( CvGraph* graph, int index ) + + :param graph: Graph + + :param index: Index of the removed vertex + +The function removes a vertex from a graph +together with all the edges incident to it. The function reports an error +if the input vertex does not belong to the graph. The return value is the +number of edges deleted, or -1 if the vertex does not belong to the graph. + +GraphRemoveVtxByPtr +------------------- +Removes a vertex from a graph by using its pointer. + +.. ocv:cfunction:: int cvGraphRemoveVtxByPtr( CvGraph* graph, CvGraphVtx* vtx ) + + :param graph: Graph + + :param vtx: Pointer to the removed vertex + +The function removes a vertex from the graph by using its pointer together with all the edges incident to it. The function reports an error if the vertex does not belong to the graph. The return value is the number of edges deleted, or -1 if the vertex does not belong to the graph. + +GraphVtxDegree +-------------- +Counts the number of edges incident to the vertex. + +.. ocv:cfunction:: int cvGraphVtxDegree( const CvGraph* graph, int vtx_idx ) + + :param graph: Graph + + :param vtx_idx: Index of the graph vertex + +The function returns the number of edges incident to the specified vertex, both incoming and outgoing. To count the edges, the following code is used: + +:: + + CvGraphEdge* edge = vertex->first; int count = 0; + while( edge ) + { + edge = CV_NEXT_GRAPH_EDGE( edge, vertex ); + count++; + } + +.. + +The macro +``CV_NEXT_GRAPH_EDGE( edge, vertex )`` +returns the edge incident to +``vertex`` +that follows after +``edge`` +. + +GraphVtxDegreeByPtr +------------------- +Finds an edge in a graph. + +.. ocv:cfunction:: int cvGraphVtxDegreeByPtr( const CvGraph* graph, const CvGraphVtx* vtx ) + + :param graph: Graph + + :param vtx: Pointer to the graph vertex + +The function returns the number of edges incident to the specified vertex, both incoming and outcoming. + +GraphVtxIdx +----------- +Returns the index of a graph vertex. + +.. ocv:cfunction:: int cvGraphVtxIdx( CvGraph* graph, CvGraphVtx* vtx ) + + :param graph: Graph + + :param vtx: Pointer to the graph vertex + +The function returns the index of a graph vertex. + +InitTreeNodeIterator +-------------------- +Initializes the tree node iterator. + +.. ocv:cfunction:: void cvInitTreeNodeIterator( CvTreeNodeIterator* tree_iterator, const void* first, int max_level ) + + :param tree_iterator: Tree iterator initialized by the function + + :param first: The initial node to start traversing from + + :param max_level: The maximal level of the tree ( ``first`` node assumed to be at the first level) to traverse up to. For example, 1 means that only nodes at the same level as ``first`` should be visited, 2 means that the nodes on the same level as ``first`` and their direct children should be visited, and so forth. + +The function initializes the tree iterator. The tree is traversed in depth-first order. + +InsertNodeIntoTree +------------------ +Adds a new node to a tree. + +.. ocv:cfunction:: void cvInsertNodeIntoTree( void* node, void* parent, void* frame ) + + :param node: The inserted node + + :param parent: The parent node that is already in the tree + + :param frame: The top level node. If ``parent`` and ``frame`` are the same, the ``v_prev`` field of ``node`` is set to NULL rather than ``parent`` . + +The function adds another node into tree. The function does not allocate any memory, it can only modify links of the tree nodes. + +MakeSeqHeaderForArray +--------------------- +Constructs a sequence header for an array. + +.. ocv:cfunction:: CvSeq* cvMakeSeqHeaderForArray( int seq_type, int header_size, int elem_size, void* elements, int total, CvSeq* seq, CvSeqBlock* block ) + + :param seq_type: Type of the created sequence + + :param header_size: Size of the header of the sequence. Parameter sequence must point to the structure of that size or greater + + :param elem_size: Size of the sequence elements + + :param elements: Elements that will form a sequence + + :param total: Total number of elements in the sequence. The number of array elements must be equal to the value of this parameter. + + :param seq: Pointer to the local variable that is used as the sequence header + + :param block: Pointer to the local variable that is the header of the single sequence block + +The function initializes a sequence +header for an array. The sequence header as well as the sequence block are +allocated by the user (for example, on stack). No data is copied by the +function. The resultant sequence will consists of a single block and +have NULL storage pointer; thus, it is possible to read its elements, +but the attempts to add elements to the sequence will raise an error in +most cases. + +MemStorageAlloc +--------------- +Allocates a memory buffer in a storage block. + +.. ocv:cfunction:: void* cvMemStorageAlloc( CvMemStorage* storage, size_t size ) + + :param storage: Memory storage + + :param size: Buffer size + +The function allocates a memory buffer in +a storage block. The buffer size must not exceed the storage block size, +otherwise a runtime error is raised. The buffer address is aligned by +``CV_STRUCT_ALIGN=sizeof(double)`` +(for the moment) bytes. + +MemStorageAllocString +--------------------- +Allocates a text string in a storage block. + +.. ocv:cfunction:: CvString cvMemStorageAllocString(CvMemStorage* storage, const char* ptr, int len=-1) + + :param storage: Memory storage + + :param ptr: The string + + :param len: Length of the string (not counting the ending ``NUL`` ) . If the parameter is negative, the function computes the length. + +:: + + typedef struct CvString + { + int len; + char* ptr; + } + CvString; + +.. + +The function creates copy of the string +in memory storage. It returns the structure that contains user-passed +or computed length of the string and pointer to the copied string. + +NextGraphItem +------------- +Executes one or more steps of the graph traversal procedure. + +.. ocv:cfunction:: int cvNextGraphItem( CvGraphScanner* scanner ) + + :param scanner: Graph traversal state. It is updated by this function. + +The function traverses through the graph +until an event of interest to the user (that is, an event, specified +in the +``mask`` +in the +:ocv:cfunc:`CreateGraphScanner` +call) is met or the +traversal is completed. In the first case, it returns one of the events +listed in the description of the +``mask`` +parameter above and with +the next call it resumes the traversal. In the latter case, it returns +``CV_GRAPH_OVER`` +(-1). When the event is +``CV_GRAPH_VERTEX`` +, +``CV_GRAPH_BACKTRACKING`` +, or +``CV_GRAPH_NEW_TREE`` +, +the currently observed vertex is stored in +``scanner-:math:`>`vtx`` +. And if the +event is edge-related, the edge itself is stored at +``scanner-:math:`>`edge`` +, +the previously visited vertex - at +``scanner-:math:`>`vtx`` +and the other ending +vertex of the edge - at +``scanner-:math:`>`dst`` +. + +NextTreeNode +------------ +Returns the currently observed node and moves the iterator toward the next node. + +.. ocv:cfunction:: void* cvNextTreeNode( CvTreeNodeIterator* tree_iterator ) + + :param tree_iterator: Tree iterator initialized by the function + +The function returns the currently observed node and then updates the +iterator - moving it toward the next node. In other words, the function +behavior is similar to the +``*p++`` +expression on a typical C +pointer or C++ collection iterator. The function returns NULL if there +are no more nodes. + +PrevTreeNode +------------ +Returns the currently observed node and moves the iterator toward the previous node. + +.. ocv:cfunction:: void* cvPrevTreeNode( CvTreeNodeIterator* tree_iterator ) + + :param tree_iterator: Tree iterator initialized by the function + +The function returns the currently observed node and then updates +the iterator - moving it toward the previous node. In other words, +the function behavior is similar to the +``*p--`` +expression on a +typical C pointer or C++ collection iterator. The function returns NULL +if there are no more nodes. + +ReleaseGraphScanner +------------------- +Completes the graph traversal procedure. + +.. ocv:cfunction:: void cvReleaseGraphScanner( CvGraphScanner** scanner ) + + :param scanner: Double pointer to graph traverser + +The function completes the graph traversal procedure and releases the traverser state. + +ReleaseMemStorage +----------------- +Releases memory storage. + +.. ocv:cfunction:: void cvReleaseMemStorage( CvMemStorage** storage ) + + :param storage: Pointer to the released storage + +The function deallocates all storage memory +blocks or returns them to the parent, if any. Then it deallocates the +storage header and clears the pointer to the storage. All child storage +associated with a given parent storage block must be released before the +parent storage block is released. + +RestoreMemStoragePos +-------------------- +Restores memory storage position. + +.. ocv:cfunction:: void cvRestoreMemStoragePos( CvMemStorage* storage, CvMemStoragePos* pos) + + :param storage: Memory storage + + :param pos: New storage top position + +The function restores the position of the storage top from the parameter +``pos`` +. This function and the function +``cvClearMemStorage`` +are the only methods to release memory occupied in memory blocks. Note again that there is no way to free memory in the middle of an occupied portion of a storage block. + +SaveMemStoragePos +----------------- +Saves memory storage position. + +.. ocv:cfunction:: void cvSaveMemStoragePos( const CvMemStorage* storage, CvMemStoragePos* pos) + + :param storage: Memory storage + + :param pos: The output position of the storage top + +The function saves the current position +of the storage top to the parameter +``pos`` +. The function +``cvRestoreMemStoragePos`` +can further retrieve this position. + +SeqElemIdx +---------- +Returns the index of a specific sequence element. + +.. ocv:cfunction:: int cvSeqElemIdx( const CvSeq* seq, const void* element, CvSeqBlock** block=NULL ) + + :param seq: Sequence + + :param element: Pointer to the element within the sequence + + :param block: Optional argument. If the pointer is not ``NULL`` , the address of the sequence block that contains the element is stored in this location. + +The function returns the index of a sequence element or a negative number if the element is not found. + +SeqInsert +--------- +Inserts an element in the middle of a sequence. + +.. ocv:cfunction:: schar* cvSeqInsert( CvSeq* seq, int before_index, const void* element=NULL ) + + :param seq: Sequence + + :param before_index: Index before which the element is inserted. Inserting before 0 (the minimal allowed value of the parameter) is equal to :ocv:cfunc:`SeqPushFront` and inserting before ``seq->total`` (the maximal allowed value of the parameter) is equal to :ocv:cfunc:`SeqPush` . + + :param element: Inserted element + +The function shifts the sequence elements from the inserted position to the nearest end of the sequence and copies the +``element`` +content there if the pointer is not NULL. The function returns a pointer to the inserted element. + +SeqInsertSlice +-------------- +Inserts an array in the middle of a sequence. + +.. ocv:cfunction:: void cvSeqInsertSlice( CvSeq* seq, int before_index, const CvArr* from_arr ) + + :param seq: Sequence + + :param before_index: Index before which the array is inserted + + :param from_arr: The array to take elements from + +The function inserts all +``fromArr`` +array elements at the specified position of the sequence. The array +``fromArr`` +can be a matrix or another sequence. + +SeqInvert +--------- +Reverses the order of sequence elements. + +.. ocv:cfunction:: void cvSeqInvert( CvSeq* seq ) + + :param seq: Sequence + +The function reverses the sequence in-place - the first element becomes the last one, the last element becomes the first one and so forth. + +SeqPop +------ +Removes an element from the end of a sequence. + +.. ocv:cfunction:: void cvSeqPop( CvSeq* seq, void* element=NULL ) + + :param seq: Sequence + + :param element: Optional parameter . If the pointer is not zero, the function copies the removed element to this location. + +The function removes an element from a sequence. The function reports an error if the sequence is already empty. The function has O(1) complexity. + +SeqPopFront +----------- +Removes an element from the beginning of a sequence. + +.. ocv:cfunction:: void cvSeqPopFront( CvSeq* seq, void* element=NULL ) + + :param seq: Sequence + + :param element: Optional parameter. If the pointer is not zero, the function copies the removed element to this location. + +The function removes an element from the beginning of a sequence. The function reports an error if the sequence is already empty. The function has O(1) complexity. + +SeqPopMulti +----------- +Removes several elements from either end of a sequence. + +.. ocv:cfunction:: void cvSeqPopMulti( CvSeq* seq, void* elements, int count, int in_front=0 ) + + :param seq: Sequence + + :param elements: Removed elements + + :param count: Number of elements to pop + + :param in_front: The flags specifying which end of the modified sequence. + + * **CV_BACK** the elements are added to the end of the sequence + + * **CV_FRONT** the elements are added to the beginning of the sequence + +The function removes several elements from either end of the sequence. If the number of the elements to be removed exceeds the total number of elements in the sequence, the function removes as many elements as possible. + +SeqPush +------- +Adds an element to the end of a sequence. + +.. ocv:cfunction:: schar* cvSeqPush( CvSeq* seq, const void* element=NULL ) + + :param seq: Sequence + + :param element: Added element + +The function adds an element to the end of a sequence and returns a pointer to the allocated element. If the input +``element`` +is NULL, the function simply allocates a space for one more element. + +The following code demonstrates how to create a new sequence using this function: + +:: + + CvMemStorage* storage = cvCreateMemStorage(0); + CvSeq* seq = cvCreateSeq( CV_32SC1, /* sequence of integer elements */ + sizeof(CvSeq), /* header size - no extra fields */ + sizeof(int), /* element size */ + storage /* the container storage */ ); + int i; + for( i = 0; i < 100; i++ ) + { + int* added = (int*)cvSeqPush( seq, &i ); + printf( " + } + + ... + /* release memory storage in the end */ + cvReleaseMemStorage( &storage ); + +.. + +The function has O(1) complexity, but there is a faster method for writing large sequences (see +:ocv:cfunc:`StartWriteSeq` +and related functions). + +SeqPushFront +------------ +Adds an element to the beginning of a sequence. + +.. ocv:cfunction:: schar* cvSeqPushFront( CvSeq* seq, const void* element=NULL ) + + :param seq: Sequence + + :param element: Added element + +The function is similar to +:ocv:cfunc:`SeqPush` +but it adds the new element to the beginning of the sequence. The function has O(1) complexity. + +SeqPushMulti +------------ +Pushes several elements to either end of a sequence. + +.. ocv:cfunction:: void cvSeqPushMulti( CvSeq* seq, const void* elements, int count, int in_front=0 ) + + :param seq: Sequence + + :param elements: Added elements + + :param count: Number of elements to push + + :param in_front: The flags specifying which end of the modified sequence. + + * **CV_BACK** the elements are added to the end of the sequence + + * **CV_FRONT** the elements are added to the beginning of the sequence + +The function adds several elements to either +end of a sequence. The elements are added to the sequence in the same +order as they are arranged in the input array but they can fall into +different sequence blocks. + +SeqRemove +--------- +Removes an element from the middle of a sequence. + +.. ocv:cfunction:: void cvSeqRemove( CvSeq* seq, int index ) + + :param seq: Sequence + + :param index: Index of removed element + +The function removes elements with the given +index. If the index is out of range the function reports an error. An +attempt to remove an element from an empty sequence is a special +case of this situation. The function removes an element by shifting +the sequence elements between the nearest end of the sequence and the +``index`` +-th position, not counting the latter. + +SeqRemoveSlice +-------------- +Removes a sequence slice. + +.. ocv:cfunction:: void cvSeqRemoveSlice( CvSeq* seq, CvSlice slice ) + + :param seq: Sequence + + :param slice: The part of the sequence to remove + +The function removes a slice from the sequence. + +SeqSearch +--------- +Searches for an element in a sequence. + +.. ocv:cfunction:: schar* cvSeqSearch( CvSeq* seq, const void* elem, CvCmpFunc func, int is_sorted, int* elem_idx, void* userdata=NULL ) + + :param seq: The sequence + + :param elem: The element to look for + + :param func: The comparison function that returns negative, zero or positive value depending on the relationships among the elements (see also :ocv:cfunc:`SeqSort` ) + + :param is_sorted: Whether the sequence is sorted or not + + :param elem_idx: Output parameter; index of the found element + + :param userdata: The user parameter passed to the comparison function; helps to avoid global variables in some cases + +:: + + /* a < b ? -1 : a > b ? 1 : 0 */ + typedef int (CV_CDECL* CvCmpFunc)(const void* a, const void* b, void* userdata); + +.. + +The function searches for the element in the sequence. If +the sequence is sorted, a binary O(log(N)) search is used; otherwise, a +simple linear search is used. If the element is not found, the function +returns a NULL pointer and the index is set to the number of sequence +elements if a linear search is used, or to the smallest index +``i, seq(i)>elem`` +. + +SeqSlice +-------- +Makes a separate header for a sequence slice. + +.. ocv:cfunction:: CvSeq* cvSeqSlice( const CvSeq* seq, CvSlice slice, CvMemStorage* storage=NULL, int copy_data=0 ) + + :param seq: Sequence + + :param slice: The part of the sequence to be extracted + + :param storage: The destination storage block to hold the new sequence header and the copied data, if any. If it is NULL, the function uses the storage block containing the input sequence. + + :param copy_data: The flag that indicates whether to copy the elements of the extracted slice ( ``copy_data!=0`` ) or not ( ``copy_data=0`` ) + +The function creates a sequence that represents the specified slice of the input sequence. The new sequence either shares the elements with the original sequence or has its own copy of the elements. So if one needs to process a part of sequence but the processing function does not have a slice parameter, the required sub-sequence may be extracted using this function. + +SeqSort +------- +Sorts sequence element using the specified comparison function. + +.. ocv:cfunction:: void cvSeqSort( CvSeq* seq, CvCmpFunc func, void* userdata=NULL ) + + :param seq: The sequence to sort + + :param func: The comparison function that returns a negative, zero, or positive value depending on the relationships among the elements (see the above declaration and the example below) - a similar function is used by ``qsort`` from C runline except that in the latter, ``userdata`` is not used + + :param userdata: The user parameter passed to the comparison function; helps to avoid global variables in some cases + +:: + + /* a < b ? -1 : a > b ? 1 : 0 */ + typedef int (CV_CDECL* CvCmpFunc)(const void* a, const void* b, void* userdata); + +.. + +The function sorts the sequence in-place using the specified criteria. Below is an example of using this function: + +:: + + /* Sort 2d points in top-to-bottom left-to-right order */ + static int cmp_func( const void* _a, const void* _b, void* userdata ) + { + CvPoint* a = (CvPoint*)_a; + CvPoint* b = (CvPoint*)_b; + int y_diff = a->y - b->y; + int x_diff = a->x - b->x; + return y_diff ? y_diff : x_diff; + } + + ... + + CvMemStorage* storage = cvCreateMemStorage(0); + CvSeq* seq = cvCreateSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage ); + int i; + + for( i = 0; i < 10; i++ ) + { + CvPoint pt; + pt.x = rand() + pt.y = rand() + cvSeqPush( seq, &pt ); + } + + cvSeqSort( seq, cmp_func, 0 /* userdata is not used here */ ); + + /* print out the sorted sequence */ + for( i = 0; i < seq->total; i++ ) + { + CvPoint* pt = (CvPoint*)cvSeqElem( seq, i ); + printf( "( + } + + cvReleaseMemStorage( &storage ); + +.. + +SetAdd +------ +Occupies a node in the set. + +.. ocv:cfunction:: int cvSetAdd( CvSet* set_header, CvSetElem* elem=NULL, CvSetElem** inserted_elem=NULL ) + + :param set_header: Set + + :param elem: Optional input argument, an inserted element. If not NULL, the function copies the data to the allocated node (the MSB of the first integer field is cleared after copying). + + :param inserted_elem: Optional output argument; the pointer to the allocated cell + +The function allocates a new node, optionally copies +input element data to it, and returns the pointer and the index to the +node. The index value is taken from the lower bits of the +``flags`` +field of the node. The function has O(1) complexity; however, there exists +a faster function for allocating set nodes (see +:ocv:cfunc:`SetNew` +). + +SetNew +------ +Adds an element to a set (fast variant). + +.. ocv:cfunction:: CvSetElem* cvSetNew( CvSet* set_header ) + + :param set_header: Set + +The function is an inline lightweight variant of +:ocv:cfunc:`SetAdd` +. It occupies a new node and returns a pointer to it rather than an index. + +SetRemove +--------- +Removes an element from a set. + +.. ocv:cfunction:: void cvSetRemove( CvSet* set_header, int index ) + + :param set_header: Set + + :param index: Index of the removed element + +The function removes an element with a specified +index from the set. If the node at the specified location is not occupied, +the function does nothing. The function has O(1) complexity; however, +:ocv:cfunc:`SetRemoveByPtr` +provides a quicker way to remove a set element +if it is located already. + +SetRemoveByPtr +-------------- +Removes a set element based on its pointer. + +.. ocv:cfunction:: void cvSetRemoveByPtr( CvSet* set_header, void* elem ) + + :param set_header: Set + + :param elem: Removed element + +The function is an inline lightweight variant of +:ocv:cfunc:`SetRemove` +that requires an element pointer. The function does not check whether the node is occupied or not - the user should take care of that. + +SetSeqBlockSize +--------------- +Sets up sequence block size. + +.. ocv:cfunction:: void cvSetSeqBlockSize( CvSeq* seq, int delta_elems ) + + :param seq: Sequence + + :param delta_elems: Desirable sequence block size for elements + +The function affects memory allocation +granularity. When the free space in the sequence buffers has run out, +the function allocates the space for +``delta_elems`` +sequence +elements. If this block immediately follows the one previously allocated, +the two blocks are concatenated; otherwise, a new sequence block is +created. Therefore, the bigger the parameter is, the lower the possible +sequence fragmentation, but the more space in the storage block is wasted. When +the sequence is created, the parameter +``delta_elems`` +is set to +the default value of about 1K. The function can be called any time after +the sequence is created and affects future allocations. The function +can modify the passed value of the parameter to meet memory storage +constraints. + +SetSeqReaderPos +--------------- +Moves the reader to the specified position. + +.. ocv:cfunction:: void cvSetSeqReaderPos( CvSeqReader* reader, int index, int is_relative=0 ) + + :param reader: Reader state + + :param index: The destination position. If the positioning mode is used (see the next parameter), the actual position will be ``index`` mod ``reader->seq->total`` . + + :param is_relative: If it is not zero, then ``index`` is a relative to the current position + +The function moves the read position to an absolute position or relative to the current position. + +StartAppendToSeq +---------------- +Initializes the process of writing data to a sequence. + +.. ocv:cfunction:: void cvStartAppendToSeq( CvSeq* seq, CvSeqWriter* writer ) + + :param seq: Pointer to the sequence + + :param writer: Writer state; initialized by the function + +The function initializes the process of +writing data to a sequence. Written elements are added to the end of the +sequence by using the +``CV_WRITE_SEQ_ELEM( written_elem, writer )`` +macro. Note +that during the writing process, other operations on the sequence may +yield an incorrect result or even corrupt the sequence (see description of +:ocv:cfunc:`FlushSeqWriter` +, which helps to avoid some of these problems). + +StartReadSeq +------------ +Initializes the process of sequential reading from a sequence. + +.. ocv:cfunction:: void cvStartReadSeq( const CvSeq* seq, CvSeqReader* reader, int reverse=0 ) + + :param seq: Sequence + + :param reader: Reader state; initialized by the function + + :param reverse: Determines the direction of the sequence traversal. If ``reverse`` is 0, the reader is positioned at the first sequence element; otherwise it is positioned at the last element. + +The function initializes the reader state. After +that, all the sequence elements from the first one down to the last one +can be read by subsequent calls of the macro +``CV_READ_SEQ_ELEM( read_elem, reader )`` +in the case of forward reading and by using +``CV_REV_READ_SEQ_ELEM( read_elem, reader )`` +in the case of reverse +reading. Both macros put the sequence element to +``read_elem`` +and +move the reading pointer toward the next element. A circular structure +of sequence blocks is used for the reading process, that is, after the +last element has been read by the macro +``CV_READ_SEQ_ELEM`` +, the +first element is read when the macro is called again. The same applies to +``CV_REV_READ_SEQ_ELEM`` +. There is no function to finish the reading +process, since it neither changes the sequence nor creates any temporary +buffers. The reader field +``ptr`` +points to the current element of +the sequence that is to be read next. The code below demonstrates how +to use the sequence writer and reader. + +:: + + CvMemStorage* storage = cvCreateMemStorage(0); + CvSeq* seq = cvCreateSeq( CV_32SC1, sizeof(CvSeq), sizeof(int), storage ); + CvSeqWriter writer; + CvSeqReader reader; + int i; + + cvStartAppendToSeq( seq, &writer ); + for( i = 0; i < 10; i++ ) + { + int val = rand() + CV_WRITE_SEQ_ELEM( val, writer ); + printf(" + } + cvEndWriteSeq( &writer ); + + cvStartReadSeq( seq, &reader, 0 ); + for( i = 0; i < seq->total; i++ ) + { + int val; + #if 1 + CV_READ_SEQ_ELEM( val, reader ); + printf(" + #else /* alternative way, that is prefferable if sequence elements are large, + or their size/type is unknown at compile time */ + printf(" + CV_NEXT_SEQ_ELEM( seq->elem_size, reader ); + #endif + } + ... + + cvReleaseStorage( &storage ); + +.. + +StartWriteSeq +------------- +Creates a new sequence and initializes a writer for it. + +.. ocv:cfunction:: void cvStartWriteSeq( int seq_flags, int header_size, int elem_size, CvMemStorage* storage, CvSeqWriter* writer ) + + :param seq_flags: Flags of the created sequence. If the sequence is not passed to any function working with a specific type of sequences, the sequence value may be equal to 0; otherwise the appropriate type must be selected from the list of predefined sequence types. + + :param header_size: Size of the sequence header. The parameter value may not be less than ``sizeof(CvSeq)`` . If a certain type or extension is specified, it must fit within the base type header. + + :param elem_size: Size of the sequence elements in bytes; must be consistent with the sequence type. For example, if a sequence of points is created (element type ``CV_SEQ_ELTYPE_POINT`` ), then the parameter ``elem_size`` must be equal to ``sizeof(CvPoint)`` . + + :param storage: Sequence location + + :param writer: Writer state; initialized by the function + +The function is a combination of +:ocv:cfunc:`CreateSeq` +and +:ocv:cfunc:`StartAppendToSeq` +. The pointer to the +created sequence is stored at +``writer->seq`` +and is also returned by the +:ocv:cfunc:`EndWriteSeq` +function that should be called at the end. + +TreeToNodeSeq +------------- +Gathers all node pointers to a single sequence. + +.. ocv:cfunction:: CvSeq* cvTreeToNodeSeq( const void* first, int header_size, CvMemStorage* storage ) + + :param first: The initial tree node + + :param header_size: Header size of the created sequence (sizeof(CvSeq) is the most frequently used value) + + :param storage: Container for the sequence + +The function puts pointers of all nodes reachable from ``first`` into a single sequence. The pointers are written sequentially in the depth-first order. + diff --git a/core/doc/intro.rst b/core/doc/intro.rst new file mode 100644 index 0000000..106d698 --- /dev/null +++ b/core/doc/intro.rst @@ -0,0 +1,229 @@ +************ +Introduction +************ + +.. highlight:: cpp + +OpenCV (Open Source Computer Vision Library: http://opencv.willowgarage.com/wiki/) is an open-source BSD-licensed library that includes several hundreds of computer vision algorithms. The document describes the so-called OpenCV 2.x API, which is essentially a C++ API, as opposite to the C-based OpenCV 1.x API. The latter is described in opencv1x.pdf. + +OpenCV has a modular structure, which means that the package includes several shared or static libraries. The following modules are available: + + * **core** - a compact module defining basic data structures, including the dense multi-dimensional array ``Mat`` and basic functions used by all other modules. + * **imgproc** - an image processing module that includes linear and non-linear image filtering, geometrical image transformations (resize, affine and perspective warping, generic table-based remapping), color space conversion, histograms, and so on. + * **video** - a video analysis module that includes motion estimation, background subtraction, and object tracking algorithms. + * **calib3d** - basic multiple-view geometry algorithms, single and stereo camera calibration, object pose estimation, stereo correspondence algorithms, and elements of 3D reconstruction. + * **features2d** - salient feature detectors, descriptors, and descriptor matchers. + * **objdetect** - detection of objects and instances of the predefined classes (for example, faces, eyes, mugs, people, cars, and so on). + * **highgui** - an easy-to-use interface to video capturing, image and video codecs, as well as simple UI capabilities. + * **gpu** - GPU-accelerated algorithms from different OpenCV modules. + * ... some other helper modules, such as FLANN and Google test wrappers, Python bindings, and others. + +The further chapters of the document describe functionality of each module. But first, make sure to get familiar with the common API concepts used thoroughly in the library. + +API Concepts +================ + +``cv`` Namespace +------------------ + +All the OpenCV classes and functions are placed into the ``cv`` namespace. Therefore, to access this functionality from your code, use the ``cv::`` specifier or ``using namespace cv;`` directive: + +.. code-block:: c + + #include "opencv2/core/core.hpp" + ... + cv::Mat H = cv::findHomography(points1, points2, CV_RANSAC, 5); + ... + +or :: + + #include "opencv2/core/core.hpp" + using namespace cv; + ... + Mat H = findHomography(points1, points2, CV_RANSAC, 5 ); + ... + +Some of the current or future OpenCV external names may conflict with STL +or other libraries. In this case, use explicit namespace specifiers to resolve the name conflicts: :: + + Mat a(100, 100, CV_32F); + randu(a, Scalar::all(1), Scalar::all(std::rand())); + cv::log(a, a); + a /= std::log(2.); + +Automatic Memory Management +--------------------------- + +OpenCV handles all the memory automatically. + +First of all, ``std::vector``, ``Mat``, and other data structures used by the functions and methods have destructors that deallocate the underlying memory buffers when needed. This means that the destructors do not always deallocate the buffers as in case of ``Mat``. They take into account possible data sharing. A destructor decrements the reference counter associated with the matrix data buffer. The buffer is deallocated if and only if the reference counter reaches zero, that is, when no other structures refer to the same buffer. Similarly, when a ``Mat`` instance is copied, no actual data is really copied. Instead, the reference counter is incremented to memorize that there is another owner of the same data. There is also the ``Mat::clone`` method that creates a full copy of the matrix data. See the example below: :: + + // create a big 8Mb matrix + Mat A(1000, 1000, CV_64F); + + // create another header for the same matrix; + // this is an instant operation, regardless of the matrix size. + Mat B = A; + // create another header for the 3-rd row of A; no data is copied either + Mat C = B.row(3); + // now create a separate copy of the matrix + Mat D = B.clone(); + // copy the 5-th row of B to C, that is, copy the 5-th row of A + // to the 3-rd row of A. + B.row(5).copyTo(C); + // now let A and D share the data; after that the modified version + // of A is still referenced by B and C. + A = D; + // now make B an empty matrix (which references no memory buffers), + // but the modified version of A will still be referenced by C, + // despite that C is just a single row of the original A + B.release(); + + // finally, make a full copy of C. As a result, the big modified + // matrix will be deallocated, since it is not referenced by anyone + C = C.clone(); + +You see that the use of ``Mat`` and other basic structures is simple. But what about high-level classes or even user data types created without taking automatic memory management into account? For them, OpenCV offers the ``Ptr<>`` template class that is similar to ``std::shared_ptr`` from C++ TR1. So, instead of using plain pointers:: + + T* ptr = new T(...); + +you can use:: + + Ptr ptr = new T(...); + +That is, ``Ptr ptr`` encapsulates a pointer to a ``T`` instance and a reference counter associated with the pointer. See the +:ocv:class:`Ptr` +description for details. + +.. _AutomaticAllocation: + +Automatic Allocation of the Output Data +--------------------------------------- + +OpenCV deallocates the memory automatically, as well as automatically allocates the memory for output function parameters most of the time. So, if a function has one or more input arrays (``cv::Mat`` instances) and some output arrays, the output arrays are automatically allocated or reallocated. The size and type of the output arrays are determined from the size and type of input arrays. If needed, the functions take extra parameters that help to figure out the output array properties. + +Example: :: + + #include "cv.h" + #include "highgui.h" + + using namespace cv; + + int main(int, char**) + { + VideoCapture cap(0); + if(!cap.isOpened()) return -1; + + Mat frame, edges; + namedWindow("edges",1); + for(;;) + { + cap >> frame; + cvtColor(frame, edges, CV_BGR2GRAY); + GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5); + Canny(edges, edges, 0, 30, 3); + imshow("edges", edges); + if(waitKey(30) >= 0) break; + } + return 0; + } + +The array ``frame`` is automatically allocated by the ``>>`` operator since the video frame resolution and the bit-depth is known to the video capturing module. The array ``edges`` is automatically allocated by the ``cvtColor`` function. It has the same size and the bit-depth as the input array. The number of channels is 1 because the color conversion code ``CV_BGR2GRAY`` is passed, which means a color to grayscale conversion. Note that ``frame`` and ``edges`` are allocated only once during the first execution of the loop body since all the next video frames have the same resolution. If you somehow change the video resolution, the arrays are automatically reallocated. + +The key component of this technology is the ``Mat::create`` method. It takes the desired array size and type. If the array already has the specified size and type, the method does nothing. Otherwise, it releases the previously allocated data, if any (this part involves decrementing the reference counter and comparing it with zero), and then allocates a new buffer of the required size. Most functions call the ``Mat::create`` method for each output array, and so the automatic output data allocation is implemented. + +Some notable exceptions from this scheme are ``cv::mixChannels``, ``cv::RNG::fill``, and a few other functions and methods. They are not able to allocate the output array, so you have to do this in advance. + +Saturation Arithmetics +---------------------- + +As a computer vision library, OpenCV deals a lot with image pixels that are often encoded in a compact, 8- or 16-bit per channel, form and thus have a limited value range. Furthermore, certain operations on images, like color space conversions, brightness/contrast adjustments, sharpening, complex interpolation (bi-cubic, Lanczos) can produce values out of the available range. If you just store the lowest 8 (16) bits of the result, this results in visual artifacts and may affect a further image analysis. To solve this problem, the so-called *saturation* arithmetics is used. For example, to store ``r``, the result of an operation, to an 8-bit image, you find the nearest value within the 0..255 range: + +.. math:: + + I(x,y)= \min ( \max (\textrm{round}(r), 0), 255) + +Similar rules are applied to 8-bit signed, 16-bit signed and unsigned types. This semantics is used everywhere in the library. In C++ code, it is done using the ``saturate_cast<>`` functions that resemble standard C++ cast operations. See below the implementation of the formula provided above:: + + I.at(y, x) = saturate_cast(r); + +where ``cv::uchar`` is an OpenCV 8-bit unsigned integer type. In the optimized SIMD code, such SSE2 instructions as ``paddusb``, ``packuswb``, and so on are used. They help achieve exactly the same behavior as in C++ code. + +.. note:: Saturation is not applied when the result is 32-bit integer. + +Fixed Pixel Types. Limited Use of Templates +------------------------------------------- + +Templates is a great feature of C++ that enables implementation of very powerful, efficient and yet safe data structures and algorithms. However, the extensive use of templates may dramatically increase compilation time and code size. Besides, it is difficult to separate an interface and implementation when templates are used exclusively. This could be fine for basic algorithms but not good for computer vision libraries where a single algorithm may span thousands lines of code. Because of this and also to simplify development of bindings for other languages, like Python, Java, Matlab that do not have templates at all or have limited template capabilities, the current OpenCV implementation is based on polymorphism and runtime dispatching over templates. In those places where runtime dispatching would be too slow (like pixel access operators), impossible (generic ``Ptr<>`` implementation), or just very inconvenient (``saturate_cast<>()``) the current implementation introduces small template classes, methods, and functions. Anywhere else in the current OpenCV version the use of templates is limited. + +Consequently, there is a limited fixed set of primitive data types the library can operate on. That is, array elements should have one of the following types: + + * 8-bit unsigned integer (uchar) + * 8-bit signed integer (schar) + * 16-bit unsigned integer (ushort) + * 16-bit signed integer (short) + * 32-bit signed integer (int) + * 32-bit floating-point number (float) + * 64-bit floating-point number (double) + * a tuple of several elements where all elements have the same type (one of the above). An array whose elements are such tuples, are called multi-channel arrays, as opposite to the single-channel arrays, whose elements are scalar values. The maximum possible number of channels is defined by the ``CV_CN_MAX`` constant, which is currently set to 512. + +For these basic types, the following enumeration is applied:: + + enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 }; + +Multi-channel (``n``-channel) types can be specified using the following options: + +* ``CV_8UC1`` ... ``CV_64FC4`` constants (for a number of channels from 1 to 4) +* ``CV_8UC(n)`` ... ``CV_64FC(n)`` or ``CV_MAKETYPE(CV_8U, n)`` ... ``CV_MAKETYPE(CV_64F, n)`` macros when the number of channels is more than 4 or unknown at the compilation time. + +.. note:: ``CV_32FC1 == CV_32F``, ``CV_32FC2 == CV_32FC(2) == CV_MAKETYPE(CV_32F, 2)``, and ``CV_MAKETYPE(depth, n) == ((x&7)<<3) + (n-1)``. This means that the constant type is formed from the ``depth``, taking the lowest 3 bits, and the number of channels minus 1, taking the next ``log2(CV_CN_MAX)`` bits. + +Examples: :: + + Mat mtx(3, 3, CV_32F); // make a 3x3 floating-point matrix + Mat cmtx(10, 1, CV_64FC2); // make a 10x1 2-channel floating-point + // matrix (10-element complex vector) + Mat img(Size(1920, 1080), CV_8UC3); // make a 3-channel (color) image + // of 1920 columns and 1080 rows. + Mat grayscale(image.size(), CV_MAKETYPE(image.depth(), 1)); // make a 1-channel image of + // the same size and same + // channel type as img + +Arrays with more complex elements cannot be constructed or processed using OpenCV. Furthermore, each function or method can handle only a subset of all possible array types. Usually, the more complex the algorithm is, the smaller the supported subset of formats is. See below typical examples of such limitations: + + * The face detection algorithm only works with 8-bit grayscale or color images. + * Linear algebra functions and most of the machine learning algorithms work with floating-point arrays only. + * Basic functions, such as ``cv::add``, support all types. + * Color space conversion functions support 8-bit unsigned, 16-bit unsigned, and 32-bit floating-point types. + +The subset of supported types for each function has been defined from practical needs and could be extended in future based on user requests. + + +InputArray and OutputArray +-------------------------- + +Many OpenCV functions process dense 2-dimensional or multi-dimensional numerical arrays. Usually, such functions take cpp:class:`Mat` as parameters, but in some cases it's more convenient to use ``std::vector<>`` (for a point set, for example) or ``Matx<>`` (for 3x3 homography matrix and such). To avoid many duplicates in the API, special "proxy" classes have been introduced. The base "proxy" class is ``InputArray``. It is used for passing read-only arrays on a function input. The derived from ``InputArray`` class ``OutputArray`` is used to specify an output array for a function. Normally, you should not care of those intermediate types (and you should not declare variables of those types explicitly) - it will all just work automatically. You can assume that instead of ``InputArray``/``OutputArray`` you can always use ``Mat``, ``std::vector<>``, ``Matx<>``, ``Vec<>`` or ``Scalar``. When a function has an optional input or output array, and you do not have or do not want one, pass ``cv::noArray()``. + +Error Handling +-------------- + +OpenCV uses exceptions to signal critical errors. When the input data has a correct format and belongs to the specified value range, but the algorithm cannot succeed for some reason (for example, the optimization algorithm did not converge), it returns a special error code (typically, just a boolean variable). + +The exceptions can be instances of the ``cv::Exception`` class or its derivatives. In its turn, ``cv::Exception`` is a derivative of ``std::exception``. So it can be gracefully handled in the code using other standard C++ library components. + +The exception is typically thrown either using the ``CV_Error(errcode, description)`` macro, or its printf-like ``CV_Error_(errcode, printf-spec, (printf-args))`` variant, or using the ``CV_Assert(condition)`` macro that checks the condition and throws an exception when it is not satisfied. For performance-critical code, there is ``CV_DbgAssert(condition)`` that is only retained in the Debug configuration. Due to the automatic memory management, all the intermediate buffers are automatically deallocated in case of a sudden error. You only need to add a try statement to catch exceptions, if needed: :: + + try + { + ... // call OpenCV + } + catch( cv::Exception& e ) + { + const char* err_msg = e.what(); + std::cout << "exception caught: " << err_msg << std::endl; + } + +Multi-threading and Re-enterability +----------------------------------- + +The current OpenCV implementation is fully re-enterable. That is, the same function, the same *constant* method of a class instance, or the same *non-constant* method of different class instances can be called from different threads. Also, the same ``cv::Mat`` can be used in different threads because the reference-counting operations use the architecture-specific atomic instructions. diff --git a/core/doc/old_basic_structures.rst b/core/doc/old_basic_structures.rst new file mode 100644 index 0000000..17bf4ce --- /dev/null +++ b/core/doc/old_basic_structures.rst @@ -0,0 +1,1779 @@ +Basic C Structures and Operations +================================= + +.. highlight:: c + +The section describes the main data structures, used by the OpenCV 1.x API, and the basic functions to create and process the data structures. + +CvPoint +------- + +.. ocv:struct:: CvPoint + + 2D point with integer coordinates (usually zero-based). + + .. ocv:member:: int x + + x-coordinate + + .. ocv:member:: int y + + y-coordinate + +.. ocv:cfunction:: CvPoint cvPoint( int x, int y ) + + constructs ``CvPoint`` structure. + +.. ocv:cfunction:: CvPoint cvPointFrom32f( CvPoint2D32f point ) + + converts ``CvPoint2D32f`` to ``CvPoint``. + +.. seealso:: :ocv:class:`Point\_` + +CvPoint2D32f +------------ + +.. ocv:struct:: CvPoint2D32f + + 2D point with floating-point coordinates. + + .. ocv:member:: float x + + x-coordinate + + .. ocv:member:: float y + + y-coordinate + +.. ocv:cfunction:: CvPoint2D32f cvPoint2D32f( double x, double y ) + + constructs ``CvPoint2D32f`` structure. + +.. ocv:cfunction:: CvPoint2D32f cvPointTo32f( CvPoint point ) + + converts ``CvPoint`` to ``CvPoint2D32f``. + +.. seealso:: :ocv:class:`Point\_` + +CvPoint3D32f +------------ + +.. ocv:struct:: CvPoint3D32f + + 3D point with floating-point coordinates + + .. ocv:member:: float x + + x-coordinate + + .. ocv:member:: float y + + y-coordinate + + .. ocv:member:: float z + + z-coordinate + +.. ocv:cfunction:: CvPoint3D32f cvPoint3D32f( double x, double y, double z ) + + constructs ``CvPoint3D32f`` structure. + +.. seealso:: :ocv:class:`Point3\_` + +CvPoint2D64f +------------ + +.. ocv:struct:: CvPoint2D64f + + 2D point with double-precision floating-point coordinates. + + .. ocv:member:: double x + + x-coordinate + + .. ocv:member:: double y + + y-coordinate + +.. ocv:cfunction:: CvPoint2D64f cvPoint2D64f( double x, double y ) + + constructs ``CvPoint2D64f`` structure. + +.. seealso:: :ocv:class:`Point\_` + +CvPoint3D64f +------------ + +.. ocv:struct:: CvPoint3D64f + + 3D point with double-precision floating-point coordinates. + + .. ocv:member:: double x + + x-coordinate + + .. ocv:member:: double y + + y-coordinate + + .. ocv:member:: double z + +.. ocv:cfunction:: CvPoint3D64f cvPoint3D64f( double x, double y, double z ) + + constructs ``CvPoint3D64f`` structure. + +.. seealso:: :ocv:class:`Point3\_` + +CvSize +------ + +.. ocv:struct:: CvSize + + Size of a rectangle or an image. + + .. ocv:member:: int width + + Width of the rectangle + + .. ocv:member:: int height + + Height of the rectangle + +.. ocv:cfunction:: CvSize cvSize( int width, int height ) + + constructs ``CvSize`` structure. + +.. seealso:: :ocv:class:`Size\_` + +CvSize2D32f +----------- + +.. ocv:struct:: CvSize2D32f + + Sub-pixel accurate size of a rectangle. + + .. ocv:member:: float width + + Width of the rectangle + + .. ocv:member:: float height + + Height of the rectangle + +.. ocv:cfunction:: CvSize2D32f cvSize2D32f( double width, double height ) + + constructs ``CvSize2D32f`` structure. + +.. seealso:: :ocv:class:`Size\_` + +CvRect +------ + +.. ocv:struct:: CvRect + + Stores coordinates of a rectangle. + + .. ocv:member:: int x + + x-coordinate of the top-left corner + + .. ocv:member:: int y + + y-coordinate of the top-left corner (sometimes bottom-left corner) + + .. ocv:member:: int width + + Width of the rectangle + + .. ocv:member:: int height + + Height of the rectangle + +.. ocv:cfunction:: CvRect cvRect( int x, int y, int width, int height ) + + constructs ``CvRect`` structure. + +.. seealso:: :ocv:class:`Rect\_` + + +CvBox2D +------- + +.. ocv:struct:: CvBox2D + + Stores coordinates of a rotated rectangle. + + .. ocv:member:: CvPoint2D32f center + + Center of the box + + .. ocv:member:: CvSize2D32f size + + Box width and height + + .. ocv:member:: float angle + + Angle between the horizontal axis and the first side (i.e. length) in degrees + +.. seealso:: :ocv:class:`RotatedRect` + + +CvScalar +-------- + +.. ocv:struct:: CvScalar + + A container for 1-,2-,3- or 4-tuples of doubles. + + .. ocv:member:: double[4] val + +.. ocv::cfunction:: CvScalar cvScalar( double val0, double val1=0, double val2=0, double val3=0 ) + + initializes val[0] with val0, val[1] with val1, val[2] with val2 and val[3] with val3. + +.. ocv::cfunction:: CvScalar cvScalarAll( double val0123 ) + + initializes all of val[0]...val[3] with val0123 + +.. ocv::cfunction:: CvScalar cvRealScalar( double val0 ) + + initializes val[0] with val0, val[1], val[2] and val[3] with 0. + +.. seealso:: :ocv:class:`Scalar\_` + +CvTermCriteria +-------------- + +.. ocv:struct:: CvTermCriteria + + Termination criteria for iterative algorithms. + + .. ocv:member:: int type + + type of the termination criteria, one of: + + * ``CV_TERMCRIT_ITER`` - stop the algorithm after ``max_iter`` iterations at maximum. + + * ``CV_TERMCRIT_EPS`` - stop the algorithm after the achieved algorithm-dependent accuracy becomes lower than ``epsilon``. + + * ``CV_TERMCRIT_ITER+CV_TERMCRIT_EPS`` - stop the algorithm after ``max_iter`` iterations or when the achieved accuracy is lower than ``epsilon``, whichever comes the earliest. + + .. ocv:member:: int max_iter + + Maximum number of iterations + + .. ocv:member:: double epsilon + + Required accuracy + +.. seealso:: :ocv:class:`TermCriteria` + +CvMat +----- + +.. ocv:struct:: CvMat + + A multi-channel dense matrix. + + .. ocv:member:: int type + + ``CvMat`` signature (``CV_MAT_MAGIC_VAL``) plus type of the elements. Type of the matrix elements can be retrieved using ``CV_MAT_TYPE`` macro: :: + + int type = CV_MAT_TYPE(matrix->type); + + For description of possible matrix elements, see :ocv:class:`Mat`. + + .. ocv:member:: int step + + Full row length in bytes + + .. ocv:member:: int* refcount + + Underlying data reference counter + + .. ocv:member:: union data + + Pointers to the actual matrix data: + + * ptr - pointer to 8-bit unsigned elements + * s - pointer to 16-bit signed elements + * i - pointer to 32-bit signed elements + * fl - pointer to 32-bit floating-point elements + * db - pointer to 64-bit floating-point elements + + .. ocv:member:: int rows + + Number of rows + + .. ocv:member:: int cols + + Number of columns + +Matrix elements are stored row by row. Element (i, j) (i - 0-based row index, j - 0-based column index) of a matrix can be retrieved or modified using ``CV_MAT_ELEM`` macro: :: + + uchar pixval = CV_MAT_ELEM(grayimg, uchar, i, j) + CV_MAT_ELEM(cameraMatrix, float, 0, 2) = image.width*0.5f; + +To access multiple-channel matrices, you can use ``CV_MAT_ELEM(matrix, type, i, j*nchannels + channel_idx)``. + +``CvMat`` is now obsolete; consider using :ocv:class:`Mat` instead. + +CvMatND +------- + +.. ocv:struct:: CvMatND + + Multi-dimensional dense multi-channel array. + + .. ocv:member:: int type + + A ``CvMatND`` signature (``CV_MATND_MAGIC_VAL``) plus the type of elements. Type of the matrix elements can be retrieved using ``CV_MAT_TYPE`` macro: :: + + int type = CV_MAT_TYPE(ndmatrix->type); + + .. ocv:member:: int dims + + The number of array dimensions + + .. ocv:member:: int* refcount + + Underlying data reference counter + + .. ocv:member:: union data + + Pointers to the actual matrix data + + * ptr - pointer to 8-bit unsigned elements + * s - pointer to 16-bit signed elements + * i - pointer to 32-bit signed elements + * fl - pointer to 32-bit floating-point elements + * db - pointer to 64-bit floating-point elements + + .. ocv:member:: array dim + + Arrays of pairs (array size along the i-th dimension, distance between neighbor elements along i-th dimension): :: + + for(int i = 0; i < ndmatrix->dims; i++) + printf("size[i] = %d, step[i] = %d\n", ndmatrix->dim[i].size, ndmatrix->dim[i].step); + +``CvMatND`` is now obsolete; consider using :ocv:class:`Mat` instead. + +CvSparseMat +----------- + +.. ocv:struct:: CvSparseMat + + Multi-dimensional sparse multi-channel array. + + .. ocv:member:: int type + + A ``CvSparseMat`` signature (CV_SPARSE_MAT_MAGIC_VAL) plus the type of sparse matrix elements. Similarly to ``CvMat`` and ``CvMatND``, use ``CV_MAT_TYPE()`` to retrieve type of the elements. + + .. ocv:member:: int dims + + Number of dimensions + + .. ocv:member:: int* refcount + + Underlying reference counter. Not used. + + .. ocv:member:: CvSet* heap + + A pool of hash table nodes + + .. ocv:member:: void** hashtable + + The hash table. Each entry is a list of nodes. + + .. ocv:member:: int hashsize + + Size of the hash table + + .. ocv:member:: int[] size + + Array of dimension sizes + +IplImage +-------- + +.. ocv:struct:: IplImage + + IPL image header + + .. ocv:member:: int nSize + + ``sizeof(IplImage)`` + + .. ocv:member:: int ID + + Version, always equals 0 + + .. ocv:member:: int nChannels + + Number of channels. Most OpenCV functions support 1-4 channels. + + .. ocv:member:: int alphaChannel + + Ignored by OpenCV + + .. ocv:member:: int depth + + Channel depth in bits + the optional sign bit ( ``IPL_DEPTH_SIGN`` ). The supported depths are: + + * ``IPL_DEPTH_8U`` - unsigned 8-bit integer. Equivalent to ``CV_8U`` in matrix types. + * ``IPL_DEPTH_8S`` - signed 8-bit integer. Equivalent to ``CV_8S`` in matrix types. + * ``IPL_DEPTH_16U`` - unsigned 16-bit integer. Equivalent to ``CV_16U`` in matrix types. + * ``IPL_DEPTH_16S`` - signed 8-bit integer. Equivalent to ``CV_16S`` in matrix types. + * ``IPL_DEPTH_32S`` - signed 32-bit integer. Equivalent to ``CV_32S`` in matrix types. + * ``IPL_DEPTH_32F`` - single-precision floating-point number. Equivalent to ``CV_32F`` in matrix types. + * ``IPL_DEPTH_64F`` - double-precision floating-point number. Equivalent to ``CV_64F`` in matrix types. + + .. ocv:member:: char[] colorModel + + Ignored by OpenCV. + + .. ocv:member:: char[] channelSeq + + Ignored by OpenCV + + .. ocv:member:: int dataOrder + + 0 = ``IPL_DATA_ORDER_PIXEL`` - interleaved color channels, 1 - separate color channels. :ocv:cfunc:`CreateImage` only creates images with interleaved channels. For example, the usual layout of a color image is: :math:`b_{00} g_{00} r_{00} b_{10} g_{10} r_{10} ...` + + .. ocv:member:: int origin + + 0 - top-left origin, 1 - bottom-left origin (Windows bitmap style) + + .. ocv:member:: int align + + Alignment of image rows (4 or 8). OpenCV ignores this and uses widthStep instead. + + .. ocv:member:: int width + + Image width in pixels + + .. ocv:member:: int height + + Image height in pixels + + .. ocv:member:: IplROI* roi + + Region Of Interest (ROI). If not NULL, only this image region will be processed. + + .. ocv:member:: IplImage* maskROI + + Must be NULL in OpenCV + + .. ocv:member:: void* imageId + + Must be NULL in OpenCV + + .. ocv:member:: void* tileInfo + + Must be NULL in OpenCV + + .. ocv:member:: int imageSize + + Image data size in bytes. For interleaved data, this equals :math:`\texttt{image->height} \cdot \texttt{image->widthStep}` + + .. ocv:member:: char* imageData + + A pointer to the aligned image data. Do not assign imageData directly. Use :ocv:cfunc:`SetData`. + + .. ocv:member:: int widthStep + + The size of an aligned image row, in bytes. + + .. ocv:member:: int[] BorderMode + + Border completion mode, ignored by OpenCV + + .. ocv:member:: int[] BorderConst + + Constant border value, ignored by OpenCV + + .. ocv:member:: char* imageDataOrigin + + A pointer to the origin of the image data (not necessarily aligned). This is used for image deallocation. + +The ``IplImage`` is taken from the Intel Image Processing Library, in which the format is native. OpenCV only supports a subset of possible ``IplImage`` formats, as outlined in the parameter list above. + +In addition to the above restrictions, OpenCV handles ROIs differently. OpenCV functions require that the image size or ROI size of all source and destination images match exactly. On the other hand, the Intel Image Processing Library processes the area of intersection between the source and destination images (or ROIs), allowing them to vary independently. + +CvArr +----- + +.. ocv:struct:: CvArr + +This is the "metatype" used *only* as a function parameter. It denotes that the function accepts arrays of multiple types, such as IplImage*, CvMat* or even CvSeq* sometimes. The particular array type is determined at runtime by analyzing the first 4 bytes of the header. In C++ interface the role of ``CvArr`` is played by ``InputArray`` and ``OutputArray``. + +ClearND +------- +Clears a specific array element. + +.. ocv:cfunction:: void cvClearND( CvArr* arr, const int* idx ) + +.. ocv:pyoldfunction:: cv.ClearND(arr, idx)-> None + + :param arr: Input array + :param idx: Array of the element indices + +The function clears (sets to zero) a specific element of a dense array or deletes the element of a sparse array. If the sparse array element does not exists, the function does nothing. + +CloneImage +---------- +Makes a full copy of an image, including the header, data, and ROI. + +.. ocv:cfunction:: IplImage* cvCloneImage(const IplImage* image) +.. ocv:pyoldfunction:: cv.CloneImage(image) -> image + + :param image: The original image + +CloneMat +-------- +Creates a full matrix copy. + +.. ocv:cfunction:: CvMat* cvCloneMat(const CvMat* mat) +.. ocv:pyoldfunction:: cv.CloneMat(mat) -> mat + + :param mat: Matrix to be copied + +Creates a full copy of a matrix and returns a pointer to the copy. Note that the matrix copy is compacted, that is, it will not have gaps between rows. + +CloneMatND +---------- +Creates full copy of a multi-dimensional array and returns a pointer to the copy. + +.. ocv:cfunction:: CvMatND* cvCloneMatND(const CvMatND* mat) +.. ocv:pyoldfunction:: cv.CloneMatND(mat) -> matND + + :param mat: Input array + +CloneSparseMat +-------------- +Creates full copy of sparse array. + +.. ocv:cfunction:: CvSparseMat* cvCloneSparseMat(const CvSparseMat* mat) + + :param mat: Input array + +The function creates a copy of the input array and returns pointer to the copy. + + +ConvertScale +------------ +Converts one array to another with optional linear transformation. + +.. ocv:cfunction:: void cvConvertScale(const CvArr* src, CvArr* dst, double scale=1, double shift=0) +.. ocv:pyoldfunction:: cv.ConvertScale(src, dst, scale=1.0, shift=0.0)-> None +.. ocv:pyoldfunction:: cv.Convert(src, dst)-> None + + :: + + #define cvCvtScale cvConvertScale + #define cvScale cvConvertScale + #define cvConvert(src, dst ) cvConvertScale((src), (dst), 1, 0 ) + + .. + + :param src: Source array + + :param dst: Destination array + + :param scale: Scale factor + + :param shift: Value added to the scaled source array elements + +The function has several different purposes, and thus has several different names. It copies one array to another with optional scaling, which is performed first, and/or optional type conversion, performed after: + +.. math:: + + \texttt{dst} (I) = \texttt{scale} \texttt{src} (I) + ( \texttt{shift} _0, \texttt{shift} _1,...) + + +All the channels of multi-channel arrays are processed independently. + +The type of conversion is done with rounding and saturation, that is if the +result of scaling + conversion can not be represented exactly by a value +of the destination array element type, it is set to the nearest representable +value on the real axis. + + +Copy +---- +Copies one array to another. + +.. ocv:cfunction:: void cvCopy(const CvArr* src, CvArr* dst, const CvArr* mask=NULL) +.. ocv:pyoldfunction:: cv.Copy(src, dst, mask=None)-> None + + :param src: The source array + + :param dst: The destination array + + :param mask: Operation mask, 8-bit single channel array; specifies elements of the destination array to be changed + +The function copies selected elements from an input array to an output array: + +.. math:: + + \texttt{dst} (I)= \texttt{src} (I) \quad \text{if} \quad \texttt{mask} (I) \ne 0. + +If any of the passed arrays is of ``IplImage`` type, then its ROI and COI fields are used. Both arrays must have the same type, the same number of dimensions, and the same size. The function can also copy sparse arrays (mask is not supported in this case). + + +CreateData +---------- +Allocates array data + +.. ocv:cfunction:: void cvCreateData(CvArr* arr) +.. ocv:pyoldfunction:: cv.CreateData(arr) -> None + + :param arr: Array header + +The function allocates image, matrix or multi-dimensional dense array data. Note that in the case of matrix types OpenCV allocation functions are used. In the case of IplImage they are used +unless ``CV_TURN_ON_IPL_COMPATIBILITY()`` has been called before. In the latter case IPL functions are used to allocate the data. + +CreateImage +----------- +Creates an image header and allocates the image data. + +.. ocv:cfunction:: IplImage* cvCreateImage(CvSize size, int depth, int channels) +.. ocv:pyoldfunction:: cv.CreateImage(size, depth, channels)->image + + :param size: Image width and height + + :param depth: Bit depth of image elements. See :ocv:struct:`IplImage` for valid depths. + + :param channels: Number of channels per pixel. See :ocv:struct:`IplImage` for details. This function only creates images with interleaved channels. + +This function call is equivalent to the following code: :: + + header = cvCreateImageHeader(size, depth, channels); + cvCreateData(header); + +CreateImageHeader +----------------- +Creates an image header but does not allocate the image data. + +.. ocv:cfunction:: IplImage* cvCreateImageHeader(CvSize size, int depth, int channels) +.. ocv:pyoldfunction:: cv.CreateImageHeader(size, depth, channels) -> image + + :param size: Image width and height + + :param depth: Image depth (see :ocv:cfunc:`CreateImage` ) + + :param channels: Number of channels (see :ocv:cfunc:`CreateImage` ) + +CreateMat +--------- +Creates a matrix header and allocates the matrix data. + +.. ocv:cfunction:: CvMat* cvCreateMat( int rows, int cols, int type) +.. ocv:pyoldfunction:: cv.CreateMat(rows, cols, type) -> mat + + :param rows: Number of rows in the matrix + + :param cols: Number of columns in the matrix + + :param type: The type of the matrix elements in the form ``CV_C`` , where S=signed, U=unsigned, F=float. For example, CV _ 8UC1 means the elements are 8-bit unsigned and the there is 1 channel, and CV _ 32SC2 means the elements are 32-bit signed and there are 2 channels. + +The function call is equivalent to the following code: :: + + CvMat* mat = cvCreateMatHeader(rows, cols, type); + cvCreateData(mat); + +CreateMatHeader +--------------- +Creates a matrix header but does not allocate the matrix data. + +.. ocv:cfunction:: CvMat* cvCreateMatHeader( int rows, int cols, int type) +.. ocv:pyoldfunction:: cv.CreateMatHeader(rows, cols, type) -> mat + + :param rows: Number of rows in the matrix + + :param cols: Number of columns in the matrix + + :param type: Type of the matrix elements, see :ocv:cfunc:`CreateMat` + +The function allocates a new matrix header and returns a pointer to it. The matrix data can then be allocated using :ocv:cfunc:`CreateData` or set explicitly to user-allocated data via :ocv:cfunc:`SetData`. + +CreateMatND +----------- +Creates the header and allocates the data for a multi-dimensional dense array. + +.. ocv:cfunction:: CvMatND* cvCreateMatND( int dims, const int* sizes, int type) +.. ocv:pyoldfunction:: cv.CreateMatND(dims, type) -> matND + + :param dims: Number of array dimensions. This must not exceed CV_MAX_DIM (32 by default, but can be changed at build time). + + :param sizes: Array of dimension sizes. + + :param type: Type of array elements, see :ocv:cfunc:`CreateMat` . + +This function call is equivalent to the following code: :: + + CvMatND* mat = cvCreateMatNDHeader(dims, sizes, type); + cvCreateData(mat); + +CreateMatNDHeader +----------------- +Creates a new matrix header but does not allocate the matrix data. + +.. ocv:cfunction:: CvMatND* cvCreateMatNDHeader( int dims, const int* sizes, int type) +.. ocv:pyoldfunction:: cv.CreateMatNDHeader(dims, type) -> matND + + :param dims: Number of array dimensions + + :param sizes: Array of dimension sizes + + :param type: Type of array elements, see :ocv:cfunc:`CreateMat` + +The function allocates a header for a multi-dimensional dense array. The array data can further be allocated using :ocv:cfunc:`CreateData` or set explicitly to user-allocated data via :ocv:cfunc:`SetData`. + +CreateSparseMat +--------------- +Creates sparse array. + +.. ocv:cfunction:: CvSparseMat* cvCreateSparseMat(int dims, const int* sizes, int type) + + :param dims: Number of array dimensions. In contrast to the dense matrix, the number of dimensions is practically unlimited (up to :math:`2^{16}` ). + + :param sizes: Array of dimension sizes + + :param type: Type of array elements. The same as for CvMat + +The function allocates a multi-dimensional sparse array. Initially the array contain no elements, that is +:ocv:cfunc:`PtrND` and other related functions will return 0 for every index. + + +CrossProduct +------------ +Calculates the cross product of two 3D vectors. + +.. ocv:cfunction:: void cvCrossProduct(const CvArr* src1, const CvArr* src2, CvArr* dst) +.. ocv:pyoldfunction:: cv.CrossProduct(src1, src2, dst)-> None + + :param src1: The first source vector + + :param src2: The second source vector + + :param dst: The destination vector + +The function calculates the cross product of two 3D vectors: + +.. math:: + + \texttt{dst} = \texttt{src1} \times \texttt{src2} + +or: + +.. math:: + + \begin{array}{l} \texttt{dst} _1 = \texttt{src1} _2 \texttt{src2} _3 - \texttt{src1} _3 \texttt{src2} _2 \\ \texttt{dst} _2 = \texttt{src1} _3 \texttt{src2} _1 - \texttt{src1} _1 \texttt{src2} _3 \\ \texttt{dst} _3 = \texttt{src1} _1 \texttt{src2} _2 - \texttt{src1} _2 \texttt{src2} _1 \end{array} + + +DotProduct +---------- +Calculates the dot product of two arrays in Euclidean metrics. + +.. ocv:cfunction:: double cvDotProduct(const CvArr* src1, const CvArr* src2) +.. ocv:pyoldfunction:: cv.DotProduct(src1, src2) -> float + + :param src1: The first source array + + :param src2: The second source array + +The function calculates and returns the Euclidean dot product of two arrays. + +.. math:: + + src1 \bullet src2 = \sum _I ( \texttt{src1} (I) \texttt{src2} (I)) + +In the case of multiple channel arrays, the results for all channels are accumulated. In particular, +``cvDotProduct(a,a)`` where ``a`` is a complex vector, will return :math:`||\texttt{a}||^2`. +The function can process multi-dimensional arrays, row by row, layer by layer, and so on. + + +Get?D +----- + +.. ocv:cfunction:: CvScalar cvGet1D(const CvArr* arr, int idx0) +.. ocv:cfunction:: CvScalar cvGet2D(const CvArr* arr, int idx0, int idx1) +.. ocv:cfunction:: CvScalar cvGet3D(const CvArr* arr, int idx0, int idx1, int idx2) +.. ocv:cfunction:: CvScalar cvGetND( const CvArr* arr, const int* idx ) + +.. ocv:pyoldfunction:: cv.Get1D(arr, idx) -> scalar +.. ocv:pyoldfunction:: cv.Get2D(arr, idx0, idx1) -> scalar +.. ocv:pyoldfunction:: cv.Get3D(arr, idx0, idx1, idx2) -> scalar +.. ocv:pyoldfunction:: cv.GetND(arr, indices) -> scalar + + Return a specific array element. + + :param arr: Input array + + :param idx0: The first zero-based component of the element index + + :param idx1: The second zero-based component of the element index + + :param idx2: The third zero-based component of the element index + + :param idx: Array of the element indices + +The functions return a specific array element. In the case of a sparse array the functions return 0 if the requested node does not exist (no new node is created by the functions). + +GetCol(s) +--------- +Returns one of more array columns. + +.. ocv:cfunction:: CvMat* cvGetCol(const CvArr* arr, CvMat* submat, int col) + +.. ocv:cfunction:: CvMat* cvGetCols( const CvArr* arr, CvMat* submat, int start_col, int end_col ) + +.. ocv:pyoldfunction:: cv.GetCol(arr, col)-> submat + +.. ocv:pyoldfunction:: cv.GetCols(arr, startCol, endCol)-> submat + + :param arr: Input array + + :param submat: Pointer to the resulting sub-array header + + :param col: Zero-based index of the selected column + + :param start_col: Zero-based index of the starting column (inclusive) of the span + + :param end_col: Zero-based index of the ending column (exclusive) of the span + +The functions return the header, corresponding to a specified column span of the input array. That is, no data is copied. Therefore, any modifications of the submatrix will affect the original array. If you need to copy the columns, use :ocv:cfunc:`CloneMat`. ``cvGetCol(arr, submat, col)`` is a shortcut for ``cvGetCols(arr, submat, col, col+1)``. + +GetDiag +------- +Returns one of array diagonals. + +.. ocv:cfunction:: CvMat* cvGetDiag(const CvArr* arr, CvMat* submat, int diag=0) +.. ocv:pyoldfunction:: cv.GetDiag(arr, diag=0)-> submat + + :param arr: Input array + + :param submat: Pointer to the resulting sub-array header + + :param diag: Index of the array diagonal. Zero value corresponds to the main diagonal, -1 corresponds to the diagonal above the main, 1 corresponds to the diagonal below the main, and so forth. + +The function returns the header, corresponding to a specified diagonal of the input array. + +GetDims +--------- +Return number of array dimensions + +.. ocv:cfunction:: int cvGetDims(const CvArr* arr, int* sizes=NULL) +.. ocv:pyoldfunction:: cv.GetDims(arr) -> (dim1, dim2, ...) + + :param arr: Input array + + :param sizes: Optional output vector of the array dimension sizes. For + 2d arrays the number of rows (height) goes first, number of columns + (width) next. + +The function returns the array dimensionality and the array of dimension sizes. In the case of ``IplImage`` or `CvMat` it always returns 2 regardless of number of image/matrix rows. For example, the following code calculates total number of array elements: :: + + int sizes[CV_MAX_DIM]; + int i, total = 1; + int dims = cvGetDims(arr, size); + for(i = 0; i < dims; i++ ) + total *= sizes[i]; + +GetDimSize +------------ +Returns array size along the specified dimension. + +.. ocv:cfunction:: int cvGetDimSize(const CvArr* arr, int index) + + :param arr: Input array + + :param index: Zero-based dimension index (for matrices 0 means number of rows, 1 means number of columns; for images 0 means height, 1 means width) + +GetElemType +----------- +Returns type of array elements. + +.. ocv:cfunction:: int cvGetElemType(const CvArr* arr) +.. ocv:pyoldfunction:: cv.GetElemType(arr)-> int + + :param arr: Input array + +The function returns type of the array elements. In the case of ``IplImage`` the type is converted to ``CvMat``-like representation. For example, if the image has been created as: :: + + IplImage* img = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 3); + +The code ``cvGetElemType(img)`` will return ``CV_8UC3``. + +GetImage +-------- +Returns image header for arbitrary array. + +.. ocv:cfunction:: IplImage* cvGetImage( const CvArr* arr, IplImage* image_header ) + +.. ocv:pyoldfunction:: cv.GetImage(arr) -> iplimage + + :param arr: Input array + + :param image_header: Pointer to ``IplImage`` structure used as a temporary buffer + +The function returns the image header for the input array that can be a matrix (:ocv:struct:`CvMat`) or image (:ocv:struct:`IplImage`). In the case of an image the function simply returns the input pointer. In the case of ``CvMat`` it initializes an ``image_header`` structure with the parameters of the input matrix. Note that if we transform ``IplImage`` to ``CvMat`` using :ocv:cfunc:`GetMat` and then transform ``CvMat`` back to IplImage using this function, we will get different headers if the ROI is set in the original image. + +GetImageCOI +----------- +Returns the index of the channel of interest. + +.. ocv:cfunction:: int cvGetImageCOI(const IplImage* image) +.. ocv:pyoldfunction:: cv.GetImageCOI(image) -> int + + :param image: A pointer to the image header + +Returns the channel of interest of in an IplImage. Returned values correspond to the ``coi`` in +:ocv:cfunc:`SetImageCOI`. + +GetImageROI +----------- +Returns the image ROI. + +.. ocv:cfunction:: CvRect cvGetImageROI(const IplImage* image) +.. ocv:pyoldfunction:: cv.GetImageROI(image)-> CvRect + + :param image: A pointer to the image header + +If there is no ROI set, ``cvRect(0,0,image->width,image->height)`` is returned. + +GetMat +------ +Returns matrix header for arbitrary array. + +.. ocv:cfunction:: CvMat* cvGetMat(const CvArr* arr, CvMat* header, int* coi=NULL, int allowND=0) +.. ocv:pyoldfunction:: cv.GetMat(arr, allowND=0) -> mat + + :param arr: Input array + + :param header: Pointer to :ocv:struct:`CvMat` structure used as a temporary buffer + + :param coi: Optional output parameter for storing COI + + :param allowND: If non-zero, the function accepts multi-dimensional dense arrays (CvMatND*) and returns 2D matrix (if CvMatND has two dimensions) or 1D matrix (when CvMatND has 1 dimension or more than 2 dimensions). The ``CvMatND`` array must be continuous. + +The function returns a matrix header for the input array that can be a matrix - :ocv:struct:`CvMat`, an image - :ocv:struct:`IplImage`, or a multi-dimensional dense array - :ocv:struct:`CvMatND` (the third option is allowed only if ``allowND != 0``) . In the case of matrix the function simply returns the input pointer. In the case of ``IplImage*`` or ``CvMatND`` it initializes the ``header`` structure with parameters of the current image ROI and returns ``&header``. Because COI is not supported by ``CvMat``, it is returned separately. + +The function provides an easy way to handle both types of arrays - ``IplImage`` and ``CvMat`` using the same code. Input array must have non-zero data pointer, otherwise the function will report an error. + +.. seealso:: :ocv:cfunc:`GetImage`, :ocv:func:`cvarrToMat`. + +.. note:: If the input array is ``IplImage`` with planar data layout and COI set, the function returns the pointer to the selected plane and ``COI == 0``. This feature allows user to process ``IplImage`` structures with planar data layout, even though OpenCV does not support such images. + +GetNextSparseNode +----------------- +Returns the next sparse matrix element + +.. ocv:cfunction:: CvSparseNode* cvGetNextSparseNode( CvSparseMatIterator* mat_iterator ) + + :param mat_iterator: Sparse array iterator + +The function moves iterator to the next sparse matrix element and returns pointer to it. In the current version there is no any particular order of the elements, because they are stored in the hash table. The sample below demonstrates how to iterate through the sparse matrix: :: + + // print all the non-zero sparse matrix elements and compute their sum + double sum = 0; + int i, dims = cvGetDims(sparsemat); + CvSparseMatIterator it; + CvSparseNode* node = cvInitSparseMatIterator(sparsemat, &it); + + for(; node != 0; node = cvGetNextSparseNode(&it)) + { + /* get pointer to the element indices */ + int* idx = CV_NODE_IDX(array, node); + /* get value of the element (assume that the type is CV_32FC1) */ + float val = *(float*)CV_NODE_VAL(array, node); + printf("M"); + for(i = 0; i < dims; i++ ) + printf("[%d]", idx[i]); + printf("=%g\n", val); + + sum += val; + } + + printf("nTotal sum = %g\n", sum); + + +GetRawData +---------- +Retrieves low-level information about the array. + +.. ocv:cfunction:: void cvGetRawData( const CvArr* arr, uchar** data, int* step=NULL, CvSize* roi_size=NULL ) + + :param arr: Array header + + :param data: Output pointer to the whole image origin or ROI origin if ROI is set + + :param step: Output full row length in bytes + + :param roi_size: Output ROI size + +The function fills output variables with low-level information about the array data. All output parameters are optional, so some of the pointers may be set to ``NULL``. If the array is ``IplImage`` with ROI set, the parameters of ROI are returned. + +The following example shows how to get access to array elements. It computes absolute values of the array elements :: + + float* data; + int step; + CvSize size; + + cvGetRawData(array, (uchar**)&data, &step, &size); + step /= sizeof(data[0]); + + for(int y = 0; y < size.height; y++, data += step ) + for(int x = 0; x < size.width; x++ ) + data[x] = (float)fabs(data[x]); + +GetReal?D +--------- +Return a specific element of single-channel 1D, 2D, 3D or nD array. + +.. ocv:cfunction:: double cvGetReal1D(const CvArr* arr, int idx0) +.. ocv:cfunction:: double cvGetReal2D(const CvArr* arr, int idx0, int idx1) +.. ocv:cfunction:: double cvGetReal3D(const CvArr* arr, int idx0, int idx1, int idx2) +.. ocv:cfunction:: double cvGetRealND( const CvArr* arr, const int* idx ) + +.. ocv:pyoldfunction:: cv.GetReal1D(arr, idx0)->float +.. ocv:pyoldfunction:: cv.GetReal2D(arr, idx0, idx1)->float +.. ocv:pyoldfunction:: cv.GetReal3D(arr, idx0, idx1, idx2)->float +.. ocv:pyoldfunction:: cv.GetRealND(arr, idx)->float + + :param arr: Input array. Must have a single channel. + + :param idx0: The first zero-based component of the element index + + :param idx1: The second zero-based component of the element index + + :param idx2: The third zero-based component of the element index + + :param idx: Array of the element indices + +Returns a specific element of a single-channel array. If the array has multiple channels, a runtime error is raised. Note that ``Get?D`` functions can be used safely for both single-channel and multiple-channel arrays though they are a bit slower. + +In the case of a sparse array the functions return 0 if the requested node does not exist (no new node is created by the functions). + + +GetRow(s) +--------- +Returns array row or row span. + +.. ocv:cfunction:: CvMat* cvGetRow(const CvArr* arr, CvMat* submat, int row) + +.. ocv:cfunction:: CvMat* cvGetRows( const CvArr* arr, CvMat* submat, int start_row, int end_row, int delta_row=1 ) + +.. ocv:pyoldfunction:: cv.GetRow(arr, row)-> submat +.. ocv:pyoldfunction:: cv.GetRows(arr, startRow, endRow, deltaRow=1)-> submat + + :param arr: Input array + + :param submat: Pointer to the resulting sub-array header + + :param row: Zero-based index of the selected row + + :param start_row: Zero-based index of the starting row (inclusive) of the span + + :param end_row: Zero-based index of the ending row (exclusive) of the span + + :param delta_row: Index step in the row span. That is, the function extracts every ``delta_row`` -th row from ``start_row`` and up to (but not including) ``end_row`` . + +The functions return the header, corresponding to a specified row/row span of the input array. ``cvGetRow(arr, submat, row)`` is a shortcut for ``cvGetRows(arr, submat, row, row+1)``. + + +GetSize +------- +Returns size of matrix or image ROI. + +.. ocv:cfunction:: CvSize cvGetSize(const CvArr* arr) +.. ocv:pyoldfunction:: cv.GetSize(arr)-> (width, height) + + :param arr: array header + +The function returns number of rows (CvSize::height) and number of columns (CvSize::width) of the input matrix or image. In the case of image the size of ROI is returned. + +GetSubRect +---------- +Returns matrix header corresponding to the rectangular sub-array of input image or matrix. + +.. ocv:cfunction:: CvMat* cvGetSubRect(const CvArr* arr, CvMat* submat, CvRect rect) +.. ocv:pyoldfunction:: cv.GetSubRect(arr, rect) -> submat + + :param arr: Input array + + :param submat: Pointer to the resultant sub-array header + + :param rect: Zero-based coordinates of the rectangle of interest + +The function returns header, corresponding to a specified rectangle of the input array. In other words, it allows the user to treat a rectangular part of input array as a stand-alone array. ROI is taken into account by the function so the sub-array of ROI is actually extracted. + +DecRefData +---------- +Decrements an array data reference counter. + +.. ocv:cfunction:: void cvDecRefData(CvArr* arr) + + :param arr: Pointer to an array header + +The function decrements the data reference counter in a :ocv:struct:`CvMat` or :ocv:struct:`CvMatND` if the reference counter pointer is not NULL. If the counter reaches zero, the data is deallocated. In the current implementation the reference counter is not NULL only if the data was allocated using the :ocv:cfunc:`CreateData` function. The counter will be NULL in other cases such as: external data was assigned to the header using :ocv:cfunc:`SetData`, header is part of a larger matrix or image, or the header was converted from an image or n-dimensional matrix header. + + +IncRefData +---------- +Increments array data reference counter. + +.. ocv:cfunction:: int cvIncRefData(CvArr* arr) + + :param arr: Array header + +The function increments :ocv:struct:`CvMat` or :ocv:struct:`CvMatND` data reference counter and returns the new counter value if the reference counter pointer is not NULL, otherwise it returns zero. + + +InitImageHeader +--------------- +Initializes an image header that was previously allocated. + +.. ocv:cfunction:: IplImage* cvInitImageHeader( IplImage* image, CvSize size, int depth, int channels, int origin=0, int align=4) + + :param image: Image header to initialize + + :param size: Image width and height + + :param depth: Image depth (see :ocv:cfunc:`CreateImage` ) + + :param channels: Number of channels (see :ocv:cfunc:`CreateImage` ) + + :param origin: Top-left ``IPL_ORIGIN_TL`` or bottom-left ``IPL_ORIGIN_BL`` + + :param align: Alignment for image rows, typically 4 or 8 bytes + +The returned ``IplImage*`` points to the initialized header. + + +InitMatHeader +------------- +Initializes a pre-allocated matrix header. + +.. ocv:cfunction:: CvMat* cvInitMatHeader( CvMat* mat, int rows, int cols, int type, void* data=NULL, int step=CV_AUTOSTEP) + + :param mat: A pointer to the matrix header to be initialized + + :param rows: Number of rows in the matrix + + :param cols: Number of columns in the matrix + + :param type: Type of the matrix elements, see :ocv:cfunc:`CreateMat` . + + :param data: Optional: data pointer assigned to the matrix header + + :param step: Optional: full row width in bytes of the assigned data. By default, the minimal possible step is used which assumes there are no gaps between subsequent rows of the matrix. + +This function is often used to process raw data with OpenCV matrix functions. For example, the following code computes the matrix product of two matrices, stored as ordinary arrays: :: + + double a[] = { 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12 }; + + double b[] = { 1, 5, 9, + 2, 6, 10, + 3, 7, 11, + 4, 8, 12 }; + + double c[9]; + CvMat Ma, Mb, Mc ; + + cvInitMatHeader(&Ma, 3, 4, CV_64FC1, a); + cvInitMatHeader(&Mb, 4, 3, CV_64FC1, b); + cvInitMatHeader(&Mc, 3, 3, CV_64FC1, c); + + cvMatMulAdd(&Ma, &Mb, 0, &Mc); + // the c array now contains the product of a (3x4) and b (4x3) + + +InitMatNDHeader +--------------- +Initializes a pre-allocated multi-dimensional array header. + +.. ocv:cfunction:: CvMatND* cvInitMatNDHeader( CvMatND* mat, int dims, const int* sizes, int type, void* data=NULL) + + :param mat: A pointer to the array header to be initialized + + :param dims: The number of array dimensions + + :param sizes: An array of dimension sizes + + :param type: Type of array elements, see :ocv:cfunc:`CreateMat` + + :param data: Optional data pointer assigned to the matrix header + + +InitSparseMatIterator +--------------------- +Initializes sparse array elements iterator. + +.. ocv:cfunction:: CvSparseNode* cvInitSparseMatIterator( const CvSparseMat* mat, CvSparseMatIterator* mat_iterator ) + + :param mat: Input array + + :param mat_iterator: Initialized iterator + +The function initializes iterator of sparse array elements and returns pointer to the first element, or NULL if the array is empty. + + +Mat +--- +Initializes matrix header (lightweight variant). + +.. ocv:cfunction:: CvMat cvMat( int rows, int cols, int type, void* data=NULL) + + :param rows: Number of rows in the matrix + + :param cols: Number of columns in the matrix + + :param type: Type of the matrix elements - see :ocv:cfunc:`CreateMat` + + :param data: Optional data pointer assigned to the matrix header + +Initializes a matrix header and assigns data to it. The matrix is filled *row*-wise (the first ``cols`` elements of data form the first row of the matrix, etc.) + +This function is a fast inline substitution for :ocv:cfunc:`InitMatHeader`. Namely, it is equivalent to: :: + + CvMat mat; + cvInitMatHeader(&mat, rows, cols, type, data, CV_AUTOSTEP); + + +Ptr?D +----- +Return pointer to a particular array element. + +.. ocv:cfunction:: uchar* cvPtr1D(const CvArr* arr, int idx0, int* type=NULL) + +.. ocv:cfunction:: uchar* cvPtr2D(const CvArr* arr, int idx0, int idx1, int* type=NULL) + +.. ocv:cfunction:: uchar* cvPtr3D(const CvArr* arr, int idx0, int idx1, int idx2, int* type=NULL) + +.. ocv:cfunction:: uchar* cvPtrND( const CvArr* arr, const int* idx, int* type=NULL, int create_node=1, unsigned* precalc_hashval=NULL ) + + :param arr: Input array + + :param idx0: The first zero-based component of the element index + + :param idx1: The second zero-based component of the element index + + :param idx2: The third zero-based component of the element index + + :param idx: Array of the element indices + + :param type: Optional output parameter: type of matrix elements + + :param create_node: Optional input parameter for sparse matrices. Non-zero value of the parameter means that the requested element is created if it does not exist already. + + :param precalc_hashval: Optional input parameter for sparse matrices. If the pointer is not NULL, the function does not recalculate the node hash value, but takes it from the specified location. It is useful for speeding up pair-wise operations (TODO: provide an example) + +The functions return a pointer to a specific array element. Number of array dimension should match to the number of indices passed to the function except for ``cvPtr1D`` function that can be used for sequential access to 1D, 2D or nD dense arrays. + +The functions can be used for sparse arrays as well - if the requested node does not exist they create it and set it to zero. + +All these as well as other functions accessing array elements ( +:ocv:cfunc:`GetND` +, +:ocv:cfunc:`GetRealND` +, +:ocv:cfunc:`Set` +, +:ocv:cfunc:`SetND` +, +:ocv:cfunc:`SetRealND` +) raise an error in case if the element index is out of range. + + +ReleaseData +----------- +Releases array data. + +.. ocv:cfunction:: void cvReleaseData(CvArr* arr) + + :param arr: Array header + +The function releases the array data. In the case of +:ocv:struct:`CvMat` +or +:ocv:struct:`CvMatND` +it simply calls cvDecRefData(), that is the function can not deallocate external data. See also the note to +:ocv:cfunc:`CreateData` +. + + +ReleaseImage +------------ +Deallocates the image header and the image data. + +.. ocv:cfunction:: void cvReleaseImage(IplImage** image) + + :param image: Double pointer to the image header + +This call is a shortened form of :: + + if(*image ) + { + cvReleaseData(*image); + cvReleaseImageHeader(image); + } + +.. + +ReleaseImageHeader +------------------ +Deallocates an image header. + +.. ocv:cfunction:: void cvReleaseImageHeader(IplImage** image) + + :param image: Double pointer to the image header + +This call is an analogue of :: + + if(image ) + { + iplDeallocate(*image, IPL_IMAGE_HEADER | IPL_IMAGE_ROI); + *image = 0; + } + +.. + +but it does not use IPL functions by default (see the ``CV_TURN_ON_IPL_COMPATIBILITY`` macro). + + +ReleaseMat +---------- +Deallocates a matrix. + +.. ocv:cfunction:: void cvReleaseMat(CvMat** mat) + + :param mat: Double pointer to the matrix + +The function decrements the matrix data reference counter and deallocates matrix header. If the data reference counter is 0, it also deallocates the data. :: + + if(*mat ) + cvDecRefData(*mat); + cvFree((void**)mat); + +.. + +ReleaseMatND +------------ +Deallocates a multi-dimensional array. + +.. ocv:cfunction:: void cvReleaseMatND(CvMatND** mat) + + :param mat: Double pointer to the array + +The function decrements the array data reference counter and releases the array header. If the reference counter reaches 0, it also deallocates the data. :: + + if(*mat ) + cvDecRefData(*mat); + cvFree((void**)mat); + +.. + +ReleaseSparseMat +---------------- +Deallocates sparse array. + +.. ocv:cfunction:: void cvReleaseSparseMat(CvSparseMat** mat) + + :param mat: Double pointer to the array + +The function releases the sparse array and clears the array pointer upon exit. + +ResetImageROI +------------- +Resets the image ROI to include the entire image and releases the ROI structure. + +.. ocv:cfunction:: void cvResetImageROI(IplImage* image) +.. ocv:pyoldfunction:: cv.ResetImageROI(image)-> None + + :param image: A pointer to the image header + +This produces a similar result to the following, but in addition it releases the ROI structure. :: + + cvSetImageROI(image, cvRect(0, 0, image->width, image->height )); + cvSetImageCOI(image, 0); + +.. + +Reshape +------- +Changes shape of matrix/image without copying data. + +.. ocv:cfunction:: CvMat* cvReshape( const CvArr* arr, CvMat* header, int new_cn, int new_rows=0 ) + +.. ocv:pyoldfunction:: cv.Reshape(arr, newCn, newRows=0) -> mat + + :param arr: Input array + + :param header: Output header to be filled + + :param new_cn: New number of channels. 'new_cn = 0' means that the number of channels remains unchanged. + + :param new_rows: New number of rows. 'new_rows = 0' means that the number of rows remains unchanged unless it needs to be changed according to ``new_cn`` value. + +The function initializes the CvMat header so that it points to the same data as the original array but has a different shape - different number of channels, different number of rows, or both. + +The following example code creates one image buffer and two image headers, the first is for a 320x240x3 image and the second is for a 960x240x1 image: :: + + IplImage* color_img = cvCreateImage(cvSize(320,240), IPL_DEPTH_8U, 3); + CvMat gray_mat_hdr; + IplImage gray_img_hdr, *gray_img; + cvReshape(color_img, &gray_mat_hdr, 1); + gray_img = cvGetImage(&gray_mat_hdr, &gray_img_hdr); + +.. + +And the next example converts a 3x3 matrix to a single 1x9 vector: + +:: + + CvMat* mat = cvCreateMat(3, 3, CV_32F); + CvMat row_header, *row; + row = cvReshape(mat, &row_header, 0, 1); + +.. + +ReshapeMatND +------------ +Changes the shape of a multi-dimensional array without copying the data. + +.. ocv:cfunction:: CvArr* cvReshapeMatND( const CvArr* arr, int sizeof_header, CvArr* header, int new_cn, int new_dims, int* new_sizes ) + +.. ocv:pyoldfunction:: cv.ReshapeMatND(arr, newCn, newDims) -> mat + + :param arr: Input array + + :param sizeof_header: Size of output header to distinguish between IplImage, CvMat and CvMatND output headers + + :param header: Output header to be filled + + :param new_cn: New number of channels. ``new_cn = 0`` means that the number of channels remains unchanged. + + :param new_dims: New number of dimensions. ``new_dims = 0`` means that the number of dimensions remains the same. + + :param new_sizes: Array of new dimension sizes. Only ``new_dims-1`` values are used, because the total number of elements must remain the same. Thus, if ``new_dims = 1``, ``new_sizes`` array is not used. + +The function is an advanced version of :ocv:cfunc:`Reshape` that can work with multi-dimensional arrays as well (though it can work with ordinary images and matrices) and change the number of dimensions. + +Below are the two samples from the +:ocv:cfunc:`Reshape` +description rewritten using +:ocv:cfunc:`ReshapeMatND` +: :: + + IplImage* color_img = cvCreateImage(cvSize(320,240), IPL_DEPTH_8U, 3); + IplImage gray_img_hdr, *gray_img; + gray_img = (IplImage*)cvReshapeND(color_img, &gray_img_hdr, 1, 0, 0); + + ... + + /* second example is modified to convert 2x2x2 array to 8x1 vector */ + int size[] = { 2, 2, 2 }; + CvMatND* mat = cvCreateMatND(3, size, CV_32F); + CvMat row_header, *row; + row = (CvMat*)cvReshapeND(mat, &row_header, 0, 1, 0); + +.. + +Set +--- +Sets every element of an array to a given value. + +.. ocv:cfunction:: void cvSet(CvArr* arr, CvScalar value, const CvArr* mask=NULL) +.. ocv:pyoldfunction:: cv.Set(arr, value, mask=None)-> None + + :param arr: The destination array + + :param value: Fill value + + :param mask: Operation mask, 8-bit single channel array; specifies elements of the destination array to be changed + +The function copies the scalar ``value`` to every selected element of the destination array: + +.. math:: + + \texttt{arr} (I)= \texttt{value} \quad \text{if} \quad \texttt{mask} (I) \ne 0 + +If array ``arr`` is of ``IplImage`` type, then is ROI used, but COI must not be set. + +Set?D +----- +Change the particular array element. + +.. ocv:cfunction:: void cvSet1D(CvArr* arr, int idx0, CvScalar value) + +.. ocv:cfunction:: void cvSet2D(CvArr* arr, int idx0, int idx1, CvScalar value) + +.. ocv:cfunction:: void cvSet3D(CvArr* arr, int idx0, int idx1, int idx2, CvScalar value) + +.. ocv:cfunction:: void cvSetND( CvArr* arr, const int* idx, CvScalar value ) + +.. ocv:pyoldfunction:: cv.Set1D(arr, idx, value) -> None +.. ocv:pyoldfunction:: cv.Set2D(arr, idx0, idx1, value) -> None +.. ocv:pyoldfunction:: cv.Set3D(arr, idx0, idx1, idx2, value) -> None +.. ocv:pyoldfunction:: cv.SetND(arr, indices, value) -> None + + + :param arr: Input array + + :param idx0: The first zero-based component of the element index + + :param idx1: The second zero-based component of the element index + + :param idx2: The third zero-based component of the element index + + :param idx: Array of the element indices + + :param value: The assigned value + +The functions assign the new value to a particular array element. In the case of a sparse array the functions create the node if it does not exist yet. + +SetData +------- +Assigns user data to the array header. + +.. ocv:cfunction:: void cvSetData(CvArr* arr, void* data, int step) +.. ocv:pyoldfunction:: cv.SetData(arr, data, step)-> None + + :param arr: Array header + + :param data: User data + + :param step: Full row length in bytes + +The function assigns user data to the array header. Header should be initialized before using +:ocv:cfunc:`cvCreateMatHeader`, :ocv:cfunc:`cvCreateImageHeader`, :ocv:cfunc:`cvCreateMatNDHeader`, +:ocv:cfunc:`cvInitMatHeader`, :ocv:cfunc:`cvInitImageHeader` or :ocv:cfunc:`cvInitMatNDHeader`. + + + +SetImageCOI +----------- +Sets the channel of interest in an IplImage. + +.. ocv:cfunction:: void cvSetImageCOI( IplImage* image, int coi) +.. ocv:pyoldfunction:: cv.SetImageCOI(image, coi)-> None + + :param image: A pointer to the image header + + :param coi: The channel of interest. 0 - all channels are selected, 1 - first channel is selected, etc. Note that the channel indices become 1-based. + +If the ROI is set to ``NULL`` and the coi is *not* 0, the ROI is allocated. Most OpenCV functions do *not* support the COI setting, so to process an individual image/matrix channel one may copy (via :ocv:cfunc:`Copy` or :ocv:cfunc:`Split`) the channel to a separate image/matrix, process it and then copy the result back (via :ocv:cfunc:`Copy` or :ocv:cfunc:`Merge`) if needed. + + +SetImageROI +----------- +Sets an image Region Of Interest (ROI) for a given rectangle. + +.. ocv:cfunction:: void cvSetImageROI( IplImage* image, CvRect rect) +.. ocv:pyoldfunction:: cv.SetImageROI(image, rect)-> None + + :param image: A pointer to the image header + + :param rect: The ROI rectangle + +If the original image ROI was ``NULL`` and the ``rect`` is not the whole image, the ROI structure is allocated. + +Most OpenCV functions support the use of ROI and treat the image rectangle as a separate image. For example, all of the pixel coordinates are counted from the top-left (or bottom-left) corner of the ROI, not the original image. + + +SetReal?D +--------- +Change a specific array element. + +.. ocv:cfunction:: void cvSetReal1D(CvArr* arr, int idx0, double value) + +.. ocv:cfunction:: void cvSetReal2D(CvArr* arr, int idx0, int idx1, double value) + +.. ocv:cfunction:: void cvSetReal3D(CvArr* arr, int idx0, int idx1, int idx2, double value) + +.. ocv:cfunction:: void cvSetRealND( CvArr* arr, const int* idx, double value ) + +.. ocv:pyoldfunction:: cv.SetReal1D(arr, idx, value) -> None +.. ocv:pyoldfunction:: cv.SetReal2D(arr, idx0, idx1, value) -> None +.. ocv:pyoldfunction:: cv.SetReal3D(arr, idx0, idx1, idx2, value) -> None +.. ocv:pyoldfunction:: cv.SetRealND(arr, indices, value) -> None + + :param arr: Input array + + :param idx0: The first zero-based component of the element index + + :param idx1: The second zero-based component of the element index + + :param idx2: The third zero-based component of the element index + + :param idx: Array of the element indices + + :param value: The assigned value + +The functions assign a new value to a specific element of a single-channel array. If the array has multiple channels, a runtime error is raised. Note that the ``Set*D`` function can be used safely for both single-channel and multiple-channel arrays, though they are a bit slower. + +In the case of a sparse array the functions create the node if it does not yet exist. + +SetZero +------- +Clears the array. + +.. ocv:cfunction:: void cvSetZero(CvArr* arr) +.. ocv:pyoldfunction:: cv.SetZero(arr) -> None + + :param arr: Array to be cleared + +The function clears the array. In the case of dense arrays (CvMat, CvMatND or IplImage), cvZero(array) is equivalent to cvSet(array,cvScalarAll(0),0). In the case of sparse arrays all the elements are removed. + +mGet +---- +Returns the particular element of single-channel floating-point matrix. + +.. ocv:cfunction:: double cvmGet(const CvMat* mat, int row, int col) +.. ocv:pyoldfunction:: cv.mGet(mat, row, col) -> float + + :param mat: Input matrix + + :param row: The zero-based index of row + + :param col: The zero-based index of column + +The function is a fast replacement for :ocv:cfunc:`GetReal2D` in the case of single-channel floating-point matrices. It is faster because it is inline, it does fewer checks for array type and array element type, and it checks for the row and column ranges only in debug mode. + +mSet +---- +Sets a specific element of a single-channel floating-point matrix. + +.. ocv:cfunction:: void cvmSet(CvMat* mat, int row, int col, double value) +.. ocv:pyoldfunction:: cv.mSet(mat, row, col, value)-> None + + :param mat: The matrix + + :param row: The zero-based index of row + + :param col: The zero-based index of column + + :param value: The new value of the matrix element + +The function is a fast replacement for :ocv:cfunc:`SetReal2D` in the case of single-channel floating-point matrices. It is faster because it is inline, it does fewer checks for array type and array element type, and it checks for the row and column ranges only in debug mode. + + +SetIPLAllocators +---------------- +Makes OpenCV use IPL functions for allocating IplImage and IplROI structures. + +.. ocv:cfunction:: void cvSetIPLAllocators( Cv_iplCreateImageHeader create_header, Cv_iplAllocateImageData allocate_data, Cv_iplDeallocate deallocate, Cv_iplCreateROI create_roi, Cv_iplCloneImage clone_image ) + +Normally, the function is not called directly. Instead, a simple macro ``CV_TURN_ON_IPL_COMPATIBILITY()`` is used that calls ``cvSetIPLAllocators`` and passes there pointers to IPL allocation functions. :: + + ... + CV_TURN_ON_IPL_COMPATIBILITY() + ... + + +RNG +--- +Initializes a random number generator state. + +.. ocv:cfunction:: CvRNG cvRNG(int64 seed=-1) +.. ocv:pyoldfunction:: cv.RNG(seed=-1LL)-> CvRNG + + :param seed: 64-bit value used to initiate a random sequence + +The function initializes a random number generator and returns the state. The pointer to the state can be then passed to the :ocv:cfunc:`RandInt`, :ocv:cfunc:`RandReal` and :ocv:cfunc:`RandArr` functions. In the current implementation a multiply-with-carry generator is used. + +.. seealso:: the C++ class :ocv:class:`RNG` replaced ``CvRNG``. + + +RandArr +------- +Fills an array with random numbers and updates the RNG state. + +.. ocv:cfunction:: void cvRandArr( CvRNG* rng, CvArr* arr, int dist_type, CvScalar param1, CvScalar param2 ) + +.. ocv:pyoldfunction:: cv.RandArr(rng, arr, distType, param1, param2)-> None + + :param rng: CvRNG state initialized by :ocv:cfunc:`RNG` + + :param arr: The destination array + + :param dist_type: Distribution type + + * **CV_RAND_UNI** uniform distribution + + * **CV_RAND_NORMAL** normal or Gaussian distribution + + :param param1: The first parameter of the distribution. In the case of a uniform distribution it is the inclusive lower boundary of the random numbers range. In the case of a normal distribution it is the mean value of the random numbers. + + :param param2: The second parameter of the distribution. In the case of a uniform distribution it is the exclusive upper boundary of the random numbers range. In the case of a normal distribution it is the standard deviation of the random numbers. + +The function fills the destination array with uniformly or normally distributed random numbers. + +.. seealso:: :ocv:func:`randu`, :ocv:func:`randn`, :ocv:func:`RNG::fill`. + +RandInt +------- +Returns a 32-bit unsigned integer and updates RNG. + +.. ocv:cfunction:: unsigned cvRandInt(CvRNG* rng) +.. ocv:pyoldfunction:: cv.RandInt(rng)-> unsigned + + :param rng: CvRNG state initialized by :ocv:cfunc:`RNG`. + +The function returns a uniformly-distributed random 32-bit unsigned integer and updates the RNG state. It is similar to the rand() function from the C runtime library, except that OpenCV functions always generates a 32-bit random number, regardless of the platform. + + +RandReal +-------- +Returns a floating-point random number and updates RNG. + +.. ocv:cfunction:: double cvRandReal(CvRNG* rng) +.. ocv:pyoldfunction:: cv.RandReal(rng) -> float + + :param rng: RNG state initialized by :ocv:cfunc:`RNG` + +The function returns a uniformly-distributed random floating-point number between 0 and 1 (1 is not included). + + +fromarray +--------- +Create a CvMat from an object that supports the array interface. + +.. ocv:pyoldfunction:: cv.fromarray(array, allowND=False) -> mat + + :param object: Any object that supports the array interface + + :param allowND: If true, will return a CvMatND + +If the object supports the `array interface `_ +, +return a :ocv:struct:`CvMat` or :ocv:struct:`CvMatND`, depending on ``allowND`` flag: + + * If ``allowND = False``, then the object's array must be either 2D or 3D. If it is 2D, then the returned CvMat has a single channel. If it is 3D, then the returned CvMat will have N channels, where N is the last dimension of the array. In this case, N cannot be greater than OpenCV's channel limit, ``CV_CN_MAX``. + + * If``allowND = True``, then ``fromarray`` returns a single-channel :ocv:struct:`CvMatND` with the same shape as the original array. + +For example, `NumPy `_ arrays support the array interface, so can be converted to OpenCV objects: + +.. code-block::python + + >>> import cv2.cv as cv, numpy + >>> a = numpy.ones((480, 640)) + >>> mat = cv.fromarray(a) + >>> print cv.GetDims(mat), cv.CV_MAT_CN(cv.GetElemType(mat)) + (480, 640) 1 + >>> a = numpy.ones((480, 640, 3)) + >>> mat = cv.fromarray(a) + >>> print cv.GetDims(mat), cv.CV_MAT_CN(cv.GetElemType(mat)) + (480, 640) 3 + >>> a = numpy.ones((480, 640, 3)) + >>> mat = cv.fromarray(a, allowND = True) + >>> print cv.GetDims(mat), cv.CV_MAT_CN(cv.GetElemType(mat)) + (480, 640, 3) 1 + +.. note:: In the new Python wrappers (**cv2** module) the function is not needed, since cv2 can process Numpy arrays (and this is the only supported array type). + diff --git a/core/doc/old_xml_yaml_persistence.rst b/core/doc/old_xml_yaml_persistence.rst new file mode 100644 index 0000000..bdd4c2d --- /dev/null +++ b/core/doc/old_xml_yaml_persistence.rst @@ -0,0 +1,913 @@ +XML/YAML Persistence (C API) +============================== + +The section describes the OpenCV 1.x API for reading and writing data structures to/from XML or YAML files. It is now recommended to use the new C++ interface for reading and writing data. + +.. highlight:: c + +CvFileStorage +------------- + +.. ocv:struct:: CvFileStorage + +The structure ``CvFileStorage`` is a "black box" representation of the file storage associated with a file on disk. Several functions that are described below take ``CvFileStorage*`` as inputs and allow the user to save or to load hierarchical collections that consist of scalar values, standard CXCore objects (such as matrices, sequences, graphs), and user-defined objects. + +OpenCV can read and write data in XML (http://www.w3c.org/XML) or YAML +(http://www.yaml.org) formats. Below is an example of 3x3 floating-point identity matrix ``A``, stored in XML and YAML files using CXCore functions: + +XML: :: + + + + + 3 + 3 +
f
+ 1. 0. 0. 0. 1. 0. 0. 0. 1. +
+
+ +YAML: :: + + %YAML:1.0 + A: !!opencv-matrix + rows: 3 + cols: 3 + dt: f + data: [ 1., 0., 0., 0., 1., 0., 0., 0., 1.] + +As it can be seen from the examples, XML uses nested tags to represent +hierarchy, while YAML uses indentation for that purpose (similar +to the Python programming language). + +The same functions can read and write data in both formats; +the particular format is determined by the extension of the opened file, ".xml" for XML files and ".yml" or ".yaml" for YAML. + +CvFileNode +---------- + +.. ocv:struct:: CvFileNode + + File storage node. When XML/YAML file is read, it is first parsed and stored in the memory as a hierarchical collection of nodes. Each node can be a "leaf", that is, contain a single number or a string, or be a collection of other nodes. Collections are also referenced to as "structures" in the data writing functions. There can be named collections (mappings), where each element has a name and is accessed by a name, and ordered collections (sequences), where elements do not have names, but rather accessed by index. + + .. ocv:member:: int tag + + type of the file node: + + * CV_NODE_NONE - empty node + * CV_NODE_INT - an integer + * CV_NODE_REAL - a floating-point number + * CV_NODE_STR - text string + * CV_NODE_SEQ - a sequence + * CV_NODE_MAP - a mapping + + type of the node can be retrieved using ``CV_NODE_TYPE(node->tag)`` macro. + + .. ocv:member:: CvTypeInfo* info + + optional pointer to the user type information. If you look at the matrix representation in XML and YAML, shown above, you may notice ``type_id="opencv-matrix"`` or ``!!opencv-matrix`` strings. They are used to specify that the certain element of a file is a representation of a data structure of certain type ("opencv-matrix" corresponds to :ocv:struct:`CvMat`). When a file is parsed, such type identifiers are passed to :ocv:cfunc:`FindType` to find type information and the pointer to it is stored in the file node. See :ocv:struct:`CvTypeInfo` for more details. + + .. ocv:member:: union data + + the node data, declared as: :: + + union + { + double f; /* scalar floating-point number */ + int i; /* scalar integer number */ + CvString str; /* text string */ + CvSeq* seq; /* sequence (ordered collection of file nodes) */ + struct CvMap* map; /* map (collection of named file nodes) */ + } data; + + .. + + Primitive nodes are read using :ocv:cfunc:`ReadInt`, :ocv:cfunc:`ReadReal` and :ocv:cfunc:`ReadString`. Sequences are read by iterating through ``node->data.seq`` (see "Dynamic Data Structures" section). Mappings are read using :ocv:cfunc:`GetFileNodeByName`. Nodes with the specified type (so that ``node->info != NULL``) can be read using :ocv:cfunc:`Read`. + +CvAttrList +---------- + +.. ocv:struct:: CvAttrList + +List of attributes. :: + + typedef struct CvAttrList + { + const char** attr; /* NULL-terminated array of (attribute_name,attribute_value) pairs */ + struct CvAttrList* next; /* pointer to next chunk of the attributes list */ + } + CvAttrList; + + /* initializes CvAttrList structure */ + inline CvAttrList cvAttrList( const char** attr=NULL, CvAttrList* next=NULL ); + + /* returns attribute value or 0 (NULL) if there is no such attribute */ + const char* cvAttrValue( const CvAttrList* attr, const char* attr_name ); + +.. + +In the current implementation, attributes are used to pass extra parameters when writing user objects (see +:ocv:cfunc:`Write`). XML attributes inside tags are not supported, aside from the object type specification (``type_id`` attribute). + +CvTypeInfo +---------- + +.. ocv:struct:: CvTypeInfo + +Type information. :: + + typedef int (CV_CDECL *CvIsInstanceFunc)( const void* structPtr ); + typedef void (CV_CDECL *CvReleaseFunc)( void** structDblPtr ); + typedef void* (CV_CDECL *CvReadFunc)( CvFileStorage* storage, CvFileNode* node ); + typedef void (CV_CDECL *CvWriteFunc)( CvFileStorage* storage, + const char* name, + const void* structPtr, + CvAttrList attributes ); + typedef void* (CV_CDECL *CvCloneFunc)( const void* structPtr ); + + typedef struct CvTypeInfo + { + int flags; /* not used */ + int header_size; /* sizeof(CvTypeInfo) */ + struct CvTypeInfo* prev; /* previous registered type in the list */ + struct CvTypeInfo* next; /* next registered type in the list */ + const char* type_name; /* type name, written to file storage */ + + /* methods */ + CvIsInstanceFunc is_instance; /* checks if the passed object belongs to the type */ + CvReleaseFunc release; /* releases object (memory etc.) */ + CvReadFunc read; /* reads object from file storage */ + CvWriteFunc write; /* writes object to file storage */ + CvCloneFunc clone; /* creates a copy of the object */ + } + CvTypeInfo; + +.. + +The structure contains information about one of the standard or user-defined types. Instances of the type may or may not contain a pointer to the corresponding :ocv:struct:`CvTypeInfo` structure. In any case, there is a way to find the type info structure for a given object using the :ocv:cfunc:`TypeOf` function. Alternatively, type info can be found by type name using :ocv:cfunc:`FindType`, which is used when an object is read from file storage. The user can register a new type with :ocv:cfunc:`RegisterType` +that adds the type information structure into the beginning of the type list. Thus, it is possible to create specialized types from generic standard types and override the basic methods. + +Clone +----- +Makes a clone of an object. + +.. ocv:cfunction:: void* cvClone( const void* struct_ptr ) + + :param struct_ptr: The object to clone + +The function finds the type of a given object and calls ``clone`` with the passed object. Of course, if you know the object type, for example, ``struct_ptr`` is ``CvMat*``, it is faster to call the specific function, like :ocv:cfunc:`CloneMat`. + +EndWriteStruct +-------------- +Finishes writing to a file node collection. + +.. ocv:cfunction:: void cvEndWriteStruct(CvFileStorage* fs) + + :param fs: File storage + +.. seealso:: :ocv:cfunc:`StartWriteStruct`. + +FindType +-------- +Finds a type by its name. + +.. ocv:cfunction:: CvTypeInfo* cvFindType( const char* type_name ) + + :param type_name: Type name + +The function finds a registered type by its name. It returns NULL if there is no type with the specified name. + +FirstType +--------- +Returns the beginning of a type list. + +.. ocv:cfunction:: CvTypeInfo* cvFirstType(void) + +The function returns the first type in the list of registered types. Navigation through the list can be done via the ``prev`` and ``next`` fields of the :ocv:struct:`CvTypeInfo` structure. + +GetFileNode +----------- +Finds a node in a map or file storage. + +.. ocv:cfunction:: CvFileNode* cvGetFileNode( CvFileStorage* fs, CvFileNode* map, const CvStringHashNode* key, int create_missing=0 ) + + :param fs: File storage + + :param map: The parent map. If it is NULL, the function searches a top-level node. If both ``map`` and ``key`` are NULLs, the function returns the root file node - a map that contains top-level nodes. + + :param key: Unique pointer to the node name, retrieved with :ocv:cfunc:`GetHashedKey` + + :param create_missing: Flag that specifies whether an absent node should be added to the map + +The function finds a file node. It is a faster version of :ocv:cfunc:`GetFileNodeByName` +(see :ocv:cfunc:`GetHashedKey` discussion). Also, the function can insert a new node, if it is not in the map yet. + +GetFileNodeByName +----------------- +Finds a node in a map or file storage. + +.. ocv:cfunction:: CvFileNode* cvGetFileNodeByName( const CvFileStorage* fs, const CvFileNode* map, const char* name) + + :param fs: File storage + + :param map: The parent map. If it is NULL, the function searches in all the top-level nodes (streams), starting with the first one. + + :param name: The file node name + +The function finds a file node by ``name``. The node is searched either in ``map`` or, if the pointer is NULL, among the top-level file storage nodes. Using this function for maps and :ocv:cfunc:`GetSeqElem` +(or sequence reader) for sequences, it is possible to navigate through the file storage. To speed up multiple queries for a certain key (e.g., in the case of an array of structures) one may use a combination of :ocv:cfunc:`GetHashedKey` and :ocv:cfunc:`GetFileNode`. + +GetFileNodeName +--------------- +Returns the name of a file node. + +.. ocv:cfunction:: const char* cvGetFileNodeName( const CvFileNode* node ) + + :param node: File node + +The function returns the name of a file node or NULL, if the file node does not have a name or if ``node`` is ``NULL``. + +GetHashedKey +------------ +Returns a unique pointer for a given name. + +.. ocv:cfunction:: CvStringHashNode* cvGetHashedKey( CvFileStorage* fs, const char* name, int len=-1, int create_missing=0 ) + + :param fs: File storage + + :param name: Literal node name + + :param len: Length of the name (if it is known apriori), or -1 if it needs to be calculated + + :param create_missing: Flag that specifies, whether an absent key should be added into the hash table + +The function returns a unique pointer for each particular file node name. This pointer can be then passed to the :ocv:cfunc:`GetFileNode` function that is faster than :ocv:cfunc:`GetFileNodeByName` +because it compares text strings by comparing pointers rather than the strings' content. + +Consider the following example where an array of points is encoded as a sequence of 2-entry maps: :: + + points: + - { x: 10, y: 10 } + - { x: 20, y: 20 } + - { x: 30, y: 30 } + # ... + +.. + +Then, it is possible to get hashed "x" and "y" pointers to speed up decoding of the points. :: + + #include "cxcore.h" + + int main( int argc, char** argv ) + { + CvFileStorage* fs = cvOpenFileStorage( "points.yml", 0, CV_STORAGE_READ ); + CvStringHashNode* x_key = cvGetHashedNode( fs, "x", -1, 1 ); + CvStringHashNode* y_key = cvGetHashedNode( fs, "y", -1, 1 ); + CvFileNode* points = cvGetFileNodeByName( fs, 0, "points" ); + + if( CV_NODE_IS_SEQ(points->tag) ) + { + CvSeq* seq = points->data.seq; + int i, total = seq->total; + CvSeqReader reader; + cvStartReadSeq( seq, &reader, 0 ); + for( i = 0; i < total; i++ ) + { + CvFileNode* pt = (CvFileNode*)reader.ptr; + #if 1 /* faster variant */ + CvFileNode* xnode = cvGetFileNode( fs, pt, x_key, 0 ); + CvFileNode* ynode = cvGetFileNode( fs, pt, y_key, 0 ); + assert( xnode && CV_NODE_IS_INT(xnode->tag) && + ynode && CV_NODE_IS_INT(ynode->tag)); + int x = xnode->data.i; // or x = cvReadInt( xnode, 0 ); + int y = ynode->data.i; // or y = cvReadInt( ynode, 0 ); + #elif 1 /* slower variant; does not use x_key & y_key */ + CvFileNode* xnode = cvGetFileNodeByName( fs, pt, "x" ); + CvFileNode* ynode = cvGetFileNodeByName( fs, pt, "y" ); + assert( xnode && CV_NODE_IS_INT(xnode->tag) && + ynode && CV_NODE_IS_INT(ynode->tag)); + int x = xnode->data.i; // or x = cvReadInt( xnode, 0 ); + int y = ynode->data.i; // or y = cvReadInt( ynode, 0 ); + #else /* the slowest yet the easiest to use variant */ + int x = cvReadIntByName( fs, pt, "x", 0 /* default value */ ); + int y = cvReadIntByName( fs, pt, "y", 0 /* default value */ ); + #endif + CV_NEXT_SEQ_ELEM( seq->elem_size, reader ); + printf(" + } + } + cvReleaseFileStorage( &fs ); + return 0; + } + +.. + +Please note that whatever method of accessing a map you are using, it is +still much slower than using plain sequences; for example, in the above +example, it is more efficient to encode the points as pairs of integers +in a single numeric sequence. + +GetRootFileNode +--------------- +Retrieves one of the top-level nodes of the file storage. + +.. ocv:cfunction:: CvFileNode* cvGetRootFileNode( const CvFileStorage* fs, int stream_index=0 ) + + :param fs: File storage + + :param stream_index: Zero-based index of the stream. See :ocv:cfunc:`StartNextStream` . In most cases, there is only one stream in the file; however, there can be several. + +The function returns one of the top-level file nodes. The top-level nodes do not have a name, they correspond to the streams that are stored one after another in the file storage. If the index is out of range, the function returns a NULL pointer, so all the top-level nodes can be iterated by subsequent calls to the function with ``stream_index=0,1,...``, until the NULL pointer is returned. This function +can be used as a base for recursive traversal of the file storage. + + +Load +---- +Loads an object from a file. + +.. ocv:cfunction:: void* cvLoad( const char* filename, CvMemStorage* memstorage=NULL, const char* name=NULL, const char** real_name=NULL ) + +.. ocv:pyoldfunction:: cv.Load(filename, storage=None, name=None)-> generic + + :param filename: File name + + :param memstorage: Memory storage for dynamic structures, such as :ocv:struct:`CvSeq` or :ocv:struct:`CvGraph` . It is not used for matrices or images. + + :param name: Optional object name. If it is NULL, the first top-level object in the storage will be loaded. + + :param real_name: Optional output parameter that will contain the name of the loaded object (useful if ``name=NULL`` ) + +The function loads an object from a file. It basically reads the specified file, find the first top-level node and calls :ocv:cfunc:`Read` for that node. If the file node does not have type information or the type information can not be found by the type name, the function returns NULL. After the object is loaded, the file storage is closed and all the temporary buffers are deleted. Thus, to load a dynamic structure, such as a sequence, contour, or graph, one should pass a valid memory storage destination to the function. + +OpenFileStorage +--------------- +Opens file storage for reading or writing data. + +.. ocv:cfunction:: CvFileStorage* cvOpenFileStorage( const char* filename, CvMemStorage* memstorage, int flags, const char* encoding=NULL ) + + :param filename: Name of the file associated with the storage + + :param memstorage: Memory storage used for temporary data and for + storing dynamic structures, such as :ocv:struct:`CvSeq` or :ocv:struct:`CvGraph` . + If it is NULL, a temporary memory storage is created and used. + + :param flags: Can be one of the following: + + * **CV_STORAGE_READ** the storage is open for reading + + * **CV_STORAGE_WRITE** the storage is open for writing + +The function opens file storage for reading or writing data. In the latter case, a new file is created or an existing file is rewritten. The type of the read or written file is determined by the filename extension: ``.xml`` for ``XML`` and ``.yml`` or ``.yaml`` for ``YAML``. The function returns a pointer to the :ocv:struct:`CvFileStorage` structure. If the file cannot be opened then the function returns ``NULL``. + +Read +---- +Decodes an object and returns a pointer to it. + +.. ocv:cfunction:: void* cvRead( CvFileStorage* fs, CvFileNode* node, CvAttrList* attributes=NULL ) + + :param fs: File storage + + :param node: The root object node + + :param attributes: Unused parameter + +The function decodes a user object (creates an object in a native representation from the file storage subtree) and returns it. The object to be decoded must be an instance of a registered type that supports the ``read`` method (see :ocv:struct:`CvTypeInfo`). The type of the object is determined by the type name that is encoded in the file. If the object is a dynamic structure, it is created either in memory storage and passed to :ocv:cfunc:`OpenFileStorage` or, if a NULL pointer was passed, in temporary +memory storage, which is released when :ocv:cfunc:`ReleaseFileStorage` is called. Otherwise, if the object is not a dynamic structure, it is created in a heap and should be released with a specialized function or by using the generic :ocv:cfunc:`Release`. + +ReadByName +---------- +Finds an object by name and decodes it. + +.. ocv:cfunction:: void* cvReadByName( CvFileStorage* fs, const CvFileNode* map, const char* name, CvAttrList* attributes=NULL ) + + :param fs: File storage + + :param map: The parent map. If it is NULL, the function searches a top-level node. + + :param name: The node name + + :param attributes: Unused parameter + +The function is a simple superposition of :ocv:cfunc:`GetFileNodeByName` and :ocv:cfunc:`Read`. + +ReadInt +------- +Retrieves an integer value from a file node. + +.. ocv:cfunction:: int cvReadInt( const CvFileNode* node, int default_value=0 ) + + :param node: File node + + :param default_value: The value that is returned if ``node`` is NULL + +The function returns an integer that is represented by the file node. If the file node is NULL, the +``default_value`` is returned (thus, it is convenient to call the function right after :ocv:cfunc:`GetFileNode` without checking for a NULL pointer). If the file node has type ``CV_NODE_INT``, then ``node->data.i`` is returned. If the file node has type ``CV_NODE_REAL``, then ``node->data.f`` +is converted to an integer and returned. Otherwise the error is reported. + +ReadIntByName +------------- +Finds a file node and returns its value. + +.. ocv:cfunction:: int cvReadIntByName( const CvFileStorage* fs, const CvFileNode* map, const char* name, int default_value=0 ) + + :param fs: File storage + + :param map: The parent map. If it is NULL, the function searches a top-level node. + + :param name: The node name + + :param default_value: The value that is returned if the file node is not found + +The function is a simple superposition of :ocv:cfunc:`GetFileNodeByName` and :ocv:cfunc:`ReadInt`. + +ReadRawData +----------- +Reads multiple numbers. + +.. ocv:cfunction:: void cvReadRawData( const CvFileStorage* fs, const CvFileNode* src, void* dst, const char* dt) + + :param fs: File storage + + :param src: The file node (a sequence) to read numbers from + + :param dst: Pointer to the destination array + + :param dt: Specification of each array element. It has the same format as in :ocv:cfunc:`WriteRawData` . + +The function reads elements from a file node that represents a sequence of scalars. + + +ReadRawDataSlice +---------------- +Initializes file node sequence reader. + +.. ocv:cfunction:: void cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader, int count, void* dst, const char* dt ) + + :param fs: File storage + + :param reader: The sequence reader. Initialize it with :ocv:cfunc:`StartReadRawData` . + + :param count: The number of elements to read + + :param dst: Pointer to the destination array + + :param dt: Specification of each array element. It has the same format as in :ocv:cfunc:`WriteRawData` . + +The function reads one or more elements from the file node, representing a sequence, to a user-specified array. The total number of read sequence elements is a product of ``total`` +and the number of components in each array element. For example, if ``dt=2if``, the function will read ``total*3`` sequence elements. As with any sequence, some parts of the file node sequence can be skipped or read repeatedly by repositioning the reader using :ocv:cfunc:`SetSeqReaderPos`. + +ReadReal +-------- +Retrieves a floating-point value from a file node. + +.. ocv:cfunction:: double cvReadReal( const CvFileNode* node, double default_value=0. ) + + :param node: File node + + :param default_value: The value that is returned if ``node`` is NULL + +The function returns a floating-point value +that is represented by the file node. If the file node is NULL, the +``default_value`` +is returned (thus, it is convenient to call +the function right after +:ocv:cfunc:`GetFileNode` +without checking for a NULL +pointer). If the file node has type +``CV_NODE_REAL`` +, +then +``node->data.f`` +is returned. If the file node has type +``CV_NODE_INT`` +, then +``node-:math:`>`data.f`` +is converted to floating-point +and returned. Otherwise the result is not determined. + + +ReadRealByName +-------------- +Finds a file node and returns its value. + +.. ocv:cfunction:: double cvReadRealByName( const CvFileStorage* fs, const CvFileNode* map, const char* name, double default_value=0. ) + + :param fs: File storage + + :param map: The parent map. If it is NULL, the function searches a top-level node. + + :param name: The node name + + :param default_value: The value that is returned if the file node is not found + +The function is a simple superposition of +:ocv:cfunc:`GetFileNodeByName` +and +:ocv:cfunc:`ReadReal` +. + + +ReadString +---------- +Retrieves a text string from a file node. + +.. ocv:cfunction:: const char* cvReadString( const CvFileNode* node, const char* default_value=NULL ) + + :param node: File node + + :param default_value: The value that is returned if ``node`` is NULL + +The function returns a text string that is represented +by the file node. If the file node is NULL, the +``default_value`` +is returned (thus, it is convenient to call the function right after +:ocv:cfunc:`GetFileNode` +without checking for a NULL pointer). If +the file node has type +``CV_NODE_STR`` +, then +``node-:math:`>`data.str.ptr`` +is returned. Otherwise the result is not determined. + + +ReadStringByName +---------------- +Finds a file node by its name and returns its value. + +.. ocv:cfunction:: const char* cvReadStringByName( const CvFileStorage* fs, const CvFileNode* map, const char* name, const char* default_value=NULL ) + + :param fs: File storage + + :param map: The parent map. If it is NULL, the function searches a top-level node. + + :param name: The node name + + :param default_value: The value that is returned if the file node is not found + +The function is a simple superposition of +:ocv:cfunc:`GetFileNodeByName` +and +:ocv:cfunc:`ReadString` +. + + +RegisterType +------------ +Registers a new type. + +.. ocv:cfunction:: void cvRegisterType(const CvTypeInfo* info) + + :param info: Type info structure + +The function registers a new type, which is +described by +``info`` +. The function creates a copy of the structure, +so the user should delete it after calling the function. + + +Release +------- +Releases an object. + +.. ocv:cfunction:: void cvRelease( void** struct_ptr ) + + :param struct_ptr: Double pointer to the object + +The function finds the type of a given object and calls +``release`` +with the double pointer. + + +ReleaseFileStorage +------------------ +Releases file storage. + +.. ocv:cfunction:: void cvReleaseFileStorage(CvFileStorage** fs) + + :param fs: Double pointer to the released file storage + +The function closes the file associated with the storage and releases all the temporary structures. It must be called after all I/O operations with the storage are finished. + + +Save +---- +Saves an object to a file. + +.. ocv:cfunction:: void cvSave( const char* filename, const void* struct_ptr, const char* name=NULL, const char* comment=NULL, CvAttrList attributes=cvAttrList() ) + +.. ocv:pyoldfunction:: cv.Save(filename, structPtr, name=None, comment=None)-> None + + :param filename: File name + + :param struct_ptr: Object to save + + :param name: Optional object name. If it is NULL, the name will be formed from ``filename`` . + + :param comment: Optional comment to put in the beginning of the file + + :param attributes: Optional attributes passed to :ocv:cfunc:`Write` + +The function saves an object to a file. It provides a simple interface to +:ocv:cfunc:`Write` +. + + +StartNextStream +--------------- +Starts the next stream. + +.. ocv:cfunction:: void cvStartNextStream(CvFileStorage* fs) + + :param fs: File storage + +The function finishes the currently written stream and starts the next stream. In the case of XML the file with multiple streams looks like this: :: + + + + + + + + ... + +The YAML file will look like this: :: + + %YAML:1.0 + # stream #1 data + ... + --- + # stream #2 data + +This is useful for concatenating files or for resuming the writing process. + + +StartReadRawData +---------------- +Initializes the file node sequence reader. + +.. ocv:cfunction:: void cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src, CvSeqReader* reader) + + :param fs: File storage + + :param src: The file node (a sequence) to read numbers from + + :param reader: Pointer to the sequence reader + +The function initializes the sequence reader to read data from a file node. The initialized reader can be then passed to :ocv:cfunc:`ReadRawDataSlice`. + + +StartWriteStruct +---------------- +Starts writing a new structure. + +.. ocv:cfunction:: void cvStartWriteStruct( CvFileStorage* fs, const char* name, int struct_flags, const char* type_name=NULL, CvAttrList attributes=cvAttrList() ) + + :param fs: File storage + + :param name: Name of the written structure. The structure can be accessed by this name when the storage is read. + + :param struct_flags: A combination one of the following values: + + * **CV_NODE_SEQ** the written structure is a sequence (see discussion of :ocv:struct:`CvFileStorage` ), that is, its elements do not have a name. + + * **CV_NODE_MAP** the written structure is a map (see discussion of :ocv:struct:`CvFileStorage` ), that is, all its elements have names. + + One and only one of the two above flags must be specified + + * **CV_NODE_FLOW** the optional flag that makes sense only for YAML streams. It means that the structure is written as a flow (not as a block), which is more compact. It is recommended to use this flag for structures or arrays whose elements are all scalars. + + :param type_name: Optional parameter - the object type name. In + case of XML it is written as a ``type_id`` attribute of the + structure opening tag. In the case of YAML it is written after a colon + following the structure name (see the example in :ocv:struct:`CvFileStorage` + description). Mainly it is used with user objects. When the storage + is read, the encoded type name is used to determine the object type + (see :ocv:struct:`CvTypeInfo` and :ocv:cfunc:`FindType` ). + + :param attributes: This parameter is not used in the current implementation + +The function starts writing a compound structure (collection) that can be a sequence or a map. After all the structure fields, which can be scalars or structures, are written, :ocv:cfunc:`EndWriteStruct` should be called. The function can be used to group some objects or to implement the ``write`` function for a some user object (see :ocv:struct:`CvTypeInfo`). + + +TypeOf +------ +Returns the type of an object. + +.. ocv:cfunction:: CvTypeInfo* cvTypeOf( const void* struct_ptr ) + + :param struct_ptr: The object pointer + +The function finds the type of a given object. It iterates through the list of registered types and calls the ``is_instance`` function/method for every type info structure with that object until one of them returns non-zero or until the whole list has been traversed. In the latter case, the function returns NULL. + + +UnregisterType +-------------- +Unregisters the type. + +.. ocv:cfunction:: void cvUnregisterType( const char* type_name ) + + :param type_name: Name of an unregistered type + +The function unregisters a type with a specified name. If the name is unknown, it is possible to locate the type info by an instance of the type using :ocv:cfunc:`TypeOf` or by iterating the type list, starting from :ocv:cfunc:`FirstType`, and then calling ``cvUnregisterType(info->typeName)``. + + +Write +----- +Writes an object to file storage. + +.. ocv:cfunction:: void cvWrite( CvFileStorage* fs, const char* name, const void* ptr, CvAttrList attributes=cvAttrList() ) + + :param fs: File storage + + :param name: Name of the written object. Should be NULL if and only if the parent structure is a sequence. + + :param ptr: Pointer to the object + + :param attributes: The attributes of the object. They are specific for each particular type (see the discussion below). + +The function writes an object to file storage. First, the appropriate type info is found using :ocv:cfunc:`TypeOf`. Then, the ``write`` method associated with the type info is called. + +Attributes are used to customize the writing procedure. The standard types support the following attributes (all the ``dt`` attributes have the same format as in :ocv:cfunc:`WriteRawData`): + +#. + CvSeq + + * **header_dt** description of user fields of the sequence header that follow CvSeq, or CvChain (if the sequence is a Freeman chain) or CvContour (if the sequence is a contour or point sequence) + + * **dt** description of the sequence elements. + + * **recursive** if the attribute is present and is not equal to "0" or "false", the whole tree of sequences (contours) is stored. + +#. + CvGraph + + * **header_dt** description of user fields of the graph header that follows CvGraph; + + * **vertex_dt** description of user fields of graph vertices + + * **edge_dt** description of user fields of graph edges (note that the edge weight is always written, so there is no need to specify it explicitly) + +Below is the code that creates the YAML file shown in the +``CvFileStorage`` +description: + +:: + + #include "cxcore.h" + + int main( int argc, char** argv ) + { + CvMat* mat = cvCreateMat( 3, 3, CV_32F ); + CvFileStorage* fs = cvOpenFileStorage( "example.yml", 0, CV_STORAGE_WRITE ); + + cvSetIdentity( mat ); + cvWrite( fs, "A", mat, cvAttrList(0,0) ); + + cvReleaseFileStorage( &fs ); + cvReleaseMat( &mat ); + return 0; + } + +.. + + +WriteComment +------------ +Writes a comment. + +.. ocv:cfunction:: void cvWriteComment( CvFileStorage* fs, const char* comment, int eol_comment ) + + :param fs: File storage + + :param comment: The written comment, single-line or multi-line + + :param eol_comment: If non-zero, the function tries to put the comment at the end of current line. If the flag is zero, if the comment is multi-line, or if it does not fit at the end of the current line, the comment starts a new line. + +The function writes a comment into file storage. The comments are skipped when the storage is read. + +WriteFileNode +------------- +Writes a file node to another file storage. + +.. ocv:cfunction:: void cvWriteFileNode( CvFileStorage* fs, const char* new_node_name, const CvFileNode* node, int embed ) + + :param fs: Destination file storage + + :param new_node_name: New name of the file node in the destination file storage. To keep the existing name, use :ocv:cfunc:`cvGetFileNodeName` + + :param node: The written node + + :param embed: If the written node is a collection and this parameter is not zero, no extra level of hierarchy is created. Instead, all the elements of ``node`` are written into the currently written structure. Of course, map elements can only be embedded into another map, and sequence elements can only be embedded into another sequence. + +The function writes a copy of a file node to file storage. Possible applications of the function are merging several file storages into one and conversion between XML and YAML formats. + +WriteInt +-------- +Writes an integer value. + +.. ocv:cfunction:: void cvWriteInt( CvFileStorage* fs, const char* name, int value) + + :param fs: File storage + + :param name: Name of the written value. Should be NULL if and only if the parent structure is a sequence. + + :param value: The written value + +The function writes a single integer value (with or without a name) to the file storage. + + +WriteRawData +------------ +Writes multiple numbers. + +.. ocv:cfunction:: void cvWriteRawData( CvFileStorage* fs, const void* src, int len, const char* dt ) + + :param fs: File storage + + :param src: Pointer to the written array + + :param len: Number of the array elements to write + + :param dt: Specification of each array element that has the following format ``([count]{'u'|'c'|'w'|'s'|'i'|'f'|'d'})...`` + where the characters correspond to fundamental C types: + + * **u** 8-bit unsigned number + + * **c** 8-bit signed number + + * **w** 16-bit unsigned number + + * **s** 16-bit signed number + + * **i** 32-bit signed number + + * **f** single precision floating-point number + + * **d** double precision floating-point number + + * **r** pointer, 32 lower bits of which are written as a signed integer. The type can be used to store structures with links between the elements. ``count`` is the optional counter of values of a given type. For + example, ``2if`` means that each array element is a structure + of 2 integers, followed by a single-precision floating-point number. The + equivalent notations of the above specification are ' ``iif`` ', + ' ``2i1f`` ' and so forth. Other examples: ``u`` means that the + array consists of bytes, and ``2d`` means the array consists of pairs + of doubles. + +The function writes an array, whose elements consist +of single or multiple numbers. The function call can be replaced with +a loop containing a few +:ocv:cfunc:`WriteInt` +and +:ocv:cfunc:`WriteReal` +calls, but +a single call is more efficient. Note that because none of the elements +have a name, they should be written to a sequence rather than a map. + + +WriteReal +--------- +Writes a floating-point value. + +.. ocv:cfunction:: void cvWriteReal( CvFileStorage* fs, const char* name, double value ) + + :param fs: File storage + + :param name: Name of the written value. Should be NULL if and only if the parent structure is a sequence. + + :param value: The written value + +The function writes a single floating-point value (with or without a name) to file storage. Special values are encoded as follows: NaN (Not A Number) as .NaN, infinity as +.Inf or -.Inf. + +The following example shows how to use the low-level writing functions to store custom structures, such as termination criteria, without registering a new type. :: + + void write_termcriteria( CvFileStorage* fs, const char* struct_name, + CvTermCriteria* termcrit ) + { + cvStartWriteStruct( fs, struct_name, CV_NODE_MAP, NULL, cvAttrList(0,0)); + cvWriteComment( fs, "termination criteria", 1 ); // just a description + if( termcrit->type & CV_TERMCRIT_ITER ) + cvWriteInteger( fs, "max_iterations", termcrit->max_iter ); + if( termcrit->type & CV_TERMCRIT_EPS ) + cvWriteReal( fs, "accuracy", termcrit->epsilon ); + cvEndWriteStruct( fs ); + } + +.. + + +WriteString +----------- +Writes a text string. + +.. ocv:cfunction:: void cvWriteString( CvFileStorage* fs, const char* name, const char* str, int quote=0 ) + + :param fs: File storage + + :param name: Name of the written string . Should be NULL if and only if the parent structure is a sequence. + + :param str: The written text string + + :param quote: If non-zero, the written string is put in quotes, regardless of whether they are required. Otherwise, if the flag is zero, quotes are used only when they are required (e.g. when the string starts with a digit or contains spaces). + +The function writes a text string to file storage. diff --git a/core/doc/operations_on_arrays.rst b/core/doc/operations_on_arrays.rst new file mode 100644 index 0000000..52aa86c --- /dev/null +++ b/core/doc/operations_on_arrays.rst @@ -0,0 +1,3460 @@ +Operations on Arrays +==================== + +.. highlight:: cpp + +abs +--- +Calculates an absolute value of each matrix element. + +.. ocv:function:: MatExpr abs( const Mat& m ) +.. ocv:function:: MatExpr abs( const MatExpr& e ) + + :param m: matrix. + :param e: matrix expression. + +``abs`` is a meta-function that is expanded to one of :ocv:func:`absdiff` forms: + + * ``C = abs(A-B)`` is equivalent to ``absdiff(A, B, C)`` + + * ``C = abs(A)`` is equivalent to ``absdiff(A, Scalar::all(0), C)`` + + * ``C = Mat_ >(abs(A*alpha + beta))`` is equivalent to :ocv:funcx:`convertScaleAbs` (A, C, alpha, beta) + +The output matrix has the same size and the same type as the input one except for the last case, where ``C`` is ``depth=CV_8U`` . + + .. seealso:: :ref:`MatrixExpressions`, :ocv:func:`absdiff` + + +absdiff +------- +Calculates the per-element absolute difference between two arrays or between an array and a scalar. + +.. ocv:function:: void absdiff(InputArray src1, InputArray src2, OutputArray dst) + +.. ocv:pyfunction:: cv2.absdiff(src1, src2[, dst]) -> dst + +.. ocv:cfunction:: void cvAbsDiff(const CvArr* src1, const CvArr* src2, CvArr* dst) +.. ocv:cfunction:: void cvAbsDiffS(const CvArr* src, CvArr* dst, CvScalar value) +.. ocv:pyoldfunction:: cv.AbsDiff(src1, src2, dst)-> None +.. ocv:pyoldfunction:: cv.AbsDiffS(src, dst, value)-> None + + :param src1: first input array or a scalar. + + :param src2: second input array or a scalar. + + :param dst: output array that has the same size and type as input arrays. + +The function ``absdiff`` calculates: + + * + Absolute difference between two arrays when they have the same size and type: + + .. math:: + + \texttt{dst}(I) = \texttt{saturate} (| \texttt{src1}(I) - \texttt{src2}(I)|) + + * + Absolute difference between an array and a scalar when the second array is constructed from ``Scalar`` or has as many elements as the number of channels in ``src1``: + + .. math:: + + \texttt{dst}(I) = \texttt{saturate} (| \texttt{src1}(I) - \texttt{src2} |) + + * + Absolute difference between a scalar and an array when the first array is constructed from ``Scalar`` or has as many elements as the number of channels in ``src2``: + + .. math:: + + \texttt{dst}(I) = \texttt{saturate} (| \texttt{src1} - \texttt{src2}(I) |) + + where ``I`` is a multi-dimensional index of array elements. In case of multi-channel arrays, each channel is processed independently. + +.. note:: Saturation is not applied when the arrays have the depth ``CV_32S``. You may even get a negative value in the case of overflow. + +.. seealso:: :ocv:func:`abs` + + +add +--- + +Calculates the per-element sum of two arrays or an array and a scalar. + +.. ocv:function:: void add(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray(), int dtype=-1) + +.. ocv:pyfunction:: cv2.add(src1, src2[, dst[, mask[, dtype]]]) -> dst + +.. ocv:cfunction:: void cvAdd(const CvArr* src1, const CvArr* src2, CvArr* dst, const CvArr* mask=NULL) +.. ocv:cfunction:: void cvAddS(const CvArr* src, CvScalar value, CvArr* dst, const CvArr* mask=NULL) +.. ocv:pyoldfunction:: cv.Add(src1, src2, dst, mask=None)-> None +.. ocv:pyoldfunction:: cv.AddS(src, value, dst, mask=None)-> None + + :param src1: first input array or a scalar. + + :param src2: second input array or a scalar. + + :param dst: output array that has the same size and number of channels as the input array(s); the depth is defined by ``dtype`` or ``src1``/``src2``. + + :param mask: optional operation mask – 8-bit single channel array, that specifies elements of the output array to be changed. + + :param dtype: optional depth of the output array (see the discussion below). + +The function ``add`` calculates: + + * + Sum of two arrays when both input arrays have the same size and the same number of channels: + + .. math:: + + \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) + \texttt{src2}(I)) \quad \texttt{if mask}(I) \ne0 + + * + Sum of an array and a scalar when ``src2`` is constructed from ``Scalar`` or has the same number of elements as ``src1.channels()``: + + .. math:: + + \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) + \texttt{src2} ) \quad \texttt{if mask}(I) \ne0 + + * + Sum of a scalar and an array when ``src1`` is constructed from ``Scalar`` or has the same number of elements as ``src2.channels()``: + + .. math:: + + \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1} + \texttt{src2}(I) ) \quad \texttt{if mask}(I) \ne0 + + where ``I`` is a multi-dimensional index of array elements. In case of multi-channel arrays, each channel is processed independently. + +The first function in the list above can be replaced with matrix expressions: :: + + dst = src1 + src2; + dst += src1; // equivalent to add(dst, src1, dst); + +The input arrays and the output array can all have the same or different depths. For example, you can add a 16-bit unsigned array to a 8-bit signed array and store the sum as a 32-bit floating-point array. Depth of the output array is determined by the ``dtype`` parameter. In the second and third cases above, as well as in the first case, when ``src1.depth() == src2.depth()``, ``dtype`` can be set to the default ``-1``. In this case, the output array will have the same depth as the input array, be it ``src1``, ``src2`` or both. + +.. note:: Saturation is not applied when the output array has the depth ``CV_32S``. You may even get result of an incorrect sign in the case of overflow. + +.. seealso:: + + :ocv:func:`subtract`, + :ocv:func:`addWeighted`, + :ocv:func:`scaleAdd`, + :ocv:func:`Mat::convertTo`, + :ref:`MatrixExpressions` + + + +addWeighted +----------- +Calculates the weighted sum of two arrays. + +.. ocv:function:: void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1) + +.. ocv:pyfunction:: cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]]) -> dst + +.. ocv:cfunction:: void cvAddWeighted(const CvArr* src1, double alpha, const CvArr* src2, double beta, double gamma, CvArr* dst) +.. ocv:pyoldfunction:: cv.AddWeighted(src1, alpha, src2, beta, gamma, dst)-> None + + :param src1: first input array. + + :param alpha: weight of the first array elements. + + :param src2: second input array of the same size and channel number as ``src1``. + + :param beta: weight of the second array elements. + + :param dst: output array that has the same size and number of channels as the input arrays. + + :param gamma: scalar added to each sum. + + :param dtype: optional depth of the output array; when both input arrays have the same depth, ``dtype`` can be set to ``-1``, which will be equivalent to ``src1.depth()``. + +The function ``addWeighted`` calculates the weighted sum of two arrays as follows: + +.. math:: + + \texttt{dst} (I)= \texttt{saturate} ( \texttt{src1} (I)* \texttt{alpha} + \texttt{src2} (I)* \texttt{beta} + \texttt{gamma} ) + +where ``I`` is a multi-dimensional index of array elements. In case of multi-channel arrays, each channel is processed independently. + +The function can be replaced with a matrix expression: :: + + dst = src1*alpha + src2*beta + gamma; + +.. note:: Saturation is not applied when the output array has the depth ``CV_32S``. You may even get result of an incorrect sign in the case of overflow. + +.. seealso:: + + :ocv:func:`add`, + :ocv:func:`subtract`, + :ocv:func:`scaleAdd`, + :ocv:func:`Mat::convertTo`, + :ref:`MatrixExpressions` + + + +bitwise_and +----------- +Calculates the per-element bit-wise conjunction of two arrays or an array and a scalar. + +.. ocv:function:: void bitwise_and(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray()) + +.. ocv:pyfunction:: cv2.bitwise_and(src1, src2[, dst[, mask]]) -> dst + +.. ocv:cfunction:: void cvAnd(const CvArr* src1, const CvArr* src2, CvArr* dst, const CvArr* mask=NULL) +.. ocv:cfunction:: void cvAndS(const CvArr* src, CvScalar value, CvArr* dst, const CvArr* mask=NULL) +.. ocv:pyoldfunction:: cv.And(src1, src2, dst, mask=None)-> None +.. ocv:pyoldfunction:: cv.AndS(src, value, dst, mask=None)-> None + + :param src1: first input array or a scalar. + + :param src2: second input array or a scalar. + + :param dst: output array that has the same size and type as the input arrays. + + :param mask: optional operation mask, 8-bit single channel array, that specifies elements of the output array to be changed. + +The function calculates the per-element bit-wise logical conjunction for: + + * + Two arrays when ``src1`` and ``src2`` have the same size: + + .. math:: + + \texttt{dst} (I) = \texttt{src1} (I) \wedge \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0 + + * + An array and a scalar when ``src2`` is constructed from ``Scalar`` or has the same number of elements as ``src1.channels()``: + + .. math:: + + \texttt{dst} (I) = \texttt{src1} (I) \wedge \texttt{src2} \quad \texttt{if mask} (I) \ne0 + + * + A scalar and an array when ``src1`` is constructed from ``Scalar`` or has the same number of elements as ``src2.channels()``: + + .. math:: + + \texttt{dst} (I) = \texttt{src1} \wedge \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0 + + +In case of floating-point arrays, their machine-specific bit representations (usually IEEE754-compliant) are used for the operation. In case of multi-channel arrays, each channel is processed independently. In the second and third cases above, the scalar is first converted to the array type. + + + +bitwise_not +----------- +Inverts every bit of an array. + +.. ocv:function:: void bitwise_not(InputArray src, OutputArray dst, InputArray mask=noArray()) + +.. ocv:pyfunction:: cv2.bitwise_not(src[, dst[, mask]]) -> dst + +.. ocv:cfunction:: void cvNot(const CvArr* src, CvArr* dst) +.. ocv:pyoldfunction:: cv.Not(src, dst)-> None + + :param src: input array. + + :param dst: output array that has the same size and type as the input array. + + :param mask: optional operation mask, 8-bit single channel array, that specifies elements of the output array to be changed. + +The function calculates per-element bit-wise inversion of the input array: + +.. math:: + + \texttt{dst} (I) = \neg \texttt{src} (I) + +In case of a floating-point input array, its machine-specific bit representation (usually IEEE754-compliant) is used for the operation. In case of multi-channel arrays, each channel is processed independently. + + + +bitwise_or +---------- +Calculates the per-element bit-wise disjunction of two arrays or an array and a scalar. + +.. ocv:function:: void bitwise_or(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray()) + +.. ocv:pyfunction:: cv2.bitwise_or(src1, src2[, dst[, mask]]) -> dst + +.. ocv:cfunction:: void cvOr(const CvArr* src1, const CvArr* src2, CvArr* dst, const CvArr* mask=NULL) +.. ocv:cfunction:: void cvOrS(const CvArr* src, CvScalar value, CvArr* dst, const CvArr* mask=NULL) +.. ocv:pyoldfunction:: cv.Or(src1, src2, dst, mask=None)-> None +.. ocv:pyoldfunction:: cv.OrS(src, value, dst, mask=None)-> None + + :param src1: first input array or a scalar. + + :param src2: second input array or a scalar. + + :param dst: output array that has the same size and type as the input arrays. + + :param mask: optional operation mask, 8-bit single channel array, that specifies elements of the output array to be changed. + +The function calculates the per-element bit-wise logical disjunction for: + + * + Two arrays when ``src1`` and ``src2`` have the same size: + + .. math:: + + \texttt{dst} (I) = \texttt{src1} (I) \vee \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0 + + * + An array and a scalar when ``src2`` is constructed from ``Scalar`` or has the same number of elements as ``src1.channels()``: + + .. math:: + + \texttt{dst} (I) = \texttt{src1} (I) \vee \texttt{src2} \quad \texttt{if mask} (I) \ne0 + + * + A scalar and an array when ``src1`` is constructed from ``Scalar`` or has the same number of elements as ``src2.channels()``: + + .. math:: + + \texttt{dst} (I) = \texttt{src1} \vee \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0 + + +In case of floating-point arrays, their machine-specific bit representations (usually IEEE754-compliant) are used for the operation. In case of multi-channel arrays, each channel is processed independently. In the second and third cases above, the scalar is first converted to the array type. + + +bitwise_xor +----------- +Calculates the per-element bit-wise "exclusive or" operation on two arrays or an array and a scalar. + +.. ocv:function:: void bitwise_xor(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray()) + +.. ocv:pyfunction:: cv2.bitwise_xor(src1, src2[, dst[, mask]]) -> dst + +.. ocv:cfunction:: void cvXor(const CvArr* src1, const CvArr* src2, CvArr* dst, const CvArr* mask=NULL) +.. ocv:cfunction:: void cvXorS(const CvArr* src, CvScalar value, CvArr* dst, const CvArr* mask=NULL) +.. ocv:pyoldfunction:: cv.Xor(src1, src2, dst, mask=None)-> None +.. ocv:pyoldfunction:: cv.XorS(src, value, dst, mask=None)-> None + + :param src1: first input array or a scalar. + + :param src2: second input array or a scalar. + + :param dst: output array that has the same size and type as the input arrays. + + :param mask: optional operation mask, 8-bit single channel array, that specifies elements of the output array to be changed. + +The function calculates the per-element bit-wise logical "exclusive-or" operation for: + + * + Two arrays when ``src1`` and ``src2`` have the same size: + + .. math:: + + \texttt{dst} (I) = \texttt{src1} (I) \oplus \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0 + + * + An array and a scalar when ``src2`` is constructed from ``Scalar`` or has the same number of elements as ``src1.channels()``: + + .. math:: + + \texttt{dst} (I) = \texttt{src1} (I) \oplus \texttt{src2} \quad \texttt{if mask} (I) \ne0 + + * + A scalar and an array when ``src1`` is constructed from ``Scalar`` or has the same number of elements as ``src2.channels()``: + + .. math:: + + \texttt{dst} (I) = \texttt{src1} \oplus \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0 + + +In case of floating-point arrays, their machine-specific bit representations (usually IEEE754-compliant) are used for the operation. In case of multi-channel arrays, each channel is processed independently. In the 2nd and 3rd cases above, the scalar is first converted to the array type. + + +calcCovarMatrix +--------------- +Calculates the covariance matrix of a set of vectors. + +.. ocv:function:: void calcCovarMatrix( const Mat* samples, int nsamples, Mat& covar, Mat& mean, int flags, int ctype=CV_64F) + +.. ocv:function:: void calcCovarMatrix( InputArray samples, OutputArray covar, OutputArray mean, int flags, int ctype=CV_64F) + +.. ocv:pyfunction:: cv2.calcCovarMatrix(samples, flags[, covar[, mean[, ctype]]]) -> covar, mean + +.. ocv:cfunction:: void cvCalcCovarMatrix( const CvArr** vects, int count, CvArr* cov_mat, CvArr* avg, int flags ) + +.. ocv:pyoldfunction:: cv.CalcCovarMatrix(vects, covMat, avg, flags)-> None + + :param samples: samples stored either as separate matrices or as rows/columns of a single matrix. + + :param nsamples: number of samples when they are stored separately. + + :param covar: output covariance matrix of the type ``ctype`` and square size. + + :param mean: input or output (depending on the flags) array as the average value of the input vectors. + + :param flags: operation flags as a combination of the following values: + + * **CV_COVAR_SCRAMBLED** The output covariance matrix is calculated as: + + .. math:: + + \texttt{scale} \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...]^T \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...], + + The covariance matrix will be ``nsamples x nsamples``. Such an unusual covariance matrix is used for fast PCA of a set of very large vectors (see, for example, the EigenFaces technique for face recognition). Eigenvalues of this "scrambled" matrix match the eigenvalues of the true covariance matrix. The "true" eigenvectors can be easily calculated from the eigenvectors of the "scrambled" covariance matrix. + + * **CV_COVAR_NORMAL** The output covariance matrix is calculated as: + + .. math:: + + \texttt{scale} \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...] \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...]^T, + + ``covar`` will be a square matrix of the same size as the total number of elements in each input vector. One and only one of ``CV_COVAR_SCRAMBLED`` and ``CV_COVAR_NORMAL`` must be specified. + + * **CV_COVAR_USE_AVG** If the flag is specified, the function does not calculate ``mean`` from the input vectors but, instead, uses the passed ``mean`` vector. This is useful if ``mean`` has been pre-calculated or known in advance, or if the covariance matrix is calculated by parts. In this case, ``mean`` is not a mean vector of the input sub-set of vectors but rather the mean vector of the whole set. + + * **CV_COVAR_SCALE** If the flag is specified, the covariance matrix is scaled. In the "normal" mode, ``scale`` is ``1./nsamples`` . In the "scrambled" mode, ``scale`` is the reciprocal of the total number of elements in each input vector. By default (if the flag is not specified), the covariance matrix is not scaled ( ``scale=1`` ). + + * **CV_COVAR_ROWS** [Only useful in the second variant of the function] If the flag is specified, all the input vectors are stored as rows of the ``samples`` matrix. ``mean`` should be a single-row vector in this case. + + * **CV_COVAR_COLS** [Only useful in the second variant of the function] If the flag is specified, all the input vectors are stored as columns of the ``samples`` matrix. ``mean`` should be a single-column vector in this case. + +The functions ``calcCovarMatrix`` calculate the covariance matrix and, optionally, the mean vector of the set of input vectors. + +.. seealso:: + + :ocv:class:`PCA`, + :ocv:func:`mulTransposed`, + :ocv:func:`Mahalanobis` + + + +cartToPolar +----------- +Calculates the magnitude and angle of 2D vectors. + +.. ocv:function:: void cartToPolar(InputArray x, InputArray y, OutputArray magnitude, OutputArray angle, bool angleInDegrees=false) + +.. ocv:pyfunction:: cv2.cartToPolar(x, y[, magnitude[, angle[, angleInDegrees]]]) -> magnitude, angle + +.. ocv:cfunction:: void cvCartToPolar( const CvArr* x, const CvArr* y, CvArr* magnitude, CvArr* angle=NULL, int angle_in_degrees=0 ) + +.. ocv:pyoldfunction:: cv.CartToPolar(x, y, magnitude, angle=None, angleInDegrees=0)-> None + + :param x: array of x-coordinates; this must be a single-precision or double-precision floating-point array. + + :param y: array of y-coordinates, that must have the same size and same type as ``x``. + + :param magnitude: output array of magnitudes of the same size and type as ``x``. + + :param angle: output array of angles that has the same size and type as ``x``; the angles are measured in radians (from 0 to 2*Pi) or in degrees (0 to 360 degrees). + + :param angleInDegrees: a flag, indicating whether the angles are measured in radians (which is by default), or in degrees. + +The function ``cartToPolar`` calculates either the magnitude, angle, or both for every 2D vector (x(I),y(I)): + +.. math:: + + \begin{array}{l} \texttt{magnitude} (I)= \sqrt{\texttt{x}(I)^2+\texttt{y}(I)^2} , \\ \texttt{angle} (I)= \texttt{atan2} ( \texttt{y} (I), \texttt{x} (I))[ \cdot180 / \pi ] \end{array} + +The angles are calculated with accuracy about 0.3 degrees. For the point (0,0), the angle is set to 0. + +.. seealso:: + + :ocv:func:`Sobel`, + :ocv:func:`Scharr` + +checkRange +---------- +Checks every element of an input array for invalid values. + +.. ocv:function:: bool checkRange( InputArray a, bool quiet=true, Point* pos=0, double minVal=-DBL_MAX, double maxVal=DBL_MAX ) + +.. ocv:pyfunction:: cv2.checkRange(a[, quiet[, minVal[, maxVal]]]) -> retval, pos + + :param a: input array. + + :param quiet: a flag, indicating whether the functions quietly return false when the array elements are out of range or they throw an exception. + + :param pos: optional output parameter, where the position of the first outlier is stored; in the second function ``pos``, when not NULL, must be a pointer to array of ``src.dims`` elements. + + :param minVal: inclusive lower boundary of valid values range. + + :param maxVal: exclusive upper boundary of valid values range. + +The functions ``checkRange`` check that every array element is neither NaN nor +infinite. When ``minVal < -DBL_MAX`` and ``maxVal < DBL_MAX``, the functions also check that each value is between ``minVal`` and ``maxVal``. In case of multi-channel arrays, each channel is processed independently. +If some values are out of range, position of the first outlier is stored in ``pos`` (when +``pos != NULL``). Then, the functions either return false (when ``quiet=true``) or throw an exception. + + + +compare +------- +Performs the per-element comparison of two arrays or an array and scalar value. + +.. ocv:function:: void compare(InputArray src1, InputArray src2, OutputArray dst, int cmpop) + +.. ocv:pyfunction:: cv2.compare(src1, src2, cmpop[, dst]) -> dst + +.. ocv:cfunction:: void cvCmp( const CvArr* src1, const CvArr* src2, CvArr* dst, int cmp_op ) + +.. ocv:pyoldfunction:: cv.Cmp(src1, src2, dst, cmpOp)-> None + +.. ocv:cfunction:: void cvCmpS( const CvArr* src, double value, CvArr* dst, int cmp_op ) + +.. ocv:pyoldfunction:: cv.CmpS(src, value, dst, cmpOp)-> None + + :param src1: first input array or a scalar (in the case of ``cvCmp``, ``cv.Cmp``, ``cvCmpS``, ``cv.CmpS`` it is always an array); when it is an array, it must have a single channel. + + :param src2: second input array or a scalar (in the case of ``cvCmp`` and ``cv.Cmp`` it is always an array; in the case of ``cvCmpS``, ``cv.CmpS`` it is always a scalar); when it is an array, it must have a single channel. + + :param dst: output array that has the same size as the input arrays and type= ``CV_8UC1`` . + + :param cmpop: a flag, that specifies correspondence between the arrays: + + * **CMP_EQ** ``src1`` is equal to ``src2``. + * **CMP_GT** ``src1`` is greater than ``src2``. + * **CMP_GE** ``src1`` is greater than or equal to ``src2``. + * **CMP_LT** ``src1`` is less than ``src2``. + * **CMP_LE** ``src1`` is less than or equal to ``src2``. + * **CMP_NE** ``src1`` is unequal to ``src2``. + +The function compares: + + + * + Elements of two arrays when ``src1`` and ``src2`` have the same size: + + .. math:: + + \texttt{dst} (I) = \texttt{src1} (I) \,\texttt{cmpop}\, \texttt{src2} (I) + + * + Elements of ``src1`` with a scalar ``src2`` when ``src2`` is constructed from ``Scalar`` or has a single element: + + .. math:: + + \texttt{dst} (I) = \texttt{src1}(I) \,\texttt{cmpop}\, \texttt{src2} + + * + ``src1`` with elements of ``src2`` when ``src1`` is constructed from ``Scalar`` or has a single element: + + .. math:: + + \texttt{dst} (I) = \texttt{src1} \,\texttt{cmpop}\, \texttt{src2} (I) + + +When the comparison result is true, the corresponding element of output array is set to 255. +The comparison operations can be replaced with the equivalent matrix expressions: :: + + Mat dst1 = src1 >= src2; + Mat dst2 = src1 < 8; + ... + + +.. seealso:: + + :ocv:func:`checkRange`, + :ocv:func:`min`, + :ocv:func:`max`, + :ocv:func:`threshold`, + :ref:`MatrixExpressions` + + + +completeSymm +------------ +Copies the lower or the upper half of a square matrix to another half. + +.. ocv:function:: void completeSymm(InputOutputArray mtx, bool lowerToUpper=false) + +.. ocv:pyfunction:: cv2.completeSymm(mtx[, lowerToUpper]) -> None + + :param mtx: input-output floating-point square matrix. + + :param lowerToUpper: operation flag; if true, the lower half is copied to the upper half. Otherwise, the upper half is copied to the lower half. + +The function ``completeSymm`` copies the lower half of a square matrix to its another half. The matrix diagonal remains unchanged: + + * + :math:`\texttt{mtx}_{ij}=\texttt{mtx}_{ji}` for + :math:`i > j` if ``lowerToUpper=false`` + + * + :math:`\texttt{mtx}_{ij}=\texttt{mtx}_{ji}` for + :math:`i < j` if ``lowerToUpper=true`` + +.. seealso:: + + :ocv:func:`flip`, + :ocv:func:`transpose` + + + +convertScaleAbs +--------------- +Scales, calculates absolute values, and converts the result to 8-bit. + +.. ocv:function:: void convertScaleAbs(InputArray src, OutputArray dst, double alpha=1, double beta=0) + +.. ocv:pyfunction:: cv2.convertScaleAbs(src[, dst[, alpha[, beta]]]) -> dst + +.. ocv:cfunction:: void cvConvertScaleAbs(const CvArr* src, CvArr* dst, double scale=1, double shift=0) +.. ocv:pyoldfunction:: cv.ConvertScaleAbs(src, dst, scale=1.0, shift=0.0)-> None + + :param src: input array. + + :param dst: output array. + + :param alpha: optional scale factor. + + :param beta: optional delta added to the scaled values. + +On each element of the input array, the function ``convertScaleAbs`` performs three operations sequentially: scaling, taking an absolute value, conversion to an unsigned 8-bit type: + + +.. math:: + + \texttt{dst} (I)= \texttt{saturate\_cast} (| \texttt{src} (I)* \texttt{alpha} + \texttt{beta} |) + +In case of multi-channel arrays, the function processes each channel independently. When the output is not 8-bit, the operation can be emulated by calling the ``Mat::convertTo`` method (or by using matrix expressions) and then by calculating an absolute value of the result. For example: :: + + Mat_ A(30,30); + randu(A, Scalar(-100), Scalar(100)); + Mat_ B = A*5 + 3; + B = abs(B); + // Mat_ B = abs(A*5+3) will also do the job, + // but it will allocate a temporary matrix + + +.. seealso:: + + :ocv:func:`Mat::convertTo`, + :ocv:func:`abs` + + + +countNonZero +------------ +Counts non-zero array elements. + +.. ocv:function:: int countNonZero( InputArray src ) + +.. ocv:pyfunction:: cv2.countNonZero(src) -> retval + +.. ocv:cfunction:: int cvCountNonZero(const CvArr* arr) + +.. ocv:pyoldfunction:: cv.CountNonZero(arr)-> int + + :param src: single-channel array. + +The function returns the number of non-zero elements in ``src`` : + +.. math:: + + \sum _{I: \; \texttt{src} (I) \ne0 } 1 + +.. seealso:: + + :ocv:func:`mean`, + :ocv:func:`meanStdDev`, + :ocv:func:`norm`, + :ocv:func:`minMaxLoc`, + :ocv:func:`calcCovarMatrix` + + + +cvarrToMat +---------- +Converts ``CvMat``, ``IplImage`` , or ``CvMatND`` to ``Mat``. + +.. ocv:function:: Mat cvarrToMat( const CvArr* arr, bool copyData=false, bool allowND=true, int coiMode=0 ) + + :param arr: input ``CvMat``, ``IplImage`` , or ``CvMatND``. + + :param copyData: when false (default value), no data is copied and only the new header is created, in this case, the original array should not be deallocated while the new matrix header is used; if the parameter is true, all the data is copied and you may deallocate the original array right after the conversion. + + :param allowND: when true (default value), ``CvMatND`` is converted to 2-dimensional ``Mat``, if it is possible (see the discussion below); if it is not possible, or when the parameter is false, the function will report an error. + + :param coiMode: parameter specifying how the IplImage COI (when set) is handled. + + * If ``coiMode=0`` and COI is set, the function reports an error. + + * If ``coiMode=1`` , the function never reports an error. Instead, it returns the header to the whole original image and you will have to check and process COI manually. See :ocv:func:`extractImageCOI` . + +The function ``cvarrToMat`` converts ``CvMat``, ``IplImage`` , or ``CvMatND`` header to +:ocv:class:`Mat` header, and optionally duplicates the underlying data. The constructed header is returned by the function. + +When ``copyData=false`` , the conversion is done really fast (in O(1) time) and the newly created matrix header will have ``refcount=0`` , which means that no reference counting is done for the matrix data. In this case, you have to preserve the data until the new header is destructed. Otherwise, when ``copyData=true`` , the new buffer is allocated and managed as if you created a new matrix from scratch and copied the data there. That is, ``cvarrToMat(arr, true)`` is equivalent to ``cvarrToMat(arr, false).clone()`` (assuming that COI is not set). The function provides a uniform way of supporting +``CvArr`` paradigm in the code that is migrated to use new-style data structures internally. The reverse transformation, from +``Mat`` to +``CvMat`` or +``IplImage`` can be done by a simple assignment: :: + + CvMat* A = cvCreateMat(10, 10, CV_32F); + cvSetIdentity(A); + IplImage A1; cvGetImage(A, &A1); + Mat B = cvarrToMat(A); + Mat B1 = cvarrToMat(&A1); + IplImage C = B; + CvMat C1 = B1; + // now A, A1, B, B1, C and C1 are different headers + // for the same 10x10 floating-point array. + // note that you will need to use "&" + // to pass C & C1 to OpenCV functions, for example: + printf("%g\n", cvNorm(&C1, 0, CV_L2)); + +Normally, the function is used to convert an old-style 2D array ( +``CvMat`` or +``IplImage`` ) to ``Mat`` . However, the function can also take +``CvMatND`` as an input and create +:ocv:func:`Mat` for it, if it is possible. And, for ``CvMatND A`` , it is possible if and only if ``A.dim[i].size*A.dim.step[i] == A.dim.step[i-1]`` for all or for all but one ``i, 0 < i < A.dims`` . That is, the matrix data should be continuous or it should be representable as a sequence of continuous matrices. By using this function in this way, you can process +``CvMatND`` using an arbitrary element-wise function. + +The last parameter, ``coiMode`` , specifies how to deal with an image with COI set. By default, it is 0 and the function reports an error when an image with COI comes in. And ``coiMode=1`` means that no error is signalled. You have to check COI presence and handle it manually. The modern structures, such as +:ocv:class:`Mat` and +``MatND`` do not support COI natively. To process an individual channel of a new-style array, you need either to organize a loop over the array (for example, using matrix iterators) where the channel of interest will be processed, or extract the COI using +:ocv:func:`mixChannels` (for new-style arrays) or +:ocv:func:`extractImageCOI` (for old-style arrays), process this individual channel, and insert it back to the output array if needed (using +:ocv:func:`mixChannels` or +:ocv:func:`insertImageCOI` , respectively). + +.. seealso:: + + :ocv:cfunc:`cvGetImage`, + :ocv:cfunc:`cvGetMat`, + :ocv:func:`extractImageCOI`, + :ocv:func:`insertImageCOI`, + :ocv:func:`mixChannels` + +dct +--- +Performs a forward or inverse discrete Cosine transform of 1D or 2D array. + +.. ocv:function:: void dct(InputArray src, OutputArray dst, int flags=0) + +.. ocv:pyfunction:: cv2.dct(src[, dst[, flags]]) -> dst + +.. ocv:cfunction:: void cvDCT(const CvArr* src, CvArr* dst, int flags) +.. ocv:pyoldfunction:: cv.DCT(src, dst, flags)-> None + + :param src: input floating-point array. + + :param dst: output array of the same size and type as ``src`` . + + :param flags: transformation flags as a combination of the following values: + + * **DCT_INVERSE** performs an inverse 1D or 2D transform instead of the default forward transform. + + * **DCT_ROWS** performs a forward or inverse transform of every individual row of the input matrix. This flag enables you to transform multiple vectors simultaneously and can be used to decrease the overhead (which is sometimes several times larger than the processing itself) to perform 3D and higher-dimensional transforms and so forth. + +The function ``dct`` performs a forward or inverse discrete Cosine transform (DCT) of a 1D or 2D floating-point array: + +* + Forward Cosine transform of a 1D vector of ``N`` elements: + + .. math:: + + Y = C^{(N)} \cdot X + + where + + .. math:: + + C^{(N)}_{jk}= \sqrt{\alpha_j/N} \cos \left ( \frac{\pi(2k+1)j}{2N} \right ) + + and + + :math:`\alpha_0=1`, :math:`\alpha_j=2` for *j > 0*. + +* + Inverse Cosine transform of a 1D vector of ``N`` elements: + + .. math:: + + X = \left (C^{(N)} \right )^{-1} \cdot Y = \left (C^{(N)} \right )^T \cdot Y + + (since + :math:`C^{(N)}` is an orthogonal matrix, + :math:`C^{(N)} \cdot \left(C^{(N)}\right)^T = I` ) + +* + Forward 2D Cosine transform of ``M x N`` matrix: + + .. math:: + + Y = C^{(N)} \cdot X \cdot \left (C^{(N)} \right )^T + +* + Inverse 2D Cosine transform of ``M x N`` matrix: + + .. math:: + + X = \left (C^{(N)} \right )^T \cdot X \cdot C^{(N)} + + +The function chooses the mode of operation by looking at the flags and size of the input array: + +* + If ``(flags & DCT_INVERSE) == 0`` , the function does a forward 1D or 2D transform. Otherwise, it is an inverse 1D or 2D transform. + +* + If ``(flags & DCT_ROWS) != 0`` , the function performs a 1D transform of each row. + +* + If the array is a single column or a single row, the function performs a 1D transform. + +* + If none of the above is true, the function performs a 2D transform. + +.. note:: + + Currently ``dct`` supports even-size arrays (2, 4, 6 ...). For data analysis and approximation, you can pad the array when necessary. + + Also, the function performance depends very much, and not monotonically, on the array size (see + :ocv:func:`getOptimalDFTSize` ). In the current implementation DCT of a vector of size ``N`` is calculated via DFT of a vector of size ``N/2`` . Thus, the optimal DCT size ``N1 >= N`` can be calculated as: :: + + size_t getOptimalDCTSize(size_t N) { return 2*getOptimalDFTSize((N+1)/2); } + N1 = getOptimalDCTSize(N); + +.. seealso:: :ocv:func:`dft` , :ocv:func:`getOptimalDFTSize` , :ocv:func:`idct` + + + +dft +--- +Performs a forward or inverse Discrete Fourier transform of a 1D or 2D floating-point array. + +.. ocv:function:: void dft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0) + +.. ocv:pyfunction:: cv2.dft(src[, dst[, flags[, nonzeroRows]]]) -> dst + +.. ocv:cfunction:: void cvDFT( const CvArr* src, CvArr* dst, int flags, int nonzero_rows=0 ) + +.. ocv:pyoldfunction:: cv.DFT(src, dst, flags, nonzeroRows=0)-> None + + :param src: input array that could be real or complex. + + :param dst: output array whose size and type depends on the ``flags`` . + + :param flags: transformation flags, representing a combination of the following values: + + * **DFT_INVERSE** performs an inverse 1D or 2D transform instead of the default forward transform. + + * **DFT_SCALE** scales the result: divide it by the number of array elements. Normally, it is combined with ``DFT_INVERSE``. + * **DFT_ROWS** performs a forward or inverse transform of every individual row of the input matrix; this flag enables you to transform multiple vectors simultaneously and can be used to decrease the overhead (which is sometimes several times larger than the processing itself) to perform 3D and higher-dimensional transformations and so forth. + + * **DFT_COMPLEX_OUTPUT** performs a forward transformation of 1D or 2D real array; the result, though being a complex array, has complex-conjugate symmetry (*CCS*, see the function description below for details), and such an array can be packed into a real array of the same size as input, which is the fastest option and which is what the function does by default; however, you may wish to get a full complex array (for simpler spectrum analysis, and so on) – pass the flag to enable the function to produce a full-size complex output array. + + * **DFT_REAL_OUTPUT** performs an inverse transformation of a 1D or 2D complex array; the result is normally a complex array of the same size, however, if the input array has conjugate-complex symmetry (for example, it is a result of forward transformation with ``DFT_COMPLEX_OUTPUT`` flag), the output is a real array; while the function itself does not check whether the input is symmetrical or not, you can pass the flag and then the function will assume the symmetry and produce the real output array (note that when the input is packed into a real array and inverse transformation is executed, the function treats the input as a packed complex-conjugate symmetrical array, and the output will also be a real array). + + :param nonzeroRows: when the parameter is not zero, the function assumes that only the first ``nonzeroRows`` rows of the input array (``DFT_INVERSE`` is not set) or only the first ``nonzeroRows`` of the output array (``DFT_INVERSE`` is set) contain non-zeros, thus, the function can handle the rest of the rows more efficiently and save some time; this technique is very useful for calculating array cross-correlation or convolution using DFT. + + +The function performs one of the following: + +* + Forward the Fourier transform of a 1D vector of ``N`` elements: + + .. math:: + + Y = F^{(N)} \cdot X, + + where + :math:`F^{(N)}_{jk}=\exp(-2\pi i j k/N)` and + :math:`i=\sqrt{-1}` + +* + Inverse the Fourier transform of a 1D vector of ``N`` elements: + + .. math:: + + \begin{array}{l} X'= \left (F^{(N)} \right )^{-1} \cdot Y = \left (F^{(N)} \right )^* \cdot y \\ X = (1/N) \cdot X, \end{array} + + where + :math:`F^*=\left(\textrm{Re}(F^{(N)})-\textrm{Im}(F^{(N)})\right)^T` + +* + Forward the 2D Fourier transform of a ``M x N`` matrix: + + .. math:: + + Y = F^{(M)} \cdot X \cdot F^{(N)} + +* + Inverse the 2D Fourier transform of a ``M x N`` matrix: + + .. math:: + + \begin{array}{l} X'= \left (F^{(M)} \right )^* \cdot Y \cdot \left (F^{(N)} \right )^* \\ X = \frac{1}{M \cdot N} \cdot X' \end{array} + + +In case of real (single-channel) data, the output spectrum of the forward Fourier transform or input spectrum of the inverse Fourier transform can be represented in a packed format called *CCS* (complex-conjugate-symmetrical). It was borrowed from IPL (Intel* Image Processing Library). Here is how 2D *CCS* spectrum looks: + +.. math:: + + \begin{bmatrix} Re Y_{0,0} & Re Y_{0,1} & Im Y_{0,1} & Re Y_{0,2} & Im Y_{0,2} & \cdots & Re Y_{0,N/2-1} & Im Y_{0,N/2-1} & Re Y_{0,N/2} \\ Re Y_{1,0} & Re Y_{1,1} & Im Y_{1,1} & Re Y_{1,2} & Im Y_{1,2} & \cdots & Re Y_{1,N/2-1} & Im Y_{1,N/2-1} & Re Y_{1,N/2} \\ Im Y_{1,0} & Re Y_{2,1} & Im Y_{2,1} & Re Y_{2,2} & Im Y_{2,2} & \cdots & Re Y_{2,N/2-1} & Im Y_{2,N/2-1} & Im Y_{1,N/2} \\ \hdotsfor{9} \\ Re Y_{M/2-1,0} & Re Y_{M-3,1} & Im Y_{M-3,1} & \hdotsfor{3} & Re Y_{M-3,N/2-1} & Im Y_{M-3,N/2-1}& Re Y_{M/2-1,N/2} \\ Im Y_{M/2-1,0} & Re Y_{M-2,1} & Im Y_{M-2,1} & \hdotsfor{3} & Re Y_{M-2,N/2-1} & Im Y_{M-2,N/2-1}& Im Y_{M/2-1,N/2} \\ Re Y_{M/2,0} & Re Y_{M-1,1} & Im Y_{M-1,1} & \hdotsfor{3} & Re Y_{M-1,N/2-1} & Im Y_{M-1,N/2-1}& Re Y_{M/2,N/2} \end{bmatrix} + +In case of 1D transform of a real vector, the output looks like the first row of the matrix above. + +So, the function chooses an operation mode depending on the flags and size of the input array: + + * If ``DFT_ROWS`` is set or the input array has a single row or single column, the function performs a 1D forward or inverse transform of each row of a matrix when ``DFT_ROWS`` is set. Otherwise, it performs a 2D transform. + + * If the input array is real and ``DFT_INVERSE`` is not set, the function performs a forward 1D or 2D transform: + + * When ``DFT_COMPLEX_OUTPUT`` is set, the output is a complex matrix of the same size as input. + + * When ``DFT_COMPLEX_OUTPUT`` is not set, the output is a real matrix of the same size as input. In case of 2D transform, it uses the packed format as shown above. In case of a single 1D transform, it looks like the first row of the matrix above. In case of multiple 1D transforms (when using the ``DCT_ROWS`` flag), each row of the output matrix looks like the first row of the matrix above. + + * If the input array is complex and either ``DFT_INVERSE`` or ``DFT_REAL_OUTPUT`` are not set, the output is a complex array of the same size as input. The function performs a forward or inverse 1D or 2D transform of the whole input array or each row of the input array independently, depending on the flags ``DFT_INVERSE`` and ``DFT_ROWS``. + + * When ``DFT_INVERSE`` is set and the input array is real, or it is complex but ``DFT_REAL_OUTPUT`` is set, the output is a real array of the same size as input. The function performs a 1D or 2D inverse transformation of the whole input array or each individual row, depending on the flags ``DFT_INVERSE`` and ``DFT_ROWS``. + +If ``DFT_SCALE`` is set, the scaling is done after the transformation. + +Unlike :ocv:func:`dct` , the function supports arrays of arbitrary size. But only those arrays are processed efficiently, whose sizes can be factorized in a product of small prime numbers (2, 3, and 5 in the current implementation). Such an efficient DFT size can be calculated using the :ocv:func:`getOptimalDFTSize` method. + +The sample below illustrates how to calculate a DFT-based convolution of two 2D real arrays: :: + + void convolveDFT(InputArray A, InputArray B, OutputArray C) + { + // reallocate the output array if needed + C.create(abs(A.rows - B.rows)+1, abs(A.cols - B.cols)+1, A.type()); + Size dftSize; + // calculate the size of DFT transform + dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1); + dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1); + + // allocate temporary buffers and initialize them with 0's + Mat tempA(dftSize, A.type(), Scalar::all(0)); + Mat tempB(dftSize, B.type(), Scalar::all(0)); + + // copy A and B to the top-left corners of tempA and tempB, respectively + Mat roiA(tempA, Rect(0,0,A.cols,A.rows)); + A.copyTo(roiA); + Mat roiB(tempB, Rect(0,0,B.cols,B.rows)); + B.copyTo(roiB); + + // now transform the padded A & B in-place; + // use "nonzeroRows" hint for faster processing + dft(tempA, tempA, 0, A.rows); + dft(tempB, tempB, 0, B.rows); + + // multiply the spectrums; + // the function handles packed spectrum representations well + mulSpectrums(tempA, tempB, tempA); + + // transform the product back from the frequency domain. + // Even though all the result rows will be non-zero, + // you need only the first C.rows of them, and thus you + // pass nonzeroRows == C.rows + dft(tempA, tempA, DFT_INVERSE + DFT_SCALE, C.rows); + + // now copy the result back to C. + tempA(Rect(0, 0, C.cols, C.rows)).copyTo(C); + + // all the temporary buffers will be deallocated automatically + } + + +To optimize this sample, consider the following approaches: + +* + Since ``nonzeroRows != 0`` is passed to the forward transform calls and since ``A`` and ``B`` are copied to the top-left corners of ``tempA`` and ``tempB``, respectively, it is not necessary to clear the whole ``tempA`` and ``tempB``. It is only necessary to clear the ``tempA.cols - A.cols`` ( ``tempB.cols - B.cols``) rightmost columns of the matrices. + +* + This DFT-based convolution does not have to be applied to the whole big arrays, especially if ``B`` is significantly smaller than ``A`` or vice versa. Instead, you can calculate convolution by parts. To do this, you need to split the output array ``C`` into multiple tiles. For each tile, estimate which parts of ``A`` and ``B`` are required to calculate convolution in this tile. If the tiles in ``C`` are too small, the speed will decrease a lot because of repeated work. In the ultimate case, when each tile in ``C`` is a single pixel, the algorithm becomes equivalent to the naive convolution algorithm. If the tiles are too big, the temporary arrays ``tempA`` and ``tempB`` become too big and there is also a slowdown because of bad cache locality. So, there is an optimal tile size somewhere in the middle. + +* + If different tiles in ``C`` can be calculated in parallel and, thus, the convolution is done by parts, the loop can be threaded. + +All of the above improvements have been implemented in :ocv:func:`matchTemplate` and :ocv:func:`filter2D` . Therefore, by using them, you can get the performance even better than with the above theoretically optimal implementation. Though, those two functions actually calculate cross-correlation, not convolution, so you need to "flip" the second convolution operand ``B`` vertically and horizontally using :ocv:func:`flip` . + +.. seealso:: :ocv:func:`dct` , :ocv:func:`getOptimalDFTSize` , :ocv:func:`mulSpectrums`, :ocv:func:`filter2D` , :ocv:func:`matchTemplate` , :ocv:func:`flip` , :ocv:func:`cartToPolar` , :ocv:func:`magnitude` , :ocv:func:`phase` + + + +divide +---------- +Performs per-element division of two arrays or a scalar by an array. + +.. ocv:function:: void divide(InputArray src1, InputArray src2, OutputArray dst, double scale=1, int dtype=-1) + +.. ocv:function:: void divide(double scale, InputArray src2, OutputArray dst, int dtype=-1) + +.. ocv:pyfunction:: cv2.divide(src1, src2[, dst[, scale[, dtype]]]) -> dst +.. ocv:pyfunction:: cv2.divide(scale, src2[, dst[, dtype]]) -> dst + +.. ocv:cfunction:: void cvDiv(const CvArr* src1, const CvArr* src2, CvArr* dst, double scale=1) +.. ocv:pyoldfunction:: cv.Div(src1, src2, dst, scale=1) -> None + + :param src1: first input array. + + :param src2: second input array of the same size and type as ``src1``. + + :param scale: scalar factor. + + :param dst: output array of the same size and type as ``src2``. + + :param dtype: optional depth of the output array; if ``-1``, ``dst`` will have depth ``src2.depth()``, but in case of an array-by-array division, you can only pass ``-1`` when ``src1.depth()==src2.depth()``. + +The functions ``divide`` divide one array by another: + +.. math:: + + \texttt{dst(I) = saturate(src1(I)*scale/src2(I))} + +or a scalar by an array when there is no ``src1`` : + +.. math:: + + \texttt{dst(I) = saturate(scale/src2(I))} + +When ``src2(I)`` is zero, ``dst(I)`` will also be zero. Different channels of multi-channel arrays are processed independently. + +.. note:: Saturation is not applied when the output array has the depth ``CV_32S``. You may even get result of an incorrect sign in the case of overflow. + +.. seealso:: + + :ocv:func:`multiply`, + :ocv:func:`add`, + :ocv:func:`subtract`, + :ref:`MatrixExpressions` + + + +determinant +----------- +Returns the determinant of a square floating-point matrix. + +.. ocv:function:: double determinant(InputArray mtx) + +.. ocv:pyfunction:: cv2.determinant(mtx) -> retval + +.. ocv:cfunction:: double cvDet( const CvArr* mat ) + +.. ocv:pyoldfunction:: cv.Det(mat) -> float + + :param mtx: input matrix that must have ``CV_32FC1`` or ``CV_64FC1`` type and square size. + +The function ``determinant`` calculates and returns the determinant of the specified matrix. For small matrices ( ``mtx.cols=mtx.rows<=3`` ), +the direct method is used. For larger matrices, the function uses LU factorization with partial pivoting. + +For symmetric positively-determined matrices, it is also possible to use :ocv:func:`eigen` decomposition to calculate the determinant. + +.. seealso:: + + :ocv:func:`trace`, + :ocv:func:`invert`, + :ocv:func:`solve`, + :ocv:func:`eigen`, + :ref:`MatrixExpressions` + + + +eigen +----- +Calculates eigenvalues and eigenvectors of a symmetric matrix. + +.. ocv:function:: bool eigen(InputArray src, OutputArray eigenvalues, int lowindex=-1, int highindex=-1) + +.. ocv:function:: bool eigen(InputArray src, OutputArray eigenvalues, OutputArray eigenvectors, int lowindex=-1,int highindex=-1) + +.. ocv:pyfunction:: cv2.eigen(src, calculateEigenvectors[, eigenvalues[, eigenvectors]]) -> retval, eigenvalues, eigenvectors + +.. ocv:cfunction:: void cvEigenVV( CvArr* mat, CvArr* evects, CvArr* evals, double eps=0, int lowindex=-1, int highindex=-1 ) + +.. ocv:pyoldfunction:: cv.EigenVV(mat, evects, evals, eps, lowindex=-1, highindex=-1)-> None + + :param src: input matrix that must have ``CV_32FC1`` or ``CV_64FC1`` type, square size and be symmetrical (``src`` :sup:`T` == ``src``). + + :param eigenvalues: output vector of eigenvalues of the same type as ``src``; the eigenvalues are stored in the descending order. + + :param eigenvectors: output matrix of eigenvectors; it has the same size and type as ``src``; the eigenvectors are stored as subsequent matrix rows, in the same order as the corresponding eigenvalues. + + :param lowindex: optional index of largest eigenvalue/-vector to calculate; the parameter is ignored in the current implementation. + + :param highindex: optional index of smallest eigenvalue/-vector to calculate; the parameter is ignored in the current implementation. + +The functions ``eigen`` calculate just eigenvalues, or eigenvalues and eigenvectors of the symmetric matrix ``src`` : :: + + src*eigenvectors.row(i).t() = eigenvalues.at(i)*eigenvectors.row(i).t() + +.. note:: in the new and the old interfaces different ordering of eigenvalues and eigenvectors parameters is used. + +.. seealso:: :ocv:func:`completeSymm` , :ocv:class:`PCA` + + + +exp +--- +Calculates the exponent of every array element. + +.. ocv:function:: void exp(InputArray src, OutputArray dst) + +.. ocv:pyfunction:: cv2.exp(src[, dst]) -> dst + +.. ocv:cfunction:: void cvExp(const CvArr* src, CvArr* dst) +.. ocv:pyoldfunction:: cv.Exp(src, dst)-> None + + :param src: input array. + + :param dst: output array of the same size and type as ``src``. + +The function ``exp`` calculates the exponent of every element of the input array: + +.. math:: + + \texttt{dst} [I] = e^{ src(I) } + +The maximum relative error is about ``7e-6`` for single-precision input and less than ``1e-10`` for double-precision input. Currently, the function converts denormalized values to zeros on output. Special values (NaN, Inf) are not handled. + +.. seealso:: :ocv:func:`log` , :ocv:func:`cartToPolar` , :ocv:func:`polarToCart` , :ocv:func:`phase` , :ocv:func:`pow` , :ocv:func:`sqrt` , :ocv:func:`magnitude` + + + +extractImageCOI +--------------- +Extracts the selected image channel. + +.. ocv:function:: void extractImageCOI( const CvArr* arr, OutputArray coiimg, int coi=-1 ) + + :param arr: input array; it should be a pointer to ``CvMat`` or ``IplImage``. + + :param coiimg: output array with a single channel and the same size and depth as ``arr``. + + :param coi: if the parameter is ``>=0``, it specifies the channel to extract, if it is ``<0`` and ``arr`` is a pointer to ``IplImage`` with a valid COI set, the selected COI is extracted. + +The function ``extractImageCOI`` is used to extract an image COI from an old-style array and put the result to the new-style C++ matrix. As usual, the output matrix is reallocated using ``Mat::create`` if needed. + +To extract a channel from a new-style matrix, use +:ocv:func:`mixChannels` or +:ocv:func:`split` . + +.. seealso:: :ocv:func:`mixChannels` , :ocv:func:`split` , :ocv:func:`merge` , :ocv:func:`cvarrToMat` , :ocv:cfunc:`cvSetImageCOI` , :ocv:cfunc:`cvGetImageCOI` + + +insertImageCOI +--------------- +Copies the selected image channel from a new-style C++ matrix to the old-style C array. + +.. ocv:function:: void insertImageCOI( InputArray coiimg, CvArr* arr, int coi=-1 ) + + :param coiimg: input array with a single channel and the same size and depth as ``arr``. + + :param arr: output array, it should be a pointer to ``CvMat`` or ``IplImage``. + + :param coi: if the parameter is ``>=0``, it specifies the channel to insert, if it is ``<0`` and ``arr`` is a pointer to ``IplImage`` with a valid COI set, the selected COI is extracted. + +The function ``insertImageCOI`` is used to extract an image COI from a new-style C++ matrix and put the result to the old-style array. + +The sample below illustrates how to use the function: +:: + + Mat temp(240, 320, CV_8UC1, Scalar(255)); + IplImage* img = cvCreateImage(cvSize(320,240), IPL_DEPTH_8U, 3); + insertImageCOI(temp, img, 1); //insert to the first channel + cvNamedWindow("window",1); + cvShowImage("window", img); //you should see green image, because channel number 1 is green (BGR) + cvWaitKey(0); + cvDestroyAllWindows(); + cvReleaseImage(&img); + +To insert a channel to a new-style matrix, use +:ocv:func:`merge` . + +.. seealso:: :ocv:func:`mixChannels` , :ocv:func:`split` , :ocv:func:`merge` , :ocv:func:`cvarrToMat` , :ocv:cfunc:`cvSetImageCOI` , :ocv:cfunc:`cvGetImageCOI` + + +flip +-------- +Flips a 2D array around vertical, horizontal, or both axes. + +.. ocv:function:: void flip(InputArray src, OutputArray dst, int flipCode) + +.. ocv:pyfunction:: cv2.flip(src, flipCode[, dst]) -> dst + +.. ocv:cfunction:: void cvFlip( const CvArr* src, CvArr* dst=NULL, int flip_mode=0 ) + +.. ocv:pyoldfunction:: cv.Flip(src, dst=None, flipMode=0)-> None + + :param src: input array. + + :param dst: output array of the same size and type as ``src``. + + :param flipCode: a flag to specify how to flip the array; 0 means flipping around the x-axis and positive value (for example, 1) means flipping around y-axis. Negative value (for example, -1) means flipping around both axes (see the discussion below for the formulas). + +The function ``flip`` flips the array in one of three different ways (row and column indices are 0-based): + +.. math:: + + \texttt{dst} _{ij} = + \left\{ + \begin{array}{l l} + \texttt{src} _{\texttt{src.rows}-i-1,j} & if\; \texttt{flipCode} = 0 \\ + \texttt{src} _{i, \texttt{src.cols} -j-1} & if\; \texttt{flipCode} > 0 \\ + \texttt{src} _{ \texttt{src.rows} -i-1, \texttt{src.cols} -j-1} & if\; \texttt{flipCode} < 0 \\ + \end{array} + \right. + +The example scenarios of using the function are the following: + + * + Vertical flipping of the image (``flipCode == 0``) to switch between top-left and bottom-left image origin. This is a typical operation in video processing on Microsoft Windows* OS. + + * + Horizontal flipping of the image with the subsequent horizontal shift and absolute difference calculation to check for a vertical-axis symmetry (``flipCode > 0``). + + * + Simultaneous horizontal and vertical flipping of the image with the subsequent shift and absolute difference calculation to check for a central symmetry (``flipCode < 0``). + + * + Reversing the order of point arrays (``flipCode > 0`` or ``flipCode == 0``). + +.. seealso:: :ocv:func:`transpose` , :ocv:func:`repeat` , :ocv:func:`completeSymm` + + + +gemm +---- +Performs generalized matrix multiplication. + +.. ocv:function:: void gemm( InputArray src1, InputArray src2, double alpha, InputArray src3, double gamma, OutputArray dst, int flags=0 ) + +.. ocv:pyfunction:: cv2.gemm(src1, src2, alpha, src3, gamma[, dst[, flags]]) -> dst + +.. ocv:cfunction:: void cvGEMM( const CvArr* src1, const CvArr* src2, double alpha, const CvArr* src3, double beta, CvArr* dst, int tABC=0) +.. ocv:pyoldfunction:: cv.GEMM(src1, src2, alpha, src3, beta, dst, tABC=0)-> None + + :param src1: first multiplied input matrix that should have ``CV_32FC1``, ``CV_64FC1``, ``CV_32FC2``, or ``CV_64FC2`` type. + + :param src2: second multiplied input matrix of the same type as ``src1``. + + :param alpha: weight of the matrix product. + + :param src3: third optional delta matrix added to the matrix product; it should have the same type as ``src1`` and ``src2``. + + :param beta: weight of ``src3``. + + :param dst: output matrix; it has the proper size and the same type as input matrices. + + :param flags: operation flags: + + * **GEMM_1_T** transposes ``src1``. + * **GEMM_2_T** transposes ``src2``. + * **GEMM_3_T** transposes ``src3``. + +The function performs generalized matrix multiplication similar to the ``gemm`` functions in BLAS level 3. For example, ``gemm(src1, src2, alpha, src3, beta, dst, GEMM_1_T + GEMM_3_T)`` corresponds to + +.. math:: + + \texttt{dst} = \texttt{alpha} \cdot \texttt{src1} ^T \cdot \texttt{src2} + \texttt{beta} \cdot \texttt{src3} ^T + +The function can be replaced with a matrix expression. For example, the above call can be replaced with: :: + + dst = alpha*src1.t()*src2 + beta*src3.t(); + + +.. seealso:: :ocv:func:`mulTransposed` , :ocv:func:`transform` , :ref:`MatrixExpressions` + + + +getConvertElem +-------------- +Returns a conversion function for a single pixel. + +.. ocv:function:: ConvertData getConvertElem(int fromType, int toType) + +.. ocv:function:: ConvertScaleData getConvertScaleElem(int fromType, int toType) + + :param fromType: input pixel type. + + :param toType: output pixel type. + + :param from: callback parameter: pointer to the input pixel. + + :param to: callback parameter: pointer to the output pixel + + :param cn: callback parameter: the number of channels; it can be arbitrary, 1, 100, 100000, etc. + + :param alpha: ``ConvertScaleData`` callback optional parameter: the scale factor. + + :param beta: ``ConvertScaleData`` callback optional parameter: the delta or offset. + +The functions ``getConvertElem`` and ``getConvertScaleElem`` return pointers to the functions for converting individual pixels from one type to another. While the main function purpose is to convert single pixels (actually, for converting sparse matrices from one type to another), you can use them to convert the whole row of a dense matrix or the whole matrix at once, by setting ``cn = matrix.cols*matrix.rows*matrix.channels()`` if the matrix data is continuous. + +``ConvertData`` and ``ConvertScaleData`` are defined as: :: + + typedef void (*ConvertData)(const void* from, void* to, int cn) + typedef void (*ConvertScaleData)(const void* from, void* to, + int cn, double alpha, double beta) + +.. seealso:: :ocv:func:`Mat::convertTo` , :ocv:func:`SparseMat::convertTo` + + + +getOptimalDFTSize +----------------- +Returns the optimal DFT size for a given vector size. + +.. ocv:function:: int getOptimalDFTSize(int vecsize) + +.. ocv:pyfunction:: cv2.getOptimalDFTSize(vecsize) -> retval + +.. ocv:cfunction:: int cvGetOptimalDFTSize(int size0) +.. ocv:pyoldfunction:: cv.GetOptimalDFTSize(size0)-> int + + :param vecsize: vector size. + +DFT performance is not a monotonic function of a vector size. Therefore, when you calculate convolution of two arrays or perform the spectral analysis of an array, it usually makes sense to pad the input data with zeros to get a bit larger array that can be transformed much faster than the original one. +Arrays whose size is a power-of-two (2, 4, 8, 16, 32, ...) are the fastest to process. Though, the arrays whose size is a product of 2's, 3's, and 5's (for example, 300 = 5*5*3*2*2) are also processed quite efficiently. + +The function ``getOptimalDFTSize`` returns the minimum number ``N`` that is greater than or equal to ``vecsize`` so that the DFT of a vector of size ``N`` can be processed efficiently. In the current implementation ``N`` = 2 :sup:`p` * 3 :sup:`q` * 5 :sup:`r` for some integer ``p``, ``q``, ``r``. + +The function returns a negative number if ``vecsize`` is too large (very close to ``INT_MAX`` ). + +While the function cannot be used directly to estimate the optimal vector size for DCT transform (since the current DCT implementation supports only even-size vectors), it can be easily processed as ``getOptimalDFTSize((vecsize+1)/2)*2``. + +.. seealso:: :ocv:func:`dft` , :ocv:func:`dct` , :ocv:func:`idft` , :ocv:func:`idct` , :ocv:func:`mulSpectrums` + + + +idct +---- +Calculates the inverse Discrete Cosine Transform of a 1D or 2D array. + +.. ocv:function:: void idct(InputArray src, OutputArray dst, int flags=0) + +.. ocv:pyfunction:: cv2.idct(src[, dst[, flags]]) -> dst + + :param src: input floating-point single-channel array. + + :param dst: output array of the same size and type as ``src``. + + :param flags: operation flags. + +``idct(src, dst, flags)`` is equivalent to ``dct(src, dst, flags | DCT_INVERSE)``. + +.. seealso:: + + :ocv:func:`dct`, + :ocv:func:`dft`, + :ocv:func:`idft`, + :ocv:func:`getOptimalDFTSize` + + + +idft +---- +Calculates the inverse Discrete Fourier Transform of a 1D or 2D array. + +.. ocv:function:: void idft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0) + +.. ocv:pyfunction:: cv2.idft(src[, dst[, flags[, nonzeroRows]]]) -> dst + + :param src: input floating-point real or complex array. + + :param dst: output array whose size and type depend on the ``flags``. + + :param flags: operation flags (see :ocv:func:`dft`). + + :param nonzeroRows: number of ``dst`` rows to process; the rest of the rows have undefined content (see the convolution sample in :ocv:func:`dft` description. + +``idft(src, dst, flags)`` is equivalent to ``dft(src, dst, flags | DFT_INVERSE)`` . + +See :ocv:func:`dft` for details. + +.. note:: None of ``dft`` and ``idft`` scales the result by default. So, you should pass ``DFT_SCALE`` to one of ``dft`` or ``idft`` explicitly to make these transforms mutually inverse. + +.. seealso:: + + :ocv:func:`dft`, + :ocv:func:`dct`, + :ocv:func:`idct`, + :ocv:func:`mulSpectrums`, + :ocv:func:`getOptimalDFTSize` + + + +inRange +------- +Checks if array elements lie between the elements of two other arrays. + +.. ocv:function:: void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst) + +.. ocv:pyfunction:: cv2.inRange(src, lowerb, upperb[, dst]) -> dst + +.. ocv:cfunction:: void cvInRange(const CvArr* src, const CvArr* lower, const CvArr* upper, CvArr* dst) +.. ocv:cfunction:: void cvInRangeS(const CvArr* src, CvScalar lower, CvScalar upper, CvArr* dst) +.. ocv:pyoldfunction:: cv.InRange(src, lower, upper, dst)-> None +.. ocv:pyoldfunction:: cv.InRangeS(src, lower, upper, dst)-> None + + :param src: first input array. + + :param lowerb: inclusive lower boundary array or a scalar. + + :param upperb: inclusive upper boundary array or a scalar. + + :param dst: output array of the same size as ``src`` and ``CV_8U`` type. + +The function checks the range as follows: + + * For every element of a single-channel input array: + + .. math:: + + \texttt{dst} (I)= \texttt{lowerb} (I)_0 \leq \texttt{src} (I)_0 \leq \texttt{upperb} (I)_0 + + * For two-channel arrays: + + .. math:: + + \texttt{dst} (I)= \texttt{lowerb} (I)_0 \leq \texttt{src} (I)_0 \leq \texttt{upperb} (I)_0 \land \texttt{lowerb} (I)_1 \leq \texttt{src} (I)_1 \leq \texttt{upperb} (I)_1 + + * and so forth. + +That is, ``dst`` (I) is set to 255 (all ``1`` -bits) if ``src`` (I) is within the specified 1D, 2D, 3D, ... box and 0 otherwise. + +When the lower and/or upper boundary parameters are scalars, the indexes ``(I)`` at ``lowerb`` and ``upperb`` in the above formulas should be omitted. + + +invert +------ +Finds the inverse or pseudo-inverse of a matrix. + +.. ocv:function:: double invert(InputArray src, OutputArray dst, int flags=DECOMP_LU) + +.. ocv:pyfunction:: cv2.invert(src[, dst[, flags]]) -> retval, dst + +.. ocv:cfunction:: double cvInvert( const CvArr* src, CvArr* dst, int method=CV_LU ) + +.. ocv:pyoldfunction:: cv.Invert(src, dst, method=CV_LU) -> float + + :param src: input floating-point ``M x N`` matrix. + + :param dst: output matrix of ``N x M`` size and the same type as ``src``. + + :param flags: inversion method : + + * **DECOMP_LU** Gaussian elimination with the optimal pivot element chosen. + + * **DECOMP_SVD** singular value decomposition (SVD) method. + + * **DECOMP_CHOLESKY** Cholesky decomposition; the matrix must be symmetrical and positively defined. + +The function ``invert`` inverts the matrix ``src`` and stores the result in ``dst`` . +When the matrix ``src`` is singular or non-square, the function calculates the pseudo-inverse matrix (the ``dst`` matrix) so that ``norm(src*dst - I)`` is minimal, where I is an identity matrix. + +In case of the ``DECOMP_LU`` method, the function returns non-zero value if the inverse has been successfully calculated and 0 if ``src`` is singular. + +In case of the ``DECOMP_SVD`` method, the function returns the inverse condition number of ``src`` (the ratio of the smallest singular value to the largest singular value) and 0 if ``src`` is singular. The SVD method calculates a pseudo-inverse matrix if ``src`` is singular. + +Similarly to ``DECOMP_LU`` , the method ``DECOMP_CHOLESKY`` works only with non-singular square matrices that should also be symmetrical and positively defined. In this case, the function stores the inverted matrix in ``dst`` and returns non-zero. Otherwise, it returns 0. + +.. seealso:: + + :ocv:func:`solve`, + :ocv:class:`SVD` + + + +log +--- +Calculates the natural logarithm of every array element. + +.. ocv:function:: void log(InputArray src, OutputArray dst) + +.. ocv:pyfunction:: cv2.log(src[, dst]) -> dst + +.. ocv:cfunction:: void cvLog(const CvArr* src, CvArr* dst) +.. ocv:pyoldfunction:: cv.Log(src, dst)-> None + + :param src: input array. + + :param dst: output array of the same size and type as ``src`` . + +The function ``log`` calculates the natural logarithm of the absolute value of every element of the input array: + +.. math:: + + \texttt{dst} (I) = \fork{\log |\texttt{src}(I)|}{if $\texttt{src}(I) \ne 0$ }{\texttt{C}}{otherwise} + +where ``C`` is a large negative number (about -700 in the current implementation). +The maximum relative error is about ``7e-6`` for single-precision input and less than ``1e-10`` for double-precision input. Special values (NaN, Inf) are not handled. + +.. seealso:: + + :ocv:func:`exp`, + :ocv:func:`cartToPolar`, + :ocv:func:`polarToCart`, + :ocv:func:`phase`, + :ocv:func:`pow`, + :ocv:func:`sqrt`, + :ocv:func:`magnitude` + + + +LUT +--- +Performs a look-up table transform of an array. + +.. ocv:function:: void LUT( InputArray src, InputArray lut, OutputArray dst, int interpolation=0 ) + +.. ocv:pyfunction:: cv2.LUT(src, lut[, dst[, interpolation]]) -> dst + +.. ocv:cfunction:: void cvLUT(const CvArr* src, CvArr* dst, const CvArr* lut) +.. ocv:pyoldfunction:: cv.LUT(src, dst, lut)-> None + + :param src: input array of 8-bit elements. + + :param lut: look-up table of 256 elements; in case of multi-channel input array, the table should either have a single channel (in this case the same table is used for all channels) or the same number of channels as in the input array. + + :param dst: output array of the same size and number of channels as ``src``, and the same depth as ``lut``. + +The function ``LUT`` fills the output array with values from the look-up table. Indices of the entries are taken from the input array. That is, the function processes each element of ``src`` as follows: + +.. math:: + + \texttt{dst} (I) \leftarrow \texttt{lut(src(I) + d)} + +where + +.. math:: + + d = \fork{0}{if \texttt{src} has depth \texttt{CV\_8U}}{128}{if \texttt{src} has depth \texttt{CV\_8S}} + +.. seealso:: + + :ocv:func:`convertScaleAbs`, + :ocv:func:`Mat::convertTo` + + + +magnitude +--------- +Calculates the magnitude of 2D vectors. + +.. ocv:function:: void magnitude(InputArray x, InputArray y, OutputArray magnitude) + +.. ocv:pyfunction:: cv2.magnitude(x, y[, magnitude]) -> magnitude + + :param x: floating-point array of x-coordinates of the vectors. + + :param y: floating-point array of y-coordinates of the vectors; it must have the same size as ``x``. + + :param magnitude: output array of the same size and type as ``x``. + +The function ``magnitude`` calculates the magnitude of 2D vectors formed from the corresponding elements of ``x`` and ``y`` arrays: + +.. math:: + + \texttt{dst} (I) = \sqrt{\texttt{x}(I)^2 + \texttt{y}(I)^2} + +.. seealso:: + + :ocv:func:`cartToPolar`, + :ocv:func:`polarToCart`, + :ocv:func:`phase`, + :ocv:func:`sqrt` + + + +Mahalanobis +----------- +Calculates the Mahalanobis distance between two vectors. + +.. ocv:function:: double Mahalanobis( InputArray v1, InputArray v2, InputArray icovar ) + +.. ocv:pyfunction:: cv2.Mahalanobis(v1, v2, icovar) -> retval + +.. ocv:cfunction:: double cvMahalanobis( const CvArr* vec1, const CvArr* vec2, const CvArr* mat ) + +.. ocv:pyoldfunction:: cv.Mahalonobis(vec1, vec2, mat) -> None + + :param vec1: first 1D input vector. + + :param vec2: second 1D input vector. + + :param icovar: inverse covariance matrix. + +The function ``Mahalanobis`` calculates and returns the weighted distance between two vectors: + +.. math:: + + d( \texttt{vec1} , \texttt{vec2} )= \sqrt{\sum_{i,j}{\texttt{icovar(i,j)}\cdot(\texttt{vec1}(I)-\texttt{vec2}(I))\cdot(\texttt{vec1(j)}-\texttt{vec2(j)})} } + +The covariance matrix may be calculated using the +:ocv:func:`calcCovarMatrix` function and then inverted using the +:ocv:func:`invert` function (preferably using the ``DECOMP_SVD`` method, as the most accurate). + + + +max +--- +Calculates per-element maximum of two arrays or an array and a scalar. + +.. ocv:function:: MatExpr max( const Mat& a, const Mat& b ) + +.. ocv:function:: MatExpr max( const Mat& a, double s ) + +.. ocv:function:: MatExpr max( double s, const Mat& a ) + +.. ocv:function:: void max(InputArray src1, InputArray src2, OutputArray dst) + +.. ocv:function:: void max(const Mat& src1, const Mat& src2, Mat& dst) + +.. ocv:function:: void max( const Mat& src1, double src2, Mat& dst ) + +.. ocv:pyfunction:: cv2.max(src1, src2[, dst]) -> dst + +.. ocv:cfunction:: void cvMax(const CvArr* src1, const CvArr* src2, CvArr* dst) +.. ocv:cfunction:: void cvMaxS(const CvArr* src, double value, CvArr* dst) +.. ocv:pyoldfunction:: cv.Max(src1, src2, dst)-> None +.. ocv:pyoldfunction:: cv.MaxS(src, value, dst)-> None + + :param src1: first input array. + + :param src2: second input array of the same size and type as ``src1`` . + + :param value: real scalar value. + + :param dst: output array of the same size and type as ``src1``. + +The functions ``max`` calculate the per-element maximum of two arrays: + +.. math:: + + \texttt{dst} (I)= \max ( \texttt{src1} (I), \texttt{src2} (I)) + +or array and a scalar: + +.. math:: + + \texttt{dst} (I)= \max ( \texttt{src1} (I), \texttt{value} ) + +In the second variant, when the input array is multi-channel, each channel is compared with ``value`` independently. + +The first 3 variants of the function listed above are actually a part of +:ref:`MatrixExpressions` . They return an expression object that can be further either transformed/ assigned to a matrix, or passed to a function, and so on. + +.. seealso:: + + :ocv:func:`min`, + :ocv:func:`compare`, + :ocv:func:`inRange`, + :ocv:func:`minMaxLoc`, + :ref:`MatrixExpressions` + + +mean +---- +Calculates an average (mean) of array elements. + +.. ocv:function:: Scalar mean(InputArray src, InputArray mask=noArray()) + +.. ocv:pyfunction:: cv2.mean(src[, mask]) -> retval + +.. ocv:cfunction:: CvScalar cvAvg( const CvArr* arr, const CvArr* mask=NULL ) + +.. ocv:pyoldfunction:: cv.Avg(arr, mask=None) -> scalar + + :param src: input array that should have from 1 to 4 channels so that the result can be stored in :ocv:class:`Scalar_` . + + :param mask: optional operation mask. + +The function ``mean`` calculates the mean value ``M`` of array elements, independently for each channel, and return it: + +.. math:: + + \begin{array}{l} N = \sum _{I: \; \texttt{mask} (I) \ne 0} 1 \\ M_c = \left ( \sum _{I: \; \texttt{mask} (I) \ne 0}{ \texttt{mtx} (I)_c} \right )/N \end{array} + +When all the mask elements are 0's, the functions return ``Scalar::all(0)`` . + +.. seealso:: + + :ocv:func:`countNonZero`, + :ocv:func:`meanStdDev`, + :ocv:func:`norm`, + :ocv:func:`minMaxLoc` + + + +meanStdDev +---------- +Calculates a mean and standard deviation of array elements. + +.. ocv:function:: void meanStdDev(InputArray src, OutputArray mean, OutputArray stddev, InputArray mask=noArray()) + +.. ocv:pyfunction:: cv2.meanStdDev(src[, mean[, stddev[, mask]]]) -> mean, stddev + +.. ocv:cfunction:: void cvAvgSdv( const CvArr* arr, CvScalar* mean, CvScalar* std_dev, const CvArr* mask=NULL ) + +.. ocv:pyoldfunction:: cv.AvgSdv(arr, mask=None) -> (mean, stdDev) + + :param src: input array that should have from 1 to 4 channels so that the results can be stored in :ocv:class:`Scalar_` 's. + + :param mean: output parameter: calculated mean value. + + :param stddev: output parameter: calculateded standard deviation. + + :param mask: optional operation mask. + +The function ``meanStdDev`` calculates the mean and the standard deviation ``M`` of array elements independently for each channel and returns it via the output parameters: + +.. math:: + + \begin{array}{l} N = \sum _{I, \texttt{mask} (I) \ne 0} 1 \\ \texttt{mean} _c = \frac{\sum_{ I: \; \texttt{mask}(I) \ne 0} \texttt{src} (I)_c}{N} \\ \texttt{stddev} _c = \sqrt{\frac{\sum_{ I: \; \texttt{mask}(I) \ne 0} \left ( \texttt{src} (I)_c - \texttt{mean} _c \right )^2}{N}} \end{array} + +When all the mask elements are 0's, the functions return ``mean=stddev=Scalar::all(0)`` . + +.. note:: The calculated standard deviation is only the diagonal of the complete normalized covariance matrix. If the full matrix is needed, you can reshape the multi-channel array ``M x N`` to the single-channel array ``M*N x mtx.channels()`` (only possible when the matrix is continuous) and then pass the matrix to :ocv:func:`calcCovarMatrix` . + +.. seealso:: + + :ocv:func:`countNonZero`, + :ocv:func:`mean`, + :ocv:func:`norm`, + :ocv:func:`minMaxLoc`, + :ocv:func:`calcCovarMatrix` + + + +merge +----- +Creates one multichannel array out of several single-channel ones. + +.. ocv:function:: void merge(const Mat* mv, size_t count, OutputArray dst) + +.. ocv:function:: void merge( InputArrayOfArrays mv, OutputArray dst ) + +.. ocv:pyfunction:: cv2.merge(mv[, dst]) -> dst + +.. ocv:cfunction:: void cvMerge(const CvArr* src0, const CvArr* src1, const CvArr* src2, const CvArr* src3, CvArr* dst) +.. ocv:pyoldfunction:: cv.Merge(src0, src1, src2, src3, dst)-> None + + :param mv: input array or vector of matrices to be merged; all the matrices in ``mv`` must have the same size and the same depth. + + :param count: number of input matrices when ``mv`` is a plain C array; it must be greater than zero. + + :param dst: output array of the same size and the same depth as ``mv[0]``; The number of channels will be the total number of channels in the matrix array. + +The functions ``merge`` merge several arrays to make a single multi-channel array. That is, each element of the output array will be a concatenation of the elements of the input arrays, where elements of i-th input array are treated as ``mv[i].channels()``-element vectors. + +The function +:ocv:func:`split` does the reverse operation. If you need to shuffle channels in some other advanced way, use +:ocv:func:`mixChannels` . + +.. seealso:: + + :ocv:func:`mixChannels`, + :ocv:func:`split`, + :ocv:func:`Mat::reshape` + + + +min +--- +Calculates per-element minimum of two arrays or an array and a scalar. + +.. ocv:function:: MatExpr min( const Mat& a, const Mat& b ) + +.. ocv:function:: MatExpr min( const Mat& a, double s ) + +.. ocv:function:: MatExpr min( double s, const Mat& a ) + +.. ocv:function:: void min(InputArray src1, InputArray src2, OutputArray dst) + +.. ocv:function:: void min(const Mat& src1, const Mat& src2, Mat& dst) + +.. ocv:function:: void min( const Mat& src1, double src2, Mat& dst ) + +.. ocv:pyfunction:: cv2.min(src1, src2[, dst]) -> dst + +.. ocv:cfunction:: void cvMin(const CvArr* src1, const CvArr* src2, CvArr* dst) +.. ocv:cfunction:: void cvMinS(const CvArr* src, double value, CvArr* dst) +.. ocv:pyoldfunction:: cv.Min(src1, src2, dst)-> None +.. ocv:pyoldfunction:: cv.MinS(src, value, dst)-> None + + :param src1: first input array. + + :param src2: second input array of the same size and type as ``src1``. + + :param value: real scalar value. + + :param dst: output array of the same size and type as ``src1``. + +The functions ``min`` calculate the per-element minimum of two arrays: + +.. math:: + + \texttt{dst} (I)= \min ( \texttt{src1} (I), \texttt{src2} (I)) + +or array and a scalar: + +.. math:: + + \texttt{dst} (I)= \min ( \texttt{src1} (I), \texttt{value} ) + +In the second variant, when the input array is multi-channel, each channel is compared with ``value`` independently. + +The first three variants of the function listed above are actually a part of +:ref:`MatrixExpressions` . They return the expression object that can be further either transformed/assigned to a matrix, or passed to a function, and so on. + +.. seealso:: + + :ocv:func:`max`, + :ocv:func:`compare`, + :ocv:func:`inRange`, + :ocv:func:`minMaxLoc`, + :ref:`MatrixExpressions` + + +minMaxIdx +--------- +Finds the global minimum and maximum in an array + +.. ocv:function:: void minMaxIdx(InputArray src, double* minVal, double* maxVal, int* minIdx=0, int* maxIdx=0, InputArray mask=noArray()) + + :param src: input single-channel array. + + :param minVal: pointer to the returned minimum value; ``NULL`` is used if not required. + + :param maxVal: pointer to the returned maximum value; ``NULL`` is used if not required. + + :param minIdx: pointer to the returned minimum location (in nD case); ``NULL`` is used if not required; Otherwise, it must point to an array of ``src.dims`` elements, the coordinates of the minimum element in each dimension are stored there sequentially. + + .. note:: + + When ``minIdx`` is not NULL, it must have at least 2 elements (as well as ``maxIdx``), even if ``src`` is a single-row or single-column matrix. In OpenCV (following MATLAB) each array has at least 2 dimensions, i.e. single-column matrix is ``Mx1`` matrix (and therefore ``minIdx``/``maxIdx`` will be ``(i1,0)``/``(i2,0)``) and single-row matrix is ``1xN`` matrix (and therefore ``minIdx``/``maxIdx`` will be ``(0,j1)``/``(0,j2)``). + + :param maxIdx: pointer to the returned maximum location (in nD case). ``NULL`` is used if not required. + + The function ``minMaxIdx`` finds the minimum and maximum element values and their positions. The extremums are searched across the whole array or, if ``mask`` is not an empty array, in the specified array region. + + The function does not work with multi-channel arrays. If you need to find minimum or maximum elements across all the channels, use + :ocv:func:`Mat::reshape` first to reinterpret the array as single-channel. Or you may extract the particular channel using either + :ocv:func:`extractImageCOI` , or + :ocv:func:`mixChannels` , or + :ocv:func:`split` . + + In case of a sparse matrix, the minimum is found among non-zero elements only. + + + +minMaxLoc +--------- +Finds the global minimum and maximum in an array. + +.. ocv:function:: void minMaxLoc(InputArray src, double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, InputArray mask=noArray()) + +.. ocv:function:: void minMaxLoc( const SparseMat& a, double* minVal, double* maxVal, int* minIdx=0, int* maxIdx=0 ) + +.. ocv:pyfunction:: cv2.minMaxLoc(src[, mask]) -> minVal, maxVal, minLoc, maxLoc + +.. ocv:cfunction:: void cvMinMaxLoc( const CvArr* arr, double* min_val, double* max_val, CvPoint* min_loc=NULL, CvPoint* max_loc=NULL, const CvArr* mask=NULL ) + +.. ocv:pyoldfunction:: cv.MinMaxLoc(arr, mask=None)-> (minVal, maxVal, minLoc, maxLoc) + + :param src: input single-channel array. + + :param minVal: pointer to the returned minimum value; ``NULL`` is used if not required. + + :param maxVal: pointer to the returned maximum value; ``NULL`` is used if not required. + + :param minLoc: pointer to the returned minimum location (in 2D case); ``NULL`` is used if not required. + + :param maxLoc: pointer to the returned maximum location (in 2D case); ``NULL`` is used if not required. + + :param mask: optional mask used to select a sub-array. + +The functions ``minMaxLoc`` find the minimum and maximum element values and their positions. The extremums are searched across the whole array or, +if ``mask`` is not an empty array, in the specified array region. + +The functions do not work with multi-channel arrays. If you need to find minimum or maximum elements across all the channels, use +:ocv:func:`Mat::reshape` first to reinterpret the array as single-channel. Or you may extract the particular channel using either +:ocv:func:`extractImageCOI` , or +:ocv:func:`mixChannels` , or +:ocv:func:`split` . + +.. seealso:: + + :ocv:func:`max`, + :ocv:func:`min`, + :ocv:func:`compare`, + :ocv:func:`inRange`, + :ocv:func:`extractImageCOI`, + :ocv:func:`mixChannels`, + :ocv:func:`split`, + :ocv:func:`Mat::reshape` + + + +mixChannels +----------- +Copies specified channels from input arrays to the specified channels of output arrays. + +.. ocv:function:: void mixChannels( const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_t npairs ) + +.. ocv:function:: void mixChannels( const vector& src, vector& dst, const int* fromTo, size_t npairs ) + +.. ocv:pyfunction:: cv2.mixChannels(src, dst, fromTo) -> None + +.. ocv:cfunction:: void cvMixChannels( const CvArr** src, int src_count, CvArr** dst, int dst_count, const int* from_to, int pair_count ) + +.. ocv:pyoldfunction:: cv.MixChannels(src, dst, fromTo) -> None + + :param src: input array or vector of matricesl; all of the matrices must have the same size and the same depth. + + :param nsrcs: number of matrices in ``src``. + + :param dst: output array or vector of matrices; all the matrices *must be allocated*; their size and depth must be the same as in ``src[0]``. + + :param ndsts: number of matrices in ``dst``. + + :param fromTo: array of index pairs specifying which channels are copied and where; ``fromTo[k*2]`` is a 0-based index of the input channel in ``src``, ``fromTo[k*2+1]`` is an index of the output channel in ``dst``; the continuous channel numbering is used: the first input image channels are indexed from ``0`` to ``src[0].channels()-1``, the second input image channels are indexed from ``src[0].channels()`` to ``src[0].channels() + src[1].channels()-1``, and so on, the same scheme is used for the output image channels; as a special case, when ``fromTo[k*2]`` is negative, the corresponding output channel is filled with zero . + + :param npairs: number of index pairs in ``fromTo``. + +The functions ``mixChannels`` provide an advanced mechanism for shuffling image channels. + +:ocv:func:`split` and +:ocv:func:`merge` and some forms of +:ocv:func:`cvtColor` are partial cases of ``mixChannels`` . + +In the example below, the code splits a 4-channel RGBA image into a 3-channel BGR (with R and B channels swapped) and a separate alpha-channel image: :: + + Mat rgba( 100, 100, CV_8UC4, Scalar(1,2,3,4) ); + Mat bgr( rgba.rows, rgba.cols, CV_8UC3 ); + Mat alpha( rgba.rows, rgba.cols, CV_8UC1 ); + + // forming an array of matrices is a quite efficient operation, + // because the matrix data is not copied, only the headers + Mat out[] = { bgr, alpha }; + // rgba[0] -> bgr[2], rgba[1] -> bgr[1], + // rgba[2] -> bgr[0], rgba[3] -> alpha[0] + int from_to[] = { 0,2, 1,1, 2,0, 3,3 }; + mixChannels( &rgba, 1, out, 2, from_to, 4 ); + + +.. note:: Unlike many other new-style C++ functions in OpenCV (see the introduction section and :ocv:func:`Mat::create` ), ``mixChannels`` requires the output arrays to be pre-allocated before calling the function. + +.. seealso:: + + :ocv:func:`split`, + :ocv:func:`merge`, + :ocv:func:`cvtColor` + + + +mulSpectrums +------------ +Performs the per-element multiplication of two Fourier spectrums. + +.. ocv:function:: void mulSpectrums( InputArray a, InputArray b, OutputArray c, int flags, bool conjB=false ) + +.. ocv:pyfunction:: cv2.mulSpectrums(a, b, flags[, c[, conjB]]) -> c + +.. ocv:cfunction:: void cvMulSpectrums( const CvArr* src1, const CvArr* src2, CvArr* dst, int flags) +.. ocv:pyoldfunction:: cv.MulSpectrums(src1, src2, dst, flags)-> None + + :param src1: first input array. + + :param src2: second input array of the same size and type as ``src1`` . + + :param dst: output array of the same size and type as ``src1`` . + + :param flags: operation flags; currently, the only supported flag is ``DFT_ROWS``, which indicates that each row of ``src1`` and ``src2`` is an independent 1D Fourier spectrum. + + :param conjB: optional flag that conjugates the second input array before the multiplication (true) or not (false). + +The function ``mulSpectrums`` performs the per-element multiplication of the two CCS-packed or complex matrices that are results of a real or complex Fourier transform. + +The function, together with +:ocv:func:`dft` and +:ocv:func:`idft` , may be used to calculate convolution (pass ``conjB=false`` ) or correlation (pass ``conjB=true`` ) of two arrays rapidly. When the arrays are complex, they are simply multiplied (per element) with an optional conjugation of the second-array elements. When the arrays are real, they are assumed to be CCS-packed (see +:ocv:func:`dft` for details). + + + +multiply +-------- +Calculates the per-element scaled product of two arrays. + +.. ocv:function:: void multiply( InputArray src1, InputArray src2, OutputArray dst, double scale=1, int dtype=-1 ) + +.. ocv:pyfunction:: cv2.multiply(src1, src2[, dst[, scale[, dtype]]]) -> dst + +.. ocv:cfunction:: void cvMul(const CvArr* src1, const CvArr* src2, CvArr* dst, double scale=1) +.. ocv:pyoldfunction:: cv.Mul(src1, src2, dst, scale=1) -> None + + :param src1: first input array. + + :param src2: second input array of the same size and the same type as ``src1``. + + :param dst: output array of the same size and type as ``src1``. + + :param scale: optional scale factor. + +The function ``multiply`` calculates the per-element product of two arrays: + +.. math:: + + \texttt{dst} (I)= \texttt{saturate} ( \texttt{scale} \cdot \texttt{src1} (I) \cdot \texttt{src2} (I)) + +There is also a +:ref:`MatrixExpressions` -friendly variant of the first function. See +:ocv:func:`Mat::mul` . + +For a not-per-element matrix product, see +:ocv:func:`gemm` . + +.. note:: Saturation is not applied when the output array has the depth ``CV_32S``. You may even get result of an incorrect sign in the case of overflow. + +.. seealso:: + + :ocv:func:`add`, + :ocv:func:`subtract`, + :ocv:func:`divide`, + :ref:`MatrixExpressions`, + :ocv:func:`scaleAdd`, + :ocv:func:`addWeighted`, + :ocv:func:`accumulate`, + :ocv:func:`accumulateProduct`, + :ocv:func:`accumulateSquare`, + :ocv:func:`Mat::convertTo` + + + +mulTransposed +------------- +Calculates the product of a matrix and its transposition. + +.. ocv:function:: void mulTransposed( InputArray src, OutputArray dst, bool aTa, InputArray delta=noArray(), double scale=1, int dtype=-1 ) + +.. ocv:pyfunction:: cv2.mulTransposed(src, aTa[, dst[, delta[, scale[, dtype]]]]) -> dst + +.. ocv:cfunction:: void cvMulTransposed( const CvArr* src, CvArr* dst, int order, const CvArr* delta=NULL, double scale=1. ) + +.. ocv:pyoldfunction:: cv.MulTransposed(src, dst, order, delta=None, scale=1.0) -> None + + :param src: input single-channel matrix. Note that unlike :ocv:func:`gemm`, the function can multiply not only floating-point matrices. + + :param dst: output square matrix. + + :param aTa: Flag specifying the multiplication ordering. See the description below. + + :param delta: Optional delta matrix subtracted from ``src`` before the multiplication. When the matrix is empty ( ``delta=noArray()`` ), it is assumed to be zero, that is, nothing is subtracted. If it has the same size as ``src`` , it is simply subtracted. Otherwise, it is "repeated" (see :ocv:func:`repeat` ) to cover the full ``src`` and then subtracted. Type of the delta matrix, when it is not empty, must be the same as the type of created output matrix. See the ``dtype`` parameter description below. + + :param scale: Optional scale factor for the matrix product. + + :param dtype: Optional type of the output matrix. When it is negative, the output matrix will have the same type as ``src`` . Otherwise, it will be ``type=CV_MAT_DEPTH(dtype)`` that should be either ``CV_32F`` or ``CV_64F`` . + +The function ``mulTransposed`` calculates the product of ``src`` and its transposition: + +.. math:: + + \texttt{dst} = \texttt{scale} ( \texttt{src} - \texttt{delta} )^T ( \texttt{src} - \texttt{delta} ) + +if ``aTa=true`` , and + +.. math:: + + \texttt{dst} = \texttt{scale} ( \texttt{src} - \texttt{delta} ) ( \texttt{src} - \texttt{delta} )^T + +otherwise. The function is used to calculate the covariance matrix. With zero delta, it can be used as a faster substitute for general matrix product ``A*B`` when ``B=A'`` + +.. seealso:: + + :ocv:func:`calcCovarMatrix`, + :ocv:func:`gemm`, + :ocv:func:`repeat`, + :ocv:func:`reduce` + + + +norm +---- +Calculates an absolute array norm, an absolute difference norm, or a relative difference norm. + +.. ocv:function:: double norm(InputArray src1, int normType=NORM_L2, InputArray mask=noArray()) + +.. ocv:function:: double norm( InputArray src1, InputArray src2, int normType=NORM_L2, InputArray mask=noArray() ) + +.. ocv:function:: double norm( const SparseMat& src, int normType ) + +.. ocv:pyfunction:: cv2.norm(src1[, normType[, mask]]) -> retval +.. ocv:pyfunction:: cv2.norm(src1, src2[, normType[, mask]]) -> retval + +.. ocv:cfunction:: double cvNorm( const CvArr* arr1, const CvArr* arr2=NULL, int norm_type=CV_L2, const CvArr* mask=NULL ) + +.. ocv:pyoldfunction:: cv.Norm(arr1, arr2, normType=CV_L2, mask=None) -> float + + :param src1: first input array. + + :param src2: second input array of the same size and the same type as ``src1``. + + :param normType: type of the norm (see the details below). + + :param mask: optional operation mask; it must have the same size as ``src1`` and ``CV_8UC1`` type. + +The functions ``norm`` calculate an absolute norm of ``src1`` (when there is no ``src2`` ): + +.. math:: + + norm = \forkthree{\|\texttt{src1}\|_{L_{\infty}} = \max _I | \texttt{src1} (I)|}{if $\texttt{normType} = \texttt{NORM\_INF}$ } + { \| \texttt{src1} \| _{L_1} = \sum _I | \texttt{src1} (I)|}{if $\texttt{normType} = \texttt{NORM\_L1}$ } + { \| \texttt{src1} \| _{L_2} = \sqrt{\sum_I \texttt{src1}(I)^2} }{if $\texttt{normType} = \texttt{NORM\_L2}$ } + +or an absolute or relative difference norm if ``src2`` is there: + +.. math:: + + norm = \forkthree{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} = \max _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if $\texttt{normType} = \texttt{NORM\_INF}$ } + { \| \texttt{src1} - \texttt{src2} \| _{L_1} = \sum _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if $\texttt{normType} = \texttt{NORM\_L1}$ } + { \| \texttt{src1} - \texttt{src2} \| _{L_2} = \sqrt{\sum_I (\texttt{src1}(I) - \texttt{src2}(I))^2} }{if $\texttt{normType} = \texttt{NORM\_L2}$ } + +or + +.. math:: + + norm = \forkthree{\frac{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} }{\|\texttt{src2}\|_{L_{\infty}} }}{if $\texttt{normType} = \texttt{NORM\_RELATIVE\_INF}$ } + { \frac{\|\texttt{src1}-\texttt{src2}\|_{L_1} }{\|\texttt{src2}\|_{L_1}} }{if $\texttt{normType} = \texttt{NORM\_RELATIVE\_L1}$ } + { \frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} }{\|\texttt{src2}\|_{L_2}} }{if $\texttt{normType} = \texttt{NORM\_RELATIVE\_L2}$ } + +The functions ``norm`` return the calculated norm. + +When the ``mask`` parameter is specified and it is not empty, the norm is calculated only over the region specified by the mask. + +A multi-channel input arrays are treated as a single-channel, that is, the results for all channels are combined. + + + +normalize +--------- +Normalizes the norm or value range of an array. + +.. ocv:function:: void normalize( InputArray src, OutputArray dst, double alpha=1, double beta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray() ) + +.. ocv:function:: void normalize(const SparseMat& src, SparseMat& dst, double alpha, int normType) + +.. ocv:pyfunction:: cv2.normalize(src[, dst[, alpha[, beta[, norm_type[, dtype[, mask]]]]]]) -> dst + + :param src: input array. + + :param dst: output array of the same size as ``src`` . + + :param alpha: norm value to normalize to or the lower range boundary in case of the range normalization. + + :param beta: upper range boundary in case of the range normalization; it is not used for the norm normalization. + + :param normType: normalization type (see the details below). + + :param dtype: when negative, the output array has the same type as ``src``; otherwise, it has the same number of channels as ``src`` and the depth ``=CV_MAT_DEPTH(dtype)``. + + :param mask: optional operation mask. + + +The functions ``normalize`` scale and shift the input array elements so that + +.. math:: + + \| \texttt{dst} \| _{L_p}= \texttt{alpha} + +(where p=Inf, 1 or 2) when ``normType=NORM_INF``, ``NORM_L1``, or ``NORM_L2``, respectively; or so that + +.. math:: + + \min _I \texttt{dst} (I)= \texttt{alpha} , \, \, \max _I \texttt{dst} (I)= \texttt{beta} + +when ``normType=NORM_MINMAX`` (for dense arrays only). +The optional mask specifies a sub-array to be normalized. This means that the norm or min-n-max are calculated over the sub-array, and then this sub-array is modified to be normalized. If you want to only use the mask to calculate the norm or min-max but modify the whole array, you can use +:ocv:func:`norm` and +:ocv:func:`Mat::convertTo`. + +In case of sparse matrices, only the non-zero values are analyzed and transformed. Because of this, the range transformation for sparse matrices is not allowed since it can shift the zero level. + +.. seealso:: + + :ocv:func:`norm`, + :ocv:func:`Mat::convertTo`, + :ocv:func:`SparseMat::convertTo` + + + +PCA +--- +.. ocv:class:: PCA + +Principal Component Analysis class. + +The class is used to calculate a special basis for a set of vectors. The basis will consist of eigenvectors of the covariance matrix calculated from the input set of vectors. The class ``PCA`` can also transform vectors to/from the new coordinate space defined by the basis. Usually, in this new coordinate system, each vector from the original set (and any linear combination of such vectors) can be quite accurately approximated by taking its first few components, corresponding to the eigenvectors of the largest eigenvalues of the covariance matrix. Geometrically it means that you calculate a projection of the vector to a subspace formed by a few eigenvectors corresponding to the dominant eigenvalues of the covariance matrix. And usually such a projection is very close to the original vector. So, you can represent the original vector from a high-dimensional space with a much shorter vector consisting of the projected vector's coordinates in the subspace. Such a transformation is also known as Karhunen-Loeve Transform, or KLT. See +http://en.wikipedia.org/wiki/Principal\_component\_analysis . + +The sample below is the function that takes two matrices. The first function stores a set of vectors (a row per vector) that is used to calculate PCA. The second function stores another "test" set of vectors (a row per vector). First, these vectors are compressed with PCA, then reconstructed back, and then the reconstruction error norm is computed and printed for each vector. :: + + PCA compressPCA(InputArray pcaset, int maxComponents, + const Mat& testset, OutputArray compressed) + { + PCA pca(pcaset, // pass the data + Mat(), // there is no pre-computed mean vector, + // so let the PCA engine to compute it + CV_PCA_DATA_AS_ROW, // indicate that the vectors + // are stored as matrix rows + // (use CV_PCA_DATA_AS_COL if the vectors are + // the matrix columns) + maxComponents // specify how many principal components to retain + ); + // if there is no test data, just return the computed basis, ready-to-use + if( !testset.data ) + return pca; + CV_Assert( testset.cols == pcaset.cols ); + + compressed.create(testset.rows, maxComponents, testset.type()); + + Mat reconstructed; + for( int i = 0; i < testset.rows; i++ ) + { + Mat vec = testset.row(i), coeffs = compressed.row(i); + // compress the vector, the result will be stored + // in the i-th row of the output matrix + pca.project(vec, coeffs); + // and then reconstruct it + pca.backProject(coeffs, reconstructed); + // and measure the error + printf("%d. diff = %g\n", i, norm(vec, reconstructed, NORM_L2)); + } + return pca; + } + + +.. seealso:: + + :ocv:func:`calcCovarMatrix`, + :ocv:func:`mulTransposed`, + :ocv:class:`SVD`, + :ocv:func:`dft`, + :ocv:func:`dct` + + + +PCA::PCA +------------ +PCA constructors + +.. ocv:function:: PCA::PCA() + +.. ocv:function:: PCA::PCA(InputArray data, InputArray mean, int flags, int maxComponents=0) + + :param data: input samples stored as matrix rows or matrix columns. + + :param mean: optional mean value; if the matrix is empty (``noArray()``), the mean is computed from the data. + + :param flags: operation flags; currently the parameter is only used to specify the data layout: + + * **CV_PCA_DATA_AS_ROW** indicates that the input samples are stored as matrix rows. + + * **CV_PCA_DATA_AS_COL** indicates that the input samples are stored as matrix columns. + + :param maxComponents: maximum number of components that PCA should retain; by default, all the components are retained. + +The default constructor initializes an empty PCA structure. The second constructor initializes the structure and calls +:ocv:funcx:`PCA::operator()` . + + + +PCA::operator () +---------------- +Performs Principal Component Analysis of the supplied dataset. + +.. ocv:function:: PCA& PCA::operator()(InputArray data, InputArray mean, int flags, int maxComponents=0) + +.. ocv:pyfunction:: cv2.PCACompute(data[, mean[, eigenvectors[, maxComponents]]]) -> mean, eigenvectors + + :param data: input samples stored as the matrix rows or as the matrix columns. + + :param mean: optional mean value; if the matrix is empty (``noArray()``), the mean is computed from the data. + + :param flags: operation flags; currently the parameter is only used to specify the data layout. + + * **CV_PCA_DATA_AS_ROW** indicates that the input samples are stored as matrix rows. + + * **CV_PCA_DATA_AS_COL** indicates that the input samples are stored as matrix columns. + + :param maxComponents: maximum number of components that PCA should retain; by default, all the components are retained. + +The operator performs PCA of the supplied dataset. It is safe to reuse the same PCA structure for multiple datasets. That is, if the structure has been previously used with another dataset, the existing internal data is reclaimed and the new ``eigenvalues``, ``eigenvectors`` , and ``mean`` are allocated and computed. + +The computed eigenvalues are sorted from the largest to the smallest and the corresponding eigenvectors are stored as ``PCA::eigenvectors`` rows. + + + +PCA::project +------------ +Projects vector(s) to the principal component subspace. + +.. ocv:function:: Mat PCA::project(InputArray vec) const + +.. ocv:function:: void PCA::project(InputArray vec, OutputArray result) const + +.. ocv:pyfunction:: cv2.PCAProject(data, mean, eigenvectors[, result]) -> result + + :param vec: input vector(s); must have the same dimensionality and the same layout as the input data used at PCA phase, that is, if ``CV_PCA_DATA_AS_ROW`` are specified, then ``vec.cols==data.cols`` (vector dimensionality) and ``vec.rows`` is the number of vectors to project, and the same is true for the ``CV_PCA_DATA_AS_COL`` case. + + :param result: output vectors; in case of ``CV_PCA_DATA_AS_COL``, the output matrix has as many columns as the number of input vectors, this means that ``result.cols==vec.cols`` and the number of rows match the number of principal components (for example, ``maxComponents`` parameter passed to the constructor). + +The methods project one or more vectors to the principal component subspace, where each vector projection is represented by coefficients in the principal component basis. The first form of the method returns the matrix that the second form writes to the result. So the first form can be used as a part of expression while the second form can be more efficient in a processing loop. + + + +PCA::backProject +---------------- +Reconstructs vectors from their PC projections. + +.. ocv:function:: Mat PCA::backProject(InputArray vec) const + +.. ocv:function:: void PCA::backProject(InputArray vec, OutputArray result) const + +.. ocv:pyfunction:: cv2.PCABackProject(data, mean, eigenvectors[, result]) -> result + + :param vec: coordinates of the vectors in the principal component subspace, the layout and size are the same as of ``PCA::project`` output vectors. + + :param result: reconstructed vectors; the layout and size are the same as of ``PCA::project`` input vectors. + +The methods are inverse operations to +:ocv:func:`PCA::project`. They take PC coordinates of projected vectors and reconstruct the original vectors. Unless all the principal components have been retained, the reconstructed vectors are different from the originals. But typically, the difference is small if the number of components is large enough (but still much smaller than the original vector dimensionality). As a result, PCA is used. + + + +perspectiveTransform +-------------------- +Performs the perspective matrix transformation of vectors. + +.. ocv:function:: void perspectiveTransform( InputArray src, OutputArray dst, InputArray m ) + +.. ocv:pyfunction:: cv2.perspectiveTransform(src, m[, dst]) -> dst + +.. ocv:cfunction:: void cvPerspectiveTransform(const CvArr* src, CvArr* dst, const CvMat* mat) +.. ocv:pyoldfunction:: cv.PerspectiveTransform(src, dst, mat)-> None + + :param src: input two-channel or three-channel floating-point array; each element is a 2D/3D vector to be transformed. + + :param dst: output array of the same size and type as ``src``. + + :param m: ``3x3`` or ``4x4`` floating-point transformation matrix. + +The function ``perspectiveTransform`` transforms every element of ``src`` by treating it as a 2D or 3D vector, in the following way: + +.. math:: + + (x, y, z) \rightarrow (x'/w, y'/w, z'/w) + +where + +.. math:: + + (x', y', z', w') = \texttt{mat} \cdot \begin{bmatrix} x & y & z & 1 \end{bmatrix} + +and + +.. math:: + + w = \fork{w'}{if $w' \ne 0$}{\infty}{otherwise} + +Here a 3D vector transformation is shown. In case of a 2D vector transformation, the ``z`` component is omitted. + +.. note:: The function transforms a sparse set of 2D or 3D vectors. If you want to transform an image using perspective transformation, use :ocv:func:`warpPerspective` . If you have an inverse problem, that is, you want to compute the most probable perspective transformation out of several pairs of corresponding points, you can use :ocv:func:`getPerspectiveTransform` or :ocv:func:`findHomography` . + +.. seealso:: + + :ocv:func:`transform`, + :ocv:func:`warpPerspective`, + :ocv:func:`getPerspectiveTransform`, + :ocv:func:`findHomography` + + + +phase +----- +Calculates the rotation angle of 2D vectors. + +.. ocv:function:: void phase(InputArray x, InputArray y, OutputArray angle, bool angleInDegrees=false) + +.. ocv:pyfunction:: cv2.phase(x, y[, angle[, angleInDegrees]]) -> angle + + :param x: input floating-point array of x-coordinates of 2D vectors. + + :param y: input array of y-coordinates of 2D vectors; it must have the same size and the same type as ``x``. + + :param angle: output array of vector angles; it has the same size and same type as ``x`` . + + :param angleInDegrees: when true, the function calculates the angle in degrees, otherwise, they are measured in radians. + +The function ``phase`` calculates the rotation angle of each 2D vector that is formed from the corresponding elements of ``x`` and ``y`` : + +.. math:: + + \texttt{angle} (I) = \texttt{atan2} ( \texttt{y} (I), \texttt{x} (I)) + +The angle estimation accuracy is about 0.3 degrees. When ``x(I)=y(I)=0`` , the corresponding ``angle(I)`` is set to 0. + + +polarToCart +----------- +Calculates x and y coordinates of 2D vectors from their magnitude and angle. + +.. ocv:function:: void polarToCart(InputArray magnitude, InputArray angle, OutputArray x, OutputArray y, bool angleInDegrees=false) + +.. ocv:pyfunction:: cv2.polarToCart(magnitude, angle[, x[, y[, angleInDegrees]]]) -> x, y + +.. ocv:cfunction:: void cvPolarToCart( const CvArr* magnitude, const CvArr* angle, CvArr* x, CvArr* y, int angle_in_degrees=0 ) + +.. ocv:pyoldfunction:: cv.PolarToCart(magnitude, angle, x, y, angleInDegrees=0)-> None + + :param magnitude: input floating-point array of magnitudes of 2D vectors; it can be an empty matrix (``=Mat()``), in this case, the function assumes that all the magnitudes are =1; if it is not empty, it must have the same size and type as ``angle``. + + :param angle: input floating-point array of angles of 2D vectors. + + :param x: output array of x-coordinates of 2D vectors; it has the same size and type as ``angle``. + + :param y: output array of y-coordinates of 2D vectors; it has the same size and type as ``angle``. + + :param angleInDegrees: when true, the input angles are measured in degrees, otherwise, they are measured in radians. + +The function ``polarToCart`` calculates the Cartesian coordinates of each 2D vector represented by the corresponding elements of ``magnitude`` and ``angle`` : + +.. math:: + + \begin{array}{l} \texttt{x} (I) = \texttt{magnitude} (I) \cos ( \texttt{angle} (I)) \\ \texttt{y} (I) = \texttt{magnitude} (I) \sin ( \texttt{angle} (I)) \\ \end{array} + +The relative accuracy of the estimated coordinates is about ``1e-6``. + +.. seealso:: + + :ocv:func:`cartToPolar`, + :ocv:func:`magnitude`, + :ocv:func:`phase`, + :ocv:func:`exp`, + :ocv:func:`log`, + :ocv:func:`pow`, + :ocv:func:`sqrt` + + + +pow +--- +Raises every array element to a power. + +.. ocv:function:: void pow( InputArray src, double power, OutputArray dst ) + +.. ocv:pyfunction:: cv2.pow(src, power[, dst]) -> dst + +.. ocv:cfunction:: void cvPow( const CvArr* src, CvArr* dst, double power) +.. ocv:pyoldfunction:: cv.Pow(src, dst, power)-> None + + :param src: input array. + + :param power: exponent of power. + + :param dst: output array of the same size and type as ``src``. + +The function ``pow`` raises every element of the input array to ``power`` : + +.. math:: + + \texttt{dst} (I) = \fork{\texttt{src}(I)^power}{if \texttt{power} is integer}{|\texttt{src}(I)|^power}{otherwise} + +So, for a non-integer power exponent, the absolute values of input array elements are used. However, it is possible to get true values for negative values using some extra operations. In the example below, computing the 5th root of array ``src`` shows: :: + + Mat mask = src < 0; + pow(src, 1./5, dst); + subtract(Scalar::all(0), dst, dst, mask); + + +For some values of ``power`` , such as integer values, 0.5 and -0.5, specialized faster algorithms are used. + +Special values (NaN, Inf) are not handled. + +.. seealso:: + + :ocv:func:`sqrt`, + :ocv:func:`exp`, + :ocv:func:`log`, + :ocv:func:`cartToPolar`, + :ocv:func:`polarToCart` + + + +RNG +--- + +.. ocv:class:: RNG + +Random number generator. It encapsulates the state (currently, a 64-bit integer) and has methods to return scalar random values and to fill arrays with random values. Currently it supports uniform and Gaussian (normal) distributions. The generator uses Multiply-With-Carry algorithm, introduced by G. Marsaglia ( +http://en.wikipedia.org/wiki/Multiply-with-carry +). Gaussian-distribution random numbers are generated using the Ziggurat algorithm ( +http://en.wikipedia.org/wiki/Ziggurat_algorithm +), introduced by G. Marsaglia and W. W. Tsang. + + + +RNG::RNG +------------ +The constructors + +.. ocv:function:: RNG::RNG() + +.. ocv:function:: RNG::RNG(uint64 state) + + :param state: 64-bit value used to initialize the RNG. + +These are the RNG constructors. The first form sets the state to some pre-defined value, equal to ``2**32-1`` in the current implementation. The second form sets the state to the specified value. If you passed ``state=0`` , the constructor uses the above default value instead to avoid the singular random number sequence, consisting of all zeros. + + + +RNG::next +------------- +Returns the next random number. + +.. ocv:function:: unsigned RNG::next() + +The method updates the state using the MWC algorithm and returns the next 32-bit random number. + + + +RNG::operator T +--------------- +Returns the next random number of the specified type. + +.. ocv:function:: RNG::operator uchar() + +.. ocv:function:: RNG::operator schar() + +.. ocv:function:: RNG::operator ushort() + +.. ocv:function:: RNG::operator short() + +.. ocv:function:: RNG::operator int() + +.. ocv:function:: RNG::operator unsigned() + +.. ocv:function:: RNG::operator float() + +.. ocv:function:: RNG::operator double() + +Each of the methods updates the state using the MWC algorithm and returns the next random number of the specified type. In case of integer types, the returned number is from the available value range for the specified type. In case of floating-point types, the returned value is from ``[0,1)`` range. + + + +RNG::operator () +-------------------- +Returns the next random number. + +.. ocv:function:: unsigned RNG::operator ()() + +.. ocv:function:: unsigned RNG::operator ()(unsigned N) + + :param N: upper non-inclusive boundary of the returned random number. + +The methods transform the state using the MWC algorithm and return the next random number. The first form is equivalent to +:ocv:func:`RNG::next` . The second form returns the random number modulo ``N`` , which means that the result is in the range ``[0, N)`` . + + + +RNG::uniform +---------------- +Returns the next random number sampled from the uniform distribution. + +.. ocv:function:: int RNG::uniform(int a, int b) + +.. ocv:function:: float RNG::uniform(float a, float b) + +.. ocv:function:: double RNG::uniform(double a, double b) + + :param a: lower inclusive boundary of the returned random numbers. + + :param b: upper non-inclusive boundary of the returned random numbers. + +The methods transform the state using the MWC algorithm and return the next uniformly-distributed random number of the specified type, deduced from the input parameter type, from the range ``[a, b)`` . There is a nuance illustrated by the following sample: :: + + RNG rng; + + // always produces 0 + double a = rng.uniform(0, 1); + + // produces double from [0, 1) + double a1 = rng.uniform((double)0, (double)1); + + // produces float from [0, 1) + double b = rng.uniform(0.f, 1.f); + + // produces double from [0, 1) + double c = rng.uniform(0., 1.); + + // may cause compiler error because of ambiguity: + // RNG::uniform(0, (int)0.999999)? or RNG::uniform((double)0, 0.99999)? + double d = rng.uniform(0, 0.999999); + + +The compiler does not take into account the type of the variable to which you assign the result of ``RNG::uniform`` . The only thing that matters to the compiler is the type of ``a`` and ``b`` parameters. So, if you want a floating-point random number, but the range boundaries are integer numbers, either put dots in the end, if they are constants, or use explicit type cast operators, as in the ``a1`` initialization above. + + + +RNG::gaussian +----------------- +Returns the next random number sampled from the Gaussian distribution. + +.. ocv:function:: double RNG::gaussian(double sigma) + + :param sigma: standard deviation of the distribution. + +The method transforms the state using the MWC algorithm and returns the next random number from the Gaussian distribution ``N(0,sigma)`` . That is, the mean value of the returned random numbers is zero and the standard deviation is the specified ``sigma`` . + + + +RNG::fill +------------- +Fills arrays with random numbers. + +.. ocv:function:: void RNG::fill( InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange=false ) + + :param mat: 2D or N-dimensional matrix; currently matrices with more than 4 channels are not supported by the methods, use :ocv:func:`Mat::reshape` as a possible workaround. + + :param distType: distribution type, ``RNG::UNIFORM`` or ``RNG::NORMAL``. + + :param a: first distribution parameter; in case of the uniform distribution, this is an inclusive lower boundary, in case of the normal distribution, this is a mean value. + + :param b: second distribution parameter; in case of the uniform distribution, this is a non-inclusive upper boundary, in case of the normal distribution, this is a standard deviation (diagonal of the standard deviation matrix or the full standard deviation matrix). + + :param saturateRange: pre-saturation flag; for uniform distribution only; if true, the method will first convert a and b to the acceptable value range (according to the mat datatype) and then will generate uniformly distributed random numbers within the range ``[saturate(a), saturate(b))``, if ``saturateRange=false``, the method will generate uniformly distributed random numbers in the original range ``[a, b)`` and then will saturate them, it means, for example, that ``theRNG().fill(mat_8u, RNG::UNIFORM, -DBL_MAX, DBL_MAX)`` will likely produce array mostly filled with 0's and 255's, since the range ``(0, 255)`` is significantly smaller than ``[-DBL_MAX, DBL_MAX)``. + +Each of the methods fills the matrix with the random values from the specified distribution. As the new numbers are generated, the RNG state is updated accordingly. In case of multiple-channel images, every channel is filled independently, which means that RNG cannot generate samples from the multi-dimensional Gaussian distribution with non-diagonal covariance matrix directly. To do that, the method generates samples from multi-dimensional standard Gaussian distribution with zero mean and identity covariation matrix, and then transforms them using :ocv:func:`transform` to get samples from the specified Gaussian distribution. + +randu +----- +Generates a single uniformly-distributed random number or an array of random numbers. + +.. ocv:function:: template _Tp randu() + +.. ocv:function:: void randu( InputOutputArray dst, InputArray low, InputArray high ) + +.. ocv:pyfunction:: cv2.randu(dst, low, high) -> None + + :param dst: output array of random numbers; the array must be pre-allocated. + + :param low: inclusive lower boundary of the generated random numbers. + + :param high: exclusive upper boundary of the generated random numbers. + +The template functions ``randu`` generate and return the next uniformly-distributed random value of the specified type. ``randu()`` is an equivalent to ``(int)theRNG();`` , and so on. See +:ocv:class:`RNG` description. + +The second non-template variant of the function fills the matrix ``dst`` with uniformly-distributed random numbers from the specified range: + +.. math:: + + \texttt{low} _c \leq \texttt{dst} (I)_c < \texttt{high} _c + +.. seealso:: + + :ocv:class:`RNG`, + :ocv:func:`randn`, + :ocv:func:`theRNG` + + + +randn +----- +Fills the array with normally distributed random numbers. + +.. ocv:function:: void randn( InputOutputArray dst, InputArray mean, InputArray stddev ) + +.. ocv:pyfunction:: cv2.randn(dst, mean, stddev) -> None + + :param dst: output array of random numbers; the array must be pre-allocated and have 1 to 4 channels. + + :param mean: mean value (expectation) of the generated random numbers. + + :param stddev: standard deviation of the generated random numbers; it can be either a vector (in which case a diagonal standard deviation matrix is assumed) or a square matrix. + +The function ``randn`` fills the matrix ``dst`` with normally distributed random numbers with the specified mean vector and the standard deviation matrix. The generated random numbers are clipped to fit the value range of the output array data type. + +.. seealso:: + + :ocv:class:`RNG`, + :ocv:func:`randu` + + + +randShuffle +----------- +Shuffles the array elements randomly. + +.. ocv:function:: void randShuffle( InputOutputArray dst, double iterFactor=1., RNG* rng=0 ) + +.. ocv:pyfunction:: cv2.randShuffle(dst[, iterFactor]) -> None + + :param dst: input/output numerical 1D array. + + :param iterFactor: scale factor that determines the number of random swap operations (see the details below). + + :param rng: optional random number generator used for shuffling; if it is zero, :ocv:func:`theRNG` () is used instead. + +The function ``randShuffle`` shuffles the specified 1D array by randomly choosing pairs of elements and swapping them. The number of such swap operations will be ``dst.rows*dst.cols*iterFactor`` . + +.. seealso:: + + :ocv:class:`RNG`, + :ocv:func:`sort` + + + +reduce +------ +Reduces a matrix to a vector. + +.. ocv:function:: void reduce( InputArray src, OutputArray dst, int dim, int rtype, int dtype=-1 ) + +.. ocv:pyfunction:: cv2.reduce(src, dim, rtype[, dst[, dtype]]) -> dst + +.. ocv:cfunction:: void cvReduce(const CvArr* src, CvArr* dst, int dim=-1, int op=CV_REDUCE_SUM) +.. ocv:pyoldfunction:: cv.Reduce(src, dst, dim=-1, op=CV_REDUCE_SUM)-> None + + :param src: input 2D matrix. + + :param dst: output vector. Its size and type is defined by ``dim`` and ``dtype`` parameters. + + :param dim: dimension index along which the matrix is reduced. 0 means that the matrix is reduced to a single row. 1 means that the matrix is reduced to a single column. + + :param rtype: reduction operation that could be one of the following: + + * **CV_REDUCE_SUM**: the output is the sum of all rows/columns of the matrix. + + * **CV_REDUCE_AVG**: the output is the mean vector of all rows/columns of the matrix. + + * **CV_REDUCE_MAX**: the output is the maximum (column/row-wise) of all rows/columns of the matrix. + + * **CV_REDUCE_MIN**: the output is the minimum (column/row-wise) of all rows/columns of the matrix. + + :param dtype: when negative, the output vector will have the same type as the input matrix, otherwise, its type will be ``CV_MAKE_TYPE(CV_MAT_DEPTH(dtype), src.channels())``. + +The function ``reduce`` reduces the matrix to a vector by treating the matrix rows/columns as a set of 1D vectors and performing the specified operation on the vectors until a single row/column is obtained. For example, the function can be used to compute horizontal and vertical projections of a raster image. In case of ``CV_REDUCE_SUM`` and ``CV_REDUCE_AVG`` , the output may have a larger element bit-depth to preserve accuracy. And multi-channel arrays are also supported in these two reduction modes. + +.. seealso:: :ocv:func:`repeat` + + + +repeat +------ +Fills the output array with repeated copies of the input array. + +.. ocv:function:: void repeat(InputArray src, int ny, int nx, OutputArray dst) + +.. ocv:function:: Mat repeat( const Mat& src, int ny, int nx ) + +.. ocv:pyfunction:: cv2.repeat(src, ny, nx[, dst]) -> dst + +.. ocv:cfunction:: void cvRepeat(const CvArr* src, CvArr* dst) + +.. ocv:pyoldfunction:: cv.Repeat(src, dst)-> None + + :param src: input array to replicate. + + :param dst: output array of the same type as ``src``. + + :param ny: Flag to specify how many times the ``src`` is repeated along the vertical axis. + + :param nx: Flag to specify how many times the ``src`` is repeated along the horizontal axis. + +The functions +:ocv:func:`repeat` duplicate the input array one or more times along each of the two axes: + +.. math:: + + \texttt{dst} _{ij}= \texttt{src} _{i\mod src.rows, \; j\mod src.cols } + +The second variant of the function is more convenient to use with +:ref:`MatrixExpressions` . + +.. seealso:: + + :ocv:func:`reduce`, + :ref:`MatrixExpressions` + + + +scaleAdd +-------- +Calculates the sum of a scaled array and another array. + +.. ocv:function:: void scaleAdd( InputArray src1, double alpha, InputArray src2, OutputArray dst ) + +.. ocv:pyfunction:: cv2.scaleAdd(src1, alpha, src2[, dst]) -> dst + +.. ocv:cfunction:: void cvScaleAdd(const CvArr* src1, CvScalar scale, const CvArr* src2, CvArr* dst) +.. ocv:pyoldfunction:: cv.ScaleAdd(src1, scale, src2, dst)-> None + + :param src1: first input array. + + :param scale: scale factor for the first array. + + :param src2: second input array of the same size and type as ``src1``. + + :param dst: output array of the same size and type as ``src1``. + +The function ``scaleAdd`` is one of the classical primitive linear algebra operations, known as ``DAXPY`` or ``SAXPY`` in `BLAS `_. It calculates the sum of a scaled array and another array: + +.. math:: + + \texttt{dst} (I)= \texttt{scale} \cdot \texttt{src1} (I) + \texttt{src2} (I) + +The function can also be emulated with a matrix expression, for example: :: + + Mat A(3, 3, CV_64F); + ... + A.row(0) = A.row(1)*2 + A.row(2); + + +.. seealso:: + + :ocv:func:`add`, + :ocv:func:`addWeighted`, + :ocv:func:`subtract`, + :ocv:func:`Mat::dot`, + :ocv:func:`Mat::convertTo`, + :ref:`MatrixExpressions` + + + +setIdentity +----------- +Initializes a scaled identity matrix. + +.. ocv:function:: void setIdentity( InputOutputArray mtx, const Scalar& s=Scalar(1) ) + +.. ocv:pyfunction:: cv2.setIdentity(mtx[, s]) -> None + +.. ocv:cfunction:: void cvSetIdentity(CvArr* mat, CvScalar value=cvRealScalar(1)) + +.. ocv:pyoldfunction:: cv.SetIdentity(mat, value=1)-> None + + :param mtx: matrix to initialize (not necessarily square). + + :param value: value to assign to diagonal elements. + +The function +:ocv:func:`setIdentity` initializes a scaled identity matrix: + +.. math:: + + \texttt{mtx} (i,j)= \fork{\texttt{value}}{ if $i=j$}{0}{otherwise} + +The function can also be emulated using the matrix initializers and the matrix expressions: :: + + Mat A = Mat::eye(4, 3, CV_32F)*5; + // A will be set to [[5, 0, 0], [0, 5, 0], [0, 0, 5], [0, 0, 0]] + + +.. seealso:: + + :ocv:func:`Mat::zeros`, + :ocv:func:`Mat::ones`, + :ref:`MatrixExpressions`, + :ocv:func:`Mat::setTo`, + :ocv:func:`Mat::operator=` + + + +solve +----- +Solves one or more linear systems or least-squares problems. + +.. ocv:function:: bool solve(InputArray src1, InputArray src2, OutputArray dst, int flags=DECOMP_LU) + +.. ocv:pyfunction:: cv2.solve(src1, src2[, dst[, flags]]) -> retval, dst + +.. ocv:cfunction:: int cvSolve(const CvArr* src1, const CvArr* src2, CvArr* dst, int method=CV_LU) +.. ocv:pyoldfunction:: cv.Solve(A, B, X, method=CV_LU)-> None + + :param src1: input matrix on the left-hand side of the system. + + :param src2: input matrix on the right-hand side of the system. + + :param dst: output solution. + + :param flags: solution (matrix inversion) method. + + * **DECOMP_LU** Gaussian elimination with optimal pivot element chosen. + + * **DECOMP_CHOLESKY** Cholesky :math:`LL^T` factorization; the matrix ``src1`` must be symmetrical and positively defined. + + * **DECOMP_EIG** eigenvalue decomposition; the matrix ``src1`` must be symmetrical. + + * **DECOMP_SVD** singular value decomposition (SVD) method; the system can be over-defined and/or the matrix ``src1`` can be singular. + + * **DECOMP_QR** QR factorization; the system can be over-defined and/or the matrix ``src1`` can be singular. + + * **DECOMP_NORMAL** while all the previous flags are mutually exclusive, this flag can be used together with any of the previous; it means that the normal equations :math:`\texttt{src1}^T\cdot\texttt{src1}\cdot\texttt{dst}=\texttt{src1}^T\texttt{src2}` are solved instead of the original system :math:`\texttt{src1}\cdot\texttt{dst}=\texttt{src2}` . + +The function ``solve`` solves a linear system or least-squares problem (the latter is possible with SVD or QR methods, or by specifying the flag ``DECOMP_NORMAL`` ): + +.. math:: + + \texttt{dst} = \arg \min _X \| \texttt{src1} \cdot \texttt{X} - \texttt{src2} \| + +If ``DECOMP_LU`` or ``DECOMP_CHOLESKY`` method is used, the function returns 1 if ``src1`` (or +:math:`\texttt{src1}^T\texttt{src1}` ) is non-singular. Otherwise, it returns 0. In the latter case, ``dst`` is not valid. Other methods find a pseudo-solution in case of a singular left-hand side part. + +.. note:: If you want to find a unity-norm solution of an under-defined singular system :math:`\texttt{src1}\cdot\texttt{dst}=0` , the function ``solve`` will not do the work. Use :ocv:func:`SVD::solveZ` instead. + +.. seealso:: + + :ocv:func:`invert`, + :ocv:class:`SVD`, + :ocv:func:`eigen` + + + +solveCubic +-------------- +Finds the real roots of a cubic equation. + +.. ocv:function:: int solveCubic( InputArray coeffs, OutputArray roots ) + +.. ocv:pyfunction:: cv2.solveCubic(coeffs[, roots]) -> retval, roots + +.. ocv:cfunction:: int cvSolveCubic( const CvMat* coeffs, CvMat* roots ) + +.. ocv:pyoldfunction:: cv.SolveCubic(coeffs, roots)-> None + + :param coeffs: equation coefficients, an array of 3 or 4 elements. + + :param roots: output array of real roots that has 1 or 3 elements. + +The function ``solveCubic`` finds the real roots of a cubic equation: + +* if ``coeffs`` is a 4-element vector: + +.. math:: + + \texttt{coeffs} [0] x^3 + \texttt{coeffs} [1] x^2 + \texttt{coeffs} [2] x + \texttt{coeffs} [3] = 0 + +* if ``coeffs`` is a 3-element vector: + +.. math:: + + x^3 + \texttt{coeffs} [0] x^2 + \texttt{coeffs} [1] x + \texttt{coeffs} [2] = 0 + +The roots are stored in the ``roots`` array. + + + +solvePoly +--------- +Finds the real or complex roots of a polynomial equation. + +.. ocv:function:: double solvePoly( InputArray coeffs, OutputArray roots, int maxIters=300 ) + +.. ocv:pyfunction:: cv2.solvePoly(coeffs[, roots[, maxIters]]) -> retval, roots + + :param coeffs: array of polynomial coefficients. + + :param roots: output (complex) array of roots. + + :param maxIters: maximum number of iterations the algorithm does. + +The function ``solvePoly`` finds real and complex roots of a polynomial equation: + +.. math:: + + \texttt{coeffs} [n] x^{n} + \texttt{coeffs} [n-1] x^{n-1} + ... + \texttt{coeffs} [1] x + \texttt{coeffs} [0] = 0 + + + +sort +---- +Sorts each row or each column of a matrix. + +.. ocv:function:: void sort(InputArray src, OutputArray dst, int flags) + +.. ocv:pyfunction:: cv2.sort(src, flags[, dst]) -> dst + + :param src: input single-channel array. + + :param dst: output array of the same size and type as ``src``. + + :param flags: operation flags, a combination of the following values: + + * **CV_SORT_EVERY_ROW** each matrix row is sorted independently. + + * **CV_SORT_EVERY_COLUMN** each matrix column is sorted independently; this flag and the previous one are mutually exclusive. + + * **CV_SORT_ASCENDING** each matrix row is sorted in the ascending order. + + * **CV_SORT_DESCENDING** each matrix row is sorted in the descending order; this flag and the previous one are also mutually exclusive. + +The function ``sort`` sorts each matrix row or each matrix column in ascending or descending order. So you should pass two operation flags to get desired behaviour. If you want to sort matrix rows or columns lexicographically, you can use STL ``std::sort`` generic function with the proper comparison predicate. + +.. seealso:: + + :ocv:func:`sortIdx`, + :ocv:func:`randShuffle` + + + +sortIdx +------- +Sorts each row or each column of a matrix. + +.. ocv:function:: void sortIdx(InputArray src, OutputArray dst, int flags) + +.. ocv:pyfunction:: cv2.sortIdx(src, flags[, dst]) -> dst + + :param src: input single-channel array. + + :param dst: output integer array of the same size as ``src``. + + :param flags: operation flags that could be a combination of the following values: + + * **CV_SORT_EVERY_ROW** each matrix row is sorted independently. + + * **CV_SORT_EVERY_COLUMN** each matrix column is sorted independently; this flag and the previous one are mutually exclusive. + + * **CV_SORT_ASCENDING** each matrix row is sorted in the ascending order. + + * **CV_SORT_DESCENDING** each matrix row is sorted in the descending order; his flag and the previous one are also mutually exclusive. + +The function ``sortIdx`` sorts each matrix row or each matrix column in the ascending or descending order. So you should pass two operation flags to get desired behaviour. Instead of reordering the elements themselves, it stores the indices of sorted elements in the output array. For example: :: + + Mat A = Mat::eye(3,3,CV_32F), B; + sortIdx(A, B, CV_SORT_EVERY_ROW + CV_SORT_ASCENDING); + // B will probably contain + // (because of equal elements in A some permutations are possible): + // [[1, 2, 0], [0, 2, 1], [0, 1, 2]] + + +.. seealso:: + + :ocv:func:`sort`, + :ocv:func:`randShuffle` + + + +split +----- +Divides a multi-channel array into several single-channel arrays. + +.. ocv:function:: void split( const Mat& src, Mat* mvbegin ) + +.. ocv:function:: void split( InputArray m, OutputArrayOfArrays mv ) + +.. ocv:pyfunction:: cv2.split(m[, mv]) -> mv + +.. ocv:cfunction:: void cvSplit(const CvArr* src, CvArr* dst0, CvArr* dst1, CvArr* dst2, CvArr* dst3) + +.. ocv:pyoldfunction:: cv.Split(src, dst0, dst1, dst2, dst3)-> None + + :param src: input multi-channel array. + + :param mv: output array or vector of arrays; in the first variant of the function the number of arrays must match ``src.channels()``; the arrays themselves are reallocated, if needed. + +The functions ``split`` split a multi-channel array into separate single-channel arrays: + +.. math:: + + \texttt{mv} [c](I) = \texttt{src} (I)_c + +If you need to extract a single channel or do some other sophisticated channel permutation, use +:ocv:func:`mixChannels` . + +.. seealso:: + + :ocv:func:`merge`, + :ocv:func:`mixChannels`, + :ocv:func:`cvtColor` + + + +sqrt +---- +Calculates a square root of array elements. + +.. ocv:function:: void sqrt(InputArray src, OutputArray dst) + +.. ocv:pyfunction:: cv2.sqrt(src[, dst]) -> dst + +.. ocv:cfunction:: float cvSqrt(float value) +.. ocv:pyoldfunction:: cv.Sqrt(value)-> float + + :param src: input floating-point array. + + :param dst: output array of the same size and type as ``src``. + +The functions ``sqrt`` calculate a square root of each input array element. In case of multi-channel arrays, each channel is processed independently. The accuracy is approximately the same as of the built-in ``std::sqrt`` . + +.. seealso:: + + :ocv:func:`pow`, + :ocv:func:`magnitude` + + + +subtract +-------- +Calculates the per-element difference between two arrays or array and a scalar. + +.. ocv:function:: void subtract(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray(), int dtype=-1) + +.. ocv:pyfunction:: cv2.subtract(src1, src2[, dst[, mask[, dtype]]]) -> dst + +.. ocv:cfunction:: void cvSub(const CvArr* src1, const CvArr* src2, CvArr* dst, const CvArr* mask=NULL) +.. ocv:cfunction:: void cvSubRS( const CvArr* src, CvScalar value, CvArr* dst, const CvArr* mask=NULL ) +.. ocv:cfunction:: void cvSubS( const CvArr* src, CvScalar value, CvArr* dst, const CvArr* mask=NULL ) + +.. ocv:pyoldfunction:: cv.Sub(src1, src2, dst, mask=None) -> None +.. ocv:pyoldfunction:: cv.SubRS(src, value, dst, mask=None) -> None +.. ocv:pyoldfunction:: cv.SubS(src, value, dst, mask=None) -> None + + :param src1: first input array or a scalar. + + :param src2: second input array or a scalar. + + :param dst: output array of the same size and the same number of channels as the input array. + + :param mask: optional operation mask; this is an 8-bit single channel array that specifies elements of the output array to be changed. + + :param dtype: optional depth of the output array (see the details below). + +The function ``subtract`` calculates: + + * + Difference between two arrays, when both input arrays have the same size and the same number of channels: + + .. math:: + + \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) - \texttt{src2}(I)) \quad \texttt{if mask}(I) \ne0 + + * + Difference between an array and a scalar, when ``src2`` is constructed from ``Scalar`` or has the same number of elements as ``src1.channels()``: + + .. math:: + + \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) - \texttt{src2} ) \quad \texttt{if mask}(I) \ne0 + + * + Difference between a scalar and an array, when ``src1`` is constructed from ``Scalar`` or has the same number of elements as ``src2.channels()``: + + .. math:: + + \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1} - \texttt{src2}(I) ) \quad \texttt{if mask}(I) \ne0 + + * + The reverse difference between a scalar and an array in the case of ``SubRS``: + + .. math:: + + \texttt{dst}(I) = \texttt{saturate} ( \texttt{src2} - \texttt{src1}(I) ) \quad \texttt{if mask}(I) \ne0 + +where ``I`` is a multi-dimensional index of array elements. In case of multi-channel arrays, each channel is processed independently. + +The first function in the list above can be replaced with matrix expressions: :: + + dst = src1 - src2; + dst -= src1; // equivalent to subtract(dst, src1, dst); + +The input arrays and the output array can all have the same or different depths. For example, you can subtract to 8-bit unsigned arrays and store the difference in a 16-bit signed array. Depth of the output array is determined by ``dtype`` parameter. In the second and third cases above, as well as in the first case, when ``src1.depth() == src2.depth()``, ``dtype`` can be set to the default ``-1``. In this case the output array will have the same depth as the input array, be it ``src1``, ``src2`` or both. + +.. note:: Saturation is not applied when the output array has the depth ``CV_32S``. You may even get result of an incorrect sign in the case of overflow. + +.. seealso:: + + :ocv:func:`add`, + :ocv:func:`addWeighted`, + :ocv:func:`scaleAdd`, + :ocv:func:`Mat::convertTo`, + :ref:`MatrixExpressions` + + + +SVD +--- +.. ocv:class:: SVD + +Class for computing Singular Value Decomposition of a floating-point matrix. The Singular Value Decomposition is used to solve least-square problems, under-determined linear systems, invert matrices, compute condition numbers, and so on. + +For a faster operation, you can pass ``flags=SVD::MODIFY_A|...`` to modify the decomposed matrix when it is not necessary to preserve it. If you want to compute a condition number of a matrix or an absolute value of its determinant, you do not need ``u`` and ``vt`` . You can pass ``flags=SVD::NO_UV|...`` . Another flag ``FULL_UV`` indicates that full-size ``u`` and ``vt`` must be computed, which is not necessary most of the time. + +.. seealso:: + + :ocv:func:`invert`, + :ocv:func:`solve`, + :ocv:func:`eigen`, + :ocv:func:`determinant` + + + +SVD::SVD +-------- +The constructors. + +.. ocv:function:: SVD::SVD() + +.. ocv:function:: SVD::SVD( InputArray src, int flags=0 ) + + :param src: decomposed matrix. + + :param flags: operation flags. + + * **SVD::MODIFY_A** use the algorithm to modify the decomposed matrix; it can save space and speed up processing. + + * **SVD::NO_UV** indicates that only a vector of singular values ``w`` is to be processed, while ``u`` and ``vt`` will be set to empty matrices. + + * **SVD::FULL_UV** when the matrix is not square, by default the algorithm produces ``u`` and ``vt`` matrices of sufficiently large size for the further ``A`` reconstruction; if, however, ``FULL_UV`` flag is specified, ``u`` and ``vt``will be full-size square orthogonal matrices. + +The first constructor initializes an empty ``SVD`` structure. The second constructor initializes an empty ``SVD`` structure and then calls +:ocv:funcx:`SVD::operator()` . + + +SVD::operator () +---------------- +Performs SVD of a matrix. + +.. ocv:function:: SVD& SVD::operator()( InputArray src, int flags=0 ) + + :param src: decomposed matrix. + + :param flags: operation flags. + + * **SVD::MODIFY_A** use the algorithm to modify the decomposed matrix; it can save space and speed up processing. + + * **SVD::NO_UV** use only singular values; the algorithm does not compute ``u`` and ``vt`` matrices. + + * **SVD::FULL_UV** when the matrix is not square, by default the algorithm produces ``u`` and ``vt`` matrices of sufficiently large size for the further ``A`` reconstruction; if, however, the ``FULL_UV`` flag is specified, ``u`` and ``vt`` are full-size square orthogonal matrices. + +The operator performs the singular value decomposition of the supplied matrix. The ``u``,``vt`` , and the vector of singular values ``w`` are stored in the structure. The same ``SVD`` structure can be reused many times with different matrices. Each time, if needed, the previous ``u``,``vt`` , and ``w`` are reclaimed and the new matrices are created, which is all handled by +:ocv:func:`Mat::create` . + + +SVD::compute +------------ +Performs SVD of a matrix + +.. ocv:function:: static void SVD::compute( InputArray src, OutputArray w, OutputArray u, OutputArray vt, int flags=0 ) + +.. ocv:function:: static void SVD::compute( InputArray src, OutputArray w, int flags=0 ) + +.. ocv:pyfunction:: cv2.SVDecomp(src[, w[, u[, vt[, flags]]]]) -> w, u, vt + +.. ocv:cfunction:: void cvSVD( CvArr* A, CvArr* W, CvArr* U=NULL, CvArr* V=NULL, int flags=0 ) + +.. ocv:pyoldfunction:: cv.SVD(A, W, U=None, V=None, flags=0) -> None + + :param src: decomposed matrix + + :param w: calculated singular values + + :param u: calculated left singular vectors + + :param V: calculated right singular vectors + + :param vt: transposed matrix of right singular values + + :param flags: operation flags - see :ocv:func:`SVD::SVD`. + +The methods/functions perform SVD of matrix. Unlike ``SVD::SVD`` constructor and ``SVD::operator()``, they store the results to the user-provided matrices. :: + + Mat A, w, u, vt; + SVD::compute(A, w, u, vt); + + +SVD::solveZ +----------- +Solves an under-determined singular linear system. + +.. ocv:function:: static void SVD::solveZ( InputArray src, OutputArray dst ) + + :param src: left-hand-side matrix. + + :param dst: found solution. + +The method finds a unit-length solution ``x`` of a singular linear system +``A*x = 0``. Depending on the rank of ``A``, there can be no solutions, a single solution or an infinite number of solutions. In general, the algorithm solves the following problem: + +.. math:: + + dst = \arg \min _{x: \| x \| =1} \| src \cdot x \| + + +SVD::backSubst +-------------- +Performs a singular value back substitution. + +.. ocv:function:: void SVD::backSubst( InputArray rhs, OutputArray dst ) const + +.. ocv:function:: static void SVD::backSubst( InputArray w, InputArray u, InputArray vt, InputArray rhs, OutputArray dst ) + +.. ocv:pyfunction:: cv2.SVBackSubst(w, u, vt, rhs[, dst]) -> dst + +.. ocv:cfunction:: void cvSVBkSb( const CvArr* W, const CvArr* U, const CvArr* V, const CvArr* B, CvArr* X, int flags ) + +.. ocv:pyoldfunction:: cv.SVBkSb(W, U, V, B, X, flags) -> None + + :param w: singular values + + :param u: left singular vectors + + :param V: right singular vectors + + :param vt: transposed matrix of right singular vectors. + + :param rhs: right-hand side of a linear system ``(u*w*v')*dst = rhs`` to be solved, where ``A`` has been previously decomposed. + + :param dst: found solution of the system. + +The method calculates a back substitution for the specified right-hand side: + +.. math:: + + \texttt{x} = \texttt{vt} ^T \cdot diag( \texttt{w} )^{-1} \cdot \texttt{u} ^T \cdot \texttt{rhs} \sim \texttt{A} ^{-1} \cdot \texttt{rhs} + +Using this technique you can either get a very accurate solution of the convenient linear system, or the best (in the least-squares terms) pseudo-solution of an overdetermined linear system. + +.. note:: Explicit SVD with the further back substitution only makes sense if you need to solve many linear systems with the same left-hand side (for example, ``src`` ). If all you need is to solve a single system (possibly with multiple ``rhs`` immediately available), simply call :ocv:func:`solve` add pass ``DECOMP_SVD`` there. It does absolutely the same thing. + + + +sum +--- +Calculates the sum of array elements. + +.. ocv:function:: Scalar sum( InputArray src ) + +.. ocv:pyfunction:: cv2.sumElems(src) -> retval + +.. ocv:cfunction:: CvScalar cvSum(const CvArr* arr) + +.. ocv:pyoldfunction:: cv.Sum(arr) -> scalar + + :param arr: input array that must have from 1 to 4 channels. + +The functions ``sum`` calculate and return the sum of array elements, independently for each channel. + +.. seealso:: + + :ocv:func:`countNonZero`, + :ocv:func:`mean`, + :ocv:func:`meanStdDev`, + :ocv:func:`norm`, + :ocv:func:`minMaxLoc`, + :ocv:func:`reduce` + + + +theRNG +------ +Returns the default random number generator. + +.. ocv:function:: RNG& theRNG() + +The function ``theRNG`` returns the default random number generator. For each thread, there is a separate random number generator, so you can use the function safely in multi-thread environments. If you just need to get a single random number using this generator or initialize an array, you can use +:ocv:func:`randu` or +:ocv:func:`randn` instead. But if you are going to generate many random numbers inside a loop, it is much faster to use this function to retrieve the generator and then use ``RNG::operator _Tp()`` . + +.. seealso:: + + :ocv:class:`RNG`, + :ocv:func:`randu`, + :ocv:func:`randn` + + + +trace +----- +Returns the trace of a matrix. + +.. ocv:function:: Scalar trace( InputArray mtx ) + +.. ocv:pyfunction:: cv2.trace(mtx) -> retval + +.. ocv:cfunction:: CvScalar cvTrace(const CvArr* mat) + +.. ocv:pyoldfunction:: cv.Trace(mat) -> scalar + + :param mat: input matrix. + +The function ``trace`` returns the sum of the diagonal elements of the matrix ``mtx`` . + +.. math:: + + \mathrm{tr} ( \texttt{mtx} ) = \sum _i \texttt{mtx} (i,i) + + + +transform +--------- +Performs the matrix transformation of every array element. + +.. ocv:function:: void transform( InputArray src, OutputArray dst, InputArray m ) + +.. ocv:pyfunction:: cv2.transform(src, m[, dst]) -> dst + +.. ocv:cfunction:: void cvTransform( const CvArr* src, CvArr* dst, const CvMat* transmat, const CvMat* shiftvec=NULL ) + +.. ocv:pyoldfunction:: cv.Transform(src, dst, transmat, shiftvec=None)-> None + + :param src: input array that must have as many channels (1 to 4) as ``m.cols`` or ``m.cols-1``. + + :param dst: output array of the same size and depth as ``src``; it has as many channels as ``m.rows``. + + :param m: transformation ``2x2`` or ``2x3`` floating-point matrix. + + :param shiftvec: optional translation vector (when ``m`` is ``2x2``) + +The function ``transform`` performs the matrix transformation of every element of the array ``src`` and stores the results in ``dst`` : + +.. math:: + + \texttt{dst} (I) = \texttt{m} \cdot \texttt{src} (I) + +(when ``m.cols=src.channels()`` ), or + +.. math:: + + \texttt{dst} (I) = \texttt{m} \cdot [ \texttt{src} (I); 1] + +(when ``m.cols=src.channels()+1`` ) + +Every element of the ``N`` -channel array ``src`` is interpreted as ``N`` -element vector that is transformed using +the ``M x N`` or ``M x (N+1)`` matrix ``m`` +to ``M``-element vector - the corresponding element of the output array ``dst`` . + +The function may be used for geometrical transformation of +``N`` -dimensional +points, arbitrary linear color space transformation (such as various kinds of RGB to YUV transforms), shuffling the image channels, and so forth. + +.. seealso:: + + :ocv:func:`perspectiveTransform`, + :ocv:func:`getAffineTransform`, + :ocv:func:`estimateRigidTransform`, + :ocv:func:`warpAffine`, + :ocv:func:`warpPerspective` + + + +transpose +--------- +Transposes a matrix. + +.. ocv:function:: void transpose(InputArray src, OutputArray dst) + +.. ocv:pyfunction:: cv2.transpose(src[, dst]) -> dst + +.. ocv:cfunction:: void cvTranspose(const CvArr* src, CvArr* dst) +.. ocv:pyoldfunction:: cv.Transpose(src, dst)-> None + + :param src: input array. + + :param dst: output array of the same type as ``src``. + +The function :ocv:func:`transpose` transposes the matrix ``src`` : + +.. math:: + + \texttt{dst} (i,j) = \texttt{src} (j,i) + +.. note:: No complex conjugation is done in case of a complex matrix. It it should be done separately if needed. diff --git a/core/doc/pics/ellipse.png b/core/doc/pics/ellipse.png new file mode 100644 index 0000000..2b16c93 Binary files /dev/null and b/core/doc/pics/ellipse.png differ diff --git a/core/doc/pics/memstorage1.png b/core/doc/pics/memstorage1.png new file mode 100644 index 0000000..d4a477c Binary files /dev/null and b/core/doc/pics/memstorage1.png differ diff --git a/core/doc/pics/memstorage2.png b/core/doc/pics/memstorage2.png new file mode 100644 index 0000000..7af0e95 Binary files /dev/null and b/core/doc/pics/memstorage2.png differ diff --git a/core/doc/pics/rotatedrect.png b/core/doc/pics/rotatedrect.png new file mode 100644 index 0000000..344bf49 Binary files /dev/null and b/core/doc/pics/rotatedrect.png differ diff --git a/core/doc/utility_and_system_functions_and_macros.rst b/core/doc/utility_and_system_functions_and_macros.rst new file mode 100644 index 0000000..30577c4 --- /dev/null +++ b/core/doc/utility_and_system_functions_and_macros.rst @@ -0,0 +1,443 @@ +Utility and System Functions and Macros +======================================= + +.. highlight:: cpp + +alignPtr +------------ +Aligns a pointer to the specified number of bytes. + +.. ocv:function:: template _Tp* alignPtr(_Tp* ptr, int n=sizeof(_Tp)) + + :param ptr: Aligned pointer. + + :param n: Alignment size that must be a power of two. + +The function returns the aligned pointer of the same type as the input pointer: + +.. math:: + + \texttt{(\_Tp*)(((size\_t)ptr + n-1) \& -n)} + + + +alignSize +------------- +Aligns a buffer size to the specified number of bytes. + +.. ocv:function:: size_t alignSize(size_t sz, int n) + + :param sz: Buffer size to align. + + :param n: Alignment size that must be a power of two. + +The function returns the minimum number that is greater or equal to ``sz`` and is divisible by ``n`` : + +.. math:: + + \texttt{(sz + n-1) \& -n} + + + +allocate +------------ +Allocates an array of elements. + +.. ocv:function:: template _Tp* allocate(size_t n) + + :param n: Number of elements to allocate. + +The generic function ``allocate`` allocates a buffer for the specified number of elements. For each element, the default constructor is called. + + + +deallocate +-------------- +Deallocates an array of elements. + +.. ocv:function:: template void deallocate(_Tp* ptr, size_t n) + + :param ptr: Pointer to the deallocated buffer. + + :param n: Number of elements in the buffer. + +The generic function ``deallocate`` deallocates the buffer allocated with +:ocv:func:`allocate` . The number of elements must match the number passed to +:ocv:func:`allocate` . + + + +fastAtan2 +--------- +Calculates the angle of a 2D vector in degrees. + +.. ocv:function:: float fastAtan2(float y, float x) + +.. ocv:pyfunction:: cv2.fastAtan2(y, x) -> retval + +.. ocv:cfunction:: float cvFastArctan(float y, float x) +.. ocv:pyoldfunction:: cv.FastArctan(y, x)-> float + + :param x: x-coordinate of the vector. + + :param y: y-coordinate of the vector. + +The function ``fastAtan2`` calculates the full-range angle of an input 2D vector. The angle is measured in degrees and varies from 0 to 360 degrees. The accuracy is about 0.3 degrees. + + +cubeRoot +-------- +Computes the cube root of an argument. + +.. ocv:function:: float cubeRoot(float val) + +.. ocv:pyfunction:: cv2.cubeRoot(val) -> retval + +.. ocv:cfunction:: float cvCbrt( float value ) + +.. ocv:pyoldfunction:: cv.Cbrt(value)-> float + + :param val: A function argument. + +The function ``cubeRoot`` computes :math:`\sqrt[3]{\texttt{val}}`. Negative arguments are handled correctly. NaN and Inf are not handled. The accuracy approaches the maximum possible accuracy for single-precision data. + + +Ceil +----- +Rounds floating-point number to the nearest integer not smaller than the original. + +.. ocv:cfunction:: int cvCeil(double value) +.. ocv:pyoldfunction:: cv.Ceil(value) -> int + + :param value: floating-point number. If the value is outside of ``INT_MIN`` ... ``INT_MAX`` range, the result is not defined. + +The function computes an integer ``i`` such that: + +.. math:: + + i-1 < \texttt{value} \le i + + +Floor +----- +Rounds floating-point number to the nearest integer not larger than the original. + +.. ocv:cfunction:: int cvFloor(double value) +.. ocv:pyoldfunction:: cv.Floor(value) -> int + + :param value: floating-point number. If the value is outside of ``INT_MIN`` ... ``INT_MAX`` range, the result is not defined. + +The function computes an integer ``i`` such that: + +.. math:: + + i \le \texttt{value} < i+1 + + +Round +----- +Rounds floating-point number to the nearest integer + +.. ocv:cfunction:: int cvRound(double value) +.. ocv:pyoldfunction:: cv.Round(value) -> int + + :param value: floating-point number. If the value is outside of ``INT_MIN`` ... ``INT_MAX`` range, the result is not defined. + + +IsInf +----- +Determines if the argument is Infinity. + +.. ocv:cfunction:: int cvIsInf(double value) +.. ocv:pyoldfunction:: cv.IsInf(value)-> int + + :param value: The input floating-point value + +The function returns 1 if the argument is a plus or minus infinity (as defined by IEEE754 standard) and 0 otherwise. + +IsNaN +----- +Determines if the argument is Not A Number. + +.. ocv:cfunction:: int cvIsNaN(double value) +.. ocv:pyoldfunction:: cv.IsNaN(value)-> int + + :param value: The input floating-point value + +The function returns 1 if the argument is Not A Number (as defined by IEEE754 standard), 0 otherwise. + + +CV_Assert +--------- +Checks a condition at runtime and throws exception if it fails + +.. ocv:function:: CV_Assert(expr) + +The macros ``CV_Assert`` (and ``CV_DbgAssert``) evaluate the specified expression. If it is 0, the macros raise an error (see :ocv:func:`error` ). The macro ``CV_Assert`` checks the condition in both Debug and Release configurations while ``CV_DbgAssert`` is only retained in the Debug configuration. + + +error +----- +Signals an error and raises an exception. + +.. ocv:function:: void error( const Exception& exc ) + +.. ocv:cfunction:: void cvError( int status, const char* func_name, const char* err_msg, const char* file_name, int line ) + + :param exc: Exception to throw. + + :param status: Error code. Normally, it is a negative value. The list of pre-defined error codes can be found in ``cxerror.h`` . + + :param err_msg: Text of the error message. + + :param args: ``printf`` -like formatted error message in parentheses. + +The function and the helper macros ``CV_Error`` and ``CV_Error_``: :: + + #define CV_Error( code, msg ) error(...) + #define CV_Error_( code, args ) error(...) + +call the error handler. Currently, the error handler prints the error code ( ``exc.code`` ), the context ( ``exc.file``,``exc.line`` ), and the error message ``exc.err`` to the standard error stream ``stderr`` . In the Debug configuration, it then provokes memory access violation, so that the execution stack and all the parameters can be analyzed by the debugger. In the Release configuration, the exception ``exc`` is thrown. + +The macro ``CV_Error_`` can be used to construct an error message on-fly to include some dynamic information, for example: :: + + // note the extra parentheses around the formatted text message + CV_Error_(CV_StsOutOfRange, + ("the matrix element ( + i, j, mtx.at(i,j))) + + +Exception +--------- +.. ocv:class:: Exception : public std::exception + +Exception class passed to an error. :: + + class Exception + { + public: + // various constructors and the copy operation + Exception() { code = 0; line = 0; } + Exception(int _code, const string& _err, + const string& _func, const string& _file, int _line); + Exception(const Exception& exc); + Exception& operator = (const Exception& exc); + + // the error code + int code; + // the error text message + string err; + // function name where the error happened + string func; + // the source file name where the error happened + string file; + // the source file line where the error happened + int line; + }; + +The class ``Exception`` encapsulates all or almost all necessary information about the error happened in the program. The exception is usually constructed and thrown implicitly via ``CV_Error`` and ``CV_Error_`` macros. See +:ocv:func:`error` . + + + +fastMalloc +-------------- +Allocates an aligned memory buffer. + +.. ocv:function:: void* fastMalloc( size_t bufSize ) + +.. ocv:cfunction:: void* cvAlloc( size_t size ) + + :param size: Allocated buffer size. + +The function allocates the buffer of the specified size and returns it. When the buffer size is 16 bytes or more, the returned buffer is aligned to 16 bytes. + + + +fastFree +------------ +Deallocates a memory buffer. + +.. ocv:function:: void fastFree(void* ptr) +.. ocv:cfunction:: void cvFree( void** pptr ) + + :param ptr: Pointer to the allocated buffer. + + :param pptr: Double pointer to the allocated buffer + +The function deallocates the buffer allocated with :ocv:func:`fastMalloc` . If NULL pointer is passed, the function does nothing. C version of the function clears the pointer ``*pptr`` to avoid problems with double memory deallocation. + + +format +------ +Returns a text string formatted using the ``printf``\ -like expression. + +.. ocv:function:: string format( const char* fmt, ... ) + + :param fmt: ``printf`` -compatible formatting specifiers. + +The function acts like ``sprintf`` but forms and returns an STL string. It can be used to form an error message in the +:ocv:class:`Exception` constructor. + + + +checkHardwareSupport +-------------------- +Returns true if the specified feature is supported by the host hardware. + +.. ocv:function:: bool checkHardwareSupport(int feature) +.. ocv:cfunction:: int cvCheckHardwareSupport(int feature) +.. ocv:pyfunction:: cv2.checkHardwareSupport(feature) -> retval + + :param feature: The feature of interest, one of: + + * ``CV_CPU_MMX`` - MMX + * ``CV_CPU_SSE`` - SSE + * ``CV_CPU_SSE2`` - SSE 2 + * ``CV_CPU_SSE3`` - SSE 3 + * ``CV_CPU_SSSE3`` - SSSE 3 + * ``CV_CPU_SSE4_1`` - SSE 4.1 + * ``CV_CPU_SSE4_2`` - SSE 4.2 + * ``CV_CPU_POPCNT`` - POPCOUNT + * ``CV_CPU_AVX`` - AVX + +The function returns true if the host hardware supports the specified feature. When user calls ``setUseOptimized(false)``, the subsequent calls to ``checkHardwareSupport()`` will return false until ``setUseOptimized(true)`` is called. This way user can dynamically switch on and off the optimized code in OpenCV. + +getNumThreads +----------------- +Returns the number of threads used by OpenCV. + +.. ocv:function:: int getNumThreads() + +The function returns the number of threads that is used by OpenCV. + +.. seealso:: + :ocv:func:`setNumThreads`, + :ocv:func:`getThreadNum` + + + +getThreadNum +---------------- +Returns the index of the currently executed thread. + +.. ocv:function:: int getThreadNum() + +The function returns a 0-based index of the currently executed thread. The function is only valid inside a parallel OpenMP region. When OpenCV is built without OpenMP support, the function always returns 0. + +.. seealso:: + :ocv:func:`setNumThreads`, + :ocv:func:`getNumThreads` . + + + +getTickCount +---------------- +Returns the number of ticks. + +.. ocv:function:: int64 getTickCount() + +.. ocv:pyfunction:: cv2.getTickCount() -> retval + +The function returns the number of ticks after the certain event (for example, when the machine was turned on). +It can be used to initialize +:ocv:func:`RNG` or to measure a function execution time by reading the tick count before and after the function call. See also the tick frequency. + + + +getTickFrequency +-------------------- +Returns the number of ticks per second. + +.. ocv:function:: double getTickFrequency() + +.. ocv:pyfunction:: cv2.getTickFrequency() -> retval + +The function returns the number of ticks per second. +That is, the following code computes the execution time in seconds: :: + + double t = (double)getTickCount(); + // do something ... + t = ((double)getTickCount() - t)/getTickFrequency(); + + + +getCPUTickCount +---------------- +Returns the number of CPU ticks. + +.. ocv:function:: int64 getCPUTickCount() + +.. ocv:pyfunction:: cv2.getCPUTickCount() -> retval + +The function returns the current number of CPU ticks on some architectures (such as x86, x64, PowerPC). On other platforms the function is equivalent to ``getTickCount``. It can also be used for very accurate time measurements, as well as for RNG initialization. Note that in case of multi-CPU systems a thread, from which ``getCPUTickCount`` is called, can be suspended and resumed at another CPU with its own counter. So, theoretically (and practically) the subsequent calls to the function do not necessary return the monotonously increasing values. Also, since a modern CPU varies the CPU frequency depending on the load, the number of CPU clocks spent in some code cannot be directly converted to time units. Therefore, ``getTickCount`` is generally a preferable solution for measuring execution time. + + +saturate_cast +------------- +Template function for accurate conversion from one primitive type to another. + +.. ocv:function:: template<...> _Tp saturate_cast(_Tp2 v) + + :param v: Function parameter. + +The functions ``saturate_cast`` resemble the standard C++ cast operations, such as ``static_cast()`` and others. They perform an efficient and accurate conversion from one primitive type to another (see the introduction chapter). ``saturate`` in the name means that when the input value ``v`` is out of the range of the target type, the result is not formed just by taking low bits of the input, but instead the value is clipped. For example: :: + + uchar a = saturate_cast(-100); // a = 0 (UCHAR_MIN) + short b = saturate_cast(33333.33333); // b = 32767 (SHRT_MAX) + +Such clipping is done when the target type is ``unsigned char`` , ``signed char`` , ``unsigned short`` or ``signed short`` . For 32-bit integers, no clipping is done. + +When the parameter is a floating-point value and the target type is an integer (8-, 16- or 32-bit), the floating-point value is first rounded to the nearest integer and then clipped if needed (when the target type is 8- or 16-bit). + +This operation is used in the simplest or most complex image processing functions in OpenCV. + +.. seealso:: + + :ocv:func:`add`, + :ocv:func:`subtract`, + :ocv:func:`multiply`, + :ocv:func:`divide`, + :ocv:func:`Mat::convertTo` + +setNumThreads +----------------- +Sets the number of threads used by OpenCV. + +.. ocv:function:: void setNumThreads(int nthreads) + + :param nthreads: Number of threads used by OpenCV. + +The function sets the number of threads used by OpenCV in parallel OpenMP regions. If ``nthreads=0`` , the function uses the default number of threads that is usually equal to the number of the processing cores. + +.. seealso:: + :ocv:func:`getNumThreads`, + :ocv:func:`getThreadNum` + + + +setUseOptimized +----------------- +Enables or disables the optimized code. + +.. ocv:function:: int cvUseOptimized( int on_off ) + +.. ocv:pyfunction:: cv2.setUseOptimized(onoff) -> None + +.. ocv:cfunction:: int cvUseOptimized( int on_off ) + + :param on_off: The boolean flag specifying whether the optimized code should be used (``on_off=true``) or not (``on_off=false``). + +The function can be used to dynamically turn on and off optimized code (code that uses SSE2, AVX, and other instructions on the platforms that support it). It sets a global flag that is further checked by OpenCV functions. Since the flag is not checked in the inner OpenCV loops, it is only safe to call the function on the very top level in your application where you can be sure that no other OpenCV function is currently executed. + +By default, the optimized code is enabled unless you disable it in CMake. The current status can be retrieved using ``useOptimized``. + +useOptimized +----------------- +Returns the status of optimized code usage. + +.. ocv:function:: bool useOptimized() + +.. ocv:pyfunction:: cv2.useOptimized() -> retval + +The function returns ``true`` if the optimized code is enabled. Otherwise, it returns ``false``. diff --git a/core/doc/xml_yaml_persistence.rst b/core/doc/xml_yaml_persistence.rst new file mode 100644 index 0000000..c7d55d0 --- /dev/null +++ b/core/doc/xml_yaml_persistence.rst @@ -0,0 +1,703 @@ +XML/YAML Persistence +==================== + +.. highlight:: cpp + +XML/YAML file storages. Writing to a file storage. +-------------------------------------------------- + +You can store and then restore various OpenCV data structures to/from XML (http://www.w3c.org/XML) or YAML +(http://www.yaml.org) formats. Also, it is possible store and load arbitrarily complex data structures, which include OpenCV data structures, as well as primitive data types (integer and floating-point numbers and text strings) as their elements. + +Use the following procedure to write something to XML or YAML: + #. Create new :ocv:class:`FileStorage` and open it for writing. It can be done with a single call to :ocv:func:`FileStorage::FileStorage` constructor that takes a filename, or you can use the default constructor and then call :ocv:func:`FileStorage::open`. Format of the file (XML or YAML) is determined from the filename extension (".xml" and ".yml"/".yaml", respectively) + #. Write all the data you want using the streaming operator ``>>``, just like in the case of STL streams. + #. Close the file using :ocv:func:`FileStorage::release`. ``FileStorage`` destructor also closes the file. + +Here is an example: :: + + #include "opencv2/opencv.hpp" + #include + + using namespace cv; + + int main(int, char** argv) + { + FileStorage fs("test.yml", FileStorage::WRITE); + + fs << "frameCount" << 5; + time_t rawtime; time(&rawtime); + fs << "calibrationDate" << asctime(localtime(&rawtime)); + Mat cameraMatrix = (Mat_(3,3) << 1000, 0, 320, 0, 1000, 240, 0, 0, 1); + Mat distCoeffs = (Mat_(5,1) << 0.1, 0.01, -0.001, 0, 0); + fs << "cameraMatrix" << cameraMatrix << "distCoeffs" << distCoeffs; + fs << "features" << "["; + for( int i = 0; i < 3; i++ ) + { + int x = rand() % 640; + int y = rand() % 480; + uchar lbp = rand() % 256; + + fs << "{:" << "x" << x << "y" << y << "lbp" << "[:"; + for( int j = 0; j < 8; j++ ) + fs << ((lbp >> j) & 1); + fs << "]" << "}"; + } + fs << "]"; + fs.release(); + return 0; + } + +The sample above stores to XML and integer, text string (calibration date), 2 matrices, and a custom structure "feature", which includes feature coordinates and LBP (local binary pattern) value. Here is output of the sample: + +.. code-block:: yaml + + %YAML:1.0 + frameCount: 5 + calibrationDate: "Fri Jun 17 14:09:29 2011\n" + cameraMatrix: !!opencv-matrix + rows: 3 + cols: 3 + dt: d + data: [ 1000., 0., 320., 0., 1000., 240., 0., 0., 1. ] + distCoeffs: !!opencv-matrix + rows: 5 + cols: 1 + dt: d + data: [ 1.0000000000000001e-01, 1.0000000000000000e-02, + -1.0000000000000000e-03, 0., 0. ] + features: + - { x:167, y:49, lbp:[ 1, 0, 0, 1, 1, 0, 1, 1 ] } + - { x:298, y:130, lbp:[ 0, 0, 0, 1, 0, 0, 1, 1 ] } + - { x:344, y:158, lbp:[ 1, 1, 0, 0, 0, 0, 1, 0 ] } + +As an exercise, you can replace ".yml" with ".xml" in the sample above and see, how the corresponding XML file will look like. + +Several things can be noted by looking at the sample code and the output: + * + The produced YAML (and XML) consists of heterogeneous collections that can be nested. There are 2 types of collections: named collections (mappings) and unnamed collections (sequences). In mappings each element has a name and is accessed by name. This is similar to structures and ``std::map`` in C/C++ and dictionaries in Python. In sequences elements do not have names, they are accessed by indices. This is similar to arrays and ``std::vector`` in C/C++ and lists, tuples in Python. "Heterogeneous" means that elements of each single collection can have different types. + + Top-level collection in YAML/XML is a mapping. Each matrix is stored as a mapping, and the matrix elements are stored as a sequence. Then, there is a sequence of features, where each feature is represented a mapping, and lbp value in a nested sequence. + + * + When you write to a mapping (a structure), you write element name followed by its value. When you write to a sequence, you simply write the elements one by one. OpenCV data structures (such as cv::Mat) are written in absolutely the same way as simple C data structures - using **``<<``** operator. + + * + To write a mapping, you first write the special string **"{"** to the storage, then write the elements as pairs (``fs << << ``) and then write the closing **"}"**. + + * + To write a sequence, you first write the special string **"["**, then write the elements, then write the closing **"]"**. + + * + In YAML (but not XML), mappings and sequences can be written in a compact Python-like inline form. In the sample above matrix elements, as well as each feature, including its lbp value, is stored in such inline form. To store a mapping/sequence in a compact form, put ":" after the opening character, e.g. use **"{:"** instead of **"{"** and **"[:"** instead of **"["**. When the data is written to XML, those extra ":" are ignored. + + +Reading data from a file storage. +--------------------------------- + +To read the previously written XML or YAML file, do the following: + + #. + Open the file storage using :ocv:func:`FileStorage::FileStorage` constructor or :ocv:func:`FileStorage::open` method. In the current implementation the whole file is parsed and the whole representation of file storage is built in memory as a hierarchy of file nodes (see :ocv:class:`FileNode`) + + #. + Read the data you are interested in. Use :ocv:func:`FileStorage::operator []`, :ocv:func:`FileNode::operator []` and/or :ocv:class:`FileNodeIterator`. + + #. + Close the storage using :ocv:func:`FileStorage::release`. + +Here is how to read the file created by the code sample above: :: + + FileStorage fs2("test.yml", FileStorage::READ); + + // first method: use (type) operator on FileNode. + int frameCount = (int)fs2["frameCount"]; + + std::string date; + // second method: use FileNode::operator >> + fs2["calibrationDate"] >> date; + + Mat cameraMatrix2, distCoeffs2; + fs2["cameraMatrix"] >> cameraMatrix2; + fs2["distCoeffs"] >> distCoeffs2; + + cout << "frameCount: " << frameCount << endl + << "calibration date: " << date << endl + << "camera matrix: " << cameraMatrix2 << endl + << "distortion coeffs: " << distCoeffs2 << endl; + + FileNode features = fs2["features"]; + FileNodeIterator it = features.begin(), it_end = features.end(); + int idx = 0; + std::vector lbpval; + + // iterate through a sequence using FileNodeIterator + for( ; it != it_end; ++it, idx++ ) + { + cout << "feature #" << idx << ": "; + cout << "x=" << (int)(*it)["x"] << ", y=" << (int)(*it)["y"] << ", lbp: ("; + // you can also easily read numerical arrays using FileNode >> std::vector operator. + (*it)["lbp"] >> lbpval; + for( int i = 0; i < (int)lbpval.size(); i++ ) + cout << " " << (int)lbpval[i]; + cout << ")" << endl; + } + fs.release(); + +FileStorage +----------- +.. ocv:class:: FileStorage + +XML/YAML file storage class that encapsulates all the information necessary for writing or reading data to/from a file. + +FileStorage::FileStorage +------------------------ +The constructors. + +.. ocv:function:: FileStorage::FileStorage() + +.. ocv:function:: FileStorage::FileStorage(const string& source, int flags, const string& encoding=string()) + + :param source: Name of the file to open or the text string to read the data from. Extension of the file (``.xml`` or ``.yml``/``.yaml``) determines its format (XML or YAML respectively). Also you can append ``.gz`` to work with compressed files, for example ``myHugeMatrix.xml.gz``. If both ``FileStorage::WRITE`` and ``FileStorage::MEMORY`` flags are specified, ``source`` is used just to specify the output file format (e.g. ``mydata.xml``, ``.yml`` etc.). + + :param flags: Mode of operation. Possible values are: + + * **FileStorage::READ** Open the file for reading. + + * **FileStorage::WRITE** Open the file for writing. + + * **FileStorage::APPEND** Open the file for appending. + + * **FileStorage::MEMORY** Read data from ``source`` or write data to the internal buffer (which is returned by ``FileStorage::release``) + + :param encoding: Encoding of the file. Note that UTF-16 XML encoding is not supported currently and you should use 8-bit encoding instead of it. + +The full constructor opens the file. Alternatively you can use the default constructor and then call :ocv:func:`FileStorage::open`. + + +FileStorage::open +----------------- +Opens a file. + +.. ocv:function:: bool FileStorage::open(const string& filename, int flags, const string& encoding=string()) + +See description of parameters in :ocv:func:`FileStorage::FileStorage`. The method calls :ocv:func:`FileStorage::release` before opening the file. + + +FileStorage::isOpened +--------------------- +Checks whether the file is opened. + +.. ocv:function:: bool FileStorage::isOpened() const + + :returns: ``true`` if the object is associated with the current file and ``false`` otherwise. + +It is a good practice to call this method after you tried to open a file. + + +FileStorage::release +-------------------- +Closes the file and releases all the memory buffers. + +.. ocv:function:: void FileStorage::release() + +Call this method after all I/O operations with the storage are finished. + + +FileStorage::releaseAndGetString +-------------------------------- +Closes the file and releases all the memory buffers. + +.. ocv:function:: string FileStorage::releaseAndGetString() + +Call this method after all I/O operations with the storage are finished. If the storage was opened for writing data and ``FileStorage::WRITE`` was specified + + +FileStorage::getFirstTopLevelNode +--------------------------------- +Returns the first element of the top-level mapping. + +.. ocv:function:: FileNode FileStorage::getFirstTopLevelNode() const + + :returns: The first element of the top-level mapping. + + +FileStorage::root +----------------- +Returns the top-level mapping + +.. ocv:function:: FileNode FileStorage::root(int streamidx=0) const + + :param streamidx: Zero-based index of the stream. In most cases there is only one stream in the file. However, YAML supports multiple streams and so there can be several. + + :returns: The top-level mapping. + + +FileStorage::operator[] +----------------------- +Returns the specified element of the top-level mapping. + +.. ocv:function:: FileNode FileStorage::operator[](const string& nodename) const + +.. ocv:function:: FileNode FileStorage::operator[](const char* nodename) const + + :param nodename: Name of the file node. + + :returns: Node with the given name. + + +FileStorage::operator* +---------------------- +Returns the obsolete C FileStorage structure. + +.. ocv:function:: CvFileStorage* FileStorage::operator *() + +.. ocv:function:: const CvFileStorage* FileStorage::operator *() const + + :returns: Pointer to the underlying C FileStorage structure + + +FileStorage::writeRaw +--------------------- +Writes multiple numbers. + +.. ocv:function:: void FileStorage::writeRaw( const string& fmt, const uchar* vec, size_t len ) + + :param fmt: Specification of each array element that has the following format ``([count]{'u'|'c'|'w'|'s'|'i'|'f'|'d'})...`` where the characters correspond to fundamental C++ types: + + * **u** 8-bit unsigned number + + * **c** 8-bit signed number + + * **w** 16-bit unsigned number + + * **s** 16-bit signed number + + * **i** 32-bit signed number + + * **f** single precision floating-point number + + * **d** double precision floating-point number + + * **r** pointer, 32 lower bits of which are written as a signed integer. The type can be used to store structures with links between the elements. + + ``count`` is the optional counter of values of a given type. For example, ``2if`` means that each array element is a structure of 2 integers, followed by a single-precision floating-point number. The equivalent notations of the above specification are ' ``iif`` ', ' ``2i1f`` ' and so forth. Other examples: ``u`` means that the array consists of bytes, and ``2d`` means the array consists of pairs of doubles. + + :param vec: Pointer to the written array. + + :param len: Number of the ``uchar`` elements to write. + +Writes one or more numbers of the specified format to the currently written structure. Usually it is more convenient to use :ocv:func:`operator <<` instead of this method. + +FileStorage::writeObj +--------------------- +Writes the registered C structure (CvMat, CvMatND, CvSeq). + +.. ocv:function:: void FileStorage::writeObj( const string& name, const void* obj ) + + :param name: Name of the written object. + + :param obj: Pointer to the object. + +See :ocv:cfunc:`Write` for details. + + +FileStorage::getDefaultObjectName +--------------------------------- +Returns the normalized object name for the specified name of a file. + +.. ocv:function:: static string FileStorage::getDefaultObjectName(const string& filename) + + :param filename: Name of a file + + :returns: The normalized object name. + + +operator << +----------- +Writes data to a file storage. + +.. ocv:function:: template FileStorage& operator << (FileStorage& fs, const _Tp& value) + +.. ocv:function:: template FileStorage& operator << ( FileStorage& fs, const vector<_Tp>& vec ) + + :param fs: Opened file storage to write data. + + :param value: Value to be written to the file storage. + + :param vec: Vector of values to be written to the file storage. + +It is the main function to write data to a file storage. See an example of its usage at the beginning of the section. + + +operator >> +----------- +Reads data from a file storage. + +.. ocv:function:: template void operator >> (const FileNode& n, _Tp& value) + +.. ocv:function:: template void operator >> (const FileNode& n, vector<_Tp>& vec) + +.. ocv:function:: template FileNodeIterator& operator >> (FileNodeIterator& it, _Tp& value) + +.. ocv:function:: template FileNodeIterator& operator >> (FileNodeIterator& it, vector<_Tp>& vec) + + :param n: Node from which data will be read. + + :param it: Iterator from which data will be read. + + :param value: Value to be read from the file storage. + + :param vec: Vector of values to be read from the file storage. + +It is the main function to read data from a file storage. See an example of its usage at the beginning of the section. + + +FileNode +-------- +.. ocv:class:: FileNode + +File Storage Node class. The node is used to store each and every element of the file storage opened for reading. When XML/YAML file is read, it is first parsed and stored in the memory as a hierarchical collection of nodes. Each node can be a “leaf” that is contain a single number or a string, or be a collection of other nodes. There can be named collections (mappings) where each element has a name and it is accessed by a name, and ordered collections (sequences) where elements do not have names but rather accessed by index. Type of the file node can be determined using :ocv:func:`FileNode::type` method. + +Note that file nodes are only used for navigating file storages opened for reading. When a file storage is opened for writing, no data is stored in memory after it is written. + + +FileNode::FileNode +------------------ +The constructors. + +.. ocv:function:: FileNode::FileNode() + +.. ocv:function:: FileNode::FileNode(const CvFileStorage* fs, const CvFileNode* node) + +.. ocv:function:: FileNode::FileNode(const FileNode& node) + + :param fs: Pointer to the obsolete file storage structure. + + :param node: File node to be used as initialization for the created file node. + +These constructors are used to create a default file node, construct it from obsolete structures or from the another file node. + + +FileNode::operator[] +-------------------- +Returns element of a mapping node or a sequence node. + +.. ocv:function:: FileNode FileNode::operator[](const string& nodename) const + +.. ocv:function:: FileNode FileNode::operator[](const char* nodename) const + +.. ocv:function:: FileNode FileNode::operator[](int i) const + + :param nodename: Name of an element in the mapping node. + + :param i: Index of an element in the sequence node. + + :returns: Returns the element with the given identifier. + + +FileNode::type +-------------- +Returns type of the node. + +.. ocv:function:: int FileNode::type() const + + :returns: Type of the node. Possible values are: + + * **FileNode::NONE** Empty node. + + * **FileNode::INT** Integer. + + * **FileNode::REAL** Floating-point number. + + * **FileNode::FLOAT** Synonym or ``REAL``. + + * **FileNode::STR** Text string in UTF-8 encoding. + + * **FileNode::STRING** Synonym for ``STR``. + + * **FileNode::REF** Integer of type ``size_t``. Typically used for storing complex dynamic structures where some elements reference the others. + + * **FileNode::SEQ** Sequence. + + * **FileNode::MAP** Mapping. + + * **FileNode::FLOW** Compact representation of a sequence or mapping. Used only by the YAML writer. + + * **FileNode::USER** Registered object (e.g. a matrix). + + * **FileNode::EMPTY** Empty structure (sequence or mapping). + + * **FileNode::NAMED** The node has a name (i.e. it is an element of a mapping). + + +FileNode::empty +--------------- +Checks whether the node is empty. + +.. ocv:function:: bool FileNode::empty() const + + :returns: ``true`` if the node is empty. + + +FileNode::isNone +---------------- +Checks whether the node is a "none" object + +.. ocv:function:: bool FileNode::isNone() const + + :returns: ``true`` if the node is a "none" object. + + +FileNode::isSeq +--------------- +Checks whether the node is a sequence. + +.. ocv:function:: bool FileNode::isSeq() const + + :returns: ``true`` if the node is a sequence. + + +FileNode::isMap +--------------- +Checks whether the node is a mapping. + +.. ocv:function:: bool FileNode::isMap() const + + :returns: ``true`` if the node is a mapping. + + +FileNode::isInt +--------------- +Checks whether the node is an integer. + +.. ocv:function:: bool FileNode::isInt() const + + :returns: ``true`` if the node is an integer. + + +FileNode::isReal +---------------- +Checks whether the node is a floating-point number. + +.. ocv:function:: bool FileNode::isReal() const + + :returns: ``true`` if the node is a floating-point number. + + +FileNode::isString +------------------ +Checks whether the node is a text string. + +.. ocv:function:: bool FileNode::isString() const + + :returns: ``true`` if the node is a text string. + + +FileNode::isNamed +----------------- +Checks whether the node has a name. + +.. ocv:function:: bool FileNode::isNamed() const + + :returns: ``true`` if the node has a name. + + +FileNode::name +-------------- +Returns the node name. + +.. ocv:function:: string FileNode::name() const + + :returns: The node name or an empty string if the node is nameless. + + +FileNode::size +-------------- +Returns the number of elements in the node. + +.. ocv:function:: size_t FileNode::size() const + + :returns: The number of elements in the node, if it is a sequence or mapping, or 1 otherwise. + + +FileNode::operator int +---------------------- +Returns the node content as an integer. + +.. ocv:function:: FileNode::operator int() const + + :returns: The node content as an integer. If the node stores a floating-point number, it is rounded. + + +FileNode::operator float +------------------------ +Returns the node content as float. + +.. ocv:function:: FileNode::operator float() const + + :returns: The node content as float. + + +FileNode::operator double +------------------------- +Returns the node content as double. + +.. ocv:function:: FileNode::operator double() const + + :returns: The node content as double. + + +FileNode::operator string +------------------------- +Returns the node content as text string. + +.. ocv:function:: FileNode::operator string() const + + :returns: The node content as a text string. + + +FileNode::operator* +------------------- +Returns pointer to the underlying obsolete file node structure. + +.. ocv:function:: CvFileNode* FileNode::operator *() + + :returns: Pointer to the underlying obsolete file node structure. + + +FileNode::begin +--------------- +Returns the iterator pointing to the first node element. + +.. ocv:function:: FileNodeIterator FileNode::begin() const + + :returns: Iterator pointing to the first node element. + + +FileNode::end +------------- +Returns the iterator pointing to the element following the last node element. + +.. ocv:function:: FileNodeIterator FileNode::end() const + + :returns: Iterator pointing to the element following the last node element. + + +FileNode::readRaw +----------------- +Reads node elements to the buffer with the specified format. + +.. ocv:function:: void FileNode::readRaw( const string& fmt, uchar* vec, size_t len ) const + + :param fmt: Specification of each array element. It has the same format as in :ocv:func:`FileStorage::writeRaw`. + + :param vec: Pointer to the destination array. + + :param len: Number of elements to read. If it is greater than number of remaining elements then all of them will be read. + +Usually it is more convenient to use :ocv:func:`operator >>` instead of this method. + +FileNode::readObj +----------------- +Reads the registered object. + +.. ocv:function:: void* FileNode::readObj() const + + :returns: Pointer to the read object. + +See :ocv:cfunc:`Read` for details. + +FileNodeIterator +---------------- +.. ocv:class:: FileNodeIterator + +The class ``FileNodeIterator`` is used to iterate through sequences and mappings. A standard STL notation, with ``node.begin()``, ``node.end()`` denoting the beginning and the end of a sequence, stored in ``node``. See the data reading sample in the beginning of the section. + + +FileNodeIterator::FileNodeIterator +---------------------------------- +The constructors. + +.. ocv:function:: FileNodeIterator::FileNodeIterator() + +.. ocv:function:: FileNodeIterator::FileNodeIterator(const CvFileStorage* fs, const CvFileNode* node, size_t ofs=0) + +.. ocv:function:: FileNodeIterator::FileNodeIterator(const FileNodeIterator& it) + + :param fs: File storage for the iterator. + + :param node: File node for the iterator. + + :param ofs: Index of the element in the node. The created iterator will point to this element. + + :param it: Iterator to be used as initialization for the created iterator. + +These constructors are used to create a default iterator, set it to specific element in a file node or construct it from another iterator. + + +FileNodeIterator::operator* +--------------------------- +Returns the currently observed element. + +.. ocv:function:: FileNode FileNodeIterator::operator *() const + + :returns: Currently observed element. + + +FileNodeIterator::operator-> +---------------------------- +Accesses methods of the currently observed element. + +.. ocv:function:: FileNode FileNodeIterator::operator ->() const + + +FileNodeIterator::operator ++ +----------------------------- +Moves iterator to the next node. + +.. ocv:function:: FileNodeIterator& FileNodeIterator::operator ++ () + +.. ocv:function:: FileNodeIterator FileNodeIterator::operator ++ (int) + + +FileNodeIterator::operator -- +----------------------------- +Moves iterator to the previous node. + +.. ocv:function:: FileNodeIterator& FileNodeIterator::operator -- () + +.. ocv:function:: FileNodeIterator FileNodeIterator::operator -- (int) + + +FileNodeIterator::operator += +----------------------------- +Moves iterator forward by the specified offset. + +.. ocv:function:: FileNodeIterator& FileNodeIterator::operator +=( int ofs ) + + :param ofs: Offset (possibly negative) to move the iterator. + + +FileNodeIterator::operator -= +----------------------------- +Moves iterator backward by the specified offset (possibly negative). + +.. ocv:function:: FileNodeIterator& FileNodeIterator::operator -=( int ofs ) + + :param ofs: Offset (possibly negative) to move the iterator. + + +FileNodeIterator::readRaw +------------------------- +Reads node elements to the buffer with the specified format. + +.. ocv:function:: FileNodeIterator& FileNodeIterator::readRaw( const string& fmt, uchar* vec, size_t maxCount=(size_t)INT_MAX ) + + :param fmt: Specification of each array element. It has the same format as in :ocv:func:`FileStorage::writeRaw`. + + :param vec: Pointer to the destination array. + + :param maxCount: Number of elements to read. If it is greater than number of remaining elements then all of them will be read. + +Usually it is more convenient to use :ocv:func:`operator >>` instead of this method. diff --git a/core/include/.DS_Store b/core/include/.DS_Store new file mode 100644 index 0000000..9619eb9 Binary files /dev/null and b/core/include/.DS_Store differ diff --git a/core/include/opencv2/.DS_Store b/core/include/opencv2/.DS_Store new file mode 100644 index 0000000..084144e Binary files /dev/null and b/core/include/opencv2/.DS_Store differ diff --git a/core/include/opencv2/core/core.hpp b/core/include/opencv2/core/core.hpp new file mode 100644 index 0000000..5fd9272 --- /dev/null +++ b/core/include/opencv2/core/core.hpp @@ -0,0 +1,4658 @@ +/*! \file core.hpp + \brief The Core Functionality + */ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_CORE_HPP__ +#define __OPENCV_CORE_HPP__ + +#include "opencv2/core/types_c.h" +#include "opencv2/core/version.hpp" + +#ifdef __cplusplus + +#ifndef SKIP_INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // SKIP_INCLUDES + +/*! \namespace cv + Namespace where all the C++ OpenCV functionality resides +*/ +namespace cv { + +#undef abs +#undef min +#undef max +#undef Complex + +using std::vector; +using std::string; +using std::ptrdiff_t; + +template class CV_EXPORTS Size_; +template class CV_EXPORTS Point_; +template class CV_EXPORTS Rect_; +template class CV_EXPORTS Vec; +template class CV_EXPORTS Matx; + +typedef std::string String; + +class Mat; +class SparseMat; +typedef Mat MatND; + +class GlBuffer; +class GlTexture; +class GlArrays; +class GlCamera; + +namespace gpu { + class GpuMat; +} + +class CV_EXPORTS MatExpr; +class CV_EXPORTS MatOp_Base; +class CV_EXPORTS MatArg; +class CV_EXPORTS MatConstIterator; + +template class CV_EXPORTS Mat_; +template class CV_EXPORTS MatIterator_; +template class CV_EXPORTS MatConstIterator_; +template class CV_EXPORTS MatCommaInitializer_; + +#if !defined(ANDROID) || (defined(_GLIBCXX_USE_WCHAR_T) && _GLIBCXX_USE_WCHAR_T) +typedef std::basic_string WString; + +CV_EXPORTS string fromUtf16(const WString& str); +CV_EXPORTS WString toUtf16(const string& str); +#endif + +CV_EXPORTS string format( const char* fmt, ... ); +CV_EXPORTS string tempfile( const char* suffix CV_DEFAULT(0)); + +// matrix decomposition types +enum { DECOMP_LU=0, DECOMP_SVD=1, DECOMP_EIG=2, DECOMP_CHOLESKY=3, DECOMP_QR=4, DECOMP_NORMAL=16 }; +enum { NORM_INF=1, NORM_L1=2, NORM_L2=4, NORM_L2SQR=5, NORM_HAMMING=6, NORM_HAMMING2=7, NORM_TYPE_MASK=7, NORM_RELATIVE=8, NORM_MINMAX=32 }; +enum { CMP_EQ=0, CMP_GT=1, CMP_GE=2, CMP_LT=3, CMP_LE=4, CMP_NE=5 }; +enum { GEMM_1_T=1, GEMM_2_T=2, GEMM_3_T=4 }; +enum { DFT_INVERSE=1, DFT_SCALE=2, DFT_ROWS=4, DFT_COMPLEX_OUTPUT=16, DFT_REAL_OUTPUT=32, + DCT_INVERSE = DFT_INVERSE, DCT_ROWS=DFT_ROWS }; + + +/*! + The standard OpenCV exception class. + Instances of the class are thrown by various functions and methods in the case of critical errors. + */ +class CV_EXPORTS Exception : public std::exception +{ +public: + /*! + Default constructor + */ + Exception(); + /*! + Full constructor. Normally the constuctor is not called explicitly. + Instead, the macros CV_Error(), CV_Error_() and CV_Assert() are used. + */ + Exception(int _code, const string& _err, const string& _func, const string& _file, int _line); + virtual ~Exception() throw(); + + /*! + \return the error description and the context as a text string. + */ + virtual const char *what() const throw(); + void formatMessage(); + + string msg; ///< the formatted error message + + int code; ///< error code @see CVStatus + string err; ///< error description + string func; ///< function name. Available only when the compiler supports __func__ macro + string file; ///< source file name where the error has occured + int line; ///< line number in the source file where the error has occured +}; + + +//! Signals an error and raises the exception. + +/*! + By default the function prints information about the error to stderr, + then it either stops if setBreakOnError() had been called before or raises the exception. + It is possible to alternate error processing by using redirectError(). + + \param exc the exception raisen. + */ +CV_EXPORTS void error( const Exception& exc ); + +//! Sets/resets the break-on-error mode. + +/*! + When the break-on-error mode is set, the default error handler + issues a hardware exception, which can make debugging more convenient. + + \return the previous state + */ +CV_EXPORTS bool setBreakOnError(bool flag); + +typedef int (CV_CDECL *ErrorCallback)( int status, const char* func_name, + const char* err_msg, const char* file_name, + int line, void* userdata ); + +//! Sets the new error handler and the optional user data. + +/*! + The function sets the new error handler, called from cv::error(). + + \param errCallback the new error handler. If NULL, the default error handler is used. + \param userdata the optional user data pointer, passed to the callback. + \param prevUserdata the optional output parameter where the previous user data pointer is stored + + \return the previous error handler +*/ +CV_EXPORTS ErrorCallback redirectError( ErrorCallback errCallback, + void* userdata=0, void** prevUserdata=0); + +#ifdef __GNUC__ +#define CV_Error( code, msg ) cv::error( cv::Exception(code, msg, __func__, __FILE__, __LINE__) ) +#define CV_Error_( code, args ) cv::error( cv::Exception(code, cv::format args, __func__, __FILE__, __LINE__) ) +#define CV_Assert( expr ) if((expr)) ; else cv::error( cv::Exception(CV_StsAssert, #expr, __func__, __FILE__, __LINE__) ) +#else +#define CV_Error( code, msg ) cv::error( cv::Exception(code, msg, "", __FILE__, __LINE__) ) +#define CV_Error_( code, args ) cv::error( cv::Exception(code, cv::format args, "", __FILE__, __LINE__) ) +#define CV_Assert( expr ) if((expr)) ; else cv::error( cv::Exception(CV_StsAssert, #expr, "", __FILE__, __LINE__) ) +#endif + +#ifdef _DEBUG +#define CV_DbgAssert(expr) CV_Assert(expr) +#else +#define CV_DbgAssert(expr) +#endif + +CV_EXPORTS void setNumThreads(int nthreads); +CV_EXPORTS int getNumThreads(); +CV_EXPORTS int getThreadNum(); + +CV_EXPORTS_W const std::string& getBuildInformation(); + +//! Returns the number of ticks. + +/*! + The function returns the number of ticks since the certain event (e.g. when the machine was turned on). + It can be used to initialize cv::RNG or to measure a function execution time by reading the tick count + before and after the function call. The granularity of ticks depends on the hardware and OS used. Use + cv::getTickFrequency() to convert ticks to seconds. +*/ +CV_EXPORTS_W int64 getTickCount(); + +/*! + Returns the number of ticks per seconds. + + The function returns the number of ticks (as returned by cv::getTickCount()) per second. + The following code computes the execution time in milliseconds: + + \code + double exec_time = (double)getTickCount(); + // do something ... + exec_time = ((double)getTickCount() - exec_time)*1000./getTickFrequency(); + \endcode +*/ +CV_EXPORTS_W double getTickFrequency(); + +/*! + Returns the number of CPU ticks. + + On platforms where the feature is available, the function returns the number of CPU ticks + since the certain event (normally, the system power-on moment). Using this function + one can accurately measure the execution time of very small code fragments, + for which cv::getTickCount() granularity is not enough. +*/ +CV_EXPORTS_W int64 getCPUTickCount(); + +/*! + Returns SSE etc. support status + + The function returns true if certain hardware features are available. + Currently, the following features are recognized: + - CV_CPU_MMX - MMX + - CV_CPU_SSE - SSE + - CV_CPU_SSE2 - SSE 2 + - CV_CPU_SSE3 - SSE 3 + - CV_CPU_SSSE3 - SSSE 3 + - CV_CPU_SSE4_1 - SSE 4.1 + - CV_CPU_SSE4_2 - SSE 4.2 + - CV_CPU_POPCNT - POPCOUNT + - CV_CPU_AVX - AVX + + \note {Note that the function output is not static. Once you called cv::useOptimized(false), + most of the hardware acceleration is disabled and thus the function will returns false, + until you call cv::useOptimized(true)} +*/ +CV_EXPORTS_W bool checkHardwareSupport(int feature); + +//! returns the number of CPUs (including hyper-threading) +CV_EXPORTS_W int getNumberOfCPUs(); + +/*! + Allocates memory buffer + + This is specialized OpenCV memory allocation function that returns properly aligned memory buffers. + The usage is identical to malloc(). The allocated buffers must be freed with cv::fastFree(). + If there is not enough memory, the function calls cv::error(), which raises an exception. + + \param bufSize buffer size in bytes + \return the allocated memory buffer. +*/ +CV_EXPORTS void* fastMalloc(size_t bufSize); + +/*! + Frees the memory allocated with cv::fastMalloc + + This is the corresponding deallocation function for cv::fastMalloc(). + When ptr==NULL, the function has no effect. +*/ +CV_EXPORTS void fastFree(void* ptr); + +template static inline _Tp* allocate(size_t n) +{ + return new _Tp[n]; +} + +template static inline void deallocate(_Tp* ptr, size_t) +{ + delete[] ptr; +} + +/*! + Aligns pointer by the certain number of bytes + + This small inline function aligns the pointer by the certian number of bytes by shifting + it forward by 0 or a positive offset. +*/ +template static inline _Tp* alignPtr(_Tp* ptr, int n=(int)sizeof(_Tp)) +{ + return (_Tp*)(((size_t)ptr + n-1) & -n); +} + +/*! + Aligns buffer size by the certain number of bytes + + This small inline function aligns a buffer size by the certian number of bytes by enlarging it. +*/ +static inline size_t alignSize(size_t sz, int n) +{ + return (sz + n-1) & -n; +} + +/*! + Turns on/off available optimization + + The function turns on or off the optimized code in OpenCV. Some optimization can not be enabled + or disabled, but, for example, most of SSE code in OpenCV can be temporarily turned on or off this way. + + \note{Since optimization may imply using special data structures, it may be unsafe + to call this function anywhere in the code. Instead, call it somewhere at the top level.} +*/ +CV_EXPORTS_W void setUseOptimized(bool onoff); + +/*! + Returns the current optimization status + + The function returns the current optimization status, which is controlled by cv::setUseOptimized(). +*/ +CV_EXPORTS_W bool useOptimized(); + +/*! + The STL-compilant memory Allocator based on cv::fastMalloc() and cv::fastFree() +*/ +template class CV_EXPORTS Allocator +{ +public: + typedef _Tp value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + template class rebind { typedef Allocator other; }; + + explicit Allocator() {} + ~Allocator() {} + explicit Allocator(Allocator const&) {} + template + explicit Allocator(Allocator const&) {} + + // address + pointer address(reference r) { return &r; } + const_pointer address(const_reference r) { return &r; } + + pointer allocate(size_type count, const void* =0) + { return reinterpret_cast(fastMalloc(count * sizeof (_Tp))); } + + void deallocate(pointer p, size_type) {fastFree(p); } + + size_type max_size() const + { return max(static_cast<_Tp>(-1)/sizeof(_Tp), 1); } + + void construct(pointer p, const _Tp& v) { new(static_cast(p)) _Tp(v); } + void destroy(pointer p) { p->~_Tp(); } +}; + +/////////////////////// Vec (used as element of multi-channel images ///////////////////// + +/*! + A helper class for cv::DataType + + The class is specialized for each fundamental numerical data type supported by OpenCV. + It provides DataDepth::value constant. +*/ +template class CV_EXPORTS DataDepth {}; + +template<> class DataDepth { public: enum { value = CV_8U, fmt=(int)'u' }; }; +template<> class DataDepth { public: enum { value = CV_8U, fmt=(int)'u' }; }; +template<> class DataDepth { public: enum { value = CV_8S, fmt=(int)'c' }; }; +template<> class DataDepth { public: enum { value = CV_8S, fmt=(int)'c' }; }; +template<> class DataDepth { public: enum { value = CV_16U, fmt=(int)'w' }; }; +template<> class DataDepth { public: enum { value = CV_16S, fmt=(int)'s' }; }; +template<> class DataDepth { public: enum { value = CV_32S, fmt=(int)'i' }; }; +// this is temporary solution to support 32-bit unsigned integers +template<> class DataDepth { public: enum { value = CV_32S, fmt=(int)'i' }; }; +template<> class DataDepth { public: enum { value = CV_32F, fmt=(int)'f' }; }; +template<> class DataDepth { public: enum { value = CV_64F, fmt=(int)'d' }; }; +template class DataDepth<_Tp*> { public: enum { value = CV_USRTYPE1, fmt=(int)'r' }; }; + + +////////////////////////////// Small Matrix /////////////////////////// + +/*! + A short numerical vector. + + This template class represents short numerical vectors (of 1, 2, 3, 4 ... elements) + on which you can perform basic arithmetical operations, access individual elements using [] operator etc. + The vectors are allocated on stack, as opposite to std::valarray, std::vector, cv::Mat etc., + which elements are dynamically allocated in the heap. + + The template takes 2 parameters: + -# _Tp element type + -# cn the number of elements + + In addition to the universal notation like Vec, you can use shorter aliases + for the most popular specialized variants of Vec, e.g. Vec3f ~ Vec. + */ + +struct CV_EXPORTS Matx_AddOp {}; +struct CV_EXPORTS Matx_SubOp {}; +struct CV_EXPORTS Matx_ScaleOp {}; +struct CV_EXPORTS Matx_MulOp {}; +struct CV_EXPORTS Matx_MatMulOp {}; +struct CV_EXPORTS Matx_TOp {}; + +template class CV_EXPORTS Matx +{ +public: + typedef _Tp value_type; + typedef Matx<_Tp, (m < n ? m : n), 1> diag_type; + typedef Matx<_Tp, m, n> mat_type; + enum { depth = DataDepth<_Tp>::value, rows = m, cols = n, channels = rows*cols, + type = CV_MAKETYPE(depth, channels) }; + + //! default constructor + Matx(); + + Matx(_Tp v0); //!< 1x1 matrix + Matx(_Tp v0, _Tp v1); //!< 1x2 or 2x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2); //!< 1x3 or 3x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 1x4, 2x2 or 4x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 1x5 or 5x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 1x6, 2x3, 3x2 or 6x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 1x7 or 7x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 1x8, 2x4, 4x2 or 8x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 1x9, 3x3 or 9x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9); //!< 1x10, 2x5 or 5x2 or 10x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7, + _Tp v8, _Tp v9, _Tp v10, _Tp v11); //!< 1x12, 2x6, 3x4, 4x3, 6x2 or 12x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7, + _Tp v8, _Tp v9, _Tp v10, _Tp v11, + _Tp v12, _Tp v13, _Tp v14, _Tp v15); //!< 1x16, 4x4 or 16x1 matrix + explicit Matx(const _Tp* vals); //!< initialize from a plain array + + static Matx all(_Tp alpha); + static Matx zeros(); + static Matx ones(); + static Matx eye(); + static Matx diag(const diag_type& d); + static Matx randu(_Tp a, _Tp b); + static Matx randn(_Tp a, _Tp b); + + //! dot product computed with the default precision + _Tp dot(const Matx<_Tp, m, n>& v) const; + + //! dot product computed in double-precision arithmetics + double ddot(const Matx<_Tp, m, n>& v) const; + + //! convertion to another data type + template operator Matx() const; + + //! change the matrix shape + template Matx<_Tp, m1, n1> reshape() const; + + //! extract part of the matrix + template Matx<_Tp, m1, n1> get_minor(int i, int j) const; + + //! extract the matrix row + Matx<_Tp, 1, n> row(int i) const; + + //! extract the matrix column + Matx<_Tp, m, 1> col(int i) const; + + //! extract the matrix diagonal + diag_type diag() const; + + //! transpose the matrix + Matx<_Tp, n, m> t() const; + + //! invert matrix the matrix + Matx<_Tp, n, m> inv(int method=DECOMP_LU) const; + + //! solve linear system + template Matx<_Tp, n, l> solve(const Matx<_Tp, m, l>& rhs, int flags=DECOMP_LU) const; + Vec<_Tp, n> solve(const Vec<_Tp, m>& rhs, int method) const; + + //! multiply two matrices element-wise + Matx<_Tp, m, n> mul(const Matx<_Tp, m, n>& a) const; + + //! element access + const _Tp& operator ()(int i, int j) const; + _Tp& operator ()(int i, int j); + + //! 1D element access + const _Tp& operator ()(int i) const; + _Tp& operator ()(int i); + + Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_AddOp); + Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_SubOp); + template Matx(const Matx<_Tp, m, n>& a, _T2 alpha, Matx_ScaleOp); + Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_MulOp); + template Matx(const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b, Matx_MatMulOp); + Matx(const Matx<_Tp, n, m>& a, Matx_TOp); + + _Tp val[m*n]; //< matrix elements +}; + + +typedef Matx Matx12f; +typedef Matx Matx12d; +typedef Matx Matx13f; +typedef Matx Matx13d; +typedef Matx Matx14f; +typedef Matx Matx14d; +typedef Matx Matx16f; +typedef Matx Matx16d; + +typedef Matx Matx21f; +typedef Matx Matx21d; +typedef Matx Matx31f; +typedef Matx Matx31d; +typedef Matx Matx41f; +typedef Matx Matx41d; +typedef Matx Matx61f; +typedef Matx Matx61d; + +typedef Matx Matx22f; +typedef Matx Matx22d; +typedef Matx Matx23f; +typedef Matx Matx23d; +typedef Matx Matx32f; +typedef Matx Matx32d; + +typedef Matx Matx33f; +typedef Matx Matx33d; + +typedef Matx Matx34f; +typedef Matx Matx34d; +typedef Matx Matx43f; +typedef Matx Matx43d; + +typedef Matx Matx44f; +typedef Matx Matx44d; +typedef Matx Matx66f; +typedef Matx Matx66d; + + +/*! + A short numerical vector. + + This template class represents short numerical vectors (of 1, 2, 3, 4 ... elements) + on which you can perform basic arithmetical operations, access individual elements using [] operator etc. + The vectors are allocated on stack, as opposite to std::valarray, std::vector, cv::Mat etc., + which elements are dynamically allocated in the heap. + + The template takes 2 parameters: + -# _Tp element type + -# cn the number of elements + + In addition to the universal notation like Vec, you can use shorter aliases + for the most popular specialized variants of Vec, e.g. Vec3f ~ Vec. +*/ +template class CV_EXPORTS Vec : public Matx<_Tp, cn, 1> +{ +public: + typedef _Tp value_type; + enum { depth = DataDepth<_Tp>::value, channels = cn, type = CV_MAKETYPE(depth, channels) }; + + //! default constructor + Vec(); + + Vec(_Tp v0); //!< 1-element vector constructor + Vec(_Tp v0, _Tp v1); //!< 2-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2); //!< 3-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 4-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 5-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 6-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 7-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 8-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 9-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9); //!< 10-element vector constructor + explicit Vec(const _Tp* values); + + Vec(const Vec<_Tp, cn>& v); + + static Vec all(_Tp alpha); + + //! per-element multiplication + Vec mul(const Vec<_Tp, cn>& v) const; + + //! conjugation (makes sense for complex numbers and quaternions) + Vec conj() const; + + /*! + cross product of the two 3D vectors. + + For other dimensionalities the exception is raised + */ + Vec cross(const Vec& v) const; + //! convertion to another data type + template operator Vec() const; + //! conversion to 4-element CvScalar. + operator CvScalar() const; + + /*! element access */ + const _Tp& operator [](int i) const; + _Tp& operator[](int i); + const _Tp& operator ()(int i) const; + _Tp& operator ()(int i); + + Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_AddOp); + Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_SubOp); + template Vec(const Matx<_Tp, cn, 1>& a, _T2 alpha, Matx_ScaleOp); +}; + + +/* \typedef + + Shorter aliases for the most popular specializations of Vec +*/ +typedef Vec Vec2b; +typedef Vec Vec3b; +typedef Vec Vec4b; + +typedef Vec Vec2s; +typedef Vec Vec3s; +typedef Vec Vec4s; + +typedef Vec Vec2w; +typedef Vec Vec3w; +typedef Vec Vec4w; + +typedef Vec Vec2i; +typedef Vec Vec3i; +typedef Vec Vec4i; +typedef Vec Vec6i; +typedef Vec Vec8i; + +typedef Vec Vec2f; +typedef Vec Vec3f; +typedef Vec Vec4f; +typedef Vec Vec6f; + +typedef Vec Vec2d; +typedef Vec Vec3d; +typedef Vec Vec4d; +typedef Vec Vec6d; + + +//////////////////////////////// Complex ////////////////////////////// + +/*! + A complex number class. + + The template class is similar and compatible with std::complex, however it provides slightly + more convenient access to the real and imaginary parts using through the simple field access, as opposite + to std::complex::real() and std::complex::imag(). +*/ +template class CV_EXPORTS Complex +{ +public: + + //! constructors + Complex(); + Complex( _Tp _re, _Tp _im=0 ); + Complex( const std::complex<_Tp>& c ); + + //! conversion to another data type + template operator Complex() const; + //! conjugation + Complex conj() const; + //! conversion to std::complex + operator std::complex<_Tp>() const; + + _Tp re, im; //< the real and the imaginary parts +}; + + +/*! + \typedef +*/ +typedef Complex Complexf; +typedef Complex Complexd; + + +//////////////////////////////// Point_ //////////////////////////////// + +/*! + template 2D point class. + + The class defines a point in 2D space. Data type of the point coordinates is specified + as a template parameter. There are a few shorter aliases available for user convenience. + See cv::Point, cv::Point2i, cv::Point2f and cv::Point2d. +*/ +template class CV_EXPORTS Point_ +{ +public: + typedef _Tp value_type; + + // various constructors + Point_(); + Point_(_Tp _x, _Tp _y); + Point_(const Point_& pt); + Point_(const CvPoint& pt); + Point_(const CvPoint2D32f& pt); + Point_(const Size_<_Tp>& sz); + Point_(const Vec<_Tp, 2>& v); + + Point_& operator = (const Point_& pt); + //! conversion to another data type + template operator Point_<_Tp2>() const; + + //! conversion to the old-style C structures + operator CvPoint() const; + operator CvPoint2D32f() const; + operator Vec<_Tp, 2>() const; + + //! dot product + _Tp dot(const Point_& pt) const; + //! dot product computed in double-precision arithmetics + double ddot(const Point_& pt) const; + //! cross-product + double cross(const Point_& pt) const; + //! checks whether the point is inside the specified rectangle + bool inside(const Rect_<_Tp>& r) const; + + _Tp x, y; //< the point coordinates +}; + +/*! + template 3D point class. + + The class defines a point in 3D space. Data type of the point coordinates is specified + as a template parameter. + + \see cv::Point3i, cv::Point3f and cv::Point3d +*/ +template class CV_EXPORTS Point3_ +{ +public: + typedef _Tp value_type; + + // various constructors + Point3_(); + Point3_(_Tp _x, _Tp _y, _Tp _z); + Point3_(const Point3_& pt); + explicit Point3_(const Point_<_Tp>& pt); + Point3_(const CvPoint3D32f& pt); + Point3_(const Vec<_Tp, 3>& v); + + Point3_& operator = (const Point3_& pt); + //! conversion to another data type + template operator Point3_<_Tp2>() const; + //! conversion to the old-style CvPoint... + operator CvPoint3D32f() const; + //! conversion to cv::Vec<> + operator Vec<_Tp, 3>() const; + + //! dot product + _Tp dot(const Point3_& pt) const; + //! dot product computed in double-precision arithmetics + double ddot(const Point3_& pt) const; + //! cross product of the 2 3D points + Point3_ cross(const Point3_& pt) const; + + _Tp x, y, z; //< the point coordinates +}; + +//////////////////////////////// Size_ //////////////////////////////// + +/*! + The 2D size class + + The class represents the size of a 2D rectangle, image size, matrix size etc. + Normally, cv::Size ~ cv::Size_ is used. +*/ +template class CV_EXPORTS Size_ +{ +public: + typedef _Tp value_type; + + //! various constructors + Size_(); + Size_(_Tp _width, _Tp _height); + Size_(const Size_& sz); + Size_(const CvSize& sz); + Size_(const CvSize2D32f& sz); + Size_(const Point_<_Tp>& pt); + + Size_& operator = (const Size_& sz); + //! the area (width*height) + _Tp area() const; + + //! conversion of another data type. + template operator Size_<_Tp2>() const; + + //! conversion to the old-style OpenCV types + operator CvSize() const; + operator CvSize2D32f() const; + + _Tp width, height; // the width and the height +}; + +//////////////////////////////// Rect_ //////////////////////////////// + +/*! + The 2D up-right rectangle class + + The class represents a 2D rectangle with coordinates of the specified data type. + Normally, cv::Rect ~ cv::Rect_ is used. +*/ +template class CV_EXPORTS Rect_ +{ +public: + typedef _Tp value_type; + + //! various constructors + Rect_(); + Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height); + Rect_(const Rect_& r); + Rect_(const CvRect& r); + Rect_(const Point_<_Tp>& org, const Size_<_Tp>& sz); + Rect_(const Point_<_Tp>& pt1, const Point_<_Tp>& pt2); + + Rect_& operator = ( const Rect_& r ); + //! the top-left corner + Point_<_Tp> tl() const; + //! the bottom-right corner + Point_<_Tp> br() const; + + //! size (width, height) of the rectangle + Size_<_Tp> size() const; + //! area (width*height) of the rectangle + _Tp area() const; + + //! conversion to another data type + template operator Rect_<_Tp2>() const; + //! conversion to the old-style CvRect + operator CvRect() const; + + //! checks whether the rectangle contains the point + bool contains(const Point_<_Tp>& pt) const; + + _Tp x, y, width, height; //< the top-left corner, as well as width and height of the rectangle +}; + + +/*! + \typedef + + shorter aliases for the most popular cv::Point_<>, cv::Size_<> and cv::Rect_<> specializations +*/ +typedef Point_ Point2i; +typedef Point2i Point; +typedef Size_ Size2i; +typedef Size2i Size; +typedef Rect_ Rect; +typedef Point_ Point2f; +typedef Point_ Point2d; +typedef Size_ Size2f; +typedef Point3_ Point3i; +typedef Point3_ Point3f; +typedef Point3_ Point3d; + + +/*! + The rotated 2D rectangle. + + The class represents rotated (i.e. not up-right) rectangles on a plane. + Each rectangle is described by the center point (mass center), length of each side + (represented by cv::Size2f structure) and the rotation angle in degrees. +*/ +class CV_EXPORTS RotatedRect +{ +public: + //! various constructors + RotatedRect(); + RotatedRect(const Point2f& center, const Size2f& size, float angle); + RotatedRect(const CvBox2D& box); + + //! returns 4 vertices of the rectangle + void points(Point2f pts[]) const; + //! returns the minimal up-right rectangle containing the rotated rectangle + Rect boundingRect() const; + //! conversion to the old-style CvBox2D structure + operator CvBox2D() const; + + Point2f center; //< the rectangle mass center + Size2f size; //< width and height of the rectangle + float angle; //< the rotation angle. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle. +}; + +//////////////////////////////// Scalar_ /////////////////////////////// + +/*! + The template scalar class. + + This is partially specialized cv::Vec class with the number of elements = 4, i.e. a short vector of four elements. + Normally, cv::Scalar ~ cv::Scalar_ is used. +*/ +template class CV_EXPORTS Scalar_ : public Vec<_Tp, 4> +{ +public: + //! various constructors + Scalar_(); + Scalar_(_Tp v0, _Tp v1, _Tp v2=0, _Tp v3=0); + Scalar_(const CvScalar& s); + Scalar_(_Tp v0); + + //! returns a scalar with all elements set to v0 + static Scalar_<_Tp> all(_Tp v0); + //! conversion to the old-style CvScalar + operator CvScalar() const; + + //! conversion to another data type + template operator Scalar_() const; + + //! per-element product + Scalar_<_Tp> mul(const Scalar_<_Tp>& t, double scale=1 ) const; + + // returns (v0, -v1, -v2, -v3) + Scalar_<_Tp> conj() const; + + // returns true iff v1 == v2 == v3 == 0 + bool isReal() const; +}; + +typedef Scalar_ Scalar; + +CV_EXPORTS void scalarToRawData(const Scalar& s, void* buf, int type, int unroll_to=0); + +//////////////////////////////// Range ///////////////////////////////// + +/*! + The 2D range class + + This is the class used to specify a continuous subsequence, i.e. part of a contour, or a column span in a matrix. +*/ +class CV_EXPORTS Range +{ +public: + Range(); + Range(int _start, int _end); + Range(const CvSlice& slice); + int size() const; + bool empty() const; + static Range all(); + operator CvSlice() const; + + int start, end; +}; + +/////////////////////////////// DataType //////////////////////////////// + +/*! + Informative template class for OpenCV "scalars". + + The class is specialized for each primitive numerical type supported by OpenCV (such as unsigned char or float), + as well as for more complex types, like cv::Complex<>, std::complex<>, cv::Vec<> etc. + The common property of all such types (called "scalars", do not confuse it with cv::Scalar_) + is that each of them is basically a tuple of numbers of the same type. Each "scalar" can be represented + by the depth id (CV_8U ... CV_64F) and the number of channels. + OpenCV matrices, 2D or nD, dense or sparse, can store "scalars", + as long as the number of channels does not exceed CV_CN_MAX. +*/ +template class DataType +{ +public: + typedef _Tp value_type; + typedef value_type work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 1, depth = -1, channels = 1, fmt=0, + type = CV_MAKETYPE(depth, channels) }; +}; + +template<> class DataType +{ +public: + typedef bool value_type; + typedef int work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 1, + fmt=DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; +}; + +template<> class DataType +{ +public: + typedef uchar value_type; + typedef int work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 1, + fmt=DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; +}; + +template<> class DataType +{ +public: + typedef schar value_type; + typedef int work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 1, + fmt=DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; +}; + +template<> class DataType +{ +public: + typedef schar value_type; + typedef int work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 1, + fmt=DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; +}; + +template<> class DataType +{ +public: + typedef ushort value_type; + typedef int work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 1, + fmt=DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; +}; + +template<> class DataType +{ +public: + typedef short value_type; + typedef int work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 1, + fmt=DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; +}; + +template<> class DataType +{ +public: + typedef int value_type; + typedef value_type work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 1, + fmt=DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; +}; + +template<> class DataType +{ +public: + typedef float value_type; + typedef value_type work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 1, + fmt=DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; +}; + +template<> class DataType +{ +public: + typedef double value_type; + typedef value_type work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 1, + fmt=DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; +}; + +template class DataType > +{ +public: + typedef Vec<_Tp, cn> value_type; + typedef Vec::work_type, cn> work_type; + typedef _Tp channel_type; + typedef value_type vec_type; + enum { generic_type = 0, depth = DataDepth::value, channels = cn, + fmt = ((channels-1)<<8) + DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; +}; + +template class DataType > +{ +public: + typedef std::complex<_Tp> value_type; + typedef value_type work_type; + typedef _Tp channel_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 2, + fmt = ((channels-1)<<8) + DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; + typedef Vec vec_type; +}; + +template class DataType > +{ +public: + typedef Complex<_Tp> value_type; + typedef value_type work_type; + typedef _Tp channel_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 2, + fmt = ((channels-1)<<8) + DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; + typedef Vec vec_type; +}; + +template class DataType > +{ +public: + typedef Point_<_Tp> value_type; + typedef Point_::work_type> work_type; + typedef _Tp channel_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 2, + fmt = ((channels-1)<<8) + DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; + typedef Vec vec_type; +}; + +template class DataType > +{ +public: + typedef Point3_<_Tp> value_type; + typedef Point3_::work_type> work_type; + typedef _Tp channel_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 3, + fmt = ((channels-1)<<8) + DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; + typedef Vec vec_type; +}; + +template class DataType > +{ +public: + typedef Size_<_Tp> value_type; + typedef Size_::work_type> work_type; + typedef _Tp channel_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 2, + fmt = ((channels-1)<<8) + DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; + typedef Vec vec_type; +}; + +template class DataType > +{ +public: + typedef Rect_<_Tp> value_type; + typedef Rect_::work_type> work_type; + typedef _Tp channel_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 4, + fmt = ((channels-1)<<8) + DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; + typedef Vec vec_type; +}; + +template class DataType > +{ +public: + typedef Scalar_<_Tp> value_type; + typedef Scalar_::work_type> work_type; + typedef _Tp channel_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 4, + fmt = ((channels-1)<<8) + DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; + typedef Vec vec_type; +}; + +template<> class DataType +{ +public: + typedef Range value_type; + typedef value_type work_type; + typedef int channel_type; + enum { generic_type = 0, depth = DataDepth::value, channels = 2, + fmt = ((channels-1)<<8) + DataDepth::fmt, + type = CV_MAKETYPE(depth, channels) }; + typedef Vec vec_type; +}; + +//////////////////// generic_type ref-counting pointer class for C/C++ objects //////////////////////// + +/*! + Smart pointer to dynamically allocated objects. + + This is template pointer-wrapping class that stores the associated reference counter along with the + object pointer. The class is similar to std::smart_ptr<> from the recent addons to the C++ standard, + but is shorter to write :) and self-contained (i.e. does add any dependency on the compiler or an external library). + + Basically, you can use "Ptr ptr" (or faster "const Ptr& ptr" for read-only access) + everywhere instead of "MyObjectType* ptr", where MyObjectType is some C structure or a C++ class. + To make it all work, you need to specialize Ptr<>::delete_obj(), like: + + \code + template<> void Ptr::delete_obj() { call_destructor_func(obj); } + \endcode + + \note{if MyObjectType is a C++ class with a destructor, you do not need to specialize delete_obj(), + since the default implementation calls "delete obj;"} + + \note{Another good property of the class is that the operations on the reference counter are atomic, + i.e. it is safe to use the class in multi-threaded applications} +*/ +template class CV_EXPORTS Ptr +{ +public: + //! empty constructor + Ptr(); + //! take ownership of the pointer. The associated reference counter is allocated and set to 1 + Ptr(_Tp* _obj); + //! calls release() + ~Ptr(); + //! copy constructor. Copies the members and calls addref() + Ptr(const Ptr& ptr); + template Ptr(const Ptr<_Tp2>& ptr); + //! copy operator. Calls ptr.addref() and release() before copying the members + Ptr& operator = (const Ptr& ptr); + //! increments the reference counter + void addref(); + //! decrements the reference counter. If it reaches 0, delete_obj() is called + void release(); + //! deletes the object. Override if needed + void delete_obj(); + //! returns true iff obj==NULL + bool empty() const; + + //! cast pointer to another type + template Ptr<_Tp2> ptr(); + template const Ptr<_Tp2> ptr() const; + + //! helper operators making "Ptr ptr" use very similar to "T* ptr". + _Tp* operator -> (); + const _Tp* operator -> () const; + + operator _Tp* (); + operator const _Tp*() const; + + _Tp* obj; //< the object pointer. + int* refcount; //< the associated reference counter +}; + + +//////////////////////// Input/Output Array Arguments ///////////////////////////////// + +/*! + Proxy datatype for passing Mat's and vector<>'s as input parameters + */ +class CV_EXPORTS _InputArray +{ +public: + enum { + KIND_SHIFT = 16, + FIXED_TYPE = 0x8000 << KIND_SHIFT, + FIXED_SIZE = 0x4000 << KIND_SHIFT, + KIND_MASK = ~(FIXED_TYPE|FIXED_SIZE) - (1 << KIND_SHIFT) + 1, + + NONE = 0 << KIND_SHIFT, + MAT = 1 << KIND_SHIFT, + MATX = 2 << KIND_SHIFT, + STD_VECTOR = 3 << KIND_SHIFT, + STD_VECTOR_VECTOR = 4 << KIND_SHIFT, + STD_VECTOR_MAT = 5 << KIND_SHIFT, + EXPR = 6 << KIND_SHIFT, + OPENGL_BUFFER = 7 << KIND_SHIFT, + OPENGL_TEXTURE = 8 << KIND_SHIFT, + GPU_MAT = 9 << KIND_SHIFT + }; + _InputArray(); + + _InputArray(const Mat& m); + _InputArray(const MatExpr& expr); + template _InputArray(const _Tp* vec, int n); + template _InputArray(const vector<_Tp>& vec); + template _InputArray(const vector >& vec); + _InputArray(const vector& vec); + template _InputArray(const vector >& vec); + template _InputArray(const Mat_<_Tp>& m); + template _InputArray(const Matx<_Tp, m, n>& matx); + _InputArray(const Scalar& s); + _InputArray(const double& val); + _InputArray(const GlBuffer& buf); + _InputArray(const GlTexture& tex); + _InputArray(const gpu::GpuMat& d_mat); + + virtual Mat getMat(int i=-1) const; + virtual void getMatVector(vector& mv) const; + virtual GlBuffer getGlBuffer() const; + virtual GlTexture getGlTexture() const; + virtual gpu::GpuMat getGpuMat() const; + + virtual int kind() const; + virtual Size size(int i=-1) const; + virtual size_t total(int i=-1) const; + virtual int type(int i=-1) const; + virtual int depth(int i=-1) const; + virtual int channels(int i=-1) const; + virtual bool empty() const; + + virtual ~_InputArray(); + + int flags; + void* obj; + Size sz; +}; + + +enum +{ + DEPTH_MASK_8U = 1 << CV_8U, + DEPTH_MASK_8S = 1 << CV_8S, + DEPTH_MASK_16U = 1 << CV_16U, + DEPTH_MASK_16S = 1 << CV_16S, + DEPTH_MASK_32S = 1 << CV_32S, + DEPTH_MASK_32F = 1 << CV_32F, + DEPTH_MASK_64F = 1 << CV_64F, + DEPTH_MASK_ALL = (DEPTH_MASK_64F<<1)-1, + DEPTH_MASK_ALL_BUT_8S = DEPTH_MASK_ALL & ~DEPTH_MASK_8S, + DEPTH_MASK_FLT = DEPTH_MASK_32F + DEPTH_MASK_64F +}; + + +/*! + Proxy datatype for passing Mat's and vector<>'s as input parameters + */ +class CV_EXPORTS _OutputArray : public _InputArray +{ +public: + _OutputArray(); + + _OutputArray(Mat& m); + template _OutputArray(vector<_Tp>& vec); + template _OutputArray(vector >& vec); + _OutputArray(vector& vec); + template _OutputArray(vector >& vec); + template _OutputArray(Mat_<_Tp>& m); + template _OutputArray(Matx<_Tp, m, n>& matx); + template _OutputArray(_Tp* vec, int n); + + _OutputArray(const Mat& m); + template _OutputArray(const vector<_Tp>& vec); + template _OutputArray(const vector >& vec); + _OutputArray(const vector& vec); + template _OutputArray(const vector >& vec); + template _OutputArray(const Mat_<_Tp>& m); + template _OutputArray(const Matx<_Tp, m, n>& matx); + template _OutputArray(const _Tp* vec, int n); + + virtual bool fixedSize() const; + virtual bool fixedType() const; + virtual bool needed() const; + virtual Mat& getMatRef(int i=-1) const; + virtual void create(Size sz, int type, int i=-1, bool allowTransposed=false, int fixedDepthMask=0) const; + virtual void create(int rows, int cols, int type, int i=-1, bool allowTransposed=false, int fixedDepthMask=0) const; + virtual void create(int dims, const int* size, int type, int i=-1, bool allowTransposed=false, int fixedDepthMask=0) const; + virtual void release() const; + virtual void clear() const; + + virtual ~_OutputArray(); +}; + +typedef const _InputArray& InputArray; +typedef InputArray InputArrayOfArrays; +typedef const _OutputArray& OutputArray; +typedef OutputArray OutputArrayOfArrays; +typedef OutputArray InputOutputArray; +typedef OutputArray InputOutputArrayOfArrays; + +CV_EXPORTS OutputArray noArray(); + +/////////////////////////////////////// Mat /////////////////////////////////////////// + +enum { MAGIC_MASK=0xFFFF0000, TYPE_MASK=0x00000FFF, DEPTH_MASK=7 }; + +static inline size_t getElemSize(int type) { return CV_ELEM_SIZE(type); } + +/*! + Custom array allocator + +*/ +class CV_EXPORTS MatAllocator +{ +public: + MatAllocator() {} + virtual ~MatAllocator() {} + virtual void allocate(int dims, const int* sizes, int type, int*& refcount, + uchar*& datastart, uchar*& data, size_t* step) = 0; + virtual void deallocate(int* refcount, uchar* datastart, uchar* data) = 0; +}; + +/*! + The n-dimensional matrix class. + + The class represents an n-dimensional dense numerical array that can act as + a matrix, image, optical flow map, 3-focal tensor etc. + It is very similar to CvMat and CvMatND types from earlier versions of OpenCV, + and similarly to those types, the matrix can be multi-channel. It also fully supports ROI mechanism. + + There are many different ways to create cv::Mat object. Here are the some popular ones: +
    +
  • using cv::Mat::create(nrows, ncols, type) method or + the similar constructor cv::Mat::Mat(nrows, ncols, type[, fill_value]) constructor. + A new matrix of the specified size and specifed type will be allocated. + "type" has the same meaning as in cvCreateMat function, + e.g. CV_8UC1 means 8-bit single-channel matrix, CV_32FC2 means 2-channel (i.e. complex) + floating-point matrix etc: + + \code + // make 7x7 complex matrix filled with 1+3j. + cv::Mat M(7,7,CV_32FC2,Scalar(1,3)); + // and now turn M to 100x60 15-channel 8-bit matrix. + // The old content will be deallocated + M.create(100,60,CV_8UC(15)); + \endcode + + As noted in the introduction of this chapter, Mat::create() + will only allocate a new matrix when the current matrix dimensionality + or type are different from the specified. + +
  • by using a copy constructor or assignment operator, where on the right side it can + be a matrix or expression, see below. Again, as noted in the introduction, + matrix assignment is O(1) operation because it only copies the header + and increases the reference counter. cv::Mat::clone() method can be used to get a full + (a.k.a. deep) copy of the matrix when you need it. + +
  • by constructing a header for a part of another matrix. It can be a single row, single column, + several rows, several columns, rectangular region in the matrix (called a minor in algebra) or + a diagonal. Such operations are also O(1), because the new header will reference the same data. + You can actually modify a part of the matrix using this feature, e.g. + + \code + // add 5-th row, multiplied by 3 to the 3rd row + M.row(3) = M.row(3) + M.row(5)*3; + + // now copy 7-th column to the 1-st column + // M.col(1) = M.col(7); // this will not work + Mat M1 = M.col(1); + M.col(7).copyTo(M1); + + // create new 320x240 image + cv::Mat img(Size(320,240),CV_8UC3); + // select a roi + cv::Mat roi(img, Rect(10,10,100,100)); + // fill the ROI with (0,255,0) (which is green in RGB space); + // the original 320x240 image will be modified + roi = Scalar(0,255,0); + \endcode + + Thanks to the additional cv::Mat::datastart and cv::Mat::dataend members, it is possible to + compute the relative sub-matrix position in the main "container" matrix using cv::Mat::locateROI(): + + \code + Mat A = Mat::eye(10, 10, CV_32S); + // extracts A columns, 1 (inclusive) to 3 (exclusive). + Mat B = A(Range::all(), Range(1, 3)); + // extracts B rows, 5 (inclusive) to 9 (exclusive). + // that is, C ~ A(Range(5, 9), Range(1, 3)) + Mat C = B(Range(5, 9), Range::all()); + Size size; Point ofs; + C.locateROI(size, ofs); + // size will be (width=10,height=10) and the ofs will be (x=1, y=5) + \endcode + + As in the case of whole matrices, if you need a deep copy, use cv::Mat::clone() method + of the extracted sub-matrices. + +
  • by making a header for user-allocated-data. It can be useful for +
      +
    1. processing "foreign" data using OpenCV (e.g. when you implement + a DirectShow filter or a processing module for gstreamer etc.), e.g. + + \code + void process_video_frame(const unsigned char* pixels, + int width, int height, int step) + { + cv::Mat img(height, width, CV_8UC3, pixels, step); + cv::GaussianBlur(img, img, cv::Size(7,7), 1.5, 1.5); + } + \endcode + +
    2. for quick initialization of small matrices and/or super-fast element access + + \code + double m[3][3] = {{a, b, c}, {d, e, f}, {g, h, i}}; + cv::Mat M = cv::Mat(3, 3, CV_64F, m).inv(); + \endcode +
    + + partial yet very common cases of this "user-allocated data" case are conversions + from CvMat and IplImage to cv::Mat. For this purpose there are special constructors + taking pointers to CvMat or IplImage and the optional + flag indicating whether to copy the data or not. + + Backward conversion from cv::Mat to CvMat or IplImage is provided via cast operators + cv::Mat::operator CvMat() an cv::Mat::operator IplImage(). + The operators do not copy the data. + + + \code + IplImage* img = cvLoadImage("greatwave.jpg", 1); + Mat mtx(img); // convert IplImage* -> cv::Mat + CvMat oldmat = mtx; // convert cv::Mat -> CvMat + CV_Assert(oldmat.cols == img->width && oldmat.rows == img->height && + oldmat.data.ptr == (uchar*)img->imageData && oldmat.step == img->widthStep); + \endcode + +
  • by using MATLAB-style matrix initializers, cv::Mat::zeros(), cv::Mat::ones(), cv::Mat::eye(), e.g.: + + \code + // create a double-precision identity martix and add it to M. + M += Mat::eye(M.rows, M.cols, CV_64F); + \endcode + +
  • by using comma-separated initializer: + + \code + // create 3x3 double-precision identity matrix + Mat M = (Mat_(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1); + \endcode + + here we first call constructor of cv::Mat_ class (that we describe further) with the proper matrix, + and then we just put "<<" operator followed by comma-separated values that can be constants, + variables, expressions etc. Also, note the extra parentheses that are needed to avoid compiler errors. + +
+ + Once matrix is created, it will be automatically managed by using reference-counting mechanism + (unless the matrix header is built on top of user-allocated data, + in which case you should handle the data by yourself). + The matrix data will be deallocated when no one points to it; + if you want to release the data pointed by a matrix header before the matrix destructor is called, + use cv::Mat::release(). + + The next important thing to learn about the matrix class is element access. Here is how the matrix is stored. + The elements are stored in row-major order (row by row). The cv::Mat::data member points to the first element of the first row, + cv::Mat::rows contains the number of matrix rows and cv::Mat::cols - the number of matrix columns. There is yet another member, + cv::Mat::step that is used to actually compute address of a matrix element. cv::Mat::step is needed because the matrix can be + a part of another matrix or because there can some padding space in the end of each row for a proper alignment. + + \image html roi.png + + Given these parameters, address of the matrix element M_{ij} is computed as following: + + addr(M_{ij})=M.data + M.step*i + j*M.elemSize() + + if you know the matrix element type, e.g. it is float, then you can use cv::Mat::at() method: + + addr(M_{ij})=&M.at(i,j) + + (where & is used to convert the reference returned by cv::Mat::at() to a pointer). + if you need to process a whole row of matrix, the most efficient way is to get + the pointer to the row first, and then just use plain C operator []: + + \code + // compute sum of positive matrix elements + // (assuming that M is double-precision matrix) + double sum=0; + for(int i = 0; i < M.rows; i++) + { + const double* Mi = M.ptr(i); + for(int j = 0; j < M.cols; j++) + sum += std::max(Mi[j], 0.); + } + \endcode + + Some operations, like the above one, do not actually depend on the matrix shape, + they just process elements of a matrix one by one (or elements from multiple matrices + that are sitting in the same place, e.g. matrix addition). Such operations are called + element-wise and it makes sense to check whether all the input/output matrices are continuous, + i.e. have no gaps in the end of each row, and if yes, process them as a single long row: + + \code + // compute sum of positive matrix elements, optimized variant + double sum=0; + int cols = M.cols, rows = M.rows; + if(M.isContinuous()) + { + cols *= rows; + rows = 1; + } + for(int i = 0; i < rows; i++) + { + const double* Mi = M.ptr(i); + for(int j = 0; j < cols; j++) + sum += std::max(Mi[j], 0.); + } + \endcode + in the case of continuous matrix the outer loop body will be executed just once, + so the overhead will be smaller, which will be especially noticeable in the case of small matrices. + + Finally, there are STL-style iterators that are smart enough to skip gaps between successive rows: + \code + // compute sum of positive matrix elements, iterator-based variant + double sum=0; + MatConstIterator_ it = M.begin(), it_end = M.end(); + for(; it != it_end; ++it) + sum += std::max(*it, 0.); + \endcode + + The matrix iterators are random-access iterators, so they can be passed + to any STL algorithm, including std::sort(). +*/ +class CV_EXPORTS Mat +{ +public: + //! default constructor + Mat(); + //! constructs 2D matrix of the specified size and type + // (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.) + Mat(int rows, int cols, int type); + Mat(Size size, int type); + //! constucts 2D matrix and fills it with the specified value _s. + Mat(int rows, int cols, int type, const Scalar& s); + Mat(Size size, int type, const Scalar& s); + + //! constructs n-dimensional matrix + Mat(int ndims, const int* sizes, int type); + Mat(int ndims, const int* sizes, int type, const Scalar& s); + + //! copy constructor + Mat(const Mat& m); + //! constructor for matrix headers pointing to user-allocated data + Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP); + Mat(Size size, int type, void* data, size_t step=AUTO_STEP); + Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0); + + //! creates a matrix header for a part of the bigger matrix + Mat(const Mat& m, const Range& rowRange, const Range& colRange=Range::all()); + Mat(const Mat& m, const Rect& roi); + Mat(const Mat& m, const Range* ranges); + //! converts old-style CvMat to the new matrix; the data is not copied by default + Mat(const CvMat* m, bool copyData=false); + //! converts old-style CvMatND to the new matrix; the data is not copied by default + Mat(const CvMatND* m, bool copyData=false); + //! converts old-style IplImage to the new matrix; the data is not copied by default + Mat(const IplImage* img, bool copyData=false); + //! builds matrix from std::vector with or without copying the data + template explicit Mat(const vector<_Tp>& vec, bool copyData=false); + //! builds matrix from cv::Vec; the data is copied by default + template explicit Mat(const Vec<_Tp, n>& vec, bool copyData=true); + //! builds matrix from cv::Matx; the data is copied by default + template explicit Mat(const Matx<_Tp, m, n>& mtx, bool copyData=true); + //! builds matrix from a 2D point + template explicit Mat(const Point_<_Tp>& pt, bool copyData=true); + //! builds matrix from a 3D point + template explicit Mat(const Point3_<_Tp>& pt, bool copyData=true); + //! builds matrix from comma initializer + template explicit Mat(const MatCommaInitializer_<_Tp>& commaInitializer); + + //! download data from GpuMat + explicit Mat(const gpu::GpuMat& m); + + //! destructor - calls release() + ~Mat(); + //! assignment operators + Mat& operator = (const Mat& m); + Mat& operator = (const MatExpr& expr); + + //! returns a new matrix header for the specified row + Mat row(int y) const; + //! returns a new matrix header for the specified column + Mat col(int x) const; + //! ... for the specified row span + Mat rowRange(int startrow, int endrow) const; + Mat rowRange(const Range& r) const; + //! ... for the specified column span + Mat colRange(int startcol, int endcol) const; + Mat colRange(const Range& r) const; + //! ... for the specified diagonal + // (d=0 - the main diagonal, + // >0 - a diagonal from the lower half, + // <0 - a diagonal from the upper half) + Mat diag(int d=0) const; + //! constructs a square diagonal matrix which main diagonal is vector "d" + static Mat diag(const Mat& d); + + //! returns deep copy of the matrix, i.e. the data is copied + Mat clone() const; + //! copies the matrix content to "m". + // It calls m.create(this->size(), this->type()). + void copyTo( OutputArray m ) const; + //! copies those matrix elements to "m" that are marked with non-zero mask elements. + void copyTo( OutputArray m, InputArray mask ) const; + //! converts matrix to another datatype with optional scalng. See cvConvertScale. + void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const; + + void assignTo( Mat& m, int type=-1 ) const; + + //! sets every matrix element to s + Mat& operator = (const Scalar& s); + //! sets some of the matrix elements to s, according to the mask + Mat& setTo(InputArray value, InputArray mask=noArray()); + //! creates alternative matrix header for the same data, with different + // number of channels and/or different number of rows. see cvReshape. + Mat reshape(int cn, int rows=0) const; + Mat reshape(int cn, int newndims, const int* newsz) const; + + //! matrix transposition by means of matrix expressions + MatExpr t() const; + //! matrix inversion by means of matrix expressions + MatExpr inv(int method=DECOMP_LU) const; + //! per-element matrix multiplication by means of matrix expressions + MatExpr mul(InputArray m, double scale=1) const; + + //! computes cross-product of 2 3D vectors + Mat cross(InputArray m) const; + //! computes dot-product + double dot(InputArray m) const; + + //! Matlab-style matrix initialization + static MatExpr zeros(int rows, int cols, int type); + static MatExpr zeros(Size size, int type); + static MatExpr zeros(int ndims, const int* sz, int type); + static MatExpr ones(int rows, int cols, int type); + static MatExpr ones(Size size, int type); + static MatExpr ones(int ndims, const int* sz, int type); + static MatExpr eye(int rows, int cols, int type); + static MatExpr eye(Size size, int type); + + //! allocates new matrix data unless the matrix already has specified size and type. + // previous data is unreferenced if needed. + void create(int rows, int cols, int type); + void create(Size size, int type); + void create(int ndims, const int* sizes, int type); + + //! increases the reference counter; use with care to avoid memleaks + void addref(); + //! decreases reference counter; + // deallocates the data when reference counter reaches 0. + void release(); + + //! deallocates the matrix data + void deallocate(); + //! internal use function; properly re-allocates _size, _step arrays + void copySize(const Mat& m); + + //! reserves enough space to fit sz hyper-planes + void reserve(size_t sz); + //! resizes matrix to the specified number of hyper-planes + void resize(size_t sz); + //! resizes matrix to the specified number of hyper-planes; initializes the newly added elements + void resize(size_t sz, const Scalar& s); + //! internal function + void push_back_(const void* elem); + //! adds element to the end of 1d matrix (or possibly multiple elements when _Tp=Mat) + template void push_back(const _Tp& elem); + template void push_back(const Mat_<_Tp>& elem); + void push_back(const Mat& m); + //! removes several hyper-planes from bottom of the matrix + void pop_back(size_t nelems=1); + + //! locates matrix header within a parent matrix. See below + void locateROI( Size& wholeSize, Point& ofs ) const; + //! moves/resizes the current matrix ROI inside the parent matrix. + Mat& adjustROI( int dtop, int dbottom, int dleft, int dright ); + //! extracts a rectangular sub-matrix + // (this is a generalized form of row, rowRange etc.) + Mat operator()( Range rowRange, Range colRange ) const; + Mat operator()( const Rect& roi ) const; + Mat operator()( const Range* ranges ) const; + + //! converts header to CvMat; no data is copied + operator CvMat() const; + //! converts header to CvMatND; no data is copied + operator CvMatND() const; + //! converts header to IplImage; no data is copied + operator IplImage() const; + + template operator vector<_Tp>() const; + template operator Vec<_Tp, n>() const; + template operator Matx<_Tp, m, n>() const; + + //! returns true iff the matrix data is continuous + // (i.e. when there are no gaps between successive rows). + // similar to CV_IS_MAT_CONT(cvmat->type) + bool isContinuous() const; + + //! returns true if the matrix is a submatrix of another matrix + bool isSubmatrix() const; + + //! returns element size in bytes, + // similar to CV_ELEM_SIZE(cvmat->type) + size_t elemSize() const; + //! returns the size of element channel in bytes. + size_t elemSize1() const; + //! returns element type, similar to CV_MAT_TYPE(cvmat->type) + int type() const; + //! returns element type, similar to CV_MAT_DEPTH(cvmat->type) + int depth() const; + //! returns element type, similar to CV_MAT_CN(cvmat->type) + int channels() const; + //! returns step/elemSize1() + size_t step1(int i=0) const; + //! returns true if matrix data is NULL + bool empty() const; + //! returns the total number of matrix elements + size_t total() const; + + //! returns N if the matrix is 1-channel (N x ptdim) or ptdim-channel (1 x N) or (N x 1); negative number otherwise + int checkVector(int elemChannels, int depth=-1, bool requireContinuous=true) const; + + //! returns pointer to i0-th submatrix along the dimension #0 + uchar* ptr(int i0=0); + const uchar* ptr(int i0=0) const; + + //! returns pointer to (i0,i1) submatrix along the dimensions #0 and #1 + uchar* ptr(int i0, int i1); + const uchar* ptr(int i0, int i1) const; + + //! returns pointer to (i0,i1,i3) submatrix along the dimensions #0, #1, #2 + uchar* ptr(int i0, int i1, int i2); + const uchar* ptr(int i0, int i1, int i2) const; + + //! returns pointer to the matrix element + uchar* ptr(const int* idx); + //! returns read-only pointer to the matrix element + const uchar* ptr(const int* idx) const; + + template uchar* ptr(const Vec& idx); + template const uchar* ptr(const Vec& idx) const; + + //! template version of the above method + template _Tp* ptr(int i0=0); + template const _Tp* ptr(int i0=0) const; + + template _Tp* ptr(int i0, int i1); + template const _Tp* ptr(int i0, int i1) const; + + template _Tp* ptr(int i0, int i1, int i2); + template const _Tp* ptr(int i0, int i1, int i2) const; + + template _Tp* ptr(const int* idx); + template const _Tp* ptr(const int* idx) const; + + template _Tp* ptr(const Vec& idx); + template const _Tp* ptr(const Vec& idx) const; + + //! the same as above, with the pointer dereferencing + template _Tp& at(int i0=0); + template const _Tp& at(int i0=0) const; + + template _Tp& at(int i0, int i1); + template const _Tp& at(int i0, int i1) const; + + template _Tp& at(int i0, int i1, int i2); + template const _Tp& at(int i0, int i1, int i2) const; + + template _Tp& at(const int* idx); + template const _Tp& at(const int* idx) const; + + template _Tp& at(const Vec& idx); + template const _Tp& at(const Vec& idx) const; + + //! special versions for 2D arrays (especially convenient for referencing image pixels) + template _Tp& at(Point pt); + template const _Tp& at(Point pt) const; + + //! template methods for iteration over matrix elements. + // the iterators take care of skipping gaps in the end of rows (if any) + template MatIterator_<_Tp> begin(); + template MatIterator_<_Tp> end(); + template MatConstIterator_<_Tp> begin() const; + template MatConstIterator_<_Tp> end() const; + + enum { MAGIC_VAL=0x42FF0000, AUTO_STEP=0, CONTINUOUS_FLAG=CV_MAT_CONT_FLAG, SUBMATRIX_FLAG=CV_SUBMAT_FLAG }; + + /*! includes several bit-fields: + - the magic signature + - continuity flag + - depth + - number of channels + */ + int flags; + //! the matrix dimensionality, >= 2 + int dims; + //! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions + int rows, cols; + //! pointer to the data + uchar* data; + + //! pointer to the reference counter; + // when matrix points to user-allocated data, the pointer is NULL + int* refcount; + + //! helper fields used in locateROI and adjustROI + uchar* datastart; + uchar* dataend; + uchar* datalimit; + + //! custom allocator + MatAllocator* allocator; + + struct CV_EXPORTS MSize + { + MSize(int* _p); + Size operator()() const; + const int& operator[](int i) const; + int& operator[](int i); + operator const int*() const; + bool operator == (const MSize& sz) const; + bool operator != (const MSize& sz) const; + + int* p; + }; + + struct CV_EXPORTS MStep + { + MStep(); + MStep(size_t s); + const size_t& operator[](int i) const; + size_t& operator[](int i); + operator size_t() const; + MStep& operator = (size_t s); + + size_t* p; + size_t buf[2]; + protected: + MStep& operator = (const MStep&); + }; + + MSize size; + MStep step; + +protected: + void initEmpty(); +}; + + +/*! + Random Number Generator + + The class implements RNG using Multiply-with-Carry algorithm +*/ +class CV_EXPORTS RNG +{ +public: + enum { UNIFORM=0, NORMAL=1 }; + + RNG(); + RNG(uint64 state); + //! updates the state and returns the next 32-bit unsigned integer random number + unsigned next(); + + operator uchar(); + operator schar(); + operator ushort(); + operator short(); + operator unsigned(); + //! returns a random integer sampled uniformly from [0, N). + unsigned operator ()(unsigned N); + unsigned operator ()(); + operator int(); + operator float(); + operator double(); + //! returns uniformly distributed integer random number from [a,b) range + int uniform(int a, int b); + //! returns uniformly distributed floating-point random number from [a,b) range + float uniform(float a, float b); + //! returns uniformly distributed double-precision floating-point random number from [a,b) range + double uniform(double a, double b); + void fill( InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange=false ); + //! returns Gaussian random variate with mean zero. + double gaussian(double sigma); + + uint64 state; +}; + + +/*! + Termination criteria in iterative algorithms + */ +class CV_EXPORTS TermCriteria +{ +public: + enum + { + COUNT=1, //!< the maximum number of iterations or elements to compute + MAX_ITER=COUNT, //!< ditto + EPS=2 //!< the desired accuracy or change in parameters at which the iterative algorithm stops + }; + + //! default constructor + TermCriteria(); + //! full constructor + TermCriteria(int _type, int _maxCount, double _epsilon); + //! conversion from CvTermCriteria + TermCriteria(const CvTermCriteria& criteria); + //! conversion from CvTermCriteria + operator CvTermCriteria() const; + + int type; //!< the type of termination criteria: COUNT, EPS or COUNT + EPS + int maxCount; // the maximum number of iterations/elements + double epsilon; // the desired accuracy +}; + + +typedef void (*BinaryFunc)(const uchar* src1, size_t step1, + const uchar* src2, size_t step2, + uchar* dst, size_t step, Size sz, + void*); + +CV_EXPORTS BinaryFunc getConvertFunc(int sdepth, int ddepth); +CV_EXPORTS BinaryFunc getConvertScaleFunc(int sdepth, int ddepth); +CV_EXPORTS BinaryFunc getCopyMaskFunc(size_t esz); + +//! swaps two matrices +CV_EXPORTS void swap(Mat& a, Mat& b); + +//! converts array (CvMat or IplImage) to cv::Mat +CV_EXPORTS Mat cvarrToMat(const CvArr* arr, bool copyData=false, + bool allowND=true, int coiMode=0); +//! extracts Channel of Interest from CvMat or IplImage and makes cv::Mat out of it. +CV_EXPORTS void extractImageCOI(const CvArr* arr, OutputArray coiimg, int coi=-1); +//! inserts single-channel cv::Mat into a multi-channel CvMat or IplImage +CV_EXPORTS void insertImageCOI(InputArray coiimg, CvArr* arr, int coi=-1); + +//! adds one matrix to another (dst = src1 + src2) +CV_EXPORTS_W void add(InputArray src1, InputArray src2, OutputArray dst, + InputArray mask=noArray(), int dtype=-1); +//! subtracts one matrix from another (dst = src1 - src2) +CV_EXPORTS_W void subtract(InputArray src1, InputArray src2, OutputArray dst, + InputArray mask=noArray(), int dtype=-1); + +//! computes element-wise weighted product of the two arrays (dst = scale*src1*src2) +CV_EXPORTS_W void multiply(InputArray src1, InputArray src2, + OutputArray dst, double scale=1, int dtype=-1); + +//! computes element-wise weighted quotient of the two arrays (dst = scale*src1/src2) +CV_EXPORTS_W void divide(InputArray src1, InputArray src2, OutputArray dst, + double scale=1, int dtype=-1); + +//! computes element-wise weighted reciprocal of an array (dst = scale/src2) +CV_EXPORTS_W void divide(double scale, InputArray src2, + OutputArray dst, int dtype=-1); + +//! adds scaled array to another one (dst = alpha*src1 + src2) +CV_EXPORTS_W void scaleAdd(InputArray src1, double alpha, InputArray src2, OutputArray dst); + +//! computes weighted sum of two arrays (dst = alpha*src1 + beta*src2 + gamma) +CV_EXPORTS_W void addWeighted(InputArray src1, double alpha, InputArray src2, + double beta, double gamma, OutputArray dst, int dtype=-1); + +//! scales array elements, computes absolute values and converts the results to 8-bit unsigned integers: dst(i)=saturate_castabs(src(i)*alpha+beta) +CV_EXPORTS_W void convertScaleAbs(InputArray src, OutputArray dst, + double alpha=1, double beta=0); +//! transforms array of numbers using a lookup table: dst(i)=lut(src(i)) +CV_EXPORTS_W void LUT(InputArray src, InputArray lut, OutputArray dst, + int interpolation=0); + +//! computes sum of array elements +CV_EXPORTS_AS(sumElems) Scalar sum(InputArray src); +//! computes the number of nonzero array elements +CV_EXPORTS_W int countNonZero( InputArray src ); +//! computes mean value of selected array elements +CV_EXPORTS_W Scalar mean(InputArray src, InputArray mask=noArray()); +//! computes mean value and standard deviation of all or selected array elements +CV_EXPORTS_W void meanStdDev(InputArray src, OutputArray mean, OutputArray stddev, + InputArray mask=noArray()); +//! computes norm of the selected array part +CV_EXPORTS_W double norm(InputArray src1, int normType=NORM_L2, InputArray mask=noArray()); +//! computes norm of selected part of the difference between two arrays +CV_EXPORTS_W double norm(InputArray src1, InputArray src2, + int normType=NORM_L2, InputArray mask=noArray()); + +//! naive nearest neighbor finder +CV_EXPORTS_W void batchDistance(InputArray src1, InputArray src2, + OutputArray dist, int dtype, OutputArray nidx, + int normType=NORM_L2, int K=0, + InputArray mask=noArray(), int update=0, + bool crosscheck=false); + +//! scales and shifts array elements so that either the specified norm (alpha) or the minimum (alpha) and maximum (beta) array values get the specified values +CV_EXPORTS_W void normalize( InputArray src, OutputArray dst, double alpha=1, double beta=0, + int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray()); + +//! finds global minimum and maximum array elements and returns their values and their locations +CV_EXPORTS_W void minMaxLoc(InputArray src, CV_OUT double* minVal, + CV_OUT double* maxVal=0, CV_OUT Point* minLoc=0, + CV_OUT Point* maxLoc=0, InputArray mask=noArray()); +CV_EXPORTS void minMaxIdx(InputArray src, double* minVal, double* maxVal, + int* minIdx=0, int* maxIdx=0, InputArray mask=noArray()); + +//! transforms 2D matrix to 1D row or column vector by taking sum, minimum, maximum or mean value over all the rows +CV_EXPORTS_W void reduce(InputArray src, OutputArray dst, int dim, int rtype, int dtype=-1); + +//! makes multi-channel array out of several single-channel arrays +CV_EXPORTS void merge(const Mat* mv, size_t count, OutputArray dst); +//! makes multi-channel array out of several single-channel arrays +CV_EXPORTS_W void merge(InputArrayOfArrays mv, OutputArray dst); + +//! copies each plane of a multi-channel array to a dedicated array +CV_EXPORTS void split(const Mat& src, Mat* mvbegin); +//! copies each plane of a multi-channel array to a dedicated array +CV_EXPORTS_W void split(InputArray m, OutputArrayOfArrays mv); + +//! copies selected channels from the input arrays to the selected channels of the output arrays +CV_EXPORTS void mixChannels(const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, + const int* fromTo, size_t npairs); +CV_EXPORTS void mixChannels(const vector& src, vector& dst, + const int* fromTo, size_t npairs); +CV_EXPORTS_W void mixChannels(InputArrayOfArrays src, InputArrayOfArrays dst, + const vector& fromTo); + +//! extracts a single channel from src (coi is 0-based index) +CV_EXPORTS_W void extractChannel(InputArray src, OutputArray dst, int coi); + +//! inserts a single channel to dst (coi is 0-based index) +CV_EXPORTS_W void insertChannel(InputArray src, InputOutputArray dst, int coi); + +//! reverses the order of the rows, columns or both in a matrix +CV_EXPORTS_W void flip(InputArray src, OutputArray dst, int flipCode); + +//! replicates the input matrix the specified number of times in the horizontal and/or vertical direction +CV_EXPORTS_W void repeat(InputArray src, int ny, int nx, OutputArray dst); +CV_EXPORTS Mat repeat(const Mat& src, int ny, int nx); + +CV_EXPORTS void hconcat(const Mat* src, size_t nsrc, OutputArray dst); +CV_EXPORTS void hconcat(InputArray src1, InputArray src2, OutputArray dst); +CV_EXPORTS_W void hconcat(InputArrayOfArrays src, OutputArray dst); + +CV_EXPORTS void vconcat(const Mat* src, size_t nsrc, OutputArray dst); +CV_EXPORTS void vconcat(InputArray src1, InputArray src2, OutputArray dst); +CV_EXPORTS_W void vconcat(InputArrayOfArrays src, OutputArray dst); + +//! computes bitwise conjunction of the two arrays (dst = src1 & src2) +CV_EXPORTS_W void bitwise_and(InputArray src1, InputArray src2, + OutputArray dst, InputArray mask=noArray()); +//! computes bitwise disjunction of the two arrays (dst = src1 | src2) +CV_EXPORTS_W void bitwise_or(InputArray src1, InputArray src2, + OutputArray dst, InputArray mask=noArray()); +//! computes bitwise exclusive-or of the two arrays (dst = src1 ^ src2) +CV_EXPORTS_W void bitwise_xor(InputArray src1, InputArray src2, + OutputArray dst, InputArray mask=noArray()); +//! inverts each bit of array (dst = ~src) +CV_EXPORTS_W void bitwise_not(InputArray src, OutputArray dst, + InputArray mask=noArray()); +//! computes element-wise absolute difference of two arrays (dst = abs(src1 - src2)) +CV_EXPORTS_W void absdiff(InputArray src1, InputArray src2, OutputArray dst); +//! set mask elements for those array elements which are within the element-specific bounding box (dst = lowerb <= src && src < upperb) +CV_EXPORTS_W void inRange(InputArray src, InputArray lowerb, + InputArray upperb, OutputArray dst); +//! compares elements of two arrays (dst = src1 src2) +CV_EXPORTS_W void compare(InputArray src1, InputArray src2, OutputArray dst, int cmpop); +//! computes per-element minimum of two arrays (dst = min(src1, src2)) +CV_EXPORTS_W void min(InputArray src1, InputArray src2, OutputArray dst); +//! computes per-element maximum of two arrays (dst = max(src1, src2)) +CV_EXPORTS_W void max(InputArray src1, InputArray src2, OutputArray dst); + +//! computes per-element minimum of two arrays (dst = min(src1, src2)) +CV_EXPORTS void min(const Mat& src1, const Mat& src2, Mat& dst); +//! computes per-element minimum of array and scalar (dst = min(src1, src2)) +CV_EXPORTS void min(const Mat& src1, double src2, Mat& dst); +//! computes per-element maximum of two arrays (dst = max(src1, src2)) +CV_EXPORTS void max(const Mat& src1, const Mat& src2, Mat& dst); +//! computes per-element maximum of array and scalar (dst = max(src1, src2)) +CV_EXPORTS void max(const Mat& src1, double src2, Mat& dst); + +//! computes square root of each matrix element (dst = src**0.5) +CV_EXPORTS_W void sqrt(InputArray src, OutputArray dst); +//! raises the input matrix elements to the specified power (b = a**power) +CV_EXPORTS_W void pow(InputArray src, double power, OutputArray dst); +//! computes exponent of each matrix element (dst = e**src) +CV_EXPORTS_W void exp(InputArray src, OutputArray dst); +//! computes natural logarithm of absolute value of each matrix element: dst = log(abs(src)) +CV_EXPORTS_W void log(InputArray src, OutputArray dst); +//! computes cube root of the argument +CV_EXPORTS_W float cubeRoot(float val); +//! computes the angle in degrees (0..360) of the vector (x,y) +CV_EXPORTS_W float fastAtan2(float y, float x); + +CV_EXPORTS void exp(const float* src, float* dst, int n); +CV_EXPORTS void log(const float* src, float* dst, int n); +CV_EXPORTS void fastAtan2(const float* y, const float* x, float* dst, int n, bool angleInDegrees); +CV_EXPORTS void magnitude(const float* x, const float* y, float* dst, int n); + +//! converts polar coordinates to Cartesian +CV_EXPORTS_W void polarToCart(InputArray magnitude, InputArray angle, + OutputArray x, OutputArray y, bool angleInDegrees=false); +//! converts Cartesian coordinates to polar +CV_EXPORTS_W void cartToPolar(InputArray x, InputArray y, + OutputArray magnitude, OutputArray angle, + bool angleInDegrees=false); +//! computes angle (angle(i)) of each (x(i), y(i)) vector +CV_EXPORTS_W void phase(InputArray x, InputArray y, OutputArray angle, + bool angleInDegrees=false); +//! computes magnitude (magnitude(i)) of each (x(i), y(i)) vector +CV_EXPORTS_W void magnitude(InputArray x, InputArray y, OutputArray magnitude); +//! checks that each matrix element is within the specified range. +CV_EXPORTS_W bool checkRange(InputArray a, bool quiet=true, CV_OUT Point* pos=0, + double minVal=-DBL_MAX, double maxVal=DBL_MAX); +//! converts NaN's to the given number +CV_EXPORTS_W void patchNaNs(InputOutputArray a, double val=0); + +//! implements generalized matrix product algorithm GEMM from BLAS +CV_EXPORTS_W void gemm(InputArray src1, InputArray src2, double alpha, + InputArray src3, double gamma, OutputArray dst, int flags=0); +//! multiplies matrix by its transposition from the left or from the right +CV_EXPORTS_W void mulTransposed( InputArray src, OutputArray dst, bool aTa, + InputArray delta=noArray(), + double scale=1, int dtype=-1 ); +//! transposes the matrix +CV_EXPORTS_W void transpose(InputArray src, OutputArray dst); +//! performs affine transformation of each element of multi-channel input matrix +CV_EXPORTS_W void transform(InputArray src, OutputArray dst, InputArray m ); +//! performs perspective transformation of each element of multi-channel input matrix +CV_EXPORTS_W void perspectiveTransform(InputArray src, OutputArray dst, InputArray m ); + +//! extends the symmetrical matrix from the lower half or from the upper half +CV_EXPORTS_W void completeSymm(InputOutputArray mtx, bool lowerToUpper=false); +//! initializes scaled identity matrix +CV_EXPORTS_W void setIdentity(InputOutputArray mtx, const Scalar& s=Scalar(1)); +//! computes determinant of a square matrix +CV_EXPORTS_W double determinant(InputArray mtx); +//! computes trace of a matrix +CV_EXPORTS_W Scalar trace(InputArray mtx); +//! computes inverse or pseudo-inverse matrix +CV_EXPORTS_W double invert(InputArray src, OutputArray dst, int flags=DECOMP_LU); +//! solves linear system or a least-square problem +CV_EXPORTS_W bool solve(InputArray src1, InputArray src2, + OutputArray dst, int flags=DECOMP_LU); + +enum +{ + SORT_EVERY_ROW=0, + SORT_EVERY_COLUMN=1, + SORT_ASCENDING=0, + SORT_DESCENDING=16 +}; + +//! sorts independently each matrix row or each matrix column +CV_EXPORTS_W void sort(InputArray src, OutputArray dst, int flags); +//! sorts independently each matrix row or each matrix column +CV_EXPORTS_W void sortIdx(InputArray src, OutputArray dst, int flags); +//! finds real roots of a cubic polynomial +CV_EXPORTS_W int solveCubic(InputArray coeffs, OutputArray roots); +//! finds real and complex roots of a polynomial +CV_EXPORTS_W double solvePoly(InputArray coeffs, OutputArray roots, int maxIters=300); +//! finds eigenvalues of a symmetric matrix +CV_EXPORTS bool eigen(InputArray src, OutputArray eigenvalues, int lowindex=-1, + int highindex=-1); +//! finds eigenvalues and eigenvectors of a symmetric matrix +CV_EXPORTS bool eigen(InputArray src, OutputArray eigenvalues, + OutputArray eigenvectors, + int lowindex=-1, int highindex=-1); +CV_EXPORTS_W bool eigen(InputArray src, bool computeEigenvectors, + OutputArray eigenvalues, OutputArray eigenvectors); + +enum +{ + COVAR_SCRAMBLED=0, + COVAR_NORMAL=1, + COVAR_USE_AVG=2, + COVAR_SCALE=4, + COVAR_ROWS=8, + COVAR_COLS=16 +}; + +//! computes covariation matrix of a set of samples +CV_EXPORTS void calcCovarMatrix( const Mat* samples, int nsamples, Mat& covar, Mat& mean, + int flags, int ctype=CV_64F); +//! computes covariation matrix of a set of samples +CV_EXPORTS_W void calcCovarMatrix( InputArray samples, OutputArray covar, + OutputArray mean, int flags, int ctype=CV_64F); + +/*! + Principal Component Analysis + + The class PCA is used to compute the special basis for a set of vectors. + The basis will consist of eigenvectors of the covariance matrix computed + from the input set of vectors. After PCA is performed, vectors can be transformed from + the original high-dimensional space to the subspace formed by a few most + prominent eigenvectors (called the principal components), + corresponding to the largest eigenvalues of the covariation matrix. + Thus the dimensionality of the vector and the correlation between the coordinates is reduced. + + The following sample is the function that takes two matrices. The first one stores the set + of vectors (a row per vector) that is used to compute PCA, the second one stores another + "test" set of vectors (a row per vector) that are first compressed with PCA, + then reconstructed back and then the reconstruction error norm is computed and printed for each vector. + + \code + using namespace cv; + + PCA compressPCA(const Mat& pcaset, int maxComponents, + const Mat& testset, Mat& compressed) + { + PCA pca(pcaset, // pass the data + Mat(), // we do not have a pre-computed mean vector, + // so let the PCA engine to compute it + CV_PCA_DATA_AS_ROW, // indicate that the vectors + // are stored as matrix rows + // (use CV_PCA_DATA_AS_COL if the vectors are + // the matrix columns) + maxComponents // specify, how many principal components to retain + ); + // if there is no test data, just return the computed basis, ready-to-use + if( !testset.data ) + return pca; + CV_Assert( testset.cols == pcaset.cols ); + + compressed.create(testset.rows, maxComponents, testset.type()); + + Mat reconstructed; + for( int i = 0; i < testset.rows; i++ ) + { + Mat vec = testset.row(i), coeffs = compressed.row(i), reconstructed; + // compress the vector, the result will be stored + // in the i-th row of the output matrix + pca.project(vec, coeffs); + // and then reconstruct it + pca.backProject(coeffs, reconstructed); + // and measure the error + printf("%d. diff = %g\n", i, norm(vec, reconstructed, NORM_L2)); + } + return pca; + } + \endcode +*/ +class CV_EXPORTS PCA +{ +public: + //! default constructor + PCA(); + //! the constructor that performs PCA + PCA(InputArray data, InputArray mean, int flags, int maxComponents=0); + //! operator that performs PCA. The previously stored data, if any, is released + PCA& operator()(InputArray data, InputArray mean, int flags, int maxComponents=0); + //! projects vector from the original space to the principal components subspace + Mat project(InputArray vec) const; + //! projects vector from the original space to the principal components subspace + void project(InputArray vec, OutputArray result) const; + //! reconstructs the original vector from the projection + Mat backProject(InputArray vec) const; + //! reconstructs the original vector from the projection + void backProject(InputArray vec, OutputArray result) const; + + Mat eigenvectors; //!< eigenvectors of the covariation matrix + Mat eigenvalues; //!< eigenvalues of the covariation matrix + Mat mean; //!< mean value subtracted before the projection and added after the back projection +}; + +CV_EXPORTS_W void PCACompute(InputArray data, CV_OUT InputOutputArray mean, + OutputArray eigenvectors, int maxComponents=0); + +CV_EXPORTS_W void PCAProject(InputArray data, InputArray mean, + InputArray eigenvectors, OutputArray result); + +CV_EXPORTS_W void PCABackProject(InputArray data, InputArray mean, + InputArray eigenvectors, OutputArray result); + + +/*! + Singular Value Decomposition class + + The class is used to compute Singular Value Decomposition of a floating-point matrix and then + use it to solve least-square problems, under-determined linear systems, invert matrices, + compute condition numbers etc. + + For a bit faster operation you can pass flags=SVD::MODIFY_A|... to modify the decomposed matrix + when it is not necessarily to preserve it. If you want to compute condition number of a matrix + or absolute value of its determinant - you do not need SVD::u or SVD::vt, + so you can pass flags=SVD::NO_UV|... . Another flag SVD::FULL_UV indicates that the full-size SVD::u and SVD::vt + must be computed, which is not necessary most of the time. +*/ +class CV_EXPORTS SVD +{ +public: + enum { MODIFY_A=1, NO_UV=2, FULL_UV=4 }; + //! the default constructor + SVD(); + //! the constructor that performs SVD + SVD( InputArray src, int flags=0 ); + //! the operator that performs SVD. The previously allocated SVD::u, SVD::w are SVD::vt are released. + SVD& operator ()( InputArray src, int flags=0 ); + + //! decomposes matrix and stores the results to user-provided matrices + static void compute( InputArray src, OutputArray w, + OutputArray u, OutputArray vt, int flags=0 ); + //! computes singular values of a matrix + static void compute( InputArray src, OutputArray w, int flags=0 ); + //! performs back substitution + static void backSubst( InputArray w, InputArray u, + InputArray vt, InputArray rhs, + OutputArray dst ); + + template static void compute( const Matx<_Tp, m, n>& a, + Matx<_Tp, nm, 1>& w, Matx<_Tp, m, nm>& u, Matx<_Tp, n, nm>& vt ); + template static void compute( const Matx<_Tp, m, n>& a, + Matx<_Tp, nm, 1>& w ); + template static void backSubst( const Matx<_Tp, nm, 1>& w, + const Matx<_Tp, m, nm>& u, const Matx<_Tp, n, nm>& vt, const Matx<_Tp, m, nb>& rhs, Matx<_Tp, n, nb>& dst ); + + //! finds dst = arg min_{|dst|=1} |m*dst| + static void solveZ( InputArray src, OutputArray dst ); + //! performs back substitution, so that dst is the solution or pseudo-solution of m*dst = rhs, where m is the decomposed matrix + void backSubst( InputArray rhs, OutputArray dst ) const; + + Mat u, w, vt; +}; + +//! computes SVD of src +CV_EXPORTS_W void SVDecomp( InputArray src, CV_OUT OutputArray w, + CV_OUT OutputArray u, CV_OUT OutputArray vt, int flags=0 ); + +//! performs back substitution for the previously computed SVD +CV_EXPORTS_W void SVBackSubst( InputArray w, InputArray u, InputArray vt, + InputArray rhs, CV_OUT OutputArray dst ); + +//! computes Mahalanobis distance between two vectors: sqrt((v1-v2)'*icovar*(v1-v2)), where icovar is the inverse covariation matrix +CV_EXPORTS_W double Mahalanobis(InputArray v1, InputArray v2, InputArray icovar); +//! a synonym for Mahalanobis +CV_EXPORTS double Mahalonobis(InputArray v1, InputArray v2, InputArray icovar); + +//! performs forward or inverse 1D or 2D Discrete Fourier Transformation +CV_EXPORTS_W void dft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0); +//! performs inverse 1D or 2D Discrete Fourier Transformation +CV_EXPORTS_W void idft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0); +//! performs forward or inverse 1D or 2D Discrete Cosine Transformation +CV_EXPORTS_W void dct(InputArray src, OutputArray dst, int flags=0); +//! performs inverse 1D or 2D Discrete Cosine Transformation +CV_EXPORTS_W void idct(InputArray src, OutputArray dst, int flags=0); +//! computes element-wise product of the two Fourier spectrums. The second spectrum can optionally be conjugated before the multiplication +CV_EXPORTS_W void mulSpectrums(InputArray a, InputArray b, OutputArray c, + int flags, bool conjB=false); +//! computes the minimal vector size vecsize1 >= vecsize so that the dft() of the vector of length vecsize1 can be computed efficiently +CV_EXPORTS_W int getOptimalDFTSize(int vecsize); + +/*! + Various k-Means flags +*/ +enum +{ + KMEANS_RANDOM_CENTERS=0, // Chooses random centers for k-Means initialization + KMEANS_PP_CENTERS=2, // Uses k-Means++ algorithm for initialization + KMEANS_USE_INITIAL_LABELS=1 // Uses the user-provided labels for K-Means initialization +}; +//! clusters the input data using k-Means algorithm +CV_EXPORTS_W double kmeans( InputArray data, int K, CV_OUT InputOutputArray bestLabels, + TermCriteria criteria, int attempts, + int flags, OutputArray centers=noArray() ); + +//! returns the thread-local Random number generator +CV_EXPORTS RNG& theRNG(); + +//! returns the next unifomly-distributed random number of the specified type +template static inline _Tp randu() { return (_Tp)theRNG(); } + +//! fills array with uniformly-distributed random numbers from the range [low, high) +CV_EXPORTS_W void randu(InputOutputArray dst, InputArray low, InputArray high); + +//! fills array with normally-distributed random numbers with the specified mean and the standard deviation +CV_EXPORTS_W void randn(InputOutputArray dst, InputArray mean, InputArray stddev); + +//! shuffles the input array elements +CV_EXPORTS void randShuffle(InputOutputArray dst, double iterFactor=1., RNG* rng=0); +CV_EXPORTS_AS(randShuffle) void randShuffle_(InputOutputArray dst, double iterFactor=1.); + +//! draws the line segment (pt1, pt2) in the image +CV_EXPORTS_W void line(CV_IN_OUT Mat& img, Point pt1, Point pt2, const Scalar& color, + int thickness=1, int lineType=8, int shift=0); + +//! draws the rectangle outline or a solid rectangle with the opposite corners pt1 and pt2 in the image +CV_EXPORTS_W void rectangle(CV_IN_OUT Mat& img, Point pt1, Point pt2, + const Scalar& color, int thickness=1, + int lineType=8, int shift=0); + +//! draws the rectangle outline or a solid rectangle covering rec in the image +CV_EXPORTS void rectangle(CV_IN_OUT Mat& img, Rect rec, + const Scalar& color, int thickness=1, + int lineType=8, int shift=0); + +//! draws the circle outline or a solid circle in the image +CV_EXPORTS_W void circle(CV_IN_OUT Mat& img, Point center, int radius, + const Scalar& color, int thickness=1, + int lineType=8, int shift=0); + +//! draws an elliptic arc, ellipse sector or a rotated ellipse in the image +CV_EXPORTS_W void ellipse(CV_IN_OUT Mat& img, Point center, Size axes, + double angle, double startAngle, double endAngle, + const Scalar& color, int thickness=1, + int lineType=8, int shift=0); + +//! draws a rotated ellipse in the image +CV_EXPORTS_W void ellipse(CV_IN_OUT Mat& img, const RotatedRect& box, const Scalar& color, + int thickness=1, int lineType=8); + +//! draws a filled convex polygon in the image +CV_EXPORTS void fillConvexPoly(Mat& img, const Point* pts, int npts, + const Scalar& color, int lineType=8, + int shift=0); +CV_EXPORTS_W void fillConvexPoly(InputOutputArray img, InputArray points, + const Scalar& color, int lineType=8, + int shift=0); + +//! fills an area bounded by one or more polygons +CV_EXPORTS void fillPoly(Mat& img, const Point** pts, + const int* npts, int ncontours, + const Scalar& color, int lineType=8, int shift=0, + Point offset=Point() ); + +CV_EXPORTS_W void fillPoly(InputOutputArray img, InputArrayOfArrays pts, + const Scalar& color, int lineType=8, int shift=0, + Point offset=Point() ); + +//! draws one or more polygonal curves +CV_EXPORTS void polylines(Mat& img, const Point* const* pts, const int* npts, + int ncontours, bool isClosed, const Scalar& color, + int thickness=1, int lineType=8, int shift=0 ); + +CV_EXPORTS_W void polylines(InputOutputArray img, InputArrayOfArrays pts, + bool isClosed, const Scalar& color, + int thickness=1, int lineType=8, int shift=0 ); + +//! draws contours in the image +CV_EXPORTS_W void drawContours( InputOutputArray image, InputArrayOfArrays contours, + int contourIdx, const Scalar& color, + int thickness=1, int lineType=8, + InputArray hierarchy=noArray(), + int maxLevel=INT_MAX, Point offset=Point() ); + +//! clips the line segment by the rectangle Rect(0, 0, imgSize.width, imgSize.height) +CV_EXPORTS bool clipLine(Size imgSize, CV_IN_OUT Point& pt1, CV_IN_OUT Point& pt2); + +//! clips the line segment by the rectangle imgRect +CV_EXPORTS_W bool clipLine(Rect imgRect, CV_OUT CV_IN_OUT Point& pt1, CV_OUT CV_IN_OUT Point& pt2); + +/*! + Line iterator class + + The class is used to iterate over all the pixels on the raster line + segment connecting two specified points. +*/ +class CV_EXPORTS LineIterator +{ +public: + //! intializes the iterator + LineIterator( const Mat& img, Point pt1, Point pt2, + int connectivity=8, bool leftToRight=false ); + //! returns pointer to the current pixel + uchar* operator *(); + //! prefix increment operator (++it). shifts iterator to the next pixel + LineIterator& operator ++(); + //! postfix increment operator (it++). shifts iterator to the next pixel + LineIterator operator ++(int); + //! returns coordinates of the current pixel + Point pos() const; + + uchar* ptr; + const uchar* ptr0; + int step, elemSize; + int err, count; + int minusDelta, plusDelta; + int minusStep, plusStep; +}; + +//! converts elliptic arc to a polygonal curve +CV_EXPORTS_W void ellipse2Poly( Point center, Size axes, int angle, + int arcStart, int arcEnd, int delta, + CV_OUT vector& pts ); + +enum +{ + FONT_HERSHEY_SIMPLEX = 0, + FONT_HERSHEY_PLAIN = 1, + FONT_HERSHEY_DUPLEX = 2, + FONT_HERSHEY_COMPLEX = 3, + FONT_HERSHEY_TRIPLEX = 4, + FONT_HERSHEY_COMPLEX_SMALL = 5, + FONT_HERSHEY_SCRIPT_SIMPLEX = 6, + FONT_HERSHEY_SCRIPT_COMPLEX = 7, + FONT_ITALIC = 16 +}; + +//! renders text string in the image +CV_EXPORTS_W void putText( Mat& img, const string& text, Point org, + int fontFace, double fontScale, Scalar color, + int thickness=1, int lineType=8, + bool bottomLeftOrigin=false ); + +//! returns bounding box of the text string +CV_EXPORTS_W Size getTextSize(const string& text, int fontFace, + double fontScale, int thickness, + CV_OUT int* baseLine); + +///////////////////////////////// Mat_<_Tp> //////////////////////////////////// + +/*! + Template matrix class derived from Mat + + The class Mat_ is a "thin" template wrapper on top of cv::Mat. It does not have any extra data fields, + nor it or cv::Mat have any virtual methods and thus references or pointers to these two classes + can be safely converted one to another. But do it with care, for example: + + \code + // create 100x100 8-bit matrix + Mat M(100,100,CV_8U); + // this will compile fine. no any data conversion will be done. + Mat_& M1 = (Mat_&)M; + // the program will likely crash at the statement below + M1(99,99) = 1.f; + \endcode + + While cv::Mat is sufficient in most cases, cv::Mat_ can be more convenient if you use a lot of element + access operations and if you know matrix type at compile time. + Note that cv::Mat::at<_Tp>(int y, int x) and cv::Mat_<_Tp>::operator ()(int y, int x) do absolutely the + same thing and run at the same speed, but the latter is certainly shorter: + + \code + Mat_ M(20,20); + for(int i = 0; i < M.rows; i++) + for(int j = 0; j < M.cols; j++) + M(i,j) = 1./(i+j+1); + Mat E, V; + eigen(M,E,V); + cout << E.at(0,0)/E.at(M.rows-1,0); + \endcode + + It is easy to use Mat_ for multi-channel images/matrices - just pass cv::Vec as cv::Mat_ template parameter: + + \code + // allocate 320x240 color image and fill it with green (in RGB space) + Mat_ img(240, 320, Vec3b(0,255,0)); + // now draw a diagonal white line + for(int i = 0; i < 100; i++) + img(i,i)=Vec3b(255,255,255); + // and now modify the 2nd (red) channel of each pixel + for(int i = 0; i < img.rows; i++) + for(int j = 0; j < img.cols; j++) + img(i,j)[2] ^= (uchar)(i ^ j); // img(y,x)[c] accesses c-th channel of the pixel (x,y) + \endcode +*/ +template class CV_EXPORTS Mat_ : public Mat +{ +public: + typedef _Tp value_type; + typedef typename DataType<_Tp>::channel_type channel_type; + typedef MatIterator_<_Tp> iterator; + typedef MatConstIterator_<_Tp> const_iterator; + + //! default constructor + Mat_(); + //! equivalent to Mat(_rows, _cols, DataType<_Tp>::type) + Mat_(int _rows, int _cols); + //! constructor that sets each matrix element to specified value + Mat_(int _rows, int _cols, const _Tp& value); + //! equivalent to Mat(_size, DataType<_Tp>::type) + explicit Mat_(Size _size); + //! constructor that sets each matrix element to specified value + Mat_(Size _size, const _Tp& value); + //! n-dim array constructor + Mat_(int _ndims, const int* _sizes); + //! n-dim array constructor that sets each matrix element to specified value + Mat_(int _ndims, const int* _sizes, const _Tp& value); + //! copy/conversion contructor. If m is of different type, it's converted + Mat_(const Mat& m); + //! copy constructor + Mat_(const Mat_& m); + //! constructs a matrix on top of user-allocated data. step is in bytes(!!!), regardless of the type + Mat_(int _rows, int _cols, _Tp* _data, size_t _step=AUTO_STEP); + //! constructs n-dim matrix on top of user-allocated data. steps are in bytes(!!!), regardless of the type + Mat_(int _ndims, const int* _sizes, _Tp* _data, const size_t* _steps=0); + //! selects a submatrix + Mat_(const Mat_& m, const Range& rowRange, const Range& colRange=Range::all()); + //! selects a submatrix + Mat_(const Mat_& m, const Rect& roi); + //! selects a submatrix, n-dim version + Mat_(const Mat_& m, const Range* ranges); + //! from a matrix expression + explicit Mat_(const MatExpr& e); + //! makes a matrix out of Vec, std::vector, Point_ or Point3_. The matrix will have a single column + explicit Mat_(const vector<_Tp>& vec, bool copyData=false); + template explicit Mat_(const Vec::channel_type, n>& vec, bool copyData=true); + template explicit Mat_(const Matx::channel_type, m, n>& mtx, bool copyData=true); + explicit Mat_(const Point_::channel_type>& pt, bool copyData=true); + explicit Mat_(const Point3_::channel_type>& pt, bool copyData=true); + explicit Mat_(const MatCommaInitializer_<_Tp>& commaInitializer); + + Mat_& operator = (const Mat& m); + Mat_& operator = (const Mat_& m); + //! set all the elements to s. + Mat_& operator = (const _Tp& s); + //! assign a matrix expression + Mat_& operator = (const MatExpr& e); + + //! iterators; they are smart enough to skip gaps in the end of rows + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; + + //! equivalent to Mat::create(_rows, _cols, DataType<_Tp>::type) + void create(int _rows, int _cols); + //! equivalent to Mat::create(_size, DataType<_Tp>::type) + void create(Size _size); + //! equivalent to Mat::create(_ndims, _sizes, DatType<_Tp>::type) + void create(int _ndims, const int* _sizes); + //! cross-product + Mat_ cross(const Mat_& m) const; + //! data type conversion + template operator Mat_() const; + //! overridden forms of Mat::row() etc. + Mat_ row(int y) const; + Mat_ col(int x) const; + Mat_ diag(int d=0) const; + Mat_ clone() const; + + //! overridden forms of Mat::elemSize() etc. + size_t elemSize() const; + size_t elemSize1() const; + int type() const; + int depth() const; + int channels() const; + size_t step1(int i=0) const; + //! returns step()/sizeof(_Tp) + size_t stepT(int i=0) const; + + //! overridden forms of Mat::zeros() etc. Data type is omitted, of course + static MatExpr zeros(int rows, int cols); + static MatExpr zeros(Size size); + static MatExpr zeros(int _ndims, const int* _sizes); + static MatExpr ones(int rows, int cols); + static MatExpr ones(Size size); + static MatExpr ones(int _ndims, const int* _sizes); + static MatExpr eye(int rows, int cols); + static MatExpr eye(Size size); + + //! some more overriden methods + Mat_& adjustROI( int dtop, int dbottom, int dleft, int dright ); + Mat_ operator()( const Range& rowRange, const Range& colRange ) const; + Mat_ operator()( const Rect& roi ) const; + Mat_ operator()( const Range* ranges ) const; + + //! more convenient forms of row and element access operators + _Tp* operator [](int y); + const _Tp* operator [](int y) const; + + //! returns reference to the specified element + _Tp& operator ()(const int* idx); + //! returns read-only reference to the specified element + const _Tp& operator ()(const int* idx) const; + + //! returns reference to the specified element + template _Tp& operator ()(const Vec& idx); + //! returns read-only reference to the specified element + template const _Tp& operator ()(const Vec& idx) const; + + //! returns reference to the specified element (1D case) + _Tp& operator ()(int idx0); + //! returns read-only reference to the specified element (1D case) + const _Tp& operator ()(int idx0) const; + //! returns reference to the specified element (2D case) + _Tp& operator ()(int idx0, int idx1); + //! returns read-only reference to the specified element (2D case) + const _Tp& operator ()(int idx0, int idx1) const; + //! returns reference to the specified element (3D case) + _Tp& operator ()(int idx0, int idx1, int idx2); + //! returns read-only reference to the specified element (3D case) + const _Tp& operator ()(int idx0, int idx1, int idx2) const; + + _Tp& operator ()(Point pt); + const _Tp& operator ()(Point pt) const; + + //! conversion to vector. + operator vector<_Tp>() const; + //! conversion to Vec + template operator Vec::channel_type, n>() const; + //! conversion to Matx + template operator Matx::channel_type, m, n>() const; +}; + +typedef Mat_ Mat1b; +typedef Mat_ Mat2b; +typedef Mat_ Mat3b; +typedef Mat_ Mat4b; + +typedef Mat_ Mat1s; +typedef Mat_ Mat2s; +typedef Mat_ Mat3s; +typedef Mat_ Mat4s; + +typedef Mat_ Mat1w; +typedef Mat_ Mat2w; +typedef Mat_ Mat3w; +typedef Mat_ Mat4w; + +typedef Mat_ Mat1i; +typedef Mat_ Mat2i; +typedef Mat_ Mat3i; +typedef Mat_ Mat4i; + +typedef Mat_ Mat1f; +typedef Mat_ Mat2f; +typedef Mat_ Mat3f; +typedef Mat_ Mat4f; + +typedef Mat_ Mat1d; +typedef Mat_ Mat2d; +typedef Mat_ Mat3d; +typedef Mat_ Mat4d; + +//////////// Iterators & Comma initializers ////////////////// + +class CV_EXPORTS MatConstIterator +{ +public: + typedef uchar* value_type; + typedef ptrdiff_t difference_type; + typedef const uchar** pointer; + typedef uchar* reference; + typedef std::random_access_iterator_tag iterator_category; + + //! default constructor + MatConstIterator(); + //! constructor that sets the iterator to the beginning of the matrix + MatConstIterator(const Mat* _m); + //! constructor that sets the iterator to the specified element of the matrix + MatConstIterator(const Mat* _m, int _row, int _col=0); + //! constructor that sets the iterator to the specified element of the matrix + MatConstIterator(const Mat* _m, Point _pt); + //! constructor that sets the iterator to the specified element of the matrix + MatConstIterator(const Mat* _m, const int* _idx); + //! copy constructor + MatConstIterator(const MatConstIterator& it); + + //! copy operator + MatConstIterator& operator = (const MatConstIterator& it); + //! returns the current matrix element + uchar* operator *() const; + //! returns the i-th matrix element, relative to the current + uchar* operator [](ptrdiff_t i) const; + + //! shifts the iterator forward by the specified number of elements + MatConstIterator& operator += (ptrdiff_t ofs); + //! shifts the iterator backward by the specified number of elements + MatConstIterator& operator -= (ptrdiff_t ofs); + //! decrements the iterator + MatConstIterator& operator --(); + //! decrements the iterator + MatConstIterator operator --(int); + //! increments the iterator + MatConstIterator& operator ++(); + //! increments the iterator + MatConstIterator operator ++(int); + //! returns the current iterator position + Point pos() const; + //! returns the current iterator position + void pos(int* _idx) const; + ptrdiff_t lpos() const; + void seek(ptrdiff_t ofs, bool relative=false); + void seek(const int* _idx, bool relative=false); + + const Mat* m; + size_t elemSize; + uchar* ptr; + uchar* sliceStart; + uchar* sliceEnd; +}; + +/*! + Matrix read-only iterator + + */ +template +class CV_EXPORTS MatConstIterator_ : public MatConstIterator +{ +public: + typedef _Tp value_type; + typedef ptrdiff_t difference_type; + typedef const _Tp* pointer; + typedef const _Tp& reference; + typedef std::random_access_iterator_tag iterator_category; + + //! default constructor + MatConstIterator_(); + //! constructor that sets the iterator to the beginning of the matrix + MatConstIterator_(const Mat_<_Tp>* _m); + //! constructor that sets the iterator to the specified element of the matrix + MatConstIterator_(const Mat_<_Tp>* _m, int _row, int _col=0); + //! constructor that sets the iterator to the specified element of the matrix + MatConstIterator_(const Mat_<_Tp>* _m, Point _pt); + //! constructor that sets the iterator to the specified element of the matrix + MatConstIterator_(const Mat_<_Tp>* _m, const int* _idx); + //! copy constructor + MatConstIterator_(const MatConstIterator_& it); + + //! copy operator + MatConstIterator_& operator = (const MatConstIterator_& it); + //! returns the current matrix element + _Tp operator *() const; + //! returns the i-th matrix element, relative to the current + _Tp operator [](ptrdiff_t i) const; + + //! shifts the iterator forward by the specified number of elements + MatConstIterator_& operator += (ptrdiff_t ofs); + //! shifts the iterator backward by the specified number of elements + MatConstIterator_& operator -= (ptrdiff_t ofs); + //! decrements the iterator + MatConstIterator_& operator --(); + //! decrements the iterator + MatConstIterator_ operator --(int); + //! increments the iterator + MatConstIterator_& operator ++(); + //! increments the iterator + MatConstIterator_ operator ++(int); + //! returns the current iterator position + Point pos() const; +}; + + +/*! + Matrix read-write iterator + +*/ +template +class CV_EXPORTS MatIterator_ : public MatConstIterator_<_Tp> +{ +public: + typedef _Tp* pointer; + typedef _Tp& reference; + typedef std::random_access_iterator_tag iterator_category; + + //! the default constructor + MatIterator_(); + //! constructor that sets the iterator to the beginning of the matrix + MatIterator_(Mat_<_Tp>* _m); + //! constructor that sets the iterator to the specified element of the matrix + MatIterator_(Mat_<_Tp>* _m, int _row, int _col=0); + //! constructor that sets the iterator to the specified element of the matrix + MatIterator_(const Mat_<_Tp>* _m, Point _pt); + //! constructor that sets the iterator to the specified element of the matrix + MatIterator_(const Mat_<_Tp>* _m, const int* _idx); + //! copy constructor + MatIterator_(const MatIterator_& it); + //! copy operator + MatIterator_& operator = (const MatIterator_<_Tp>& it ); + + //! returns the current matrix element + _Tp& operator *() const; + //! returns the i-th matrix element, relative to the current + _Tp& operator [](ptrdiff_t i) const; + + //! shifts the iterator forward by the specified number of elements + MatIterator_& operator += (ptrdiff_t ofs); + //! shifts the iterator backward by the specified number of elements + MatIterator_& operator -= (ptrdiff_t ofs); + //! decrements the iterator + MatIterator_& operator --(); + //! decrements the iterator + MatIterator_ operator --(int); + //! increments the iterator + MatIterator_& operator ++(); + //! increments the iterator + MatIterator_ operator ++(int); +}; + +template class CV_EXPORTS MatOp_Iter_; + +/*! + Comma-separated Matrix Initializer + + The class instances are usually not created explicitly. + Instead, they are created on "matrix << firstValue" operator. + + The sample below initializes 2x2 rotation matrix: + + \code + double angle = 30, a = cos(angle*CV_PI/180), b = sin(angle*CV_PI/180); + Mat R = (Mat_(2,2) << a, -b, b, a); + \endcode +*/ +template class CV_EXPORTS MatCommaInitializer_ +{ +public: + //! the constructor, created by "matrix << firstValue" operator, where matrix is cv::Mat + MatCommaInitializer_(Mat_<_Tp>* _m); + //! the operator that takes the next value and put it to the matrix + template MatCommaInitializer_<_Tp>& operator , (T2 v); + //! another form of conversion operator + Mat_<_Tp> operator *() const; + operator Mat_<_Tp>() const; +protected: + MatIterator_<_Tp> it; +}; + + +template class CV_EXPORTS MatxCommaInitializer +{ +public: + MatxCommaInitializer(Matx<_Tp, m, n>* _mtx); + template MatxCommaInitializer<_Tp, m, n>& operator , (T2 val); + Matx<_Tp, m, n> operator *() const; + + Matx<_Tp, m, n>* dst; + int idx; +}; + +template class CV_EXPORTS VecCommaInitializer : public MatxCommaInitializer<_Tp, m, 1> +{ +public: + VecCommaInitializer(Vec<_Tp, m>* _vec); + template VecCommaInitializer<_Tp, m>& operator , (T2 val); + Vec<_Tp, m> operator *() const; +}; + +/*! + Automatically Allocated Buffer Class + + The class is used for temporary buffers in functions and methods. + If a temporary buffer is usually small (a few K's of memory), + but its size depends on the parameters, it makes sense to create a small + fixed-size array on stack and use it if it's large enough. If the required buffer size + is larger than the fixed size, another buffer of sufficient size is allocated dynamically + and released after the processing. Therefore, in typical cases, when the buffer size is small, + there is no overhead associated with malloc()/free(). + At the same time, there is no limit on the size of processed data. + + This is what AutoBuffer does. The template takes 2 parameters - type of the buffer elements and + the number of stack-allocated elements. Here is how the class is used: + + \code + void my_func(const cv::Mat& m) + { + cv::AutoBuffer buf; // create automatic buffer containing 1000 floats + + buf.allocate(m.rows); // if m.rows <= 1000, the pre-allocated buffer is used, + // otherwise the buffer of "m.rows" floats will be allocated + // dynamically and deallocated in cv::AutoBuffer destructor + ... + } + \endcode +*/ +template class CV_EXPORTS AutoBuffer +{ +public: + typedef _Tp value_type; + enum { buffer_padding = (int)((16 + sizeof(_Tp) - 1)/sizeof(_Tp)) }; + + //! the default contructor + AutoBuffer(); + //! constructor taking the real buffer size + AutoBuffer(size_t _size); + //! destructor. calls deallocate() + ~AutoBuffer(); + + //! allocates the new buffer of size _size. if the _size is small enough, stack-allocated buffer is used + void allocate(size_t _size); + //! deallocates the buffer if it was dynamically allocated + void deallocate(); + //! returns pointer to the real buffer, stack-allocated or head-allocated + operator _Tp* (); + //! returns read-only pointer to the real buffer, stack-allocated or head-allocated + operator const _Tp* () const; + +protected: + //! pointer to the real buffer, can point to buf if the buffer is small enough + _Tp* ptr; + //! size of the real buffer + size_t size; + //! pre-allocated buffer + _Tp buf[fixed_size+buffer_padding]; +}; + +/////////////////////////// multi-dimensional dense matrix ////////////////////////// + +/*! + n-Dimensional Dense Matrix Iterator Class. + + The class cv::NAryMatIterator is used for iterating over one or more n-dimensional dense arrays (cv::Mat's). + + The iterator is completely different from cv::Mat_ and cv::SparseMat_ iterators. + It iterates through the slices (or planes), not the elements, where "slice" is a continuous part of the arrays. + + Here is the example on how the iterator can be used to normalize 3D histogram: + + \code + void normalizeColorHist(Mat& hist) + { + #if 1 + // intialize iterator (the style is different from STL). + // after initialization the iterator will contain + // the number of slices or planes + // the iterator will go through + Mat* arrays[] = { &hist, 0 }; + Mat planes[1]; + NAryMatIterator it(arrays, planes); + double s = 0; + // iterate through the matrix. on each iteration + // it.planes[i] (of type Mat) will be set to the current plane of + // i-th n-dim matrix passed to the iterator constructor. + for(int p = 0; p < it.nplanes; p++, ++it) + s += sum(it.planes[0])[0]; + it = NAryMatIterator(hist); + s = 1./s; + for(int p = 0; p < it.nplanes; p++, ++it) + it.planes[0] *= s; + #elif 1 + // this is a shorter implementation of the above + // using built-in operations on Mat + double s = sum(hist)[0]; + hist.convertTo(hist, hist.type(), 1./s, 0); + #else + // and this is even shorter one + // (assuming that the histogram elements are non-negative) + normalize(hist, hist, 1, 0, NORM_L1); + #endif + } + \endcode + + You can iterate through several matrices simultaneously as long as they have the same geometry + (dimensionality and all the dimension sizes are the same), which is useful for binary + and n-ary operations on such matrices. Just pass those matrices to cv::MatNDIterator. + Then, during the iteration it.planes[0], it.planes[1], ... will + be the slices of the corresponding matrices +*/ +class CV_EXPORTS NAryMatIterator +{ +public: + //! the default constructor + NAryMatIterator(); + //! the full constructor taking arbitrary number of n-dim matrices + NAryMatIterator(const Mat** arrays, uchar** ptrs, int narrays=-1); + //! the full constructor taking arbitrary number of n-dim matrices + NAryMatIterator(const Mat** arrays, Mat* planes, int narrays=-1); + //! the separate iterator initialization method + void init(const Mat** arrays, Mat* planes, uchar** ptrs, int narrays=-1); + + //! proceeds to the next plane of every iterated matrix + NAryMatIterator& operator ++(); + //! proceeds to the next plane of every iterated matrix (postfix increment operator) + NAryMatIterator operator ++(int); + + //! the iterated arrays + const Mat** arrays; + //! the current planes + Mat* planes; + //! data pointers + uchar** ptrs; + //! the number of arrays + int narrays; + //! the number of hyper-planes that the iterator steps through + size_t nplanes; + //! the size of each segment (in elements) + size_t size; +protected: + int iterdepth; + size_t idx; +}; + +//typedef NAryMatIterator NAryMatNDIterator; + +typedef void (*ConvertData)(const void* from, void* to, int cn); +typedef void (*ConvertScaleData)(const void* from, void* to, int cn, double alpha, double beta); + +//! returns the function for converting pixels from one data type to another +CV_EXPORTS ConvertData getConvertElem(int fromType, int toType); +//! returns the function for converting pixels from one data type to another with the optional scaling +CV_EXPORTS ConvertScaleData getConvertScaleElem(int fromType, int toType); + + +/////////////////////////// multi-dimensional sparse matrix ////////////////////////// + +class SparseMatIterator; +class SparseMatConstIterator; +template class SparseMatIterator_; +template class SparseMatConstIterator_; + +/*! + Sparse matrix class. + + The class represents multi-dimensional sparse numerical arrays. Such a sparse array can store elements + of any type that cv::Mat is able to store. "Sparse" means that only non-zero elements + are stored (though, as a result of some operations on a sparse matrix, some of its stored elements + can actually become 0. It's user responsibility to detect such elements and delete them using cv::SparseMat::erase(). + The non-zero elements are stored in a hash table that grows when it's filled enough, + so that the search time remains O(1) in average. Elements can be accessed using the following methods: + +
    +
  1. Query operations: cv::SparseMat::ptr() and the higher-level cv::SparseMat::ref(), + cv::SparseMat::value() and cv::SparseMat::find, for example: + \code + const int dims = 5; + int size[] = {10, 10, 10, 10, 10}; + SparseMat sparse_mat(dims, size, CV_32F); + for(int i = 0; i < 1000; i++) + { + int idx[dims]; + for(int k = 0; k < dims; k++) + idx[k] = rand()%sparse_mat.size(k); + sparse_mat.ref(idx) += 1.f; + } + \endcode + +
  2. Sparse matrix iterators. Like cv::Mat iterators and unlike cv::Mat iterators, the sparse matrix iterators are STL-style, + that is, the iteration is done as following: + \code + // prints elements of a sparse floating-point matrix and the sum of elements. + SparseMatConstIterator_ + it = sparse_mat.begin(), + it_end = sparse_mat.end(); + double s = 0; + int dims = sparse_mat.dims(); + for(; it != it_end; ++it) + { + // print element indices and the element value + const Node* n = it.node(); + printf("(") + for(int i = 0; i < dims; i++) + printf("%3d%c", n->idx[i], i < dims-1 ? ',' : ')'); + printf(": %f\n", *it); + s += *it; + } + printf("Element sum is %g\n", s); + \endcode + If you run this loop, you will notice that elements are enumerated + in no any logical order (lexicographical etc.), + they come in the same order as they stored in the hash table, i.e. semi-randomly. + + You may collect pointers to the nodes and sort them to get the proper ordering. + Note, however, that pointers to the nodes may become invalid when you add more + elements to the matrix; this is because of possible buffer reallocation. + +
  3. A combination of the above 2 methods when you need to process 2 or more sparse + matrices simultaneously, e.g. this is how you can compute unnormalized + cross-correlation of the 2 floating-point sparse matrices: + \code + double crossCorr(const SparseMat& a, const SparseMat& b) + { + const SparseMat *_a = &a, *_b = &b; + // if b contains less elements than a, + // it's faster to iterate through b + if(_a->nzcount() > _b->nzcount()) + std::swap(_a, _b); + SparseMatConstIterator_ it = _a->begin(), + it_end = _a->end(); + double ccorr = 0; + for(; it != it_end; ++it) + { + // take the next element from the first matrix + float avalue = *it; + const Node* anode = it.node(); + // and try to find element with the same index in the second matrix. + // since the hash value depends only on the element index, + // we reuse hashvalue stored in the node + float bvalue = _b->value(anode->idx,&anode->hashval); + ccorr += avalue*bvalue; + } + return ccorr; + } + \endcode +
+*/ +class CV_EXPORTS SparseMat +{ +public: + typedef SparseMatIterator iterator; + typedef SparseMatConstIterator const_iterator; + + //! the sparse matrix header + struct CV_EXPORTS Hdr + { + Hdr(int _dims, const int* _sizes, int _type); + void clear(); + int refcount; + int dims; + int valueOffset; + size_t nodeSize; + size_t nodeCount; + size_t freeList; + vector pool; + vector hashtab; + int size[CV_MAX_DIM]; + }; + + //! sparse matrix node - element of a hash table + struct CV_EXPORTS Node + { + //! hash value + size_t hashval; + //! index of the next node in the same hash table entry + size_t next; + //! index of the matrix element + int idx[CV_MAX_DIM]; + }; + + //! default constructor + SparseMat(); + //! creates matrix of the specified size and type + SparseMat(int dims, const int* _sizes, int _type); + //! copy constructor + SparseMat(const SparseMat& m); + //! converts dense 2d matrix to the sparse form + /*! + \param m the input matrix + \param try1d if true and m is a single-column matrix (Nx1), + then the sparse matrix will be 1-dimensional. + */ + explicit SparseMat(const Mat& m); + //! converts old-style sparse matrix to the new-style. All the data is copied + SparseMat(const CvSparseMat* m); + //! the destructor + ~SparseMat(); + + //! assignment operator. This is O(1) operation, i.e. no data is copied + SparseMat& operator = (const SparseMat& m); + //! equivalent to the corresponding constructor + SparseMat& operator = (const Mat& m); + + //! creates full copy of the matrix + SparseMat clone() const; + + //! copies all the data to the destination matrix. All the previous content of m is erased + void copyTo( SparseMat& m ) const; + //! converts sparse matrix to dense matrix. + void copyTo( Mat& m ) const; + //! multiplies all the matrix elements by the specified scale factor alpha and converts the results to the specified data type + void convertTo( SparseMat& m, int rtype, double alpha=1 ) const; + //! converts sparse matrix to dense n-dim matrix with optional type conversion and scaling. + /*! + \param rtype The output matrix data type. When it is =-1, the output array will have the same data type as (*this) + \param alpha The scale factor + \param beta The optional delta added to the scaled values before the conversion + */ + void convertTo( Mat& m, int rtype, double alpha=1, double beta=0 ) const; + + // not used now + void assignTo( SparseMat& m, int type=-1 ) const; + + //! reallocates sparse matrix. + /*! + If the matrix already had the proper size and type, + it is simply cleared with clear(), otherwise, + the old matrix is released (using release()) and the new one is allocated. + */ + void create(int dims, const int* _sizes, int _type); + //! sets all the sparse matrix elements to 0, which means clearing the hash table. + void clear(); + //! manually increments the reference counter to the header. + void addref(); + // decrements the header reference counter. When the counter reaches 0, the header and all the underlying data are deallocated. + void release(); + + //! converts sparse matrix to the old-style representation; all the elements are copied. + operator CvSparseMat*() const; + //! returns the size of each element in bytes (not including the overhead - the space occupied by SparseMat::Node elements) + size_t elemSize() const; + //! returns elemSize()/channels() + size_t elemSize1() const; + + //! returns type of sparse matrix elements + int type() const; + //! returns the depth of sparse matrix elements + int depth() const; + //! returns the number of channels + int channels() const; + + //! returns the array of sizes, or NULL if the matrix is not allocated + const int* size() const; + //! returns the size of i-th matrix dimension (or 0) + int size(int i) const; + //! returns the matrix dimensionality + int dims() const; + //! returns the number of non-zero elements (=the number of hash table nodes) + size_t nzcount() const; + + //! computes the element hash value (1D case) + size_t hash(int i0) const; + //! computes the element hash value (2D case) + size_t hash(int i0, int i1) const; + //! computes the element hash value (3D case) + size_t hash(int i0, int i1, int i2) const; + //! computes the element hash value (nD case) + size_t hash(const int* idx) const; + + //@{ + /*! + specialized variants for 1D, 2D, 3D cases and the generic_type one for n-D case. + + return pointer to the matrix element. +
    +
  • if the element is there (it's non-zero), the pointer to it is returned +
  • if it's not there and createMissing=false, NULL pointer is returned +
  • if it's not there and createMissing=true, then the new element + is created and initialized with 0. Pointer to it is returned +
  • if the optional hashval pointer is not NULL, the element hash value is + not computed, but *hashval is taken instead. +
+ */ + //! returns pointer to the specified element (1D case) + uchar* ptr(int i0, bool createMissing, size_t* hashval=0); + //! returns pointer to the specified element (2D case) + uchar* ptr(int i0, int i1, bool createMissing, size_t* hashval=0); + //! returns pointer to the specified element (3D case) + uchar* ptr(int i0, int i1, int i2, bool createMissing, size_t* hashval=0); + //! returns pointer to the specified element (nD case) + uchar* ptr(const int* idx, bool createMissing, size_t* hashval=0); + //@} + + //@{ + /*! + return read-write reference to the specified sparse matrix element. + + ref<_Tp>(i0,...[,hashval]) is equivalent to *(_Tp*)ptr(i0,...,true[,hashval]). + The methods always return a valid reference. + If the element did not exist, it is created and initialiazed with 0. + */ + //! returns reference to the specified element (1D case) + template _Tp& ref(int i0, size_t* hashval=0); + //! returns reference to the specified element (2D case) + template _Tp& ref(int i0, int i1, size_t* hashval=0); + //! returns reference to the specified element (3D case) + template _Tp& ref(int i0, int i1, int i2, size_t* hashval=0); + //! returns reference to the specified element (nD case) + template _Tp& ref(const int* idx, size_t* hashval=0); + //@} + + //@{ + /*! + return value of the specified sparse matrix element. + + value<_Tp>(i0,...[,hashval]) is equivalent + + \code + { const _Tp* p = find<_Tp>(i0,...[,hashval]); return p ? *p : _Tp(); } + \endcode + + That is, if the element did not exist, the methods return 0. + */ + //! returns value of the specified element (1D case) + template _Tp value(int i0, size_t* hashval=0) const; + //! returns value of the specified element (2D case) + template _Tp value(int i0, int i1, size_t* hashval=0) const; + //! returns value of the specified element (3D case) + template _Tp value(int i0, int i1, int i2, size_t* hashval=0) const; + //! returns value of the specified element (nD case) + template _Tp value(const int* idx, size_t* hashval=0) const; + //@} + + //@{ + /*! + Return pointer to the specified sparse matrix element if it exists + + find<_Tp>(i0,...[,hashval]) is equivalent to (_const Tp*)ptr(i0,...false[,hashval]). + + If the specified element does not exist, the methods return NULL. + */ + //! returns pointer to the specified element (1D case) + template const _Tp* find(int i0, size_t* hashval=0) const; + //! returns pointer to the specified element (2D case) + template const _Tp* find(int i0, int i1, size_t* hashval=0) const; + //! returns pointer to the specified element (3D case) + template const _Tp* find(int i0, int i1, int i2, size_t* hashval=0) const; + //! returns pointer to the specified element (nD case) + template const _Tp* find(const int* idx, size_t* hashval=0) const; + + //! erases the specified element (2D case) + void erase(int i0, int i1, size_t* hashval=0); + //! erases the specified element (3D case) + void erase(int i0, int i1, int i2, size_t* hashval=0); + //! erases the specified element (nD case) + void erase(const int* idx, size_t* hashval=0); + + //@{ + /*! + return the sparse matrix iterator pointing to the first sparse matrix element + */ + //! returns the sparse matrix iterator at the matrix beginning + SparseMatIterator begin(); + //! returns the sparse matrix iterator at the matrix beginning + template SparseMatIterator_<_Tp> begin(); + //! returns the read-only sparse matrix iterator at the matrix beginning + SparseMatConstIterator begin() const; + //! returns the read-only sparse matrix iterator at the matrix beginning + template SparseMatConstIterator_<_Tp> begin() const; + //@} + /*! + return the sparse matrix iterator pointing to the element following the last sparse matrix element + */ + //! returns the sparse matrix iterator at the matrix end + SparseMatIterator end(); + //! returns the read-only sparse matrix iterator at the matrix end + SparseMatConstIterator end() const; + //! returns the typed sparse matrix iterator at the matrix end + template SparseMatIterator_<_Tp> end(); + //! returns the typed read-only sparse matrix iterator at the matrix end + template SparseMatConstIterator_<_Tp> end() const; + + //! returns the value stored in the sparse martix node + template _Tp& value(Node* n); + //! returns the value stored in the sparse martix node + template const _Tp& value(const Node* n) const; + + ////////////// some internal-use methods /////////////// + Node* node(size_t nidx); + const Node* node(size_t nidx) const; + + uchar* newNode(const int* idx, size_t hashval); + void removeNode(size_t hidx, size_t nidx, size_t previdx); + void resizeHashTab(size_t newsize); + + enum { MAGIC_VAL=0x42FD0000, MAX_DIM=CV_MAX_DIM, HASH_SCALE=0x5bd1e995, HASH_BIT=0x80000000 }; + + int flags; + Hdr* hdr; +}; + +//! finds global minimum and maximum sparse array elements and returns their values and their locations +CV_EXPORTS void minMaxLoc(const SparseMat& a, double* minVal, + double* maxVal, int* minIdx=0, int* maxIdx=0); +//! computes norm of a sparse matrix +CV_EXPORTS double norm( const SparseMat& src, int normType ); +//! scales and shifts array elements so that either the specified norm (alpha) or the minimum (alpha) and maximum (beta) array values get the specified values +CV_EXPORTS void normalize( const SparseMat& src, SparseMat& dst, double alpha, int normType ); + +/*! + Read-Only Sparse Matrix Iterator. + Here is how to use the iterator to compute the sum of floating-point sparse matrix elements: + + \code + SparseMatConstIterator it = m.begin(), it_end = m.end(); + double s = 0; + CV_Assert( m.type() == CV_32F ); + for( ; it != it_end; ++it ) + s += it.value(); + \endcode +*/ +class CV_EXPORTS SparseMatConstIterator +{ +public: + //! the default constructor + SparseMatConstIterator(); + //! the full constructor setting the iterator to the first sparse matrix element + SparseMatConstIterator(const SparseMat* _m); + //! the copy constructor + SparseMatConstIterator(const SparseMatConstIterator& it); + + //! the assignment operator + SparseMatConstIterator& operator = (const SparseMatConstIterator& it); + + //! template method returning the current matrix element + template const _Tp& value() const; + //! returns the current node of the sparse matrix. it.node->idx is the current element index + const SparseMat::Node* node() const; + + //! moves iterator to the previous element + SparseMatConstIterator& operator --(); + //! moves iterator to the previous element + SparseMatConstIterator operator --(int); + //! moves iterator to the next element + SparseMatConstIterator& operator ++(); + //! moves iterator to the next element + SparseMatConstIterator operator ++(int); + + //! moves iterator to the element after the last element + void seekEnd(); + + const SparseMat* m; + size_t hashidx; + uchar* ptr; +}; + +/*! + Read-write Sparse Matrix Iterator + + The class is similar to cv::SparseMatConstIterator, + but can be used for in-place modification of the matrix elements. +*/ +class CV_EXPORTS SparseMatIterator : public SparseMatConstIterator +{ +public: + //! the default constructor + SparseMatIterator(); + //! the full constructor setting the iterator to the first sparse matrix element + SparseMatIterator(SparseMat* _m); + //! the full constructor setting the iterator to the specified sparse matrix element + SparseMatIterator(SparseMat* _m, const int* idx); + //! the copy constructor + SparseMatIterator(const SparseMatIterator& it); + + //! the assignment operator + SparseMatIterator& operator = (const SparseMatIterator& it); + //! returns read-write reference to the current sparse matrix element + template _Tp& value() const; + //! returns pointer to the current sparse matrix node. it.node->idx is the index of the current element (do not modify it!) + SparseMat::Node* node() const; + + //! moves iterator to the next element + SparseMatIterator& operator ++(); + //! moves iterator to the next element + SparseMatIterator operator ++(int); +}; + +/*! + The Template Sparse Matrix class derived from cv::SparseMat + + The class provides slightly more convenient operations for accessing elements. + + \code + SparseMat m; + ... + SparseMat_ m_ = (SparseMat_&)m; + m_.ref(1)++; // equivalent to m.ref(1)++; + m_.ref(2) += m_(3); // equivalent to m.ref(2) += m.value(3); + \endcode +*/ +template class CV_EXPORTS SparseMat_ : public SparseMat +{ +public: + typedef SparseMatIterator_<_Tp> iterator; + typedef SparseMatConstIterator_<_Tp> const_iterator; + + //! the default constructor + SparseMat_(); + //! the full constructor equivelent to SparseMat(dims, _sizes, DataType<_Tp>::type) + SparseMat_(int dims, const int* _sizes); + //! the copy constructor. If DataType<_Tp>.type != m.type(), the m elements are converted + SparseMat_(const SparseMat& m); + //! the copy constructor. This is O(1) operation - no data is copied + SparseMat_(const SparseMat_& m); + //! converts dense matrix to the sparse form + SparseMat_(const Mat& m); + //! converts the old-style sparse matrix to the C++ class. All the elements are copied + SparseMat_(const CvSparseMat* m); + //! the assignment operator. If DataType<_Tp>.type != m.type(), the m elements are converted + SparseMat_& operator = (const SparseMat& m); + //! the assignment operator. This is O(1) operation - no data is copied + SparseMat_& operator = (const SparseMat_& m); + //! converts dense matrix to the sparse form + SparseMat_& operator = (const Mat& m); + + //! makes full copy of the matrix. All the elements are duplicated + SparseMat_ clone() const; + //! equivalent to cv::SparseMat::create(dims, _sizes, DataType<_Tp>::type) + void create(int dims, const int* _sizes); + //! converts sparse matrix to the old-style CvSparseMat. All the elements are copied + operator CvSparseMat*() const; + + //! returns type of the matrix elements + int type() const; + //! returns depth of the matrix elements + int depth() const; + //! returns the number of channels in each matrix element + int channels() const; + + //! equivalent to SparseMat::ref<_Tp>(i0, hashval) + _Tp& ref(int i0, size_t* hashval=0); + //! equivalent to SparseMat::ref<_Tp>(i0, i1, hashval) + _Tp& ref(int i0, int i1, size_t* hashval=0); + //! equivalent to SparseMat::ref<_Tp>(i0, i1, i2, hashval) + _Tp& ref(int i0, int i1, int i2, size_t* hashval=0); + //! equivalent to SparseMat::ref<_Tp>(idx, hashval) + _Tp& ref(const int* idx, size_t* hashval=0); + + //! equivalent to SparseMat::value<_Tp>(i0, hashval) + _Tp operator()(int i0, size_t* hashval=0) const; + //! equivalent to SparseMat::value<_Tp>(i0, i1, hashval) + _Tp operator()(int i0, int i1, size_t* hashval=0) const; + //! equivalent to SparseMat::value<_Tp>(i0, i1, i2, hashval) + _Tp operator()(int i0, int i1, int i2, size_t* hashval=0) const; + //! equivalent to SparseMat::value<_Tp>(idx, hashval) + _Tp operator()(const int* idx, size_t* hashval=0) const; + + //! returns sparse matrix iterator pointing to the first sparse matrix element + SparseMatIterator_<_Tp> begin(); + //! returns read-only sparse matrix iterator pointing to the first sparse matrix element + SparseMatConstIterator_<_Tp> begin() const; + //! returns sparse matrix iterator pointing to the element following the last sparse matrix element + SparseMatIterator_<_Tp> end(); + //! returns read-only sparse matrix iterator pointing to the element following the last sparse matrix element + SparseMatConstIterator_<_Tp> end() const; +}; + + +/*! + Template Read-Only Sparse Matrix Iterator Class. + + This is the derived from SparseMatConstIterator class that + introduces more convenient operator *() for accessing the current element. +*/ +template class CV_EXPORTS SparseMatConstIterator_ : public SparseMatConstIterator +{ +public: + typedef std::forward_iterator_tag iterator_category; + + //! the default constructor + SparseMatConstIterator_(); + //! the full constructor setting the iterator to the first sparse matrix element + SparseMatConstIterator_(const SparseMat_<_Tp>* _m); + //! the copy constructor + SparseMatConstIterator_(const SparseMatConstIterator_& it); + + //! the assignment operator + SparseMatConstIterator_& operator = (const SparseMatConstIterator_& it); + //! the element access operator + const _Tp& operator *() const; + + //! moves iterator to the next element + SparseMatConstIterator_& operator ++(); + //! moves iterator to the next element + SparseMatConstIterator_ operator ++(int); +}; + +/*! + Template Read-Write Sparse Matrix Iterator Class. + + This is the derived from cv::SparseMatConstIterator_ class that + introduces more convenient operator *() for accessing the current element. +*/ +template class CV_EXPORTS SparseMatIterator_ : public SparseMatConstIterator_<_Tp> +{ +public: + typedef std::forward_iterator_tag iterator_category; + + //! the default constructor + SparseMatIterator_(); + //! the full constructor setting the iterator to the first sparse matrix element + SparseMatIterator_(SparseMat_<_Tp>* _m); + //! the copy constructor + SparseMatIterator_(const SparseMatIterator_& it); + + //! the assignment operator + SparseMatIterator_& operator = (const SparseMatIterator_& it); + //! returns the reference to the current element + _Tp& operator *() const; + + //! moves the iterator to the next element + SparseMatIterator_& operator ++(); + //! moves the iterator to the next element + SparseMatIterator_ operator ++(int); +}; + +//////////////////// Fast Nearest-Neighbor Search Structure //////////////////// + +/*! + Fast Nearest Neighbor Search Class. + + The class implements D. Lowe BBF (Best-Bin-First) algorithm for the last + approximate (or accurate) nearest neighbor search in multi-dimensional spaces. + + First, a set of vectors is passed to KDTree::KDTree() constructor + or KDTree::build() method, where it is reordered. + + Then arbitrary vectors can be passed to KDTree::findNearest() methods, which + find the K nearest neighbors among the vectors from the initial set. + The user can balance between the speed and accuracy of the search by varying Emax + parameter, which is the number of leaves that the algorithm checks. + The larger parameter values yield more accurate results at the expense of lower processing speed. + + \code + KDTree T(points, false); + const int K = 3, Emax = INT_MAX; + int idx[K]; + float dist[K]; + T.findNearest(query_vec, K, Emax, idx, 0, dist); + CV_Assert(dist[0] <= dist[1] && dist[1] <= dist[2]); + \endcode +*/ +class CV_EXPORTS_W KDTree +{ +public: + /*! + The node of the search tree. + */ + struct Node + { + Node() : idx(-1), left(-1), right(-1), boundary(0.f) {} + Node(int _idx, int _left, int _right, float _boundary) + : idx(_idx), left(_left), right(_right), boundary(_boundary) {} + //! split dimension; >=0 for nodes (dim), < 0 for leaves (index of the point) + int idx; + //! node indices of the left and the right branches + int left, right; + //! go to the left if query_vec[node.idx]<=node.boundary, otherwise go to the right + float boundary; + }; + + //! the default constructor + CV_WRAP KDTree(); + //! the full constructor that builds the search tree + CV_WRAP KDTree(InputArray points, bool copyAndReorderPoints=false); + //! the full constructor that builds the search tree + CV_WRAP KDTree(InputArray points, InputArray _labels, + bool copyAndReorderPoints=false); + //! builds the search tree + CV_WRAP void build(InputArray points, bool copyAndReorderPoints=false); + //! builds the search tree + CV_WRAP void build(InputArray points, InputArray labels, + bool copyAndReorderPoints=false); + //! finds the K nearest neighbors of "vec" while looking at Emax (at most) leaves + CV_WRAP int findNearest(InputArray vec, int K, int Emax, + OutputArray neighborsIdx, + OutputArray neighbors=noArray(), + OutputArray dist=noArray(), + OutputArray labels=noArray()) const; + //! finds all the points from the initial set that belong to the specified box + CV_WRAP void findOrthoRange(InputArray minBounds, + InputArray maxBounds, + OutputArray neighborsIdx, + OutputArray neighbors=noArray(), + OutputArray labels=noArray()) const; + //! returns vectors with the specified indices + CV_WRAP void getPoints(InputArray idx, OutputArray pts, + OutputArray labels=noArray()) const; + //! return a vector with the specified index + const float* getPoint(int ptidx, int* label=0) const; + //! returns the search space dimensionality + CV_WRAP int dims() const; + + vector nodes; //!< all the tree nodes + CV_PROP Mat points; //!< all the points. It can be a reordered copy of the input vector set or the original vector set. + CV_PROP vector labels; //!< the parallel array of labels. + CV_PROP int maxDepth; //!< maximum depth of the search tree. Do not modify it + CV_PROP_RW int normType; //!< type of the distance (cv::NORM_L1 or cv::NORM_L2) used for search. Initially set to cv::NORM_L2, but you can modify it +}; + +//////////////////////////////////////// XML & YAML I/O //////////////////////////////////// + +class CV_EXPORTS FileNode; + +/*! + XML/YAML File Storage Class. + + The class describes an object associated with XML or YAML file. + It can be used to store data to such a file or read and decode the data. + + The storage is organized as a tree of nested sequences (or lists) and mappings. + Sequence is a heterogenious array, which elements are accessed by indices or sequentially using an iterator. + Mapping is analogue of std::map or C structure, which elements are accessed by names. + The most top level structure is a mapping. + Leaves of the file storage tree are integers, floating-point numbers and text strings. + + For example, the following code: + + \code + // open file storage for writing. Type of the file is determined from the extension + FileStorage fs("test.yml", FileStorage::WRITE); + fs << "test_int" << 5 << "test_real" << 3.1 << "test_string" << "ABCDEFGH"; + fs << "test_mat" << Mat::eye(3,3,CV_32F); + + fs << "test_list" << "[" << 0.0000000000001 << 2 << CV_PI << -3435345 << "2-502 2-029 3egegeg" << + "{:" << "month" << 12 << "day" << 31 << "year" << 1969 << "}" << "]"; + fs << "test_map" << "{" << "x" << 1 << "y" << 2 << "width" << 100 << "height" << 200 << "lbp" << "[:"; + + const uchar arr[] = {0, 1, 1, 0, 1, 1, 0, 1}; + fs.writeRaw("u", arr, (int)(sizeof(arr)/sizeof(arr[0]))); + + fs << "]" << "}"; + \endcode + + will produce the following file: + + \verbatim + %YAML:1.0 + test_int: 5 + test_real: 3.1000000000000001e+00 + test_string: ABCDEFGH + test_mat: !!opencv-matrix + rows: 3 + cols: 3 + dt: f + data: [ 1., 0., 0., 0., 1., 0., 0., 0., 1. ] + test_list: + - 1.0000000000000000e-13 + - 2 + - 3.1415926535897931e+00 + - -3435345 + - "2-502 2-029 3egegeg" + - { month:12, day:31, year:1969 } + test_map: + x: 1 + y: 2 + width: 100 + height: 200 + lbp: [ 0, 1, 1, 0, 1, 1, 0, 1 ] + \endverbatim + + and to read the file above, the following code can be used: + + \code + // open file storage for reading. + // Type of the file is determined from the content, not the extension + FileStorage fs("test.yml", FileStorage::READ); + int test_int = (int)fs["test_int"]; + double test_real = (double)fs["test_real"]; + string test_string = (string)fs["test_string"]; + + Mat M; + fs["test_mat"] >> M; + + FileNode tl = fs["test_list"]; + CV_Assert(tl.type() == FileNode::SEQ && tl.size() == 6); + double tl0 = (double)tl[0]; + int tl1 = (int)tl[1]; + double tl2 = (double)tl[2]; + int tl3 = (int)tl[3]; + string tl4 = (string)tl[4]; + CV_Assert(tl[5].type() == FileNode::MAP && tl[5].size() == 3); + + int month = (int)tl[5]["month"]; + int day = (int)tl[5]["day"]; + int year = (int)tl[5]["year"]; + + FileNode tm = fs["test_map"]; + + int x = (int)tm["x"]; + int y = (int)tm["y"]; + int width = (int)tm["width"]; + int height = (int)tm["height"]; + + int lbp_val = 0; + FileNodeIterator it = tm["lbp"].begin(); + + for(int k = 0; k < 8; k++, ++it) + lbp_val |= ((int)*it) << k; + \endcode +*/ +class CV_EXPORTS_W FileStorage +{ +public: + //! file storage mode + enum + { + READ=0, //! read mode + WRITE=1, //! write mode + APPEND=2, //! append mode + MEMORY=4, + FORMAT_MASK=(7<<3), + FORMAT_AUTO=0, + FORMAT_XML=(1<<3), + FORMAT_YAML=(2<<3) + }; + enum + { + UNDEFINED=0, + VALUE_EXPECTED=1, + NAME_EXPECTED=2, + INSIDE_MAP=4 + }; + //! the default constructor + CV_WRAP FileStorage(); + //! the full constructor that opens file storage for reading or writing + CV_WRAP FileStorage(const string& source, int flags, const string& encoding=string()); + //! the constructor that takes pointer to the C FileStorage structure + FileStorage(CvFileStorage* fs); + //! the destructor. calls release() + virtual ~FileStorage(); + + //! opens file storage for reading or writing. The previous storage is closed with release() + CV_WRAP virtual bool open(const string& filename, int flags, const string& encoding=string()); + //! returns true if the object is associated with currently opened file. + CV_WRAP virtual bool isOpened() const; + //! closes the file and releases all the memory buffers + CV_WRAP virtual void release(); + //! closes the file, releases all the memory buffers and returns the text string + CV_WRAP virtual string releaseAndGetString(); + + //! returns the first element of the top-level mapping + CV_WRAP FileNode getFirstTopLevelNode() const; + //! returns the top-level mapping. YAML supports multiple streams + CV_WRAP FileNode root(int streamidx=0) const; + //! returns the specified element of the top-level mapping + FileNode operator[](const string& nodename) const; + //! returns the specified element of the top-level mapping + CV_WRAP FileNode operator[](const char* nodename) const; + + //! returns pointer to the underlying C FileStorage structure + CvFileStorage* operator *() { return fs; } + //! returns pointer to the underlying C FileStorage structure + const CvFileStorage* operator *() const { return fs; } + //! writes one or more numbers of the specified format to the currently written structure + void writeRaw( const string& fmt, const uchar* vec, size_t len ); + //! writes the registered C structure (CvMat, CvMatND, CvSeq). See cvWrite() + void writeObj( const string& name, const void* obj ); + + //! returns the normalized object name for the specified file name + static string getDefaultObjectName(const string& filename); + + Ptr fs; //!< the underlying C FileStorage structure + string elname; //!< the currently written element + vector structs; //!< the stack of written structures + int state; //!< the writer state +}; + +class CV_EXPORTS FileNodeIterator; + +/*! + File Storage Node class + + The node is used to store each and every element of the file storage opened for reading - + from the primitive objects, such as numbers and text strings, to the complex nodes: + sequences, mappings and the registered objects. + + Note that file nodes are only used for navigating file storages opened for reading. + When a file storage is opened for writing, no data is stored in memory after it is written. +*/ +class CV_EXPORTS_W_SIMPLE FileNode +{ +public: + //! type of the file storage node + enum + { + NONE=0, //!< empty node + INT=1, //!< an integer + REAL=2, //!< floating-point number + FLOAT=REAL, //!< synonym or REAL + STR=3, //!< text string in UTF-8 encoding + STRING=STR, //!< synonym for STR + REF=4, //!< integer of size size_t. Typically used for storing complex dynamic structures where some elements reference the others + SEQ=5, //!< sequence + MAP=6, //!< mapping + TYPE_MASK=7, + FLOW=8, //!< compact representation of a sequence or mapping. Used only by YAML writer + USER=16, //!< a registered object (e.g. a matrix) + EMPTY=32, //!< empty structure (sequence or mapping) + NAMED=64 //!< the node has a name (i.e. it is element of a mapping) + }; + //! the default constructor + CV_WRAP FileNode(); + //! the full constructor wrapping CvFileNode structure. + FileNode(const CvFileStorage* fs, const CvFileNode* node); + //! the copy constructor + FileNode(const FileNode& node); + //! returns element of a mapping node + FileNode operator[](const string& nodename) const; + //! returns element of a mapping node + CV_WRAP FileNode operator[](const char* nodename) const; + //! returns element of a sequence node + CV_WRAP FileNode operator[](int i) const; + //! returns type of the node + CV_WRAP int type() const; + + //! returns true if the node is empty + CV_WRAP bool empty() const; + //! returns true if the node is a "none" object + CV_WRAP bool isNone() const; + //! returns true if the node is a sequence + CV_WRAP bool isSeq() const; + //! returns true if the node is a mapping + CV_WRAP bool isMap() const; + //! returns true if the node is an integer + CV_WRAP bool isInt() const; + //! returns true if the node is a floating-point number + CV_WRAP bool isReal() const; + //! returns true if the node is a text string + CV_WRAP bool isString() const; + //! returns true if the node has a name + CV_WRAP bool isNamed() const; + //! returns the node name or an empty string if the node is nameless + CV_WRAP string name() const; + //! returns the number of elements in the node, if it is a sequence or mapping, or 1 otherwise. + CV_WRAP size_t size() const; + //! returns the node content as an integer. If the node stores floating-point number, it is rounded. + operator int() const; + //! returns the node content as float + operator float() const; + //! returns the node content as double + operator double() const; + //! returns the node content as text string + operator string() const; + + //! returns pointer to the underlying file node + CvFileNode* operator *(); + //! returns pointer to the underlying file node + const CvFileNode* operator* () const; + + //! returns iterator pointing to the first node element + FileNodeIterator begin() const; + //! returns iterator pointing to the element following the last node element + FileNodeIterator end() const; + + //! reads node elements to the buffer with the specified format + void readRaw( const string& fmt, uchar* vec, size_t len ) const; + //! reads the registered object and returns pointer to it + void* readObj() const; + + // do not use wrapper pointer classes for better efficiency + const CvFileStorage* fs; + const CvFileNode* node; +}; + + +/*! + File Node Iterator + + The class is used for iterating sequences (usually) and mappings. + */ +class CV_EXPORTS FileNodeIterator +{ +public: + //! the default constructor + FileNodeIterator(); + //! the full constructor set to the ofs-th element of the node + FileNodeIterator(const CvFileStorage* fs, const CvFileNode* node, size_t ofs=0); + //! the copy constructor + FileNodeIterator(const FileNodeIterator& it); + //! returns the currently observed element + FileNode operator *() const; + //! accesses the currently observed element methods + FileNode operator ->() const; + + //! moves iterator to the next node + FileNodeIterator& operator ++ (); + //! moves iterator to the next node + FileNodeIterator operator ++ (int); + //! moves iterator to the previous node + FileNodeIterator& operator -- (); + //! moves iterator to the previous node + FileNodeIterator operator -- (int); + //! moves iterator forward by the specified offset (possibly negative) + FileNodeIterator& operator += (int ofs); + //! moves iterator backward by the specified offset (possibly negative) + FileNodeIterator& operator -= (int ofs); + + //! reads the next maxCount elements (or less, if the sequence/mapping last element occurs earlier) to the buffer with the specified format + FileNodeIterator& readRaw( const string& fmt, uchar* vec, + size_t maxCount=(size_t)INT_MAX ); + + const CvFileStorage* fs; + const CvFileNode* container; + CvSeqReader reader; + size_t remaining; +}; + +////////////// convenient wrappers for operating old-style dynamic structures ////////////// + +template class SeqIterator; + +typedef Ptr MemStorage; + +/*! + Template Sequence Class derived from CvSeq + + The class provides more convenient access to sequence elements, + STL-style operations and iterators. + + \note The class is targeted for simple data types, + i.e. no constructors or destructors + are called for the sequence elements. +*/ +template class CV_EXPORTS Seq +{ +public: + typedef SeqIterator<_Tp> iterator; + typedef SeqIterator<_Tp> const_iterator; + + //! the default constructor + Seq(); + //! the constructor for wrapping CvSeq structure. The real element type in CvSeq should match _Tp. + Seq(const CvSeq* seq); + //! creates the empty sequence that resides in the specified storage + Seq(MemStorage& storage, int headerSize = sizeof(CvSeq)); + //! returns read-write reference to the specified element + _Tp& operator [](int idx); + //! returns read-only reference to the specified element + const _Tp& operator[](int idx) const; + //! returns iterator pointing to the beginning of the sequence + SeqIterator<_Tp> begin() const; + //! returns iterator pointing to the element following the last sequence element + SeqIterator<_Tp> end() const; + //! returns the number of elements in the sequence + size_t size() const; + //! returns the type of sequence elements (CV_8UC1 ... CV_64FC(CV_CN_MAX) ...) + int type() const; + //! returns the depth of sequence elements (CV_8U ... CV_64F) + int depth() const; + //! returns the number of channels in each sequence element + int channels() const; + //! returns the size of each sequence element + size_t elemSize() const; + //! returns index of the specified sequence element + size_t index(const _Tp& elem) const; + //! appends the specified element to the end of the sequence + void push_back(const _Tp& elem); + //! appends the specified element to the front of the sequence + void push_front(const _Tp& elem); + //! appends zero or more elements to the end of the sequence + void push_back(const _Tp* elems, size_t count); + //! appends zero or more elements to the front of the sequence + void push_front(const _Tp* elems, size_t count); + //! inserts the specified element to the specified position + void insert(int idx, const _Tp& elem); + //! inserts zero or more elements to the specified position + void insert(int idx, const _Tp* elems, size_t count); + //! removes element at the specified position + void remove(int idx); + //! removes the specified subsequence + void remove(const Range& r); + + //! returns reference to the first sequence element + _Tp& front(); + //! returns read-only reference to the first sequence element + const _Tp& front() const; + //! returns reference to the last sequence element + _Tp& back(); + //! returns read-only reference to the last sequence element + const _Tp& back() const; + //! returns true iff the sequence contains no elements + bool empty() const; + + //! removes all the elements from the sequence + void clear(); + //! removes the first element from the sequence + void pop_front(); + //! removes the last element from the sequence + void pop_back(); + //! removes zero or more elements from the beginning of the sequence + void pop_front(_Tp* elems, size_t count); + //! removes zero or more elements from the end of the sequence + void pop_back(_Tp* elems, size_t count); + + //! copies the whole sequence or the sequence slice to the specified vector + void copyTo(vector<_Tp>& vec, const Range& range=Range::all()) const; + //! returns the vector containing all the sequence elements + operator vector<_Tp>() const; + + CvSeq* seq; +}; + + +/*! + STL-style Sequence Iterator inherited from the CvSeqReader structure +*/ +template class CV_EXPORTS SeqIterator : public CvSeqReader +{ +public: + //! the default constructor + SeqIterator(); + //! the constructor setting the iterator to the beginning or to the end of the sequence + SeqIterator(const Seq<_Tp>& seq, bool seekEnd=false); + //! positions the iterator within the sequence + void seek(size_t pos); + //! reports the current iterator position + size_t tell() const; + //! returns reference to the current sequence element + _Tp& operator *(); + //! returns read-only reference to the current sequence element + const _Tp& operator *() const; + //! moves iterator to the next sequence element + SeqIterator& operator ++(); + //! moves iterator to the next sequence element + SeqIterator operator ++(int) const; + //! moves iterator to the previous sequence element + SeqIterator& operator --(); + //! moves iterator to the previous sequence element + SeqIterator operator --(int) const; + + //! moves iterator forward by the specified offset (possibly negative) + SeqIterator& operator +=(int); + //! moves iterator backward by the specified offset (possibly negative) + SeqIterator& operator -=(int); + + // this is index of the current element module seq->total*2 + // (to distinguish between 0 and seq->total) + int index; +}; + + +class CV_EXPORTS Algorithm; +class CV_EXPORTS AlgorithmInfo; +struct CV_EXPORTS AlgorithmInfoData; + +template struct ParamType {}; + +/*! + Base class for high-level OpenCV algorithms +*/ +class CV_EXPORTS_W Algorithm +{ +public: + Algorithm(); + virtual ~Algorithm(); + string name() const; + + template typename ParamType<_Tp>::member_type get(const string& name) const; + template typename ParamType<_Tp>::member_type get(const char* name) const; + + CV_WRAP int getInt(const string& name) const; + CV_WRAP double getDouble(const string& name) const; + CV_WRAP bool getBool(const string& name) const; + CV_WRAP string getString(const string& name) const; + CV_WRAP Mat getMat(const string& name) const; + CV_WRAP vector getMatVector(const string& name) const; + CV_WRAP Ptr getAlgorithm(const string& name) const; + + CV_WRAP_AS(setInt) void set(const string& name, int value); + CV_WRAP_AS(setDouble) void set(const string& name, double value); + CV_WRAP_AS(setBool) void set(const string& name, bool value); + CV_WRAP_AS(setString) void set(const string& name, const string& value); + CV_WRAP_AS(setMat) void set(const string& name, const Mat& value); + CV_WRAP_AS(setMatVector) void set(const string& name, const vector& value); + CV_WRAP_AS(setAlgorithm) void set(const string& name, const Ptr& value); + template void set(const string& name, const Ptr<_Tp>& value); + + void set(const char* name, int value); + void set(const char* name, double value); + void set(const char* name, bool value); + void set(const char* name, const string& value); + void set(const char* name, const Mat& value); + void set(const char* name, const vector& value); + void set(const char* name, const Ptr& value); + template void set(const char* name, const Ptr<_Tp>& value); + + CV_WRAP string paramHelp(const string& name) const; + int paramType(const char* name) const; + CV_WRAP int paramType(const string& name) const; + CV_WRAP void getParams(CV_OUT vector& names) const; + + + virtual void write(FileStorage& fs) const; + virtual void read(const FileNode& fn); + + typedef Algorithm* (*Constructor)(void); + typedef int (Algorithm::*Getter)() const; + typedef void (Algorithm::*Setter)(int); + + CV_WRAP static void getList(CV_OUT vector& algorithms); + CV_WRAP static Ptr _create(const string& name); + template static Ptr<_Tp> create(const string& name); + + virtual AlgorithmInfo* info() const /* TODO: make it = 0;*/ { return 0; } +}; + + +class CV_EXPORTS AlgorithmInfo +{ +public: + friend class Algorithm; + AlgorithmInfo(const string& name, Algorithm::Constructor create); + ~AlgorithmInfo(); + void get(const Algorithm* algo, const char* name, int argType, void* value) const; + void addParam_(Algorithm& algo, const char* name, int argType, + void* value, bool readOnly, + Algorithm::Getter getter, Algorithm::Setter setter, + const string& help=string()); + string paramHelp(const char* name) const; + int paramType(const char* name) const; + void getParams(vector& names) const; + + void write(const Algorithm* algo, FileStorage& fs) const; + void read(Algorithm* algo, const FileNode& fn) const; + string name() const; + + void addParam(Algorithm& algo, const char* name, + int& value, bool readOnly=false, + int (Algorithm::*getter)()=0, + void (Algorithm::*setter)(int)=0, + const string& help=string()); + void addParam(Algorithm& algo, const char* name, + bool& value, bool readOnly=false, + int (Algorithm::*getter)()=0, + void (Algorithm::*setter)(int)=0, + const string& help=string()); + void addParam(Algorithm& algo, const char* name, + double& value, bool readOnly=false, + double (Algorithm::*getter)()=0, + void (Algorithm::*setter)(double)=0, + const string& help=string()); + void addParam(Algorithm& algo, const char* name, + string& value, bool readOnly=false, + string (Algorithm::*getter)()=0, + void (Algorithm::*setter)(const string&)=0, + const string& help=string()); + void addParam(Algorithm& algo, const char* name, + Mat& value, bool readOnly=false, + Mat (Algorithm::*getter)()=0, + void (Algorithm::*setter)(const Mat&)=0, + const string& help=string()); + void addParam(Algorithm& algo, const char* name, + vector& value, bool readOnly=false, + vector (Algorithm::*getter)()=0, + void (Algorithm::*setter)(const vector&)=0, + const string& help=string()); + void addParam(Algorithm& algo, const char* name, + Ptr& value, bool readOnly=false, + Ptr (Algorithm::*getter)()=0, + void (Algorithm::*setter)(const Ptr&)=0, + const string& help=string()); + template void addParam(Algorithm& algo, const char* name, + Ptr<_Tp>& value, bool readOnly=false, + Ptr<_Tp> (Algorithm::*getter)()=0, + void (Algorithm::*setter)(const Ptr<_Tp>&)=0, + const string& help=string()); + template void addParam(Algorithm& algo, const char* name, + Ptr<_Tp>& value, bool readOnly=false, + Ptr<_Tp> (Algorithm::*getter)()=0, + void (Algorithm::*setter)(const Ptr<_Tp>&)=0, + const string& help=string()); +protected: + AlgorithmInfoData* data; + void set(Algorithm* algo, const char* name, int argType, + const void* value, bool force=false) const; +}; + + +struct CV_EXPORTS Param +{ + enum { INT=0, BOOLEAN=1, REAL=2, STRING=3, MAT=4, MAT_VECTOR=5, ALGORITHM=6 }; + + Param(); + Param(int _type, bool _readonly, int _offset, + Algorithm::Getter _getter=0, + Algorithm::Setter _setter=0, + const string& _help=string()); + int type; + int offset; + bool readonly; + Algorithm::Getter getter; + Algorithm::Setter setter; + string help; +}; + +template<> struct ParamType +{ + typedef bool const_param_type; + typedef bool member_type; + + enum { type = Param::BOOLEAN }; +}; + +template<> struct ParamType +{ + typedef int const_param_type; + typedef int member_type; + + enum { type = Param::INT }; +}; + +template<> struct ParamType +{ + typedef double const_param_type; + typedef double member_type; + + enum { type = Param::REAL }; +}; + +template<> struct ParamType +{ + typedef const string& const_param_type; + typedef string member_type; + + enum { type = Param::STRING }; +}; + +template<> struct ParamType +{ + typedef const Mat& const_param_type; + typedef Mat member_type; + + enum { type = Param::MAT }; +}; + +template<> struct ParamType > +{ + typedef const vector& const_param_type; + typedef vector member_type; + + enum { type = Param::MAT_VECTOR }; +}; + +template<> struct ParamType +{ + typedef const Ptr& const_param_type; + typedef Ptr member_type; + + enum { type = Param::ALGORITHM }; +}; + + +/*! +"\nThe CommandLineParser class is designed for command line arguments parsing\n" + "Keys map: \n" + "Before you start to work with CommandLineParser you have to create a map for keys.\n" + " It will look like this\n" + " const char* keys =\n" + " {\n" + " { s| string| 123asd |string parameter}\n" + " { d| digit | 100 |digit parameter }\n" + " { c|noCamera|false |without camera }\n" + " { 1| |some text|help }\n" + " { 2| |333 |another help }\n" + " };\n" + "Usage syntax: \n" + " \"{\" - start of parameter string.\n" + " \"}\" - end of parameter string\n" + " \"|\" - separator between short name, full name, default value and help\n" + "Supported syntax: \n" + " --key1=arg1 \n" + " -key2=arg2 \n" + "Usage: \n" + " Imagine that the input parameters are next:\n" + " -s=string_value --digit=250 --noCamera lena.jpg 10000\n" + " CommandLineParser parser(argc, argv, keys) - create a parser object\n" + " parser.get(\"s\" or \"string\") will return you first parameter value\n" + " parser.get(\"s\", false or \"string\", false) will return you first parameter value\n" + " without spaces in end and begin\n" + " parser.get(\"d\" or \"digit\") will return you second parameter value.\n" + " It also works with 'unsigned int', 'double', and 'float' types>\n" + " parser.get(\"c\" or \"noCamera\") will return you true .\n" + " If you enter this key in commandline>\n" + " It return you false otherwise.\n" + " parser.get(\"1\") will return you the first argument without parameter (lena.jpg) \n" + " parser.get(\"2\") will return you the second argument without parameter (10000)\n" + " It also works with 'unsigned int', 'double', and 'float' types \n" +*/ +class CV_EXPORTS CommandLineParser +{ + public: + + //! the default constructor + CommandLineParser(int argc, const char* const argv[], const char* key_map); + + //! get parameter, you can choose: delete spaces in end and begin or not + template + _Tp get(const std::string& name, bool space_delete=true) + { + if (!has(name)) + { + return _Tp(); + } + std::string str = getString(name); + return analyzeValue<_Tp>(str, space_delete); + } + + //! print short name, full name, current value and help for all params + void printParams(); + + protected: + std::map > data; + std::string getString(const std::string& name); + + bool has(const std::string& keys); + + template + _Tp analyzeValue(const std::string& str, bool space_delete=false); + + template + static _Tp getData(const std::string& str) + { + _Tp res; + std::stringstream s1(str); + s1 >> res; + return res; + } + + template + _Tp fromStringNumber(const std::string& str);//the default conversion function for numbers + + }; + +template<> CV_EXPORTS +bool CommandLineParser::get(const std::string& name, bool space_delete); + +template<> CV_EXPORTS +std::string CommandLineParser::analyzeValue(const std::string& str, bool space_delete); + +template<> CV_EXPORTS +int CommandLineParser::analyzeValue(const std::string& str, bool space_delete); + +template<> CV_EXPORTS +unsigned int CommandLineParser::analyzeValue(const std::string& str, bool space_delete); + +template<> CV_EXPORTS +uint64 CommandLineParser::analyzeValue(const std::string& str, bool space_delete); + +template<> CV_EXPORTS +float CommandLineParser::analyzeValue(const std::string& str, bool space_delete); + +template<> CV_EXPORTS +double CommandLineParser::analyzeValue(const std::string& str, bool space_delete); + +/////////////////////////////// Parallel Primitives ////////////////////////////////// + +// a base body class +class CV_EXPORTS ParallelLoopBody +{ +public: + virtual void operator() (const Range& range) const = 0; + virtual ~ParallelLoopBody(); +}; + +CV_EXPORTS void parallel_for_(const Range& range, const ParallelLoopBody& body); + +/////////////////////////// Synchronization Primitives /////////////////////////////// + +class CV_EXPORTS Mutex +{ +public: + Mutex(); + ~Mutex(); + Mutex(const Mutex& m); + Mutex& operator = (const Mutex& m); + + void lock(); + bool trylock(); + void unlock(); + + struct Impl; +protected: + Impl* impl; +}; + +class CV_EXPORTS AutoLock +{ +public: + AutoLock(Mutex& m) : mutex(&m) { mutex->lock(); } + ~AutoLock() { mutex->unlock(); } +protected: + Mutex* mutex; +}; + +} + +#endif // __cplusplus + +#include "opencv2/core/operations.hpp" +#include "opencv2/core/mat.hpp" + +#endif /*__OPENCV_CORE_HPP__*/ diff --git a/core/include/opencv2/core/core_c.h b/core/include/opencv2/core/core_c.h new file mode 100644 index 0000000..df763ab --- /dev/null +++ b/core/include/opencv2/core/core_c.h @@ -0,0 +1,1885 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + + +#ifndef __OPENCV_CORE_C_H__ +#define __OPENCV_CORE_C_H__ + +#include "opencv2/core/types_c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************************\ +* Array allocation, deallocation, initialization and access to elements * +\****************************************************************************************/ + +/* wrapper. + If there is no enough memory, the function + (as well as other OpenCV functions that call cvAlloc) + raises an error. */ +CVAPI(void*) cvAlloc( size_t size ); + +/* wrapper. + Here and further all the memory releasing functions + (that all call cvFree) take double pointer in order to + to clear pointer to the data after releasing it. + Passing pointer to NULL pointer is Ok: nothing happens in this case +*/ +CVAPI(void) cvFree_( void* ptr ); +#define cvFree(ptr) (cvFree_(*(ptr)), *(ptr)=0) + +/* Allocates and initializes IplImage header */ +CVAPI(IplImage*) cvCreateImageHeader( CvSize size, int depth, int channels ); + +/* Inializes IplImage header */ +CVAPI(IplImage*) cvInitImageHeader( IplImage* image, CvSize size, int depth, + int channels, int origin CV_DEFAULT(0), + int align CV_DEFAULT(4)); + +/* Creates IPL image (header and data) */ +CVAPI(IplImage*) cvCreateImage( CvSize size, int depth, int channels ); + +/* Releases (i.e. deallocates) IPL image header */ +CVAPI(void) cvReleaseImageHeader( IplImage** image ); + +/* Releases IPL image header and data */ +CVAPI(void) cvReleaseImage( IplImage** image ); + +/* Creates a copy of IPL image (widthStep may differ) */ +CVAPI(IplImage*) cvCloneImage( const IplImage* image ); + +/* Sets a Channel Of Interest (only a few functions support COI) - + use cvCopy to extract the selected channel and/or put it back */ +CVAPI(void) cvSetImageCOI( IplImage* image, int coi ); + +/* Retrieves image Channel Of Interest */ +CVAPI(int) cvGetImageCOI( const IplImage* image ); + +/* Sets image ROI (region of interest) (COI is not changed) */ +CVAPI(void) cvSetImageROI( IplImage* image, CvRect rect ); + +/* Resets image ROI and COI */ +CVAPI(void) cvResetImageROI( IplImage* image ); + +/* Retrieves image ROI */ +CVAPI(CvRect) cvGetImageROI( const IplImage* image ); + +/* Allocates and initalizes CvMat header */ +CVAPI(CvMat*) cvCreateMatHeader( int rows, int cols, int type ); + +#define CV_AUTOSTEP 0x7fffffff + +/* Initializes CvMat header */ +CVAPI(CvMat*) cvInitMatHeader( CvMat* mat, int rows, int cols, + int type, void* data CV_DEFAULT(NULL), + int step CV_DEFAULT(CV_AUTOSTEP) ); + +/* Allocates and initializes CvMat header and allocates data */ +CVAPI(CvMat*) cvCreateMat( int rows, int cols, int type ); + +/* Releases CvMat header and deallocates matrix data + (reference counting is used for data) */ +CVAPI(void) cvReleaseMat( CvMat** mat ); + +/* Decrements CvMat data reference counter and deallocates the data if + it reaches 0 */ +CV_INLINE void cvDecRefData( CvArr* arr ) +{ + if( CV_IS_MAT( arr )) + { + CvMat* mat = (CvMat*)arr; + mat->data.ptr = NULL; + if( mat->refcount != NULL && --*mat->refcount == 0 ) + cvFree( &mat->refcount ); + mat->refcount = NULL; + } + else if( CV_IS_MATND( arr )) + { + CvMatND* mat = (CvMatND*)arr; + mat->data.ptr = NULL; + if( mat->refcount != NULL && --*mat->refcount == 0 ) + cvFree( &mat->refcount ); + mat->refcount = NULL; + } +} + +/* Increments CvMat data reference counter */ +CV_INLINE int cvIncRefData( CvArr* arr ) +{ + int refcount = 0; + if( CV_IS_MAT( arr )) + { + CvMat* mat = (CvMat*)arr; + if( mat->refcount != NULL ) + refcount = ++*mat->refcount; + } + else if( CV_IS_MATND( arr )) + { + CvMatND* mat = (CvMatND*)arr; + if( mat->refcount != NULL ) + refcount = ++*mat->refcount; + } + return refcount; +} + + +/* Creates an exact copy of the input matrix (except, may be, step value) */ +CVAPI(CvMat*) cvCloneMat( const CvMat* mat ); + + +/* Makes a new matrix from subrectangle of input array. + No data is copied */ +CVAPI(CvMat*) cvGetSubRect( const CvArr* arr, CvMat* submat, CvRect rect ); +#define cvGetSubArr cvGetSubRect + +/* Selects row span of the input array: arr(start_row:delta_row:end_row,:) + (end_row is not included into the span). */ +CVAPI(CvMat*) cvGetRows( const CvArr* arr, CvMat* submat, + int start_row, int end_row, + int delta_row CV_DEFAULT(1)); + +CV_INLINE CvMat* cvGetRow( const CvArr* arr, CvMat* submat, int row ) +{ + return cvGetRows( arr, submat, row, row + 1, 1 ); +} + + +/* Selects column span of the input array: arr(:,start_col:end_col) + (end_col is not included into the span) */ +CVAPI(CvMat*) cvGetCols( const CvArr* arr, CvMat* submat, + int start_col, int end_col ); + +CV_INLINE CvMat* cvGetCol( const CvArr* arr, CvMat* submat, int col ) +{ + return cvGetCols( arr, submat, col, col + 1 ); +} + +/* Select a diagonal of the input array. + (diag = 0 means the main diagonal, >0 means a diagonal above the main one, + <0 - below the main one). + The diagonal will be represented as a column (nx1 matrix). */ +CVAPI(CvMat*) cvGetDiag( const CvArr* arr, CvMat* submat, + int diag CV_DEFAULT(0)); + +/* low-level scalar <-> raw data conversion functions */ +CVAPI(void) cvScalarToRawData( const CvScalar* scalar, void* data, int type, + int extend_to_12 CV_DEFAULT(0) ); + +CVAPI(void) cvRawDataToScalar( const void* data, int type, CvScalar* scalar ); + +/* Allocates and initializes CvMatND header */ +CVAPI(CvMatND*) cvCreateMatNDHeader( int dims, const int* sizes, int type ); + +/* Allocates and initializes CvMatND header and allocates data */ +CVAPI(CvMatND*) cvCreateMatND( int dims, const int* sizes, int type ); + +/* Initializes preallocated CvMatND header */ +CVAPI(CvMatND*) cvInitMatNDHeader( CvMatND* mat, int dims, const int* sizes, + int type, void* data CV_DEFAULT(NULL) ); + +/* Releases CvMatND */ +CV_INLINE void cvReleaseMatND( CvMatND** mat ) +{ + cvReleaseMat( (CvMat**)mat ); +} + +/* Creates a copy of CvMatND (except, may be, steps) */ +CVAPI(CvMatND*) cvCloneMatND( const CvMatND* mat ); + +/* Allocates and initializes CvSparseMat header and allocates data */ +CVAPI(CvSparseMat*) cvCreateSparseMat( int dims, const int* sizes, int type ); + +/* Releases CvSparseMat */ +CVAPI(void) cvReleaseSparseMat( CvSparseMat** mat ); + +/* Creates a copy of CvSparseMat (except, may be, zero items) */ +CVAPI(CvSparseMat*) cvCloneSparseMat( const CvSparseMat* mat ); + +/* Initializes sparse array iterator + (returns the first node or NULL if the array is empty) */ +CVAPI(CvSparseNode*) cvInitSparseMatIterator( const CvSparseMat* mat, + CvSparseMatIterator* mat_iterator ); + +// returns next sparse array node (or NULL if there is no more nodes) +CV_INLINE CvSparseNode* cvGetNextSparseNode( CvSparseMatIterator* mat_iterator ) +{ + if( mat_iterator->node->next ) + return mat_iterator->node = mat_iterator->node->next; + else + { + int idx; + for( idx = ++mat_iterator->curidx; idx < mat_iterator->mat->hashsize; idx++ ) + { + CvSparseNode* node = (CvSparseNode*)mat_iterator->mat->hashtable[idx]; + if( node ) + { + mat_iterator->curidx = idx; + return mat_iterator->node = node; + } + } + return NULL; + } +} + +/**************** matrix iterator: used for n-ary operations on dense arrays *********/ + +#define CV_MAX_ARR 10 + +typedef struct CvNArrayIterator +{ + int count; /* number of arrays */ + int dims; /* number of dimensions to iterate */ + CvSize size; /* maximal common linear size: { width = size, height = 1 } */ + uchar* ptr[CV_MAX_ARR]; /* pointers to the array slices */ + int stack[CV_MAX_DIM]; /* for internal use */ + CvMatND* hdr[CV_MAX_ARR]; /* pointers to the headers of the + matrices that are processed */ +} +CvNArrayIterator; + +#define CV_NO_DEPTH_CHECK 1 +#define CV_NO_CN_CHECK 2 +#define CV_NO_SIZE_CHECK 4 + +/* initializes iterator that traverses through several arrays simulteneously + (the function together with cvNextArraySlice is used for + N-ari element-wise operations) */ +CVAPI(int) cvInitNArrayIterator( int count, CvArr** arrs, + const CvArr* mask, CvMatND* stubs, + CvNArrayIterator* array_iterator, + int flags CV_DEFAULT(0) ); + +/* returns zero value if iteration is finished, non-zero (slice length) otherwise */ +CVAPI(int) cvNextNArraySlice( CvNArrayIterator* array_iterator ); + + +/* Returns type of array elements: + CV_8UC1 ... CV_64FC4 ... */ +CVAPI(int) cvGetElemType( const CvArr* arr ); + +/* Retrieves number of an array dimensions and + optionally sizes of the dimensions */ +CVAPI(int) cvGetDims( const CvArr* arr, int* sizes CV_DEFAULT(NULL) ); + + +/* Retrieves size of a particular array dimension. + For 2d arrays cvGetDimSize(arr,0) returns number of rows (image height) + and cvGetDimSize(arr,1) returns number of columns (image width) */ +CVAPI(int) cvGetDimSize( const CvArr* arr, int index ); + + +/* ptr = &arr(idx0,idx1,...). All indexes are zero-based, + the major dimensions go first (e.g. (y,x) for 2D, (z,y,x) for 3D */ +CVAPI(uchar*) cvPtr1D( const CvArr* arr, int idx0, int* type CV_DEFAULT(NULL)); +CVAPI(uchar*) cvPtr2D( const CvArr* arr, int idx0, int idx1, int* type CV_DEFAULT(NULL) ); +CVAPI(uchar*) cvPtr3D( const CvArr* arr, int idx0, int idx1, int idx2, + int* type CV_DEFAULT(NULL)); + +/* For CvMat or IplImage number of indices should be 2 + (row index (y) goes first, column index (x) goes next). + For CvMatND or CvSparseMat number of infices should match number of and + indices order should match the array dimension order. */ +CVAPI(uchar*) cvPtrND( const CvArr* arr, const int* idx, int* type CV_DEFAULT(NULL), + int create_node CV_DEFAULT(1), + unsigned* precalc_hashval CV_DEFAULT(NULL)); + +/* value = arr(idx0,idx1,...) */ +CVAPI(CvScalar) cvGet1D( const CvArr* arr, int idx0 ); +CVAPI(CvScalar) cvGet2D( const CvArr* arr, int idx0, int idx1 ); +CVAPI(CvScalar) cvGet3D( const CvArr* arr, int idx0, int idx1, int idx2 ); +CVAPI(CvScalar) cvGetND( const CvArr* arr, const int* idx ); + +/* for 1-channel arrays */ +CVAPI(double) cvGetReal1D( const CvArr* arr, int idx0 ); +CVAPI(double) cvGetReal2D( const CvArr* arr, int idx0, int idx1 ); +CVAPI(double) cvGetReal3D( const CvArr* arr, int idx0, int idx1, int idx2 ); +CVAPI(double) cvGetRealND( const CvArr* arr, const int* idx ); + +/* arr(idx0,idx1,...) = value */ +CVAPI(void) cvSet1D( CvArr* arr, int idx0, CvScalar value ); +CVAPI(void) cvSet2D( CvArr* arr, int idx0, int idx1, CvScalar value ); +CVAPI(void) cvSet3D( CvArr* arr, int idx0, int idx1, int idx2, CvScalar value ); +CVAPI(void) cvSetND( CvArr* arr, const int* idx, CvScalar value ); + +/* for 1-channel arrays */ +CVAPI(void) cvSetReal1D( CvArr* arr, int idx0, double value ); +CVAPI(void) cvSetReal2D( CvArr* arr, int idx0, int idx1, double value ); +CVAPI(void) cvSetReal3D( CvArr* arr, int idx0, + int idx1, int idx2, double value ); +CVAPI(void) cvSetRealND( CvArr* arr, const int* idx, double value ); + +/* clears element of ND dense array, + in case of sparse arrays it deletes the specified node */ +CVAPI(void) cvClearND( CvArr* arr, const int* idx ); + +/* Converts CvArr (IplImage or CvMat,...) to CvMat. + If the last parameter is non-zero, function can + convert multi(>2)-dimensional array to CvMat as long as + the last array's dimension is continous. The resultant + matrix will be have appropriate (a huge) number of rows */ +CVAPI(CvMat*) cvGetMat( const CvArr* arr, CvMat* header, + int* coi CV_DEFAULT(NULL), + int allowND CV_DEFAULT(0)); + +/* Converts CvArr (IplImage or CvMat) to IplImage */ +CVAPI(IplImage*) cvGetImage( const CvArr* arr, IplImage* image_header ); + + +/* Changes a shape of multi-dimensional array. + new_cn == 0 means that number of channels remains unchanged. + new_dims == 0 means that number and sizes of dimensions remain the same + (unless they need to be changed to set the new number of channels) + if new_dims == 1, there is no need to specify new dimension sizes + The resultant configuration should be achievable w/o data copying. + If the resultant array is sparse, CvSparseMat header should be passed + to the function else if the result is 1 or 2 dimensional, + CvMat header should be passed to the function + else CvMatND header should be passed */ +CVAPI(CvArr*) cvReshapeMatND( const CvArr* arr, + int sizeof_header, CvArr* header, + int new_cn, int new_dims, int* new_sizes ); + +#define cvReshapeND( arr, header, new_cn, new_dims, new_sizes ) \ + cvReshapeMatND( (arr), sizeof(*(header)), (header), \ + (new_cn), (new_dims), (new_sizes)) + +CVAPI(CvMat*) cvReshape( const CvArr* arr, CvMat* header, + int new_cn, int new_rows CV_DEFAULT(0) ); + +/* Repeats source 2d array several times in both horizontal and + vertical direction to fill destination array */ +CVAPI(void) cvRepeat( const CvArr* src, CvArr* dst ); + +/* Allocates array data */ +CVAPI(void) cvCreateData( CvArr* arr ); + +/* Releases array data */ +CVAPI(void) cvReleaseData( CvArr* arr ); + +/* Attaches user data to the array header. The step is reffered to + the pre-last dimension. That is, all the planes of the array + must be joint (w/o gaps) */ +CVAPI(void) cvSetData( CvArr* arr, void* data, int step ); + +/* Retrieves raw data of CvMat, IplImage or CvMatND. + In the latter case the function raises an error if + the array can not be represented as a matrix */ +CVAPI(void) cvGetRawData( const CvArr* arr, uchar** data, + int* step CV_DEFAULT(NULL), + CvSize* roi_size CV_DEFAULT(NULL)); + +/* Returns width and height of array in elements */ +CVAPI(CvSize) cvGetSize( const CvArr* arr ); + +/* Copies source array to destination array */ +CVAPI(void) cvCopy( const CvArr* src, CvArr* dst, + const CvArr* mask CV_DEFAULT(NULL) ); + +/* Sets all or "masked" elements of input array + to the same value*/ +CVAPI(void) cvSet( CvArr* arr, CvScalar value, + const CvArr* mask CV_DEFAULT(NULL) ); + +/* Clears all the array elements (sets them to 0) */ +CVAPI(void) cvSetZero( CvArr* arr ); +#define cvZero cvSetZero + + +/* Splits a multi-channel array into the set of single-channel arrays or + extracts particular [color] plane */ +CVAPI(void) cvSplit( const CvArr* src, CvArr* dst0, CvArr* dst1, + CvArr* dst2, CvArr* dst3 ); + +/* Merges a set of single-channel arrays into the single multi-channel array + or inserts one particular [color] plane to the array */ +CVAPI(void) cvMerge( const CvArr* src0, const CvArr* src1, + const CvArr* src2, const CvArr* src3, + CvArr* dst ); + +/* Copies several channels from input arrays to + certain channels of output arrays */ +CVAPI(void) cvMixChannels( const CvArr** src, int src_count, + CvArr** dst, int dst_count, + const int* from_to, int pair_count ); + +/* Performs linear transformation on every source array element: + dst(x,y,c) = scale*src(x,y,c)+shift. + Arbitrary combination of input and output array depths are allowed + (number of channels must be the same), thus the function can be used + for type conversion */ +CVAPI(void) cvConvertScale( const CvArr* src, CvArr* dst, + double scale CV_DEFAULT(1), + double shift CV_DEFAULT(0) ); +#define cvCvtScale cvConvertScale +#define cvScale cvConvertScale +#define cvConvert( src, dst ) cvConvertScale( (src), (dst), 1, 0 ) + + +/* Performs linear transformation on every source array element, + stores absolute value of the result: + dst(x,y,c) = abs(scale*src(x,y,c)+shift). + destination array must have 8u type. + In other cases one may use cvConvertScale + cvAbsDiffS */ +CVAPI(void) cvConvertScaleAbs( const CvArr* src, CvArr* dst, + double scale CV_DEFAULT(1), + double shift CV_DEFAULT(0) ); +#define cvCvtScaleAbs cvConvertScaleAbs + + +/* checks termination criteria validity and + sets eps to default_eps (if it is not set), + max_iter to default_max_iters (if it is not set) +*/ +CVAPI(CvTermCriteria) cvCheckTermCriteria( CvTermCriteria criteria, + double default_eps, + int default_max_iters ); + +/****************************************************************************************\ +* Arithmetic, logic and comparison operations * +\****************************************************************************************/ + +/* dst(mask) = src1(mask) + src2(mask) */ +CVAPI(void) cvAdd( const CvArr* src1, const CvArr* src2, CvArr* dst, + const CvArr* mask CV_DEFAULT(NULL)); + +/* dst(mask) = src(mask) + value */ +CVAPI(void) cvAddS( const CvArr* src, CvScalar value, CvArr* dst, + const CvArr* mask CV_DEFAULT(NULL)); + +/* dst(mask) = src1(mask) - src2(mask) */ +CVAPI(void) cvSub( const CvArr* src1, const CvArr* src2, CvArr* dst, + const CvArr* mask CV_DEFAULT(NULL)); + +/* dst(mask) = src(mask) - value = src(mask) + (-value) */ +CV_INLINE void cvSubS( const CvArr* src, CvScalar value, CvArr* dst, + const CvArr* mask CV_DEFAULT(NULL)) +{ + cvAddS( src, cvScalar( -value.val[0], -value.val[1], -value.val[2], -value.val[3]), + dst, mask ); +} + +/* dst(mask) = value - src(mask) */ +CVAPI(void) cvSubRS( const CvArr* src, CvScalar value, CvArr* dst, + const CvArr* mask CV_DEFAULT(NULL)); + +/* dst(idx) = src1(idx) * src2(idx) * scale + (scaled element-wise multiplication of 2 arrays) */ +CVAPI(void) cvMul( const CvArr* src1, const CvArr* src2, + CvArr* dst, double scale CV_DEFAULT(1) ); + +/* element-wise division/inversion with scaling: + dst(idx) = src1(idx) * scale / src2(idx) + or dst(idx) = scale / src2(idx) if src1 == 0 */ +CVAPI(void) cvDiv( const CvArr* src1, const CvArr* src2, + CvArr* dst, double scale CV_DEFAULT(1)); + +/* dst = src1 * scale + src2 */ +CVAPI(void) cvScaleAdd( const CvArr* src1, CvScalar scale, + const CvArr* src2, CvArr* dst ); +#define cvAXPY( A, real_scalar, B, C ) cvScaleAdd(A, cvRealScalar(real_scalar), B, C) + +/* dst = src1 * alpha + src2 * beta + gamma */ +CVAPI(void) cvAddWeighted( const CvArr* src1, double alpha, + const CvArr* src2, double beta, + double gamma, CvArr* dst ); + +/* result = sum_i(src1(i) * src2(i)) (results for all channels are accumulated together) */ +CVAPI(double) cvDotProduct( const CvArr* src1, const CvArr* src2 ); + +/* dst(idx) = src1(idx) & src2(idx) */ +CVAPI(void) cvAnd( const CvArr* src1, const CvArr* src2, + CvArr* dst, const CvArr* mask CV_DEFAULT(NULL)); + +/* dst(idx) = src(idx) & value */ +CVAPI(void) cvAndS( const CvArr* src, CvScalar value, + CvArr* dst, const CvArr* mask CV_DEFAULT(NULL)); + +/* dst(idx) = src1(idx) | src2(idx) */ +CVAPI(void) cvOr( const CvArr* src1, const CvArr* src2, + CvArr* dst, const CvArr* mask CV_DEFAULT(NULL)); + +/* dst(idx) = src(idx) | value */ +CVAPI(void) cvOrS( const CvArr* src, CvScalar value, + CvArr* dst, const CvArr* mask CV_DEFAULT(NULL)); + +/* dst(idx) = src1(idx) ^ src2(idx) */ +CVAPI(void) cvXor( const CvArr* src1, const CvArr* src2, + CvArr* dst, const CvArr* mask CV_DEFAULT(NULL)); + +/* dst(idx) = src(idx) ^ value */ +CVAPI(void) cvXorS( const CvArr* src, CvScalar value, + CvArr* dst, const CvArr* mask CV_DEFAULT(NULL)); + +/* dst(idx) = ~src(idx) */ +CVAPI(void) cvNot( const CvArr* src, CvArr* dst ); + +/* dst(idx) = lower(idx) <= src(idx) < upper(idx) */ +CVAPI(void) cvInRange( const CvArr* src, const CvArr* lower, + const CvArr* upper, CvArr* dst ); + +/* dst(idx) = lower <= src(idx) < upper */ +CVAPI(void) cvInRangeS( const CvArr* src, CvScalar lower, + CvScalar upper, CvArr* dst ); + +#define CV_CMP_EQ 0 +#define CV_CMP_GT 1 +#define CV_CMP_GE 2 +#define CV_CMP_LT 3 +#define CV_CMP_LE 4 +#define CV_CMP_NE 5 + +/* The comparison operation support single-channel arrays only. + Destination image should be 8uC1 or 8sC1 */ + +/* dst(idx) = src1(idx) _cmp_op_ src2(idx) */ +CVAPI(void) cvCmp( const CvArr* src1, const CvArr* src2, CvArr* dst, int cmp_op ); + +/* dst(idx) = src1(idx) _cmp_op_ value */ +CVAPI(void) cvCmpS( const CvArr* src, double value, CvArr* dst, int cmp_op ); + +/* dst(idx) = min(src1(idx),src2(idx)) */ +CVAPI(void) cvMin( const CvArr* src1, const CvArr* src2, CvArr* dst ); + +/* dst(idx) = max(src1(idx),src2(idx)) */ +CVAPI(void) cvMax( const CvArr* src1, const CvArr* src2, CvArr* dst ); + +/* dst(idx) = min(src(idx),value) */ +CVAPI(void) cvMinS( const CvArr* src, double value, CvArr* dst ); + +/* dst(idx) = max(src(idx),value) */ +CVAPI(void) cvMaxS( const CvArr* src, double value, CvArr* dst ); + +/* dst(x,y,c) = abs(src1(x,y,c) - src2(x,y,c)) */ +CVAPI(void) cvAbsDiff( const CvArr* src1, const CvArr* src2, CvArr* dst ); + +/* dst(x,y,c) = abs(src(x,y,c) - value(c)) */ +CVAPI(void) cvAbsDiffS( const CvArr* src, CvArr* dst, CvScalar value ); +#define cvAbs( src, dst ) cvAbsDiffS( (src), (dst), cvScalarAll(0)) + +/****************************************************************************************\ +* Math operations * +\****************************************************************************************/ + +/* Does cartesian->polar coordinates conversion. + Either of output components (magnitude or angle) is optional */ +CVAPI(void) cvCartToPolar( const CvArr* x, const CvArr* y, + CvArr* magnitude, CvArr* angle CV_DEFAULT(NULL), + int angle_in_degrees CV_DEFAULT(0)); + +/* Does polar->cartesian coordinates conversion. + Either of output components (magnitude or angle) is optional. + If magnitude is missing it is assumed to be all 1's */ +CVAPI(void) cvPolarToCart( const CvArr* magnitude, const CvArr* angle, + CvArr* x, CvArr* y, + int angle_in_degrees CV_DEFAULT(0)); + +/* Does powering: dst(idx) = src(idx)^power */ +CVAPI(void) cvPow( const CvArr* src, CvArr* dst, double power ); + +/* Does exponention: dst(idx) = exp(src(idx)). + Overflow is not handled yet. Underflow is handled. + Maximal relative error is ~7e-6 for single-precision input */ +CVAPI(void) cvExp( const CvArr* src, CvArr* dst ); + +/* Calculates natural logarithms: dst(idx) = log(abs(src(idx))). + Logarithm of 0 gives large negative number(~-700) + Maximal relative error is ~3e-7 for single-precision output +*/ +CVAPI(void) cvLog( const CvArr* src, CvArr* dst ); + +/* Fast arctangent calculation */ +CVAPI(float) cvFastArctan( float y, float x ); + +/* Fast cubic root calculation */ +CVAPI(float) cvCbrt( float value ); + +/* Checks array values for NaNs, Infs or simply for too large numbers + (if CV_CHECK_RANGE is set). If CV_CHECK_QUIET is set, + no runtime errors is raised (function returns zero value in case of "bad" values). + Otherwise cvError is called */ +#define CV_CHECK_RANGE 1 +#define CV_CHECK_QUIET 2 +CVAPI(int) cvCheckArr( const CvArr* arr, int flags CV_DEFAULT(0), + double min_val CV_DEFAULT(0), double max_val CV_DEFAULT(0)); +#define cvCheckArray cvCheckArr + +#define CV_RAND_UNI 0 +#define CV_RAND_NORMAL 1 +CVAPI(void) cvRandArr( CvRNG* rng, CvArr* arr, int dist_type, + CvScalar param1, CvScalar param2 ); + +CVAPI(void) cvRandShuffle( CvArr* mat, CvRNG* rng, + double iter_factor CV_DEFAULT(1.)); + +#define CV_SORT_EVERY_ROW 0 +#define CV_SORT_EVERY_COLUMN 1 +#define CV_SORT_ASCENDING 0 +#define CV_SORT_DESCENDING 16 + +CVAPI(void) cvSort( const CvArr* src, CvArr* dst CV_DEFAULT(NULL), + CvArr* idxmat CV_DEFAULT(NULL), + int flags CV_DEFAULT(0)); + +/* Finds real roots of a cubic equation */ +CVAPI(int) cvSolveCubic( const CvMat* coeffs, CvMat* roots ); + +/* Finds all real and complex roots of a polynomial equation */ +CVAPI(void) cvSolvePoly(const CvMat* coeffs, CvMat *roots2, + int maxiter CV_DEFAULT(20), int fig CV_DEFAULT(100)); + +/****************************************************************************************\ +* Matrix operations * +\****************************************************************************************/ + +/* Calculates cross product of two 3d vectors */ +CVAPI(void) cvCrossProduct( const CvArr* src1, const CvArr* src2, CvArr* dst ); + +/* Matrix transform: dst = A*B + C, C is optional */ +#define cvMatMulAdd( src1, src2, src3, dst ) cvGEMM( (src1), (src2), 1., (src3), 1., (dst), 0 ) +#define cvMatMul( src1, src2, dst ) cvMatMulAdd( (src1), (src2), NULL, (dst)) + +#define CV_GEMM_A_T 1 +#define CV_GEMM_B_T 2 +#define CV_GEMM_C_T 4 +/* Extended matrix transform: + dst = alpha*op(A)*op(B) + beta*op(C), where op(X) is X or X^T */ +CVAPI(void) cvGEMM( const CvArr* src1, const CvArr* src2, double alpha, + const CvArr* src3, double beta, CvArr* dst, + int tABC CV_DEFAULT(0)); +#define cvMatMulAddEx cvGEMM + +/* Transforms each element of source array and stores + resultant vectors in destination array */ +CVAPI(void) cvTransform( const CvArr* src, CvArr* dst, + const CvMat* transmat, + const CvMat* shiftvec CV_DEFAULT(NULL)); +#define cvMatMulAddS cvTransform + +/* Does perspective transform on every element of input array */ +CVAPI(void) cvPerspectiveTransform( const CvArr* src, CvArr* dst, + const CvMat* mat ); + +/* Calculates (A-delta)*(A-delta)^T (order=0) or (A-delta)^T*(A-delta) (order=1) */ +CVAPI(void) cvMulTransposed( const CvArr* src, CvArr* dst, int order, + const CvArr* delta CV_DEFAULT(NULL), + double scale CV_DEFAULT(1.) ); + +/* Tranposes matrix. Square matrices can be transposed in-place */ +CVAPI(void) cvTranspose( const CvArr* src, CvArr* dst ); +#define cvT cvTranspose + +/* Completes the symmetric matrix from the lower (LtoR=0) or from the upper (LtoR!=0) part */ +CVAPI(void) cvCompleteSymm( CvMat* matrix, int LtoR CV_DEFAULT(0) ); + +/* Mirror array data around horizontal (flip=0), + vertical (flip=1) or both(flip=-1) axises: + cvFlip(src) flips images vertically and sequences horizontally (inplace) */ +CVAPI(void) cvFlip( const CvArr* src, CvArr* dst CV_DEFAULT(NULL), + int flip_mode CV_DEFAULT(0)); +#define cvMirror cvFlip + + +#define CV_SVD_MODIFY_A 1 +#define CV_SVD_U_T 2 +#define CV_SVD_V_T 4 + +/* Performs Singular Value Decomposition of a matrix */ +CVAPI(void) cvSVD( CvArr* A, CvArr* W, CvArr* U CV_DEFAULT(NULL), + CvArr* V CV_DEFAULT(NULL), int flags CV_DEFAULT(0)); + +/* Performs Singular Value Back Substitution (solves A*X = B): + flags must be the same as in cvSVD */ +CVAPI(void) cvSVBkSb( const CvArr* W, const CvArr* U, + const CvArr* V, const CvArr* B, + CvArr* X, int flags ); + +#define CV_LU 0 +#define CV_SVD 1 +#define CV_SVD_SYM 2 +#define CV_CHOLESKY 3 +#define CV_QR 4 +#define CV_NORMAL 16 + +/* Inverts matrix */ +CVAPI(double) cvInvert( const CvArr* src, CvArr* dst, + int method CV_DEFAULT(CV_LU)); +#define cvInv cvInvert + +/* Solves linear system (src1)*(dst) = (src2) + (returns 0 if src1 is a singular and CV_LU method is used) */ +CVAPI(int) cvSolve( const CvArr* src1, const CvArr* src2, CvArr* dst, + int method CV_DEFAULT(CV_LU)); + +/* Calculates determinant of input matrix */ +CVAPI(double) cvDet( const CvArr* mat ); + +/* Calculates trace of the matrix (sum of elements on the main diagonal) */ +CVAPI(CvScalar) cvTrace( const CvArr* mat ); + +/* Finds eigen values and vectors of a symmetric matrix */ +CVAPI(void) cvEigenVV( CvArr* mat, CvArr* evects, CvArr* evals, + double eps CV_DEFAULT(0), + int lowindex CV_DEFAULT(-1), + int highindex CV_DEFAULT(-1)); + +///* Finds selected eigen values and vectors of a symmetric matrix */ +//CVAPI(void) cvSelectedEigenVV( CvArr* mat, CvArr* evects, CvArr* evals, +// int lowindex, int highindex ); + +/* Makes an identity matrix (mat_ij = i == j) */ +CVAPI(void) cvSetIdentity( CvArr* mat, CvScalar value CV_DEFAULT(cvRealScalar(1)) ); + +/* Fills matrix with given range of numbers */ +CVAPI(CvArr*) cvRange( CvArr* mat, double start, double end ); + +/* Calculates covariation matrix for a set of vectors */ +/* transpose([v1-avg, v2-avg,...]) * [v1-avg,v2-avg,...] */ +#define CV_COVAR_SCRAMBLED 0 + +/* [v1-avg, v2-avg,...] * transpose([v1-avg,v2-avg,...]) */ +#define CV_COVAR_NORMAL 1 + +/* do not calc average (i.e. mean vector) - use the input vector instead + (useful for calculating covariance matrix by parts) */ +#define CV_COVAR_USE_AVG 2 + +/* scale the covariance matrix coefficients by number of the vectors */ +#define CV_COVAR_SCALE 4 + +/* all the input vectors are stored in a single matrix, as its rows */ +#define CV_COVAR_ROWS 8 + +/* all the input vectors are stored in a single matrix, as its columns */ +#define CV_COVAR_COLS 16 + +CVAPI(void) cvCalcCovarMatrix( const CvArr** vects, int count, + CvArr* cov_mat, CvArr* avg, int flags ); + +#define CV_PCA_DATA_AS_ROW 0 +#define CV_PCA_DATA_AS_COL 1 +#define CV_PCA_USE_AVG 2 +CVAPI(void) cvCalcPCA( const CvArr* data, CvArr* mean, + CvArr* eigenvals, CvArr* eigenvects, int flags ); + +CVAPI(void) cvProjectPCA( const CvArr* data, const CvArr* mean, + const CvArr* eigenvects, CvArr* result ); + +CVAPI(void) cvBackProjectPCA( const CvArr* proj, const CvArr* mean, + const CvArr* eigenvects, CvArr* result ); + +/* Calculates Mahalanobis(weighted) distance */ +CVAPI(double) cvMahalanobis( const CvArr* vec1, const CvArr* vec2, const CvArr* mat ); +#define cvMahalonobis cvMahalanobis + +/****************************************************************************************\ +* Array Statistics * +\****************************************************************************************/ + +/* Finds sum of array elements */ +CVAPI(CvScalar) cvSum( const CvArr* arr ); + +/* Calculates number of non-zero pixels */ +CVAPI(int) cvCountNonZero( const CvArr* arr ); + +/* Calculates mean value of array elements */ +CVAPI(CvScalar) cvAvg( const CvArr* arr, const CvArr* mask CV_DEFAULT(NULL) ); + +/* Calculates mean and standard deviation of pixel values */ +CVAPI(void) cvAvgSdv( const CvArr* arr, CvScalar* mean, CvScalar* std_dev, + const CvArr* mask CV_DEFAULT(NULL) ); + +/* Finds global minimum, maximum and their positions */ +CVAPI(void) cvMinMaxLoc( const CvArr* arr, double* min_val, double* max_val, + CvPoint* min_loc CV_DEFAULT(NULL), + CvPoint* max_loc CV_DEFAULT(NULL), + const CvArr* mask CV_DEFAULT(NULL) ); + +/* types of array norm */ +#define CV_C 1 +#define CV_L1 2 +#define CV_L2 4 +#define CV_NORM_MASK 7 +#define CV_RELATIVE 8 +#define CV_DIFF 16 +#define CV_MINMAX 32 + +#define CV_DIFF_C (CV_DIFF | CV_C) +#define CV_DIFF_L1 (CV_DIFF | CV_L1) +#define CV_DIFF_L2 (CV_DIFF | CV_L2) +#define CV_RELATIVE_C (CV_RELATIVE | CV_C) +#define CV_RELATIVE_L1 (CV_RELATIVE | CV_L1) +#define CV_RELATIVE_L2 (CV_RELATIVE | CV_L2) + +/* Finds norm, difference norm or relative difference norm for an array (or two arrays) */ +CVAPI(double) cvNorm( const CvArr* arr1, const CvArr* arr2 CV_DEFAULT(NULL), + int norm_type CV_DEFAULT(CV_L2), + const CvArr* mask CV_DEFAULT(NULL) ); + +CVAPI(void) cvNormalize( const CvArr* src, CvArr* dst, + double a CV_DEFAULT(1.), double b CV_DEFAULT(0.), + int norm_type CV_DEFAULT(CV_L2), + const CvArr* mask CV_DEFAULT(NULL) ); + + +#define CV_REDUCE_SUM 0 +#define CV_REDUCE_AVG 1 +#define CV_REDUCE_MAX 2 +#define CV_REDUCE_MIN 3 + +CVAPI(void) cvReduce( const CvArr* src, CvArr* dst, int dim CV_DEFAULT(-1), + int op CV_DEFAULT(CV_REDUCE_SUM) ); + +/****************************************************************************************\ +* Discrete Linear Transforms and Related Functions * +\****************************************************************************************/ + +#define CV_DXT_FORWARD 0 +#define CV_DXT_INVERSE 1 +#define CV_DXT_SCALE 2 /* divide result by size of array */ +#define CV_DXT_INV_SCALE (CV_DXT_INVERSE + CV_DXT_SCALE) +#define CV_DXT_INVERSE_SCALE CV_DXT_INV_SCALE +#define CV_DXT_ROWS 4 /* transform each row individually */ +#define CV_DXT_MUL_CONJ 8 /* conjugate the second argument of cvMulSpectrums */ + +/* Discrete Fourier Transform: + complex->complex, + real->ccs (forward), + ccs->real (inverse) */ +CVAPI(void) cvDFT( const CvArr* src, CvArr* dst, int flags, + int nonzero_rows CV_DEFAULT(0) ); +#define cvFFT cvDFT + +/* Multiply results of DFTs: DFT(X)*DFT(Y) or DFT(X)*conj(DFT(Y)) */ +CVAPI(void) cvMulSpectrums( const CvArr* src1, const CvArr* src2, + CvArr* dst, int flags ); + +/* Finds optimal DFT vector size >= size0 */ +CVAPI(int) cvGetOptimalDFTSize( int size0 ); + +/* Discrete Cosine Transform */ +CVAPI(void) cvDCT( const CvArr* src, CvArr* dst, int flags ); + +/****************************************************************************************\ +* Dynamic data structures * +\****************************************************************************************/ + +/* Calculates length of sequence slice (with support of negative indices). */ +CVAPI(int) cvSliceLength( CvSlice slice, const CvSeq* seq ); + + +/* Creates new memory storage. + block_size == 0 means that default, + somewhat optimal size, is used (currently, it is 64K) */ +CVAPI(CvMemStorage*) cvCreateMemStorage( int block_size CV_DEFAULT(0)); + + +/* Creates a memory storage that will borrow memory blocks from parent storage */ +CVAPI(CvMemStorage*) cvCreateChildMemStorage( CvMemStorage* parent ); + + +/* Releases memory storage. All the children of a parent must be released before + the parent. A child storage returns all the blocks to parent when it is released */ +CVAPI(void) cvReleaseMemStorage( CvMemStorage** storage ); + + +/* Clears memory storage. This is the only way(!!!) (besides cvRestoreMemStoragePos) + to reuse memory allocated for the storage - cvClearSeq,cvClearSet ... + do not free any memory. + A child storage returns all the blocks to the parent when it is cleared */ +CVAPI(void) cvClearMemStorage( CvMemStorage* storage ); + +/* Remember a storage "free memory" position */ +CVAPI(void) cvSaveMemStoragePos( const CvMemStorage* storage, CvMemStoragePos* pos ); + +/* Restore a storage "free memory" position */ +CVAPI(void) cvRestoreMemStoragePos( CvMemStorage* storage, CvMemStoragePos* pos ); + +/* Allocates continuous buffer of the specified size in the storage */ +CVAPI(void*) cvMemStorageAlloc( CvMemStorage* storage, size_t size ); + +/* Allocates string in memory storage */ +CVAPI(CvString) cvMemStorageAllocString( CvMemStorage* storage, const char* ptr, + int len CV_DEFAULT(-1) ); + +/* Creates new empty sequence that will reside in the specified storage */ +CVAPI(CvSeq*) cvCreateSeq( int seq_flags, size_t header_size, + size_t elem_size, CvMemStorage* storage ); + +/* Changes default size (granularity) of sequence blocks. + The default size is ~1Kbyte */ +CVAPI(void) cvSetSeqBlockSize( CvSeq* seq, int delta_elems ); + + +/* Adds new element to the end of sequence. Returns pointer to the element */ +CVAPI(schar*) cvSeqPush( CvSeq* seq, const void* element CV_DEFAULT(NULL)); + + +/* Adds new element to the beginning of sequence. Returns pointer to it */ +CVAPI(schar*) cvSeqPushFront( CvSeq* seq, const void* element CV_DEFAULT(NULL)); + + +/* Removes the last element from sequence and optionally saves it */ +CVAPI(void) cvSeqPop( CvSeq* seq, void* element CV_DEFAULT(NULL)); + + +/* Removes the first element from sequence and optioanally saves it */ +CVAPI(void) cvSeqPopFront( CvSeq* seq, void* element CV_DEFAULT(NULL)); + + +#define CV_FRONT 1 +#define CV_BACK 0 +/* Adds several new elements to the end of sequence */ +CVAPI(void) cvSeqPushMulti( CvSeq* seq, const void* elements, + int count, int in_front CV_DEFAULT(0) ); + +/* Removes several elements from the end of sequence and optionally saves them */ +CVAPI(void) cvSeqPopMulti( CvSeq* seq, void* elements, + int count, int in_front CV_DEFAULT(0) ); + +/* Inserts a new element in the middle of sequence. + cvSeqInsert(seq,0,elem) == cvSeqPushFront(seq,elem) */ +CVAPI(schar*) cvSeqInsert( CvSeq* seq, int before_index, + const void* element CV_DEFAULT(NULL)); + +/* Removes specified sequence element */ +CVAPI(void) cvSeqRemove( CvSeq* seq, int index ); + + +/* Removes all the elements from the sequence. The freed memory + can be reused later only by the same sequence unless cvClearMemStorage + or cvRestoreMemStoragePos is called */ +CVAPI(void) cvClearSeq( CvSeq* seq ); + + +/* Retrieves pointer to specified sequence element. + Negative indices are supported and mean counting from the end + (e.g -1 means the last sequence element) */ +CVAPI(schar*) cvGetSeqElem( const CvSeq* seq, int index ); + +/* Calculates index of the specified sequence element. + Returns -1 if element does not belong to the sequence */ +CVAPI(int) cvSeqElemIdx( const CvSeq* seq, const void* element, + CvSeqBlock** block CV_DEFAULT(NULL) ); + +/* Initializes sequence writer. The new elements will be added to the end of sequence */ +CVAPI(void) cvStartAppendToSeq( CvSeq* seq, CvSeqWriter* writer ); + + +/* Combination of cvCreateSeq and cvStartAppendToSeq */ +CVAPI(void) cvStartWriteSeq( int seq_flags, int header_size, + int elem_size, CvMemStorage* storage, + CvSeqWriter* writer ); + +/* Closes sequence writer, updates sequence header and returns pointer + to the resultant sequence + (which may be useful if the sequence was created using cvStartWriteSeq)) +*/ +CVAPI(CvSeq*) cvEndWriteSeq( CvSeqWriter* writer ); + + +/* Updates sequence header. May be useful to get access to some of previously + written elements via cvGetSeqElem or sequence reader */ +CVAPI(void) cvFlushSeqWriter( CvSeqWriter* writer ); + + +/* Initializes sequence reader. + The sequence can be read in forward or backward direction */ +CVAPI(void) cvStartReadSeq( const CvSeq* seq, CvSeqReader* reader, + int reverse CV_DEFAULT(0) ); + + +/* Returns current sequence reader position (currently observed sequence element) */ +CVAPI(int) cvGetSeqReaderPos( CvSeqReader* reader ); + + +/* Changes sequence reader position. It may seek to an absolute or + to relative to the current position */ +CVAPI(void) cvSetSeqReaderPos( CvSeqReader* reader, int index, + int is_relative CV_DEFAULT(0)); + +/* Copies sequence content to a continuous piece of memory */ +CVAPI(void*) cvCvtSeqToArray( const CvSeq* seq, void* elements, + CvSlice slice CV_DEFAULT(CV_WHOLE_SEQ) ); + +/* Creates sequence header for array. + After that all the operations on sequences that do not alter the content + can be applied to the resultant sequence */ +CVAPI(CvSeq*) cvMakeSeqHeaderForArray( int seq_type, int header_size, + int elem_size, void* elements, int total, + CvSeq* seq, CvSeqBlock* block ); + +/* Extracts sequence slice (with or without copying sequence elements) */ +CVAPI(CvSeq*) cvSeqSlice( const CvSeq* seq, CvSlice slice, + CvMemStorage* storage CV_DEFAULT(NULL), + int copy_data CV_DEFAULT(0)); + +CV_INLINE CvSeq* cvCloneSeq( const CvSeq* seq, CvMemStorage* storage CV_DEFAULT(NULL)) +{ + return cvSeqSlice( seq, CV_WHOLE_SEQ, storage, 1 ); +} + +/* Removes sequence slice */ +CVAPI(void) cvSeqRemoveSlice( CvSeq* seq, CvSlice slice ); + +/* Inserts a sequence or array into another sequence */ +CVAPI(void) cvSeqInsertSlice( CvSeq* seq, int before_index, const CvArr* from_arr ); + +/* a < b ? -1 : a > b ? 1 : 0 */ +typedef int (CV_CDECL* CvCmpFunc)(const void* a, const void* b, void* userdata ); + +/* Sorts sequence in-place given element comparison function */ +CVAPI(void) cvSeqSort( CvSeq* seq, CvCmpFunc func, void* userdata CV_DEFAULT(NULL) ); + +/* Finds element in a [sorted] sequence */ +CVAPI(schar*) cvSeqSearch( CvSeq* seq, const void* elem, CvCmpFunc func, + int is_sorted, int* elem_idx, + void* userdata CV_DEFAULT(NULL) ); + +/* Reverses order of sequence elements in-place */ +CVAPI(void) cvSeqInvert( CvSeq* seq ); + +/* Splits sequence into one or more equivalence classes using the specified criteria */ +CVAPI(int) cvSeqPartition( const CvSeq* seq, CvMemStorage* storage, + CvSeq** labels, CvCmpFunc is_equal, void* userdata ); + +/************ Internal sequence functions ************/ +CVAPI(void) cvChangeSeqBlock( void* reader, int direction ); +CVAPI(void) cvCreateSeqBlock( CvSeqWriter* writer ); + + +/* Creates a new set */ +CVAPI(CvSet*) cvCreateSet( int set_flags, int header_size, + int elem_size, CvMemStorage* storage ); + +/* Adds new element to the set and returns pointer to it */ +CVAPI(int) cvSetAdd( CvSet* set_header, CvSetElem* elem CV_DEFAULT(NULL), + CvSetElem** inserted_elem CV_DEFAULT(NULL) ); + +/* Fast variant of cvSetAdd */ +CV_INLINE CvSetElem* cvSetNew( CvSet* set_header ) +{ + CvSetElem* elem = set_header->free_elems; + if( elem ) + { + set_header->free_elems = elem->next_free; + elem->flags = elem->flags & CV_SET_ELEM_IDX_MASK; + set_header->active_count++; + } + else + cvSetAdd( set_header, NULL, (CvSetElem**)&elem ); + return elem; +} + +/* Removes set element given its pointer */ +CV_INLINE void cvSetRemoveByPtr( CvSet* set_header, void* elem ) +{ + CvSetElem* _elem = (CvSetElem*)elem; + assert( _elem->flags >= 0 /*&& (elem->flags & CV_SET_ELEM_IDX_MASK) < set_header->total*/ ); + _elem->next_free = set_header->free_elems; + _elem->flags = (_elem->flags & CV_SET_ELEM_IDX_MASK) | CV_SET_ELEM_FREE_FLAG; + set_header->free_elems = _elem; + set_header->active_count--; +} + +/* Removes element from the set by its index */ +CVAPI(void) cvSetRemove( CvSet* set_header, int index ); + +/* Returns a set element by index. If the element doesn't belong to the set, + NULL is returned */ +CV_INLINE CvSetElem* cvGetSetElem( const CvSet* set_header, int idx ) +{ + CvSetElem* elem = (CvSetElem*)cvGetSeqElem( (CvSeq*)set_header, idx ); + return elem && CV_IS_SET_ELEM( elem ) ? elem : 0; +} + +/* Removes all the elements from the set */ +CVAPI(void) cvClearSet( CvSet* set_header ); + +/* Creates new graph */ +CVAPI(CvGraph*) cvCreateGraph( int graph_flags, int header_size, + int vtx_size, int edge_size, + CvMemStorage* storage ); + +/* Adds new vertex to the graph */ +CVAPI(int) cvGraphAddVtx( CvGraph* graph, const CvGraphVtx* vtx CV_DEFAULT(NULL), + CvGraphVtx** inserted_vtx CV_DEFAULT(NULL) ); + + +/* Removes vertex from the graph together with all incident edges */ +CVAPI(int) cvGraphRemoveVtx( CvGraph* graph, int index ); +CVAPI(int) cvGraphRemoveVtxByPtr( CvGraph* graph, CvGraphVtx* vtx ); + + +/* Link two vertices specifed by indices or pointers if they + are not connected or return pointer to already existing edge + connecting the vertices. + Functions return 1 if a new edge was created, 0 otherwise */ +CVAPI(int) cvGraphAddEdge( CvGraph* graph, + int start_idx, int end_idx, + const CvGraphEdge* edge CV_DEFAULT(NULL), + CvGraphEdge** inserted_edge CV_DEFAULT(NULL) ); + +CVAPI(int) cvGraphAddEdgeByPtr( CvGraph* graph, + CvGraphVtx* start_vtx, CvGraphVtx* end_vtx, + const CvGraphEdge* edge CV_DEFAULT(NULL), + CvGraphEdge** inserted_edge CV_DEFAULT(NULL) ); + +/* Remove edge connecting two vertices */ +CVAPI(void) cvGraphRemoveEdge( CvGraph* graph, int start_idx, int end_idx ); +CVAPI(void) cvGraphRemoveEdgeByPtr( CvGraph* graph, CvGraphVtx* start_vtx, + CvGraphVtx* end_vtx ); + +/* Find edge connecting two vertices */ +CVAPI(CvGraphEdge*) cvFindGraphEdge( const CvGraph* graph, int start_idx, int end_idx ); +CVAPI(CvGraphEdge*) cvFindGraphEdgeByPtr( const CvGraph* graph, + const CvGraphVtx* start_vtx, + const CvGraphVtx* end_vtx ); +#define cvGraphFindEdge cvFindGraphEdge +#define cvGraphFindEdgeByPtr cvFindGraphEdgeByPtr + +/* Remove all vertices and edges from the graph */ +CVAPI(void) cvClearGraph( CvGraph* graph ); + + +/* Count number of edges incident to the vertex */ +CVAPI(int) cvGraphVtxDegree( const CvGraph* graph, int vtx_idx ); +CVAPI(int) cvGraphVtxDegreeByPtr( const CvGraph* graph, const CvGraphVtx* vtx ); + + +/* Retrieves graph vertex by given index */ +#define cvGetGraphVtx( graph, idx ) (CvGraphVtx*)cvGetSetElem((CvSet*)(graph), (idx)) + +/* Retrieves index of a graph vertex given its pointer */ +#define cvGraphVtxIdx( graph, vtx ) ((vtx)->flags & CV_SET_ELEM_IDX_MASK) + +/* Retrieves index of a graph edge given its pointer */ +#define cvGraphEdgeIdx( graph, edge ) ((edge)->flags & CV_SET_ELEM_IDX_MASK) + +#define cvGraphGetVtxCount( graph ) ((graph)->active_count) +#define cvGraphGetEdgeCount( graph ) ((graph)->edges->active_count) + +#define CV_GRAPH_VERTEX 1 +#define CV_GRAPH_TREE_EDGE 2 +#define CV_GRAPH_BACK_EDGE 4 +#define CV_GRAPH_FORWARD_EDGE 8 +#define CV_GRAPH_CROSS_EDGE 16 +#define CV_GRAPH_ANY_EDGE 30 +#define CV_GRAPH_NEW_TREE 32 +#define CV_GRAPH_BACKTRACKING 64 +#define CV_GRAPH_OVER -1 + +#define CV_GRAPH_ALL_ITEMS -1 + +/* flags for graph vertices and edges */ +#define CV_GRAPH_ITEM_VISITED_FLAG (1 << 30) +#define CV_IS_GRAPH_VERTEX_VISITED(vtx) \ + (((CvGraphVtx*)(vtx))->flags & CV_GRAPH_ITEM_VISITED_FLAG) +#define CV_IS_GRAPH_EDGE_VISITED(edge) \ + (((CvGraphEdge*)(edge))->flags & CV_GRAPH_ITEM_VISITED_FLAG) +#define CV_GRAPH_SEARCH_TREE_NODE_FLAG (1 << 29) +#define CV_GRAPH_FORWARD_EDGE_FLAG (1 << 28) + +typedef struct CvGraphScanner +{ + CvGraphVtx* vtx; /* current graph vertex (or current edge origin) */ + CvGraphVtx* dst; /* current graph edge destination vertex */ + CvGraphEdge* edge; /* current edge */ + + CvGraph* graph; /* the graph */ + CvSeq* stack; /* the graph vertex stack */ + int index; /* the lower bound of certainly visited vertices */ + int mask; /* event mask */ +} +CvGraphScanner; + +/* Creates new graph scanner. */ +CVAPI(CvGraphScanner*) cvCreateGraphScanner( CvGraph* graph, + CvGraphVtx* vtx CV_DEFAULT(NULL), + int mask CV_DEFAULT(CV_GRAPH_ALL_ITEMS)); + +/* Releases graph scanner. */ +CVAPI(void) cvReleaseGraphScanner( CvGraphScanner** scanner ); + +/* Get next graph element */ +CVAPI(int) cvNextGraphItem( CvGraphScanner* scanner ); + +/* Creates a copy of graph */ +CVAPI(CvGraph*) cvCloneGraph( const CvGraph* graph, CvMemStorage* storage ); + +/****************************************************************************************\ +* Drawing * +\****************************************************************************************/ + +/****************************************************************************************\ +* Drawing functions work with images/matrices of arbitrary type. * +* For color images the channel order is BGR[A] * +* Antialiasing is supported only for 8-bit image now. * +* All the functions include parameter color that means rgb value (that may be * +* constructed with CV_RGB macro) for color images and brightness * +* for grayscale images. * +* If a drawn figure is partially or completely outside of the image, it is clipped.* +\****************************************************************************************/ + +#define CV_RGB( r, g, b ) cvScalar( (b), (g), (r), 0 ) +#define CV_FILLED -1 + +#define CV_AA 16 + +/* Draws 4-connected, 8-connected or antialiased line segment connecting two points */ +CVAPI(void) cvLine( CvArr* img, CvPoint pt1, CvPoint pt2, + CvScalar color, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) ); + +/* Draws a rectangle given two opposite corners of the rectangle (pt1 & pt2), + if thickness<0 (e.g. thickness == CV_FILLED), the filled box is drawn */ +CVAPI(void) cvRectangle( CvArr* img, CvPoint pt1, CvPoint pt2, + CvScalar color, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), + int shift CV_DEFAULT(0)); + +/* Draws a rectangle specified by a CvRect structure */ +CVAPI(void) cvRectangleR( CvArr* img, CvRect r, + CvScalar color, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), + int shift CV_DEFAULT(0)); + + +/* Draws a circle with specified center and radius. + Thickness works in the same way as with cvRectangle */ +CVAPI(void) cvCircle( CvArr* img, CvPoint center, int radius, + CvScalar color, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0)); + +/* Draws ellipse outline, filled ellipse, elliptic arc or filled elliptic sector, + depending on , and parameters. The resultant figure + is rotated by . All the angles are in degrees */ +CVAPI(void) cvEllipse( CvArr* img, CvPoint center, CvSize axes, + double angle, double start_angle, double end_angle, + CvScalar color, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0)); + +CV_INLINE void cvEllipseBox( CvArr* img, CvBox2D box, CvScalar color, + int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) ) +{ + CvSize axes; + axes.width = cvRound(box.size.width*0.5); + axes.height = cvRound(box.size.height*0.5); + + cvEllipse( img, cvPointFrom32f( box.center ), axes, box.angle, + 0, 360, color, thickness, line_type, shift ); +} + +/* Fills convex or monotonous polygon. */ +CVAPI(void) cvFillConvexPoly( CvArr* img, const CvPoint* pts, int npts, CvScalar color, + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0)); + +/* Fills an area bounded by one or more arbitrary polygons */ +CVAPI(void) cvFillPoly( CvArr* img, CvPoint** pts, const int* npts, + int contours, CvScalar color, + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) ); + +/* Draws one or more polygonal curves */ +CVAPI(void) cvPolyLine( CvArr* img, CvPoint** pts, const int* npts, int contours, + int is_closed, CvScalar color, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) ); + +#define cvDrawRect cvRectangle +#define cvDrawLine cvLine +#define cvDrawCircle cvCircle +#define cvDrawEllipse cvEllipse +#define cvDrawPolyLine cvPolyLine + +/* Clips the line segment connecting *pt1 and *pt2 + by the rectangular window + (0<=xptr will point + to pt1 (or pt2, see left_to_right description) location in the image. + Returns the number of pixels on the line between the ending points. */ +CVAPI(int) cvInitLineIterator( const CvArr* image, CvPoint pt1, CvPoint pt2, + CvLineIterator* line_iterator, + int connectivity CV_DEFAULT(8), + int left_to_right CV_DEFAULT(0)); + +/* Moves iterator to the next line point */ +#define CV_NEXT_LINE_POINT( line_iterator ) \ +{ \ + int _line_iterator_mask = (line_iterator).err < 0 ? -1 : 0; \ + (line_iterator).err += (line_iterator).minus_delta + \ + ((line_iterator).plus_delta & _line_iterator_mask); \ + (line_iterator).ptr += (line_iterator).minus_step + \ + ((line_iterator).plus_step & _line_iterator_mask); \ +} + + +/* basic font types */ +#define CV_FONT_HERSHEY_SIMPLEX 0 +#define CV_FONT_HERSHEY_PLAIN 1 +#define CV_FONT_HERSHEY_DUPLEX 2 +#define CV_FONT_HERSHEY_COMPLEX 3 +#define CV_FONT_HERSHEY_TRIPLEX 4 +#define CV_FONT_HERSHEY_COMPLEX_SMALL 5 +#define CV_FONT_HERSHEY_SCRIPT_SIMPLEX 6 +#define CV_FONT_HERSHEY_SCRIPT_COMPLEX 7 + +/* font flags */ +#define CV_FONT_ITALIC 16 + +#define CV_FONT_VECTOR0 CV_FONT_HERSHEY_SIMPLEX + + +/* Font structure */ +typedef struct CvFont +{ + const char* nameFont; //Qt:nameFont + CvScalar color; //Qt:ColorFont -> cvScalar(blue_component, green_component, red\_component[, alpha_component]) + int font_face; //Qt: bool italic /* =CV_FONT_* */ + const int* ascii; /* font data and metrics */ + const int* greek; + const int* cyrillic; + float hscale, vscale; + float shear; /* slope coefficient: 0 - normal, >0 - italic */ + int thickness; //Qt: weight /* letters thickness */ + float dx; /* horizontal interval between letters */ + int line_type; //Qt: PointSize +} +CvFont; + +/* Initializes font structure used further in cvPutText */ +CVAPI(void) cvInitFont( CvFont* font, int font_face, + double hscale, double vscale, + double shear CV_DEFAULT(0), + int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8)); + +CV_INLINE CvFont cvFont( double scale, int thickness CV_DEFAULT(1) ) +{ + CvFont font; + cvInitFont( &font, CV_FONT_HERSHEY_PLAIN, scale, scale, 0, thickness, CV_AA ); + return font; +} + +/* Renders text stroke with specified font and color at specified location. + CvFont should be initialized with cvInitFont */ +CVAPI(void) cvPutText( CvArr* img, const char* text, CvPoint org, + const CvFont* font, CvScalar color ); + +/* Calculates bounding box of text stroke (useful for alignment) */ +CVAPI(void) cvGetTextSize( const char* text_string, const CvFont* font, + CvSize* text_size, int* baseline ); + + + +/* Unpacks color value, if arrtype is CV_8UC?, is treated as + packed color value, otherwise the first channels (depending on arrtype) + of destination scalar are set to the same value = */ +CVAPI(CvScalar) cvColorToScalar( double packed_color, int arrtype ); + +/* Returns the polygon points which make up the given ellipse. The ellipse is define by + the box of size 'axes' rotated 'angle' around the 'center'. A partial sweep + of the ellipse arc can be done by spcifying arc_start and arc_end to be something + other than 0 and 360, respectively. The input array 'pts' must be large enough to + hold the result. The total number of points stored into 'pts' is returned by this + function. */ +CVAPI(int) cvEllipse2Poly( CvPoint center, CvSize axes, + int angle, int arc_start, int arc_end, CvPoint * pts, int delta ); + +/* Draws contour outlines or filled interiors on the image */ +CVAPI(void) cvDrawContours( CvArr *img, CvSeq* contour, + CvScalar external_color, CvScalar hole_color, + int max_level, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), + CvPoint offset CV_DEFAULT(cvPoint(0,0))); + +/* Does look-up transformation. Elements of the source array + (that should be 8uC1 or 8sC1) are used as indexes in lutarr 256-element table */ +CVAPI(void) cvLUT( const CvArr* src, CvArr* dst, const CvArr* lut ); + + +/******************* Iteration through the sequence tree *****************/ +typedef struct CvTreeNodeIterator +{ + const void* node; + int level; + int max_level; +} +CvTreeNodeIterator; + +CVAPI(void) cvInitTreeNodeIterator( CvTreeNodeIterator* tree_iterator, + const void* first, int max_level ); +CVAPI(void*) cvNextTreeNode( CvTreeNodeIterator* tree_iterator ); +CVAPI(void*) cvPrevTreeNode( CvTreeNodeIterator* tree_iterator ); + +/* Inserts sequence into tree with specified "parent" sequence. + If parent is equal to frame (e.g. the most external contour), + then added contour will have null pointer to parent. */ +CVAPI(void) cvInsertNodeIntoTree( void* node, void* parent, void* frame ); + +/* Removes contour from tree (together with the contour children). */ +CVAPI(void) cvRemoveNodeFromTree( void* node, void* frame ); + +/* Gathers pointers to all the sequences, + accessible from the , to the single sequence */ +CVAPI(CvSeq*) cvTreeToNodeSeq( const void* first, int header_size, + CvMemStorage* storage ); + +/* The function implements the K-means algorithm for clustering an array of sample + vectors in a specified number of classes */ +#define CV_KMEANS_USE_INITIAL_LABELS 1 +CVAPI(int) cvKMeans2( const CvArr* samples, int cluster_count, CvArr* labels, + CvTermCriteria termcrit, int attempts CV_DEFAULT(1), + CvRNG* rng CV_DEFAULT(0), int flags CV_DEFAULT(0), + CvArr* _centers CV_DEFAULT(0), double* compactness CV_DEFAULT(0) ); + +/****************************************************************************************\ +* System functions * +\****************************************************************************************/ + +/* Add the function pointers table with associated information to the IPP primitives list */ +CVAPI(int) cvRegisterModule( const CvModuleInfo* module_info ); + +/* Loads optimized functions from IPP, MKL etc. or switches back to pure C code */ +CVAPI(int) cvUseOptimized( int on_off ); + +/* Retrieves information about the registered modules and loaded optimized plugins */ +CVAPI(void) cvGetModuleInfo( const char* module_name, + const char** version, + const char** loaded_addon_plugins ); + +typedef void* (CV_CDECL *CvAllocFunc)(size_t size, void* userdata); +typedef int (CV_CDECL *CvFreeFunc)(void* pptr, void* userdata); + +/* Set user-defined memory managment functions (substitutors for malloc and free) that + will be called by cvAlloc, cvFree and higher-level functions (e.g. cvCreateImage) */ +CVAPI(void) cvSetMemoryManager( CvAllocFunc alloc_func CV_DEFAULT(NULL), + CvFreeFunc free_func CV_DEFAULT(NULL), + void* userdata CV_DEFAULT(NULL)); + + +typedef IplImage* (CV_STDCALL* Cv_iplCreateImageHeader) + (int,int,int,char*,char*,int,int,int,int,int, + IplROI*,IplImage*,void*,IplTileInfo*); +typedef void (CV_STDCALL* Cv_iplAllocateImageData)(IplImage*,int,int); +typedef void (CV_STDCALL* Cv_iplDeallocate)(IplImage*,int); +typedef IplROI* (CV_STDCALL* Cv_iplCreateROI)(int,int,int,int,int); +typedef IplImage* (CV_STDCALL* Cv_iplCloneImage)(const IplImage*); + +/* Makes OpenCV use IPL functions for IplImage allocation/deallocation */ +CVAPI(void) cvSetIPLAllocators( Cv_iplCreateImageHeader create_header, + Cv_iplAllocateImageData allocate_data, + Cv_iplDeallocate deallocate, + Cv_iplCreateROI create_roi, + Cv_iplCloneImage clone_image ); + +#define CV_TURN_ON_IPL_COMPATIBILITY() \ + cvSetIPLAllocators( iplCreateImageHeader, iplAllocateImage, \ + iplDeallocate, iplCreateROI, iplCloneImage ) + +/****************************************************************************************\ +* Data Persistence * +\****************************************************************************************/ + +/********************************** High-level functions ********************************/ + +/* opens existing or creates new file storage */ +CVAPI(CvFileStorage*) cvOpenFileStorage( const char* filename, CvMemStorage* memstorage, + int flags, const char* encoding CV_DEFAULT(NULL) ); + +/* closes file storage and deallocates buffers */ +CVAPI(void) cvReleaseFileStorage( CvFileStorage** fs ); + +/* returns attribute value or 0 (NULL) if there is no such attribute */ +CVAPI(const char*) cvAttrValue( const CvAttrList* attr, const char* attr_name ); + +/* starts writing compound structure (map or sequence) */ +CVAPI(void) cvStartWriteStruct( CvFileStorage* fs, const char* name, + int struct_flags, const char* type_name CV_DEFAULT(NULL), + CvAttrList attributes CV_DEFAULT(cvAttrList())); + +/* finishes writing compound structure */ +CVAPI(void) cvEndWriteStruct( CvFileStorage* fs ); + +/* writes an integer */ +CVAPI(void) cvWriteInt( CvFileStorage* fs, const char* name, int value ); + +/* writes a floating-point number */ +CVAPI(void) cvWriteReal( CvFileStorage* fs, const char* name, double value ); + +/* writes a string */ +CVAPI(void) cvWriteString( CvFileStorage* fs, const char* name, + const char* str, int quote CV_DEFAULT(0) ); + +/* writes a comment */ +CVAPI(void) cvWriteComment( CvFileStorage* fs, const char* comment, + int eol_comment ); + +/* writes instance of a standard type (matrix, image, sequence, graph etc.) + or user-defined type */ +CVAPI(void) cvWrite( CvFileStorage* fs, const char* name, const void* ptr, + CvAttrList attributes CV_DEFAULT(cvAttrList())); + +/* starts the next stream */ +CVAPI(void) cvStartNextStream( CvFileStorage* fs ); + +/* helper function: writes multiple integer or floating-point numbers */ +CVAPI(void) cvWriteRawData( CvFileStorage* fs, const void* src, + int len, const char* dt ); + +/* returns the hash entry corresponding to the specified literal key string or 0 + if there is no such a key in the storage */ +CVAPI(CvStringHashNode*) cvGetHashedKey( CvFileStorage* fs, const char* name, + int len CV_DEFAULT(-1), + int create_missing CV_DEFAULT(0)); + +/* returns file node with the specified key within the specified map + (collection of named nodes) */ +CVAPI(CvFileNode*) cvGetRootFileNode( const CvFileStorage* fs, + int stream_index CV_DEFAULT(0) ); + +/* returns file node with the specified key within the specified map + (collection of named nodes) */ +CVAPI(CvFileNode*) cvGetFileNode( CvFileStorage* fs, CvFileNode* map, + const CvStringHashNode* key, + int create_missing CV_DEFAULT(0) ); + +/* this is a slower version of cvGetFileNode that takes the key as a literal string */ +CVAPI(CvFileNode*) cvGetFileNodeByName( const CvFileStorage* fs, + const CvFileNode* map, + const char* name ); + +CV_INLINE int cvReadInt( const CvFileNode* node, int default_value CV_DEFAULT(0) ) +{ + return !node ? default_value : + CV_NODE_IS_INT(node->tag) ? node->data.i : + CV_NODE_IS_REAL(node->tag) ? cvRound(node->data.f) : 0x7fffffff; +} + + +CV_INLINE int cvReadIntByName( const CvFileStorage* fs, const CvFileNode* map, + const char* name, int default_value CV_DEFAULT(0) ) +{ + return cvReadInt( cvGetFileNodeByName( fs, map, name ), default_value ); +} + + +CV_INLINE double cvReadReal( const CvFileNode* node, double default_value CV_DEFAULT(0.) ) +{ + return !node ? default_value : + CV_NODE_IS_INT(node->tag) ? (double)node->data.i : + CV_NODE_IS_REAL(node->tag) ? node->data.f : 1e300; +} + + +CV_INLINE double cvReadRealByName( const CvFileStorage* fs, const CvFileNode* map, + const char* name, double default_value CV_DEFAULT(0.) ) +{ + return cvReadReal( cvGetFileNodeByName( fs, map, name ), default_value ); +} + + +CV_INLINE const char* cvReadString( const CvFileNode* node, + const char* default_value CV_DEFAULT(NULL) ) +{ + return !node ? default_value : CV_NODE_IS_STRING(node->tag) ? node->data.str.ptr : 0; +} + + +CV_INLINE const char* cvReadStringByName( const CvFileStorage* fs, const CvFileNode* map, + const char* name, const char* default_value CV_DEFAULT(NULL) ) +{ + return cvReadString( cvGetFileNodeByName( fs, map, name ), default_value ); +} + + +/* decodes standard or user-defined object and returns it */ +CVAPI(void*) cvRead( CvFileStorage* fs, CvFileNode* node, + CvAttrList* attributes CV_DEFAULT(NULL)); + +/* decodes standard or user-defined object and returns it */ +CV_INLINE void* cvReadByName( CvFileStorage* fs, const CvFileNode* map, + const char* name, CvAttrList* attributes CV_DEFAULT(NULL) ) +{ + return cvRead( fs, cvGetFileNodeByName( fs, map, name ), attributes ); +} + + +/* starts reading data from sequence or scalar numeric node */ +CVAPI(void) cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src, + CvSeqReader* reader ); + +/* reads multiple numbers and stores them to array */ +CVAPI(void) cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader, + int count, void* dst, const char* dt ); + +/* combination of two previous functions for easier reading of whole sequences */ +CVAPI(void) cvReadRawData( const CvFileStorage* fs, const CvFileNode* src, + void* dst, const char* dt ); + +/* writes a copy of file node to file storage */ +CVAPI(void) cvWriteFileNode( CvFileStorage* fs, const char* new_node_name, + const CvFileNode* node, int embed ); + +/* returns name of file node */ +CVAPI(const char*) cvGetFileNodeName( const CvFileNode* node ); + +/*********************************** Adding own types ***********************************/ + +CVAPI(void) cvRegisterType( const CvTypeInfo* info ); +CVAPI(void) cvUnregisterType( const char* type_name ); +CVAPI(CvTypeInfo*) cvFirstType(void); +CVAPI(CvTypeInfo*) cvFindType( const char* type_name ); +CVAPI(CvTypeInfo*) cvTypeOf( const void* struct_ptr ); + +/* universal functions */ +CVAPI(void) cvRelease( void** struct_ptr ); +CVAPI(void*) cvClone( const void* struct_ptr ); + +/* simple API for reading/writing data */ +CVAPI(void) cvSave( const char* filename, const void* struct_ptr, + const char* name CV_DEFAULT(NULL), + const char* comment CV_DEFAULT(NULL), + CvAttrList attributes CV_DEFAULT(cvAttrList())); +CVAPI(void*) cvLoad( const char* filename, + CvMemStorage* memstorage CV_DEFAULT(NULL), + const char* name CV_DEFAULT(NULL), + const char** real_name CV_DEFAULT(NULL) ); + +/*********************************** Measuring Execution Time ***************************/ + +/* helper functions for RNG initialization and accurate time measurement: + uses internal clock counter on x86 */ +CVAPI(int64) cvGetTickCount( void ); +CVAPI(double) cvGetTickFrequency( void ); + +/*********************************** CPU capabilities ***********************************/ + +#define CV_CPU_NONE 0 +#define CV_CPU_MMX 1 +#define CV_CPU_SSE 2 +#define CV_CPU_SSE2 3 +#define CV_CPU_SSE3 4 +#define CV_CPU_SSSE3 5 +#define CV_CPU_SSE4_1 6 +#define CV_CPU_SSE4_2 7 +#define CV_CPU_POPCNT 8 +#define CV_CPU_AVX 10 +#define CV_HARDWARE_MAX_FEATURE 255 + +CVAPI(int) cvCheckHardwareSupport(int feature); + +/*********************************** Multi-Threading ************************************/ + +/* retrieve/set the number of threads used in OpenMP implementations */ +CVAPI(int) cvGetNumThreads( void ); +CVAPI(void) cvSetNumThreads( int threads CV_DEFAULT(0) ); +/* get index of the thread being executed */ +CVAPI(int) cvGetThreadNum( void ); + + +/********************************** Error Handling **************************************/ + +/* Get current OpenCV error status */ +CVAPI(int) cvGetErrStatus( void ); + +/* Sets error status silently */ +CVAPI(void) cvSetErrStatus( int status ); + +#define CV_ErrModeLeaf 0 /* Print error and exit program */ +#define CV_ErrModeParent 1 /* Print error and continue */ +#define CV_ErrModeSilent 2 /* Don't print and continue */ + +/* Retrives current error processing mode */ +CVAPI(int) cvGetErrMode( void ); + +/* Sets error processing mode, returns previously used mode */ +CVAPI(int) cvSetErrMode( int mode ); + +/* Sets error status and performs some additonal actions (displaying message box, + writing message to stderr, terminating application etc.) + depending on the current error mode */ +CVAPI(void) cvError( int status, const char* func_name, + const char* err_msg, const char* file_name, int line ); + +/* Retrieves textual description of the error given its code */ +CVAPI(const char*) cvErrorStr( int status ); + +/* Retrieves detailed information about the last error occured */ +CVAPI(int) cvGetErrInfo( const char** errcode_desc, const char** description, + const char** filename, int* line ); + +/* Maps IPP error codes to the counterparts from OpenCV */ +CVAPI(int) cvErrorFromIppStatus( int ipp_status ); + +typedef int (CV_CDECL *CvErrorCallback)( int status, const char* func_name, + const char* err_msg, const char* file_name, int line, void* userdata ); + +/* Assigns a new error-handling function */ +CVAPI(CvErrorCallback) cvRedirectError( CvErrorCallback error_handler, + void* userdata CV_DEFAULT(NULL), + void** prev_userdata CV_DEFAULT(NULL) ); + +/* + Output to: + cvNulDevReport - nothing + cvStdErrReport - console(fprintf(stderr,...)) + cvGuiBoxReport - MessageBox(WIN32) + */ +CVAPI(int) cvNulDevReport( int status, const char* func_name, const char* err_msg, + const char* file_name, int line, void* userdata ); + +CVAPI(int) cvStdErrReport( int status, const char* func_name, const char* err_msg, + const char* file_name, int line, void* userdata ); + +CVAPI(int) cvGuiBoxReport( int status, const char* func_name, const char* err_msg, + const char* file_name, int line, void* userdata ); + +#define OPENCV_ERROR(status,func,context) \ +cvError((status),(func),(context),__FILE__,__LINE__) + +#define OPENCV_ERRCHK(func,context) \ +{if (cvGetErrStatus() >= 0) \ +{OPENCV_ERROR(CV_StsBackTrace,(func),(context));}} + +#define OPENCV_ASSERT(expr,func,context) \ +{if (! (expr)) \ +{OPENCV_ERROR(CV_StsInternal,(func),(context));}} + +#define OPENCV_RSTERR() (cvSetErrStatus(CV_StsOk)) + +#define OPENCV_CALL( Func ) \ +{ \ +Func; \ +} + + +/* CV_FUNCNAME macro defines icvFuncName constant which is used by CV_ERROR macro */ +#ifdef CV_NO_FUNC_NAMES +#define CV_FUNCNAME( Name ) +#define cvFuncName "" +#else +#define CV_FUNCNAME( Name ) \ +static char cvFuncName[] = Name +#endif + + +/* + CV_ERROR macro unconditionally raises error with passed code and message. + After raising error, control will be transferred to the exit label. + */ +#define CV_ERROR( Code, Msg ) \ +{ \ + cvError( (Code), cvFuncName, Msg, __FILE__, __LINE__ ); \ + __CV_EXIT__; \ +} + +/* Simplified form of CV_ERROR */ +#define CV_ERROR_FROM_CODE( code ) \ + CV_ERROR( code, "" ) + +/* + CV_CHECK macro checks error status after CV (or IPL) + function call. If error detected, control will be transferred to the exit + label. + */ +#define CV_CHECK() \ +{ \ + if( cvGetErrStatus() < 0 ) \ + CV_ERROR( CV_StsBackTrace, "Inner function failed." ); \ +} + + +/* + CV_CALL macro calls CV (or IPL) function, checks error status and + signals a error if the function failed. Useful in "parent node" + error procesing mode + */ +#define CV_CALL( Func ) \ +{ \ + Func; \ + CV_CHECK(); \ +} + + +/* Runtime assertion macro */ +#define CV_ASSERT( Condition ) \ +{ \ + if( !(Condition) ) \ + CV_ERROR( CV_StsInternal, "Assertion: " #Condition " failed" ); \ +} + +#define __CV_BEGIN__ { +#define __CV_END__ goto exit; exit: ; } +#define __CV_EXIT__ goto exit + +#ifdef __cplusplus +} + +// classes for automatic module/RTTI data registration/unregistration +struct CV_EXPORTS CvModule +{ + CvModule( CvModuleInfo* _info ); + ~CvModule(); + CvModuleInfo* info; + + static CvModuleInfo* first; + static CvModuleInfo* last; +}; + +struct CV_EXPORTS CvType +{ + CvType( const char* type_name, + CvIsInstanceFunc is_instance, CvReleaseFunc release=0, + CvReadFunc read=0, CvWriteFunc write=0, CvCloneFunc clone=0 ); + ~CvType(); + CvTypeInfo* info; + + static CvTypeInfo* first; + static CvTypeInfo* last; +}; + +#endif + +#endif diff --git a/core/include/opencv2/core/cuda_devptrs.hpp b/core/include/opencv2/core/cuda_devptrs.hpp new file mode 100644 index 0000000..257f596 --- /dev/null +++ b/core/include/opencv2/core/cuda_devptrs.hpp @@ -0,0 +1,160 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other GpuMaterials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_CORE_DEVPTRS_HPP__ +#define __OPENCV_CORE_DEVPTRS_HPP__ + +#ifdef __cplusplus + +#ifdef __CUDACC__ + #define __CV_GPU_HOST_DEVICE__ __host__ __device__ __forceinline__ +#else + #define __CV_GPU_HOST_DEVICE__ +#endif + +namespace cv +{ + namespace gpu + { + // Simple lightweight structures that encapsulates information about an image on device. + // It is intended to pass to nvcc-compiled code. GpuMat depends on headers that nvcc can't compile + + template struct StaticAssert; + template <> struct StaticAssert {static __CV_GPU_HOST_DEVICE__ void check(){}}; + + template struct DevPtr + { + typedef T elem_type; + typedef int index_type; + + enum { elem_size = sizeof(elem_type) }; + + T* data; + + __CV_GPU_HOST_DEVICE__ DevPtr() : data(0) {} + __CV_GPU_HOST_DEVICE__ DevPtr(T* data_) : data(data_) {} + + __CV_GPU_HOST_DEVICE__ size_t elemSize() const { return elem_size; } + __CV_GPU_HOST_DEVICE__ operator T*() { return data; } + __CV_GPU_HOST_DEVICE__ operator const T*() const { return data; } + }; + + template struct PtrSz : public DevPtr + { + __CV_GPU_HOST_DEVICE__ PtrSz() : size(0) {} + __CV_GPU_HOST_DEVICE__ PtrSz(T* data_, size_t size_) : DevPtr(data_), size(size_) {} + + size_t size; + }; + + template struct PtrStep : public DevPtr + { + __CV_GPU_HOST_DEVICE__ PtrStep() : step(0) {} + __CV_GPU_HOST_DEVICE__ PtrStep(T* data_, size_t step_) : DevPtr(data_), step(step_) {} + + /** \brief stride between two consecutive rows in bytes. Step is stored always and everywhere in bytes!!! */ + size_t step; + + __CV_GPU_HOST_DEVICE__ T* ptr(int y = 0) { return ( T*)( ( char*)DevPtr::data + y * step); } + __CV_GPU_HOST_DEVICE__ const T* ptr(int y = 0) const { return (const T*)( (const char*)DevPtr::data + y * step); } + + __CV_GPU_HOST_DEVICE__ T& operator ()(int y, int x) { return ptr(y)[x]; } + __CV_GPU_HOST_DEVICE__ const T& operator ()(int y, int x) const { return ptr(y)[x]; } + }; + + template struct PtrStepSz : public PtrStep + { + __CV_GPU_HOST_DEVICE__ PtrStepSz() : cols(0), rows(0) {} + __CV_GPU_HOST_DEVICE__ PtrStepSz(int rows_, int cols_, T* data_, size_t step_) + : PtrStep(data_, step_), cols(cols_), rows(rows_) {} + + template + explicit PtrStepSz(const PtrStepSz& d) : PtrStep((T*)d.data, d.step), cols(d.cols), rows(d.rows){} + + int cols; + int rows; + }; + + typedef PtrStepSz PtrStepSzb; + typedef PtrStepSz PtrStepSzf; + typedef PtrStepSz PtrStepSzi; + + typedef PtrStep PtrStepb; + typedef PtrStep PtrStepf; + typedef PtrStep PtrStepi; + + +#if defined __GNUC__ + #define __CV_GPU_DEPR_BEFORE__ + #define __CV_GPU_DEPR_AFTER__ __attribute__ ((deprecated)) +#elif defined(__MSVC__) //|| defined(__CUDACC__) + #pragma deprecated(DevMem2D_) + #define __CV_GPU_DEPR_BEFORE__ __declspec(deprecated) + #define __CV_GPU_DEPR_AFTER__ +#else + #define __CV_GPU_DEPR_BEFORE__ + #define __CV_GPU_DEPR_AFTER__ +#endif + + template struct __CV_GPU_DEPR_BEFORE__ DevMem2D_ : public PtrStepSz + { + DevMem2D_() {} + DevMem2D_(int rows_, int cols_, T* data_, size_t step_) : PtrStepSz(rows_, cols_, data_, step_) {} + + template + explicit __CV_GPU_DEPR_BEFORE__ DevMem2D_(const DevMem2D_& d) : PtrStepSz(d.rows, d.cols, (T*)d.data, d.step) {} + } __CV_GPU_DEPR_AFTER__ ; + + typedef DevMem2D_ DevMem2Db; + typedef DevMem2Db DevMem2D; + typedef DevMem2D_ DevMem2Df; + typedef DevMem2D_ DevMem2Di; + +//#undef __CV_GPU_DEPR_BEFORE__ +//#undef __CV_GPU_DEPR_AFTER__ + + } +} + +#endif // __cplusplus + +#endif /* __OPENCV_CORE_DEVPTRS_HPP__ */ diff --git a/core/include/opencv2/core/eigen.hpp b/core/include/opencv2/core/eigen.hpp new file mode 100644 index 0000000..49bd36b --- /dev/null +++ b/core/include/opencv2/core/eigen.hpp @@ -0,0 +1,296 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_CORE_EIGEN_HPP__ +#define __OPENCV_CORE_EIGEN_HPP__ + +#ifdef __cplusplus + +#include "opencv2/core/core_c.h" +#include "opencv2/core/core.hpp" + +#if defined _MSC_VER && _MSC_VER >= 1200 +#pragma warning( disable: 4714 ) //__forceinline is not inlined +#pragma warning( disable: 4127 ) //conditional expression is constant +#pragma warning( disable: 4244 ) //conversion from '__int64' to 'int', possible loss of data +#endif + +namespace cv +{ + +template +void eigen2cv( const Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& src, Mat& dst ) +{ + if( !(src.Flags & Eigen::RowMajorBit) ) + { + Mat _src(src.cols(), src.rows(), DataType<_Tp>::type, + (void*)src.data(), src.stride()*sizeof(_Tp)); + transpose(_src, dst); + } + else + { + Mat _src(src.rows(), src.cols(), DataType<_Tp>::type, + (void*)src.data(), src.stride()*sizeof(_Tp)); + _src.copyTo(dst); + } +} + +// Matx case +template +void eigen2cv( const Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& src, + Matx<_Tp, _rows, _cols>& dst ) +{ + if( !(src.Flags & Eigen::RowMajorBit) ) + { + dst = Matx<_Tp, _cols, _rows>(static_cast(src.data())).t(); + } + else + { + dst = Matx<_Tp, _rows, _cols>(static_cast(src.data())); + } +} + +template +void cv2eigen( const Mat& src, + Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& dst ) +{ + CV_DbgAssert(src.rows == _rows && src.cols == _cols); + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + Mat _dst(src.cols, src.rows, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + if( src.type() == _dst.type() ) + transpose(src, _dst); + else if( src.cols == src.rows ) + { + src.convertTo(_dst, _dst.type()); + transpose(_dst, _dst); + } + else + Mat(src.t()).convertTo(_dst, _dst.type()); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } + else + { + Mat _dst(src.rows, src.cols, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + src.convertTo(_dst, _dst.type()); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } +} + +// Matx case +template +void cv2eigen( const Matx<_Tp, _rows, _cols>& src, + Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& dst ) +{ + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + Mat _dst(_cols, _rows, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + transpose(src, _dst); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } + else + { + Mat _dst(_rows, _cols, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + Mat(src).copyTo(_dst); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } +} + +template +void cv2eigen( const Mat& src, + Eigen::Matrix<_Tp, Eigen::Dynamic, Eigen::Dynamic>& dst ) +{ + dst.resize(src.rows, src.cols); + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + Mat _dst(src.cols, src.rows, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + if( src.type() == _dst.type() ) + transpose(src, _dst); + else if( src.cols == src.rows ) + { + src.convertTo(_dst, _dst.type()); + transpose(_dst, _dst); + } + else + Mat(src.t()).convertTo(_dst, _dst.type()); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } + else + { + Mat _dst(src.rows, src.cols, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + src.convertTo(_dst, _dst.type()); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } +} + +// Matx case +template +void cv2eigen( const Matx<_Tp, _rows, _cols>& src, + Eigen::Matrix<_Tp, Eigen::Dynamic, Eigen::Dynamic>& dst ) +{ + dst.resize(_rows, _cols); + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + Mat _dst(_cols, _rows, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + transpose(src, _dst); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } + else + { + Mat _dst(_rows, _cols, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + Mat(src).copyTo(_dst); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } +} + +template +void cv2eigen( const Mat& src, + Eigen::Matrix<_Tp, Eigen::Dynamic, 1>& dst ) +{ + CV_Assert(src.cols == 1); + dst.resize(src.rows); + + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + Mat _dst(src.cols, src.rows, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + if( src.type() == _dst.type() ) + transpose(src, _dst); + else + Mat(src.t()).convertTo(_dst, _dst.type()); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } + else + { + Mat _dst(src.rows, src.cols, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + src.convertTo(_dst, _dst.type()); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } +} + +// Matx case +template +void cv2eigen( const Matx<_Tp, _rows, 1>& src, + Eigen::Matrix<_Tp, Eigen::Dynamic, 1>& dst ) +{ + dst.resize(_rows); + + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + Mat _dst(1, _rows, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + transpose(src, _dst); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } + else + { + Mat _dst(_rows, 1, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + src.copyTo(_dst); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } +} + + +template +void cv2eigen( const Mat& src, + Eigen::Matrix<_Tp, 1, Eigen::Dynamic>& dst ) +{ + CV_Assert(src.rows == 1); + dst.resize(src.cols); + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + Mat _dst(src.cols, src.rows, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + if( src.type() == _dst.type() ) + transpose(src, _dst); + else + Mat(src.t()).convertTo(_dst, _dst.type()); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } + else + { + Mat _dst(src.rows, src.cols, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + src.convertTo(_dst, _dst.type()); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } +} + +//Matx +template +void cv2eigen( const Matx<_Tp, 1, _cols>& src, + Eigen::Matrix<_Tp, 1, Eigen::Dynamic>& dst ) +{ + dst.resize(_cols); + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + Mat _dst(_cols, 1, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + transpose(src, _dst); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } + else + { + Mat _dst(1, _cols, DataType<_Tp>::type, + dst.data(), (size_t)(dst.stride()*sizeof(_Tp))); + Mat(src).copyTo(_dst); + CV_DbgAssert(_dst.data == (uchar*)dst.data()); + } +} + + +} + +#endif + +#endif + diff --git a/core/include/opencv2/core/gpumat.hpp b/core/include/opencv2/core/gpumat.hpp new file mode 100644 index 0000000..c0ae17b --- /dev/null +++ b/core/include/opencv2/core/gpumat.hpp @@ -0,0 +1,574 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other GpuMaterials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_GPUMAT_HPP__ +#define __OPENCV_GPUMAT_HPP__ + +#ifdef __cplusplus + +#include "opencv2/core/core.hpp" +#include "opencv2/core/cuda_devptrs.hpp" + +namespace cv { namespace gpu +{ + //////////////////////////////// Initialization & Info //////////////////////// + + //! This is the only function that do not throw exceptions if the library is compiled without Cuda. + CV_EXPORTS int getCudaEnabledDeviceCount(); + + //! Functions below throw cv::Expception if the library is compiled without Cuda. + + CV_EXPORTS void setDevice(int device); + CV_EXPORTS int getDevice(); + + //! Explicitly destroys and cleans up all resources associated with the current device in the current process. + //! Any subsequent API call to this device will reinitialize the device. + CV_EXPORTS void resetDevice(); + + enum FeatureSet + { + FEATURE_SET_COMPUTE_10 = 10, + FEATURE_SET_COMPUTE_11 = 11, + FEATURE_SET_COMPUTE_12 = 12, + FEATURE_SET_COMPUTE_13 = 13, + FEATURE_SET_COMPUTE_20 = 20, + FEATURE_SET_COMPUTE_21 = 21, + FEATURE_SET_COMPUTE_30 = 30, + GLOBAL_ATOMICS = FEATURE_SET_COMPUTE_11, + SHARED_ATOMICS = FEATURE_SET_COMPUTE_12, + NATIVE_DOUBLE = FEATURE_SET_COMPUTE_13, + WARP_SHUFFLE_FUNCTIONS = FEATURE_SET_COMPUTE_30 + }; + + // Gives information about what GPU archs this OpenCV GPU module was + // compiled for + class CV_EXPORTS TargetArchs + { + public: + static bool builtWith(FeatureSet feature_set); + static bool has(int major, int minor); + static bool hasPtx(int major, int minor); + static bool hasBin(int major, int minor); + static bool hasEqualOrLessPtx(int major, int minor); + static bool hasEqualOrGreater(int major, int minor); + static bool hasEqualOrGreaterPtx(int major, int minor); + static bool hasEqualOrGreaterBin(int major, int minor); + private: + TargetArchs(); + }; + + // Gives information about the given GPU + class CV_EXPORTS DeviceInfo + { + public: + // Creates DeviceInfo object for the current GPU + DeviceInfo() : device_id_(getDevice()) { query(); } + + // Creates DeviceInfo object for the given GPU + DeviceInfo(int device_id) : device_id_(device_id) { query(); } + + std::string name() const { return name_; } + + // Return compute capability versions + int majorVersion() const { return majorVersion_; } + int minorVersion() const { return minorVersion_; } + + int multiProcessorCount() const { return multi_processor_count_; } + + size_t sharedMemPerBlock() const { return sharedMemPerBlock_; } + + size_t freeMemory() const; + size_t totalMemory() const; + + // Checks whether device supports the given feature + bool supports(FeatureSet feature_set) const; + + // Checks whether the GPU module can be run on the given device + bool isCompatible() const; + + int deviceID() const { return device_id_; } + + private: + void query(); + void queryMemory(size_t& free_memory, size_t& total_memory) const; + + int device_id_; + + std::string name_; + int multi_processor_count_; + int majorVersion_; + int minorVersion_; + size_t sharedMemPerBlock_; + }; + + CV_EXPORTS void printCudaDeviceInfo(int device); + CV_EXPORTS void printShortCudaDeviceInfo(int device); + + //////////////////////////////// GpuMat /////////////////////////////// + + //! Smart pointer for GPU memory with reference counting. Its interface is mostly similar with cv::Mat. + class CV_EXPORTS GpuMat + { + public: + //! default constructor + GpuMat(); + + //! constructs GpuMatrix of the specified size and type (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.) + GpuMat(int rows, int cols, int type); + GpuMat(Size size, int type); + + //! constucts GpuMatrix and fills it with the specified value _s. + GpuMat(int rows, int cols, int type, Scalar s); + GpuMat(Size size, int type, Scalar s); + + //! copy constructor + GpuMat(const GpuMat& m); + + //! constructor for GpuMatrix headers pointing to user-allocated data + GpuMat(int rows, int cols, int type, void* data, size_t step = Mat::AUTO_STEP); + GpuMat(Size size, int type, void* data, size_t step = Mat::AUTO_STEP); + + //! creates a matrix header for a part of the bigger matrix + GpuMat(const GpuMat& m, Range rowRange, Range colRange); + GpuMat(const GpuMat& m, Rect roi); + + //! builds GpuMat from Mat. Perfom blocking upload to device. + explicit GpuMat(const Mat& m); + + //! destructor - calls release() + ~GpuMat(); + + //! assignment operators + GpuMat& operator = (const GpuMat& m); + + //! pefroms blocking upload data to GpuMat. + void upload(const Mat& m); + + //! downloads data from device to host memory. Blocking calls. + void download(Mat& m) const; + + //! returns a new GpuMatrix header for the specified row + GpuMat row(int y) const; + //! returns a new GpuMatrix header for the specified column + GpuMat col(int x) const; + //! ... for the specified row span + GpuMat rowRange(int startrow, int endrow) const; + GpuMat rowRange(Range r) const; + //! ... for the specified column span + GpuMat colRange(int startcol, int endcol) const; + GpuMat colRange(Range r) const; + + //! returns deep copy of the GpuMatrix, i.e. the data is copied + GpuMat clone() const; + //! copies the GpuMatrix content to "m". + // It calls m.create(this->size(), this->type()). + void copyTo(GpuMat& m) const; + //! copies those GpuMatrix elements to "m" that are marked with non-zero mask elements. + void copyTo(GpuMat& m, const GpuMat& mask) const; + //! converts GpuMatrix to another datatype with optional scalng. See cvConvertScale. + void convertTo(GpuMat& m, int rtype, double alpha = 1, double beta = 0) const; + + void assignTo(GpuMat& m, int type=-1) const; + + //! sets every GpuMatrix element to s + GpuMat& operator = (Scalar s); + //! sets some of the GpuMatrix elements to s, according to the mask + GpuMat& setTo(Scalar s, const GpuMat& mask = GpuMat()); + //! creates alternative GpuMatrix header for the same data, with different + // number of channels and/or different number of rows. see cvReshape. + GpuMat reshape(int cn, int rows = 0) const; + + //! allocates new GpuMatrix data unless the GpuMatrix already has specified size and type. + // previous data is unreferenced if needed. + void create(int rows, int cols, int type); + void create(Size size, int type); + //! decreases reference counter; + // deallocate the data when reference counter reaches 0. + void release(); + + //! swaps with other smart pointer + void swap(GpuMat& mat); + + //! locates GpuMatrix header within a parent GpuMatrix. See below + void locateROI(Size& wholeSize, Point& ofs) const; + //! moves/resizes the current GpuMatrix ROI inside the parent GpuMatrix. + GpuMat& adjustROI(int dtop, int dbottom, int dleft, int dright); + //! extracts a rectangular sub-GpuMatrix + // (this is a generalized form of row, rowRange etc.) + GpuMat operator()(Range rowRange, Range colRange) const; + GpuMat operator()(Rect roi) const; + + //! returns true iff the GpuMatrix data is continuous + // (i.e. when there are no gaps between successive rows). + // similar to CV_IS_GpuMat_CONT(cvGpuMat->type) + bool isContinuous() const; + //! returns element size in bytes, + // similar to CV_ELEM_SIZE(cvMat->type) + size_t elemSize() const; + //! returns the size of element channel in bytes. + size_t elemSize1() const; + //! returns element type, similar to CV_MAT_TYPE(cvMat->type) + int type() const; + //! returns element type, similar to CV_MAT_DEPTH(cvMat->type) + int depth() const; + //! returns element type, similar to CV_MAT_CN(cvMat->type) + int channels() const; + //! returns step/elemSize1() + size_t step1() const; + //! returns GpuMatrix size: + // width == number of columns, height == number of rows + Size size() const; + //! returns true if GpuMatrix data is NULL + bool empty() const; + + //! returns pointer to y-th row + uchar* ptr(int y = 0); + const uchar* ptr(int y = 0) const; + + //! template version of the above method + template _Tp* ptr(int y = 0); + template const _Tp* ptr(int y = 0) const; + + template operator PtrStepSz<_Tp>() const; + template operator PtrStep<_Tp>() const; + + // Deprecated function + __CV_GPU_DEPR_BEFORE__ template operator DevMem2D_<_Tp>() const __CV_GPU_DEPR_AFTER__; + #undef __CV_GPU_DEPR_BEFORE__ + #undef __CV_GPU_DEPR_AFTER__ + + /*! includes several bit-fields: + - the magic signature + - continuity flag + - depth + - number of channels + */ + int flags; + + //! the number of rows and columns + int rows, cols; + + //! a distance between successive rows in bytes; includes the gap if any + size_t step; + + //! pointer to the data + uchar* data; + + //! pointer to the reference counter; + // when GpuMatrix points to user-allocated data, the pointer is NULL + int* refcount; + + //! helper fields used in locateROI and adjustROI + uchar* datastart; + uchar* dataend; + }; + + //! Creates continuous GPU matrix + CV_EXPORTS void createContinuous(int rows, int cols, int type, GpuMat& m); + CV_EXPORTS GpuMat createContinuous(int rows, int cols, int type); + CV_EXPORTS void createContinuous(Size size, int type, GpuMat& m); + CV_EXPORTS GpuMat createContinuous(Size size, int type); + + //! Ensures that size of the given matrix is not less than (rows, cols) size + //! and matrix type is match specified one too + CV_EXPORTS void ensureSizeIsEnough(int rows, int cols, int type, GpuMat& m); + CV_EXPORTS void ensureSizeIsEnough(Size size, int type, GpuMat& m); + + CV_EXPORTS GpuMat allocMatFromBuf(int rows, int cols, int type, GpuMat &mat); + + //////////////////////////////////////////////////////////////////////// + // Error handling + + CV_EXPORTS void error(const char* error_string, const char* file, const int line, const char* func = ""); + + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + + inline GpuMat::GpuMat() + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) + { + } + + inline GpuMat::GpuMat(int rows_, int cols_, int type_) + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) + { + if (rows_ > 0 && cols_ > 0) + create(rows_, cols_, type_); + } + + inline GpuMat::GpuMat(Size size_, int type_) + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) + { + if (size_.height > 0 && size_.width > 0) + create(size_.height, size_.width, type_); + } + + inline GpuMat::GpuMat(int rows_, int cols_, int type_, Scalar s_) + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) + { + if (rows_ > 0 && cols_ > 0) + { + create(rows_, cols_, type_); + setTo(s_); + } + } + + inline GpuMat::GpuMat(Size size_, int type_, Scalar s_) + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) + { + if (size_.height > 0 && size_.width > 0) + { + create(size_.height, size_.width, type_); + setTo(s_); + } + } + + inline GpuMat::~GpuMat() + { + release(); + } + + inline GpuMat GpuMat::clone() const + { + GpuMat m; + copyTo(m); + return m; + } + + inline void GpuMat::assignTo(GpuMat& m, int _type) const + { + if (_type < 0) + m = *this; + else + convertTo(m, _type); + } + + inline size_t GpuMat::step1() const + { + return step / elemSize1(); + } + + inline bool GpuMat::empty() const + { + return data == 0; + } + + template inline _Tp* GpuMat::ptr(int y) + { + return (_Tp*)ptr(y); + } + + template inline const _Tp* GpuMat::ptr(int y) const + { + return (const _Tp*)ptr(y); + } + + inline void swap(GpuMat& a, GpuMat& b) + { + a.swap(b); + } + + inline GpuMat GpuMat::row(int y) const + { + return GpuMat(*this, Range(y, y+1), Range::all()); + } + + inline GpuMat GpuMat::col(int x) const + { + return GpuMat(*this, Range::all(), Range(x, x+1)); + } + + inline GpuMat GpuMat::rowRange(int startrow, int endrow) const + { + return GpuMat(*this, Range(startrow, endrow), Range::all()); + } + + inline GpuMat GpuMat::rowRange(Range r) const + { + return GpuMat(*this, r, Range::all()); + } + + inline GpuMat GpuMat::colRange(int startcol, int endcol) const + { + return GpuMat(*this, Range::all(), Range(startcol, endcol)); + } + + inline GpuMat GpuMat::colRange(Range r) const + { + return GpuMat(*this, Range::all(), r); + } + + inline void GpuMat::create(Size size_, int type_) + { + create(size_.height, size_.width, type_); + } + + inline GpuMat GpuMat::operator()(Range _rowRange, Range _colRange) const + { + return GpuMat(*this, _rowRange, _colRange); + } + + inline GpuMat GpuMat::operator()(Rect roi) const + { + return GpuMat(*this, roi); + } + + inline bool GpuMat::isContinuous() const + { + return (flags & Mat::CONTINUOUS_FLAG) != 0; + } + + inline size_t GpuMat::elemSize() const + { + return CV_ELEM_SIZE(flags); + } + + inline size_t GpuMat::elemSize1() const + { + return CV_ELEM_SIZE1(flags); + } + + inline int GpuMat::type() const + { + return CV_MAT_TYPE(flags); + } + + inline int GpuMat::depth() const + { + return CV_MAT_DEPTH(flags); + } + + inline int GpuMat::channels() const + { + return CV_MAT_CN(flags); + } + + inline Size GpuMat::size() const + { + return Size(cols, rows); + } + + inline uchar* GpuMat::ptr(int y) + { + CV_DbgAssert((unsigned)y < (unsigned)rows); + return data + step * y; + } + + inline const uchar* GpuMat::ptr(int y) const + { + CV_DbgAssert((unsigned)y < (unsigned)rows); + return data + step * y; + } + + inline GpuMat& GpuMat::operator = (Scalar s) + { + setTo(s); + return *this; + } + + template inline GpuMat::operator PtrStepSz() const + { + return PtrStepSz(rows, cols, (T*)data, step); + } + + template inline GpuMat::operator PtrStep() const + { + return PtrStep((T*)data, step); + } + + template inline GpuMat::operator DevMem2D_() const + { + return DevMem2D_(rows, cols, (T*)data, step); + } + + inline GpuMat createContinuous(int rows, int cols, int type) + { + GpuMat m; + createContinuous(rows, cols, type, m); + return m; + } + + inline void createContinuous(Size size, int type, GpuMat& m) + { + createContinuous(size.height, size.width, type, m); + } + + inline GpuMat createContinuous(Size size, int type) + { + GpuMat m; + createContinuous(size, type, m); + return m; + } + + inline void ensureSizeIsEnough(Size size, int type, GpuMat& m) + { + ensureSizeIsEnough(size.height, size.width, type, m); + } + + inline void createContinuous(int rows, int cols, int type, GpuMat& m) + { + int area = rows * cols; + if (!m.isContinuous() || m.type() != type || m.size().area() != area) + ensureSizeIsEnough(1, area, type, m); + m = m.reshape(0, rows); + } + + inline void ensureSizeIsEnough(int rows, int cols, int type, GpuMat& m) + { + if (m.type() == type && m.rows >= rows && m.cols >= cols) + m = m(Rect(0, 0, cols, rows)); + else + m.create(rows, cols, type); + } + + inline GpuMat allocMatFromBuf(int rows, int cols, int type, GpuMat &mat) + { + if (!mat.empty() && mat.type() == type && mat.rows >= rows && mat.cols >= cols) + return mat(Rect(0, 0, cols, rows)); + return mat = GpuMat(rows, cols, type); + } +}} + +#endif // __cplusplus + +#endif // __OPENCV_GPUMAT_HPP__ diff --git a/core/include/opencv2/core/internal.hpp b/core/include/opencv2/core/internal.hpp new file mode 100644 index 0000000..59e26ec --- /dev/null +++ b/core/include/opencv2/core/internal.hpp @@ -0,0 +1,801 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +/* The header is for internal use and it is likely to change. + It contains some macro definitions that are used in cxcore, cv, cvaux + and, probably, other libraries. If you need some of this functionality, + the safe way is to copy it into your code and rename the macros. +*/ +#ifndef __OPENCV_CORE_INTERNAL_HPP__ +#define __OPENCV_CORE_INTERNAL_HPP__ + +#include + +#if defined WIN32 || defined _WIN32 +# ifndef WIN32 +# define WIN32 +# endif +# ifndef _WIN32 +# define _WIN32 +# endif +#endif + +#if defined WIN32 || defined WINCE +# ifndef _WIN32_WINNT // This is needed for the declaration of TryEnterCriticalSection in winbase.h with Visual Studio 2005 (and older?) +# define _WIN32_WINNT 0x0400 // http://msdn.microsoft.com/en-us/library/ms686857(VS.85).aspx +# endif +# include +# undef small +# undef min +# undef max +#else +# include +#endif + +#ifdef __BORLANDC__ +# ifndef WIN32 +# define WIN32 +# endif +# ifndef _WIN32 +# define _WIN32 +# endif +# define CV_DLL +# undef _CV_ALWAYS_PROFILE_ +# define _CV_ALWAYS_NO_PROFILE_ +#endif + +#ifndef FALSE +# define FALSE 0 +#endif +#ifndef TRUE +# define TRUE 1 +#endif + +#define __BEGIN__ __CV_BEGIN__ +#define __END__ __CV_END__ +#define EXIT __CV_EXIT__ + +#ifdef HAVE_IPP +# include "ipp.h" + +CV_INLINE IppiSize ippiSize(int width, int height) +{ + IppiSize size = { width, height }; + return size; +} +#endif + +#if defined __SSE2__ || (defined _MSC_VER && _MSC_VER >= 1300) +# include "emmintrin.h" +# define CV_SSE 1 +# define CV_SSE2 1 +# if defined __SSE3__ || (defined _MSC_VER && _MSC_VER >= 1500) +# include "pmmintrin.h" +# define CV_SSE3 1 +# else +# define CV_SSE3 0 +# endif +# if defined __SSSE3__ +# include "tmmintrin.h" +# define CV_SSSE3 1 +# else +# define CV_SSSE3 0 +# endif +# if defined __SSE4_1__ || (defined _MSC_VER && _MSC_VER >= 1500) +# include +# define CV_SSE4_1 1 +# else +# define CV_SSE4_1 0 +# endif +# if defined __SSE4_2__ || (defined _MSC_VER && _MSC_VER >= 1500) +# include +# define CV_SSE4_2 1 +# else +# define CV_SSE4_2 0 +# endif +# if defined __AVX__ || (defined _MSC_FULL_VER && _MSC_FULL_VER >= 160040219) +# include +# define CV_AVX 1 +# else +# define CV_AVX 0 +# endif +# else +# define CV_SSE 0 +# define CV_SSE2 0 +# define CV_SSE3 0 +# define CV_SSSE3 0 +# define CV_SSE4_1 0 +# define CV_SSE4_2 0 +# define CV_AVX 0 +# endif + + +//#if defined __NEON__ + +#ifndef CV_NEON +#include +#define CV_NEON 1 +//#define ANUVIS_TEST +#endif +//#endif + + + +#if defined ANDROID && defined __ARM_NEON__ +# include "arm_neon.h" +# define CV_NEON 1 + +# define CPU_HAS_NEON_FEATURE (true) +//TODO: make real check using stuff from "cpu-features.h" +//((bool)android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) +#else +# define CV_NEON 0 +# define CPU_HAS_NEON_FEATURE (false) +#endif + + +#ifndef IPPI_CALL +# define IPPI_CALL(func) CV_Assert((func) >= 0) +#endif + +#ifdef HAVE_TBB +# include "tbb/tbb_stddef.h" +# if TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202 +# include "tbb/tbb.h" +# include "tbb/task.h" +# undef min +# undef max +# else +# undef HAVE_TBB +# endif +#endif + +#ifdef HAVE_EIGEN +# if defined __GNUC__ && defined __APPLE__ +# pragma GCC diagnostic ignored "-Wshadow" +# endif +# include +# include "opencv2/core/eigen.hpp" +#endif + +#ifdef __cplusplus + +namespace cv +{ +#ifdef HAVE_TBB + + typedef tbb::blocked_range BlockedRange; + + template static inline + void parallel_for( const BlockedRange& range, const Body& body ) + { + tbb::parallel_for(range, body); + } + + template static inline + void parallel_do( Iterator first, Iterator last, const Body& body ) + { + tbb::parallel_do(first, last, body); + } + + typedef tbb::split Split; + + template static inline + void parallel_reduce( const BlockedRange& range, Body& body ) + { + tbb::parallel_reduce(range, body); + } + + typedef tbb::concurrent_vector ConcurrentRectVector; + typedef tbb::concurrent_vector ConcurrentDoubleVector; +#else + class BlockedRange + { + public: + BlockedRange() : _begin(0), _end(0), _grainsize(0) {} + BlockedRange(int b, int e, int g=1) : _begin(b), _end(e), _grainsize(g) {} + int begin() const { return _begin; } + int end() const { return _end; } + int grainsize() const { return _grainsize; } + + protected: + int _begin, _end, _grainsize; + }; + + template static inline + void parallel_for( const BlockedRange& range, const Body& body ) + { + body(range); + } + typedef std::vector ConcurrentRectVector; + typedef std::vector ConcurrentDoubleVector; + + template static inline + void parallel_do( Iterator first, Iterator last, const Body& body ) + { + for( ; first != last; ++first ) + body(*first); + } + + class Split {}; + + template static inline + void parallel_reduce( const BlockedRange& range, Body& body ) + { + body(range); + } +#endif +} //namespace cv + +#define CV_INIT_ALGORITHM(classname, algname, memberinit) \ + static Algorithm* create##classname() \ + { \ + return new classname; \ + } \ + \ + static AlgorithmInfo& classname##_info() \ + { \ + static AlgorithmInfo classname##_info_var(algname, create##classname); \ + return classname##_info_var; \ + } \ + \ + static AlgorithmInfo& classname##_info_auto = classname##_info(); \ + \ + AlgorithmInfo* classname::info() const \ + { \ + static volatile bool initialized = false; \ + \ + if( !initialized ) \ + { \ + initialized = true; \ + classname obj; \ + memberinit; \ + } \ + return &classname##_info(); \ + } + +#endif //__cplusplus + +/* maximal size of vector to run matrix operations on it inline (i.e. w/o ipp calls) */ +#define CV_MAX_INLINE_MAT_OP_SIZE 10 + +/* maximal linear size of matrix to allocate it on stack. */ +#define CV_MAX_LOCAL_MAT_SIZE 32 + +/* maximal size of local memory storage */ +#define CV_MAX_LOCAL_SIZE \ + (CV_MAX_LOCAL_MAT_SIZE*CV_MAX_LOCAL_MAT_SIZE*(int)sizeof(double)) + +/* default image row align (in bytes) */ +#define CV_DEFAULT_IMAGE_ROW_ALIGN 4 + +/* matrices are continuous by default */ +#define CV_DEFAULT_MAT_ROW_ALIGN 1 + +/* maximum size of dynamic memory buffer. + cvAlloc reports an error if a larger block is requested. */ +#define CV_MAX_ALLOC_SIZE (((size_t)1 << (sizeof(size_t)*8-2))) + +/* the alignment of all the allocated buffers */ +#define CV_MALLOC_ALIGN 16 + +/* default alignment for dynamic data strucutures, resided in storages. */ +#define CV_STRUCT_ALIGN ((int)sizeof(double)) + +/* default storage block size */ +#define CV_STORAGE_BLOCK_SIZE ((1<<16) - 128) + +/* default memory block for sparse array elements */ +#define CV_SPARSE_MAT_BLOCK (1<<12) + +/* initial hash table size */ +#define CV_SPARSE_HASH_SIZE0 (1<<10) + +/* maximal average node_count/hash_size ratio beyond which hash table is resized */ +#define CV_SPARSE_HASH_RATIO 3 + +/* max length of strings */ +#define CV_MAX_STRLEN 1024 + +#if 0 /*def CV_CHECK_FOR_NANS*/ +# define CV_CHECK_NANS( arr ) cvCheckArray((arr)) +#else +# define CV_CHECK_NANS( arr ) +#endif + +/****************************************************************************************\ +* Common declarations * +\****************************************************************************************/ + +/* get alloca declaration */ +#ifdef __GNUC__ +# undef alloca +# define alloca __builtin_alloca +# define CV_HAVE_ALLOCA 1 +#elif defined WIN32 || defined _WIN32 || \ + defined WINCE || defined _MSC_VER || defined __BORLANDC__ +# include +# define CV_HAVE_ALLOCA 1 +#elif defined HAVE_ALLOCA_H +# include +# define CV_HAVE_ALLOCA 1 +#elif defined HAVE_ALLOCA +# include +# define CV_HAVE_ALLOCA 1 +#else +# undef CV_HAVE_ALLOCA +#endif + +#ifdef __GNUC__ +# define CV_DECL_ALIGNED(x) __attribute__ ((aligned (x))) +#elif defined _MSC_VER +# define CV_DECL_ALIGNED(x) __declspec(align(x)) +#else +# define CV_DECL_ALIGNED(x) +#endif + +#if CV_HAVE_ALLOCA +/* ! DO NOT make it an inline function */ +# define cvStackAlloc(size) cvAlignPtr( alloca((size) + CV_MALLOC_ALIGN), CV_MALLOC_ALIGN ) +#endif + +#ifndef CV_IMPL +# define CV_IMPL CV_EXTERN_C +#endif + +#define CV_DBG_BREAK() { volatile int* crashMe = 0; *crashMe = 0; } + +/* default step, set in case of continuous data + to work around checks for valid step in some ipp functions */ +#define CV_STUB_STEP (1 << 30) + +#define CV_SIZEOF_FLOAT ((int)sizeof(float)) +#define CV_SIZEOF_SHORT ((int)sizeof(short)) + +#define CV_ORIGIN_TL 0 +#define CV_ORIGIN_BL 1 + +/* IEEE754 constants and macros */ +#define CV_POS_INF 0x7f800000 +#define CV_NEG_INF 0x807fffff /* CV_TOGGLE_FLT(0xff800000) */ +#define CV_1F 0x3f800000 +#define CV_TOGGLE_FLT(x) ((x)^((int)(x) < 0 ? 0x7fffffff : 0)) +#define CV_TOGGLE_DBL(x) \ + ((x)^((int64)(x) < 0 ? CV_BIG_INT(0x7fffffffffffffff) : 0)) + +#define CV_NOP(a) (a) +#define CV_ADD(a, b) ((a) + (b)) +#define CV_SUB(a, b) ((a) - (b)) +#define CV_MUL(a, b) ((a) * (b)) +#define CV_AND(a, b) ((a) & (b)) +#define CV_OR(a, b) ((a) | (b)) +#define CV_XOR(a, b) ((a) ^ (b)) +#define CV_ANDN(a, b) (~(a) & (b)) +#define CV_ORN(a, b) (~(a) | (b)) +#define CV_SQR(a) ((a) * (a)) + +#define CV_LT(a, b) ((a) < (b)) +#define CV_LE(a, b) ((a) <= (b)) +#define CV_EQ(a, b) ((a) == (b)) +#define CV_NE(a, b) ((a) != (b)) +#define CV_GT(a, b) ((a) > (b)) +#define CV_GE(a, b) ((a) >= (b)) + +#define CV_NONZERO(a) ((a) != 0) +#define CV_NONZERO_FLT(a) (((a)+(a)) != 0) + +/* general-purpose saturation macros */ +#define CV_CAST_8U(t) (uchar)(!((t) & ~255) ? (t) : (t) > 0 ? 255 : 0) +#define CV_CAST_8S(t) (schar)(!(((t)+128) & ~255) ? (t) : (t) > 0 ? 127 : -128) +#define CV_CAST_16U(t) (ushort)(!((t) & ~65535) ? (t) : (t) > 0 ? 65535 : 0) +#define CV_CAST_16S(t) (short)(!(((t)+32768) & ~65535) ? (t) : (t) > 0 ? 32767 : -32768) +#define CV_CAST_32S(t) (int)(t) +#define CV_CAST_64S(t) (int64)(t) +#define CV_CAST_32F(t) (float)(t) +#define CV_CAST_64F(t) (double)(t) + +#define CV_PASTE2(a,b) a##b +#define CV_PASTE(a,b) CV_PASTE2(a,b) + +#define CV_EMPTY +#define CV_MAKE_STR(a) #a + +#define CV_ZERO_OBJ(x) memset((x), 0, sizeof(*(x))) + +#define CV_DIM(static_array) ((int)(sizeof(static_array)/sizeof((static_array)[0]))) + +#define cvUnsupportedFormat "Unsupported format" + +CV_INLINE void* cvAlignPtr( const void* ptr, int align CV_DEFAULT(32) ) +{ + assert( (align & (align-1)) == 0 ); + return (void*)( ((size_t)ptr + align - 1) & ~(size_t)(align-1) ); +} + +CV_INLINE int cvAlign( int size, int align ) +{ + assert( (align & (align-1)) == 0 && size < INT_MAX ); + return (size + align - 1) & -align; +} + +CV_INLINE CvSize cvGetMatSize( const CvMat* mat ) +{ + CvSize size; + size.width = mat->cols; + size.height = mat->rows; + return size; +} + +#define CV_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n)) +#define CV_FLT_TO_FIX(x,n) cvRound((x)*(1<<(n))) + +/****************************************************************************************\ + + Generic implementation of QuickSort algorithm. + ---------------------------------------------- + Using this macro user can declare customized sort function that can be much faster + than built-in qsort function because of lower overhead on elements + comparison and exchange. The macro takes less_than (or LT) argument - a macro or function + that takes 2 arguments returns non-zero if the first argument should be before the second + one in the sorted sequence and zero otherwise. + + Example: + + Suppose that the task is to sort points by ascending of y coordinates and if + y's are equal x's should ascend. + + The code is: + ------------------------------------------------------------------------------ + #define cmp_pts( pt1, pt2 ) \ + ((pt1).y < (pt2).y || ((pt1).y < (pt2).y && (pt1).x < (pt2).x)) + + [static] CV_IMPLEMENT_QSORT( icvSortPoints, CvPoint, cmp_pts ) + ------------------------------------------------------------------------------ + + After that the function "void icvSortPoints( CvPoint* array, size_t total, int aux );" + is available to user. + + aux is an additional parameter, which can be used when comparing elements. + The current implementation was derived from *BSD system qsort(): + + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + +\****************************************************************************************/ + +#define CV_IMPLEMENT_QSORT_EX( func_name, T, LT, user_data_type ) \ +void func_name( T *array, size_t total, user_data_type aux ) \ +{ \ + int isort_thresh = 7; \ + T t; \ + int sp = 0; \ + \ + struct \ + { \ + T *lb; \ + T *ub; \ + } \ + stack[48]; \ + \ + aux = aux; \ + \ + if( total <= 1 ) \ + return; \ + \ + stack[0].lb = array; \ + stack[0].ub = array + (total - 1); \ + \ + while( sp >= 0 ) \ + { \ + T* left = stack[sp].lb; \ + T* right = stack[sp--].ub; \ + \ + for(;;) \ + { \ + int i, n = (int)(right - left) + 1, m; \ + T* ptr; \ + T* ptr2; \ + \ + if( n <= isort_thresh ) \ + { \ + insert_sort: \ + for( ptr = left + 1; ptr <= right; ptr++ ) \ + { \ + for( ptr2 = ptr; ptr2 > left && LT(ptr2[0],ptr2[-1]); ptr2--) \ + CV_SWAP( ptr2[0], ptr2[-1], t ); \ + } \ + break; \ + } \ + else \ + { \ + T* left0; \ + T* left1; \ + T* right0; \ + T* right1; \ + T* pivot; \ + T* a; \ + T* b; \ + T* c; \ + int swap_cnt = 0; \ + \ + left0 = left; \ + right0 = right; \ + pivot = left + (n/2); \ + \ + if( n > 40 ) \ + { \ + int d = n / 8; \ + a = left, b = left + d, c = left + 2*d; \ + left = LT(*a, *b) ? (LT(*b, *c) ? b : (LT(*a, *c) ? c : a)) \ + : (LT(*c, *b) ? b : (LT(*a, *c) ? a : c)); \ + \ + a = pivot - d, b = pivot, c = pivot + d; \ + pivot = LT(*a, *b) ? (LT(*b, *c) ? b : (LT(*a, *c) ? c : a)) \ + : (LT(*c, *b) ? b : (LT(*a, *c) ? a : c)); \ + \ + a = right - 2*d, b = right - d, c = right; \ + right = LT(*a, *b) ? (LT(*b, *c) ? b : (LT(*a, *c) ? c : a)) \ + : (LT(*c, *b) ? b : (LT(*a, *c) ? a : c)); \ + } \ + \ + a = left, b = pivot, c = right; \ + pivot = LT(*a, *b) ? (LT(*b, *c) ? b : (LT(*a, *c) ? c : a)) \ + : (LT(*c, *b) ? b : (LT(*a, *c) ? a : c)); \ + if( pivot != left0 ) \ + { \ + CV_SWAP( *pivot, *left0, t ); \ + pivot = left0; \ + } \ + left = left1 = left0 + 1; \ + right = right1 = right0; \ + \ + for(;;) \ + { \ + while( left <= right && !LT(*pivot, *left) ) \ + { \ + if( !LT(*left, *pivot) ) \ + { \ + if( left > left1 ) \ + CV_SWAP( *left1, *left, t ); \ + swap_cnt = 1; \ + left1++; \ + } \ + left++; \ + } \ + \ + while( left <= right && !LT(*right, *pivot) ) \ + { \ + if( !LT(*pivot, *right) ) \ + { \ + if( right < right1 ) \ + CV_SWAP( *right1, *right, t ); \ + swap_cnt = 1; \ + right1--; \ + } \ + right--; \ + } \ + \ + if( left > right ) \ + break; \ + CV_SWAP( *left, *right, t ); \ + swap_cnt = 1; \ + left++; \ + right--; \ + } \ + \ + if( swap_cnt == 0 ) \ + { \ + left = left0, right = right0; \ + goto insert_sort; \ + } \ + \ + n = MIN( (int)(left1 - left0), (int)(left - left1) ); \ + for( i = 0; i < n; i++ ) \ + CV_SWAP( left0[i], left[i-n], t ); \ + \ + n = MIN( (int)(right0 - right1), (int)(right1 - right) ); \ + for( i = 0; i < n; i++ ) \ + CV_SWAP( left[i], right0[i-n+1], t ); \ + n = (int)(left - left1); \ + m = (int)(right1 - right); \ + if( n > 1 ) \ + { \ + if( m > 1 ) \ + { \ + if( n > m ) \ + { \ + stack[++sp].lb = left0; \ + stack[sp].ub = left0 + n - 1; \ + left = right0 - m + 1, right = right0; \ + } \ + else \ + { \ + stack[++sp].lb = right0 - m + 1; \ + stack[sp].ub = right0; \ + left = left0, right = left0 + n - 1; \ + } \ + } \ + else \ + left = left0, right = left0 + n - 1; \ + } \ + else if( m > 1 ) \ + left = right0 - m + 1, right = right0; \ + else \ + break; \ + } \ + } \ + } \ +} + +#define CV_IMPLEMENT_QSORT( func_name, T, cmp ) \ + CV_IMPLEMENT_QSORT_EX( func_name, T, cmp, int ) + +/****************************************************************************************\ +* Structures and macros for integration with IPP * +\****************************************************************************************/ + +/* IPP-compatible return codes */ +typedef enum CvStatus +{ + CV_BADMEMBLOCK_ERR = -113, + CV_INPLACE_NOT_SUPPORTED_ERR= -112, + CV_UNMATCHED_ROI_ERR = -111, + CV_NOTFOUND_ERR = -110, + CV_BADCONVERGENCE_ERR = -109, + + CV_BADDEPTH_ERR = -107, + CV_BADROI_ERR = -106, + CV_BADHEADER_ERR = -105, + CV_UNMATCHED_FORMATS_ERR = -104, + CV_UNSUPPORTED_COI_ERR = -103, + CV_UNSUPPORTED_CHANNELS_ERR = -102, + CV_UNSUPPORTED_DEPTH_ERR = -101, + CV_UNSUPPORTED_FORMAT_ERR = -100, + + CV_BADARG_ERR = -49, //ipp comp + CV_NOTDEFINED_ERR = -48, //ipp comp + + CV_BADCHANNELS_ERR = -47, //ipp comp + CV_BADRANGE_ERR = -44, //ipp comp + CV_BADSTEP_ERR = -29, //ipp comp + + CV_BADFLAG_ERR = -12, + CV_DIV_BY_ZERO_ERR = -11, //ipp comp + CV_BADCOEF_ERR = -10, + + CV_BADFACTOR_ERR = -7, + CV_BADPOINT_ERR = -6, + CV_BADSCALE_ERR = -4, + CV_OUTOFMEM_ERR = -3, + CV_NULLPTR_ERR = -2, + CV_BADSIZE_ERR = -1, + CV_NO_ERR = 0, + CV_OK = CV_NO_ERR +} +CvStatus; + +#define CV_NOTHROW throw() + +typedef struct CvFuncTable +{ + void* fn_2d[CV_DEPTH_MAX]; +} +CvFuncTable; + +typedef struct CvBigFuncTable +{ + void* fn_2d[CV_DEPTH_MAX*4]; +} CvBigFuncTable; + +#define CV_INIT_FUNC_TAB( tab, FUNCNAME, FLAG ) \ + (tab).fn_2d[CV_8U] = (void*)FUNCNAME##_8u##FLAG; \ + (tab).fn_2d[CV_8S] = 0; \ + (tab).fn_2d[CV_16U] = (void*)FUNCNAME##_16u##FLAG; \ + (tab).fn_2d[CV_16S] = (void*)FUNCNAME##_16s##FLAG; \ + (tab).fn_2d[CV_32S] = (void*)FUNCNAME##_32s##FLAG; \ + (tab).fn_2d[CV_32F] = (void*)FUNCNAME##_32f##FLAG; \ + (tab).fn_2d[CV_64F] = (void*)FUNCNAME##_64f##FLAG + +#ifdef __cplusplus +//! OpenGL extension table +class CV_EXPORTS CvOpenGlFuncTab +{ +public: + virtual ~CvOpenGlFuncTab(); + + virtual void genBuffers(int n, unsigned int* buffers) const = 0; + virtual void deleteBuffers(int n, const unsigned int* buffers) const = 0; + + virtual void bufferData(unsigned int target, ptrdiff_t size, const void* data, unsigned int usage) const = 0; + virtual void bufferSubData(unsigned int target, ptrdiff_t offset, ptrdiff_t size, const void* data) const = 0; + + virtual void bindBuffer(unsigned int target, unsigned int buffer) const = 0; + + virtual void* mapBuffer(unsigned int target, unsigned int access) const = 0; + virtual void unmapBuffer(unsigned int target) const = 0; + + virtual void generateBitmapFont(const std::string& family, int height, int weight, bool italic, bool underline, int start, int count, int base) const = 0; + + virtual bool isGlContextInitialized() const = 0; +}; + +CV_EXPORTS void icvSetOpenGlFuncTab(const CvOpenGlFuncTab* tab); + +CV_EXPORTS bool icvCheckGlError(const char* file, const int line, const char* func = ""); + +#if defined(__GNUC__) + #define CV_CheckGlError() CV_DbgAssert( (::icvCheckGlError(__FILE__, __LINE__, __func__)) ) +#else + #define CV_CheckGlError() CV_DbgAssert( (::icvCheckGlError(__FILE__, __LINE__)) ) +#endif + +#endif //__cplusplus + +#endif // __OPENCV_CORE_INTERNAL_HPP__ diff --git a/core/include/opencv2/core/mat.hpp b/core/include/opencv2/core/mat.hpp new file mode 100644 index 0000000..92301cf --- /dev/null +++ b/core/include/opencv2/core/mat.hpp @@ -0,0 +1,2605 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_CORE_MATRIX_OPERATIONS_HPP__ +#define __OPENCV_CORE_MATRIX_OPERATIONS_HPP__ + +#ifndef SKIP_INCLUDES +#include +#include +#endif // SKIP_INCLUDES + +#ifdef __cplusplus + +namespace cv +{ + +//////////////////////////////// Mat //////////////////////////////// + +inline void Mat::initEmpty() +{ + flags = MAGIC_VAL; + dims = rows = cols = 0; + data = datastart = dataend = datalimit = 0; + refcount = 0; + allocator = 0; +} + +inline Mat::Mat() : size(&rows) +{ + initEmpty(); +} + +inline Mat::Mat(int _rows, int _cols, int _type) : size(&rows) +{ + initEmpty(); + create(_rows, _cols, _type); +} + +inline Mat::Mat(int _rows, int _cols, int _type, const Scalar& _s) : size(&rows) +{ + initEmpty(); + create(_rows, _cols, _type); + *this = _s; +} + +inline Mat::Mat(Size _sz, int _type) : size(&rows) +{ + initEmpty(); + create( _sz.height, _sz.width, _type ); +} + +inline Mat::Mat(Size _sz, int _type, const Scalar& _s) : size(&rows) +{ + initEmpty(); + create(_sz.height, _sz.width, _type); + *this = _s; +} + +inline Mat::Mat(int _dims, const int* _sz, int _type) : size(&rows) +{ + initEmpty(); + create(_dims, _sz, _type); +} + +inline Mat::Mat(int _dims, const int* _sz, int _type, const Scalar& _s) : size(&rows) +{ + initEmpty(); + create(_dims, _sz, _type); + *this = _s; +} + +inline Mat::Mat(const Mat& m) + : flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), data(m.data), + refcount(m.refcount), datastart(m.datastart), dataend(m.dataend), + datalimit(m.datalimit), allocator(m.allocator), size(&rows) +{ + if( refcount ) + CV_XADD(refcount, 1); + if( m.dims <= 2 ) + { + step[0] = m.step[0]; step[1] = m.step[1]; + } + else + { + dims = 0; + copySize(m); + } +} + +inline Mat::Mat(int _rows, int _cols, int _type, void* _data, size_t _step) + : flags(MAGIC_VAL + (_type & TYPE_MASK)), dims(2), rows(_rows), cols(_cols), + data((uchar*)_data), refcount(0), datastart((uchar*)_data), dataend(0), + datalimit(0), allocator(0), size(&rows) +{ + size_t esz = CV_ELEM_SIZE(_type), minstep = cols*esz; + if( _step == AUTO_STEP ) + { + _step = minstep; + flags |= CONTINUOUS_FLAG; + } + else + { + if( rows == 1 ) _step = minstep; + CV_DbgAssert( _step >= minstep ); + flags |= _step == minstep ? CONTINUOUS_FLAG : 0; + } + step[0] = _step; step[1] = esz; + datalimit = datastart + _step*rows; + dataend = datalimit - _step + minstep; +} + +inline Mat::Mat(Size _sz, int _type, void* _data, size_t _step) + : flags(MAGIC_VAL + (_type & TYPE_MASK)), dims(2), rows(_sz.height), cols(_sz.width), + data((uchar*)_data), refcount(0), datastart((uchar*)_data), dataend(0), + datalimit(0), allocator(0), size(&rows) +{ + size_t esz = CV_ELEM_SIZE(_type), minstep = cols*esz; + if( _step == AUTO_STEP ) + { + _step = minstep; + flags |= CONTINUOUS_FLAG; + } + else + { + if( rows == 1 ) _step = minstep; + CV_DbgAssert( _step >= minstep ); + flags |= _step == minstep ? CONTINUOUS_FLAG : 0; + } + step[0] = _step; step[1] = esz; + datalimit = datastart + _step*rows; + dataend = datalimit - _step + minstep; +} + + +template inline Mat::Mat(const vector<_Tp>& vec, bool copyData) + : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), + dims(2), rows((int)vec.size()), cols(1), data(0), refcount(0), + datastart(0), dataend(0), allocator(0), size(&rows) +{ + if(vec.empty()) + return; + if( !copyData ) + { + step[0] = step[1] = sizeof(_Tp); + data = datastart = (uchar*)&vec[0]; + datalimit = dataend = datastart + rows*step[0]; + } + else + Mat((int)vec.size(), 1, DataType<_Tp>::type, (uchar*)&vec[0]).copyTo(*this); +} + + +template inline Mat::Mat(const Vec<_Tp, n>& vec, bool copyData) + : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), + dims(2), rows(n), cols(1), data(0), refcount(0), + datastart(0), dataend(0), allocator(0), size(&rows) +{ + if( !copyData ) + { + step[0] = step[1] = sizeof(_Tp); + data = datastart = (uchar*)vec.val; + datalimit = dataend = datastart + rows*step[0]; + } + else + Mat(n, 1, DataType<_Tp>::type, (void*)vec.val).copyTo(*this); +} + + +template inline Mat::Mat(const Matx<_Tp,m,n>& M, bool copyData) + : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), + dims(2), rows(m), cols(n), data(0), refcount(0), + datastart(0), dataend(0), allocator(0), size(&rows) +{ + if( !copyData ) + { + step[0] = cols*sizeof(_Tp); + step[1] = sizeof(_Tp); + data = datastart = (uchar*)M.val; + datalimit = dataend = datastart + rows*step[0]; + } + else + Mat(m, n, DataType<_Tp>::type, (uchar*)M.val).copyTo(*this); +} + + +template inline Mat::Mat(const Point_<_Tp>& pt, bool copyData) + : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), + dims(2), rows(2), cols(1), data(0), refcount(0), + datastart(0), dataend(0), allocator(0), size(&rows) +{ + if( !copyData ) + { + step[0] = step[1] = sizeof(_Tp); + data = datastart = (uchar*)&pt.x; + datalimit = dataend = datastart + rows*step[0]; + } + else + { + create(2, 1, DataType<_Tp>::type); + ((_Tp*)data)[0] = pt.x; + ((_Tp*)data)[1] = pt.y; + } +} + + +template inline Mat::Mat(const Point3_<_Tp>& pt, bool copyData) + : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), + dims(2), rows(3), cols(1), data(0), refcount(0), + datastart(0), dataend(0), allocator(0), size(&rows) +{ + if( !copyData ) + { + step[0] = step[1] = sizeof(_Tp); + data = datastart = (uchar*)&pt.x; + datalimit = dataend = datastart + rows*step[0]; + } + else + { + create(3, 1, DataType<_Tp>::type); + ((_Tp*)data)[0] = pt.x; + ((_Tp*)data)[1] = pt.y; + ((_Tp*)data)[2] = pt.z; + } +} + + +template inline Mat::Mat(const MatCommaInitializer_<_Tp>& commaInitializer) + : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), + dims(0), rows(0), cols(0), data(0), refcount(0), + datastart(0), dataend(0), allocator(0), size(&rows) +{ + *this = *commaInitializer; +} + +inline Mat::~Mat() +{ + release(); + if( step.p != step.buf ) + fastFree(step.p); +} + +inline Mat& Mat::operator = (const Mat& m) +{ + if( this != &m ) + { + if( m.refcount ) + CV_XADD(m.refcount, 1); + release(); + flags = m.flags; + if( dims <= 2 && m.dims <= 2 ) + { + dims = m.dims; + rows = m.rows; + cols = m.cols; + step[0] = m.step[0]; + step[1] = m.step[1]; + } + else + copySize(m); + data = m.data; + datastart = m.datastart; + dataend = m.dataend; + datalimit = m.datalimit; + refcount = m.refcount; + allocator = m.allocator; + } + return *this; +} + +inline Mat Mat::row(int y) const { return Mat(*this, Range(y, y+1), Range::all()); } +inline Mat Mat::col(int x) const { return Mat(*this, Range::all(), Range(x, x+1)); } +inline Mat Mat::rowRange(int startrow, int endrow) const + { return Mat(*this, Range(startrow, endrow), Range::all()); } +inline Mat Mat::rowRange(const Range& r) const + { return Mat(*this, r, Range::all()); } +inline Mat Mat::colRange(int startcol, int endcol) const + { return Mat(*this, Range::all(), Range(startcol, endcol)); } +inline Mat Mat::colRange(const Range& r) const + { return Mat(*this, Range::all(), r); } + +inline Mat Mat::diag(const Mat& d) +{ + CV_Assert( d.cols == 1 || d.rows == 1 ); + int len = d.rows + d.cols - 1; + Mat m(len, len, d.type(), Scalar(0)), md = m.diag(); + if( d.cols == 1 ) + d.copyTo(md); + else + transpose(d, md); + return m; +} + +inline Mat Mat::clone() const +{ + Mat m; + copyTo(m); + return m; +} + +inline void Mat::assignTo( Mat& m, int _type ) const +{ + if( _type < 0 ) + m = *this; + else + convertTo(m, _type); +} + +inline void Mat::create(int _rows, int _cols, int _type) +{ + _type &= TYPE_MASK; + if( dims <= 2 && rows == _rows && cols == _cols && type() == _type && data ) + return; + int sz[] = {_rows, _cols}; + create(2, sz, _type); +} + +inline void Mat::create(Size _sz, int _type) +{ + create(_sz.height, _sz.width, _type); +} + +inline void Mat::addref() +{ if( refcount ) CV_XADD(refcount, 1); } + +inline void Mat::release() +{ + if( refcount && CV_XADD(refcount, -1) == 1 ) + deallocate(); + data = datastart = dataend = datalimit = 0; + size.p[0] = 0; + refcount = 0; +} + +inline Mat Mat::operator()( Range _rowRange, Range _colRange ) const +{ + return Mat(*this, _rowRange, _colRange); +} + +inline Mat Mat::operator()( const Rect& roi ) const +{ return Mat(*this, roi); } + +inline Mat Mat::operator()(const Range* ranges) const +{ + return Mat(*this, ranges); +} + +inline Mat::operator CvMat() const +{ + CV_DbgAssert(dims <= 2); + CvMat m = cvMat(rows, dims == 1 ? 1 : cols, type(), data); + m.step = (int)step[0]; + m.type = (m.type & ~CONTINUOUS_FLAG) | (flags & CONTINUOUS_FLAG); + return m; +} + +inline bool Mat::isContinuous() const { return (flags & CONTINUOUS_FLAG) != 0; } +inline bool Mat::isSubmatrix() const { return (flags & SUBMATRIX_FLAG) != 0; } +inline size_t Mat::elemSize() const { return dims > 0 ? step.p[dims-1] : 0; } +inline size_t Mat::elemSize1() const { return CV_ELEM_SIZE1(flags); } +inline int Mat::type() const { return CV_MAT_TYPE(flags); } +inline int Mat::depth() const { return CV_MAT_DEPTH(flags); } +inline int Mat::channels() const { return CV_MAT_CN(flags); } +inline size_t Mat::step1(int i) const { return step.p[i]/elemSize1(); } +inline bool Mat::empty() const { return data == 0 || total() == 0; } +inline size_t Mat::total() const +{ + if( dims <= 2 ) + return (size_t)rows*cols; + size_t p = 1; + for( int i = 0; i < dims; i++ ) + p *= size[i]; + return p; +} + +inline uchar* Mat::ptr(int y) +{ + CV_DbgAssert( y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0]) ); + return data + step.p[0]*y; +} + +inline const uchar* Mat::ptr(int y) const +{ + CV_DbgAssert( y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0]) ); + return data + step.p[0]*y; +} + +template inline _Tp* Mat::ptr(int y) +{ + CV_DbgAssert( y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0]) ); + return (_Tp*)(data + step.p[0]*y); +} + +template inline const _Tp* Mat::ptr(int y) const +{ + CV_DbgAssert( y == 0 || (data && dims >= 1 && data && (unsigned)y < (unsigned)size.p[0]) ); + return (const _Tp*)(data + step.p[0]*y); +} + + +inline uchar* Mat::ptr(int i0, int i1) +{ + CV_DbgAssert( dims >= 2 && data && + (unsigned)i0 < (unsigned)size.p[0] && + (unsigned)i1 < (unsigned)size.p[1] ); + return data + i0*step.p[0] + i1*step.p[1]; +} + +inline const uchar* Mat::ptr(int i0, int i1) const +{ + CV_DbgAssert( dims >= 2 && data && + (unsigned)i0 < (unsigned)size.p[0] && + (unsigned)i1 < (unsigned)size.p[1] ); + return data + i0*step.p[0] + i1*step.p[1]; +} + +template inline _Tp* Mat::ptr(int i0, int i1) +{ + CV_DbgAssert( dims >= 2 && data && + (unsigned)i0 < (unsigned)size.p[0] && + (unsigned)i1 < (unsigned)size.p[1] ); + return (_Tp*)(data + i0*step.p[0] + i1*step.p[1]); +} + +template inline const _Tp* Mat::ptr(int i0, int i1) const +{ + CV_DbgAssert( dims >= 2 && data && + (unsigned)i0 < (unsigned)size.p[0] && + (unsigned)i1 < (unsigned)size.p[1] ); + return (const _Tp*)(data + i0*step.p[0] + i1*step.p[1]); +} + +inline uchar* Mat::ptr(int i0, int i1, int i2) +{ + CV_DbgAssert( dims >= 3 && data && + (unsigned)i0 < (unsigned)size.p[0] && + (unsigned)i1 < (unsigned)size.p[1] && + (unsigned)i2 < (unsigned)size.p[2] ); + return data + i0*step.p[0] + i1*step.p[1] + i2*step.p[2]; +} + +inline const uchar* Mat::ptr(int i0, int i1, int i2) const +{ + CV_DbgAssert( dims >= 3 && data && + (unsigned)i0 < (unsigned)size.p[0] && + (unsigned)i1 < (unsigned)size.p[1] && + (unsigned)i2 < (unsigned)size.p[2] ); + return data + i0*step.p[0] + i1*step.p[1] + i2*step.p[2]; +} + +template inline _Tp* Mat::ptr(int i0, int i1, int i2) +{ + CV_DbgAssert( dims >= 3 && data && + (unsigned)i0 < (unsigned)size.p[0] && + (unsigned)i1 < (unsigned)size.p[1] && + (unsigned)i2 < (unsigned)size.p[2] ); + return (_Tp*)(data + i0*step.p[0] + i1*step.p[1] + i2*step.p[2]); +} + +template inline const _Tp* Mat::ptr(int i0, int i1, int i2) const +{ + CV_DbgAssert( dims >= 3 && data && + (unsigned)i0 < (unsigned)size.p[0] && + (unsigned)i1 < (unsigned)size.p[1] && + (unsigned)i2 < (unsigned)size.p[2] ); + return (const _Tp*)(data + i0*step.p[0] + i1*step.p[1] + i2*step.p[2]); +} + +inline uchar* Mat::ptr(const int* idx) +{ + int i, d = dims; + uchar* p = data; + CV_DbgAssert( d >= 1 && p ); + for( i = 0; i < d; i++ ) + { + CV_DbgAssert( (unsigned)idx[i] < (unsigned)size.p[i] ); + p += idx[i]*step.p[i]; + } + return p; +} + +inline const uchar* Mat::ptr(const int* idx) const +{ + int i, d = dims; + uchar* p = data; + CV_DbgAssert( d >= 1 && p ); + for( i = 0; i < d; i++ ) + { + CV_DbgAssert( (unsigned)idx[i] < (unsigned)size.p[i] ); + p += idx[i]*step.p[i]; + } + return p; +} + +template inline _Tp& Mat::at(int i0, int i1) +{ + CV_DbgAssert( dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] && + (unsigned)(i1*DataType<_Tp>::channels) < (unsigned)(size.p[1]*channels()) && + CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1()); + return ((_Tp*)(data + step.p[0]*i0))[i1]; +} + +template inline const _Tp& Mat::at(int i0, int i1) const +{ + CV_DbgAssert( dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] && + (unsigned)(i1*DataType<_Tp>::channels) < (unsigned)(size.p[1]*channels()) && + CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1()); + return ((const _Tp*)(data + step.p[0]*i0))[i1]; +} + +template inline _Tp& Mat::at(Point pt) +{ + CV_DbgAssert( dims <= 2 && data && (unsigned)pt.y < (unsigned)size.p[0] && + (unsigned)(pt.x*DataType<_Tp>::channels) < (unsigned)(size.p[1]*channels()) && + CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1()); + return ((_Tp*)(data + step.p[0]*pt.y))[pt.x]; +} + +template inline const _Tp& Mat::at(Point pt) const +{ + CV_DbgAssert( dims <= 2 && data && (unsigned)pt.y < (unsigned)size.p[0] && + (unsigned)(pt.x*DataType<_Tp>::channels) < (unsigned)(size.p[1]*channels()) && + CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1()); + return ((const _Tp*)(data + step.p[0]*pt.y))[pt.x]; +} + +template inline _Tp& Mat::at(int i0) +{ + CV_DbgAssert( dims <= 2 && data && + (unsigned)i0 < (unsigned)(size.p[0]*size.p[1]) && + elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + if( isContinuous() || size.p[0] == 1 ) + return ((_Tp*)data)[i0]; + if( size.p[1] == 1 ) + return *(_Tp*)(data + step.p[0]*i0); + int i = i0/cols, j = i0 - i*cols; + return ((_Tp*)(data + step.p[0]*i))[j]; +} + +template inline const _Tp& Mat::at(int i0) const +{ + CV_DbgAssert( dims <= 2 && data && + (unsigned)i0 < (unsigned)(size.p[0]*size.p[1]) && + elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + if( isContinuous() || size.p[0] == 1 ) + return ((const _Tp*)data)[i0]; + if( size.p[1] == 1 ) + return *(const _Tp*)(data + step.p[0]*i0); + int i = i0/cols, j = i0 - i*cols; + return ((const _Tp*)(data + step.p[0]*i))[j]; +} + +template inline _Tp& Mat::at(int i0, int i1, int i2) +{ + CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + return *(_Tp*)ptr(i0, i1, i2); +} +template inline const _Tp& Mat::at(int i0, int i1, int i2) const +{ + CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + return *(const _Tp*)ptr(i0, i1, i2); +} +template inline _Tp& Mat::at(const int* idx) +{ + CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + return *(_Tp*)ptr(idx); +} +template inline const _Tp& Mat::at(const int* idx) const +{ + CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + return *(const _Tp*)ptr(idx); +} +template _Tp& Mat::at(const Vec& idx) +{ + CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + return *(_Tp*)ptr(idx.val); +} +template inline const _Tp& Mat::at(const Vec& idx) const +{ + CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) ); + return *(const _Tp*)ptr(idx.val); +} + + +template inline MatConstIterator_<_Tp> Mat::begin() const +{ + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return MatConstIterator_<_Tp>((const Mat_<_Tp>*)this); +} + +template inline MatConstIterator_<_Tp> Mat::end() const +{ + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + MatConstIterator_<_Tp> it((const Mat_<_Tp>*)this); + it += total(); + return it; +} + +template inline MatIterator_<_Tp> Mat::begin() +{ + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return MatIterator_<_Tp>((Mat_<_Tp>*)this); +} + +template inline MatIterator_<_Tp> Mat::end() +{ + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + MatIterator_<_Tp> it((Mat_<_Tp>*)this); + it += total(); + return it; +} + +template inline Mat::operator vector<_Tp>() const +{ + vector<_Tp> v; + copyTo(v); + return v; +} + +template inline Mat::operator Vec<_Tp, n>() const +{ + CV_Assert( data && dims <= 2 && (rows == 1 || cols == 1) && + rows + cols - 1 == n && channels() == 1 ); + + if( isContinuous() && type() == DataType<_Tp>::type ) + return Vec<_Tp, n>((_Tp*)data); + Vec<_Tp, n> v; Mat tmp(rows, cols, DataType<_Tp>::type, v.val); + convertTo(tmp, tmp.type()); + return v; +} + +template inline Mat::operator Matx<_Tp, m, n>() const +{ + CV_Assert( data && dims <= 2 && rows == m && cols == n && channels() == 1 ); + + if( isContinuous() && type() == DataType<_Tp>::type ) + return Matx<_Tp, m, n>((_Tp*)data); + Matx<_Tp, m, n> mtx; Mat tmp(rows, cols, DataType<_Tp>::type, mtx.val); + convertTo(tmp, tmp.type()); + return mtx; +} + + +template inline void Mat::push_back(const _Tp& elem) +{ + if( !data ) + { + *this = Mat(1, 1, DataType<_Tp>::type, (void*)&elem).clone(); + return; + } + CV_Assert(DataType<_Tp>::type == type() && cols == 1 + /* && dims == 2 (cols == 1 implies dims == 2) */); + uchar* tmp = dataend + step[0]; + if( !isSubmatrix() && isContinuous() && tmp <= datalimit ) + { + *(_Tp*)(data + (size.p[0]++)*step.p[0]) = elem; + dataend = tmp; + } + else + push_back_(&elem); +} + +template inline void Mat::push_back(const Mat_<_Tp>& m) +{ + push_back((const Mat&)m); +} + +inline Mat::MSize::MSize(int* _p) : p(_p) {} +inline Size Mat::MSize::operator()() const +{ + CV_DbgAssert(p[-1] <= 2); + return Size(p[1], p[0]); +} +inline const int& Mat::MSize::operator[](int i) const { return p[i]; } +inline int& Mat::MSize::operator[](int i) { return p[i]; } +inline Mat::MSize::operator const int*() const { return p; } + +inline bool Mat::MSize::operator == (const MSize& sz) const +{ + int d = p[-1], dsz = sz.p[-1]; + if( d != dsz ) + return false; + if( d == 2 ) + return p[0] == sz.p[0] && p[1] == sz.p[1]; + + for( int i = 0; i < d; i++ ) + if( p[i] != sz.p[i] ) + return false; + return true; +} + +inline bool Mat::MSize::operator != (const MSize& sz) const +{ + return !(*this == sz); +} + +inline Mat::MStep::MStep() { p = buf; p[0] = p[1] = 0; } +inline Mat::MStep::MStep(size_t s) { p = buf; p[0] = s; p[1] = 0; } +inline const size_t& Mat::MStep::operator[](int i) const { return p[i]; } +inline size_t& Mat::MStep::operator[](int i) { return p[i]; } +inline Mat::MStep::operator size_t() const +{ + CV_DbgAssert( p == buf ); + return buf[0]; +} +inline Mat::MStep& Mat::MStep::operator = (size_t s) +{ + CV_DbgAssert( p == buf ); + buf[0] = s; + return *this; +} + +static inline Mat cvarrToMatND(const CvArr* arr, bool copyData=false, int coiMode=0) +{ + return cvarrToMat(arr, copyData, true, coiMode); +} + +///////////////////////////////////////////// SVD ////////////////////////////////////////////////////// + +inline SVD::SVD() {} +inline SVD::SVD( InputArray m, int flags ) { operator ()(m, flags); } +inline void SVD::solveZ( InputArray m, OutputArray _dst ) +{ + Mat mtx = m.getMat(); + SVD svd(mtx, (mtx.rows >= mtx.cols ? 0 : SVD::FULL_UV)); + _dst.create(svd.vt.cols, 1, svd.vt.type()); + Mat dst = _dst.getMat(); + svd.vt.row(svd.vt.rows-1).reshape(1,svd.vt.cols).copyTo(dst); +} + +template inline void + SVD::compute( const Matx<_Tp, m, n>& a, Matx<_Tp, nm, 1>& w, Matx<_Tp, m, nm>& u, Matx<_Tp, n, nm>& vt ) +{ + assert( nm == MIN(m, n)); + Mat _a(a, false), _u(u, false), _w(w, false), _vt(vt, false); + SVD::compute(_a, _w, _u, _vt); + CV_Assert(_w.data == (uchar*)&w.val[0] && _u.data == (uchar*)&u.val[0] && _vt.data == (uchar*)&vt.val[0]); +} + +template inline void +SVD::compute( const Matx<_Tp, m, n>& a, Matx<_Tp, nm, 1>& w ) +{ + assert( nm == MIN(m, n)); + Mat _a(a, false), _w(w, false); + SVD::compute(_a, _w); + CV_Assert(_w.data == (uchar*)&w.val[0]); +} + +template inline void +SVD::backSubst( const Matx<_Tp, nm, 1>& w, const Matx<_Tp, m, nm>& u, + const Matx<_Tp, n, nm>& vt, const Matx<_Tp, m, nb>& rhs, + Matx<_Tp, n, nb>& dst ) +{ + assert( nm == MIN(m, n)); + Mat _u(u, false), _w(w, false), _vt(vt, false), _rhs(rhs, false), _dst(dst, false); + SVD::backSubst(_w, _u, _vt, _rhs, _dst); + CV_Assert(_dst.data == (uchar*)&dst.val[0]); +} + +///////////////////////////////// Mat_<_Tp> //////////////////////////////////// + +template inline Mat_<_Tp>::Mat_() + : Mat() { flags = (flags & ~CV_MAT_TYPE_MASK) | DataType<_Tp>::type; } + +template inline Mat_<_Tp>::Mat_(int _rows, int _cols) + : Mat(_rows, _cols, DataType<_Tp>::type) {} + +template inline Mat_<_Tp>::Mat_(int _rows, int _cols, const _Tp& value) + : Mat(_rows, _cols, DataType<_Tp>::type) { *this = value; } + +template inline Mat_<_Tp>::Mat_(Size _sz) + : Mat(_sz.height, _sz.width, DataType<_Tp>::type) {} + +template inline Mat_<_Tp>::Mat_(Size _sz, const _Tp& value) + : Mat(_sz.height, _sz.width, DataType<_Tp>::type) { *this = value; } + +template inline Mat_<_Tp>::Mat_(int _dims, const int* _sz) + : Mat(_dims, _sz, DataType<_Tp>::type) {} + +template inline Mat_<_Tp>::Mat_(int _dims, const int* _sz, const _Tp& _s) + : Mat(_dims, _sz, DataType<_Tp>::type, Scalar(_s)) {} + +template inline Mat_<_Tp>::Mat_(const Mat_<_Tp>& m, const Range* ranges) + : Mat(m, ranges) {} + +template inline Mat_<_Tp>::Mat_(const Mat& m) + : Mat() { flags = (flags & ~CV_MAT_TYPE_MASK) | DataType<_Tp>::type; *this = m; } + +template inline Mat_<_Tp>::Mat_(const Mat_& m) + : Mat(m) {} + +template inline Mat_<_Tp>::Mat_(int _rows, int _cols, _Tp* _data, size_t steps) + : Mat(_rows, _cols, DataType<_Tp>::type, _data, steps) {} + +template inline Mat_<_Tp>::Mat_(const Mat_& m, const Range& _rowRange, const Range& _colRange) + : Mat(m, _rowRange, _colRange) {} + +template inline Mat_<_Tp>::Mat_(const Mat_& m, const Rect& roi) + : Mat(m, roi) {} + +template template inline + Mat_<_Tp>::Mat_(const Vec::channel_type, n>& vec, bool copyData) + : Mat(n/DataType<_Tp>::channels, 1, DataType<_Tp>::type, (void*)&vec) +{ + CV_Assert(n%DataType<_Tp>::channels == 0); + if( copyData ) + *this = clone(); +} + +template template inline + Mat_<_Tp>::Mat_(const Matx::channel_type,m,n>& M, bool copyData) + : Mat(m, n/DataType<_Tp>::channels, DataType<_Tp>::type, (void*)&M) +{ + CV_Assert(n % DataType<_Tp>::channels == 0); + if( copyData ) + *this = clone(); +} + +template inline Mat_<_Tp>::Mat_(const Point_::channel_type>& pt, bool copyData) + : Mat(2/DataType<_Tp>::channels, 1, DataType<_Tp>::type, (void*)&pt) +{ + CV_Assert(2 % DataType<_Tp>::channels == 0); + if( copyData ) + *this = clone(); +} + +template inline Mat_<_Tp>::Mat_(const Point3_::channel_type>& pt, bool copyData) + : Mat(3/DataType<_Tp>::channels, 1, DataType<_Tp>::type, (void*)&pt) +{ + CV_Assert(3 % DataType<_Tp>::channels == 0); + if( copyData ) + *this = clone(); +} + +template inline Mat_<_Tp>::Mat_(const MatCommaInitializer_<_Tp>& commaInitializer) + : Mat(commaInitializer) {} + +template inline Mat_<_Tp>::Mat_(const vector<_Tp>& vec, bool copyData) + : Mat(vec, copyData) {} + +template inline Mat_<_Tp>& Mat_<_Tp>::operator = (const Mat& m) +{ + if( DataType<_Tp>::type == m.type() ) + { + Mat::operator = (m); + return *this; + } + if( DataType<_Tp>::depth == m.depth() ) + { + return (*this = m.reshape(DataType<_Tp>::channels, m.dims, 0)); + } + CV_DbgAssert(DataType<_Tp>::channels == m.channels()); + m.convertTo(*this, type()); + return *this; +} + +template inline Mat_<_Tp>& Mat_<_Tp>::operator = (const Mat_& m) +{ + Mat::operator=(m); + return *this; +} + +template inline Mat_<_Tp>& Mat_<_Tp>::operator = (const _Tp& s) +{ + typedef typename DataType<_Tp>::vec_type VT; + Mat::operator=(Scalar((const VT&)s)); + return *this; +} + +template inline void Mat_<_Tp>::create(int _rows, int _cols) +{ + Mat::create(_rows, _cols, DataType<_Tp>::type); +} + +template inline void Mat_<_Tp>::create(Size _sz) +{ + Mat::create(_sz, DataType<_Tp>::type); +} + +template inline void Mat_<_Tp>::create(int _dims, const int* _sz) +{ + Mat::create(_dims, _sz, DataType<_Tp>::type); +} + + +template inline Mat_<_Tp> Mat_<_Tp>::cross(const Mat_& m) const +{ return Mat_<_Tp>(Mat::cross(m)); } + +template template inline Mat_<_Tp>::operator Mat_() const +{ return Mat_(*this); } + +template inline Mat_<_Tp> Mat_<_Tp>::row(int y) const +{ return Mat_(*this, Range(y, y+1), Range::all()); } +template inline Mat_<_Tp> Mat_<_Tp>::col(int x) const +{ return Mat_(*this, Range::all(), Range(x, x+1)); } +template inline Mat_<_Tp> Mat_<_Tp>::diag(int d) const +{ return Mat_(Mat::diag(d)); } +template inline Mat_<_Tp> Mat_<_Tp>::clone() const +{ return Mat_(Mat::clone()); } + +template inline size_t Mat_<_Tp>::elemSize() const +{ + CV_DbgAssert( Mat::elemSize() == sizeof(_Tp) ); + return sizeof(_Tp); +} + +template inline size_t Mat_<_Tp>::elemSize1() const +{ + CV_DbgAssert( Mat::elemSize1() == sizeof(_Tp)/DataType<_Tp>::channels ); + return sizeof(_Tp)/DataType<_Tp>::channels; +} +template inline int Mat_<_Tp>::type() const +{ + CV_DbgAssert( Mat::type() == DataType<_Tp>::type ); + return DataType<_Tp>::type; +} +template inline int Mat_<_Tp>::depth() const +{ + CV_DbgAssert( Mat::depth() == DataType<_Tp>::depth ); + return DataType<_Tp>::depth; +} +template inline int Mat_<_Tp>::channels() const +{ + CV_DbgAssert( Mat::channels() == DataType<_Tp>::channels ); + return DataType<_Tp>::channels; +} +template inline size_t Mat_<_Tp>::stepT(int i) const { return step.p[i]/elemSize(); } +template inline size_t Mat_<_Tp>::step1(int i) const { return step.p[i]/elemSize1(); } + +template inline Mat_<_Tp>& Mat_<_Tp>::adjustROI( int dtop, int dbottom, int dleft, int dright ) +{ return (Mat_<_Tp>&)(Mat::adjustROI(dtop, dbottom, dleft, dright)); } + +template inline Mat_<_Tp> Mat_<_Tp>::operator()( const Range& _rowRange, const Range& _colRange ) const +{ return Mat_<_Tp>(*this, _rowRange, _colRange); } + +template inline Mat_<_Tp> Mat_<_Tp>::operator()( const Rect& roi ) const +{ return Mat_<_Tp>(*this, roi); } + +template inline Mat_<_Tp> Mat_<_Tp>::operator()( const Range* ranges ) const +{ return Mat_<_Tp>(*this, ranges); } + +template inline _Tp* Mat_<_Tp>::operator [](int y) +{ return (_Tp*)ptr(y); } +template inline const _Tp* Mat_<_Tp>::operator [](int y) const +{ return (const _Tp*)ptr(y); } + +template inline _Tp& Mat_<_Tp>::operator ()(int i0, int i1) +{ + CV_DbgAssert( dims <= 2 && data && + (unsigned)i0 < (unsigned)size.p[0] && + (unsigned)i1 < (unsigned)size.p[1] && + type() == DataType<_Tp>::type ); + return ((_Tp*)(data + step.p[0]*i0))[i1]; +} + +template inline const _Tp& Mat_<_Tp>::operator ()(int i0, int i1) const +{ + CV_DbgAssert( dims <= 2 && data && + (unsigned)i0 < (unsigned)size.p[0] && + (unsigned)i1 < (unsigned)size.p[1] && + type() == DataType<_Tp>::type ); + return ((const _Tp*)(data + step.p[0]*i0))[i1]; +} + +template inline _Tp& Mat_<_Tp>::operator ()(Point pt) +{ + CV_DbgAssert( dims <= 2 && data && + (unsigned)pt.y < (unsigned)size.p[0] && + (unsigned)pt.x < (unsigned)size.p[1] && + type() == DataType<_Tp>::type ); + return ((_Tp*)(data + step.p[0]*pt.y))[pt.x]; +} + +template inline const _Tp& Mat_<_Tp>::operator ()(Point pt) const +{ + CV_DbgAssert( dims <= 2 && data && + (unsigned)pt.y < (unsigned)size.p[0] && + (unsigned)pt.x < (unsigned)size.p[1] && + type() == DataType<_Tp>::type ); + return ((const _Tp*)(data + step.p[0]*pt.y))[pt.x]; +} + +template inline _Tp& Mat_<_Tp>::operator ()(const int* idx) +{ + return Mat::at<_Tp>(idx); +} + +template inline const _Tp& Mat_<_Tp>::operator ()(const int* idx) const +{ + return Mat::at<_Tp>(idx); +} + +template template inline _Tp& Mat_<_Tp>::operator ()(const Vec& idx) +{ + return Mat::at<_Tp>(idx); +} + +template template inline const _Tp& Mat_<_Tp>::operator ()(const Vec& idx) const +{ + return Mat::at<_Tp>(idx); +} + +template inline _Tp& Mat_<_Tp>::operator ()(int i0) +{ + return this->at<_Tp>(i0); +} + +template inline const _Tp& Mat_<_Tp>::operator ()(int i0) const +{ + return this->at<_Tp>(i0); +} + +template inline _Tp& Mat_<_Tp>::operator ()(int i0, int i1, int i2) +{ + return this->at<_Tp>(i0, i1, i2); +} + +template inline const _Tp& Mat_<_Tp>::operator ()(int i0, int i1, int i2) const +{ + return this->at<_Tp>(i0, i1, i2); +} + + +template inline Mat_<_Tp>::operator vector<_Tp>() const +{ + vector<_Tp> v; + copyTo(v); + return v; +} + +template template inline Mat_<_Tp>::operator Vec::channel_type, n>() const +{ + CV_Assert(n % DataType<_Tp>::channels == 0); + return this->Mat::operator Vec::channel_type, n>(); +} + +template template inline Mat_<_Tp>::operator Matx::channel_type, m, n>() const +{ + CV_Assert(n % DataType<_Tp>::channels == 0); + return this->Mat::operator Matx::channel_type, m, n>(); +} + +template inline void +process( const Mat_& m1, Mat_& m2, Op op ) +{ + int y, x, rows = m1.rows, cols = m1.cols; + + CV_DbgAssert( m1.size() == m2.size() ); + + for( y = 0; y < rows; y++ ) + { + const T1* src = m1[y]; + T2* dst = m2[y]; + + for( x = 0; x < cols; x++ ) + dst[x] = op(src[x]); + } +} + +template inline void +process( const Mat_& m1, const Mat_& m2, Mat_& m3, Op op ) +{ + int y, x, rows = m1.rows, cols = m1.cols; + + CV_DbgAssert( m1.size() == m2.size() ); + + for( y = 0; y < rows; y++ ) + { + const T1* src1 = m1[y]; + const T2* src2 = m2[y]; + T3* dst = m3[y]; + + for( x = 0; x < cols; x++ ) + dst[x] = op( src1[x], src2[x] ); + } +} + + +/////////////////////////////// Input/Output Arrays ///////////////////////////////// + +template inline _InputArray::_InputArray(const vector<_Tp>& vec) + : flags(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type), obj((void*)&vec) {} + +template inline _InputArray::_InputArray(const vector >& vec) + : flags(FIXED_TYPE + STD_VECTOR_VECTOR + DataType<_Tp>::type), obj((void*)&vec) {} + +template inline _InputArray::_InputArray(const vector >& vec) + : flags(FIXED_TYPE + STD_VECTOR_MAT + DataType<_Tp>::type), obj((void*)&vec) {} + +template inline _InputArray::_InputArray(const Matx<_Tp, m, n>& mtx) + : flags(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type), obj((void*)&mtx), sz(n, m) {} + +template inline _InputArray::_InputArray(const _Tp* vec, int n) + : flags(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type), obj((void*)vec), sz(n, 1) {} + +inline _InputArray::_InputArray(const Scalar& s) + : flags(FIXED_TYPE + FIXED_SIZE + MATX + CV_64F), obj((void*)&s), sz(1, 4) {} + +template inline _InputArray::_InputArray(const Mat_<_Tp>& m) + : flags(FIXED_TYPE + MAT + DataType<_Tp>::type), obj((void*)&m) {} + +template inline _OutputArray::_OutputArray(vector<_Tp>& vec) + : _InputArray(vec) {} +template inline _OutputArray::_OutputArray(vector >& vec) + : _InputArray(vec) {} +template inline _OutputArray::_OutputArray(vector >& vec) + : _InputArray(vec) {} +template inline _OutputArray::_OutputArray(Mat_<_Tp>& m) + : _InputArray(m) {} +template inline _OutputArray::_OutputArray(Matx<_Tp, m, n>& mtx) + : _InputArray(mtx) {} +template inline _OutputArray::_OutputArray(_Tp* vec, int n) + : _InputArray(vec, n) {} + +template inline _OutputArray::_OutputArray(const vector<_Tp>& vec) + : _InputArray(vec) {flags |= FIXED_SIZE;} +template inline _OutputArray::_OutputArray(const vector >& vec) + : _InputArray(vec) {flags |= FIXED_SIZE;} +template inline _OutputArray::_OutputArray(const vector >& vec) + : _InputArray(vec) {flags |= FIXED_SIZE;} + +template inline _OutputArray::_OutputArray(const Mat_<_Tp>& m) + : _InputArray(m) {flags |= FIXED_SIZE;} +template inline _OutputArray::_OutputArray(const Matx<_Tp, m, n>& mtx) + : _InputArray(mtx) {} +template inline _OutputArray::_OutputArray(const _Tp* vec, int n) + : _InputArray(vec, n) {} + +//////////////////////////////////// Matrix Expressions ///////////////////////////////////////// + +class CV_EXPORTS MatOp +{ +public: + MatOp() {}; + virtual ~MatOp() {}; + + virtual bool elementWise(const MatExpr& expr) const; + virtual void assign(const MatExpr& expr, Mat& m, int type=-1) const = 0; + virtual void roi(const MatExpr& expr, const Range& rowRange, + const Range& colRange, MatExpr& res) const; + virtual void diag(const MatExpr& expr, int d, MatExpr& res) const; + virtual void augAssignAdd(const MatExpr& expr, Mat& m) const; + virtual void augAssignSubtract(const MatExpr& expr, Mat& m) const; + virtual void augAssignMultiply(const MatExpr& expr, Mat& m) const; + virtual void augAssignDivide(const MatExpr& expr, Mat& m) const; + virtual void augAssignAnd(const MatExpr& expr, Mat& m) const; + virtual void augAssignOr(const MatExpr& expr, Mat& m) const; + virtual void augAssignXor(const MatExpr& expr, Mat& m) const; + + virtual void add(const MatExpr& expr1, const MatExpr& expr2, MatExpr& res) const; + virtual void add(const MatExpr& expr1, const Scalar& s, MatExpr& res) const; + + virtual void subtract(const MatExpr& expr1, const MatExpr& expr2, MatExpr& res) const; + virtual void subtract(const Scalar& s, const MatExpr& expr, MatExpr& res) const; + + virtual void multiply(const MatExpr& expr1, const MatExpr& expr2, MatExpr& res, double scale=1) const; + virtual void multiply(const MatExpr& expr1, double s, MatExpr& res) const; + + virtual void divide(const MatExpr& expr1, const MatExpr& expr2, MatExpr& res, double scale=1) const; + virtual void divide(double s, const MatExpr& expr, MatExpr& res) const; + + virtual void abs(const MatExpr& expr, MatExpr& res) const; + + virtual void transpose(const MatExpr& expr, MatExpr& res) const; + virtual void matmul(const MatExpr& expr1, const MatExpr& expr2, MatExpr& res) const; + virtual void invert(const MatExpr& expr, int method, MatExpr& res) const; + + virtual Size size(const MatExpr& expr) const; + virtual int type(const MatExpr& expr) const; +}; + + +class CV_EXPORTS MatExpr +{ +public: + MatExpr() : op(0), flags(0), a(Mat()), b(Mat()), c(Mat()), alpha(0), beta(0), s(Scalar()) {} + MatExpr(const MatOp* _op, int _flags, const Mat& _a=Mat(), const Mat& _b=Mat(), + const Mat& _c=Mat(), double _alpha=1, double _beta=1, const Scalar& _s=Scalar()) + : op(_op), flags(_flags), a(_a), b(_b), c(_c), alpha(_alpha), beta(_beta), s(_s) {} + explicit MatExpr(const Mat& m); + operator Mat() const + { + Mat m; + op->assign(*this, m); + return m; + } + + template operator Mat_<_Tp>() const + { + Mat_<_Tp> m; + op->assign(*this, m, DataType<_Tp>::type); + return m; + } + + MatExpr row(int y) const; + MatExpr col(int x) const; + MatExpr diag(int d=0) const; + MatExpr operator()( const Range& rowRange, const Range& colRange ) const; + MatExpr operator()( const Rect& roi ) const; + + Mat cross(const Mat& m) const; + double dot(const Mat& m) const; + + MatExpr t() const; + MatExpr inv(int method = DECOMP_LU) const; + MatExpr mul(const MatExpr& e, double scale=1) const; + MatExpr mul(const Mat& m, double scale=1) const; + + Size size() const; + int type() const; + + const MatOp* op; + int flags; + + Mat a, b, c; + double alpha, beta; + Scalar s; +}; + + +CV_EXPORTS MatExpr operator + (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator + (const Mat& a, const Scalar& s); +CV_EXPORTS MatExpr operator + (const Scalar& s, const Mat& a); +CV_EXPORTS MatExpr operator + (const MatExpr& e, const Mat& m); +CV_EXPORTS MatExpr operator + (const Mat& m, const MatExpr& e); +CV_EXPORTS MatExpr operator + (const MatExpr& e, const Scalar& s); +CV_EXPORTS MatExpr operator + (const Scalar& s, const MatExpr& e); +CV_EXPORTS MatExpr operator + (const MatExpr& e1, const MatExpr& e2); + +CV_EXPORTS MatExpr operator - (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator - (const Mat& a, const Scalar& s); +CV_EXPORTS MatExpr operator - (const Scalar& s, const Mat& a); +CV_EXPORTS MatExpr operator - (const MatExpr& e, const Mat& m); +CV_EXPORTS MatExpr operator - (const Mat& m, const MatExpr& e); +CV_EXPORTS MatExpr operator - (const MatExpr& e, const Scalar& s); +CV_EXPORTS MatExpr operator - (const Scalar& s, const MatExpr& e); +CV_EXPORTS MatExpr operator - (const MatExpr& e1, const MatExpr& e2); + +CV_EXPORTS MatExpr operator - (const Mat& m); +CV_EXPORTS MatExpr operator - (const MatExpr& e); + +CV_EXPORTS MatExpr operator * (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator * (const Mat& a, double s); +CV_EXPORTS MatExpr operator * (double s, const Mat& a); +CV_EXPORTS MatExpr operator * (const MatExpr& e, const Mat& m); +CV_EXPORTS MatExpr operator * (const Mat& m, const MatExpr& e); +CV_EXPORTS MatExpr operator * (const MatExpr& e, double s); +CV_EXPORTS MatExpr operator * (double s, const MatExpr& e); +CV_EXPORTS MatExpr operator * (const MatExpr& e1, const MatExpr& e2); + +CV_EXPORTS MatExpr operator / (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator / (const Mat& a, double s); +CV_EXPORTS MatExpr operator / (double s, const Mat& a); +CV_EXPORTS MatExpr operator / (const MatExpr& e, const Mat& m); +CV_EXPORTS MatExpr operator / (const Mat& m, const MatExpr& e); +CV_EXPORTS MatExpr operator / (const MatExpr& e, double s); +CV_EXPORTS MatExpr operator / (double s, const MatExpr& e); +CV_EXPORTS MatExpr operator / (const MatExpr& e1, const MatExpr& e2); + +CV_EXPORTS MatExpr operator < (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator < (const Mat& a, double s); +CV_EXPORTS MatExpr operator < (double s, const Mat& a); + +CV_EXPORTS MatExpr operator <= (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator <= (const Mat& a, double s); +CV_EXPORTS MatExpr operator <= (double s, const Mat& a); + +CV_EXPORTS MatExpr operator == (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator == (const Mat& a, double s); +CV_EXPORTS MatExpr operator == (double s, const Mat& a); + +CV_EXPORTS MatExpr operator != (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator != (const Mat& a, double s); +CV_EXPORTS MatExpr operator != (double s, const Mat& a); + +CV_EXPORTS MatExpr operator >= (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator >= (const Mat& a, double s); +CV_EXPORTS MatExpr operator >= (double s, const Mat& a); + +CV_EXPORTS MatExpr operator > (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator > (const Mat& a, double s); +CV_EXPORTS MatExpr operator > (double s, const Mat& a); + +CV_EXPORTS MatExpr min(const Mat& a, const Mat& b); +CV_EXPORTS MatExpr min(const Mat& a, double s); +CV_EXPORTS MatExpr min(double s, const Mat& a); + +CV_EXPORTS MatExpr max(const Mat& a, const Mat& b); +CV_EXPORTS MatExpr max(const Mat& a, double s); +CV_EXPORTS MatExpr max(double s, const Mat& a); + +template static inline MatExpr min(const Mat_<_Tp>& a, const Mat_<_Tp>& b) +{ + return cv::min((const Mat&)a, (const Mat&)b); +} + +template static inline MatExpr min(const Mat_<_Tp>& a, double s) +{ + return cv::min((const Mat&)a, s); +} + +template static inline MatExpr min(double s, const Mat_<_Tp>& a) +{ + return cv::min((const Mat&)a, s); +} + +template static inline MatExpr max(const Mat_<_Tp>& a, const Mat_<_Tp>& b) +{ + return cv::max((const Mat&)a, (const Mat&)b); +} + +template static inline MatExpr max(const Mat_<_Tp>& a, double s) +{ + return cv::max((const Mat&)a, s); +} + +template static inline MatExpr max(double s, const Mat_<_Tp>& a) +{ + return cv::max((const Mat&)a, s); +} + +template static inline void min(const Mat_<_Tp>& a, const Mat_<_Tp>& b, Mat_<_Tp>& c) +{ + cv::min((const Mat&)a, (const Mat&)b, (Mat&)c); +} + +template static inline void min(const Mat_<_Tp>& a, double s, Mat_<_Tp>& c) +{ + cv::min((const Mat&)a, s, (Mat&)c); +} + +template static inline void min(double s, const Mat_<_Tp>& a, Mat_<_Tp>& c) +{ + cv::min((const Mat&)a, s, (Mat&)c); +} + +template static inline void max(const Mat_<_Tp>& a, const Mat_<_Tp>& b, Mat_<_Tp>& c) +{ + cv::max((const Mat&)a, (const Mat&)b, (Mat&)c); +} + +template static inline void max(const Mat_<_Tp>& a, double s, Mat_<_Tp>& c) +{ + cv::max((const Mat&)a, s, (Mat&)c); +} + +template static inline void max(double s, const Mat_<_Tp>& a, Mat_<_Tp>& c) +{ + cv::max((const Mat&)a, s, (Mat&)c); +} + + +CV_EXPORTS MatExpr operator & (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator & (const Mat& a, const Scalar& s); +CV_EXPORTS MatExpr operator & (const Scalar& s, const Mat& a); + +CV_EXPORTS MatExpr operator | (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator | (const Mat& a, const Scalar& s); +CV_EXPORTS MatExpr operator | (const Scalar& s, const Mat& a); + +CV_EXPORTS MatExpr operator ^ (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator ^ (const Mat& a, const Scalar& s); +CV_EXPORTS MatExpr operator ^ (const Scalar& s, const Mat& a); + +CV_EXPORTS MatExpr operator ~(const Mat& m); + +CV_EXPORTS MatExpr abs(const Mat& m); +CV_EXPORTS MatExpr abs(const MatExpr& e); + +template static inline MatExpr abs(const Mat_<_Tp>& m) +{ + return cv::abs((const Mat&)m); +} + +////////////////////////////// Augmenting algebraic operations ////////////////////////////////// + +inline Mat& Mat::operator = (const MatExpr& e) +{ + e.op->assign(e, *this); + return *this; +} + +template inline Mat_<_Tp>::Mat_(const MatExpr& e) +{ + e.op->assign(e, *this, DataType<_Tp>::type); +} + +template Mat_<_Tp>& Mat_<_Tp>::operator = (const MatExpr& e) +{ + e.op->assign(e, *this, DataType<_Tp>::type); + return *this; +} + +static inline Mat& operator += (const Mat& a, const Mat& b) +{ + add(a, b, (Mat&)a); + return (Mat&)a; +} + +static inline Mat& operator += (const Mat& a, const Scalar& s) +{ + add(a, s, (Mat&)a); + return (Mat&)a; +} + +template static inline +Mat_<_Tp>& operator += (const Mat_<_Tp>& a, const Mat_<_Tp>& b) +{ + add(a, b, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +template static inline +Mat_<_Tp>& operator += (const Mat_<_Tp>& a, const Scalar& s) +{ + add(a, s, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +static inline Mat& operator += (const Mat& a, const MatExpr& b) +{ + b.op->augAssignAdd(b, (Mat&)a); + return (Mat&)a; +} + +template static inline +Mat_<_Tp>& operator += (const Mat_<_Tp>& a, const MatExpr& b) +{ + b.op->augAssignAdd(b, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +static inline Mat& operator -= (const Mat& a, const Mat& b) +{ + subtract(a, b, (Mat&)a); + return (Mat&)a; +} + +static inline Mat& operator -= (const Mat& a, const Scalar& s) +{ + subtract(a, s, (Mat&)a); + return (Mat&)a; +} + +template static inline +Mat_<_Tp>& operator -= (const Mat_<_Tp>& a, const Mat_<_Tp>& b) +{ + subtract(a, b, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +template static inline +Mat_<_Tp>& operator -= (const Mat_<_Tp>& a, const Scalar& s) +{ + subtract(a, s, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +static inline Mat& operator -= (const Mat& a, const MatExpr& b) +{ + b.op->augAssignSubtract(b, (Mat&)a); + return (Mat&)a; +} + +template static inline +Mat_<_Tp>& operator -= (const Mat_<_Tp>& a, const MatExpr& b) +{ + b.op->augAssignSubtract(b, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +static inline Mat& operator *= (const Mat& a, const Mat& b) +{ + gemm(a, b, 1, Mat(), 0, (Mat&)a, 0); + return (Mat&)a; +} + +static inline Mat& operator *= (const Mat& a, double s) +{ + a.convertTo((Mat&)a, -1, s); + return (Mat&)a; +} + +template static inline +Mat_<_Tp>& operator *= (const Mat_<_Tp>& a, const Mat_<_Tp>& b) +{ + gemm(a, b, 1, Mat(), 0, (Mat&)a, 0); + return (Mat_<_Tp>&)a; +} + +template static inline +Mat_<_Tp>& operator *= (const Mat_<_Tp>& a, double s) +{ + a.convertTo((Mat&)a, -1, s); + return (Mat_<_Tp>&)a; +} + +static inline Mat& operator *= (const Mat& a, const MatExpr& b) +{ + b.op->augAssignMultiply(b, (Mat&)a); + return (Mat&)a; +} + +template static inline +Mat_<_Tp>& operator *= (const Mat_<_Tp>& a, const MatExpr& b) +{ + b.op->augAssignMultiply(b, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +static inline Mat& operator /= (const Mat& a, const Mat& b) +{ + divide(a, b, (Mat&)a); + return (Mat&)a; +} + +static inline Mat& operator /= (const Mat& a, double s) +{ + a.convertTo((Mat&)a, -1, 1./s); + return (Mat&)a; +} + +template static inline +Mat_<_Tp>& operator /= (const Mat_<_Tp>& a, const Mat_<_Tp>& b) +{ + divide(a, b, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +template static inline +Mat_<_Tp>& operator /= (const Mat_<_Tp>& a, double s) +{ + a.convertTo((Mat&)a, -1, 1./s); + return (Mat_<_Tp>&)a; +} + +static inline Mat& operator /= (const Mat& a, const MatExpr& b) +{ + b.op->augAssignDivide(b, (Mat&)a); + return (Mat&)a; +} + +template static inline +Mat_<_Tp>& operator /= (const Mat_<_Tp>& a, const MatExpr& b) +{ + b.op->augAssignDivide(b, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +////////////////////////////// Logical operations /////////////////////////////// + +static inline Mat& operator &= (const Mat& a, const Mat& b) +{ + bitwise_and(a, b, (Mat&)a); + return (Mat&)a; +} + +static inline Mat& operator &= (const Mat& a, const Scalar& s) +{ + bitwise_and(a, s, (Mat&)a); + return (Mat&)a; +} + +template static inline Mat_<_Tp>& +operator &= (const Mat_<_Tp>& a, const Mat_<_Tp>& b) +{ + bitwise_and(a, b, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +template static inline Mat_<_Tp>& +operator &= (const Mat_<_Tp>& a, const Scalar& s) +{ + bitwise_and(a, s, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +static inline Mat& operator |= (const Mat& a, const Mat& b) +{ + bitwise_or(a, b, (Mat&)a); + return (Mat&)a; +} + +static inline Mat& operator |= (const Mat& a, const Scalar& s) +{ + bitwise_or(a, s, (Mat&)a); + return (Mat&)a; +} + +template static inline Mat_<_Tp>& +operator |= (const Mat_<_Tp>& a, const Mat_<_Tp>& b) +{ + bitwise_or(a, b, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +template static inline Mat_<_Tp>& +operator |= (const Mat_<_Tp>& a, const Scalar& s) +{ + bitwise_or(a, s, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +static inline Mat& operator ^= (const Mat& a, const Mat& b) +{ + bitwise_xor(a, b, (Mat&)a); + return (Mat&)a; +} + +static inline Mat& operator ^= (const Mat& a, const Scalar& s) +{ + bitwise_xor(a, s, (Mat&)a); + return (Mat&)a; +} + +template static inline Mat_<_Tp>& +operator ^= (const Mat_<_Tp>& a, const Mat_<_Tp>& b) +{ + bitwise_xor(a, b, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +template static inline Mat_<_Tp>& +operator ^= (const Mat_<_Tp>& a, const Scalar& s) +{ + bitwise_xor(a, s, (Mat&)a); + return (Mat_<_Tp>&)a; +} + +/////////////////////////////// Miscellaneous operations ////////////////////////////// + +template void split(const Mat& src, vector >& mv) +{ split(src, (vector&)mv ); } + +////////////////////////////////////////////////////////////// + +template inline MatExpr Mat_<_Tp>::zeros(int rows, int cols) +{ + return Mat::zeros(rows, cols, DataType<_Tp>::type); +} + +template inline MatExpr Mat_<_Tp>::zeros(Size sz) +{ + return Mat::zeros(sz, DataType<_Tp>::type); +} + +template inline MatExpr Mat_<_Tp>::ones(int rows, int cols) +{ + return Mat::ones(rows, cols, DataType<_Tp>::type); +} + +template inline MatExpr Mat_<_Tp>::ones(Size sz) +{ + return Mat::ones(sz, DataType<_Tp>::type); +} + +template inline MatExpr Mat_<_Tp>::eye(int rows, int cols) +{ + return Mat::eye(rows, cols, DataType<_Tp>::type); +} + +template inline MatExpr Mat_<_Tp>::eye(Size sz) +{ + return Mat::eye(sz, DataType<_Tp>::type); +} + +//////////////////////////////// Iterators & Comma initializers ////////////////////////////////// + +inline MatConstIterator::MatConstIterator() + : m(0), elemSize(0), ptr(0), sliceStart(0), sliceEnd(0) {} + +inline MatConstIterator::MatConstIterator(const Mat* _m) + : m(_m), elemSize(_m->elemSize()), ptr(0), sliceStart(0), sliceEnd(0) +{ + if( m && m->isContinuous() ) + { + sliceStart = m->data; + sliceEnd = sliceStart + m->total()*elemSize; + } + seek((const int*)0); +} + +inline MatConstIterator::MatConstIterator(const Mat* _m, int _row, int _col) + : m(_m), elemSize(_m->elemSize()), ptr(0), sliceStart(0), sliceEnd(0) +{ + CV_Assert(m && m->dims <= 2); + if( m->isContinuous() ) + { + sliceStart = m->data; + sliceEnd = sliceStart + m->total()*elemSize; + } + int idx[]={_row, _col}; + seek(idx); +} + +inline MatConstIterator::MatConstIterator(const Mat* _m, Point _pt) + : m(_m), elemSize(_m->elemSize()), ptr(0), sliceStart(0), sliceEnd(0) +{ + CV_Assert(m && m->dims <= 2); + if( m->isContinuous() ) + { + sliceStart = m->data; + sliceEnd = sliceStart + m->total()*elemSize; + } + int idx[]={_pt.y, _pt.x}; + seek(idx); +} + +inline MatConstIterator::MatConstIterator(const MatConstIterator& it) + : m(it.m), elemSize(it.elemSize), ptr(it.ptr), sliceStart(it.sliceStart), sliceEnd(it.sliceEnd) +{} + +inline MatConstIterator& MatConstIterator::operator = (const MatConstIterator& it ) +{ + m = it.m; elemSize = it.elemSize; ptr = it.ptr; + sliceStart = it.sliceStart; sliceEnd = it.sliceEnd; + return *this; +} + +inline uchar* MatConstIterator::operator *() const { return ptr; } + +inline MatConstIterator& MatConstIterator::operator += (ptrdiff_t ofs) +{ + if( !m || ofs == 0 ) + return *this; + ptrdiff_t ofsb = ofs*elemSize; + ptr += ofsb; + if( ptr < sliceStart || sliceEnd <= ptr ) + { + ptr -= ofsb; + seek(ofs, true); + } + return *this; +} + +inline MatConstIterator& MatConstIterator::operator -= (ptrdiff_t ofs) +{ return (*this += -ofs); } + +inline MatConstIterator& MatConstIterator::operator --() +{ + if( m && (ptr -= elemSize) < sliceStart ) + { + ptr += elemSize; + seek(-1, true); + } + return *this; +} + +inline MatConstIterator MatConstIterator::operator --(int) +{ + MatConstIterator b = *this; + *this += -1; + return b; +} + +inline MatConstIterator& MatConstIterator::operator ++() +{ + if( m && (ptr += elemSize) >= sliceEnd ) + { + ptr -= elemSize; + seek(1, true); + } + return *this; +} + +inline MatConstIterator MatConstIterator::operator ++(int) +{ + MatConstIterator b = *this; + *this += 1; + return b; +} + +template inline MatConstIterator_<_Tp>::MatConstIterator_() {} + +template inline MatConstIterator_<_Tp>::MatConstIterator_(const Mat_<_Tp>* _m) + : MatConstIterator(_m) {} + +template inline MatConstIterator_<_Tp>:: + MatConstIterator_(const Mat_<_Tp>* _m, int _row, int _col) + : MatConstIterator(_m, _row, _col) {} + +template inline MatConstIterator_<_Tp>:: + MatConstIterator_(const Mat_<_Tp>* _m, Point _pt) + : MatConstIterator(_m, _pt) {} + +template inline MatConstIterator_<_Tp>:: + MatConstIterator_(const MatConstIterator_& it) + : MatConstIterator(it) {} + +template inline MatConstIterator_<_Tp>& + MatConstIterator_<_Tp>::operator = (const MatConstIterator_& it ) +{ + MatConstIterator::operator = (it); + return *this; +} + +template inline _Tp MatConstIterator_<_Tp>::operator *() const { return *(_Tp*)(this->ptr); } + +template inline MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator += (ptrdiff_t ofs) +{ + MatConstIterator::operator += (ofs); + return *this; +} + +template inline MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator -= (ptrdiff_t ofs) +{ return (*this += -ofs); } + +template inline MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator --() +{ + MatConstIterator::operator --(); + return *this; +} + +template inline MatConstIterator_<_Tp> MatConstIterator_<_Tp>::operator --(int) +{ + MatConstIterator_ b = *this; + MatConstIterator::operator --(); + return b; +} + +template inline MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator ++() +{ + MatConstIterator::operator ++(); + return *this; +} + +template inline MatConstIterator_<_Tp> MatConstIterator_<_Tp>::operator ++(int) +{ + MatConstIterator_ b = *this; + MatConstIterator::operator ++(); + return b; +} + +template inline MatIterator_<_Tp>::MatIterator_() : MatConstIterator_<_Tp>() {} + +template inline MatIterator_<_Tp>::MatIterator_(Mat_<_Tp>* _m) + : MatConstIterator_<_Tp>(_m) {} + +template inline MatIterator_<_Tp>::MatIterator_(Mat_<_Tp>* _m, int _row, int _col) + : MatConstIterator_<_Tp>(_m, _row, _col) {} + +template inline MatIterator_<_Tp>::MatIterator_(const Mat_<_Tp>* _m, Point _pt) + : MatConstIterator_<_Tp>(_m, _pt) {} + +template inline MatIterator_<_Tp>::MatIterator_(const Mat_<_Tp>* _m, const int* _idx) + : MatConstIterator_<_Tp>(_m, _idx) {} + +template inline MatIterator_<_Tp>::MatIterator_(const MatIterator_& it) + : MatConstIterator_<_Tp>(it) {} + +template inline MatIterator_<_Tp>& MatIterator_<_Tp>::operator = (const MatIterator_<_Tp>& it ) +{ + MatConstIterator::operator = (it); + return *this; +} + +template inline _Tp& MatIterator_<_Tp>::operator *() const { return *(_Tp*)(this->ptr); } + +template inline MatIterator_<_Tp>& MatIterator_<_Tp>::operator += (ptrdiff_t ofs) +{ + MatConstIterator::operator += (ofs); + return *this; +} + +template inline MatIterator_<_Tp>& MatIterator_<_Tp>::operator -= (ptrdiff_t ofs) +{ + MatConstIterator::operator += (-ofs); + return *this; +} + +template inline MatIterator_<_Tp>& MatIterator_<_Tp>::operator --() +{ + MatConstIterator::operator --(); + return *this; +} + +template inline MatIterator_<_Tp> MatIterator_<_Tp>::operator --(int) +{ + MatIterator_ b = *this; + MatConstIterator::operator --(); + return b; +} + +template inline MatIterator_<_Tp>& MatIterator_<_Tp>::operator ++() +{ + MatConstIterator::operator ++(); + return *this; +} + +template inline MatIterator_<_Tp> MatIterator_<_Tp>::operator ++(int) +{ + MatIterator_ b = *this; + MatConstIterator::operator ++(); + return b; +} + +template inline Point MatConstIterator_<_Tp>::pos() const +{ + if( !m ) + return Point(); + CV_DbgAssert( m->dims <= 2 ); + if( m->isContinuous() ) + { + ptrdiff_t ofs = (const _Tp*)ptr - (const _Tp*)m->data; + int y = (int)(ofs / m->cols), x = (int)(ofs - (ptrdiff_t)y*m->cols); + return Point(x, y); + } + else + { + ptrdiff_t ofs = (uchar*)ptr - m->data; + int y = (int)(ofs / m->step), x = (int)((ofs - y*m->step)/sizeof(_Tp)); + return Point(x, y); + } +} + +static inline bool +operator == (const MatConstIterator& a, const MatConstIterator& b) +{ return a.m == b.m && a.ptr == b.ptr; } + +template static inline bool +operator != (const MatConstIterator& a, const MatConstIterator& b) +{ return !(a == b); } + +template static inline bool +operator == (const MatConstIterator_<_Tp>& a, const MatConstIterator_<_Tp>& b) +{ return a.m == b.m && a.ptr == b.ptr; } + +template static inline bool +operator != (const MatConstIterator_<_Tp>& a, const MatConstIterator_<_Tp>& b) +{ return a.m != b.m || a.ptr != b.ptr; } + +template static inline bool +operator == (const MatIterator_<_Tp>& a, const MatIterator_<_Tp>& b) +{ return a.m == b.m && a.ptr == b.ptr; } + +template static inline bool +operator != (const MatIterator_<_Tp>& a, const MatIterator_<_Tp>& b) +{ return a.m != b.m || a.ptr != b.ptr; } + +static inline bool +operator < (const MatConstIterator& a, const MatConstIterator& b) +{ return a.ptr < b.ptr; } + +static inline bool +operator > (const MatConstIterator& a, const MatConstIterator& b) +{ return a.ptr > b.ptr; } + +static inline bool +operator <= (const MatConstIterator& a, const MatConstIterator& b) +{ return a.ptr <= b.ptr; } + +static inline bool +operator >= (const MatConstIterator& a, const MatConstIterator& b) +{ return a.ptr >= b.ptr; } + +CV_EXPORTS ptrdiff_t operator - (const MatConstIterator& b, const MatConstIterator& a); + +static inline MatConstIterator operator + (const MatConstIterator& a, ptrdiff_t ofs) +{ MatConstIterator b = a; return b += ofs; } + +static inline MatConstIterator operator + (ptrdiff_t ofs, const MatConstIterator& a) +{ MatConstIterator b = a; return b += ofs; } + +static inline MatConstIterator operator - (const MatConstIterator& a, ptrdiff_t ofs) +{ MatConstIterator b = a; return b += -ofs; } + +template static inline MatConstIterator_<_Tp> +operator + (const MatConstIterator_<_Tp>& a, ptrdiff_t ofs) +{ MatConstIterator t = (const MatConstIterator&)a + ofs; return (MatConstIterator_<_Tp>&)t; } + +template static inline MatConstIterator_<_Tp> +operator + (ptrdiff_t ofs, const MatConstIterator_<_Tp>& a) +{ MatConstIterator t = (const MatConstIterator&)a + ofs; return (MatConstIterator_<_Tp>&)t; } + +template static inline MatConstIterator_<_Tp> +operator - (const MatConstIterator_<_Tp>& a, ptrdiff_t ofs) +{ MatConstIterator t = (const MatConstIterator&)a - ofs; return (MatConstIterator_<_Tp>&)t; } + +inline uchar* MatConstIterator::operator [](ptrdiff_t i) const +{ return *(*this + i); } + +template inline _Tp MatConstIterator_<_Tp>::operator [](ptrdiff_t i) const +{ return *(_Tp*)MatConstIterator::operator [](i); } + +template static inline MatIterator_<_Tp> +operator + (const MatIterator_<_Tp>& a, ptrdiff_t ofs) +{ MatConstIterator t = (const MatConstIterator&)a + ofs; return (MatIterator_<_Tp>&)t; } + +template static inline MatIterator_<_Tp> +operator + (ptrdiff_t ofs, const MatIterator_<_Tp>& a) +{ MatConstIterator t = (const MatConstIterator&)a + ofs; return (MatIterator_<_Tp>&)t; } + +template static inline MatIterator_<_Tp> +operator - (const MatIterator_<_Tp>& a, ptrdiff_t ofs) +{ MatConstIterator t = (const MatConstIterator&)a - ofs; return (MatIterator_<_Tp>&)t; } + +template inline _Tp& MatIterator_<_Tp>::operator [](ptrdiff_t i) const +{ return *(*this + i); } + +template inline MatConstIterator_<_Tp> Mat_<_Tp>::begin() const +{ return Mat::begin<_Tp>(); } + +template inline MatConstIterator_<_Tp> Mat_<_Tp>::end() const +{ return Mat::end<_Tp>(); } + +template inline MatIterator_<_Tp> Mat_<_Tp>::begin() +{ return Mat::begin<_Tp>(); } + +template inline MatIterator_<_Tp> Mat_<_Tp>::end() +{ return Mat::end<_Tp>(); } + +template inline MatCommaInitializer_<_Tp>::MatCommaInitializer_(Mat_<_Tp>* _m) : it(_m) {} + +template template inline MatCommaInitializer_<_Tp>& +MatCommaInitializer_<_Tp>::operator , (T2 v) +{ + CV_DbgAssert( this->it < ((const Mat_<_Tp>*)this->it.m)->end() ); + *this->it = _Tp(v); ++this->it; + return *this; +} + +template inline Mat_<_Tp> MatCommaInitializer_<_Tp>::operator *() const +{ + CV_DbgAssert( this->it == ((const Mat_<_Tp>*)this->it.m)->end() ); + return Mat_<_Tp>(*this->it.m); +} + +template inline MatCommaInitializer_<_Tp>::operator Mat_<_Tp>() const +{ + CV_DbgAssert( this->it == ((const Mat_<_Tp>*)this->it.m)->end() ); + return Mat_<_Tp>(*this->it.m); +} + +template static inline MatCommaInitializer_<_Tp> +operator << (const Mat_<_Tp>& m, T2 val) +{ + MatCommaInitializer_<_Tp> commaInitializer((Mat_<_Tp>*)&m); + return (commaInitializer, val); +} + +//////////////////////////////// SparseMat //////////////////////////////// + +inline SparseMat::SparseMat() +: flags(MAGIC_VAL), hdr(0) +{ +} + +inline SparseMat::SparseMat(int _dims, const int* _sizes, int _type) +: flags(MAGIC_VAL), hdr(0) +{ + create(_dims, _sizes, _type); +} + +inline SparseMat::SparseMat(const SparseMat& m) +: flags(m.flags), hdr(m.hdr) +{ + addref(); +} + +inline SparseMat::~SparseMat() +{ + release(); +} + +inline SparseMat& SparseMat::operator = (const SparseMat& m) +{ + if( this != &m ) + { + if( m.hdr ) + CV_XADD(&m.hdr->refcount, 1); + release(); + flags = m.flags; + hdr = m.hdr; + } + return *this; +} + +inline SparseMat& SparseMat::operator = (const Mat& m) +{ return (*this = SparseMat(m)); } + +inline SparseMat SparseMat::clone() const +{ + SparseMat temp; + this->copyTo(temp); + return temp; +} + + +inline void SparseMat::assignTo( SparseMat& m, int _type ) const +{ + if( _type < 0 ) + m = *this; + else + convertTo(m, _type); +} + +inline void SparseMat::addref() +{ if( hdr ) CV_XADD(&hdr->refcount, 1); } + +inline void SparseMat::release() +{ + if( hdr && CV_XADD(&hdr->refcount, -1) == 1 ) + delete hdr; + hdr = 0; +} + +inline size_t SparseMat::elemSize() const +{ return CV_ELEM_SIZE(flags); } + +inline size_t SparseMat::elemSize1() const +{ return CV_ELEM_SIZE1(flags); } + +inline int SparseMat::type() const +{ return CV_MAT_TYPE(flags); } + +inline int SparseMat::depth() const +{ return CV_MAT_DEPTH(flags); } + +inline int SparseMat::channels() const +{ return CV_MAT_CN(flags); } + +inline const int* SparseMat::size() const +{ + return hdr ? hdr->size : 0; +} + +inline int SparseMat::size(int i) const +{ + if( hdr ) + { + CV_DbgAssert((unsigned)i < (unsigned)hdr->dims); + return hdr->size[i]; + } + return 0; +} + +inline int SparseMat::dims() const +{ + return hdr ? hdr->dims : 0; +} + +inline size_t SparseMat::nzcount() const +{ + return hdr ? hdr->nodeCount : 0; +} + +inline size_t SparseMat::hash(int i0) const +{ + return (size_t)i0; +} + +inline size_t SparseMat::hash(int i0, int i1) const +{ + return (size_t)(unsigned)i0*HASH_SCALE + (unsigned)i1; +} + +inline size_t SparseMat::hash(int i0, int i1, int i2) const +{ + return ((size_t)(unsigned)i0*HASH_SCALE + (unsigned)i1)*HASH_SCALE + (unsigned)i2; +} + +inline size_t SparseMat::hash(const int* idx) const +{ + size_t h = (unsigned)idx[0]; + if( !hdr ) + return 0; + int i, d = hdr->dims; + for( i = 1; i < d; i++ ) + h = h*HASH_SCALE + (unsigned)idx[i]; + return h; +} + +template inline _Tp& SparseMat::ref(int i0, size_t* hashval) +{ return *(_Tp*)((SparseMat*)this)->ptr(i0, true, hashval); } + +template inline _Tp& SparseMat::ref(int i0, int i1, size_t* hashval) +{ return *(_Tp*)((SparseMat*)this)->ptr(i0, i1, true, hashval); } + +template inline _Tp& SparseMat::ref(int i0, int i1, int i2, size_t* hashval) +{ return *(_Tp*)((SparseMat*)this)->ptr(i0, i1, i2, true, hashval); } + +template inline _Tp& SparseMat::ref(const int* idx, size_t* hashval) +{ return *(_Tp*)((SparseMat*)this)->ptr(idx, true, hashval); } + +template inline _Tp SparseMat::value(int i0, size_t* hashval) const +{ + const _Tp* p = (const _Tp*)((SparseMat*)this)->ptr(i0, false, hashval); + return p ? *p : _Tp(); +} + +template inline _Tp SparseMat::value(int i0, int i1, size_t* hashval) const +{ + const _Tp* p = (const _Tp*)((SparseMat*)this)->ptr(i0, i1, false, hashval); + return p ? *p : _Tp(); +} + +template inline _Tp SparseMat::value(int i0, int i1, int i2, size_t* hashval) const +{ + const _Tp* p = (const _Tp*)((SparseMat*)this)->ptr(i0, i1, i2, false, hashval); + return p ? *p : _Tp(); +} + +template inline _Tp SparseMat::value(const int* idx, size_t* hashval) const +{ + const _Tp* p = (const _Tp*)((SparseMat*)this)->ptr(idx, false, hashval); + return p ? *p : _Tp(); +} + +template inline const _Tp* SparseMat::find(int i0, size_t* hashval) const +{ return (const _Tp*)((SparseMat*)this)->ptr(i0, false, hashval); } + +template inline const _Tp* SparseMat::find(int i0, int i1, size_t* hashval) const +{ return (const _Tp*)((SparseMat*)this)->ptr(i0, i1, false, hashval); } + +template inline const _Tp* SparseMat::find(int i0, int i1, int i2, size_t* hashval) const +{ return (const _Tp*)((SparseMat*)this)->ptr(i0, i1, i2, false, hashval); } + +template inline const _Tp* SparseMat::find(const int* idx, size_t* hashval) const +{ return (const _Tp*)((SparseMat*)this)->ptr(idx, false, hashval); } + +template inline _Tp& SparseMat::value(Node* n) +{ return *(_Tp*)((uchar*)n + hdr->valueOffset); } + +template inline const _Tp& SparseMat::value(const Node* n) const +{ return *(const _Tp*)((const uchar*)n + hdr->valueOffset); } + +inline SparseMat::Node* SparseMat::node(size_t nidx) +{ return (Node*)&hdr->pool[nidx]; } + +inline const SparseMat::Node* SparseMat::node(size_t nidx) const +{ return (const Node*)&hdr->pool[nidx]; } + +inline SparseMatIterator SparseMat::begin() +{ return SparseMatIterator(this); } + +inline SparseMatConstIterator SparseMat::begin() const +{ return SparseMatConstIterator(this); } + +inline SparseMatIterator SparseMat::end() +{ SparseMatIterator it(this); it.seekEnd(); return it; } + +inline SparseMatConstIterator SparseMat::end() const +{ SparseMatConstIterator it(this); it.seekEnd(); return it; } + +template inline SparseMatIterator_<_Tp> SparseMat::begin() +{ return SparseMatIterator_<_Tp>(this); } + +template inline SparseMatConstIterator_<_Tp> SparseMat::begin() const +{ return SparseMatConstIterator_<_Tp>(this); } + +template inline SparseMatIterator_<_Tp> SparseMat::end() +{ SparseMatIterator_<_Tp> it(this); it.seekEnd(); return it; } + +template inline SparseMatConstIterator_<_Tp> SparseMat::end() const +{ SparseMatConstIterator_<_Tp> it(this); it.seekEnd(); return it; } + + +inline SparseMatConstIterator::SparseMatConstIterator() +: m(0), hashidx(0), ptr(0) +{ +} + +inline SparseMatConstIterator::SparseMatConstIterator(const SparseMatConstIterator& it) +: m(it.m), hashidx(it.hashidx), ptr(it.ptr) +{ +} + +static inline bool operator == (const SparseMatConstIterator& it1, const SparseMatConstIterator& it2) +{ return it1.m == it2.m && it1.ptr == it2.ptr; } + +static inline bool operator != (const SparseMatConstIterator& it1, const SparseMatConstIterator& it2) +{ return !(it1 == it2); } + + +inline SparseMatConstIterator& SparseMatConstIterator::operator = (const SparseMatConstIterator& it) +{ + if( this != &it ) + { + m = it.m; + hashidx = it.hashidx; + ptr = it.ptr; + } + return *this; +} + +template inline const _Tp& SparseMatConstIterator::value() const +{ return *(_Tp*)ptr; } + +inline const SparseMat::Node* SparseMatConstIterator::node() const +{ + return ptr && m && m->hdr ? + (const SparseMat::Node*)(ptr - m->hdr->valueOffset) : 0; +} + +inline SparseMatConstIterator SparseMatConstIterator::operator ++(int) +{ + SparseMatConstIterator it = *this; + ++*this; + return it; +} + + +inline void SparseMatConstIterator::seekEnd() +{ + if( m && m->hdr ) + { + hashidx = m->hdr->hashtab.size(); + ptr = 0; + } +} + +inline SparseMatIterator::SparseMatIterator() +{} + +inline SparseMatIterator::SparseMatIterator(SparseMat* _m) +: SparseMatConstIterator(_m) +{} + +inline SparseMatIterator::SparseMatIterator(const SparseMatIterator& it) +: SparseMatConstIterator(it) +{ +} + +inline SparseMatIterator& SparseMatIterator::operator = (const SparseMatIterator& it) +{ + (SparseMatConstIterator&)*this = it; + return *this; +} + +template inline _Tp& SparseMatIterator::value() const +{ return *(_Tp*)ptr; } + +inline SparseMat::Node* SparseMatIterator::node() const +{ + return (SparseMat::Node*)SparseMatConstIterator::node(); +} + +inline SparseMatIterator& SparseMatIterator::operator ++() +{ + SparseMatConstIterator::operator ++(); + return *this; +} + +inline SparseMatIterator SparseMatIterator::operator ++(int) +{ + SparseMatIterator it = *this; + ++*this; + return it; +} + + +template inline SparseMat_<_Tp>::SparseMat_() +{ flags = MAGIC_VAL | DataType<_Tp>::type; } + +template inline SparseMat_<_Tp>::SparseMat_(int _dims, const int* _sizes) +: SparseMat(_dims, _sizes, DataType<_Tp>::type) +{} + +template inline SparseMat_<_Tp>::SparseMat_(const SparseMat& m) +{ + if( m.type() == DataType<_Tp>::type ) + *this = (const SparseMat_<_Tp>&)m; + else + m.convertTo(this, DataType<_Tp>::type); +} + +template inline SparseMat_<_Tp>::SparseMat_(const SparseMat_<_Tp>& m) +{ + this->flags = m.flags; + this->hdr = m.hdr; + if( this->hdr ) + CV_XADD(&this->hdr->refcount, 1); +} + +template inline SparseMat_<_Tp>::SparseMat_(const Mat& m) +{ + SparseMat sm(m); + *this = sm; +} + +template inline SparseMat_<_Tp>::SparseMat_(const CvSparseMat* m) +{ + SparseMat sm(m); + *this = sm; +} + +template inline SparseMat_<_Tp>& +SparseMat_<_Tp>::operator = (const SparseMat_<_Tp>& m) +{ + if( this != &m ) + { + if( m.hdr ) CV_XADD(&m.hdr->refcount, 1); + release(); + flags = m.flags; + hdr = m.hdr; + } + return *this; +} + +template inline SparseMat_<_Tp>& +SparseMat_<_Tp>::operator = (const SparseMat& m) +{ + if( m.type() == DataType<_Tp>::type ) + return (*this = (const SparseMat_<_Tp>&)m); + m.convertTo(*this, DataType<_Tp>::type); + return *this; +} + +template inline SparseMat_<_Tp>& +SparseMat_<_Tp>::operator = (const Mat& m) +{ return (*this = SparseMat(m)); } + +template inline SparseMat_<_Tp> +SparseMat_<_Tp>::clone() const +{ + SparseMat_<_Tp> m; + this->copyTo(m); + return m; +} + +template inline void +SparseMat_<_Tp>::create(int _dims, const int* _sizes) +{ + SparseMat::create(_dims, _sizes, DataType<_Tp>::type); +} + +template inline +SparseMat_<_Tp>::operator CvSparseMat*() const +{ + return SparseMat::operator CvSparseMat*(); +} + +template inline int SparseMat_<_Tp>::type() const +{ return DataType<_Tp>::type; } + +template inline int SparseMat_<_Tp>::depth() const +{ return DataType<_Tp>::depth; } + +template inline int SparseMat_<_Tp>::channels() const +{ return DataType<_Tp>::channels; } + +template inline _Tp& +SparseMat_<_Tp>::ref(int i0, size_t* hashval) +{ return SparseMat::ref<_Tp>(i0, hashval); } + +template inline _Tp +SparseMat_<_Tp>::operator()(int i0, size_t* hashval) const +{ return SparseMat::value<_Tp>(i0, hashval); } + +template inline _Tp& +SparseMat_<_Tp>::ref(int i0, int i1, size_t* hashval) +{ return SparseMat::ref<_Tp>(i0, i1, hashval); } + +template inline _Tp +SparseMat_<_Tp>::operator()(int i0, int i1, size_t* hashval) const +{ return SparseMat::value<_Tp>(i0, i1, hashval); } + +template inline _Tp& +SparseMat_<_Tp>::ref(int i0, int i1, int i2, size_t* hashval) +{ return SparseMat::ref<_Tp>(i0, i1, i2, hashval); } + +template inline _Tp +SparseMat_<_Tp>::operator()(int i0, int i1, int i2, size_t* hashval) const +{ return SparseMat::value<_Tp>(i0, i1, i2, hashval); } + +template inline _Tp& +SparseMat_<_Tp>::ref(const int* idx, size_t* hashval) +{ return SparseMat::ref<_Tp>(idx, hashval); } + +template inline _Tp +SparseMat_<_Tp>::operator()(const int* idx, size_t* hashval) const +{ return SparseMat::value<_Tp>(idx, hashval); } + +template inline SparseMatIterator_<_Tp> SparseMat_<_Tp>::begin() +{ return SparseMatIterator_<_Tp>(this); } + +template inline SparseMatConstIterator_<_Tp> SparseMat_<_Tp>::begin() const +{ return SparseMatConstIterator_<_Tp>(this); } + +template inline SparseMatIterator_<_Tp> SparseMat_<_Tp>::end() +{ SparseMatIterator_<_Tp> it(this); it.seekEnd(); return it; } + +template inline SparseMatConstIterator_<_Tp> SparseMat_<_Tp>::end() const +{ SparseMatConstIterator_<_Tp> it(this); it.seekEnd(); return it; } + +template inline +SparseMatConstIterator_<_Tp>::SparseMatConstIterator_() +{} + +template inline +SparseMatConstIterator_<_Tp>::SparseMatConstIterator_(const SparseMat_<_Tp>* _m) +: SparseMatConstIterator(_m) +{} + +template inline +SparseMatConstIterator_<_Tp>::SparseMatConstIterator_(const SparseMatConstIterator_<_Tp>& it) +: SparseMatConstIterator(it) +{} + +template inline SparseMatConstIterator_<_Tp>& +SparseMatConstIterator_<_Tp>::operator = (const SparseMatConstIterator_<_Tp>& it) +{ return reinterpret_cast&> + (*reinterpret_cast(this) = + reinterpret_cast(it)); } + +template inline const _Tp& +SparseMatConstIterator_<_Tp>::operator *() const +{ return *(const _Tp*)this->ptr; } + +template inline SparseMatConstIterator_<_Tp>& +SparseMatConstIterator_<_Tp>::operator ++() +{ + SparseMatConstIterator::operator ++(); + return *this; +} + +template inline SparseMatConstIterator_<_Tp> +SparseMatConstIterator_<_Tp>::operator ++(int) +{ + SparseMatConstIterator it = *this; + SparseMatConstIterator::operator ++(); + return it; +} + +template inline +SparseMatIterator_<_Tp>::SparseMatIterator_() +{} + +template inline +SparseMatIterator_<_Tp>::SparseMatIterator_(SparseMat_<_Tp>* _m) +: SparseMatConstIterator_<_Tp>(_m) +{} + +template inline +SparseMatIterator_<_Tp>::SparseMatIterator_(const SparseMatIterator_<_Tp>& it) +: SparseMatConstIterator_<_Tp>(it) +{} + +template inline SparseMatIterator_<_Tp>& +SparseMatIterator_<_Tp>::operator = (const SparseMatIterator_<_Tp>& it) +{ return reinterpret_cast&> + (*reinterpret_cast(this) = + reinterpret_cast(it)); } + +template inline _Tp& +SparseMatIterator_<_Tp>::operator *() const +{ return *(_Tp*)this->ptr; } + +template inline SparseMatIterator_<_Tp>& +SparseMatIterator_<_Tp>::operator ++() +{ + SparseMatConstIterator::operator ++(); + return *this; +} + +template inline SparseMatIterator_<_Tp> +SparseMatIterator_<_Tp>::operator ++(int) +{ + SparseMatIterator it = *this; + SparseMatConstIterator::operator ++(); + return it; +} + +} + +#endif +#endif diff --git a/core/include/opencv2/core/opengl_interop.hpp b/core/include/opencv2/core/opengl_interop.hpp new file mode 100644 index 0000000..c039a1f --- /dev/null +++ b/core/include/opencv2/core/opengl_interop.hpp @@ -0,0 +1,335 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other GpuMaterials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_OPENGL_INTEROP_HPP__ +#define __OPENCV_OPENGL_INTEROP_HPP__ + +#ifdef __cplusplus + +#include "opencv2/core/core.hpp" + +namespace cv +{ +//! Smart pointer for OpenGL buffer memory with reference counting. +class CV_EXPORTS GlBuffer +{ +public: + enum Usage + { + ARRAY_BUFFER = 0x8892, // buffer will use for OpenGL arrays (vertices, colors, normals, etc) + TEXTURE_BUFFER = 0x88EC // buffer will ise for OpenGL textures + }; + + //! create empty buffer + explicit GlBuffer(Usage usage); + + //! create buffer + GlBuffer(int rows, int cols, int type, Usage usage); + GlBuffer(Size size, int type, Usage usage); + + //! copy from host/device memory + GlBuffer(InputArray mat, Usage usage); + + void create(int rows, int cols, int type, Usage usage); + void create(Size size, int type, Usage usage); + void create(int rows, int cols, int type); + void create(Size size, int type); + + void release(); + + //! copy from host/device memory + void copyFrom(InputArray mat); + + void bind() const; + void unbind() const; + + //! map to host memory + Mat mapHost(); + void unmapHost(); + + //! map to device memory + gpu::GpuMat mapDevice(); + void unmapDevice(); + + inline int rows() const { return rows_; } + inline int cols() const { return cols_; } + inline Size size() const { return Size(cols_, rows_); } + inline bool empty() const { return rows_ == 0 || cols_ == 0; } + + inline int type() const { return type_; } + inline int depth() const { return CV_MAT_DEPTH(type_); } + inline int channels() const { return CV_MAT_CN(type_); } + inline int elemSize() const { return CV_ELEM_SIZE(type_); } + inline int elemSize1() const { return CV_ELEM_SIZE1(type_); } + + inline Usage usage() const { return usage_; } + + class Impl; +private: + int rows_; + int cols_; + int type_; + Usage usage_; + + Ptr impl_; +}; + +template <> CV_EXPORTS void Ptr::delete_obj(); + +//! Smart pointer for OpenGL 2d texture memory with reference counting. +class CV_EXPORTS GlTexture +{ +public: + //! create empty texture + GlTexture(); + + //! create texture + GlTexture(int rows, int cols, int type); + GlTexture(Size size, int type); + + //! copy from host/device memory + explicit GlTexture(InputArray mat, bool bgra = true); + + void create(int rows, int cols, int type); + void create(Size size, int type); + void release(); + + //! copy from host/device memory + void copyFrom(InputArray mat, bool bgra = true); + + void bind() const; + void unbind() const; + + inline int rows() const { return rows_; } + inline int cols() const { return cols_; } + inline Size size() const { return Size(cols_, rows_); } + inline bool empty() const { return rows_ == 0 || cols_ == 0; } + + inline int type() const { return type_; } + inline int depth() const { return CV_MAT_DEPTH(type_); } + inline int channels() const { return CV_MAT_CN(type_); } + inline int elemSize() const { return CV_ELEM_SIZE(type_); } + inline int elemSize1() const { return CV_ELEM_SIZE1(type_); } + + class Impl; +private: + int rows_; + int cols_; + int type_; + + Ptr impl_; + GlBuffer buf_; +}; + +template <> CV_EXPORTS void Ptr::delete_obj(); + +//! OpenGL Arrays +class CV_EXPORTS GlArrays +{ +public: + inline GlArrays() + : vertex_(GlBuffer::ARRAY_BUFFER), color_(GlBuffer::ARRAY_BUFFER), bgra_(true), normal_(GlBuffer::ARRAY_BUFFER), texCoord_(GlBuffer::ARRAY_BUFFER) + { + } + + void setVertexArray(InputArray vertex); + inline void resetVertexArray() { vertex_.release(); } + + void setColorArray(InputArray color, bool bgra = true); + inline void resetColorArray() { color_.release(); } + + void setNormalArray(InputArray normal); + inline void resetNormalArray() { normal_.release(); } + + void setTexCoordArray(InputArray texCoord); + inline void resetTexCoordArray() { texCoord_.release(); } + + void bind() const; + void unbind() const; + + inline int rows() const { return vertex_.rows(); } + inline int cols() const { return vertex_.cols(); } + inline Size size() const { return vertex_.size(); } + inline bool empty() const { return vertex_.empty(); } + +private: + GlBuffer vertex_; + GlBuffer color_; + bool bgra_; + GlBuffer normal_; + GlBuffer texCoord_; +}; + +//! OpenGL Font +class CV_EXPORTS GlFont +{ +public: + enum Weight + { + WEIGHT_LIGHT = 300, + WEIGHT_NORMAL = 400, + WEIGHT_SEMIBOLD = 600, + WEIGHT_BOLD = 700, + WEIGHT_BLACK = 900 + }; + + enum Style + { + STYLE_NORMAL = 0, + STYLE_ITALIC = 1, + STYLE_UNDERLINE = 2 + }; + + static Ptr get(const std::string& family, int height = 12, Weight weight = WEIGHT_NORMAL, Style style = STYLE_NORMAL); + + void draw(const char* str, size_t len) const; + + inline const std::string& family() const { return family_; } + inline int height() const { return height_; } + inline Weight weight() const { return weight_; } + inline Style style() const { return style_; } + +private: + GlFont(const std::string& family, int height, Weight weight, Style style); + + std::string family_; + int height_; + Weight weight_; + Style style_; + + unsigned int base_; + + GlFont(const GlFont&); + GlFont& operator =(const GlFont&); +}; + +//! render functions + +//! render texture rectangle in window +CV_EXPORTS void render(const GlTexture& tex, + Rect_ wndRect = Rect_(0.0, 0.0, 1.0, 1.0), + Rect_ texRect = Rect_(0.0, 0.0, 1.0, 1.0)); + +//! render mode +namespace RenderMode { + enum { + POINTS = 0x0000, + LINES = 0x0001, + LINE_LOOP = 0x0002, + LINE_STRIP = 0x0003, + TRIANGLES = 0x0004, + TRIANGLE_STRIP = 0x0005, + TRIANGLE_FAN = 0x0006, + QUADS = 0x0007, + QUAD_STRIP = 0x0008, + POLYGON = 0x0009 + }; +} + +//! render OpenGL arrays +CV_EXPORTS void render(const GlArrays& arr, int mode = RenderMode::POINTS, Scalar color = Scalar::all(255)); + +CV_EXPORTS void render(const std::string& str, const Ptr& font, Scalar color, Point2d pos); + +//! OpenGL camera +class CV_EXPORTS GlCamera +{ +public: + GlCamera(); + + void lookAt(Point3d eye, Point3d center, Point3d up); + void setCameraPos(Point3d pos, double yaw, double pitch, double roll); + + void setScale(Point3d scale); + + void setProjectionMatrix(const Mat& projectionMatrix, bool transpose = true); + void setPerspectiveProjection(double fov, double aspect, double zNear, double zFar); + void setOrthoProjection(double left, double right, double bottom, double top, double zNear, double zFar); + + void setupProjectionMatrix() const; + void setupModelViewMatrix() const; + +private: + Point3d eye_; + Point3d center_; + Point3d up_; + + Point3d pos_; + double yaw_; + double pitch_; + double roll_; + + bool useLookAtParams_; + + Point3d scale_; + + Mat projectionMatrix_; + + double fov_; + double aspect_; + + double left_; + double right_; + double bottom_; + double top_; + + double zNear_; + double zFar_; + + bool perspectiveProjection_; +}; + +inline void GlBuffer::create(Size _size, int _type, Usage _usage) { create(_size.height, _size.width, _type, _usage); } +inline void GlBuffer::create(int _rows, int _cols, int _type) { create(_rows, _cols, _type, usage()); } +inline void GlBuffer::create(Size _size, int _type) { create(_size.height, _size.width, _type, usage()); } +inline void GlTexture::create(Size _size, int _type) { create(_size.height, _size.width, _type); } + +namespace gpu +{ + //! set a CUDA device to use OpenGL interoperability + CV_EXPORTS void setGlDevice(int device = 0); +} +} // namespace cv + +#endif // __cplusplus + +#endif // __OPENCV_OPENGL_INTEROP_HPP__ diff --git a/core/include/opencv2/core/operations.hpp b/core/include/opencv2/core/operations.hpp new file mode 100644 index 0000000..af89bbf --- /dev/null +++ b/core/include/opencv2/core/operations.hpp @@ -0,0 +1,3924 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_CORE_OPERATIONS_HPP__ +#define __OPENCV_CORE_OPERATIONS_HPP__ + +#ifndef SKIP_INCLUDES + #include + #include +#endif // SKIP_INCLUDES + + +#ifdef __cplusplus + +/////// exchange-add operation for atomic operations on reference counters /////// +#if defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32) // atomic increment on the linux version of the Intel(tm) compiler + #define CV_XADD(addr,delta) _InterlockedExchangeAdd(const_cast(reinterpret_cast(addr)), delta) +#elif defined __GNUC__ + + #if __GNUC__*10 + __GNUC_MINOR__ >= 42 + + #if !defined WIN32 && (defined __i486__ || defined __i586__ || \ + defined __i686__ || defined __MMX__ || defined __SSE__ || defined __ppc__) + #define CV_XADD __sync_fetch_and_add + #else + #include + #define CV_XADD __gnu_cxx::__exchange_and_add + #endif + + #else + #include + #if __GNUC__*10 + __GNUC_MINOR__ >= 34 + #define CV_XADD __gnu_cxx::__exchange_and_add + #else + #define CV_XADD __exchange_and_add + #endif + #endif + +#elif defined WIN32 || defined _WIN32 + #define WIN32_MEAN_AND_LEAN + #ifndef _WIN32_WINNT // This is needed for the declaration of TryEnterCriticalSection in winbase.h with Visual Studio 2005 (and older?) + #define _WIN32_WINNT 0x0400 // http://msdn.microsoft.com/en-us/library/ms686857(VS.85).aspx + #endif + #include + #undef min + #undef max + #undef abs + #define CV_XADD(addr,delta) InterlockedExchangeAdd((long volatile*)(addr), (delta)) + +#else + static inline int CV_XADD(int* addr, int delta) + { int tmp = *addr; *addr += delta; return tmp; } +#endif + +#include + +namespace cv +{ + +using std::cos; +using std::sin; +using std::max; +using std::min; +using std::exp; +using std::log; +using std::pow; +using std::sqrt; + + +/////////////// saturate_cast (used in image & signal processing) /////////////////// + +template static inline _Tp saturate_cast(uchar v) { return _Tp(v); } +template static inline _Tp saturate_cast(schar v) { return _Tp(v); } +template static inline _Tp saturate_cast(ushort v) { return _Tp(v); } +template static inline _Tp saturate_cast(short v) { return _Tp(v); } +template static inline _Tp saturate_cast(unsigned v) { return _Tp(v); } +template static inline _Tp saturate_cast(int v) { return _Tp(v); } +template static inline _Tp saturate_cast(float v) { return _Tp(v); } +template static inline _Tp saturate_cast(double v) { return _Tp(v); } + +template<> inline uchar saturate_cast(schar v) +{ return (uchar)std::max((int)v, 0); } +template<> inline uchar saturate_cast(ushort v) +{ return (uchar)std::min((unsigned)v, (unsigned)UCHAR_MAX); } +template<> inline uchar saturate_cast(int v) +{ return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); } +template<> inline uchar saturate_cast(short v) +{ return saturate_cast((int)v); } +template<> inline uchar saturate_cast(unsigned v) +{ return (uchar)std::min(v, (unsigned)UCHAR_MAX); } +template<> inline uchar saturate_cast(float v) +{ int iv = cvRound(v); return saturate_cast(iv); } +template<> inline uchar saturate_cast(double v) +{ int iv = cvRound(v); return saturate_cast(iv); } + +template<> inline schar saturate_cast(uchar v) +{ return (schar)std::min((int)v, SCHAR_MAX); } +template<> inline schar saturate_cast(ushort v) +{ return (schar)std::min((unsigned)v, (unsigned)SCHAR_MAX); } +template<> inline schar saturate_cast(int v) +{ + return (schar)((unsigned)(v-SCHAR_MIN) <= (unsigned)UCHAR_MAX ? + v : v > 0 ? SCHAR_MAX : SCHAR_MIN); +} +template<> inline schar saturate_cast(short v) +{ return saturate_cast((int)v); } +template<> inline schar saturate_cast(unsigned v) +{ return (schar)std::min(v, (unsigned)SCHAR_MAX); } + +template<> inline schar saturate_cast(float v) +{ int iv = cvRound(v); return saturate_cast(iv); } +template<> inline schar saturate_cast(double v) +{ int iv = cvRound(v); return saturate_cast(iv); } + +template<> inline ushort saturate_cast(schar v) +{ return (ushort)std::max((int)v, 0); } +template<> inline ushort saturate_cast(short v) +{ return (ushort)std::max((int)v, 0); } +template<> inline ushort saturate_cast(int v) +{ return (ushort)((unsigned)v <= (unsigned)USHRT_MAX ? v : v > 0 ? USHRT_MAX : 0); } +template<> inline ushort saturate_cast(unsigned v) +{ return (ushort)std::min(v, (unsigned)USHRT_MAX); } +template<> inline ushort saturate_cast(float v) +{ int iv = cvRound(v); return saturate_cast(iv); } +template<> inline ushort saturate_cast(double v) +{ int iv = cvRound(v); return saturate_cast(iv); } + +template<> inline short saturate_cast(ushort v) +{ return (short)std::min((int)v, SHRT_MAX); } +template<> inline short saturate_cast(int v) +{ + return (short)((unsigned)(v - SHRT_MIN) <= (unsigned)USHRT_MAX ? + v : v > 0 ? SHRT_MAX : SHRT_MIN); +} +template<> inline short saturate_cast(unsigned v) +{ return (short)std::min(v, (unsigned)SHRT_MAX); } +template<> inline short saturate_cast(float v) +{ int iv = cvRound(v); return saturate_cast(iv); } +template<> inline short saturate_cast(double v) +{ int iv = cvRound(v); return saturate_cast(iv); } + +template<> inline int saturate_cast(float v) { return cvRound(v); } +template<> inline int saturate_cast(double v) { return cvRound(v); } + +// we intentionally do not clip negative numbers, to make -1 become 0xffffffff etc. +template<> inline unsigned saturate_cast(float v){ return cvRound(v); } +template<> inline unsigned saturate_cast(double v) { return cvRound(v); } + +inline int fast_abs(uchar v) { return v; } +inline int fast_abs(schar v) { return std::abs((int)v); } +inline int fast_abs(ushort v) { return v; } +inline int fast_abs(short v) { return std::abs((int)v); } +inline int fast_abs(int v) { return std::abs(v); } +inline float fast_abs(float v) { return std::abs(v); } +inline double fast_abs(double v) { return std::abs(v); } + +//////////////////////////////// Matx ///////////////////////////////// + + +template inline Matx<_Tp, m, n>::Matx() +{ + for(int i = 0; i < channels; i++) val[i] = _Tp(0); +} + +template inline Matx<_Tp, m, n>::Matx(_Tp v0) +{ + val[0] = v0; + for(int i = 1; i < channels; i++) val[i] = _Tp(0); +} + +template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1) +{ + assert(channels >= 2); + val[0] = v0; val[1] = v1; + for(int i = 2; i < channels; i++) val[i] = _Tp(0); +} + +template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2) +{ + assert(channels >= 3); + val[0] = v0; val[1] = v1; val[2] = v2; + for(int i = 3; i < channels; i++) val[i] = _Tp(0); +} + +template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3) +{ + assert(channels >= 4); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + for(int i = 4; i < channels; i++) val[i] = _Tp(0); +} + +template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4) +{ + assert(channels >= 5); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; + for(int i = 5; i < channels; i++) val[i] = _Tp(0); +} + +template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5) +{ + assert(channels >= 6); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; + for(int i = 6; i < channels; i++) val[i] = _Tp(0); +} + +template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6) +{ + assert(channels >= 7); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; + for(int i = 7; i < channels; i++) val[i] = _Tp(0); +} + +template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7) +{ + assert(channels >= 8); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; + for(int i = 8; i < channels; i++) val[i] = _Tp(0); +} + +template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7, + _Tp v8) +{ + assert(channels >= 9); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; + val[8] = v8; + for(int i = 9; i < channels; i++) val[i] = _Tp(0); +} + +template inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7, + _Tp v8, _Tp v9) +{ + assert(channels >= 10); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; + val[8] = v8; val[9] = v9; + for(int i = 10; i < channels; i++) val[i] = _Tp(0); +} + + +template +inline Matx<_Tp,m,n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7, + _Tp v8, _Tp v9, _Tp v10, _Tp v11) +{ + assert(channels == 12); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; + val[8] = v8; val[9] = v9; val[10] = v10; val[11] = v11; +} + +template +inline Matx<_Tp,m,n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7, + _Tp v8, _Tp v9, _Tp v10, _Tp v11, + _Tp v12, _Tp v13, _Tp v14, _Tp v15) +{ + assert(channels == 16); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; + val[8] = v8; val[9] = v9; val[10] = v10; val[11] = v11; + val[12] = v12; val[13] = v13; val[14] = v14; val[15] = v15; +} + +template inline Matx<_Tp, m, n>::Matx(const _Tp* values) +{ + for( int i = 0; i < channels; i++ ) val[i] = values[i]; +} + +template inline Matx<_Tp, m, n> Matx<_Tp, m, n>::all(_Tp alpha) +{ + Matx<_Tp, m, n> M; + for( int i = 0; i < m*n; i++ ) M.val[i] = alpha; + return M; +} + +template inline +Matx<_Tp,m,n> Matx<_Tp,m,n>::zeros() +{ + return all(0); +} + +template inline +Matx<_Tp,m,n> Matx<_Tp,m,n>::ones() +{ + return all(1); +} + +template inline +Matx<_Tp,m,n> Matx<_Tp,m,n>::eye() +{ + Matx<_Tp,m,n> M; + for(int i = 0; i < MIN(m,n); i++) + M(i,i) = 1; + return M; +} + +template inline _Tp Matx<_Tp, m, n>::dot(const Matx<_Tp, m, n>& M) const +{ + _Tp s = 0; + for( int i = 0; i < m*n; i++ ) s += val[i]*M.val[i]; + return s; +} + + +template inline double Matx<_Tp, m, n>::ddot(const Matx<_Tp, m, n>& M) const +{ + double s = 0; + for( int i = 0; i < m*n; i++ ) s += (double)val[i]*M.val[i]; + return s; +} + + + +template inline +Matx<_Tp,m,n> Matx<_Tp,m,n>::diag(const typename Matx<_Tp,m,n>::diag_type& d) +{ + Matx<_Tp,m,n> M; + for(int i = 0; i < MIN(m,n); i++) + M(i,i) = d(i, 0); + return M; +} + +template inline +Matx<_Tp,m,n> Matx<_Tp,m,n>::randu(_Tp a, _Tp b) +{ + Matx<_Tp,m,n> M; + Mat matM(M, false); + cv::randu(matM, Scalar(a), Scalar(b)); + return M; +} + +template inline +Matx<_Tp,m,n> Matx<_Tp,m,n>::randn(_Tp a, _Tp b) +{ + Matx<_Tp,m,n> M; + Mat matM(M, false); + cv::randn(matM, Scalar(a), Scalar(b)); + return M; +} + +template template +inline Matx<_Tp, m, n>::operator Matx() const +{ + Matx M; + for( int i = 0; i < m*n; i++ ) M.val[i] = saturate_cast(val[i]); + return M; +} + + +template template inline +Matx<_Tp, m1, n1> Matx<_Tp, m, n>::reshape() const +{ + CV_DbgAssert(m1*n1 == m*n); + return (const Matx<_Tp, m1, n1>&)*this; +} + + +template +template inline +Matx<_Tp, m1, n1> Matx<_Tp, m, n>::get_minor(int i, int j) const +{ + CV_DbgAssert(0 <= i && i+m1 <= m && 0 <= j && j+n1 <= n); + Matx<_Tp, m1, n1> s; + for( int di = 0; di < m1; di++ ) + for( int dj = 0; dj < n1; dj++ ) + s(di, dj) = (*this)(i+di, j+dj); + return s; +} + + +template inline +Matx<_Tp, 1, n> Matx<_Tp, m, n>::row(int i) const +{ + CV_DbgAssert((unsigned)i < (unsigned)m); + return Matx<_Tp, 1, n>(&val[i*n]); +} + + +template inline +Matx<_Tp, m, 1> Matx<_Tp, m, n>::col(int j) const +{ + CV_DbgAssert((unsigned)j < (unsigned)n); + Matx<_Tp, m, 1> v; + for( int i = 0; i < m; i++ ) + v.val[i] = val[i*n + j]; + return v; +} + + +template inline +typename Matx<_Tp, m, n>::diag_type Matx<_Tp, m, n>::diag() const +{ + diag_type d; + for( int i = 0; i < MIN(m, n); i++ ) + d.val[i] = val[i*n + i]; + return d; +} + + +template inline +const _Tp& Matx<_Tp, m, n>::operator ()(int i, int j) const +{ + CV_DbgAssert( (unsigned)i < (unsigned)m && (unsigned)j < (unsigned)n ); + return this->val[i*n + j]; +} + + +template inline +_Tp& Matx<_Tp, m, n>::operator ()(int i, int j) +{ + CV_DbgAssert( (unsigned)i < (unsigned)m && (unsigned)j < (unsigned)n ); + return val[i*n + j]; +} + + +template inline +const _Tp& Matx<_Tp, m, n>::operator ()(int i) const +{ + CV_DbgAssert( (m == 1 || n == 1) && (unsigned)i < (unsigned)(m+n-1) ); + return val[i]; +} + + +template inline +_Tp& Matx<_Tp, m, n>::operator ()(int i) +{ + CV_DbgAssert( (m == 1 || n == 1) && (unsigned)i < (unsigned)(m+n-1) ); + return val[i]; +} + + +template static inline +Matx<_Tp1, m, n>& operator += (Matx<_Tp1, m, n>& a, const Matx<_Tp2, m, n>& b) +{ + for( int i = 0; i < m*n; i++ ) + a.val[i] = saturate_cast<_Tp1>(a.val[i] + b.val[i]); + return a; +} + + +template static inline +Matx<_Tp1, m, n>& operator -= (Matx<_Tp1, m, n>& a, const Matx<_Tp2, m, n>& b) +{ + for( int i = 0; i < m*n; i++ ) + a.val[i] = saturate_cast<_Tp1>(a.val[i] - b.val[i]); + return a; +} + + +template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_AddOp) +{ + for( int i = 0; i < m*n; i++ ) + val[i] = saturate_cast<_Tp>(a.val[i] + b.val[i]); +} + + +template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_SubOp) +{ + for( int i = 0; i < m*n; i++ ) + val[i] = saturate_cast<_Tp>(a.val[i] - b.val[i]); +} + + +template template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, n>& a, _T2 alpha, Matx_ScaleOp) +{ + for( int i = 0; i < m*n; i++ ) + val[i] = saturate_cast<_Tp>(a.val[i] * alpha); +} + + +template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_MulOp) +{ + for( int i = 0; i < m*n; i++ ) + val[i] = saturate_cast<_Tp>(a.val[i] * b.val[i]); +} + + +template template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b, Matx_MatMulOp) +{ + for( int i = 0; i < m; i++ ) + for( int j = 0; j < n; j++ ) + { + _Tp s = 0; + for( int k = 0; k < l; k++ ) + s += a(i, k) * b(k, j); + val[i*n + j] = s; + } +} + + +template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, n, m>& a, Matx_TOp) +{ + for( int i = 0; i < m; i++ ) + for( int j = 0; j < n; j++ ) + val[i*n + j] = a(j, i); +} + + +template static inline +Matx<_Tp, m, n> operator + (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b) +{ + return Matx<_Tp, m, n>(a, b, Matx_AddOp()); +} + + +template static inline +Matx<_Tp, m, n> operator - (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b) +{ + return Matx<_Tp, m, n>(a, b, Matx_SubOp()); +} + + +template static inline +Matx<_Tp, m, n>& operator *= (Matx<_Tp, m, n>& a, int alpha) +{ + for( int i = 0; i < m*n; i++ ) + a.val[i] = saturate_cast<_Tp>(a.val[i] * alpha); + return a; +} + +template static inline +Matx<_Tp, m, n>& operator *= (Matx<_Tp, m, n>& a, float alpha) +{ + for( int i = 0; i < m*n; i++ ) + a.val[i] = saturate_cast<_Tp>(a.val[i] * alpha); + return a; +} + +template static inline +Matx<_Tp, m, n>& operator *= (Matx<_Tp, m, n>& a, double alpha) +{ + for( int i = 0; i < m*n; i++ ) + a.val[i] = saturate_cast<_Tp>(a.val[i] * alpha); + return a; +} + +template static inline +Matx<_Tp, m, n> operator * (const Matx<_Tp, m, n>& a, int alpha) +{ + return Matx<_Tp, m, n>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator * (const Matx<_Tp, m, n>& a, float alpha) +{ + return Matx<_Tp, m, n>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator * (const Matx<_Tp, m, n>& a, double alpha) +{ + return Matx<_Tp, m, n>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator * (int alpha, const Matx<_Tp, m, n>& a) +{ + return Matx<_Tp, m, n>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator * (float alpha, const Matx<_Tp, m, n>& a) +{ + return Matx<_Tp, m, n>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator * (double alpha, const Matx<_Tp, m, n>& a) +{ + return Matx<_Tp, m, n>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator - (const Matx<_Tp, m, n>& a) +{ + return Matx<_Tp, m, n>(a, -1, Matx_ScaleOp()); +} + + +template static inline +Matx<_Tp, m, n> operator * (const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b) +{ + return Matx<_Tp, m, n>(a, b, Matx_MatMulOp()); +} + + +template static inline +Vec<_Tp, m> operator * (const Matx<_Tp, m, n>& a, const Vec<_Tp, n>& b) +{ + Matx<_Tp, m, 1> c(a, b, Matx_MatMulOp()); + return reinterpret_cast&>(c); +} + + +template static inline +Point_<_Tp> operator * (const Matx<_Tp, 2, 2>& a, const Point_<_Tp>& b) +{ + Matx<_Tp, 2, 1> tmp = a*Vec<_Tp,2>(b.x, b.y); + return Point_<_Tp>(tmp.val[0], tmp.val[1]); +} + + +template static inline +Point3_<_Tp> operator * (const Matx<_Tp, 3, 3>& a, const Point3_<_Tp>& b) +{ + Matx<_Tp, 3, 1> tmp = a*Vec<_Tp,3>(b.x, b.y, b.z); + return Point3_<_Tp>(tmp.val[0], tmp.val[1], tmp.val[2]); +} + + +template static inline +Point3_<_Tp> operator * (const Matx<_Tp, 3, 3>& a, const Point_<_Tp>& b) +{ + Matx<_Tp, 3, 1> tmp = a*Vec<_Tp,3>(b.x, b.y, 1); + return Point3_<_Tp>(tmp.val[0], tmp.val[1], tmp.val[2]); +} + + +template static inline +Matx<_Tp, 4, 1> operator * (const Matx<_Tp, 4, 4>& a, const Point3_<_Tp>& b) +{ + return a*Matx<_Tp, 4, 1>(b.x, b.y, b.z, 1); +} + + +template static inline +Scalar operator * (const Matx<_Tp, 4, 4>& a, const Scalar& b) +{ + Matx c(Matx(a), b, Matx_MatMulOp()); + return reinterpret_cast(c); +} + + +static inline +Scalar operator * (const Matx& a, const Scalar& b) +{ + Matx c(a, b, Matx_MatMulOp()); + return reinterpret_cast(c); +} + + +template inline +Matx<_Tp, m, n> Matx<_Tp, m, n>::mul(const Matx<_Tp, m, n>& a) const +{ + return Matx<_Tp, m, n>(*this, a, Matx_MulOp()); +} + + +CV_EXPORTS int LU(float* A, size_t astep, int m, float* b, size_t bstep, int n); +CV_EXPORTS int LU(double* A, size_t astep, int m, double* b, size_t bstep, int n); +CV_EXPORTS bool Cholesky(float* A, size_t astep, int m, float* b, size_t bstep, int n); +CV_EXPORTS bool Cholesky(double* A, size_t astep, int m, double* b, size_t bstep, int n); + + +template struct CV_EXPORTS Matx_DetOp +{ + double operator ()(const Matx<_Tp, m, m>& a) const + { + Matx<_Tp, m, m> temp = a; + double p = LU(temp.val, m, m, 0, 0, 0); + if( p == 0 ) + return p; + for( int i = 0; i < m; i++ ) + p *= temp(i, i); + return p; + } +}; + + +template struct CV_EXPORTS Matx_DetOp<_Tp, 1> +{ + double operator ()(const Matx<_Tp, 1, 1>& a) const + { + return a(0,0); + } +}; + + +template struct CV_EXPORTS Matx_DetOp<_Tp, 2> +{ + double operator ()(const Matx<_Tp, 2, 2>& a) const + { + return a(0,0)*a(1,1) - a(0,1)*a(1,0); + } +}; + + +template struct CV_EXPORTS Matx_DetOp<_Tp, 3> +{ + double operator ()(const Matx<_Tp, 3, 3>& a) const + { + return a(0,0)*(a(1,1)*a(2,2) - a(2,1)*a(1,2)) - + a(0,1)*(a(1,0)*a(2,2) - a(2,0)*a(1,2)) + + a(0,2)*(a(1,0)*a(2,1) - a(2,0)*a(1,1)); + } +}; + +template static inline +double determinant(const Matx<_Tp, m, m>& a) +{ + return Matx_DetOp<_Tp, m>()(a); +} + + +template static inline +double trace(const Matx<_Tp, m, n>& a) +{ + _Tp s = 0; + for( int i = 0; i < std::min(m, n); i++ ) + s += a(i,i); + return s; +} + + +template inline +Matx<_Tp, n, m> Matx<_Tp, m, n>::t() const +{ + return Matx<_Tp, n, m>(*this, Matx_TOp()); +} + + +template struct CV_EXPORTS Matx_FastInvOp +{ + bool operator()(const Matx<_Tp, m, m>& a, Matx<_Tp, m, m>& b, int method) const + { + Matx<_Tp, m, m> temp = a; + + // assume that b is all 0's on input => make it a unity matrix + for( int i = 0; i < m; i++ ) + b(i, i) = (_Tp)1; + + if( method == DECOMP_CHOLESKY ) + return Cholesky(temp.val, m*sizeof(_Tp), m, b.val, m*sizeof(_Tp), m); + + return LU(temp.val, m*sizeof(_Tp), m, b.val, m*sizeof(_Tp), m) != 0; + } +}; + + +template struct CV_EXPORTS Matx_FastInvOp<_Tp, 2> +{ + bool operator()(const Matx<_Tp, 2, 2>& a, Matx<_Tp, 2, 2>& b, int) const + { + _Tp d = determinant(a); + if( d == 0 ) + return false; + d = 1/d; + b(1,1) = a(0,0)*d; + b(0,0) = a(1,1)*d; + b(0,1) = -a(0,1)*d; + b(1,0) = -a(1,0)*d; + return true; + } +}; + + +template struct CV_EXPORTS Matx_FastInvOp<_Tp, 3> +{ + bool operator()(const Matx<_Tp, 3, 3>& a, Matx<_Tp, 3, 3>& b, int) const + { + _Tp d = (_Tp)determinant(a); + if( d == 0 ) + return false; + d = 1/d; + b(0,0) = (a(1,1) * a(2,2) - a(1,2) * a(2,1)) * d; + b(0,1) = (a(0,2) * a(2,1) - a(0,1) * a(2,2)) * d; + b(0,2) = (a(0,1) * a(1,2) - a(0,2) * a(1,1)) * d; + + b(1,0) = (a(1,2) * a(2,0) - a(1,0) * a(2,2)) * d; + b(1,1) = (a(0,0) * a(2,2) - a(0,2) * a(2,0)) * d; + b(1,2) = (a(0,2) * a(1,0) - a(0,0) * a(1,2)) * d; + + b(2,0) = (a(1,0) * a(2,1) - a(1,1) * a(2,0)) * d; + b(2,1) = (a(0,1) * a(2,0) - a(0,0) * a(2,1)) * d; + b(2,2) = (a(0,0) * a(1,1) - a(0,1) * a(1,0)) * d; + return true; + } +}; + + +template inline +Matx<_Tp, n, m> Matx<_Tp, m, n>::inv(int method) const +{ + Matx<_Tp, n, m> b; + bool ok; + if( method == DECOMP_LU || method == DECOMP_CHOLESKY ) + ok = Matx_FastInvOp<_Tp, m>()(*this, b, method); + else + { + Mat A(*this, false), B(b, false); + ok = (invert(A, B, method) != 0); + } + return ok ? b : Matx<_Tp, n, m>::zeros(); +} + + +template struct CV_EXPORTS Matx_FastSolveOp +{ + bool operator()(const Matx<_Tp, m, m>& a, const Matx<_Tp, m, n>& b, + Matx<_Tp, m, n>& x, int method) const + { + Matx<_Tp, m, m> temp = a; + x = b; + if( method == DECOMP_CHOLESKY ) + return Cholesky(temp.val, m*sizeof(_Tp), m, x.val, n*sizeof(_Tp), n); + + return LU(temp.val, m*sizeof(_Tp), m, x.val, n*sizeof(_Tp), n) != 0; + } +}; + + +template struct CV_EXPORTS Matx_FastSolveOp<_Tp, 2, 1> +{ + bool operator()(const Matx<_Tp, 2, 2>& a, const Matx<_Tp, 2, 1>& b, + Matx<_Tp, 2, 1>& x, int) const + { + _Tp d = determinant(a); + if( d == 0 ) + return false; + d = 1/d; + x(0) = (b(0)*a(1,1) - b(1)*a(0,1))*d; + x(1) = (b(1)*a(0,0) - b(0)*a(1,0))*d; + return true; + } +}; + + +template struct CV_EXPORTS Matx_FastSolveOp<_Tp, 3, 1> +{ + bool operator()(const Matx<_Tp, 3, 3>& a, const Matx<_Tp, 3, 1>& b, + Matx<_Tp, 3, 1>& x, int) const + { + _Tp d = (_Tp)determinant(a); + if( d == 0 ) + return false; + d = 1/d; + x(0) = d*(b(0)*(a(1,1)*a(2,2) - a(1,2)*a(2,1)) - + a(0,1)*(b(1)*a(2,2) - a(1,2)*b(2)) + + a(0,2)*(b(1)*a(2,1) - a(1,1)*b(2))); + + x(1) = d*(a(0,0)*(b(1)*a(2,2) - a(1,2)*b(2)) - + b(0)*(a(1,0)*a(2,2) - a(1,2)*a(2,0)) + + a(0,2)*(a(1,0)*b(2) - b(1)*a(2,0))); + + x(2) = d*(a(0,0)*(a(1,1)*b(2) - b(1)*a(2,1)) - + a(0,1)*(a(1,0)*b(2) - b(1)*a(2,0)) + + b(0)*(a(1,0)*a(2,1) - a(1,1)*a(2,0))); + return true; + } +}; + + +template template inline +Matx<_Tp, n, l> Matx<_Tp, m, n>::solve(const Matx<_Tp, m, l>& rhs, int method) const +{ + Matx<_Tp, n, l> x; + bool ok; + if( method == DECOMP_LU || method == DECOMP_CHOLESKY ) + ok = Matx_FastSolveOp<_Tp, m, l>()(*this, rhs, x, method); + else + { + Mat A(*this, false), B(rhs, false), X(x, false); + ok = cv::solve(A, B, X, method); + } + + return ok ? x : Matx<_Tp, n, l>::zeros(); +} + +template inline +Vec<_Tp, n> Matx<_Tp, m, n>::solve(const Vec<_Tp, m>& rhs, int method) const +{ + Matx<_Tp, n, 1> x = solve(reinterpret_cast&>(rhs), method); + return reinterpret_cast&>(x); +} + +template static inline +_AccTp normL2Sqr(const _Tp* a, int n) +{ + _AccTp s = 0; + int i=0; + #if CV_ENABLE_UNROLLED + for( ; i <= n - 4; i += 4 ) + { + _AccTp v0 = a[i], v1 = a[i+1], v2 = a[i+2], v3 = a[i+3]; + s += v0*v0 + v1*v1 + v2*v2 + v3*v3; + } +#endif + for( ; i < n; i++ ) + { + _AccTp v = a[i]; + s += v*v; + } + return s; +} + + +template static inline +_AccTp normL1(const _Tp* a, int n) +{ + _AccTp s = 0; + int i = 0; +#if CV_ENABLE_UNROLLED + for(; i <= n - 4; i += 4 ) + { + s += (_AccTp)fast_abs(a[i]) + (_AccTp)fast_abs(a[i+1]) + + (_AccTp)fast_abs(a[i+2]) + (_AccTp)fast_abs(a[i+3]); + } +#endif + for( ; i < n; i++ ) + s += fast_abs(a[i]); + return s; +} + + +template static inline +_AccTp normInf(const _Tp* a, int n) +{ + _AccTp s = 0; + for( int i = 0; i < n; i++ ) + s = std::max(s, (_AccTp)fast_abs(a[i])); + return s; +} + + +template static inline +_AccTp normL2Sqr(const _Tp* a, const _Tp* b, int n) +{ + _AccTp s = 0; + int i= 0; +#if CV_ENABLE_UNROLLED + for(; i <= n - 4; i += 4 ) + { + _AccTp v0 = _AccTp(a[i] - b[i]), v1 = _AccTp(a[i+1] - b[i+1]), v2 = _AccTp(a[i+2] - b[i+2]), v3 = _AccTp(a[i+3] - b[i+3]); + s += v0*v0 + v1*v1 + v2*v2 + v3*v3; + } +#endif + for( ; i < n; i++ ) + { + _AccTp v = _AccTp(a[i] - b[i]); + s += v*v; + } + return s; +} + +CV_EXPORTS float normL2Sqr_(const float* a, const float* b, int n); +CV_EXPORTS float normL1_(const float* a, const float* b, int n); +CV_EXPORTS int normL1_(const uchar* a, const uchar* b, int n); +CV_EXPORTS int normHamming(const uchar* a, const uchar* b, int n); +CV_EXPORTS int normHamming(const uchar* a, const uchar* b, int n, int cellSize); + +template<> inline float normL2Sqr(const float* a, const float* b, int n) +{ + if( n >= 8 ) + return normL2Sqr_(a, b, n); + float s = 0; + for( int i = 0; i < n; i++ ) + { + float v = a[i] - b[i]; + s += v*v; + } + return s; +} + + +template static inline +_AccTp normL1(const _Tp* a, const _Tp* b, int n) +{ + _AccTp s = 0; + int i= 0; +#if CV_ENABLE_UNROLLED + for(; i <= n - 4; i += 4 ) + { + _AccTp v0 = _AccTp(a[i] - b[i]), v1 = _AccTp(a[i+1] - b[i+1]), v2 = _AccTp(a[i+2] - b[i+2]), v3 = _AccTp(a[i+3] - b[i+3]); + s += std::abs(v0) + std::abs(v1) + std::abs(v2) + std::abs(v3); + } +#endif + for( ; i < n; i++ ) + { + _AccTp v = _AccTp(a[i] - b[i]); + s += std::abs(v); + } + return s; +} + +template<> inline float normL1(const float* a, const float* b, int n) +{ + if( n >= 8 ) + return normL1_(a, b, n); + float s = 0; + for( int i = 0; i < n; i++ ) + { + float v = a[i] - b[i]; + s += std::abs(v); + } + return s; +} + +template<> inline int normL1(const uchar* a, const uchar* b, int n) +{ + return normL1_(a, b, n); +} + +template static inline +_AccTp normInf(const _Tp* a, const _Tp* b, int n) +{ + _AccTp s = 0; + for( int i = 0; i < n; i++ ) + { + _AccTp v0 = a[i] - b[i]; + s = std::max(s, std::abs(v0)); + } + return s; +} + + +template static inline +double norm(const Matx<_Tp, m, n>& M) +{ + return std::sqrt(normL2Sqr<_Tp, double>(M.val, m*n)); +} + + +template static inline +double norm(const Matx<_Tp, m, n>& M, int normType) +{ + return normType == NORM_INF ? (double)normInf<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n) : + normType == NORM_L1 ? (double)normL1<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n) : + std::sqrt((double)normL2Sqr<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n)); +} + + +template static inline +bool operator == (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b) +{ + for( int i = 0; i < m*n; i++ ) + if( a.val[i] != b.val[i] ) return false; + return true; +} + +template static inline +bool operator != (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b) +{ + return !(a == b); +} + + +template static inline +MatxCommaInitializer<_Tp, m, n> operator << (const Matx<_Tp, m, n>& mtx, _T2 val) +{ + MatxCommaInitializer<_Tp, m, n> commaInitializer((Matx<_Tp, m, n>*)&mtx); + return (commaInitializer, val); +} + +template inline +MatxCommaInitializer<_Tp, m, n>::MatxCommaInitializer(Matx<_Tp, m, n>* _mtx) + : dst(_mtx), idx(0) +{} + +template template inline +MatxCommaInitializer<_Tp, m, n>& MatxCommaInitializer<_Tp, m, n>::operator , (_T2 value) +{ + CV_DbgAssert( idx < m*n ); + dst->val[idx++] = saturate_cast<_Tp>(value); + return *this; +} + +template inline +Matx<_Tp, m, n> MatxCommaInitializer<_Tp, m, n>::operator *() const +{ + CV_DbgAssert( idx == n*m ); + return *dst; +} + +/////////////////////////// short vector (Vec) ///////////////////////////// + +template inline Vec<_Tp, cn>::Vec() +{} + +template inline Vec<_Tp, cn>::Vec(_Tp v0) + : Matx<_Tp, cn, 1>(v0) +{} + +template inline Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1) + : Matx<_Tp, cn, 1>(v0, v1) +{} + +template inline Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2) + : Matx<_Tp, cn, 1>(v0, v1, v2) +{} + +template inline Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3) +{} + +template inline Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4) +{} + +template inline Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5) +{} + +template inline Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6) +{} + +template inline Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6, v7) +{} + +template inline Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7, + _Tp v8) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6, v7, v8) +{} + +template inline Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7, + _Tp v8, _Tp v9) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) +{} + +template inline Vec<_Tp, cn>::Vec(const _Tp* values) + : Matx<_Tp, cn, 1>(values) +{} + + +template inline Vec<_Tp, cn>::Vec(const Vec<_Tp, cn>& m) + : Matx<_Tp, cn, 1>(m.val) +{} + +template inline +Vec<_Tp, cn>::Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_AddOp op) +: Matx<_Tp, cn, 1>(a, b, op) +{} + +template inline +Vec<_Tp, cn>::Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_SubOp op) +: Matx<_Tp, cn, 1>(a, b, op) +{} + +template template inline +Vec<_Tp, cn>::Vec(const Matx<_Tp, cn, 1>& a, _T2 alpha, Matx_ScaleOp op) +: Matx<_Tp, cn, 1>(a, alpha, op) +{} + +template inline Vec<_Tp, cn> Vec<_Tp, cn>::all(_Tp alpha) +{ + Vec v; + for( int i = 0; i < cn; i++ ) v.val[i] = alpha; + return v; +} + +template inline Vec<_Tp, cn> Vec<_Tp, cn>::mul(const Vec<_Tp, cn>& v) const +{ + Vec<_Tp, cn> w; + for( int i = 0; i < cn; i++ ) w.val[i] = saturate_cast<_Tp>(this->val[i]*v.val[i]); + return w; +} + +template Vec<_Tp, 2> conjugate(const Vec<_Tp, 2>& v) +{ + return Vec<_Tp, 2>(v[0], -v[1]); +} + +template Vec<_Tp, 4> conjugate(const Vec<_Tp, 4>& v) +{ + return Vec<_Tp, 4>(v[0], -v[1], -v[2], -v[3]); +} + +template<> inline Vec Vec::conj() const +{ + return conjugate(*this); +} + +template<> inline Vec Vec::conj() const +{ + return conjugate(*this); +} + +template<> inline Vec Vec::conj() const +{ + return conjugate(*this); +} + +template<> inline Vec Vec::conj() const +{ + return conjugate(*this); +} + +template inline Vec<_Tp, cn> Vec<_Tp, cn>::cross(const Vec<_Tp, cn>&) const +{ + CV_Error(CV_StsError, "for arbitrary-size vector there is no cross-product defined"); + return Vec<_Tp, cn>(); +} + +template template +inline Vec<_Tp, cn>::operator Vec() const +{ + Vec v; + for( int i = 0; i < cn; i++ ) v.val[i] = saturate_cast(this->val[i]); + return v; +} + +template inline Vec<_Tp, cn>::operator CvScalar() const +{ + CvScalar s = {{0,0,0,0}}; + int i; + for( i = 0; i < std::min(cn, 4); i++ ) s.val[i] = this->val[i]; + for( ; i < 4; i++ ) s.val[i] = 0; + return s; +} + +template inline const _Tp& Vec<_Tp, cn>::operator [](int i) const +{ + CV_DbgAssert( (unsigned)i < (unsigned)cn ); + return this->val[i]; +} + +template inline _Tp& Vec<_Tp, cn>::operator [](int i) +{ + CV_DbgAssert( (unsigned)i < (unsigned)cn ); + return this->val[i]; +} + +template inline const _Tp& Vec<_Tp, cn>::operator ()(int i) const +{ + CV_DbgAssert( (unsigned)i < (unsigned)cn ); + return this->val[i]; +} + +template inline _Tp& Vec<_Tp, cn>::operator ()(int i) +{ + CV_DbgAssert( (unsigned)i < (unsigned)cn ); + return this->val[i]; +} + +template static inline Vec<_Tp1, cn>& +operator += (Vec<_Tp1, cn>& a, const Vec<_Tp2, cn>& b) +{ + for( int i = 0; i < cn; i++ ) + a.val[i] = saturate_cast<_Tp1>(a.val[i] + b.val[i]); + return a; +} + +template static inline Vec<_Tp1, cn>& +operator -= (Vec<_Tp1, cn>& a, const Vec<_Tp2, cn>& b) +{ + for( int i = 0; i < cn; i++ ) + a.val[i] = saturate_cast<_Tp1>(a.val[i] - b.val[i]); + return a; +} + +template static inline Vec<_Tp, cn> +operator + (const Vec<_Tp, cn>& a, const Vec<_Tp, cn>& b) +{ + return Vec<_Tp, cn>(a, b, Matx_AddOp()); +} + +template static inline Vec<_Tp, cn> +operator - (const Vec<_Tp, cn>& a, const Vec<_Tp, cn>& b) +{ + return Vec<_Tp, cn>(a, b, Matx_SubOp()); +} + +template static inline +Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, int alpha) +{ + for( int i = 0; i < cn; i++ ) + a[i] = saturate_cast<_Tp>(a[i]*alpha); + return a; +} + +template static inline +Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, float alpha) +{ + for( int i = 0; i < cn; i++ ) + a[i] = saturate_cast<_Tp>(a[i]*alpha); + return a; +} + +template static inline +Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, double alpha) +{ + for( int i = 0; i < cn; i++ ) + a[i] = saturate_cast<_Tp>(a[i]*alpha); + return a; +} + +template static inline +Vec<_Tp, cn>& operator /= (Vec<_Tp, cn>& a, int alpha) +{ + double ialpha = 1./alpha; + for( int i = 0; i < cn; i++ ) + a[i] = saturate_cast<_Tp>(a[i]*ialpha); + return a; +} + +template static inline +Vec<_Tp, cn>& operator /= (Vec<_Tp, cn>& a, float alpha) +{ + float ialpha = 1.f/alpha; + for( int i = 0; i < cn; i++ ) + a[i] = saturate_cast<_Tp>(a[i]*ialpha); + return a; +} + +template static inline +Vec<_Tp, cn>& operator /= (Vec<_Tp, cn>& a, double alpha) +{ + double ialpha = 1./alpha; + for( int i = 0; i < cn; i++ ) + a[i] = saturate_cast<_Tp>(a[i]*ialpha); + return a; +} + +template static inline Vec<_Tp, cn> +operator * (const Vec<_Tp, cn>& a, int alpha) +{ + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); +} + +template static inline Vec<_Tp, cn> +operator * (int alpha, const Vec<_Tp, cn>& a) +{ + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); +} + +template static inline Vec<_Tp, cn> +operator * (const Vec<_Tp, cn>& a, float alpha) +{ + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); +} + +template static inline Vec<_Tp, cn> +operator * (float alpha, const Vec<_Tp, cn>& a) +{ + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); +} + +template static inline Vec<_Tp, cn> +operator * (const Vec<_Tp, cn>& a, double alpha) +{ + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); +} + +template static inline Vec<_Tp, cn> +operator * (double alpha, const Vec<_Tp, cn>& a) +{ + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); +} + +template static inline Vec<_Tp, cn> +operator / (const Vec<_Tp, cn>& a, int alpha) +{ + return Vec<_Tp, cn>(a, 1./alpha, Matx_ScaleOp()); +} + +template static inline Vec<_Tp, cn> +operator / (const Vec<_Tp, cn>& a, float alpha) +{ + return Vec<_Tp, cn>(a, 1.f/alpha, Matx_ScaleOp()); +} + +template static inline Vec<_Tp, cn> +operator / (const Vec<_Tp, cn>& a, double alpha) +{ + return Vec<_Tp, cn>(a, 1./alpha, Matx_ScaleOp()); +} + +template static inline Vec<_Tp, cn> +operator - (const Vec<_Tp, cn>& a) +{ + Vec<_Tp,cn> t; + for( int i = 0; i < cn; i++ ) t.val[i] = saturate_cast<_Tp>(-a.val[i]); + return t; +} + +template inline Vec<_Tp, 4> operator * (const Vec<_Tp, 4>& v1, const Vec<_Tp, 4>& v2) +{ + return Vec<_Tp, 4>(saturate_cast<_Tp>(v1[0]*v2[0] - v1[1]*v2[1] - v1[2]*v2[2] - v1[3]*v2[3]), + saturate_cast<_Tp>(v1[0]*v2[1] + v1[1]*v2[0] + v1[2]*v2[3] - v1[3]*v2[2]), + saturate_cast<_Tp>(v1[0]*v2[2] - v1[1]*v2[3] + v1[2]*v2[0] + v1[3]*v2[1]), + saturate_cast<_Tp>(v1[0]*v2[3] + v1[1]*v2[2] - v1[2]*v2[1] + v1[3]*v2[0])); +} + +template inline Vec<_Tp, 4>& operator *= (Vec<_Tp, 4>& v1, const Vec<_Tp, 4>& v2) +{ + v1 = v1 * v2; + return v1; +} + +template<> inline Vec Vec::cross(const Vec& v) const +{ + return Vec(val[1]*v.val[2] - val[2]*v.val[1], + val[2]*v.val[0] - val[0]*v.val[2], + val[0]*v.val[1] - val[1]*v.val[0]); +} + +template<> inline Vec Vec::cross(const Vec& v) const +{ + return Vec(val[1]*v.val[2] - val[2]*v.val[1], + val[2]*v.val[0] - val[0]*v.val[2], + val[0]*v.val[1] - val[1]*v.val[0]); +} + +template inline Vec<_Tp, cn> normalize(const Vec<_Tp, cn>& v) +{ + double nv = norm(v); + return v * (nv ? 1./nv : 0.); +} + +template static inline +VecCommaInitializer<_Tp, cn> operator << (const Vec<_Tp, cn>& vec, _T2 val) +{ + VecCommaInitializer<_Tp, cn> commaInitializer((Vec<_Tp, cn>*)&vec); + return (commaInitializer, val); +} + +template inline +VecCommaInitializer<_Tp, cn>::VecCommaInitializer(Vec<_Tp, cn>* _vec) + : MatxCommaInitializer<_Tp, cn, 1>(_vec) +{} + +template template inline +VecCommaInitializer<_Tp, cn>& VecCommaInitializer<_Tp, cn>::operator , (_T2 value) +{ + CV_DbgAssert( this->idx < cn ); + this->dst->val[this->idx++] = saturate_cast<_Tp>(value); + return *this; +} + +template inline +Vec<_Tp, cn> VecCommaInitializer<_Tp, cn>::operator *() const +{ + CV_DbgAssert( this->idx == cn ); + return *this->dst; +} + +//////////////////////////////// Complex ////////////////////////////// + +template inline Complex<_Tp>::Complex() : re(0), im(0) {} +template inline Complex<_Tp>::Complex( _Tp _re, _Tp _im ) : re(_re), im(_im) {} +template template inline Complex<_Tp>::operator Complex() const +{ return Complex(saturate_cast(re), saturate_cast(im)); } +template inline Complex<_Tp> Complex<_Tp>::conj() const +{ return Complex<_Tp>(re, -im); } + +template static inline +bool operator == (const Complex<_Tp>& a, const Complex<_Tp>& b) +{ return a.re == b.re && a.im == b.im; } + +template static inline +bool operator != (const Complex<_Tp>& a, const Complex<_Tp>& b) +{ return a.re != b.re || a.im != b.im; } + +template static inline +Complex<_Tp> operator + (const Complex<_Tp>& a, const Complex<_Tp>& b) +{ return Complex<_Tp>( a.re + b.re, a.im + b.im ); } + +template static inline +Complex<_Tp>& operator += (Complex<_Tp>& a, const Complex<_Tp>& b) +{ a.re += b.re; a.im += b.im; return a; } + +template static inline +Complex<_Tp> operator - (const Complex<_Tp>& a, const Complex<_Tp>& b) +{ return Complex<_Tp>( a.re - b.re, a.im - b.im ); } + +template static inline +Complex<_Tp>& operator -= (Complex<_Tp>& a, const Complex<_Tp>& b) +{ a.re -= b.re; a.im -= b.im; return a; } + +template static inline +Complex<_Tp> operator - (const Complex<_Tp>& a) +{ return Complex<_Tp>(-a.re, -a.im); } + +template static inline +Complex<_Tp> operator * (const Complex<_Tp>& a, const Complex<_Tp>& b) +{ return Complex<_Tp>( a.re*b.re - a.im*b.im, a.re*b.im + a.im*b.re ); } + +template static inline +Complex<_Tp> operator * (const Complex<_Tp>& a, _Tp b) +{ return Complex<_Tp>( a.re*b, a.im*b ); } + +template static inline +Complex<_Tp> operator * (_Tp b, const Complex<_Tp>& a) +{ return Complex<_Tp>( a.re*b, a.im*b ); } + +template static inline +Complex<_Tp> operator + (const Complex<_Tp>& a, _Tp b) +{ return Complex<_Tp>( a.re + b, a.im ); } + +template static inline +Complex<_Tp> operator - (const Complex<_Tp>& a, _Tp b) +{ return Complex<_Tp>( a.re - b, a.im ); } + +template static inline +Complex<_Tp> operator + (_Tp b, const Complex<_Tp>& a) +{ return Complex<_Tp>( a.re + b, a.im ); } + +template static inline +Complex<_Tp> operator - (_Tp b, const Complex<_Tp>& a) +{ return Complex<_Tp>( b - a.re, -a.im ); } + +template static inline +Complex<_Tp>& operator += (Complex<_Tp>& a, _Tp b) +{ a.re += b; return a; } + +template static inline +Complex<_Tp>& operator -= (Complex<_Tp>& a, _Tp b) +{ a.re -= b; return a; } + +template static inline +Complex<_Tp>& operator *= (Complex<_Tp>& a, _Tp b) +{ a.re *= b; a.im *= b; return a; } + +template static inline +double abs(const Complex<_Tp>& a) +{ return std::sqrt( (double)a.re*a.re + (double)a.im*a.im); } + +template static inline +Complex<_Tp> operator / (const Complex<_Tp>& a, const Complex<_Tp>& b) +{ + double t = 1./((double)b.re*b.re + (double)b.im*b.im); + return Complex<_Tp>( (_Tp)((a.re*b.re + a.im*b.im)*t), + (_Tp)((-a.re*b.im + a.im*b.re)*t) ); +} + +template static inline +Complex<_Tp>& operator /= (Complex<_Tp>& a, const Complex<_Tp>& b) +{ + return (a = a / b); +} + +template static inline +Complex<_Tp> operator / (const Complex<_Tp>& a, _Tp b) +{ + _Tp t = (_Tp)1/b; + return Complex<_Tp>( a.re*t, a.im*t ); +} + +template static inline +Complex<_Tp> operator / (_Tp b, const Complex<_Tp>& a) +{ + return Complex<_Tp>(b)/a; +} + +template static inline +Complex<_Tp> operator /= (const Complex<_Tp>& a, _Tp b) +{ + _Tp t = (_Tp)1/b; + a.re *= t; a.im *= t; return a; +} + +//////////////////////////////// 2D Point //////////////////////////////// + +template inline Point_<_Tp>::Point_() : x(0), y(0) {} +template inline Point_<_Tp>::Point_(_Tp _x, _Tp _y) : x(_x), y(_y) {} +template inline Point_<_Tp>::Point_(const Point_& pt) : x(pt.x), y(pt.y) {} +template inline Point_<_Tp>::Point_(const CvPoint& pt) : x((_Tp)pt.x), y((_Tp)pt.y) {} +template inline Point_<_Tp>::Point_(const CvPoint2D32f& pt) + : x(saturate_cast<_Tp>(pt.x)), y(saturate_cast<_Tp>(pt.y)) {} +template inline Point_<_Tp>::Point_(const Size_<_Tp>& sz) : x(sz.width), y(sz.height) {} +template inline Point_<_Tp>::Point_(const Vec<_Tp,2>& v) : x(v[0]), y(v[1]) {} +template inline Point_<_Tp>& Point_<_Tp>::operator = (const Point_& pt) +{ x = pt.x; y = pt.y; return *this; } + +template template inline Point_<_Tp>::operator Point_<_Tp2>() const +{ return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); } +template inline Point_<_Tp>::operator CvPoint() const +{ return cvPoint(saturate_cast(x), saturate_cast(y)); } +template inline Point_<_Tp>::operator CvPoint2D32f() const +{ return cvPoint2D32f((float)x, (float)y); } +template inline Point_<_Tp>::operator Vec<_Tp, 2>() const +{ return Vec<_Tp, 2>(x, y); } + +template inline _Tp Point_<_Tp>::dot(const Point_& pt) const +{ return saturate_cast<_Tp>(x*pt.x + y*pt.y); } +template inline double Point_<_Tp>::ddot(const Point_& pt) const +{ return (double)x*pt.x + (double)y*pt.y; } + +template inline double Point_<_Tp>::cross(const Point_& pt) const +{ return (double)x*pt.y - (double)y*pt.x; } + +template static inline Point_<_Tp>& +operator += (Point_<_Tp>& a, const Point_<_Tp>& b) +{ + a.x = saturate_cast<_Tp>(a.x + b.x); + a.y = saturate_cast<_Tp>(a.y + b.y); + return a; +} + +template static inline Point_<_Tp>& +operator -= (Point_<_Tp>& a, const Point_<_Tp>& b) +{ + a.x = saturate_cast<_Tp>(a.x - b.x); + a.y = saturate_cast<_Tp>(a.y - b.y); + return a; +} + +template static inline Point_<_Tp>& +operator *= (Point_<_Tp>& a, int b) +{ + a.x = saturate_cast<_Tp>(a.x*b); + a.y = saturate_cast<_Tp>(a.y*b); + return a; +} + +template static inline Point_<_Tp>& +operator *= (Point_<_Tp>& a, float b) +{ + a.x = saturate_cast<_Tp>(a.x*b); + a.y = saturate_cast<_Tp>(a.y*b); + return a; +} + +template static inline Point_<_Tp>& +operator *= (Point_<_Tp>& a, double b) +{ + a.x = saturate_cast<_Tp>(a.x*b); + a.y = saturate_cast<_Tp>(a.y*b); + return a; +} + +template static inline double norm(const Point_<_Tp>& pt) +{ return std::sqrt((double)pt.x*pt.x + (double)pt.y*pt.y); } + +template static inline bool operator == (const Point_<_Tp>& a, const Point_<_Tp>& b) +{ return a.x == b.x && a.y == b.y; } + +template static inline bool operator != (const Point_<_Tp>& a, const Point_<_Tp>& b) +{ return a.x != b.x || a.y != b.y; } + +template static inline Point_<_Tp> operator + (const Point_<_Tp>& a, const Point_<_Tp>& b) +{ return Point_<_Tp>( saturate_cast<_Tp>(a.x + b.x), saturate_cast<_Tp>(a.y + b.y) ); } + +template static inline Point_<_Tp> operator - (const Point_<_Tp>& a, const Point_<_Tp>& b) +{ return Point_<_Tp>( saturate_cast<_Tp>(a.x - b.x), saturate_cast<_Tp>(a.y - b.y) ); } + +template static inline Point_<_Tp> operator - (const Point_<_Tp>& a) +{ return Point_<_Tp>( saturate_cast<_Tp>(-a.x), saturate_cast<_Tp>(-a.y) ); } + +template static inline Point_<_Tp> operator * (const Point_<_Tp>& a, int b) +{ return Point_<_Tp>( saturate_cast<_Tp>(a.x*b), saturate_cast<_Tp>(a.y*b) ); } + +template static inline Point_<_Tp> operator * (int a, const Point_<_Tp>& b) +{ return Point_<_Tp>( saturate_cast<_Tp>(b.x*a), saturate_cast<_Tp>(b.y*a) ); } + +template static inline Point_<_Tp> operator * (const Point_<_Tp>& a, float b) +{ return Point_<_Tp>( saturate_cast<_Tp>(a.x*b), saturate_cast<_Tp>(a.y*b) ); } + +template static inline Point_<_Tp> operator * (float a, const Point_<_Tp>& b) +{ return Point_<_Tp>( saturate_cast<_Tp>(b.x*a), saturate_cast<_Tp>(b.y*a) ); } + +template static inline Point_<_Tp> operator * (const Point_<_Tp>& a, double b) +{ return Point_<_Tp>( saturate_cast<_Tp>(a.x*b), saturate_cast<_Tp>(a.y*b) ); } + +template static inline Point_<_Tp> operator * (double a, const Point_<_Tp>& b) +{ return Point_<_Tp>( saturate_cast<_Tp>(b.x*a), saturate_cast<_Tp>(b.y*a) ); } + +//////////////////////////////// 3D Point //////////////////////////////// + +template inline Point3_<_Tp>::Point3_() : x(0), y(0), z(0) {} +template inline Point3_<_Tp>::Point3_(_Tp _x, _Tp _y, _Tp _z) : x(_x), y(_y), z(_z) {} +template inline Point3_<_Tp>::Point3_(const Point3_& pt) : x(pt.x), y(pt.y), z(pt.z) {} +template inline Point3_<_Tp>::Point3_(const Point_<_Tp>& pt) : x(pt.x), y(pt.y), z(_Tp()) {} +template inline Point3_<_Tp>::Point3_(const CvPoint3D32f& pt) : + x(saturate_cast<_Tp>(pt.x)), y(saturate_cast<_Tp>(pt.y)), z(saturate_cast<_Tp>(pt.z)) {} +template inline Point3_<_Tp>::Point3_(const Vec<_Tp, 3>& v) : x(v[0]), y(v[1]), z(v[2]) {} + +template template inline Point3_<_Tp>::operator Point3_<_Tp2>() const +{ return Point3_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(z)); } + +template inline Point3_<_Tp>::operator CvPoint3D32f() const +{ return cvPoint3D32f((float)x, (float)y, (float)z); } + +template inline Point3_<_Tp>::operator Vec<_Tp, 3>() const +{ return Vec<_Tp, 3>(x, y, z); } + +template inline Point3_<_Tp>& Point3_<_Tp>::operator = (const Point3_& pt) +{ x = pt.x; y = pt.y; z = pt.z; return *this; } + +template inline _Tp Point3_<_Tp>::dot(const Point3_& pt) const +{ return saturate_cast<_Tp>(x*pt.x + y*pt.y + z*pt.z); } +template inline double Point3_<_Tp>::ddot(const Point3_& pt) const +{ return (double)x*pt.x + (double)y*pt.y + (double)z*pt.z; } + +template inline Point3_<_Tp> Point3_<_Tp>::cross(const Point3_<_Tp>& pt) const +{ + return Point3_<_Tp>(y*pt.z - z*pt.y, z*pt.x - x*pt.z, x*pt.y - y*pt.x); +} + +template static inline Point3_<_Tp>& +operator += (Point3_<_Tp>& a, const Point3_<_Tp>& b) +{ + a.x = saturate_cast<_Tp>(a.x + b.x); + a.y = saturate_cast<_Tp>(a.y + b.y); + a.z = saturate_cast<_Tp>(a.z + b.z); + return a; +} + +template static inline Point3_<_Tp>& +operator -= (Point3_<_Tp>& a, const Point3_<_Tp>& b) +{ + a.x = saturate_cast<_Tp>(a.x - b.x); + a.y = saturate_cast<_Tp>(a.y - b.y); + a.z = saturate_cast<_Tp>(a.z - b.z); + return a; +} + +template static inline Point3_<_Tp>& +operator *= (Point3_<_Tp>& a, int b) +{ + a.x = saturate_cast<_Tp>(a.x*b); + a.y = saturate_cast<_Tp>(a.y*b); + a.z = saturate_cast<_Tp>(a.z*b); + return a; +} + +template static inline Point3_<_Tp>& +operator *= (Point3_<_Tp>& a, float b) +{ + a.x = saturate_cast<_Tp>(a.x*b); + a.y = saturate_cast<_Tp>(a.y*b); + a.z = saturate_cast<_Tp>(a.z*b); + return a; +} + +template static inline Point3_<_Tp>& +operator *= (Point3_<_Tp>& a, double b) +{ + a.x = saturate_cast<_Tp>(a.x*b); + a.y = saturate_cast<_Tp>(a.y*b); + a.z = saturate_cast<_Tp>(a.z*b); + return a; +} + +template static inline double norm(const Point3_<_Tp>& pt) +{ return std::sqrt((double)pt.x*pt.x + (double)pt.y*pt.y + (double)pt.z*pt.z); } + +template static inline bool operator == (const Point3_<_Tp>& a, const Point3_<_Tp>& b) +{ return a.x == b.x && a.y == b.y && a.z == b.z; } + +template static inline bool operator != (const Point3_<_Tp>& a, const Point3_<_Tp>& b) +{ return a.x != b.x || a.y != b.y || a.z != b.z; } + +template static inline Point3_<_Tp> operator + (const Point3_<_Tp>& a, const Point3_<_Tp>& b) +{ return Point3_<_Tp>( saturate_cast<_Tp>(a.x + b.x), + saturate_cast<_Tp>(a.y + b.y), + saturate_cast<_Tp>(a.z + b.z)); } + +template static inline Point3_<_Tp> operator - (const Point3_<_Tp>& a, const Point3_<_Tp>& b) +{ return Point3_<_Tp>( saturate_cast<_Tp>(a.x - b.x), + saturate_cast<_Tp>(a.y - b.y), + saturate_cast<_Tp>(a.z - b.z)); } + +template static inline Point3_<_Tp> operator - (const Point3_<_Tp>& a) +{ return Point3_<_Tp>( saturate_cast<_Tp>(-a.x), + saturate_cast<_Tp>(-a.y), + saturate_cast<_Tp>(-a.z) ); } + +template static inline Point3_<_Tp> operator * (const Point3_<_Tp>& a, int b) +{ return Point3_<_Tp>( saturate_cast<_Tp>(a.x*b), + saturate_cast<_Tp>(a.y*b), + saturate_cast<_Tp>(a.z*b) ); } + +template static inline Point3_<_Tp> operator * (int a, const Point3_<_Tp>& b) +{ return Point3_<_Tp>( saturate_cast<_Tp>(b.x*a), + saturate_cast<_Tp>(b.y*a), + saturate_cast<_Tp>(b.z*a) ); } + +template static inline Point3_<_Tp> operator * (const Point3_<_Tp>& a, float b) +{ return Point3_<_Tp>( saturate_cast<_Tp>(a.x*b), + saturate_cast<_Tp>(a.y*b), + saturate_cast<_Tp>(a.z*b) ); } + +template static inline Point3_<_Tp> operator * (float a, const Point3_<_Tp>& b) +{ return Point3_<_Tp>( saturate_cast<_Tp>(b.x*a), + saturate_cast<_Tp>(b.y*a), + saturate_cast<_Tp>(b.z*a) ); } + +template static inline Point3_<_Tp> operator * (const Point3_<_Tp>& a, double b) +{ return Point3_<_Tp>( saturate_cast<_Tp>(a.x*b), + saturate_cast<_Tp>(a.y*b), + saturate_cast<_Tp>(a.z*b) ); } + +template static inline Point3_<_Tp> operator * (double a, const Point3_<_Tp>& b) +{ return Point3_<_Tp>( saturate_cast<_Tp>(b.x*a), + saturate_cast<_Tp>(b.y*a), + saturate_cast<_Tp>(b.z*a) ); } + +//////////////////////////////// Size //////////////////////////////// + +template inline Size_<_Tp>::Size_() + : width(0), height(0) {} +template inline Size_<_Tp>::Size_(_Tp _width, _Tp _height) + : width(_width), height(_height) {} +template inline Size_<_Tp>::Size_(const Size_& sz) + : width(sz.width), height(sz.height) {} +template inline Size_<_Tp>::Size_(const CvSize& sz) + : width(saturate_cast<_Tp>(sz.width)), height(saturate_cast<_Tp>(sz.height)) {} +template inline Size_<_Tp>::Size_(const CvSize2D32f& sz) + : width(saturate_cast<_Tp>(sz.width)), height(saturate_cast<_Tp>(sz.height)) {} +template inline Size_<_Tp>::Size_(const Point_<_Tp>& pt) : width(pt.x), height(pt.y) {} + +template template inline Size_<_Tp>::operator Size_<_Tp2>() const +{ return Size_<_Tp2>(saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); } +template inline Size_<_Tp>::operator CvSize() const +{ return cvSize(saturate_cast(width), saturate_cast(height)); } +template inline Size_<_Tp>::operator CvSize2D32f() const +{ return cvSize2D32f((float)width, (float)height); } + +template inline Size_<_Tp>& Size_<_Tp>::operator = (const Size_<_Tp>& sz) +{ width = sz.width; height = sz.height; return *this; } +template static inline Size_<_Tp> operator * (const Size_<_Tp>& a, _Tp b) +{ return Size_<_Tp>(a.width * b, a.height * b); } +template static inline Size_<_Tp> operator + (const Size_<_Tp>& a, const Size_<_Tp>& b) +{ return Size_<_Tp>(a.width + b.width, a.height + b.height); } +template static inline Size_<_Tp> operator - (const Size_<_Tp>& a, const Size_<_Tp>& b) +{ return Size_<_Tp>(a.width - b.width, a.height - b.height); } +template inline _Tp Size_<_Tp>::area() const { return width*height; } + +template static inline Size_<_Tp>& operator += (Size_<_Tp>& a, const Size_<_Tp>& b) +{ a.width += b.width; a.height += b.height; return a; } +template static inline Size_<_Tp>& operator -= (Size_<_Tp>& a, const Size_<_Tp>& b) +{ a.width -= b.width; a.height -= b.height; return a; } + +template static inline bool operator == (const Size_<_Tp>& a, const Size_<_Tp>& b) +{ return a.width == b.width && a.height == b.height; } +template static inline bool operator != (const Size_<_Tp>& a, const Size_<_Tp>& b) +{ return a.width != b.width || a.height != b.height; } + +//////////////////////////////// Rect //////////////////////////////// + + +template inline Rect_<_Tp>::Rect_() : x(0), y(0), width(0), height(0) {} +template inline Rect_<_Tp>::Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height) : x(_x), y(_y), width(_width), height(_height) {} +template inline Rect_<_Tp>::Rect_(const Rect_<_Tp>& r) : x(r.x), y(r.y), width(r.width), height(r.height) {} +template inline Rect_<_Tp>::Rect_(const CvRect& r) : x((_Tp)r.x), y((_Tp)r.y), width((_Tp)r.width), height((_Tp)r.height) {} +template inline Rect_<_Tp>::Rect_(const Point_<_Tp>& org, const Size_<_Tp>& sz) : + x(org.x), y(org.y), width(sz.width), height(sz.height) {} +template inline Rect_<_Tp>::Rect_(const Point_<_Tp>& pt1, const Point_<_Tp>& pt2) +{ + x = std::min(pt1.x, pt2.x); y = std::min(pt1.y, pt2.y); + width = std::max(pt1.x, pt2.x) - x; height = std::max(pt1.y, pt2.y) - y; +} +template inline Rect_<_Tp>& Rect_<_Tp>::operator = ( const Rect_<_Tp>& r ) +{ x = r.x; y = r.y; width = r.width; height = r.height; return *this; } + +template inline Point_<_Tp> Rect_<_Tp>::tl() const { return Point_<_Tp>(x,y); } +template inline Point_<_Tp> Rect_<_Tp>::br() const { return Point_<_Tp>(x+width, y+height); } + +template static inline Rect_<_Tp>& operator += ( Rect_<_Tp>& a, const Point_<_Tp>& b ) +{ a.x += b.x; a.y += b.y; return a; } +template static inline Rect_<_Tp>& operator -= ( Rect_<_Tp>& a, const Point_<_Tp>& b ) +{ a.x -= b.x; a.y -= b.y; return a; } + +template static inline Rect_<_Tp>& operator += ( Rect_<_Tp>& a, const Size_<_Tp>& b ) +{ a.width += b.width; a.height += b.height; return a; } + +template static inline Rect_<_Tp>& operator -= ( Rect_<_Tp>& a, const Size_<_Tp>& b ) +{ a.width -= b.width; a.height -= b.height; return a; } + +template static inline Rect_<_Tp>& operator &= ( Rect_<_Tp>& a, const Rect_<_Tp>& b ) +{ + _Tp x1 = std::max(a.x, b.x), y1 = std::max(a.y, b.y); + a.width = std::min(a.x + a.width, b.x + b.width) - x1; + a.height = std::min(a.y + a.height, b.y + b.height) - y1; + a.x = x1; a.y = y1; + if( a.width <= 0 || a.height <= 0 ) + a = Rect(); + return a; +} + +template static inline Rect_<_Tp>& operator |= ( Rect_<_Tp>& a, const Rect_<_Tp>& b ) +{ + _Tp x1 = std::min(a.x, b.x), y1 = std::min(a.y, b.y); + a.width = std::max(a.x + a.width, b.x + b.width) - x1; + a.height = std::max(a.y + a.height, b.y + b.height) - y1; + a.x = x1; a.y = y1; + return a; +} + +template inline Size_<_Tp> Rect_<_Tp>::size() const { return Size_<_Tp>(width, height); } +template inline _Tp Rect_<_Tp>::area() const { return width*height; } + +template template inline Rect_<_Tp>::operator Rect_<_Tp2>() const +{ return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), + saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); } +template inline Rect_<_Tp>::operator CvRect() const +{ return cvRect(saturate_cast(x), saturate_cast(y), + saturate_cast(width), saturate_cast(height)); } + +template inline bool Rect_<_Tp>::contains(const Point_<_Tp>& pt) const +{ return x <= pt.x && pt.x < x + width && y <= pt.y && pt.y < y + height; } + +template static inline bool operator == (const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + return a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height; +} + +template static inline bool operator != (const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + return a.x != b.x || a.y != b.y || a.width != b.width || a.height != b.height; +} + +template static inline Rect_<_Tp> operator + (const Rect_<_Tp>& a, const Point_<_Tp>& b) +{ + return Rect_<_Tp>( a.x + b.x, a.y + b.y, a.width, a.height ); +} + +template static inline Rect_<_Tp> operator - (const Rect_<_Tp>& a, const Point_<_Tp>& b) +{ + return Rect_<_Tp>( a.x - b.x, a.y - b.y, a.width, a.height ); +} + +template static inline Rect_<_Tp> operator + (const Rect_<_Tp>& a, const Size_<_Tp>& b) +{ + return Rect_<_Tp>( a.x, a.y, a.width + b.width, a.height + b.height ); +} + +template static inline Rect_<_Tp> operator & (const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c &= b; +} + +template static inline Rect_<_Tp> operator | (const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c |= b; +} + +template inline bool Point_<_Tp>::inside( const Rect_<_Tp>& r ) const +{ + return r.contains(*this); +} + +inline RotatedRect::RotatedRect() { angle = 0; } +inline RotatedRect::RotatedRect(const Point2f& _center, const Size2f& _size, float _angle) + : center(_center), size(_size), angle(_angle) {} +inline RotatedRect::RotatedRect(const CvBox2D& box) + : center(box.center), size(box.size), angle(box.angle) {} +inline RotatedRect::operator CvBox2D() const +{ + CvBox2D box; box.center = center; box.size = size; box.angle = angle; + return box; +} + +//////////////////////////////// Scalar_ /////////////////////////////// + +template inline Scalar_<_Tp>::Scalar_() +{ this->val[0] = this->val[1] = this->val[2] = this->val[3] = 0; } + +template inline Scalar_<_Tp>::Scalar_(_Tp v0, _Tp v1, _Tp v2, _Tp v3) +{ this->val[0] = v0; this->val[1] = v1; this->val[2] = v2; this->val[3] = v3; } + +template inline Scalar_<_Tp>::Scalar_(const CvScalar& s) +{ + this->val[0] = saturate_cast<_Tp>(s.val[0]); + this->val[1] = saturate_cast<_Tp>(s.val[1]); + this->val[2] = saturate_cast<_Tp>(s.val[2]); + this->val[3] = saturate_cast<_Tp>(s.val[3]); +} + +template inline Scalar_<_Tp>::Scalar_(_Tp v0) +{ this->val[0] = v0; this->val[1] = this->val[2] = this->val[3] = 0; } + +template inline Scalar_<_Tp> Scalar_<_Tp>::all(_Tp v0) +{ return Scalar_<_Tp>(v0, v0, v0, v0); } +template inline Scalar_<_Tp>::operator CvScalar() const +{ return cvScalar(this->val[0], this->val[1], this->val[2], this->val[3]); } + +template template inline Scalar_<_Tp>::operator Scalar_() const +{ + return Scalar_(saturate_cast(this->val[0]), + saturate_cast(this->val[1]), + saturate_cast(this->val[2]), + saturate_cast(this->val[3])); +} + +template static inline Scalar_<_Tp>& operator += (Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + a.val[0] = saturate_cast<_Tp>(a.val[0] + b.val[0]); + a.val[1] = saturate_cast<_Tp>(a.val[1] + b.val[1]); + a.val[2] = saturate_cast<_Tp>(a.val[2] + b.val[2]); + a.val[3] = saturate_cast<_Tp>(a.val[3] + b.val[3]); + return a; +} + +template static inline Scalar_<_Tp>& operator -= (Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + a.val[0] = saturate_cast<_Tp>(a.val[0] - b.val[0]); + a.val[1] = saturate_cast<_Tp>(a.val[1] - b.val[1]); + a.val[2] = saturate_cast<_Tp>(a.val[2] - b.val[2]); + a.val[3] = saturate_cast<_Tp>(a.val[3] - b.val[3]); + return a; +} + +template static inline Scalar_<_Tp>& operator *= ( Scalar_<_Tp>& a, _Tp v ) +{ + a.val[0] = saturate_cast<_Tp>(a.val[0] * v); + a.val[1] = saturate_cast<_Tp>(a.val[1] * v); + a.val[2] = saturate_cast<_Tp>(a.val[2] * v); + a.val[3] = saturate_cast<_Tp>(a.val[3] * v); + return a; +} + +template inline Scalar_<_Tp> Scalar_<_Tp>::mul(const Scalar_<_Tp>& t, double scale ) const +{ + return Scalar_<_Tp>( saturate_cast<_Tp>(this->val[0]*t.val[0]*scale), + saturate_cast<_Tp>(this->val[1]*t.val[1]*scale), + saturate_cast<_Tp>(this->val[2]*t.val[2]*scale), + saturate_cast<_Tp>(this->val[3]*t.val[3]*scale)); +} + +template static inline bool operator == ( const Scalar_<_Tp>& a, const Scalar_<_Tp>& b ) +{ + return a.val[0] == b.val[0] && a.val[1] == b.val[1] && + a.val[2] == b.val[2] && a.val[3] == b.val[3]; +} + +template static inline bool operator != ( const Scalar_<_Tp>& a, const Scalar_<_Tp>& b ) +{ + return a.val[0] != b.val[0] || a.val[1] != b.val[1] || + a.val[2] != b.val[2] || a.val[3] != b.val[3]; +} + +template static inline Scalar_<_Tp> operator + (const Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + return Scalar_<_Tp>(saturate_cast<_Tp>(a.val[0] + b.val[0]), + saturate_cast<_Tp>(a.val[1] + b.val[1]), + saturate_cast<_Tp>(a.val[2] + b.val[2]), + saturate_cast<_Tp>(a.val[3] + b.val[3])); +} + +template static inline Scalar_<_Tp> operator - (const Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + return Scalar_<_Tp>(saturate_cast<_Tp>(a.val[0] - b.val[0]), + saturate_cast<_Tp>(a.val[1] - b.val[1]), + saturate_cast<_Tp>(a.val[2] - b.val[2]), + saturate_cast<_Tp>(a.val[3] - b.val[3])); +} + +template static inline Scalar_<_Tp> operator * (const Scalar_<_Tp>& a, _Tp alpha) +{ + return Scalar_<_Tp>(saturate_cast<_Tp>(a.val[0] * alpha), + saturate_cast<_Tp>(a.val[1] * alpha), + saturate_cast<_Tp>(a.val[2] * alpha), + saturate_cast<_Tp>(a.val[3] * alpha)); +} + +template static inline Scalar_<_Tp> operator * (_Tp alpha, const Scalar_<_Tp>& a) +{ + return a*alpha; +} + +template static inline Scalar_<_Tp> operator - (const Scalar_<_Tp>& a) +{ + return Scalar_<_Tp>(saturate_cast<_Tp>(-a.val[0]), saturate_cast<_Tp>(-a.val[1]), + saturate_cast<_Tp>(-a.val[2]), saturate_cast<_Tp>(-a.val[3])); +} + + +template static inline Scalar_<_Tp> +operator * (const Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + return Scalar_<_Tp>(saturate_cast<_Tp>(a[0]*b[0] - a[1]*b[1] - a[2]*b[2] - a[3]*b[3]), + saturate_cast<_Tp>(a[0]*b[1] + a[1]*b[0] + a[2]*b[3] - a[3]*b[2]), + saturate_cast<_Tp>(a[0]*b[2] - a[1]*b[3] + a[2]*b[0] + a[3]*b[1]), + saturate_cast<_Tp>(a[0]*b[3] + a[1]*b[2] - a[2]*b[1] + a[3]*b[0])); +} + +template static inline Scalar_<_Tp>& +operator *= (Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + a = a*b; + return a; +} + +template inline Scalar_<_Tp> Scalar_<_Tp>::conj() const +{ + return Scalar_<_Tp>(saturate_cast<_Tp>(this->val[0]), + saturate_cast<_Tp>(-this->val[1]), + saturate_cast<_Tp>(-this->val[2]), + saturate_cast<_Tp>(-this->val[3])); +} + +template inline bool Scalar_<_Tp>::isReal() const +{ + return this->val[1] == 0 && this->val[2] == 0 && this->val[3] == 0; +} + +template static inline +Scalar_<_Tp> operator / (const Scalar_<_Tp>& a, _Tp alpha) +{ + return Scalar_<_Tp>(saturate_cast<_Tp>(a.val[0] / alpha), + saturate_cast<_Tp>(a.val[1] / alpha), + saturate_cast<_Tp>(a.val[2] / alpha), + saturate_cast<_Tp>(a.val[3] / alpha)); +} + +template static inline +Scalar_ operator / (const Scalar_& a, float alpha) +{ + float s = 1/alpha; + return Scalar_(a.val[0]*s, a.val[1]*s, a.val[2]*s, a.val[3]*s); +} + +template static inline +Scalar_ operator / (const Scalar_& a, double alpha) +{ + double s = 1/alpha; + return Scalar_(a.val[0]*s, a.val[1]*s, a.val[2]*s, a.val[3]*s); +} + +template static inline +Scalar_<_Tp>& operator /= (Scalar_<_Tp>& a, _Tp alpha) +{ + a = a/alpha; + return a; +} + +template static inline +Scalar_<_Tp> operator / (_Tp a, const Scalar_<_Tp>& b) +{ + _Tp s = a/(b[0]*b[0] + b[1]*b[1] + b[2]*b[2] + b[3]*b[3]); + return b.conj()*s; +} + +template static inline +Scalar_<_Tp> operator / (const Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + return a*((_Tp)1/b); +} + +template static inline +Scalar_<_Tp>& operator /= (Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + a = a/b; + return a; +} + +//////////////////////////////// Range ///////////////////////////////// + +inline Range::Range() : start(0), end(0) {} +inline Range::Range(int _start, int _end) : start(_start), end(_end) {} +inline Range::Range(const CvSlice& slice) : start(slice.start_index), end(slice.end_index) +{ + if( start == 0 && end == CV_WHOLE_SEQ_END_INDEX ) + *this = Range::all(); +} + +inline int Range::size() const { return end - start; } +inline bool Range::empty() const { return start == end; } +inline Range Range::all() { return Range(INT_MIN, INT_MAX); } + +static inline bool operator == (const Range& r1, const Range& r2) +{ return r1.start == r2.start && r1.end == r2.end; } + +static inline bool operator != (const Range& r1, const Range& r2) +{ return !(r1 == r2); } + +static inline bool operator !(const Range& r) +{ return r.start == r.end; } + +static inline Range operator & (const Range& r1, const Range& r2) +{ + Range r(std::max(r1.start, r2.start), std::min(r1.end, r2.end)); + r.end = std::max(r.end, r.start); + return r; +} + +static inline Range& operator &= (Range& r1, const Range& r2) +{ + r1 = r1 & r2; + return r1; +} + +static inline Range operator + (const Range& r1, int delta) +{ + return Range(r1.start + delta, r1.end + delta); +} + +static inline Range operator + (int delta, const Range& r1) +{ + return Range(r1.start + delta, r1.end + delta); +} + +static inline Range operator - (const Range& r1, int delta) +{ + return r1 + (-delta); +} + +inline Range::operator CvSlice() const +{ return *this != Range::all() ? cvSlice(start, end) : CV_WHOLE_SEQ; } + + + +//////////////////////////////// Vector //////////////////////////////// + +// template vector class. It is similar to STL's vector, +// with a few important differences: +// 1) it can be created on top of user-allocated data w/o copying it +// 2) vector b = a means copying the header, +// not the underlying data (use clone() to make a deep copy) +template class CV_EXPORTS Vector +{ +public: + typedef _Tp value_type; + typedef _Tp* iterator; + typedef const _Tp* const_iterator; + typedef _Tp& reference; + typedef const _Tp& const_reference; + + struct CV_EXPORTS Hdr + { + Hdr() : data(0), datastart(0), refcount(0), size(0), capacity(0) {}; + _Tp* data; + _Tp* datastart; + int* refcount; + size_t size; + size_t capacity; + }; + + Vector() {} + Vector(size_t _size) { resize(_size); } + Vector(size_t _size, const _Tp& val) + { + resize(_size); + for(size_t i = 0; i < _size; i++) + hdr.data[i] = val; + } + Vector(_Tp* _data, size_t _size, bool _copyData=false) + { set(_data, _size, _copyData); } + + template Vector(const Vec<_Tp, n>& vec) + { set((_Tp*)&vec.val[0], n, true); } + + Vector(const std::vector<_Tp>& vec, bool _copyData=false) + { set(!vec.empty() ? (_Tp*)&vec[0] : 0, vec.size(), _copyData); } + + Vector(const Vector& d) { *this = d; } + + Vector(const Vector& d, const Range& r_) + { + Range r = r_ == Range::all() ? Range(0, d.size()) : r_; + /*if( r == Range::all() ) + r = Range(0, d.size());*/ + if( r.size() > 0 && r.start >= 0 && r.end <= d.size() ) + { + if( d.hdr.refcount ) + CV_XADD(d.hdr.refcount, 1); + hdr.refcount = d.hdr.refcount; + hdr.datastart = d.hdr.datastart; + hdr.data = d.hdr.data + r.start; + hdr.capacity = hdr.size = r.size(); + } + } + + Vector<_Tp>& operator = (const Vector& d) + { + if( this != &d ) + { + if( d.hdr.refcount ) + CV_XADD(d.hdr.refcount, 1); + release(); + hdr = d.hdr; + } + return *this; + } + + ~Vector() { release(); } + + Vector<_Tp> clone() const + { return hdr.data ? Vector<_Tp>(hdr.data, hdr.size, true) : Vector<_Tp>(); } + + void copyTo(Vector<_Tp>& vec) const + { + size_t i, sz = size(); + vec.resize(sz); + const _Tp* src = hdr.data; + _Tp* dst = vec.hdr.data; + for( i = 0; i < sz; i++ ) + dst[i] = src[i]; + } + + void copyTo(std::vector<_Tp>& vec) const + { + size_t i, sz = size(); + vec.resize(sz); + const _Tp* src = hdr.data; + _Tp* dst = sz ? &vec[0] : 0; + for( i = 0; i < sz; i++ ) + dst[i] = src[i]; + } + + operator CvMat() const + { return cvMat((int)size(), 1, type(), (void*)hdr.data); } + + _Tp& operator [] (size_t i) { CV_DbgAssert( i < size() ); return hdr.data[i]; } + const _Tp& operator [] (size_t i) const { CV_DbgAssert( i < size() ); return hdr.data[i]; } + Vector operator() (const Range& r) const { return Vector(*this, r); } + _Tp& back() { CV_DbgAssert(!empty()); return hdr.data[hdr.size-1]; } + const _Tp& back() const { CV_DbgAssert(!empty()); return hdr.data[hdr.size-1]; } + _Tp& front() { CV_DbgAssert(!empty()); return hdr.data[0]; } + const _Tp& front() const { CV_DbgAssert(!empty()); return hdr.data[0]; } + + _Tp* begin() { return hdr.data; } + _Tp* end() { return hdr.data + hdr.size; } + const _Tp* begin() const { return hdr.data; } + const _Tp* end() const { return hdr.data + hdr.size; } + + void addref() { if( hdr.refcount ) CV_XADD(hdr.refcount, 1); } + void release() + { + if( hdr.refcount && CV_XADD(hdr.refcount, -1) == 1 ) + { + delete[] hdr.datastart; + delete hdr.refcount; + } + hdr = Hdr(); + } + + void set(_Tp* _data, size_t _size, bool _copyData=false) + { + if( !_copyData ) + { + release(); + hdr.data = hdr.datastart = _data; + hdr.size = hdr.capacity = _size; + hdr.refcount = 0; + } + else + { + reserve(_size); + for( size_t i = 0; i < _size; i++ ) + hdr.data[i] = _data[i]; + hdr.size = _size; + } + } + + void reserve(size_t newCapacity) + { + _Tp* newData; + int* newRefcount; + size_t i, oldSize = hdr.size; + if( (!hdr.refcount || *hdr.refcount == 1) && hdr.capacity >= newCapacity ) + return; + newCapacity = std::max(newCapacity, oldSize); + newData = new _Tp[newCapacity]; + newRefcount = new int(1); + for( i = 0; i < oldSize; i++ ) + newData[i] = hdr.data[i]; + release(); + hdr.data = hdr.datastart = newData; + hdr.capacity = newCapacity; + hdr.size = oldSize; + hdr.refcount = newRefcount; + } + + void resize(size_t newSize) + { + size_t i; + newSize = std::max(newSize, (size_t)0); + if( (!hdr.refcount || *hdr.refcount == 1) && hdr.size == newSize ) + return; + if( newSize > hdr.capacity ) + reserve(std::max(newSize, std::max((size_t)4, hdr.capacity*2))); + for( i = hdr.size; i < newSize; i++ ) + hdr.data[i] = _Tp(); + hdr.size = newSize; + } + + Vector<_Tp>& push_back(const _Tp& elem) + { + if( hdr.size == hdr.capacity ) + reserve( std::max((size_t)4, hdr.capacity*2) ); + hdr.data[hdr.size++] = elem; + return *this; + } + + Vector<_Tp>& pop_back() + { + if( hdr.size > 0 ) + --hdr.size; + return *this; + } + + size_t size() const { return hdr.size; } + size_t capacity() const { return hdr.capacity; } + bool empty() const { return hdr.size == 0; } + void clear() { resize(0); } + int type() const { return DataType<_Tp>::type; } + +protected: + Hdr hdr; +}; + + +template inline typename DataType<_Tp>::work_type +dot(const Vector<_Tp>& v1, const Vector<_Tp>& v2) +{ + typedef typename DataType<_Tp>::work_type _Tw; + size_t i = 0, n = v1.size(); + assert(v1.size() == v2.size()); + + _Tw s = 0; + if( n > 0 ) + { + const _Tp *ptr1 = &v1[0], *ptr2 = &v2[0]; + #if CV_ENABLE_UNROLLED + const size_t n2 = (n > 4) ? n : 4; + for(; i <= n2 - 4; i += 4 ) + s += (_Tw)ptr1[i]*ptr2[i] + (_Tw)ptr1[i+1]*ptr2[i+1] + + (_Tw)ptr1[i+2]*ptr2[i+2] + (_Tw)ptr1[i+3]*ptr2[i+3]; + #endif + for( ; i < n; i++ ) + s += (_Tw)ptr1[i]*ptr2[i]; + } + return s; +} + +// Multiply-with-Carry RNG +inline RNG::RNG() { state = 0xffffffff; } +inline RNG::RNG(uint64 _state) { state = _state ? _state : 0xffffffff; } +inline unsigned RNG::next() +{ + state = (uint64)(unsigned)state*CV_RNG_COEFF + (unsigned)(state >> 32); + return (unsigned)state; +} + +inline RNG::operator uchar() { return (uchar)next(); } +inline RNG::operator schar() { return (schar)next(); } +inline RNG::operator ushort() { return (ushort)next(); } +inline RNG::operator short() { return (short)next(); } +inline RNG::operator unsigned() { return next(); } +inline unsigned RNG::operator ()(unsigned N) {return (unsigned)uniform(0,N);} +inline unsigned RNG::operator ()() {return next();} +inline RNG::operator int() { return (int)next(); } +// * (2^32-1)^-1 +inline RNG::operator float() { return next()*2.3283064365386962890625e-10f; } +inline RNG::operator double() +{ + unsigned t = next(); + return (((uint64)t << 32) | next())*5.4210108624275221700372640043497e-20; +} +inline int RNG::uniform(int a, int b) { return a == b ? a : (int)(next()%(b - a) + a); } +inline float RNG::uniform(float a, float b) { return ((float)*this)*(b - a) + a; } +inline double RNG::uniform(double a, double b) { return ((double)*this)*(b - a) + a; } + +inline TermCriteria::TermCriteria() : type(0), maxCount(0), epsilon(0) {} +inline TermCriteria::TermCriteria(int _type, int _maxCount, double _epsilon) + : type(_type), maxCount(_maxCount), epsilon(_epsilon) {} +inline TermCriteria::TermCriteria(const CvTermCriteria& criteria) + : type(criteria.type), maxCount(criteria.max_iter), epsilon(criteria.epsilon) {} +inline TermCriteria::operator CvTermCriteria() const +{ return cvTermCriteria(type, maxCount, epsilon); } + +inline uchar* LineIterator::operator *() { return ptr; } +inline LineIterator& LineIterator::operator ++() +{ + int mask = err < 0 ? -1 : 0; + err += minusDelta + (plusDelta & mask); + ptr += minusStep + (plusStep & mask); + return *this; +} +inline LineIterator LineIterator::operator ++(int) +{ + LineIterator it = *this; + ++(*this); + return it; +} +inline Point LineIterator::pos() const +{ + Point p; + p.y = (int)((ptr - ptr0)/step); + p.x = (int)(((ptr - ptr0) - p.y*step)/elemSize); + return p; +} + +/////////////////////////////// AutoBuffer //////////////////////////////////////// + +template inline AutoBuffer<_Tp, fixed_size>::AutoBuffer() +{ + ptr = buf; + size = fixed_size; +} + +template inline AutoBuffer<_Tp, fixed_size>::AutoBuffer(size_t _size) +{ + ptr = buf; + size = fixed_size; + allocate(_size); +} + +template inline AutoBuffer<_Tp, fixed_size>::~AutoBuffer() +{ deallocate(); } + +template inline void AutoBuffer<_Tp, fixed_size>::allocate(size_t _size) +{ + if(_size <= size) + return; + deallocate(); + if(_size > fixed_size) + { + ptr = cv::allocate<_Tp>(_size); + size = _size; + } +} + +template inline void AutoBuffer<_Tp, fixed_size>::deallocate() +{ + if( ptr != buf ) + { + cv::deallocate<_Tp>(ptr, size); + ptr = buf; + size = fixed_size; + } +} + +template inline AutoBuffer<_Tp, fixed_size>::operator _Tp* () +{ return ptr; } + +template inline AutoBuffer<_Tp, fixed_size>::operator const _Tp* () const +{ return ptr; } + + +/////////////////////////////////// Ptr //////////////////////////////////////// + +template inline Ptr<_Tp>::Ptr() : obj(0), refcount(0) {} +template inline Ptr<_Tp>::Ptr(_Tp* _obj) : obj(_obj) +{ + if(obj) + { + refcount = (int*)fastMalloc(sizeof(*refcount)); + *refcount = 1; + } + else + refcount = 0; +} + +template inline void Ptr<_Tp>::addref() +{ if( refcount ) CV_XADD(refcount, 1); } + +template inline void Ptr<_Tp>::release() +{ + if( refcount && CV_XADD(refcount, -1) == 1 ) + { + delete_obj(); + fastFree(refcount); + } + refcount = 0; + obj = 0; +} + +template inline void Ptr<_Tp>::delete_obj() +{ + if( obj ) delete obj; +} + +template inline Ptr<_Tp>::~Ptr() { release(); } + +template inline Ptr<_Tp>::Ptr(const Ptr<_Tp>& _ptr) +{ + obj = _ptr.obj; + refcount = _ptr.refcount; + addref(); +} + +template inline Ptr<_Tp>& Ptr<_Tp>::operator = (const Ptr<_Tp>& _ptr) +{ + int* _refcount = _ptr.refcount; + if( _refcount ) + CV_XADD(_refcount, 1); + release(); + obj = _ptr.obj; + refcount = _refcount; + return *this; +} + +template inline _Tp* Ptr<_Tp>::operator -> () { return obj; } +template inline const _Tp* Ptr<_Tp>::operator -> () const { return obj; } + +template inline Ptr<_Tp>::operator _Tp* () { return obj; } +template inline Ptr<_Tp>::operator const _Tp*() const { return obj; } + +template inline bool Ptr<_Tp>::empty() const { return obj == 0; } + +template template Ptr<_Tp>::Ptr(const Ptr<_Tp2>& p) + : obj(0), refcount(0) +{ + if (p.empty()) + return; + + _Tp* p_casted = dynamic_cast<_Tp*>(p.obj); + if (!p_casted) + return; + + obj = p_casted; + refcount = p.refcount; + addref(); +} + +template template inline Ptr<_Tp2> Ptr<_Tp>::ptr() +{ + Ptr<_Tp2> p; + if( !obj ) + return p; + + _Tp2* obj_casted = dynamic_cast<_Tp2*>(obj); + if (!obj_casted) + return p; + + if( refcount ) + CV_XADD(refcount, 1); + + p.obj = obj_casted; + p.refcount = refcount; + return p; +} + +template template inline const Ptr<_Tp2> Ptr<_Tp>::ptr() const +{ + Ptr<_Tp2> p; + if( !obj ) + return p; + + _Tp2* obj_casted = dynamic_cast<_Tp2*>(obj); + if (!obj_casted) + return p; + + if( refcount ) + CV_XADD(refcount, 1); + + p.obj = obj_casted; + p.refcount = refcount; + return p; +} + +//// specializied implementations of Ptr::delete_obj() for classic OpenCV types + +template<> CV_EXPORTS void Ptr::delete_obj(); +template<> CV_EXPORTS void Ptr::delete_obj(); +template<> CV_EXPORTS void Ptr::delete_obj(); +template<> CV_EXPORTS void Ptr::delete_obj(); +template<> CV_EXPORTS void Ptr::delete_obj(); +template<> CV_EXPORTS void Ptr::delete_obj(); + +//////////////////////////////////////// XML & YAML I/O //////////////////////////////////// + +CV_EXPORTS_W void write( FileStorage& fs, const string& name, int value ); +CV_EXPORTS_W void write( FileStorage& fs, const string& name, float value ); +CV_EXPORTS_W void write( FileStorage& fs, const string& name, double value ); +CV_EXPORTS_W void write( FileStorage& fs, const string& name, const string& value ); + +template inline void write(FileStorage& fs, const _Tp& value) +{ write(fs, string(), value); } + +CV_EXPORTS void writeScalar( FileStorage& fs, int value ); +CV_EXPORTS void writeScalar( FileStorage& fs, float value ); +CV_EXPORTS void writeScalar( FileStorage& fs, double value ); +CV_EXPORTS void writeScalar( FileStorage& fs, const string& value ); + +template<> inline void write( FileStorage& fs, const int& value ) +{ + writeScalar(fs, value); +} + +template<> inline void write( FileStorage& fs, const float& value ) +{ + writeScalar(fs, value); +} + +template<> inline void write( FileStorage& fs, const double& value ) +{ + writeScalar(fs, value); +} + +template<> inline void write( FileStorage& fs, const string& value ) +{ + writeScalar(fs, value); +} + +template inline void write(FileStorage& fs, const Point_<_Tp>& pt ) +{ + write(fs, pt.x); + write(fs, pt.y); +} + +template inline void write(FileStorage& fs, const Point3_<_Tp>& pt ) +{ + write(fs, pt.x); + write(fs, pt.y); + write(fs, pt.z); +} + +template inline void write(FileStorage& fs, const Size_<_Tp>& sz ) +{ + write(fs, sz.width); + write(fs, sz.height); +} + +template inline void write(FileStorage& fs, const Complex<_Tp>& c ) +{ + write(fs, c.re); + write(fs, c.im); +} + +template inline void write(FileStorage& fs, const Rect_<_Tp>& r ) +{ + write(fs, r.x); + write(fs, r.y); + write(fs, r.width); + write(fs, r.height); +} + +template inline void write(FileStorage& fs, const Vec<_Tp, cn>& v ) +{ + for(int i = 0; i < cn; i++) + write(fs, v.val[i]); +} + +template inline void write(FileStorage& fs, const Scalar_<_Tp>& s ) +{ + write(fs, s.val[0]); + write(fs, s.val[1]); + write(fs, s.val[2]); + write(fs, s.val[3]); +} + +inline void write(FileStorage& fs, const Range& r ) +{ + write(fs, r.start); + write(fs, r.end); +} + +class CV_EXPORTS WriteStructContext +{ +public: + WriteStructContext(FileStorage& _fs, const string& name, + int flags, const string& typeName=string()); + ~WriteStructContext(); + FileStorage* fs; +}; + +template inline void write(FileStorage& fs, const string& name, const Point_<_Tp>& pt ) +{ + WriteStructContext ws(fs, name, CV_NODE_SEQ+CV_NODE_FLOW); + write(fs, pt.x); + write(fs, pt.y); +} + +template inline void write(FileStorage& fs, const string& name, const Point3_<_Tp>& pt ) +{ + WriteStructContext ws(fs, name, CV_NODE_SEQ+CV_NODE_FLOW); + write(fs, pt.x); + write(fs, pt.y); + write(fs, pt.z); +} + +template inline void write(FileStorage& fs, const string& name, const Size_<_Tp>& sz ) +{ + WriteStructContext ws(fs, name, CV_NODE_SEQ+CV_NODE_FLOW); + write(fs, sz.width); + write(fs, sz.height); +} + +template inline void write(FileStorage& fs, const string& name, const Complex<_Tp>& c ) +{ + WriteStructContext ws(fs, name, CV_NODE_SEQ+CV_NODE_FLOW); + write(fs, c.re); + write(fs, c.im); +} + +template inline void write(FileStorage& fs, const string& name, const Rect_<_Tp>& r ) +{ + WriteStructContext ws(fs, name, CV_NODE_SEQ+CV_NODE_FLOW); + write(fs, r.x); + write(fs, r.y); + write(fs, r.width); + write(fs, r.height); +} + +template inline void write(FileStorage& fs, const string& name, const Vec<_Tp, cn>& v ) +{ + WriteStructContext ws(fs, name, CV_NODE_SEQ+CV_NODE_FLOW); + for(int i = 0; i < cn; i++) + write(fs, v.val[i]); +} + +template inline void write(FileStorage& fs, const string& name, const Scalar_<_Tp>& s ) +{ + WriteStructContext ws(fs, name, CV_NODE_SEQ+CV_NODE_FLOW); + write(fs, s.val[0]); + write(fs, s.val[1]); + write(fs, s.val[2]); + write(fs, s.val[3]); +} + +inline void write(FileStorage& fs, const string& name, const Range& r ) +{ + WriteStructContext ws(fs, name, CV_NODE_SEQ+CV_NODE_FLOW); + write(fs, r.start); + write(fs, r.end); +} + +template class CV_EXPORTS VecWriterProxy +{ +public: + VecWriterProxy( FileStorage* _fs ) : fs(_fs) {} + void operator()(const vector<_Tp>& vec) const + { + size_t i, count = vec.size(); + for( i = 0; i < count; i++ ) + write( *fs, vec[i] ); + } + FileStorage* fs; +}; + +template class CV_EXPORTS VecWriterProxy<_Tp,1> +{ +public: + VecWriterProxy( FileStorage* _fs ) : fs(_fs) {} + void operator()(const vector<_Tp>& vec) const + { + int _fmt = DataType<_Tp>::fmt; + char fmt[] = { (char)((_fmt>>8)+'1'), (char)_fmt, '\0' }; + fs->writeRaw( string(fmt), !vec.empty() ? (uchar*)&vec[0] : 0, vec.size()*sizeof(_Tp) ); + } + FileStorage* fs; +}; + +template static inline void write( FileStorage& fs, const vector<_Tp>& vec ) +{ + VecWriterProxy<_Tp, DataType<_Tp>::fmt != 0> w(&fs); + w(vec); +} + +template static inline void write( FileStorage& fs, const string& name, + const vector<_Tp>& vec ) +{ + WriteStructContext ws(fs, name, CV_NODE_SEQ+(DataType<_Tp>::fmt != 0 ? CV_NODE_FLOW : 0)); + write(fs, vec); +} + +CV_EXPORTS_W void write( FileStorage& fs, const string& name, const Mat& value ); +CV_EXPORTS void write( FileStorage& fs, const string& name, const SparseMat& value ); + +template static inline FileStorage& operator << (FileStorage& fs, const _Tp& value) +{ + if( !fs.isOpened() ) + return fs; + if( fs.state == FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP ) + CV_Error( CV_StsError, "No element name has been given" ); + write( fs, fs.elname, value ); + if( fs.state & FileStorage::INSIDE_MAP ) + fs.state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP; + return fs; +} + +CV_EXPORTS FileStorage& operator << (FileStorage& fs, const string& str); + +static inline FileStorage& operator << (FileStorage& fs, const char* str) +{ return (fs << string(str)); } + +inline FileNode::FileNode() : fs(0), node(0) {} +inline FileNode::FileNode(const CvFileStorage* _fs, const CvFileNode* _node) + : fs(_fs), node(_node) {} + +inline FileNode::FileNode(const FileNode& _node) : fs(_node.fs), node(_node.node) {} + +inline int FileNode::type() const { return !node ? NONE : (node->tag & TYPE_MASK); } +inline bool FileNode::empty() const { return node == 0; } +inline bool FileNode::isNone() const { return type() == NONE; } +inline bool FileNode::isSeq() const { return type() == SEQ; } +inline bool FileNode::isMap() const { return type() == MAP; } +inline bool FileNode::isInt() const { return type() == INT; } +inline bool FileNode::isReal() const { return type() == REAL; } +inline bool FileNode::isString() const { return type() == STR; } +inline bool FileNode::isNamed() const { return !node ? false : (node->tag & NAMED) != 0; } +inline size_t FileNode::size() const +{ + int t = type(); + return t == MAP ? (size_t)((CvSet*)node->data.map)->active_count : + t == SEQ ? (size_t)node->data.seq->total : (size_t)!isNone(); +} + +inline CvFileNode* FileNode::operator *() { return (CvFileNode*)node; } +inline const CvFileNode* FileNode::operator* () const { return node; } + +static inline void read(const FileNode& node, int& value, int default_value) +{ + value = !node.node ? default_value : + CV_NODE_IS_INT(node.node->tag) ? node.node->data.i : + CV_NODE_IS_REAL(node.node->tag) ? cvRound(node.node->data.f) : 0x7fffffff; +} + +static inline void read(const FileNode& node, bool& value, bool default_value) +{ + int temp; read(node, temp, (int)default_value); + value = temp != 0; +} + +static inline void read(const FileNode& node, uchar& value, uchar default_value) +{ + int temp; read(node, temp, (int)default_value); + value = saturate_cast(temp); +} + +static inline void read(const FileNode& node, schar& value, schar default_value) +{ + int temp; read(node, temp, (int)default_value); + value = saturate_cast(temp); +} + +static inline void read(const FileNode& node, ushort& value, ushort default_value) +{ + int temp; read(node, temp, (int)default_value); + value = saturate_cast(temp); +} + +static inline void read(const FileNode& node, short& value, short default_value) +{ + int temp; read(node, temp, (int)default_value); + value = saturate_cast(temp); +} + +static inline void read(const FileNode& node, float& value, float default_value) +{ + value = !node.node ? default_value : + CV_NODE_IS_INT(node.node->tag) ? (float)node.node->data.i : + CV_NODE_IS_REAL(node.node->tag) ? (float)node.node->data.f : 1e30f; +} + +static inline void read(const FileNode& node, double& value, double default_value) +{ + value = !node.node ? default_value : + CV_NODE_IS_INT(node.node->tag) ? (double)node.node->data.i : + CV_NODE_IS_REAL(node.node->tag) ? node.node->data.f : 1e300; +} + +static inline void read(const FileNode& node, string& value, const string& default_value) +{ + value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? string(node.node->data.str.ptr) : string(""); +} + +CV_EXPORTS_W void read(const FileNode& node, Mat& mat, const Mat& default_mat=Mat() ); +CV_EXPORTS void read(const FileNode& node, SparseMat& mat, const SparseMat& default_mat=SparseMat() ); + +inline FileNode::operator int() const +{ + int value; + read(*this, value, 0); + return value; +} +inline FileNode::operator float() const +{ + float value; + read(*this, value, 0.f); + return value; +} +inline FileNode::operator double() const +{ + double value; + read(*this, value, 0.); + return value; +} +inline FileNode::operator string() const +{ + string value; + read(*this, value, value); + return value; +} + +inline void FileNode::readRaw( const string& fmt, uchar* vec, size_t len ) const +{ + begin().readRaw( fmt, vec, len ); +} + +template class CV_EXPORTS VecReaderProxy +{ +public: + VecReaderProxy( FileNodeIterator* _it ) : it(_it) {} + void operator()(vector<_Tp>& vec, size_t count) const + { + count = std::min(count, it->remaining); + vec.resize(count); + for( size_t i = 0; i < count; i++, ++(*it) ) + read(**it, vec[i], _Tp()); + } + FileNodeIterator* it; +}; + +template class CV_EXPORTS VecReaderProxy<_Tp,1> +{ +public: + VecReaderProxy( FileNodeIterator* _it ) : it(_it) {} + void operator()(vector<_Tp>& vec, size_t count) const + { + size_t remaining = it->remaining, cn = DataType<_Tp>::channels; + int _fmt = DataType<_Tp>::fmt; + char fmt[] = { (char)((_fmt>>8)+'1'), (char)_fmt, '\0' }; + size_t remaining1 = remaining/cn; + count = count < remaining1 ? count : remaining1; + vec.resize(count); + it->readRaw( string(fmt), !vec.empty() ? (uchar*)&vec[0] : 0, count*sizeof(_Tp) ); + } + FileNodeIterator* it; +}; + +template static inline void +read( FileNodeIterator& it, vector<_Tp>& vec, size_t maxCount=(size_t)INT_MAX ) +{ + VecReaderProxy<_Tp, DataType<_Tp>::fmt != 0> r(&it); + r(vec, maxCount); +} + +template static inline void +read( const FileNode& node, vector<_Tp>& vec, const vector<_Tp>& default_value=vector<_Tp>() ) +{ + if(!node.node) + vec = default_value; + else + { + FileNodeIterator it = node.begin(); + read( it, vec ); + } +} + +inline FileNodeIterator FileNode::begin() const +{ + return FileNodeIterator(fs, node); +} + +inline FileNodeIterator FileNode::end() const +{ + return FileNodeIterator(fs, node, size()); +} + +inline FileNode FileNodeIterator::operator *() const +{ return FileNode(fs, (const CvFileNode*)reader.ptr); } + +inline FileNode FileNodeIterator::operator ->() const +{ return FileNode(fs, (const CvFileNode*)reader.ptr); } + +template static inline FileNodeIterator& operator >> (FileNodeIterator& it, _Tp& value) +{ read( *it, value, _Tp()); return ++it; } + +template static inline +FileNodeIterator& operator >> (FileNodeIterator& it, vector<_Tp>& vec) +{ + VecReaderProxy<_Tp, DataType<_Tp>::fmt != 0> r(&it); + r(vec, (size_t)INT_MAX); + return it; +} + +template static inline void operator >> (const FileNode& n, _Tp& value) +{ read( n, value, _Tp()); } + +template static inline void operator >> (const FileNode& n, vector<_Tp>& vec) +{ FileNodeIterator it = n.begin(); it >> vec; } + +static inline bool operator == (const FileNodeIterator& it1, const FileNodeIterator& it2) +{ + return it1.fs == it2.fs && it1.container == it2.container && + it1.reader.ptr == it2.reader.ptr && it1.remaining == it2.remaining; +} + +static inline bool operator != (const FileNodeIterator& it1, const FileNodeIterator& it2) +{ + return !(it1 == it2); +} + +static inline ptrdiff_t operator - (const FileNodeIterator& it1, const FileNodeIterator& it2) +{ + return it2.remaining - it1.remaining; +} + +static inline bool operator < (const FileNodeIterator& it1, const FileNodeIterator& it2) +{ + return it1.remaining > it2.remaining; +} + +inline FileNode FileStorage::getFirstTopLevelNode() const +{ + FileNode r = root(); + FileNodeIterator it = r.begin(); + return it != r.end() ? *it : FileNode(); +} + +//////////////////////////////////////// Various algorithms //////////////////////////////////// + +template static inline _Tp gcd(_Tp a, _Tp b) +{ + if( a < b ) + std::swap(a, b); + while( b > 0 ) + { + _Tp r = a % b; + a = b; + b = r; + } + return a; +} + +/****************************************************************************************\ + + Generic implementation of QuickSort algorithm + Use it as: vector<_Tp> a; ... sort(a,); + + The current implementation was derived from *BSD system qsort(): + + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + +\****************************************************************************************/ + +template void sort( vector<_Tp>& vec, _LT LT=_LT() ) +{ + int isort_thresh = 7; + int sp = 0; + + struct + { + _Tp *lb; + _Tp *ub; + } stack[48]; + + size_t total = vec.size(); + + if( total <= 1 ) + return; + + _Tp* arr = &vec[0]; + stack[0].lb = arr; + stack[0].ub = arr + (total - 1); + + while( sp >= 0 ) + { + _Tp* left = stack[sp].lb; + _Tp* right = stack[sp--].ub; + + for(;;) + { + int i, n = (int)(right - left) + 1, m; + _Tp* ptr; + _Tp* ptr2; + + if( n <= isort_thresh ) + { + insert_sort: + for( ptr = left + 1; ptr <= right; ptr++ ) + { + for( ptr2 = ptr; ptr2 > left && LT(ptr2[0],ptr2[-1]); ptr2--) + std::swap( ptr2[0], ptr2[-1] ); + } + break; + } + else + { + _Tp* left0; + _Tp* left1; + _Tp* right0; + _Tp* right1; + _Tp* pivot; + _Tp* a; + _Tp* b; + _Tp* c; + int swap_cnt = 0; + + left0 = left; + right0 = right; + pivot = left + (n/2); + + if( n > 40 ) + { + int d = n / 8; + a = left, b = left + d, c = left + 2*d; + left = LT(*a, *b) ? (LT(*b, *c) ? b : (LT(*a, *c) ? c : a)) + : (LT(*c, *b) ? b : (LT(*a, *c) ? a : c)); + + a = pivot - d, b = pivot, c = pivot + d; + pivot = LT(*a, *b) ? (LT(*b, *c) ? b : (LT(*a, *c) ? c : a)) + : (LT(*c, *b) ? b : (LT(*a, *c) ? a : c)); + + a = right - 2*d, b = right - d, c = right; + right = LT(*a, *b) ? (LT(*b, *c) ? b : (LT(*a, *c) ? c : a)) + : (LT(*c, *b) ? b : (LT(*a, *c) ? a : c)); + } + + a = left, b = pivot, c = right; + pivot = LT(*a, *b) ? (LT(*b, *c) ? b : (LT(*a, *c) ? c : a)) + : (LT(*c, *b) ? b : (LT(*a, *c) ? a : c)); + if( pivot != left0 ) + { + std::swap( *pivot, *left0 ); + pivot = left0; + } + left = left1 = left0 + 1; + right = right1 = right0; + + for(;;) + { + while( left <= right && !LT(*pivot, *left) ) + { + if( !LT(*left, *pivot) ) + { + if( left > left1 ) + std::swap( *left1, *left ); + swap_cnt = 1; + left1++; + } + left++; + } + + while( left <= right && !LT(*right, *pivot) ) + { + if( !LT(*pivot, *right) ) + { + if( right < right1 ) + std::swap( *right1, *right ); + swap_cnt = 1; + right1--; + } + right--; + } + + if( left > right ) + break; + std::swap( *left, *right ); + swap_cnt = 1; + left++; + right--; + } + + if( swap_cnt == 0 ) + { + left = left0, right = right0; + goto insert_sort; + } + + n = std::min( (int)(left1 - left0), (int)(left - left1) ); + for( i = 0; i < n; i++ ) + std::swap( left0[i], left[i-n] ); + + n = std::min( (int)(right0 - right1), (int)(right1 - right) ); + for( i = 0; i < n; i++ ) + std::swap( left[i], right0[i-n+1] ); + n = (int)(left - left1); + m = (int)(right1 - right); + if( n > 1 ) + { + if( m > 1 ) + { + if( n > m ) + { + stack[++sp].lb = left0; + stack[sp].ub = left0 + n - 1; + left = right0 - m + 1, right = right0; + } + else + { + stack[++sp].lb = right0 - m + 1; + stack[sp].ub = right0; + left = left0, right = left0 + n - 1; + } + } + else + left = left0, right = left0 + n - 1; + } + else if( m > 1 ) + left = right0 - m + 1, right = right0; + else + break; + } + } + } +} + +template class CV_EXPORTS LessThan +{ +public: + bool operator()(const _Tp& a, const _Tp& b) const { return a < b; } +}; + +template class CV_EXPORTS GreaterEq +{ +public: + bool operator()(const _Tp& a, const _Tp& b) const { return a >= b; } +}; + +template class CV_EXPORTS LessThanIdx +{ +public: + LessThanIdx( const _Tp* _arr ) : arr(_arr) {} + bool operator()(int a, int b) const { return arr[a] < arr[b]; } + const _Tp* arr; +}; + +template class CV_EXPORTS GreaterEqIdx +{ +public: + GreaterEqIdx( const _Tp* _arr ) : arr(_arr) {} + bool operator()(int a, int b) const { return arr[a] >= arr[b]; } + const _Tp* arr; +}; + + +// This function splits the input sequence or set into one or more equivalence classes and +// returns the vector of labels - 0-based class indexes for each element. +// predicate(a,b) returns true if the two sequence elements certainly belong to the same class. +// +// The algorithm is described in "Introduction to Algorithms" +// by Cormen, Leiserson and Rivest, the chapter "Data structures for disjoint sets" +template int +partition( const vector<_Tp>& _vec, vector& labels, + _EqPredicate predicate=_EqPredicate()) +{ + int i, j, N = (int)_vec.size(); + const _Tp* vec = &_vec[0]; + + const int PARENT=0; + const int RANK=1; + + vector _nodes(N*2); + int (*nodes)[2] = (int(*)[2])&_nodes[0]; + + // The first O(N) pass: create N single-vertex trees + for(i = 0; i < N; i++) + { + nodes[i][PARENT]=-1; + nodes[i][RANK] = 0; + } + + // The main O(N^2) pass: merge connected components + for( i = 0; i < N; i++ ) + { + int root = i; + + // find root + while( nodes[root][PARENT] >= 0 ) + root = nodes[root][PARENT]; + + for( j = 0; j < N; j++ ) + { + if( i == j || !predicate(vec[i], vec[j])) + continue; + int root2 = j; + + while( nodes[root2][PARENT] >= 0 ) + root2 = nodes[root2][PARENT]; + + if( root2 != root ) + { + // unite both trees + int rank = nodes[root][RANK], rank2 = nodes[root2][RANK]; + if( rank > rank2 ) + nodes[root2][PARENT] = root; + else + { + nodes[root][PARENT] = root2; + nodes[root2][RANK] += rank == rank2; + root = root2; + } + assert( nodes[root][PARENT] < 0 ); + + int k = j, parent; + + // compress the path from node2 to root + while( (parent = nodes[k][PARENT]) >= 0 ) + { + nodes[k][PARENT] = root; + k = parent; + } + + // compress the path from node to root + k = i; + while( (parent = nodes[k][PARENT]) >= 0 ) + { + nodes[k][PARENT] = root; + k = parent; + } + } + } + } + + // Final O(N) pass: enumerate classes + labels.resize(N); + int nclasses = 0; + + for( i = 0; i < N; i++ ) + { + int root = i; + while( nodes[root][PARENT] >= 0 ) + root = nodes[root][PARENT]; + // re-use the rank as the class label + if( nodes[root][RANK] >= 0 ) + nodes[root][RANK] = ~nclasses++; + labels[i] = ~nodes[root][RANK]; + } + + return nclasses; +} + + +////////////////////////////////////////////////////////////////////////////// + +// bridge C++ => C Seq API +CV_EXPORTS schar* seqPush( CvSeq* seq, const void* element=0); +CV_EXPORTS schar* seqPushFront( CvSeq* seq, const void* element=0); +CV_EXPORTS void seqPop( CvSeq* seq, void* element=0); +CV_EXPORTS void seqPopFront( CvSeq* seq, void* element=0); +CV_EXPORTS void seqPopMulti( CvSeq* seq, void* elements, + int count, int in_front=0 ); +CV_EXPORTS void seqRemove( CvSeq* seq, int index ); +CV_EXPORTS void clearSeq( CvSeq* seq ); +CV_EXPORTS schar* getSeqElem( const CvSeq* seq, int index ); +CV_EXPORTS void seqRemoveSlice( CvSeq* seq, CvSlice slice ); +CV_EXPORTS void seqInsertSlice( CvSeq* seq, int before_index, const CvArr* from_arr ); + +template inline Seq<_Tp>::Seq() : seq(0) {} +template inline Seq<_Tp>::Seq( const CvSeq* _seq ) : seq((CvSeq*)_seq) +{ + CV_Assert(!_seq || _seq->elem_size == sizeof(_Tp)); +} + +template inline Seq<_Tp>::Seq( MemStorage& storage, + int headerSize ) +{ + CV_Assert(headerSize >= (int)sizeof(CvSeq)); + seq = cvCreateSeq(DataType<_Tp>::type, headerSize, sizeof(_Tp), storage); +} + +template inline _Tp& Seq<_Tp>::operator [](int idx) +{ return *(_Tp*)getSeqElem(seq, idx); } + +template inline const _Tp& Seq<_Tp>::operator [](int idx) const +{ return *(_Tp*)getSeqElem(seq, idx); } + +template inline SeqIterator<_Tp> Seq<_Tp>::begin() const +{ return SeqIterator<_Tp>(*this); } + +template inline SeqIterator<_Tp> Seq<_Tp>::end() const +{ return SeqIterator<_Tp>(*this, true); } + +template inline size_t Seq<_Tp>::size() const +{ return seq ? seq->total : 0; } + +template inline int Seq<_Tp>::type() const +{ return seq ? CV_MAT_TYPE(seq->flags) : 0; } + +template inline int Seq<_Tp>::depth() const +{ return seq ? CV_MAT_DEPTH(seq->flags) : 0; } + +template inline int Seq<_Tp>::channels() const +{ return seq ? CV_MAT_CN(seq->flags) : 0; } + +template inline size_t Seq<_Tp>::elemSize() const +{ return seq ? seq->elem_size : 0; } + +template inline size_t Seq<_Tp>::index(const _Tp& elem) const +{ return cvSeqElemIdx(seq, &elem); } + +template inline void Seq<_Tp>::push_back(const _Tp& elem) +{ cvSeqPush(seq, &elem); } + +template inline void Seq<_Tp>::push_front(const _Tp& elem) +{ cvSeqPushFront(seq, &elem); } + +template inline void Seq<_Tp>::push_back(const _Tp* elem, size_t count) +{ cvSeqPushMulti(seq, elem, (int)count, 0); } + +template inline void Seq<_Tp>::push_front(const _Tp* elem, size_t count) +{ cvSeqPushMulti(seq, elem, (int)count, 1); } + +template inline _Tp& Seq<_Tp>::back() +{ return *(_Tp*)getSeqElem(seq, -1); } + +template inline const _Tp& Seq<_Tp>::back() const +{ return *(const _Tp*)getSeqElem(seq, -1); } + +template inline _Tp& Seq<_Tp>::front() +{ return *(_Tp*)getSeqElem(seq, 0); } + +template inline const _Tp& Seq<_Tp>::front() const +{ return *(const _Tp*)getSeqElem(seq, 0); } + +template inline bool Seq<_Tp>::empty() const +{ return !seq || seq->total == 0; } + +template inline void Seq<_Tp>::clear() +{ if(seq) clearSeq(seq); } + +template inline void Seq<_Tp>::pop_back() +{ seqPop(seq); } + +template inline void Seq<_Tp>::pop_front() +{ seqPopFront(seq); } + +template inline void Seq<_Tp>::pop_back(_Tp* elem, size_t count) +{ seqPopMulti(seq, elem, (int)count, 0); } + +template inline void Seq<_Tp>::pop_front(_Tp* elem, size_t count) +{ seqPopMulti(seq, elem, (int)count, 1); } + +template inline void Seq<_Tp>::insert(int idx, const _Tp& elem) +{ seqInsert(seq, idx, &elem); } + +template inline void Seq<_Tp>::insert(int idx, const _Tp* elems, size_t count) +{ + CvMat m = cvMat(1, count, DataType<_Tp>::type, elems); + seqInsertSlice(seq, idx, &m); +} + +template inline void Seq<_Tp>::remove(int idx) +{ seqRemove(seq, idx); } + +template inline void Seq<_Tp>::remove(const Range& r) +{ seqRemoveSlice(seq, r); } + +template inline void Seq<_Tp>::copyTo(vector<_Tp>& vec, const Range& range) const +{ + size_t len = !seq ? 0 : range == Range::all() ? seq->total : range.end - range.start; + vec.resize(len); + if( seq && len ) + cvCvtSeqToArray(seq, &vec[0], range); +} + +template inline Seq<_Tp>::operator vector<_Tp>() const +{ + vector<_Tp> vec; + copyTo(vec); + return vec; +} + +template inline SeqIterator<_Tp>::SeqIterator() +{ memset(this, 0, sizeof(*this)); } + +template inline SeqIterator<_Tp>::SeqIterator(const Seq<_Tp>& _seq, bool seekEnd) +{ + cvStartReadSeq(_seq.seq, this); + index = seekEnd ? _seq.seq->total : 0; +} + +template inline void SeqIterator<_Tp>::seek(size_t pos) +{ + cvSetSeqReaderPos(this, (int)pos, false); + index = pos; +} + +template inline size_t SeqIterator<_Tp>::tell() const +{ return index; } + +template inline _Tp& SeqIterator<_Tp>::operator *() +{ return *(_Tp*)ptr; } + +template inline const _Tp& SeqIterator<_Tp>::operator *() const +{ return *(const _Tp*)ptr; } + +template inline SeqIterator<_Tp>& SeqIterator<_Tp>::operator ++() +{ + CV_NEXT_SEQ_ELEM(sizeof(_Tp), *this); + if( ++index >= seq->total*2 ) + index = 0; + return *this; +} + +template inline SeqIterator<_Tp> SeqIterator<_Tp>::operator ++(int) const +{ + SeqIterator<_Tp> it = *this; + ++*this; + return it; +} + +template inline SeqIterator<_Tp>& SeqIterator<_Tp>::operator --() +{ + CV_PREV_SEQ_ELEM(sizeof(_Tp), *this); + if( --index < 0 ) + index = seq->total*2-1; + return *this; +} + +template inline SeqIterator<_Tp> SeqIterator<_Tp>::operator --(int) const +{ + SeqIterator<_Tp> it = *this; + --*this; + return it; +} + +template inline SeqIterator<_Tp>& SeqIterator<_Tp>::operator +=(int delta) +{ + cvSetSeqReaderPos(this, delta, 1); + index += delta; + int n = seq->total*2; + if( index < 0 ) + index += n; + if( index >= n ) + index -= n; + return *this; +} + +template inline SeqIterator<_Tp>& SeqIterator<_Tp>::operator -=(int delta) +{ + return (*this += -delta); +} + +template inline ptrdiff_t operator - (const SeqIterator<_Tp>& a, + const SeqIterator<_Tp>& b) +{ + ptrdiff_t delta = a.index - b.index, n = a.seq->total; + if( std::abs(static_cast(delta)) > n ) + delta += delta < 0 ? n : -n; + return delta; +} + +template inline bool operator == (const SeqIterator<_Tp>& a, + const SeqIterator<_Tp>& b) +{ + return a.seq == b.seq && a.index == b.index; +} + +template inline bool operator != (const SeqIterator<_Tp>& a, + const SeqIterator<_Tp>& b) +{ + return !(a == b); +} + + +template struct CV_EXPORTS RTTIImpl +{ +public: + static int isInstance(const void* ptr) + { + static _ClsName dummy; + static void* dummyp = &dummy; + union + { + const void* p; + const void** pp; + } a, b; + a.p = dummyp; + b.p = ptr; + return *a.pp == *b.pp; + } + static void release(void** dbptr) + { + if(dbptr && *dbptr) + { + delete (_ClsName*)*dbptr; + *dbptr = 0; + } + } + static void* read(CvFileStorage* fs, CvFileNode* n) + { + FileNode fn(fs, n); + _ClsName* obj = new _ClsName; + if(obj->read(fn)) + return obj; + delete obj; + return 0; + } + + static void write(CvFileStorage* _fs, const char* name, const void* ptr, CvAttrList) + { + if(ptr && _fs) + { + FileStorage fs(_fs); + fs.fs.addref(); + ((const _ClsName*)ptr)->write(fs, string(name)); + } + } + + static void* clone(const void* ptr) + { + if(!ptr) + return 0; + return new _ClsName(*(const _ClsName*)ptr); + } +}; + + +class CV_EXPORTS Formatter +{ +public: + virtual ~Formatter() {} + virtual void write(std::ostream& out, const Mat& m, const int* params=0, int nparams=0) const = 0; + virtual void write(std::ostream& out, const void* data, int nelems, int type, + const int* params=0, int nparams=0) const = 0; + static const Formatter* get(const char* fmt=""); + static const Formatter* setDefault(const Formatter* fmt); +}; + + +struct CV_EXPORTS Formatted +{ + Formatted(const Mat& m, const Formatter* fmt, + const vector& params); + Formatted(const Mat& m, const Formatter* fmt, + const int* params=0); + Mat mtx; + const Formatter* fmt; + vector params; +}; + + +/** Writes a point to an output stream in Matlab notation + */ +template inline std::ostream& operator<<(std::ostream& out, const Point_<_Tp>& p) +{ + out << "[" << p.x << ", " << p.y << "]"; + return out; +} + +/** Writes a point to an output stream in Matlab notation + */ +template inline std::ostream& operator<<(std::ostream& out, const Point3_<_Tp>& p) +{ + out << "[" << p.x << ", " << p.y << ", " << p.z << "]"; + return out; +} + +static inline Formatted format(const Mat& mtx, const char* fmt, + const vector& params=vector()) +{ + return Formatted(mtx, Formatter::get(fmt), params); +} + +template static inline Formatted format(const vector >& vec, + const char* fmt, const vector& params=vector()) +{ + return Formatted(Mat(vec), Formatter::get(fmt), params); +} + +template static inline Formatted format(const vector >& vec, + const char* fmt, const vector& params=vector()) +{ + return Formatted(Mat(vec), Formatter::get(fmt), params); +} + +/** \brief prints Mat to the output stream in Matlab notation + * use like + @verbatim + Mat my_mat = Mat::eye(3,3,CV_32F); + std::cout << my_mat; + @endverbatim + */ +static inline std::ostream& operator << (std::ostream& out, const Mat& mtx) +{ + Formatter::get()->write(out, mtx); + return out; +} + +/** \brief prints Mat to the output stream allows in the specified notation (see format) + * use like + @verbatim + Mat my_mat = Mat::eye(3,3,CV_32F); + std::cout << my_mat; + @endverbatim + */ +static inline std::ostream& operator << (std::ostream& out, const Formatted& fmtd) +{ + fmtd.fmt->write(out, fmtd.mtx); + return out; +} + + +template static inline std::ostream& operator << (std::ostream& out, + const vector >& vec) +{ + Formatter::get()->write(out, Mat(vec)); + return out; +} + + +template static inline std::ostream& operator << (std::ostream& out, + const vector >& vec) +{ + Formatter::get()->write(out, Mat(vec)); + return out; +} + + +template inline Ptr<_Tp> Algorithm::create(const string& name) +{ + return _create(name).ptr<_Tp>(); +} + +template +inline void Algorithm::set(const char* _name, const Ptr<_Tp>& value) +{ + Ptr algo_ptr = value. template ptr(); + if (algo_ptr.empty()) { + CV_Error( CV_StsUnsupportedFormat, "unknown/unsupported Ptr type of the second parameter of the method Algorithm::set"); + } + info()->set(this, _name, ParamType::type, &algo_ptr); +} + +template +inline void Algorithm::set(const string& _name, const Ptr<_Tp>& value) +{ + this->set<_Tp>(_name.c_str(), value); +} + +template inline typename ParamType<_Tp>::member_type Algorithm::get(const string& _name) const +{ + typename ParamType<_Tp>::member_type value; + info()->get(this, _name.c_str(), ParamType<_Tp>::type, &value); + return value; +} + +template inline typename ParamType<_Tp>::member_type Algorithm::get(const char* _name) const +{ + typename ParamType<_Tp>::member_type value; + info()->get(this, _name, ParamType<_Tp>::type, &value); + return value; +} + +template inline void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, + Ptr<_Tp>& value, bool readOnly, Ptr<_Tp> (Algorithm::*getter)(), void (Algorithm::*setter)(const Ptr<_Tp>&), + const string& help) +{ + //TODO: static assert: _Tp inherits from _Base + addParam_(algo, parameter, ParamType<_Base>::type, &value, readOnly, + (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); +} + +template inline void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, + Ptr<_Tp>& value, bool readOnly, Ptr<_Tp> (Algorithm::*getter)(), void (Algorithm::*setter)(const Ptr<_Tp>&), + const string& help) +{ + //TODO: static assert: _Tp inherits from Algorithm + addParam_(algo, parameter, ParamType::type, &value, readOnly, + (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); +} + +} + +#endif // __cplusplus +#endif diff --git a/core/include/opencv2/core/types_c.h b/core/include/opencv2/core/types_c.h new file mode 100644 index 0000000..cbc7872 --- /dev/null +++ b/core/include/opencv2/core/types_c.h @@ -0,0 +1,1901 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_CORE_TYPES_H__ +#define __OPENCV_CORE_TYPES_H__ + +#if !defined _CRT_SECURE_NO_DEPRECATE && defined _MSC_VER +# if _MSC_VER > 1300 +# define _CRT_SECURE_NO_DEPRECATE /* to avoid multiple Visual Studio 2005 warnings */ +# endif +#endif + + +#ifndef SKIP_INCLUDES + +#include +#include +#include +#include + +#if !defined _MSC_VER && !defined __BORLANDC__ +# include +#endif + +#if defined __ICL +# define CV_ICC __ICL +#elif defined __ICC +# define CV_ICC __ICC +#elif defined __ECL +# define CV_ICC __ECL +#elif defined __ECC +# define CV_ICC __ECC +#elif defined __INTEL_COMPILER +# define CV_ICC __INTEL_COMPILER +#endif + +#if defined CV_ICC && !defined CV_ENABLE_UNROLLED +# define CV_ENABLE_UNROLLED 0 +#else +# define CV_ENABLE_UNROLLED 1 +#endif + +#if (defined _M_X64 && defined _MSC_VER && _MSC_VER >= 1400) || (__GNUC__ >= 4 && defined __x86_64__) +# if defined WIN32 +# include +# endif +# if defined __SSE2__ || !defined __GNUC__ +# include +# endif +#endif + +#if defined __BORLANDC__ +# include +#else +# include +#endif + +#ifdef HAVE_IPL +# ifndef __IPL_H__ +# if defined WIN32 || defined _WIN32 +# include +# else +# include +# endif +# endif +#elif defined __IPL_H__ +# define HAVE_IPL +#endif + +#endif // SKIP_INCLUDES + +#if defined WIN32 || defined _WIN32 +# define CV_CDECL __cdecl +# define CV_STDCALL __stdcall +#else +# define CV_CDECL +# define CV_STDCALL +#endif + +#ifndef CV_EXTERN_C +# ifdef __cplusplus +# define CV_EXTERN_C extern "C" +# define CV_DEFAULT(val) = val +# else +# define CV_EXTERN_C +# define CV_DEFAULT(val) +# endif +#endif + +#ifndef CV_EXTERN_C_FUNCPTR +# ifdef __cplusplus +# define CV_EXTERN_C_FUNCPTR(x) extern "C" { typedef x; } +# else +# define CV_EXTERN_C_FUNCPTR(x) typedef x +# endif +#endif + +#ifndef CV_INLINE +# if defined __cplusplus +# define CV_INLINE inline +# elif (defined WIN32 || defined _WIN32 || defined WINCE) && !defined __GNUC__ +# define CV_INLINE __inline +# else +# define CV_INLINE static +# endif +#endif /* CV_INLINE */ + +#if (defined WIN32 || defined _WIN32 || defined WINCE) && defined CVAPI_EXPORTS +# define CV_EXPORTS __declspec(dllexport) +#else +# define CV_EXPORTS +#endif + +#ifndef CVAPI +# define CVAPI(rettype) CV_EXTERN_C CV_EXPORTS rettype CV_CDECL +#endif + +#if defined _MSC_VER || defined __BORLANDC__ + typedef __int64 int64; + typedef unsigned __int64 uint64; +# define CV_BIG_INT(n) n##I64 +# define CV_BIG_UINT(n) n##UI64 +#else + typedef int64_t int64; + typedef uint64_t uint64; +# define CV_BIG_INT(n) n##LL +# define CV_BIG_UINT(n) n##ULL +#endif + +#ifndef HAVE_IPL + typedef unsigned char uchar; + typedef unsigned short ushort; +#endif + +typedef signed char schar; + +/* special informative macros for wrapper generators */ +#define CV_CARRAY(counter) +#define CV_CUSTOM_CARRAY(args) +#define CV_EXPORTS_W CV_EXPORTS +#define CV_EXPORTS_W_SIMPLE CV_EXPORTS +#define CV_EXPORTS_AS(synonym) CV_EXPORTS +#define CV_EXPORTS_W_MAP CV_EXPORTS +#define CV_IN_OUT +#define CV_OUT +#define CV_PROP +#define CV_PROP_RW +#define CV_WRAP +#define CV_WRAP_AS(synonym) +#define CV_WRAP_DEFAULT(value) + +/* CvArr* is used to pass arbitrary + * array-like data structures + * into functions where the particular + * array type is recognized at runtime: + */ +typedef void CvArr; + +typedef union Cv32suf +{ + int i; + unsigned u; + float f; +} +Cv32suf; + +typedef union Cv64suf +{ + int64 i; + uint64 u; + double f; +} +Cv64suf; + +typedef int CVStatus; + +enum { + CV_StsOk= 0, /* everithing is ok */ + CV_StsBackTrace= -1, /* pseudo error for back trace */ + CV_StsError= -2, /* unknown /unspecified error */ + CV_StsInternal= -3, /* internal error (bad state) */ + CV_StsNoMem= -4, /* insufficient memory */ + CV_StsBadArg= -5, /* function arg/param is bad */ + CV_StsBadFunc= -6, /* unsupported function */ + CV_StsNoConv= -7, /* iter. didn't converge */ + CV_StsAutoTrace= -8, /* tracing */ + CV_HeaderIsNull= -9, /* image header is NULL */ + CV_BadImageSize= -10, /* image size is invalid */ + CV_BadOffset= -11, /* offset is invalid */ + CV_BadDataPtr= -12, /**/ + CV_BadStep= -13, /**/ + CV_BadModelOrChSeq= -14, /**/ + CV_BadNumChannels= -15, /**/ + CV_BadNumChannel1U= -16, /**/ + CV_BadDepth= -17, /**/ + CV_BadAlphaChannel= -18, /**/ + CV_BadOrder= -19, /**/ + CV_BadOrigin= -20, /**/ + CV_BadAlign= -21, /**/ + CV_BadCallBack= -22, /**/ + CV_BadTileSize= -23, /**/ + CV_BadCOI= -24, /**/ + CV_BadROISize= -25, /**/ + CV_MaskIsTiled= -26, /**/ + CV_StsNullPtr= -27, /* null pointer */ + CV_StsVecLengthErr= -28, /* incorrect vector length */ + CV_StsFilterStructContentErr= -29, /* incorr. filter structure content */ + CV_StsKernelStructContentErr= -30, /* incorr. transform kernel content */ + CV_StsFilterOffsetErr= -31, /* incorrect filter ofset value */ + CV_StsBadSize= -201, /* the input/output structure size is incorrect */ + CV_StsDivByZero= -202, /* division by zero */ + CV_StsInplaceNotSupported= -203, /* in-place operation is not supported */ + CV_StsObjectNotFound= -204, /* request can't be completed */ + CV_StsUnmatchedFormats= -205, /* formats of input/output arrays differ */ + CV_StsBadFlag= -206, /* flag is wrong or not supported */ + CV_StsBadPoint= -207, /* bad CvPoint */ + CV_StsBadMask= -208, /* bad format of mask (neither 8uC1 nor 8sC1)*/ + CV_StsUnmatchedSizes= -209, /* sizes of input/output structures do not match */ + CV_StsUnsupportedFormat= -210, /* the data format/type is not supported by the function*/ + CV_StsOutOfRange= -211, /* some of parameters are out of range */ + CV_StsParseError= -212, /* invalid syntax/structure of the parsed file */ + CV_StsNotImplemented= -213, /* the requested function/feature is not implemented */ + CV_StsBadMemBlock= -214, /* an allocated block has been corrupted */ + CV_StsAssert= -215, /* assertion failed */ + CV_GpuNotSupported= -216, + CV_GpuApiCallError= -217, + CV_OpenGlNotSupported= -218, + CV_OpenGlApiCallError= -219 +}; + +/****************************************************************************************\ +* Common macros and inline functions * +\****************************************************************************************/ + +#ifdef HAVE_TEGRA_OPTIMIZATION +# include "tegra_round.hpp" +#endif + +#define CV_PI 3.1415926535897932384626433832795 +#define CV_LOG2 0.69314718055994530941723212145818 + +#define CV_SWAP(a,b,t) ((t) = (a), (a) = (b), (b) = (t)) + +#ifndef MIN +# define MIN(a,b) ((a) > (b) ? (b) : (a)) +#endif + +#ifndef MAX +# define MAX(a,b) ((a) < (b) ? (b) : (a)) +#endif + +/* min & max without jumps */ +#define CV_IMIN(a, b) ((a) ^ (((a)^(b)) & (((a) < (b)) - 1))) + +#define CV_IMAX(a, b) ((a) ^ (((a)^(b)) & (((a) > (b)) - 1))) + +/* absolute value without jumps */ +#ifndef __cplusplus +# define CV_IABS(a) (((a) ^ ((a) < 0 ? -1 : 0)) - ((a) < 0 ? -1 : 0)) +#else +# define CV_IABS(a) abs(a) +#endif +#define CV_CMP(a,b) (((a) > (b)) - ((a) < (b))) +#define CV_SIGN(a) CV_CMP((a),0) + +CV_INLINE int cvRound( double value ) +{ +#if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__ && defined __SSE2__ && !defined __APPLE__) + __m128d t = _mm_set_sd( value ); + return _mm_cvtsd_si32(t); +#elif defined _MSC_VER && defined _M_IX86 + int t; + __asm + { + fld value; + fistp t; + } + return t; +#elif defined HAVE_LRINT || defined CV_ICC || defined __GNUC__ +# ifdef HAVE_TEGRA_OPTIMIZATION + TEGRA_ROUND(value); +# else + return (int)lrint(value); +# endif +#else + // while this is not IEEE754-compliant rounding, it's usually a good enough approximation + return (int)(value + (value >= 0 ? 0.5 : -0.5)); +#endif +} + +#if defined __SSE2__ || (defined _M_IX86_FP && 2 == _M_IX86_FP) +# include "emmintrin.h" +#endif + +CV_INLINE int cvFloor( double value ) +{ +#if defined _MSC_VER && defined _M_X64 || (defined __GNUC__ && defined __SSE2__ && !defined __APPLE__) + __m128d t = _mm_set_sd( value ); + int i = _mm_cvtsd_si32(t); + return i - _mm_movemask_pd(_mm_cmplt_sd(t, _mm_cvtsi32_sd(t,i))); +#elif defined __GNUC__ + int i = (int)value; + return i - (i > value); +#else + int i = cvRound(value); + Cv32suf diff; + diff.f = (float)(value - i); + return i - (diff.i < 0); +#endif +} + + +CV_INLINE int cvCeil( double value ) +{ +#if defined _MSC_VER && defined _M_X64 || (defined __GNUC__ && defined __SSE2__&& !defined __APPLE__) + __m128d t = _mm_set_sd( value ); + int i = _mm_cvtsd_si32(t); + return i + _mm_movemask_pd(_mm_cmplt_sd(_mm_cvtsi32_sd(t,i), t)); +#elif defined __GNUC__ + int i = (int)value; + return i + (i < value); +#else + int i = cvRound(value); + Cv32suf diff; + diff.f = (float)(i - value); + return i + (diff.i < 0); +#endif +} + +#define cvInvSqrt(value) ((float)(1./sqrt(value))) +#define cvSqrt(value) ((float)sqrt(value)) + +CV_INLINE int cvIsNaN( double value ) +{ +#if 1/*defined _MSC_VER || defined __BORLANDC__ + return _isnan(value); +#elif defined __GNUC__ + return isnan(value); +#else*/ + Cv64suf ieee754; + ieee754.f = value; + return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) + + ((unsigned)ieee754.u != 0) > 0x7ff00000; +#endif +} + + +CV_INLINE int cvIsInf( double value ) +{ +#if 1/*defined _MSC_VER || defined __BORLANDC__ + return !_finite(value); +#elif defined __GNUC__ + return isinf(value); +#else*/ + Cv64suf ieee754; + ieee754.f = value; + return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && + (unsigned)ieee754.u == 0; +#endif +} + + +/*************** Random number generation *******************/ + +typedef uint64 CvRNG; + +#define CV_RNG_COEFF 4164903690U + +CV_INLINE CvRNG cvRNG( int64 seed CV_DEFAULT(-1)) +{ + CvRNG rng = seed ? (uint64)seed : (uint64)(int64)-1; + return rng; +} + +/* Return random 32-bit unsigned integer: */ +CV_INLINE unsigned cvRandInt( CvRNG* rng ) +{ + uint64 temp = *rng; + temp = (uint64)(unsigned)temp*CV_RNG_COEFF + (temp >> 32); + *rng = temp; + return (unsigned)temp; +} + +/* Returns random floating-point number between 0 and 1: */ +CV_INLINE double cvRandReal( CvRNG* rng ) +{ + return cvRandInt(rng)*2.3283064365386962890625e-10 /* 2^-32 */; +} + +/****************************************************************************************\ +* Image type (IplImage) * +\****************************************************************************************/ + +#ifndef HAVE_IPL + +/* + * The following definitions (until #endif) + * is an extract from IPL headers. + * Copyright (c) 1995 Intel Corporation. + */ +#define IPL_DEPTH_SIGN 0x80000000 + +#define IPL_DEPTH_1U 1 +#define IPL_DEPTH_8U 8 +#define IPL_DEPTH_16U 16 +#define IPL_DEPTH_32F 32 + +#define IPL_DEPTH_8S (IPL_DEPTH_SIGN| 8) +#define IPL_DEPTH_16S (IPL_DEPTH_SIGN|16) +#define IPL_DEPTH_32S (IPL_DEPTH_SIGN|32) + +#define IPL_DATA_ORDER_PIXEL 0 +#define IPL_DATA_ORDER_PLANE 1 + +#define IPL_ORIGIN_TL 0 +#define IPL_ORIGIN_BL 1 + +#define IPL_ALIGN_4BYTES 4 +#define IPL_ALIGN_8BYTES 8 +#define IPL_ALIGN_16BYTES 16 +#define IPL_ALIGN_32BYTES 32 + +#define IPL_ALIGN_DWORD IPL_ALIGN_4BYTES +#define IPL_ALIGN_QWORD IPL_ALIGN_8BYTES + +#define IPL_BORDER_CONSTANT 0 +#define IPL_BORDER_REPLICATE 1 +#define IPL_BORDER_REFLECT 2 +#define IPL_BORDER_WRAP 3 + +typedef struct _IplImage +{ + int nSize; /* sizeof(IplImage) */ + int ID; /* version (=0)*/ + int nChannels; /* Most of OpenCV functions support 1,2,3 or 4 channels */ + int alphaChannel; /* Ignored by OpenCV */ + int depth; /* Pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16S, + IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported. */ + char colorModel[4]; /* Ignored by OpenCV */ + char channelSeq[4]; /* ditto */ + int dataOrder; /* 0 - interleaved color channels, 1 - separate color channels. + cvCreateImage can only create interleaved images */ + int origin; /* 0 - top-left origin, + 1 - bottom-left origin (Windows bitmaps style). */ + int align; /* Alignment of image rows (4 or 8). + OpenCV ignores it and uses widthStep instead. */ + int width; /* Image width in pixels. */ + int height; /* Image height in pixels. */ + struct _IplROI *roi; /* Image ROI. If NULL, the whole image is selected. */ + struct _IplImage *maskROI; /* Must be NULL. */ + void *imageId; /* " " */ + struct _IplTileInfo *tileInfo; /* " " */ + int imageSize; /* Image data size in bytes + (==image->height*image->widthStep + in case of interleaved data)*/ + char *imageData; /* Pointer to aligned image data. */ + int widthStep; /* Size of aligned image row in bytes. */ + int BorderMode[4]; /* Ignored by OpenCV. */ + int BorderConst[4]; /* Ditto. */ + char *imageDataOrigin; /* Pointer to very origin of image data + (not necessarily aligned) - + needed for correct deallocation */ +} +IplImage; + +typedef struct _IplTileInfo IplTileInfo; + +typedef struct _IplROI +{ + int coi; /* 0 - no COI (all channels are selected), 1 - 0th channel is selected ...*/ + int xOffset; + int yOffset; + int width; + int height; +} +IplROI; + +typedef struct _IplConvKernel +{ + int nCols; + int nRows; + int anchorX; + int anchorY; + int *values; + int nShiftR; +} +IplConvKernel; + +typedef struct _IplConvKernelFP +{ + int nCols; + int nRows; + int anchorX; + int anchorY; + float *values; +} +IplConvKernelFP; + +#define IPL_IMAGE_HEADER 1 +#define IPL_IMAGE_DATA 2 +#define IPL_IMAGE_ROI 4 + +#endif/*HAVE_IPL*/ + +/* extra border mode */ +#define IPL_BORDER_REFLECT_101 4 +#define IPL_BORDER_TRANSPARENT 5 + +#define IPL_IMAGE_MAGIC_VAL ((int)sizeof(IplImage)) +#define CV_TYPE_NAME_IMAGE "opencv-image" + +#define CV_IS_IMAGE_HDR(img) \ + ((img) != NULL && ((const IplImage*)(img))->nSize == sizeof(IplImage)) + +#define CV_IS_IMAGE(img) \ + (CV_IS_IMAGE_HDR(img) && ((IplImage*)img)->imageData != NULL) + +/* for storing double-precision + floating point data in IplImage's */ +#define IPL_DEPTH_64F 64 + +/* get reference to pixel at (col,row), + for multi-channel images (col) should be multiplied by number of channels */ +#define CV_IMAGE_ELEM( image, elemtype, row, col ) \ + (((elemtype*)((image)->imageData + (image)->widthStep*(row)))[(col)]) + +/****************************************************************************************\ +* Matrix type (CvMat) * +\****************************************************************************************/ + +#define CV_CN_MAX 512 +#define CV_CN_SHIFT 3 +#define CV_DEPTH_MAX (1 << CV_CN_SHIFT) + +#define CV_8U 0 +#define CV_8S 1 +#define CV_16U 2 +#define CV_16S 3 +#define CV_32S 4 +#define CV_32F 5 +#define CV_64F 6 +#define CV_USRTYPE1 7 + +#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1) +#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK) + +#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT)) +#define CV_MAKE_TYPE CV_MAKETYPE + +#define CV_8UC1 CV_MAKETYPE(CV_8U,1) +#define CV_8UC2 CV_MAKETYPE(CV_8U,2) +#define CV_8UC3 CV_MAKETYPE(CV_8U,3) +#define CV_8UC4 CV_MAKETYPE(CV_8U,4) +#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n)) + +#define CV_8SC1 CV_MAKETYPE(CV_8S,1) +#define CV_8SC2 CV_MAKETYPE(CV_8S,2) +#define CV_8SC3 CV_MAKETYPE(CV_8S,3) +#define CV_8SC4 CV_MAKETYPE(CV_8S,4) +#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n)) + +#define CV_16UC1 CV_MAKETYPE(CV_16U,1) +#define CV_16UC2 CV_MAKETYPE(CV_16U,2) +#define CV_16UC3 CV_MAKETYPE(CV_16U,3) +#define CV_16UC4 CV_MAKETYPE(CV_16U,4) +#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n)) + +#define CV_16SC1 CV_MAKETYPE(CV_16S,1) +#define CV_16SC2 CV_MAKETYPE(CV_16S,2) +#define CV_16SC3 CV_MAKETYPE(CV_16S,3) +#define CV_16SC4 CV_MAKETYPE(CV_16S,4) +#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n)) + +#define CV_32SC1 CV_MAKETYPE(CV_32S,1) +#define CV_32SC2 CV_MAKETYPE(CV_32S,2) +#define CV_32SC3 CV_MAKETYPE(CV_32S,3) +#define CV_32SC4 CV_MAKETYPE(CV_32S,4) +#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n)) + +#define CV_32FC1 CV_MAKETYPE(CV_32F,1) +#define CV_32FC2 CV_MAKETYPE(CV_32F,2) +#define CV_32FC3 CV_MAKETYPE(CV_32F,3) +#define CV_32FC4 CV_MAKETYPE(CV_32F,4) +#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n)) + +#define CV_64FC1 CV_MAKETYPE(CV_64F,1) +#define CV_64FC2 CV_MAKETYPE(CV_64F,2) +#define CV_64FC3 CV_MAKETYPE(CV_64F,3) +#define CV_64FC4 CV_MAKETYPE(CV_64F,4) +#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n)) + +#define CV_AUTO_STEP 0x7fffffff +#define CV_WHOLE_ARR cvSlice( 0, 0x3fffffff ) + +#define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT) +#define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1) +#define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1) +#define CV_MAT_TYPE(flags) ((flags) & CV_MAT_TYPE_MASK) +#define CV_MAT_CONT_FLAG_SHIFT 14 +#define CV_MAT_CONT_FLAG (1 << CV_MAT_CONT_FLAG_SHIFT) +#define CV_IS_MAT_CONT(flags) ((flags) & CV_MAT_CONT_FLAG) +#define CV_IS_CONT_MAT CV_IS_MAT_CONT +#define CV_SUBMAT_FLAG_SHIFT 15 +#define CV_SUBMAT_FLAG (1 << CV_SUBMAT_FLAG_SHIFT) +#define CV_IS_SUBMAT(flags) ((flags) & CV_MAT_SUBMAT_FLAG) + +#define CV_MAGIC_MASK 0xFFFF0000 +#define CV_MAT_MAGIC_VAL 0x42420000 +#define CV_TYPE_NAME_MAT "opencv-matrix" + +typedef struct CvMat +{ + int type; + int step; + + /* for internal use only */ + int* refcount; + int hdr_refcount; + + union + { + uchar* ptr; + short* s; + int* i; + float* fl; + double* db; + } data; + +#ifdef __cplusplus + union + { + int rows; + int height; + }; + + union + { + int cols; + int width; + }; +#else + int rows; + int cols; +#endif + +} +CvMat; + + +#define CV_IS_MAT_HDR(mat) \ + ((mat) != NULL && \ + (((const CvMat*)(mat))->type & CV_MAGIC_MASK) == CV_MAT_MAGIC_VAL && \ + ((const CvMat*)(mat))->cols > 0 && ((const CvMat*)(mat))->rows > 0) + +#define CV_IS_MAT_HDR_Z(mat) \ + ((mat) != NULL && \ + (((const CvMat*)(mat))->type & CV_MAGIC_MASK) == CV_MAT_MAGIC_VAL && \ + ((const CvMat*)(mat))->cols >= 0 && ((const CvMat*)(mat))->rows >= 0) + +#define CV_IS_MAT(mat) \ + (CV_IS_MAT_HDR(mat) && ((const CvMat*)(mat))->data.ptr != NULL) + +#define CV_IS_MASK_ARR(mat) \ + (((mat)->type & (CV_MAT_TYPE_MASK & ~CV_8SC1)) == 0) + +#define CV_ARE_TYPES_EQ(mat1, mat2) \ + ((((mat1)->type ^ (mat2)->type) & CV_MAT_TYPE_MASK) == 0) + +#define CV_ARE_CNS_EQ(mat1, mat2) \ + ((((mat1)->type ^ (mat2)->type) & CV_MAT_CN_MASK) == 0) + +#define CV_ARE_DEPTHS_EQ(mat1, mat2) \ + ((((mat1)->type ^ (mat2)->type) & CV_MAT_DEPTH_MASK) == 0) + +#define CV_ARE_SIZES_EQ(mat1, mat2) \ + ((mat1)->rows == (mat2)->rows && (mat1)->cols == (mat2)->cols) + +#define CV_IS_MAT_CONST(mat) \ + (((mat)->rows|(mat)->cols) == 1) + +/* Size of each channel item, + 0x124489 = 1000 0100 0100 0010 0010 0001 0001 ~ array of sizeof(arr_type_elem) */ +#define CV_ELEM_SIZE1(type) \ + ((((sizeof(size_t)<<28)|0x8442211) >> CV_MAT_DEPTH(type)*4) & 15) + +/* 0x3a50 = 11 10 10 01 01 00 00 ~ array of log2(sizeof(arr_type_elem)) */ +#define CV_ELEM_SIZE(type) \ + (CV_MAT_CN(type) << ((((sizeof(size_t)/4+1)*16384|0x3a50) >> CV_MAT_DEPTH(type)*2) & 3)) + +#define IPL2CV_DEPTH(depth) \ + ((((CV_8U)+(CV_16U<<4)+(CV_32F<<8)+(CV_64F<<16)+(CV_8S<<20)+ \ + (CV_16S<<24)+(CV_32S<<28)) >> ((((depth) & 0xF0) >> 2) + \ + (((depth) & IPL_DEPTH_SIGN) ? 20 : 0))) & 15) + +/* Inline constructor. No data is allocated internally!!! + * (Use together with cvCreateData, or use cvCreateMat instead to + * get a matrix with allocated data): + */ +CV_INLINE CvMat cvMat( int rows, int cols, int type, void* data CV_DEFAULT(NULL)) +{ + CvMat m; + + assert( (unsigned)CV_MAT_DEPTH(type) <= CV_64F ); + type = CV_MAT_TYPE(type); + m.type = CV_MAT_MAGIC_VAL | CV_MAT_CONT_FLAG | type; + m.cols = cols; + m.rows = rows; + m.step = m.cols*CV_ELEM_SIZE(type); + m.data.ptr = (uchar*)data; + m.refcount = NULL; + m.hdr_refcount = 0; + + return m; +} + + +#define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size ) \ + (assert( (unsigned)(row) < (unsigned)(mat).rows && \ + (unsigned)(col) < (unsigned)(mat).cols ), \ + (mat).data.ptr + (size_t)(mat).step*(row) + (pix_size)*(col)) + +#define CV_MAT_ELEM_PTR( mat, row, col ) \ + CV_MAT_ELEM_PTR_FAST( mat, row, col, CV_ELEM_SIZE((mat).type) ) + +#define CV_MAT_ELEM( mat, elemtype, row, col ) \ + (*(elemtype*)CV_MAT_ELEM_PTR_FAST( mat, row, col, sizeof(elemtype))) + + +CV_INLINE double cvmGet( const CvMat* mat, int row, int col ) +{ + int type; + + type = CV_MAT_TYPE(mat->type); + assert( (unsigned)row < (unsigned)mat->rows && + (unsigned)col < (unsigned)mat->cols ); + + if( type == CV_32FC1 ) + return ((float*)(mat->data.ptr + (size_t)mat->step*row))[col]; + else + { + assert( type == CV_64FC1 ); + return ((double*)(mat->data.ptr + (size_t)mat->step*row))[col]; + } +} + + +CV_INLINE void cvmSet( CvMat* mat, int row, int col, double value ) +{ + int type; + type = CV_MAT_TYPE(mat->type); + assert( (unsigned)row < (unsigned)mat->rows && + (unsigned)col < (unsigned)mat->cols ); + + if( type == CV_32FC1 ) + ((float*)(mat->data.ptr + (size_t)mat->step*row))[col] = (float)value; + else + { + assert( type == CV_64FC1 ); + ((double*)(mat->data.ptr + (size_t)mat->step*row))[col] = (double)value; + } +} + + +CV_INLINE int cvIplDepth( int type ) +{ + int depth = CV_MAT_DEPTH(type); + return CV_ELEM_SIZE1(depth)*8 | (depth == CV_8S || depth == CV_16S || + depth == CV_32S ? IPL_DEPTH_SIGN : 0); +} + + +/****************************************************************************************\ +* Multi-dimensional dense array (CvMatND) * +\****************************************************************************************/ + +#define CV_MATND_MAGIC_VAL 0x42430000 +#define CV_TYPE_NAME_MATND "opencv-nd-matrix" + +#define CV_MAX_DIM 32 +#define CV_MAX_DIM_HEAP 1024 + +typedef struct CvMatND +{ + int type; + int dims; + + int* refcount; + int hdr_refcount; + + union + { + uchar* ptr; + float* fl; + double* db; + int* i; + short* s; + } data; + + struct + { + int size; + int step; + } + dim[CV_MAX_DIM]; +} +CvMatND; + +#define CV_IS_MATND_HDR(mat) \ + ((mat) != NULL && (((const CvMatND*)(mat))->type & CV_MAGIC_MASK) == CV_MATND_MAGIC_VAL) + +#define CV_IS_MATND(mat) \ + (CV_IS_MATND_HDR(mat) && ((const CvMatND*)(mat))->data.ptr != NULL) + + +/****************************************************************************************\ +* Multi-dimensional sparse array (CvSparseMat) * +\****************************************************************************************/ + +#define CV_SPARSE_MAT_MAGIC_VAL 0x42440000 +#define CV_TYPE_NAME_SPARSE_MAT "opencv-sparse-matrix" + +struct CvSet; + +typedef struct CvSparseMat +{ + int type; + int dims; + int* refcount; + int hdr_refcount; + + struct CvSet* heap; + void** hashtable; + int hashsize; + int valoffset; + int idxoffset; + int size[CV_MAX_DIM]; +} +CvSparseMat; + +#define CV_IS_SPARSE_MAT_HDR(mat) \ + ((mat) != NULL && \ + (((const CvSparseMat*)(mat))->type & CV_MAGIC_MASK) == CV_SPARSE_MAT_MAGIC_VAL) + +#define CV_IS_SPARSE_MAT(mat) \ + CV_IS_SPARSE_MAT_HDR(mat) + +/**************** iteration through a sparse array *****************/ + +typedef struct CvSparseNode +{ + unsigned hashval; + struct CvSparseNode* next; +} +CvSparseNode; + +typedef struct CvSparseMatIterator +{ + CvSparseMat* mat; + CvSparseNode* node; + int curidx; +} +CvSparseMatIterator; + +#define CV_NODE_VAL(mat,node) ((void*)((uchar*)(node) + (mat)->valoffset)) +#define CV_NODE_IDX(mat,node) ((int*)((uchar*)(node) + (mat)->idxoffset)) + +/****************************************************************************************\ +* Histogram * +\****************************************************************************************/ + +typedef int CvHistType; + +#define CV_HIST_MAGIC_VAL 0x42450000 +#define CV_HIST_UNIFORM_FLAG (1 << 10) + +/* indicates whether bin ranges are set already or not */ +#define CV_HIST_RANGES_FLAG (1 << 11) + +#define CV_HIST_ARRAY 0 +#define CV_HIST_SPARSE 1 +#define CV_HIST_TREE CV_HIST_SPARSE + +/* should be used as a parameter only, + it turns to CV_HIST_UNIFORM_FLAG of hist->type */ +#define CV_HIST_UNIFORM 1 + +typedef struct CvHistogram +{ + int type; + CvArr* bins; + float thresh[CV_MAX_DIM][2]; /* For uniform histograms. */ + float** thresh2; /* For non-uniform histograms. */ + CvMatND mat; /* Embedded matrix header for array histograms. */ +} +CvHistogram; + +#define CV_IS_HIST( hist ) \ + ((hist) != NULL && \ + (((CvHistogram*)(hist))->type & CV_MAGIC_MASK) == CV_HIST_MAGIC_VAL && \ + (hist)->bins != NULL) + +#define CV_IS_UNIFORM_HIST( hist ) \ + (((hist)->type & CV_HIST_UNIFORM_FLAG) != 0) + +#define CV_IS_SPARSE_HIST( hist ) \ + CV_IS_SPARSE_MAT((hist)->bins) + +#define CV_HIST_HAS_RANGES( hist ) \ + (((hist)->type & CV_HIST_RANGES_FLAG) != 0) + +/****************************************************************************************\ +* Other supplementary data type definitions * +\****************************************************************************************/ + +/*************************************** CvRect *****************************************/ + +typedef struct CvRect +{ + int x; + int y; + int width; + int height; +} +CvRect; + +CV_INLINE CvRect cvRect( int x, int y, int width, int height ) +{ + CvRect r; + + r.x = x; + r.y = y; + r.width = width; + r.height = height; + + return r; +} + + +CV_INLINE IplROI cvRectToROI( CvRect rect, int coi ) +{ + IplROI roi; + roi.xOffset = rect.x; + roi.yOffset = rect.y; + roi.width = rect.width; + roi.height = rect.height; + roi.coi = coi; + + return roi; +} + + +CV_INLINE CvRect cvROIToRect( IplROI roi ) +{ + return cvRect( roi.xOffset, roi.yOffset, roi.width, roi.height ); +} + +/*********************************** CvTermCriteria *************************************/ + +#define CV_TERMCRIT_ITER 1 +#define CV_TERMCRIT_NUMBER CV_TERMCRIT_ITER +#define CV_TERMCRIT_EPS 2 + +typedef struct CvTermCriteria +{ + int type; /* may be combination of + CV_TERMCRIT_ITER + CV_TERMCRIT_EPS */ + int max_iter; + double epsilon; +} +CvTermCriteria; + +CV_INLINE CvTermCriteria cvTermCriteria( int type, int max_iter, double epsilon ) +{ + CvTermCriteria t; + + t.type = type; + t.max_iter = max_iter; + t.epsilon = (float)epsilon; + + return t; +} + + +/******************************* CvPoint and variants ***********************************/ + +typedef struct CvPoint +{ + int x; + int y; +} +CvPoint; + + +CV_INLINE CvPoint cvPoint( int x, int y ) +{ + CvPoint p; + + p.x = x; + p.y = y; + + return p; +} + + +typedef struct CvPoint2D32f +{ + float x; + float y; +} +CvPoint2D32f; + + +CV_INLINE CvPoint2D32f cvPoint2D32f( double x, double y ) +{ + CvPoint2D32f p; + + p.x = (float)x; + p.y = (float)y; + + return p; +} + + +CV_INLINE CvPoint2D32f cvPointTo32f( CvPoint point ) +{ + return cvPoint2D32f( (float)point.x, (float)point.y ); +} + + +CV_INLINE CvPoint cvPointFrom32f( CvPoint2D32f point ) +{ + CvPoint ipt; + ipt.x = cvRound(point.x); + ipt.y = cvRound(point.y); + + return ipt; +} + + +typedef struct CvPoint3D32f +{ + float x; + float y; + float z; +} +CvPoint3D32f; + + +CV_INLINE CvPoint3D32f cvPoint3D32f( double x, double y, double z ) +{ + CvPoint3D32f p; + + p.x = (float)x; + p.y = (float)y; + p.z = (float)z; + + return p; +} + + +typedef struct CvPoint2D64f +{ + double x; + double y; +} +CvPoint2D64f; + + +CV_INLINE CvPoint2D64f cvPoint2D64f( double x, double y ) +{ + CvPoint2D64f p; + + p.x = x; + p.y = y; + + return p; +} + + +typedef struct CvPoint3D64f +{ + double x; + double y; + double z; +} +CvPoint3D64f; + + +CV_INLINE CvPoint3D64f cvPoint3D64f( double x, double y, double z ) +{ + CvPoint3D64f p; + + p.x = x; + p.y = y; + p.z = z; + + return p; +} + + +/******************************** CvSize's & CvBox **************************************/ + +typedef struct CvSize +{ + int width; + int height; +} +CvSize; + +CV_INLINE CvSize cvSize( int width, int height ) +{ + CvSize s; + + s.width = width; + s.height = height; + + return s; +} + +typedef struct CvSize2D32f +{ + float width; + float height; +} +CvSize2D32f; + + +CV_INLINE CvSize2D32f cvSize2D32f( double width, double height ) +{ + CvSize2D32f s; + + s.width = (float)width; + s.height = (float)height; + + return s; +} + +typedef struct CvBox2D +{ + CvPoint2D32f center; /* Center of the box. */ + CvSize2D32f size; /* Box width and length. */ + float angle; /* Angle between the horizontal axis */ + /* and the first side (i.e. length) in degrees */ +} +CvBox2D; + + +/* Line iterator state: */ +typedef struct CvLineIterator +{ + /* Pointer to the current point: */ + uchar* ptr; + + /* Bresenham algorithm state: */ + int err; + int plus_delta; + int minus_delta; + int plus_step; + int minus_step; +} +CvLineIterator; + + + +/************************************* CvSlice ******************************************/ + +typedef struct CvSlice +{ + int start_index, end_index; +} +CvSlice; + +CV_INLINE CvSlice cvSlice( int start, int end ) +{ + CvSlice slice; + slice.start_index = start; + slice.end_index = end; + + return slice; +} + +#define CV_WHOLE_SEQ_END_INDEX 0x3fffffff +#define CV_WHOLE_SEQ cvSlice(0, CV_WHOLE_SEQ_END_INDEX) + + +/************************************* CvScalar *****************************************/ + +typedef struct CvScalar +{ + double val[4]; +} +CvScalar; + +CV_INLINE CvScalar cvScalar( double val0, double val1 CV_DEFAULT(0), + double val2 CV_DEFAULT(0), double val3 CV_DEFAULT(0)) +{ + CvScalar scalar; + scalar.val[0] = val0; scalar.val[1] = val1; + scalar.val[2] = val2; scalar.val[3] = val3; + return scalar; +} + + +CV_INLINE CvScalar cvRealScalar( double val0 ) +{ + CvScalar scalar; + scalar.val[0] = val0; + scalar.val[1] = scalar.val[2] = scalar.val[3] = 0; + return scalar; +} + +CV_INLINE CvScalar cvScalarAll( double val0123 ) +{ + CvScalar scalar; + scalar.val[0] = val0123; + scalar.val[1] = val0123; + scalar.val[2] = val0123; + scalar.val[3] = val0123; + return scalar; +} + +/****************************************************************************************\ +* Dynamic Data structures * +\****************************************************************************************/ + +/******************************** Memory storage ****************************************/ + +typedef struct CvMemBlock +{ + struct CvMemBlock* prev; + struct CvMemBlock* next; +} +CvMemBlock; + +#define CV_STORAGE_MAGIC_VAL 0x42890000 + +typedef struct CvMemStorage +{ + int signature; + CvMemBlock* bottom; /* First allocated block. */ + CvMemBlock* top; /* Current memory block - top of the stack. */ + struct CvMemStorage* parent; /* We get new blocks from parent as needed. */ + int block_size; /* Block size. */ + int free_space; /* Remaining free space in current block. */ +} +CvMemStorage; + +#define CV_IS_STORAGE(storage) \ + ((storage) != NULL && \ + (((CvMemStorage*)(storage))->signature & CV_MAGIC_MASK) == CV_STORAGE_MAGIC_VAL) + + +typedef struct CvMemStoragePos +{ + CvMemBlock* top; + int free_space; +} +CvMemStoragePos; + + +/*********************************** Sequence *******************************************/ + +typedef struct CvSeqBlock +{ + struct CvSeqBlock* prev; /* Previous sequence block. */ + struct CvSeqBlock* next; /* Next sequence block. */ + int start_index; /* Index of the first element in the block + */ + /* sequence->first->start_index. */ + int count; /* Number of elements in the block. */ + schar* data; /* Pointer to the first element of the block. */ +} +CvSeqBlock; + + +#define CV_TREE_NODE_FIELDS(node_type) \ + int flags; /* Miscellaneous flags. */ \ + int header_size; /* Size of sequence header. */ \ + struct node_type* h_prev; /* Previous sequence. */ \ + struct node_type* h_next; /* Next sequence. */ \ + struct node_type* v_prev; /* 2nd previous sequence. */ \ + struct node_type* v_next /* 2nd next sequence. */ + +/* + Read/Write sequence. + Elements can be dynamically inserted to or deleted from the sequence. +*/ +#define CV_SEQUENCE_FIELDS() \ + CV_TREE_NODE_FIELDS(CvSeq); \ + int total; /* Total number of elements. */ \ + int elem_size; /* Size of sequence element in bytes. */ \ + schar* block_max; /* Maximal bound of the last block. */ \ + schar* ptr; /* Current write pointer. */ \ + int delta_elems; /* Grow seq this many at a time. */ \ + CvMemStorage* storage; /* Where the seq is stored. */ \ + CvSeqBlock* free_blocks; /* Free blocks list. */ \ + CvSeqBlock* first; /* Pointer to the first sequence block. */ + +typedef struct CvSeq +{ + CV_SEQUENCE_FIELDS() +} +CvSeq; + +#define CV_TYPE_NAME_SEQ "opencv-sequence" +#define CV_TYPE_NAME_SEQ_TREE "opencv-sequence-tree" + +/*************************************** Set ********************************************/ +/* + Set. + Order is not preserved. There can be gaps between sequence elements. + After the element has been inserted it stays in the same place all the time. + The MSB(most-significant or sign bit) of the first field (flags) is 0 iff the element exists. +*/ +#define CV_SET_ELEM_FIELDS(elem_type) \ + int flags; \ + struct elem_type* next_free; + +typedef struct CvSetElem +{ + CV_SET_ELEM_FIELDS(CvSetElem) +} +CvSetElem; + +#define CV_SET_FIELDS() \ + CV_SEQUENCE_FIELDS() \ + CvSetElem* free_elems; \ + int active_count; + +typedef struct CvSet +{ + CV_SET_FIELDS() +} +CvSet; + + +#define CV_SET_ELEM_IDX_MASK ((1 << 26) - 1) +#define CV_SET_ELEM_FREE_FLAG (1 << (sizeof(int)*8-1)) + +/* Checks whether the element pointed by ptr belongs to a set or not */ +#define CV_IS_SET_ELEM( ptr ) (((CvSetElem*)(ptr))->flags >= 0) + +/************************************* Graph ********************************************/ + +/* + We represent a graph as a set of vertices. + Vertices contain their adjacency lists (more exactly, pointers to first incoming or + outcoming edge (or 0 if isolated vertex)). Edges are stored in another set. + There is a singly-linked list of incoming/outcoming edges for each vertex. + + Each edge consists of + + o Two pointers to the starting and ending vertices + (vtx[0] and vtx[1] respectively). + + A graph may be oriented or not. In the latter case, edges between + vertex i to vertex j are not distinguished during search operations. + + o Two pointers to next edges for the starting and ending vertices, where + next[0] points to the next edge in the vtx[0] adjacency list and + next[1] points to the next edge in the vtx[1] adjacency list. +*/ +#define CV_GRAPH_EDGE_FIELDS() \ + int flags; \ + float weight; \ + struct CvGraphEdge* next[2]; \ + struct CvGraphVtx* vtx[2]; + + +#define CV_GRAPH_VERTEX_FIELDS() \ + int flags; \ + struct CvGraphEdge* first; + + +typedef struct CvGraphEdge +{ + CV_GRAPH_EDGE_FIELDS() +} +CvGraphEdge; + +typedef struct CvGraphVtx +{ + CV_GRAPH_VERTEX_FIELDS() +} +CvGraphVtx; + +typedef struct CvGraphVtx2D +{ + CV_GRAPH_VERTEX_FIELDS() + CvPoint2D32f* ptr; +} +CvGraphVtx2D; + +/* + Graph is "derived" from the set (this is set a of vertices) + and includes another set (edges) +*/ +#define CV_GRAPH_FIELDS() \ + CV_SET_FIELDS() \ + CvSet* edges; + +typedef struct CvGraph +{ + CV_GRAPH_FIELDS() +} +CvGraph; + +#define CV_TYPE_NAME_GRAPH "opencv-graph" + +/*********************************** Chain/Countour *************************************/ + +typedef struct CvChain +{ + CV_SEQUENCE_FIELDS() + CvPoint origin; +} +CvChain; + +#define CV_CONTOUR_FIELDS() \ + CV_SEQUENCE_FIELDS() \ + CvRect rect; \ + int color; \ + int reserved[3]; + +typedef struct CvContour +{ + CV_CONTOUR_FIELDS() +} +CvContour; + +typedef CvContour CvPoint2DSeq; + +/****************************************************************************************\ +* Sequence types * +\****************************************************************************************/ + +#define CV_SEQ_MAGIC_VAL 0x42990000 + +#define CV_IS_SEQ(seq) \ + ((seq) != NULL && (((CvSeq*)(seq))->flags & CV_MAGIC_MASK) == CV_SEQ_MAGIC_VAL) + +#define CV_SET_MAGIC_VAL 0x42980000 +#define CV_IS_SET(set) \ + ((set) != NULL && (((CvSeq*)(set))->flags & CV_MAGIC_MASK) == CV_SET_MAGIC_VAL) + +#define CV_SEQ_ELTYPE_BITS 12 +#define CV_SEQ_ELTYPE_MASK ((1 << CV_SEQ_ELTYPE_BITS) - 1) + +#define CV_SEQ_ELTYPE_POINT CV_32SC2 /* (x,y) */ +#define CV_SEQ_ELTYPE_CODE CV_8UC1 /* freeman code: 0..7 */ +#define CV_SEQ_ELTYPE_GENERIC 0 +#define CV_SEQ_ELTYPE_PTR CV_USRTYPE1 +#define CV_SEQ_ELTYPE_PPOINT CV_SEQ_ELTYPE_PTR /* &(x,y) */ +#define CV_SEQ_ELTYPE_INDEX CV_32SC1 /* #(x,y) */ +#define CV_SEQ_ELTYPE_GRAPH_EDGE 0 /* &next_o, &next_d, &vtx_o, &vtx_d */ +#define CV_SEQ_ELTYPE_GRAPH_VERTEX 0 /* first_edge, &(x,y) */ +#define CV_SEQ_ELTYPE_TRIAN_ATR 0 /* vertex of the binary tree */ +#define CV_SEQ_ELTYPE_CONNECTED_COMP 0 /* connected component */ +#define CV_SEQ_ELTYPE_POINT3D CV_32FC3 /* (x,y,z) */ + +#define CV_SEQ_KIND_BITS 2 +#define CV_SEQ_KIND_MASK (((1 << CV_SEQ_KIND_BITS) - 1)<flags & CV_SEQ_ELTYPE_MASK) +#define CV_SEQ_KIND( seq ) ((seq)->flags & CV_SEQ_KIND_MASK ) + +/* flag checking */ +#define CV_IS_SEQ_INDEX( seq ) ((CV_SEQ_ELTYPE(seq) == CV_SEQ_ELTYPE_INDEX) && \ + (CV_SEQ_KIND(seq) == CV_SEQ_KIND_GENERIC)) + +#define CV_IS_SEQ_CURVE( seq ) (CV_SEQ_KIND(seq) == CV_SEQ_KIND_CURVE) +#define CV_IS_SEQ_CLOSED( seq ) (((seq)->flags & CV_SEQ_FLAG_CLOSED) != 0) +#define CV_IS_SEQ_CONVEX( seq ) 0 +#define CV_IS_SEQ_HOLE( seq ) (((seq)->flags & CV_SEQ_FLAG_HOLE) != 0) +#define CV_IS_SEQ_SIMPLE( seq ) 1 + +/* type checking macros */ +#define CV_IS_SEQ_POINT_SET( seq ) \ + ((CV_SEQ_ELTYPE(seq) == CV_32SC2 || CV_SEQ_ELTYPE(seq) == CV_32FC2)) + +#define CV_IS_SEQ_POINT_SUBSET( seq ) \ + (CV_IS_SEQ_INDEX( seq ) || CV_SEQ_ELTYPE(seq) == CV_SEQ_ELTYPE_PPOINT) + +#define CV_IS_SEQ_POLYLINE( seq ) \ + (CV_SEQ_KIND(seq) == CV_SEQ_KIND_CURVE && CV_IS_SEQ_POINT_SET(seq)) + +#define CV_IS_SEQ_POLYGON( seq ) \ + (CV_IS_SEQ_POLYLINE(seq) && CV_IS_SEQ_CLOSED(seq)) + +#define CV_IS_SEQ_CHAIN( seq ) \ + (CV_SEQ_KIND(seq) == CV_SEQ_KIND_CURVE && (seq)->elem_size == 1) + +#define CV_IS_SEQ_CONTOUR( seq ) \ + (CV_IS_SEQ_CLOSED(seq) && (CV_IS_SEQ_POLYLINE(seq) || CV_IS_SEQ_CHAIN(seq))) + +#define CV_IS_SEQ_CHAIN_CONTOUR( seq ) \ + (CV_IS_SEQ_CHAIN( seq ) && CV_IS_SEQ_CLOSED( seq )) + +#define CV_IS_SEQ_POLYGON_TREE( seq ) \ + (CV_SEQ_ELTYPE (seq) == CV_SEQ_ELTYPE_TRIAN_ATR && \ + CV_SEQ_KIND( seq ) == CV_SEQ_KIND_BIN_TREE ) + +#define CV_IS_GRAPH( seq ) \ + (CV_IS_SET(seq) && CV_SEQ_KIND((CvSet*)(seq)) == CV_SEQ_KIND_GRAPH) + +#define CV_IS_GRAPH_ORIENTED( seq ) \ + (((seq)->flags & CV_GRAPH_FLAG_ORIENTED) != 0) + +#define CV_IS_SUBDIV2D( seq ) \ + (CV_IS_SET(seq) && CV_SEQ_KIND((CvSet*)(seq)) == CV_SEQ_KIND_SUBDIV2D) + +/****************************************************************************************/ +/* Sequence writer & reader */ +/****************************************************************************************/ + +#define CV_SEQ_WRITER_FIELDS() \ + int header_size; \ + CvSeq* seq; /* the sequence written */ \ + CvSeqBlock* block; /* current block */ \ + schar* ptr; /* pointer to free space */ \ + schar* block_min; /* pointer to the beginning of block*/\ + schar* block_max; /* pointer to the end of block */ + +typedef struct CvSeqWriter +{ + CV_SEQ_WRITER_FIELDS() +} +CvSeqWriter; + + +#define CV_SEQ_READER_FIELDS() \ + int header_size; \ + CvSeq* seq; /* sequence, beign read */ \ + CvSeqBlock* block; /* current block */ \ + schar* ptr; /* pointer to element be read next */ \ + schar* block_min; /* pointer to the beginning of block */\ + schar* block_max; /* pointer to the end of block */ \ + int delta_index;/* = seq->first->start_index */ \ + schar* prev_elem; /* pointer to previous element */ + + +typedef struct CvSeqReader +{ + CV_SEQ_READER_FIELDS() +} +CvSeqReader; + +/****************************************************************************************/ +/* Operations on sequences */ +/****************************************************************************************/ + +#define CV_SEQ_ELEM( seq, elem_type, index ) \ +/* assert gives some guarantee that parameter is valid */ \ +( assert(sizeof((seq)->first[0]) == sizeof(CvSeqBlock) && \ + (seq)->elem_size == sizeof(elem_type)), \ + (elem_type*)((seq)->first && (unsigned)index < \ + (unsigned)((seq)->first->count) ? \ + (seq)->first->data + (index) * sizeof(elem_type) : \ + cvGetSeqElem( (CvSeq*)(seq), (index) ))) +#define CV_GET_SEQ_ELEM( elem_type, seq, index ) CV_SEQ_ELEM( (seq), elem_type, (index) ) + +/* Add element to sequence: */ +#define CV_WRITE_SEQ_ELEM_VAR( elem_ptr, writer ) \ +{ \ + if( (writer).ptr >= (writer).block_max ) \ + { \ + cvCreateSeqBlock( &writer); \ + } \ + memcpy((writer).ptr, elem_ptr, (writer).seq->elem_size);\ + (writer).ptr += (writer).seq->elem_size; \ +} + +#define CV_WRITE_SEQ_ELEM( elem, writer ) \ +{ \ + assert( (writer).seq->elem_size == sizeof(elem)); \ + if( (writer).ptr >= (writer).block_max ) \ + { \ + cvCreateSeqBlock( &writer); \ + } \ + assert( (writer).ptr <= (writer).block_max - sizeof(elem));\ + memcpy((writer).ptr, &(elem), sizeof(elem)); \ + (writer).ptr += sizeof(elem); \ +} + + +/* Move reader position forward: */ +#define CV_NEXT_SEQ_ELEM( elem_size, reader ) \ +{ \ + if( ((reader).ptr += (elem_size)) >= (reader).block_max ) \ + { \ + cvChangeSeqBlock( &(reader), 1 ); \ + } \ +} + + +/* Move reader position backward: */ +#define CV_PREV_SEQ_ELEM( elem_size, reader ) \ +{ \ + if( ((reader).ptr -= (elem_size)) < (reader).block_min ) \ + { \ + cvChangeSeqBlock( &(reader), -1 ); \ + } \ +} + +/* Read element and move read position forward: */ +#define CV_READ_SEQ_ELEM( elem, reader ) \ +{ \ + assert( (reader).seq->elem_size == sizeof(elem)); \ + memcpy( &(elem), (reader).ptr, sizeof((elem))); \ + CV_NEXT_SEQ_ELEM( sizeof(elem), reader ) \ +} + +/* Read element and move read position backward: */ +#define CV_REV_READ_SEQ_ELEM( elem, reader ) \ +{ \ + assert( (reader).seq->elem_size == sizeof(elem)); \ + memcpy(&(elem), (reader).ptr, sizeof((elem))); \ + CV_PREV_SEQ_ELEM( sizeof(elem), reader ) \ +} + + +#define CV_READ_CHAIN_POINT( _pt, reader ) \ +{ \ + (_pt) = (reader).pt; \ + if( (reader).ptr ) \ + { \ + CV_READ_SEQ_ELEM( (reader).code, (reader)); \ + assert( ((reader).code & ~7) == 0 ); \ + (reader).pt.x += (reader).deltas[(int)(reader).code][0]; \ + (reader).pt.y += (reader).deltas[(int)(reader).code][1]; \ + } \ +} + +#define CV_CURRENT_POINT( reader ) (*((CvPoint*)((reader).ptr))) +#define CV_PREV_POINT( reader ) (*((CvPoint*)((reader).prev_elem))) + +#define CV_READ_EDGE( pt1, pt2, reader ) \ +{ \ + assert( sizeof(pt1) == sizeof(CvPoint) && \ + sizeof(pt2) == sizeof(CvPoint) && \ + reader.seq->elem_size == sizeof(CvPoint)); \ + (pt1) = CV_PREV_POINT( reader ); \ + (pt2) = CV_CURRENT_POINT( reader ); \ + (reader).prev_elem = (reader).ptr; \ + CV_NEXT_SEQ_ELEM( sizeof(CvPoint), (reader)); \ +} + +/************ Graph macros ************/ + +/* Return next graph edge for given vertex: */ +#define CV_NEXT_GRAPH_EDGE( edge, vertex ) \ + (assert((edge)->vtx[0] == (vertex) || (edge)->vtx[1] == (vertex)), \ + (edge)->next[(edge)->vtx[1] == (vertex)]) + + + +/****************************************************************************************\ +* Data structures for persistence (a.k.a serialization) functionality * +\****************************************************************************************/ + +/* "black box" file storage */ +typedef struct CvFileStorage CvFileStorage; + +/* Storage flags: */ +#define CV_STORAGE_READ 0 +#define CV_STORAGE_WRITE 1 +#define CV_STORAGE_WRITE_TEXT CV_STORAGE_WRITE +#define CV_STORAGE_WRITE_BINARY CV_STORAGE_WRITE +#define CV_STORAGE_APPEND 2 +#define CV_STORAGE_MEMORY 4 +#define CV_STORAGE_FORMAT_MASK (7<<3) +#define CV_STORAGE_FORMAT_AUTO 0 +#define CV_STORAGE_FORMAT_XML 8 +#define CV_STORAGE_FORMAT_YAML 16 + +/* List of attributes: */ +typedef struct CvAttrList +{ + const char** attr; /* NULL-terminated array of (attribute_name,attribute_value) pairs. */ + struct CvAttrList* next; /* Pointer to next chunk of the attributes list. */ +} +CvAttrList; + +CV_INLINE CvAttrList cvAttrList( const char** attr CV_DEFAULT(NULL), + CvAttrList* next CV_DEFAULT(NULL) ) +{ + CvAttrList l; + l.attr = attr; + l.next = next; + + return l; +} + +struct CvTypeInfo; + +#define CV_NODE_NONE 0 +#define CV_NODE_INT 1 +#define CV_NODE_INTEGER CV_NODE_INT +#define CV_NODE_REAL 2 +#define CV_NODE_FLOAT CV_NODE_REAL +#define CV_NODE_STR 3 +#define CV_NODE_STRING CV_NODE_STR +#define CV_NODE_REF 4 /* not used */ +#define CV_NODE_SEQ 5 +#define CV_NODE_MAP 6 +#define CV_NODE_TYPE_MASK 7 + +#define CV_NODE_TYPE(flags) ((flags) & CV_NODE_TYPE_MASK) + +/* file node flags */ +#define CV_NODE_FLOW 8 /* Used only for writing structures in YAML format. */ +#define CV_NODE_USER 16 +#define CV_NODE_EMPTY 32 +#define CV_NODE_NAMED 64 + +#define CV_NODE_IS_INT(flags) (CV_NODE_TYPE(flags) == CV_NODE_INT) +#define CV_NODE_IS_REAL(flags) (CV_NODE_TYPE(flags) == CV_NODE_REAL) +#define CV_NODE_IS_STRING(flags) (CV_NODE_TYPE(flags) == CV_NODE_STRING) +#define CV_NODE_IS_SEQ(flags) (CV_NODE_TYPE(flags) == CV_NODE_SEQ) +#define CV_NODE_IS_MAP(flags) (CV_NODE_TYPE(flags) == CV_NODE_MAP) +#define CV_NODE_IS_COLLECTION(flags) (CV_NODE_TYPE(flags) >= CV_NODE_SEQ) +#define CV_NODE_IS_FLOW(flags) (((flags) & CV_NODE_FLOW) != 0) +#define CV_NODE_IS_EMPTY(flags) (((flags) & CV_NODE_EMPTY) != 0) +#define CV_NODE_IS_USER(flags) (((flags) & CV_NODE_USER) != 0) +#define CV_NODE_HAS_NAME(flags) (((flags) & CV_NODE_NAMED) != 0) + +#define CV_NODE_SEQ_SIMPLE 256 +#define CV_NODE_SEQ_IS_SIMPLE(seq) (((seq)->flags & CV_NODE_SEQ_SIMPLE) != 0) + +typedef struct CvString +{ + int len; + char* ptr; +} +CvString; + +/* All the keys (names) of elements in the readed file storage + are stored in the hash to speed up the lookup operations: */ +typedef struct CvStringHashNode +{ + unsigned hashval; + CvString str; + struct CvStringHashNode* next; +} +CvStringHashNode; + +typedef struct CvGenericHash CvFileNodeHash; + +/* Basic element of the file storage - scalar or collection: */ +typedef struct CvFileNode +{ + int tag; + struct CvTypeInfo* info; /* type information + (only for user-defined object, for others it is 0) */ + union + { + double f; /* scalar floating-point number */ + int i; /* scalar integer number */ + CvString str; /* text string */ + CvSeq* seq; /* sequence (ordered collection of file nodes) */ + CvFileNodeHash* map; /* map (collection of named file nodes) */ + } data; +} +CvFileNode; + +#ifdef __cplusplus +extern "C" { +#endif +typedef int (CV_CDECL *CvIsInstanceFunc)( const void* struct_ptr ); +typedef void (CV_CDECL *CvReleaseFunc)( void** struct_dblptr ); +typedef void* (CV_CDECL *CvReadFunc)( CvFileStorage* storage, CvFileNode* node ); +typedef void (CV_CDECL *CvWriteFunc)( CvFileStorage* storage, const char* name, + const void* struct_ptr, CvAttrList attributes ); +typedef void* (CV_CDECL *CvCloneFunc)( const void* struct_ptr ); +#ifdef __cplusplus +} +#endif + +typedef struct CvTypeInfo +{ + int flags; + int header_size; + struct CvTypeInfo* prev; + struct CvTypeInfo* next; + const char* type_name; + CvIsInstanceFunc is_instance; + CvReleaseFunc release; + CvReadFunc read; + CvWriteFunc write; + CvCloneFunc clone; +} +CvTypeInfo; + + +/**** System data types ******/ + +typedef struct CvPluginFuncInfo +{ + void** func_addr; + void* default_func_addr; + const char* func_names; + int search_modules; + int loaded_from; +} +CvPluginFuncInfo; + +typedef struct CvModuleInfo +{ + struct CvModuleInfo* next; + const char* name; + const char* version; + CvPluginFuncInfo* func_tab; +} +CvModuleInfo; + +#endif /*__OPENCV_CORE_TYPES_H__*/ + +/* End of file. */ diff --git a/core/include/opencv2/core/version.hpp b/core/include/opencv2/core/version.hpp new file mode 100644 index 0000000..8d47f45 --- /dev/null +++ b/core/include/opencv2/core/version.hpp @@ -0,0 +1,58 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright( C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +/* + definition of the current version of OpenCV + Usefull to test in user programs +*/ + +#ifndef __OPENCV_VERSION_HPP__ +#define __OPENCV_VERSION_HPP__ + +#define CV_MAJOR_VERSION 2 +#define CV_MINOR_VERSION 4 +#define CV_SUBMINOR_VERSION 9 + +#define CVAUX_STR_EXP(__A) #__A +#define CVAUX_STR(__A) CVAUX_STR_EXP(__A) +#define CV_VERSION CVAUX_STR(CV_MAJOR_VERSION) "." CVAUX_STR(CV_MINOR_VERSION) "." CVAUX_STR(CV_SUBMINOR_VERSION) + +#endif diff --git a/core/include/opencv2/core/wimage.hpp b/core/include/opencv2/core/wimage.hpp new file mode 100644 index 0000000..579c009 --- /dev/null +++ b/core/include/opencv2/core/wimage.hpp @@ -0,0 +1,621 @@ +/////////////////////////////////////////////////////////////////////////////// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to +// this license. If you do not agree to this license, do not download, +// install, copy or use the software. +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2008, Google, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation or contributors may not be used to endorse +// or promote products derived from this software without specific +// prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. + + +///////////////////////////////////////////////////////////////////////////////// +// +// Image class which provides a thin layer around an IplImage. The goals +// of the class design are: +// 1. All the data has explicit ownership to avoid memory leaks +// 2. No hidden allocations or copies for performance. +// 3. Easy access to OpenCV methods (which will access IPP if available) +// 4. Can easily treat external data as an image +// 5. Easy to create images which are subsets of other images +// 6. Fast pixel access which can take advantage of number of channels +// if known at compile time. +// +// The WImage class is the image class which provides the data accessors. +// The 'W' comes from the fact that it is also a wrapper around the popular +// but inconvenient IplImage class. A WImage can be constructed either using a +// WImageBuffer class which allocates and frees the data, +// or using a WImageView class which constructs a subimage or a view into +// external data. The view class does no memory management. Each class +// actually has two versions, one when the number of channels is known at +// compile time and one when it isn't. Using the one with the number of +// channels specified can provide some compile time optimizations by using the +// fact that the number of channels is a constant. +// +// We use the convention (c,r) to refer to column c and row r with (0,0) being +// the upper left corner. This is similar to standard Euclidean coordinates +// with the first coordinate varying in the horizontal direction and the second +// coordinate varying in the vertical direction. +// Thus (c,r) is usually in the domain [0, width) X [0, height) +// +// Example usage: +// WImageBuffer3_b im(5,7); // Make a 5X7 3 channel image of type uchar +// WImageView3_b sub_im(im, 2,2, 3,3); // 3X3 submatrix +// vector vec(10, 3.0f); +// WImageView1_f user_im(&vec[0], 2, 5); // 2X5 image w/ supplied data +// +// im.SetZero(); // same as cvSetZero(im.Ipl()) +// *im(2, 3) = 15; // Modify the element at column 2, row 3 +// MySetRand(&sub_im); +// +// // Copy the second row into the first. This can be done with no memory +// // allocation and will use SSE if IPP is available. +// int w = im.Width(); +// im.View(0,0, w,1).CopyFrom(im.View(0,1, w,1)); +// +// // Doesn't care about source of data since using WImage +// void MySetRand(WImage_b* im) { // Works with any number of channels +// for (int r = 0; r < im->Height(); ++r) { +// float* row = im->Row(r); +// for (int c = 0; c < im->Width(); ++c) { +// for (int ch = 0; ch < im->Channels(); ++ch, ++row) { +// *row = uchar(rand() & 255); +// } +// } +// } +// } +// +// Functions that are not part of the basic image allocation, viewing, and +// access should come from OpenCV, except some useful functions that are not +// part of OpenCV can be found in wimage_util.h +#ifndef __OPENCV_CORE_WIMAGE_HPP__ +#define __OPENCV_CORE_WIMAGE_HPP__ + +#include "opencv2/core/core_c.h" + +#ifdef __cplusplus + +namespace cv { + +template class WImage; +template class WImageBuffer; +template class WImageView; + +template class WImageC; +template class WImageBufferC; +template class WImageViewC; + +// Commonly used typedefs. +typedef WImage WImage_b; +typedef WImageView WImageView_b; +typedef WImageBuffer WImageBuffer_b; + +typedef WImageC WImage1_b; +typedef WImageViewC WImageView1_b; +typedef WImageBufferC WImageBuffer1_b; + +typedef WImageC WImage3_b; +typedef WImageViewC WImageView3_b; +typedef WImageBufferC WImageBuffer3_b; + +typedef WImage WImage_f; +typedef WImageView WImageView_f; +typedef WImageBuffer WImageBuffer_f; + +typedef WImageC WImage1_f; +typedef WImageViewC WImageView1_f; +typedef WImageBufferC WImageBuffer1_f; + +typedef WImageC WImage3_f; +typedef WImageViewC WImageView3_f; +typedef WImageBufferC WImageBuffer3_f; + +// There isn't a standard for signed and unsigned short so be more +// explicit in the typename for these cases. +typedef WImage WImage_16s; +typedef WImageView WImageView_16s; +typedef WImageBuffer WImageBuffer_16s; + +typedef WImageC WImage1_16s; +typedef WImageViewC WImageView1_16s; +typedef WImageBufferC WImageBuffer1_16s; + +typedef WImageC WImage3_16s; +typedef WImageViewC WImageView3_16s; +typedef WImageBufferC WImageBuffer3_16s; + +typedef WImage WImage_16u; +typedef WImageView WImageView_16u; +typedef WImageBuffer WImageBuffer_16u; + +typedef WImageC WImage1_16u; +typedef WImageViewC WImageView1_16u; +typedef WImageBufferC WImageBuffer1_16u; + +typedef WImageC WImage3_16u; +typedef WImageViewC WImageView3_16u; +typedef WImageBufferC WImageBuffer3_16u; + +// +// WImage definitions +// +// This WImage class gives access to the data it refers to. It can be +// constructed either by allocating the data with a WImageBuffer class or +// using the WImageView class to refer to a subimage or outside data. +template +class WImage +{ +public: + typedef T BaseType; + + // WImage is an abstract class with no other virtual methods so make the + // destructor virtual. + virtual ~WImage() = 0; + + // Accessors + IplImage* Ipl() {return image_; } + const IplImage* Ipl() const {return image_; } + T* ImageData() { return reinterpret_cast(image_->imageData); } + const T* ImageData() const { + return reinterpret_cast(image_->imageData); + } + + int Width() const {return image_->width; } + int Height() const {return image_->height; } + + // WidthStep is the number of bytes to go to the pixel with the next y coord + int WidthStep() const {return image_->widthStep; } + + int Channels() const {return image_->nChannels; } + int ChannelSize() const {return sizeof(T); } // number of bytes per channel + + // Number of bytes per pixel + int PixelSize() const {return Channels() * ChannelSize(); } + + // Return depth type (e.g. IPL_DEPTH_8U, IPL_DEPTH_32F) which is the number + // of bits per channel and with the signed bit set. + // This is known at compile time using specializations. + int Depth() const; + + inline const T* Row(int r) const { + return reinterpret_cast(image_->imageData + r*image_->widthStep); + } + + inline T* Row(int r) { + return reinterpret_cast(image_->imageData + r*image_->widthStep); + } + + // Pixel accessors which returns a pointer to the start of the channel + inline T* operator() (int c, int r) { + return reinterpret_cast(image_->imageData + r*image_->widthStep) + + c*Channels(); + } + + inline const T* operator() (int c, int r) const { + return reinterpret_cast(image_->imageData + r*image_->widthStep) + + c*Channels(); + } + + // Copy the contents from another image which is just a convenience to cvCopy + void CopyFrom(const WImage& src) { cvCopy(src.Ipl(), image_); } + + // Set contents to zero which is just a convenient to cvSetZero + void SetZero() { cvSetZero(image_); } + + // Construct a view into a region of this image + WImageView View(int c, int r, int width, int height); + +protected: + // Disallow copy and assignment + WImage(const WImage&); + void operator=(const WImage&); + + explicit WImage(IplImage* img) : image_(img) { + assert(!img || img->depth == Depth()); + } + + void SetIpl(IplImage* image) { + assert(!image || image->depth == Depth()); + image_ = image; + } + + IplImage* image_; +}; + + + +// Image class when both the pixel type and number of channels +// are known at compile time. This wrapper will speed up some of the operations +// like accessing individual pixels using the () operator. +template +class WImageC : public WImage +{ +public: + typedef typename WImage::BaseType BaseType; + enum { kChannels = C }; + + explicit WImageC(IplImage* img) : WImage(img) { + assert(!img || img->nChannels == Channels()); + } + + // Construct a view into a region of this image + WImageViewC View(int c, int r, int width, int height); + + // Copy the contents from another image which is just a convenience to cvCopy + void CopyFrom(const WImageC& src) { + cvCopy(src.Ipl(), WImage::image_); + } + + // WImageC is an abstract class with no other virtual methods so make the + // destructor virtual. + virtual ~WImageC() = 0; + + int Channels() const {return C; } + +protected: + // Disallow copy and assignment + WImageC(const WImageC&); + void operator=(const WImageC&); + + void SetIpl(IplImage* image) { + assert(!image || image->depth == WImage::Depth()); + WImage::SetIpl(image); + } +}; + +// +// WImageBuffer definitions +// +// Image class which owns the data, so it can be allocated and is always +// freed. It cannot be copied but can be explicity cloned. +// +template +class WImageBuffer : public WImage +{ +public: + typedef typename WImage::BaseType BaseType; + + // Default constructor which creates an object that can be + WImageBuffer() : WImage(0) {} + + WImageBuffer(int width, int height, int nchannels) : WImage(0) { + Allocate(width, height, nchannels); + } + + // Constructor which takes ownership of a given IplImage so releases + // the image on destruction. + explicit WImageBuffer(IplImage* img) : WImage(img) {} + + // Allocate an image. Does nothing if current size is the same as + // the new size. + void Allocate(int width, int height, int nchannels); + + // Set the data to point to an image, releasing the old data + void SetIpl(IplImage* img) { + ReleaseImage(); + WImage::SetIpl(img); + } + + // Clone an image which reallocates the image if of a different dimension. + void CloneFrom(const WImage& src) { + Allocate(src.Width(), src.Height(), src.Channels()); + CopyFrom(src); + } + + ~WImageBuffer() { + ReleaseImage(); + } + + // Release the image if it isn't null. + void ReleaseImage() { + if (WImage::image_) { + IplImage* image = WImage::image_; + cvReleaseImage(&image); + WImage::SetIpl(0); + } + } + + bool IsNull() const {return WImage::image_ == NULL; } + +private: + // Disallow copy and assignment + WImageBuffer(const WImageBuffer&); + void operator=(const WImageBuffer&); +}; + +// Like a WImageBuffer class but when the number of channels is known +// at compile time. +template +class WImageBufferC : public WImageC +{ +public: + typedef typename WImage::BaseType BaseType; + enum { kChannels = C }; + + // Default constructor which creates an object that can be + WImageBufferC() : WImageC(0) {} + + WImageBufferC(int width, int height) : WImageC(0) { + Allocate(width, height); + } + + // Constructor which takes ownership of a given IplImage so releases + // the image on destruction. + explicit WImageBufferC(IplImage* img) : WImageC(img) {} + + // Allocate an image. Does nothing if current size is the same as + // the new size. + void Allocate(int width, int height); + + // Set the data to point to an image, releasing the old data + void SetIpl(IplImage* img) { + ReleaseImage(); + WImageC::SetIpl(img); + } + + // Clone an image which reallocates the image if of a different dimension. + void CloneFrom(const WImageC& src) { + Allocate(src.Width(), src.Height()); + CopyFrom(src); + } + + ~WImageBufferC() { + ReleaseImage(); + } + + // Release the image if it isn't null. + void ReleaseImage() { + if (WImage::image_) { + IplImage* image = WImage::image_; + cvReleaseImage(&image); + WImageC::SetIpl(0); + } + } + + bool IsNull() const {return WImage::image_ == NULL; } + +private: + // Disallow copy and assignment + WImageBufferC(const WImageBufferC&); + void operator=(const WImageBufferC&); +}; + +// +// WImageView definitions +// +// View into an image class which allows treating a subimage as an image +// or treating external data as an image +// +template +class WImageView : public WImage +{ +public: + typedef typename WImage::BaseType BaseType; + + // Construct a subimage. No checks are done that the subimage lies + // completely inside the original image. + WImageView(WImage* img, int c, int r, int width, int height); + + // Refer to external data. + // If not given width_step assumed to be same as width. + WImageView(T* data, int width, int height, int channels, int width_step = -1); + + // Refer to external data. This does NOT take ownership + // of the supplied IplImage. + WImageView(IplImage* img) : WImage(img) {} + + // Copy constructor + WImageView(const WImage& img) : WImage(0) { + header_ = *(img.Ipl()); + WImage::SetIpl(&header_); + } + + WImageView& operator=(const WImage& img) { + header_ = *(img.Ipl()); + WImage::SetIpl(&header_); + return *this; + } + +protected: + IplImage header_; +}; + + +template +class WImageViewC : public WImageC +{ +public: + typedef typename WImage::BaseType BaseType; + enum { kChannels = C }; + + // Default constructor needed for vectors of views. + WImageViewC(); + + virtual ~WImageViewC() {} + + // Construct a subimage. No checks are done that the subimage lies + // completely inside the original image. + WImageViewC(WImageC* img, + int c, int r, int width, int height); + + // Refer to external data + WImageViewC(T* data, int width, int height, int width_step = -1); + + // Refer to external data. This does NOT take ownership + // of the supplied IplImage. + WImageViewC(IplImage* img) : WImageC(img) {} + + // Copy constructor which does a shallow copy to allow multiple views + // of same data. gcc-4.1.1 gets confused if both versions of + // the constructor and assignment operator are not provided. + WImageViewC(const WImageC& img) : WImageC(0) { + header_ = *(img.Ipl()); + WImageC::SetIpl(&header_); + } + WImageViewC(const WImageViewC& img) : WImageC(0) { + header_ = *(img.Ipl()); + WImageC::SetIpl(&header_); + } + + WImageViewC& operator=(const WImageC& img) { + header_ = *(img.Ipl()); + WImageC::SetIpl(&header_); + return *this; + } + WImageViewC& operator=(const WImageViewC& img) { + header_ = *(img.Ipl()); + WImageC::SetIpl(&header_); + return *this; + } + +protected: + IplImage header_; +}; + + +// Specializations for depth +template<> +inline int WImage::Depth() const {return IPL_DEPTH_8U; } +template<> +inline int WImage::Depth() const {return IPL_DEPTH_8S; } +template<> +inline int WImage::Depth() const {return IPL_DEPTH_16S; } +template<> +inline int WImage::Depth() const {return IPL_DEPTH_16U; } +template<> +inline int WImage::Depth() const {return IPL_DEPTH_32S; } +template<> +inline int WImage::Depth() const {return IPL_DEPTH_32F; } +template<> +inline int WImage::Depth() const {return IPL_DEPTH_64F; } + +// +// Pure virtual destructors still need to be defined. +// +template inline WImage::~WImage() {} +template inline WImageC::~WImageC() {} + +// +// Allocate ImageData +// +template +inline void WImageBuffer::Allocate(int width, int height, int nchannels) +{ + if (IsNull() || WImage::Width() != width || + WImage::Height() != height || WImage::Channels() != nchannels) { + ReleaseImage(); + WImage::image_ = cvCreateImage(cvSize(width, height), + WImage::Depth(), nchannels); + } +} + +template +inline void WImageBufferC::Allocate(int width, int height) +{ + if (IsNull() || WImage::Width() != width || WImage::Height() != height) { + ReleaseImage(); + WImageC::SetIpl(cvCreateImage(cvSize(width, height),WImage::Depth(), C)); + } +} + +// +// ImageView methods +// +template +WImageView::WImageView(WImage* img, int c, int r, int width, int height) + : WImage(0) +{ + header_ = *(img->Ipl()); + header_.imageData = reinterpret_cast((*img)(c, r)); + header_.width = width; + header_.height = height; + WImage::SetIpl(&header_); +} + +template +WImageView::WImageView(T* data, int width, int height, int nchannels, int width_step) + : WImage(0) +{ + cvInitImageHeader(&header_, cvSize(width, height), WImage::Depth(), nchannels); + header_.imageData = reinterpret_cast(data); + if (width_step > 0) { + header_.widthStep = width_step; + } + WImage::SetIpl(&header_); +} + +template +WImageViewC::WImageViewC(WImageC* img, int c, int r, int width, int height) + : WImageC(0) +{ + header_ = *(img->Ipl()); + header_.imageData = reinterpret_cast((*img)(c, r)); + header_.width = width; + header_.height = height; + WImageC::SetIpl(&header_); +} + +template +WImageViewC::WImageViewC() : WImageC(0) { + cvInitImageHeader(&header_, cvSize(0, 0), WImage::Depth(), C); + header_.imageData = reinterpret_cast(0); + WImageC::SetIpl(&header_); +} + +template +WImageViewC::WImageViewC(T* data, int width, int height, int width_step) + : WImageC(0) +{ + cvInitImageHeader(&header_, cvSize(width, height), WImage::Depth(), C); + header_.imageData = reinterpret_cast(data); + if (width_step > 0) { + header_.widthStep = width_step; + } + WImageC::SetIpl(&header_); +} + +// Construct a view into a region of an image +template +WImageView WImage::View(int c, int r, int width, int height) { + return WImageView(this, c, r, width, height); +} + +template +WImageViewC WImageC::View(int c, int r, int width, int height) { + return WImageViewC(this, c, r, width, height); +} + +} // end of namespace + +#endif // __cplusplus + +#endif diff --git a/core/perf/perf_abs.cpp b/core/perf/perf_abs.cpp new file mode 100644 index 0000000..c84608b --- /dev/null +++ b/core/perf/perf_abs.cpp @@ -0,0 +1,27 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +#define TYPICAL_MAT_SIZES_ABS TYPICAL_MAT_SIZES +#define TYPICAL_MAT_TYPES_ABS CV_8SC1, CV_8SC4, CV_32SC1, CV_32FC1 +#define TYPICAL_MATS_ABS testing::Combine( testing::Values( TYPICAL_MAT_SIZES_ABS), testing::Values( TYPICAL_MAT_TYPES_ABS) ) + +PERF_TEST_P(Size_MatType, abs, TYPICAL_MATS_ABS) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + + cv::Mat a = Mat(sz, type); + cv::Mat c = Mat(sz, type); + + declare.in(a, WARMUP_RNG).out(c); + + TEST_CYCLE() c = cv::abs(a); + + SANITY_CHECK(c); +} + diff --git a/core/perf/perf_addWeighted.cpp b/core/perf/perf_addWeighted.cpp new file mode 100644 index 0000000..6eeded4 --- /dev/null +++ b/core/perf/perf_addWeighted.cpp @@ -0,0 +1,29 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +#define TYPICAL_MAT_TYPES_ADWEIGHTED CV_8UC1, CV_8UC4, CV_8SC1, CV_16UC1, CV_16SC1, CV_32SC1, CV_32SC4 +#define TYPICAL_MATS_ADWEIGHTED testing::Combine(testing::Values(szVGA, sz720p, sz1080p), testing::Values(TYPICAL_MAT_TYPES_ADWEIGHTED)) + +PERF_TEST_P(Size_MatType, addWeighted, TYPICAL_MATS_ADWEIGHTED) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + Mat src1(size, type); + Mat src2(size, type); + double alpha = 3.75; + double beta = -0.125; + double gamma = 100.0; + + Mat dst(size, type); + + declare.in(src1, src2, dst, WARMUP_RNG).out(dst); + + TEST_CYCLE() cv::addWeighted( src1, alpha, src2, beta, gamma, dst, dst.type() ); + + SANITY_CHECK(dst); +} diff --git a/core/perf/perf_arithm.cpp b/core/perf/perf_arithm.cpp new file mode 100644 index 0000000..ea05360 --- /dev/null +++ b/core/perf/perf_arithm.cpp @@ -0,0 +1,190 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +#define TYPICAL_MAT_SIZES_CORE_ARITHM TYPICAL_MAT_SIZES +#define TYPICAL_MAT_TYPES_CORE_ARITHM CV_8UC1, CV_8SC1, CV_16SC1, CV_16SC2, CV_16SC3, CV_16SC4, CV_8UC4, CV_32SC1, CV_32FC1 +#define TYPICAL_MATS_CORE_ARITHM testing::Combine( testing::Values( TYPICAL_MAT_SIZES_CORE_ARITHM ), testing::Values( TYPICAL_MAT_TYPES_CORE_ARITHM ) ) + +#ifdef ANDROID +PERF_TEST(convert, cvRound) +{ + double number = theRNG().uniform(-100, 100); + + int result = 0; + + TEST_CYCLE_N(1000) + { + for (int i = 0; i < 500000; ++i) + result += cvRound(number); + } + + SANITY_CHECK(result); +} +#endif + +PERF_TEST_P(Size_MatType, min, TYPICAL_MATS_CORE_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type); + cv::Mat b = Mat(sz, type); + cv::Mat c = Mat(sz, type); + + declare.in(a, b, WARMUP_RNG).out(c); + + TEST_CYCLE() min(a, b, c); + + SANITY_CHECK(c); +} + +PERF_TEST_P(Size_MatType, minScalar, TYPICAL_MATS_CORE_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type); + cv::Scalar b; + cv::Mat c = Mat(sz, type); + + declare.in(a, b, WARMUP_RNG).out(c); + + TEST_CYCLE() min(a, b, c); + + SANITY_CHECK(c); +} + +PERF_TEST_P(Size_MatType, max, TYPICAL_MATS_CORE_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type); + cv::Mat b = Mat(sz, type); + cv::Mat c = Mat(sz, type); + + declare.in(a, b, WARMUP_RNG).out(c); + + TEST_CYCLE() max(a, b, c); + + SANITY_CHECK(c); +} + +PERF_TEST_P(Size_MatType, maxScalar, TYPICAL_MATS_CORE_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type); + cv::Scalar b; + cv::Mat c = Mat(sz, type); + + declare.in(a, b, WARMUP_RNG).out(c); + + TEST_CYCLE() max(a, b, c); + + SANITY_CHECK(c); +} + +PERF_TEST_P(Size_MatType, absdiff, TYPICAL_MATS_CORE_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type); + cv::Mat b = Mat(sz, type); + cv::Mat c = Mat(sz, type); + + declare.in(a, b, WARMUP_RNG).out(c); + + TEST_CYCLE() absdiff(a, b, c); + + //see ticket 1529: absdiff can be without saturation on 32S + if (CV_MAT_DEPTH(type) != CV_32S) + SANITY_CHECK(c, 1e-8); +} + +PERF_TEST_P(Size_MatType, absdiffScalar, TYPICAL_MATS_CORE_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type); + cv::Scalar b; + cv::Mat c = Mat(sz, type); + + declare.in(a, b, WARMUP_RNG).out(c); + + TEST_CYCLE() absdiff(a, b, c); + + //see ticket 1529: absdiff can be without saturation on 32S + if (CV_MAT_DEPTH(type) != CV_32S) + SANITY_CHECK(c, 1e-8); +} + +PERF_TEST_P(Size_MatType, add, TYPICAL_MATS_CORE_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type); + cv::Mat b = Mat(sz, type); + cv::Mat c = Mat(sz, type); + + declare.in(a, b, WARMUP_RNG).out(c); + + TEST_CYCLE() add(a, b, c); + + //see ticket 1529: add can be without saturation on 32S + if (CV_MAT_DEPTH(type) != CV_32S) + SANITY_CHECK(c, 1e-8); +} + +PERF_TEST_P(Size_MatType, addScalar, TYPICAL_MATS_CORE_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type); + cv::Scalar b; + cv::Mat c = Mat(sz, type); + + declare.in(a, b, WARMUP_RNG).out(c); + + TEST_CYCLE() add(a, b, c); + + //see ticket 1529: add can be without saturation on 32S + if (CV_MAT_DEPTH(type) != CV_32S) + SANITY_CHECK(c, 1e-8); +} + +PERF_TEST_P(Size_MatType, subtract, TYPICAL_MATS_CORE_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type); + cv::Mat b = Mat(sz, type); + cv::Mat c = Mat(sz, type); + + declare.in(a, b, WARMUP_RNG).out(c); + + TEST_CYCLE() subtract(a, b, c); + + //see ticket 1529: subtract can be without saturation on 32S + if (CV_MAT_DEPTH(type) != CV_32S) + SANITY_CHECK(c, 1e-8); +} + +PERF_TEST_P(Size_MatType, subtractScalar, TYPICAL_MATS_CORE_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type); + cv::Scalar b; + cv::Mat c = Mat(sz, type); + + declare.in(a, b, WARMUP_RNG).out(c); + + TEST_CYCLE() subtract(a, b, c); + + //see ticket 1529: subtract can be without saturation on 32S + if (CV_MAT_DEPTH(type) != CV_32S) + SANITY_CHECK(c, 1e-8); +} diff --git a/core/perf/perf_bitwise.cpp b/core/perf/perf_bitwise.cpp new file mode 100644 index 0000000..76354f4 --- /dev/null +++ b/core/perf/perf_bitwise.cpp @@ -0,0 +1,72 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +#define TYPICAL_MAT_SIZES_BITW_ARITHM TYPICAL_MAT_SIZES +#define TYPICAL_MAT_TYPES_BITW_ARITHM CV_8UC1, CV_8SC1, CV_8UC4, CV_32SC1, CV_32SC4 +#define TYPICAL_MATS_BITW_ARITHM testing::Combine(testing::Values(TYPICAL_MAT_SIZES_BITW_ARITHM), testing::Values(TYPICAL_MAT_TYPES_BITW_ARITHM)) + +PERF_TEST_P(Size_MatType, bitwise_not, TYPICAL_MATS_BITW_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + + cv::Mat a = Mat(sz, type); + cv::Mat c = Mat(sz, type); + + declare.in(a, WARMUP_RNG).out(c); + + TEST_CYCLE() cv::bitwise_not(a, c); + + SANITY_CHECK(c); +} + +PERF_TEST_P(Size_MatType, bitwise_and, TYPICAL_MATS_BITW_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type); + cv::Mat b = Mat(sz, type); + cv::Mat c = Mat(sz, type); + + declare.in(a, b, WARMUP_RNG).out(c); + + TEST_CYCLE() bitwise_and(a, b, c); + + SANITY_CHECK(c); +} + +PERF_TEST_P(Size_MatType, bitwise_or, TYPICAL_MATS_BITW_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type); + cv::Mat b = Mat(sz, type); + cv::Mat c = Mat(sz, type); + + declare.in(a, b, WARMUP_RNG).out(c); + + TEST_CYCLE() bitwise_or(a, b, c); + + SANITY_CHECK(c); +} + +PERF_TEST_P(Size_MatType, bitwise_xor, TYPICAL_MATS_BITW_ARITHM) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type); + cv::Mat b = Mat(sz, type); + cv::Mat c = Mat(sz, type); + + declare.in(a, b, WARMUP_RNG).out(c); + + TEST_CYCLE() bitwise_xor(a, b, c); + + SANITY_CHECK(c); +} + diff --git a/core/perf/perf_compare.cpp b/core/perf/perf_compare.cpp new file mode 100644 index 0000000..abbd0d0 --- /dev/null +++ b/core/perf/perf_compare.cpp @@ -0,0 +1,58 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +CV_ENUM(CmpType, CMP_EQ, CMP_GT, CMP_GE, CMP_LT, CMP_LE, CMP_NE) + +typedef std::tr1::tuple Size_MatType_CmpType_t; +typedef perf::TestBaseWithParam Size_MatType_CmpType; + +PERF_TEST_P( Size_MatType_CmpType, compare, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(CV_8UC1, CV_8UC4, CV_8SC1, CV_16UC1, CV_16SC1, CV_32SC1, CV_32FC1), + testing::ValuesIn(CmpType::all()) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType1 = get<1>(GetParam()); + CmpType cmpType = get<2>(GetParam()); + + Mat src1(sz, matType1); + Mat src2(sz, matType1); + Mat dst(sz, CV_8UC(CV_MAT_CN(matType1))); + + declare.in(src1, src2, WARMUP_RNG).out(dst); + + TEST_CYCLE() cv::compare(src1, src2, dst, cmpType); + + SANITY_CHECK(dst); +} + +PERF_TEST_P( Size_MatType_CmpType, compareScalar, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES), + testing::ValuesIn(CmpType::all()) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + CmpType cmpType = get<2>(GetParam()); + + Mat src1(sz, matType); + Scalar src2; + Mat dst(sz, CV_8UC(CV_MAT_CN(matType))); + + declare.in(src1, src2, WARMUP_RNG).out(dst); + + TEST_CYCLE() cv::compare(src1, src2, dst, cmpType); + + SANITY_CHECK(dst); +} diff --git a/core/perf/perf_convertTo.cpp b/core/perf/perf_convertTo.cpp new file mode 100644 index 0000000..7ba9d36 --- /dev/null +++ b/core/perf/perf_convertTo.cpp @@ -0,0 +1,36 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef std::tr1::tuple Size_DepthSrc_DepthDst_Channels_alpha_t; +typedef perf::TestBaseWithParam Size_DepthSrc_DepthDst_Channels_alpha; + +PERF_TEST_P( Size_DepthSrc_DepthDst_Channels_alpha, convertTo, + testing::Combine + ( + testing::Values(szVGA, sz1080p), + testing::Values(CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F), + testing::Values(CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F), + testing::Values(1, 4), + testing::Values(1.0, 1./255) + ) + ) +{ + Size sz = get<0>(GetParam()); + int depthSrc = get<1>(GetParam()); + int depthDst = get<2>(GetParam()); + int channels = get<3>(GetParam()); + double alpha = get<4>(GetParam()); + + Mat src(sz, CV_MAKETYPE(depthSrc, channels)); + randu(src, 0, 255); + Mat dst(sz, CV_MAKETYPE(depthDst, channels)); + + TEST_CYCLE() src.convertTo(dst, depthDst, alpha); + + SANITY_CHECK(dst, alpha == 1.0 ? 1e-12 : 1e-7); +} diff --git a/core/perf/perf_dft.cpp b/core/perf/perf_dft.cpp new file mode 100644 index 0000000..43200d2 --- /dev/null +++ b/core/perf/perf_dft.cpp @@ -0,0 +1,26 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +#define MAT_TYPES_DFT CV_32FC1, CV_64FC1 +#define MAT_SIZES_DFT sz1080p, sz2K +#define TEST_MATS_DFT testing::Combine(testing::Values(MAT_SIZES_DFT), testing::Values(MAT_TYPES_DFT)) + +PERF_TEST_P(Size_MatType, dft, TEST_MATS_DFT) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + + Mat src(sz, type); + Mat dst(sz, type); + + declare.in(src, WARMUP_RNG).time(60); + + TEST_CYCLE() dft(src, dst); + + SANITY_CHECK(dst, 1e-5); +} diff --git a/core/perf/perf_dot.cpp b/core/perf/perf_dot.cpp new file mode 100644 index 0000000..9ff4f8b --- /dev/null +++ b/core/perf/perf_dot.cpp @@ -0,0 +1,30 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef tr1::tuple MatType_Length_t; +typedef TestBaseWithParam MatType_Length; + +PERF_TEST_P( MatType_Length, dot, + testing::Combine( + testing::Values( CV_8UC1, CV_32SC1, CV_32FC1 ), + testing::Values( 32, 64, 128, 256, 512, 1024 ) + )) +{ + int type = get<0>(GetParam()); + int size = get<1>(GetParam()); + Mat a(size, size, type); + Mat b(size, size, type); + + declare.in(a, b, WARMUP_RNG); + + double product; + + TEST_CYCLE_N(1000) product = a.dot(b); + + SANITY_CHECK(product, 1e-6, ERROR_RELATIVE); +} diff --git a/core/perf/perf_inRange.cpp b/core/perf/perf_inRange.cpp new file mode 100644 index 0000000..c4268f2 --- /dev/null +++ b/core/perf/perf_inRange.cpp @@ -0,0 +1,26 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +#define TYPICAL_MAT_TYPES_INRANGE CV_8UC1, CV_8UC4, CV_8SC1, CV_16UC1, CV_16SC1, CV_32SC1, CV_32FC1, CV_32FC4 +#define TYPICAL_MATS_INRANGE testing::Combine(testing::Values(szVGA, sz720p, sz1080p), testing::Values(TYPICAL_MAT_TYPES_INRANGE)) + +PERF_TEST_P(Size_MatType, inRange, TYPICAL_MATS_INRANGE) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + Mat src1(size, type); + Mat src2(size, type); + Mat src3(size, type); + Mat dst(size, type); + + declare.in(src1, src2, src3, WARMUP_RNG).out(dst); + + TEST_CYCLE() inRange( src1, src2, src3, dst ); + + SANITY_CHECK(dst); +} diff --git a/core/perf/perf_main.cpp b/core/perf/perf_main.cpp new file mode 100644 index 0000000..79c28a6 --- /dev/null +++ b/core/perf/perf_main.cpp @@ -0,0 +1,3 @@ +#include "perf_precomp.hpp" + +CV_PERF_TEST_MAIN(core) diff --git a/core/perf/perf_mat.cpp b/core/perf/perf_mat.cpp new file mode 100644 index 0000000..3749feb --- /dev/null +++ b/core/perf/perf_mat.cpp @@ -0,0 +1,96 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +PERF_TEST_P(Size_MatType, Mat_Eye, + testing::Combine(testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES)) + + ) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + Mat diagonalMatrix(size.height, size.width, type); + + declare.out(diagonalMatrix); + + TEST_CYCLE() + { + diagonalMatrix = Mat::eye(size, type); + } + + SANITY_CHECK(diagonalMatrix, 1); +} + +PERF_TEST_P(Size_MatType, Mat_Zeros, + testing::Combine(testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES, CV_32FC3)) + + ) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + Mat zeroMatrix(size.height, size.width, type); + + declare.out(zeroMatrix); + + TEST_CYCLE() + { + zeroMatrix = Mat::zeros(size, type); + } + + SANITY_CHECK(zeroMatrix, 1); +} + +PERF_TEST_P(Size_MatType, Mat_Clone, + testing::Combine(testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES)) + + ) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + Mat source(size.height, size.width, type); + Mat destination(size.height, size.width, type);; + + declare.in(source, WARMUP_RNG).out(destination); + + TEST_CYCLE() + { + source.clone(); + } + destination = source.clone(); + + SANITY_CHECK(destination, 1); +} + +PERF_TEST_P(Size_MatType, Mat_Clone_Roi, + testing::Combine(testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES)) + + ) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + + unsigned int width = size.width; + unsigned int height = size.height; + Mat source(height, width, type); + Mat destination(size.height/2, size.width/2, type); + + declare.in(source, WARMUP_RNG).out(destination); + + Mat roi(source, Rect(width/4, height/4, 3*width/4, 3*height/4)); + + TEST_CYCLE() + { + roi.clone(); + } + destination = roi.clone(); + + SANITY_CHECK(destination, 1); +} diff --git a/core/perf/perf_math.cpp b/core/perf/perf_math.cpp new file mode 100644 index 0000000..de97210 --- /dev/null +++ b/core/perf/perf_math.cpp @@ -0,0 +1,23 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef perf::TestBaseWithParam VectorLength; + +PERF_TEST_P(VectorLength, phase32f, testing::Values(128, 1000, 128*1024, 512*1024, 1024*1024)) +{ + size_t length = GetParam(); + vector X(length); + vector Y(length); + vector angle(length); + + declare.in(X, Y, WARMUP_RNG).out(angle); + + TEST_CYCLE_N(200) cv::phase(X, Y, angle, true); + + SANITY_CHECK(angle, 5e-5); +} diff --git a/core/perf/perf_merge.cpp b/core/perf/perf_merge.cpp new file mode 100644 index 0000000..302b9b2 --- /dev/null +++ b/core/perf/perf_merge.cpp @@ -0,0 +1,36 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef std::tr1::tuple Size_SrcDepth_DstChannels_t; +typedef perf::TestBaseWithParam Size_SrcDepth_DstChannels; + +PERF_TEST_P( Size_SrcDepth_DstChannels, merge, + testing::Combine + ( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(CV_8U, CV_16S, CV_32S, CV_32F, CV_64F), + testing::Values(2, 3, 4) + ) + ) +{ + Size sz = get<0>(GetParam()); + int srcDepth = get<1>(GetParam()); + int dstChannels = get<2>(GetParam()); + + vector mv; + for( int i = 0; i < dstChannels; ++i ) + { + mv.push_back( Mat(sz, CV_MAKETYPE(srcDepth, 1)) ); + randu(mv[i], 0, 255); + } + + Mat dst; + TEST_CYCLE() merge( (vector &)mv, dst ); + + SANITY_CHECK(dst, 1e-12); +} \ No newline at end of file diff --git a/core/perf/perf_minmaxloc.cpp b/core/perf/perf_minmaxloc.cpp new file mode 100644 index 0000000..21fb354 --- /dev/null +++ b/core/perf/perf_minmaxloc.cpp @@ -0,0 +1,35 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +PERF_TEST_P(Size_MatType, minMaxLoc, testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(CV_8UC1, CV_8SC1, CV_16UC1, CV_16SC1, CV_32SC1, CV_32FC1, CV_64FC1) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + + Mat src(sz, matType); + double minVal, maxVal; + Point minLoc, maxLoc; + + if (matType == CV_8U) + randu(src, 1, 254 /*do not include 0 and 255 to avoid early exit on 1 byte data*/); + else if (matType == CV_8S) + randu(src, -127, 126); + else + warmup(src, WARMUP_RNG); + + declare.in(src); + + TEST_CYCLE() minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc); + + SANITY_CHECK(minVal, 1e-12); + SANITY_CHECK(maxVal, 1e-12); +} diff --git a/core/perf/perf_norm.cpp b/core/perf/perf_norm.cpp new file mode 100644 index 0000000..a9428ee --- /dev/null +++ b/core/perf/perf_norm.cpp @@ -0,0 +1,198 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + + +CV_FLAGS(NormType, NORM_INF, NORM_L1, NORM_L2, NORM_TYPE_MASK, NORM_RELATIVE, NORM_MINMAX) +typedef std::tr1::tuple Size_MatType_NormType_t; +typedef perf::TestBaseWithParam Size_MatType_NormType; + +PERF_TEST_P(Size_MatType_NormType, norm, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES), + testing::Values((int)NORM_INF, (int)NORM_L1, (int)NORM_L2) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + int normType = get<2>(GetParam()); + + Mat src(sz, matType); + double n; + + declare.in(src, WARMUP_RNG); + + TEST_CYCLE() n = norm(src, normType); + + SANITY_CHECK(n, 1e-6, ERROR_RELATIVE); +} + +PERF_TEST_P(Size_MatType_NormType, norm_mask, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES), + testing::Values((int)NORM_INF, (int)NORM_L1, (int)NORM_L2) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + int normType = get<2>(GetParam()); + + Mat src(sz, matType); + Mat mask = Mat::ones(sz, CV_8U); + double n; + + declare.in(src, WARMUP_RNG).in(mask); + + TEST_CYCLE() n = norm(src, normType, mask); + + SANITY_CHECK(n, 1e-6, ERROR_RELATIVE); +} + +PERF_TEST_P(Size_MatType_NormType, norm2, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES), + testing::Values((int)NORM_INF, (int)NORM_L1, (int)NORM_L2, (int)(NORM_RELATIVE+NORM_INF), (int)(NORM_RELATIVE+NORM_L1), (int)(NORM_RELATIVE+NORM_L2)) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + int normType = get<2>(GetParam()); + + Mat src1(sz, matType); + Mat src2(sz, matType); + double n; + + declare.in(src1, src2, WARMUP_RNG); + + TEST_CYCLE() n = norm(src1, src2, normType); + + SANITY_CHECK(n, 1e-5, ERROR_RELATIVE); +} + +PERF_TEST_P(Size_MatType_NormType, norm2_mask, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES), + testing::Values((int)NORM_INF, (int)NORM_L1, (int)NORM_L2, (int)(NORM_RELATIVE|NORM_INF), (int)(NORM_RELATIVE|NORM_L1), (int)(NORM_RELATIVE|NORM_L2)) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + int normType = get<2>(GetParam()); + + Mat src1(sz, matType); + Mat src2(sz, matType); + Mat mask = Mat::ones(sz, CV_8U); + double n; + + declare.in(src1, src2, WARMUP_RNG).in(mask); + + TEST_CYCLE() n = norm(src1, src2, normType, mask); + + SANITY_CHECK(n, 1e-5, ERROR_RELATIVE); +} + +PERF_TEST_P(Size_MatType_NormType, normalize, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES), + testing::Values((int)NORM_INF, (int)NORM_L1, (int)NORM_L2) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + int normType = get<2>(GetParam()); + + Mat src(sz, matType); + Mat dst(sz, matType); + + double alpha = 100.; + if(normType==NORM_L1) alpha = (double)src.total() * src.channels(); + if(normType==NORM_L2) alpha = (double)src.total()/10; + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() normalize(src, dst, alpha, 0., normType); + + SANITY_CHECK(dst, 1e-6); +} + +PERF_TEST_P(Size_MatType_NormType, normalize_mask, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES), + testing::Values((int)NORM_INF, (int)NORM_L1, (int)NORM_L2) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + int normType = get<2>(GetParam()); + + Mat src(sz, matType); + Mat dst(sz, matType); + Mat mask = Mat::ones(sz, CV_8U); + + double alpha = 100.; + if(normType==NORM_L1) alpha = (double)src.total() * src.channels(); + if(normType==NORM_L2) alpha = (double)src.total()/10; + + declare.in(src, WARMUP_RNG).in(mask).out(dst); + + TEST_CYCLE() normalize(src, dst, alpha, 0., normType, -1, mask); + + SANITY_CHECK(dst, 1e-6); +} + +PERF_TEST_P(Size_MatType_NormType, normalize_32f, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES), + testing::Values((int)NORM_INF, (int)NORM_L1, (int)NORM_L2) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + int normType = get<2>(GetParam()); + + Mat src(sz, matType); + Mat dst(sz, CV_32F); + + double alpha = 100.; + if(normType==NORM_L1) alpha = (double)src.total() * src.channels(); + if(normType==NORM_L2) alpha = (double)src.total()/10; + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() normalize(src, dst, alpha, 0., normType, CV_32F); + + SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE); +} + +PERF_TEST_P( Size_MatType, normalize_minmax, TYPICAL_MATS ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + + Mat src(sz, matType); + Mat dst(sz, matType); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() normalize(src, dst, 20., 100., NORM_MINMAX); + + SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE); +} diff --git a/core/perf/perf_precomp.cpp b/core/perf/perf_precomp.cpp new file mode 100644 index 0000000..8552ac3 --- /dev/null +++ b/core/perf/perf_precomp.cpp @@ -0,0 +1 @@ +#include "perf_precomp.hpp" diff --git a/core/perf/perf_precomp.hpp b/core/perf/perf_precomp.hpp new file mode 100644 index 0000000..184e84b --- /dev/null +++ b/core/perf/perf_precomp.hpp @@ -0,0 +1,15 @@ +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wmissing-declarations" +# pragma GCC diagnostic ignored "-Wmissing-prototypes" //OSX +#endif + +#ifndef __OPENCV_PERF_PRECOMP_HPP__ +#define __OPENCV_PERF_PRECOMP_HPP__ + +#include "opencv2/ts/ts.hpp" + +#ifdef GTEST_CREATE_SHARED_LIBRARY +#error no modules except ts should have GTEST_CREATE_SHARED_LIBRARY defined +#endif + +#endif diff --git a/core/perf/perf_reduce.cpp b/core/perf/perf_reduce.cpp new file mode 100644 index 0000000..7717277 --- /dev/null +++ b/core/perf/perf_reduce.cpp @@ -0,0 +1,66 @@ +#include "perf_precomp.hpp" +#include "opencv2/core/core_c.h" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +CV_ENUM(ROp, CV_REDUCE_SUM, CV_REDUCE_AVG, CV_REDUCE_MAX, CV_REDUCE_MIN) +typedef std::tr1::tuple Size_MatType_ROp_t; +typedef perf::TestBaseWithParam Size_MatType_ROp; + + +PERF_TEST_P(Size_MatType_ROp, reduceR, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES), + testing::ValuesIn(ROp::all()) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + int reduceOp = get<2>(GetParam()); + + int ddepth = -1; + if( CV_MAT_DEPTH(matType) < CV_32S && (reduceOp == CV_REDUCE_SUM || reduceOp == CV_REDUCE_AVG) ) + ddepth = CV_32S; + + Mat src(sz, matType); + Mat vec(1, sz.width, ddepth < 0 ? matType : ddepth); + + declare.in(src, WARMUP_RNG).out(vec); + + TEST_CYCLE() reduce(src, vec, 0, reduceOp, ddepth); + + SANITY_CHECK(vec, 1); +} + +PERF_TEST_P(Size_MatType_ROp, reduceC, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(TYPICAL_MAT_TYPES), + testing::ValuesIn(ROp::all()) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + int reduceOp = get<2>(GetParam()); + + int ddepth = -1; + if( CV_MAT_DEPTH(matType)< CV_32S && (reduceOp == CV_REDUCE_SUM || reduceOp == CV_REDUCE_AVG) ) + ddepth = CV_32S; + + Mat src(sz, matType); + Mat vec(sz.height, 1, ddepth < 0 ? matType : ddepth); + + declare.in(src, WARMUP_RNG).out(vec); + + TEST_CYCLE() reduce(src, vec, 1, reduceOp, ddepth); + + SANITY_CHECK(vec, 1); +} + diff --git a/core/perf/perf_split.cpp b/core/perf/perf_split.cpp new file mode 100644 index 0000000..ea4e5ab --- /dev/null +++ b/core/perf/perf_split.cpp @@ -0,0 +1,33 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef std::tr1::tuple Size_Depth_Channels_t; +typedef perf::TestBaseWithParam Size_Depth_Channels; + +PERF_TEST_P( Size_Depth_Channels, split, + testing::Combine + ( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(CV_8U, CV_16S, CV_32F, CV_64F), + testing::Values(2, 3, 4) + ) + ) +{ + Size sz = get<0>(GetParam()); + int depth = get<1>(GetParam()); + int channels = get<2>(GetParam()); + + Mat m(sz, CV_MAKETYPE(depth, channels)); + randu(m, 0, 255); + + vector mv; + + TEST_CYCLE() split(m, (vector&)mv); + + SANITY_CHECK(mv, 1e-12); +} diff --git a/core/perf/perf_stat.cpp b/core/perf/perf_stat.cpp new file mode 100644 index 0000000..79e849e --- /dev/null +++ b/core/perf/perf_stat.cpp @@ -0,0 +1,103 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +PERF_TEST_P(Size_MatType, sum, TYPICAL_MATS) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + + Mat arr(sz, type); + Scalar s; + + declare.in(arr, WARMUP_RNG).out(s); + + TEST_CYCLE() s = sum(arr); + + SANITY_CHECK(s, 1e-6, ERROR_RELATIVE); +} + +PERF_TEST_P(Size_MatType, mean, TYPICAL_MATS) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + + Mat src(sz, type); + Scalar s; + + declare.in(src, WARMUP_RNG).out(s); + + TEST_CYCLE() s = mean(src); + + SANITY_CHECK(s, 1e-6); +} + +PERF_TEST_P(Size_MatType, mean_mask, TYPICAL_MATS) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + + Mat src(sz, type); + Mat mask = Mat::ones(src.size(), CV_8U); + Scalar s; + + declare.in(src, WARMUP_RNG).in(mask).out(s); + + TEST_CYCLE() s = mean(src, mask); + + SANITY_CHECK(s, 1e-6); +} + +PERF_TEST_P(Size_MatType, meanStdDev, TYPICAL_MATS) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + + Mat src(sz, matType); + Scalar mean; + Scalar dev; + + declare.in(src, WARMUP_RNG).out(mean, dev); + + TEST_CYCLE() meanStdDev(src, mean, dev); + + SANITY_CHECK(mean, 1e-6); + SANITY_CHECK(dev, 1e-6); +} + +PERF_TEST_P(Size_MatType, meanStdDev_mask, TYPICAL_MATS) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + + Mat src(sz, matType); + Mat mask = Mat::ones(sz, CV_8U); + Scalar mean; + Scalar dev; + + declare.in(src, WARMUP_RNG).in(mask).out(mean, dev); + + TEST_CYCLE() meanStdDev(src, mean, dev, mask); + + SANITY_CHECK(mean, 1e-6); + SANITY_CHECK(dev, 1e-6); +} + +PERF_TEST_P(Size_MatType, countNonZero, testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( CV_8UC1, CV_8SC1, CV_16UC1, CV_16SC1, CV_32SC1, CV_32FC1, CV_64FC1 ) )) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + + Mat src(sz, matType); + int cnt = 0; + + declare.in(src, WARMUP_RNG); + + TEST_CYCLE() cnt = countNonZero(src); + + SANITY_CHECK(cnt); +} diff --git a/core/src/.DS_Store b/core/src/.DS_Store new file mode 100644 index 0000000..f75b91c Binary files /dev/null and b/core/src/.DS_Store differ diff --git a/core/src/algorithm.cpp b/core/src/algorithm.cpp new file mode 100644 index 0000000..3fedfaa --- /dev/null +++ b/core/src/algorithm.cpp @@ -0,0 +1,721 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +namespace cv +{ + +using std::pair; + +template struct sorted_vector +{ + sorted_vector() {} + void clear() { vec.clear(); } + size_t size() const { return vec.size(); } + _ValueTp& operator [](size_t idx) { return vec[idx]; } + const _ValueTp& operator [](size_t idx) const { return vec[idx]; } + + void add(const _KeyTp& k, const _ValueTp& val) + { + pair<_KeyTp, _ValueTp> p(k, val); + vec.push_back(p); + size_t i = vec.size()-1; + for( ; i > 0 && vec[i].first < vec[i-1].first; i-- ) + std::swap(vec[i-1], vec[i]); + CV_Assert( i == 0 || vec[i].first != vec[i-1].first ); + } + + bool find(const _KeyTp& key, _ValueTp& value) const + { + size_t a = 0, b = vec.size(); + while( b > a ) + { + size_t c = (a + b)/2; + if( vec[c].first < key ) + a = c+1; + else + b = c; + } + + if( a < vec.size() && vec[a].first == key ) + { + value = vec[a].second; + return true; + } + return false; + } + + void get_keys(vector<_KeyTp>& keys) const + { + size_t i = 0, n = vec.size(); + keys.resize(n); + + for( i = 0; i < n; i++ ) + keys[i] = vec[i].first; + } + + vector > vec; +}; + + +template inline const _ValueTp* findstr(const sorted_vector& vec, + const char* key) +{ + if( !key ) + return 0; + + size_t a = 0, b = vec.vec.size(); + while( b > a ) + { + size_t c = (a + b)/2; + if( strcmp(vec.vec[c].first.c_str(), key) < 0 ) + a = c+1; + else + b = c; + } + + if( strcmp(vec.vec[a].first.c_str(), key) == 0 ) + return &vec.vec[a].second; + return 0; +} + + +Param::Param() +{ + type = 0; + offset = 0; + readonly = false; + getter = 0; + setter = 0; +} + + +Param::Param(int _type, bool _readonly, int _offset, + Algorithm::Getter _getter, Algorithm::Setter _setter, + const string& _help) +{ + type = _type; + readonly = _readonly; + offset = _offset; + getter = _getter; + setter = _setter; + help = _help; +} + +struct CV_EXPORTS AlgorithmInfoData +{ + sorted_vector params; + string _name; +}; + + +static sorted_vector& alglist() +{ + static sorted_vector alglist_var; + return alglist_var; +} + +void Algorithm::getList(vector& algorithms) +{ + alglist().get_keys(algorithms); +} + +Ptr Algorithm::_create(const string& name) +{ + Algorithm::Constructor c = 0; + if( !alglist().find(name, c) ) + return Ptr(); + return c(); +} + +Algorithm::Algorithm() +{ +} + +Algorithm::~Algorithm() +{ +} + +string Algorithm::name() const +{ + return info()->name(); +} + +void Algorithm::set(const string& parameter, int value) +{ + info()->set(this, parameter.c_str(), ParamType::type, &value); +} + +void Algorithm::set(const string& parameter, double value) +{ + info()->set(this, parameter.c_str(), ParamType::type, &value); +} + +void Algorithm::set(const string& parameter, bool value) +{ + info()->set(this, parameter.c_str(), ParamType::type, &value); +} + +void Algorithm::set(const string& parameter, const string& value) +{ + info()->set(this, parameter.c_str(), ParamType::type, &value); +} + +void Algorithm::set(const string& parameter, const Mat& value) +{ + info()->set(this, parameter.c_str(), ParamType::type, &value); +} + +void Algorithm::set(const string& parameter, const vector& value) +{ + info()->set(this, parameter.c_str(), ParamType >::type, &value); +} + +void Algorithm::set(const string& parameter, const Ptr& value) +{ + info()->set(this, parameter.c_str(), ParamType::type, &value); +} + +void Algorithm::set(const char* parameter, int value) +{ + info()->set(this, parameter, ParamType::type, &value); +} + +void Algorithm::set(const char* parameter, double value) +{ + info()->set(this, parameter, ParamType::type, &value); +} + +void Algorithm::set(const char* parameter, bool value) +{ + info()->set(this, parameter, ParamType::type, &value); +} + +void Algorithm::set(const char* parameter, const string& value) +{ + info()->set(this, parameter, ParamType::type, &value); +} + +void Algorithm::set(const char* parameter, const Mat& value) +{ + info()->set(this, parameter, ParamType::type, &value); +} + +void Algorithm::set(const char* parameter, const vector& value) +{ + info()->set(this, parameter, ParamType >::type, &value); +} + +void Algorithm::set(const char* parameter, const Ptr& value) +{ + info()->set(this, parameter, ParamType::type, &value); +} + +int Algorithm::getInt(const string& parameter) const +{ + return get(parameter); +} + +double Algorithm::getDouble(const string& parameter) const +{ + return get(parameter); +} + +bool Algorithm::getBool(const string& parameter) const +{ + return get(parameter); +} + +string Algorithm::getString(const string& parameter) const +{ + return get(parameter); +} + +Mat Algorithm::getMat(const string& parameter) const +{ + return get(parameter); +} + +vector Algorithm::getMatVector(const string& parameter) const +{ + return get >(parameter); +} + +Ptr Algorithm::getAlgorithm(const string& parameter) const +{ + return get(parameter); +} + +string Algorithm::paramHelp(const string& parameter) const +{ + return info()->paramHelp(parameter.c_str()); +} + +int Algorithm::paramType(const string& parameter) const +{ + return info()->paramType(parameter.c_str()); +} + +int Algorithm::paramType(const char* parameter) const +{ + return info()->paramType(parameter); +} + +void Algorithm::getParams(vector& names) const +{ + info()->getParams(names); +} + +void Algorithm::write(FileStorage& fs) const +{ + info()->write(this, fs); +} + +void Algorithm::read(const FileNode& fn) +{ + info()->read(this, fn); +} + + +AlgorithmInfo::AlgorithmInfo(const string& _name, Algorithm::Constructor create) +{ + data = new AlgorithmInfoData; + data->_name = _name; + if (!alglist().find(_name, create)) + alglist().add(_name, create); +} + +AlgorithmInfo::~AlgorithmInfo() +{ + delete data; +} + +void AlgorithmInfo::write(const Algorithm* algo, FileStorage& fs) const +{ + size_t i = 0, nparams = data->params.vec.size(); + cv::write(fs, "name", algo->name()); + for( i = 0; i < nparams; i++ ) + { + const Param& p = data->params.vec[i].second; + const string& pname = data->params.vec[i].first; + if( p.type == Param::INT ) + cv::write(fs, pname, algo->get(pname)); + else if( p.type == Param::BOOLEAN ) + cv::write(fs, pname, (int)algo->get(pname)); + else if( p.type == Param::REAL ) + cv::write(fs, pname, algo->get(pname)); + else if( p.type == Param::STRING ) + cv::write(fs, pname, algo->get(pname)); + else if( p.type == Param::MAT ) + cv::write(fs, pname, algo->get(pname)); + else if( p.type == Param::MAT_VECTOR ) + cv::write(fs, pname, algo->get >(pname)); + else if( p.type == Param::ALGORITHM ) + { + WriteStructContext ws(fs, pname, CV_NODE_MAP); + Ptr nestedAlgo = algo->get(pname); + nestedAlgo->write(fs); + } + else + CV_Error( CV_StsUnsupportedFormat, "unknown/unsupported parameter type"); + } +} + +void AlgorithmInfo::read(Algorithm* algo, const FileNode& fn) const +{ + size_t i = 0, nparams = data->params.vec.size(); + AlgorithmInfo* info = algo->info(); + + for( i = 0; i < nparams; i++ ) + { + const Param& p = data->params.vec[i].second; + const string& pname = data->params.vec[i].first; + const FileNode n = fn[pname]; + if( n.empty() ) + continue; + if( p.type == Param::INT ) + { + int val = (int)n; + info->set(algo, pname.c_str(), p.type, &val, true); + } + else if( p.type == Param::BOOLEAN ) + { + bool val = (int)n != 0; + info->set(algo, pname.c_str(), p.type, &val, true); + } + else if( p.type == Param::REAL ) + { + double val = (double)n; + info->set(algo, pname.c_str(), p.type, &val, true); + } + else if( p.type == Param::STRING ) + { + string val = (string)n; + info->set(algo, pname.c_str(), p.type, &val, true); + } + else if( p.type == Param::MAT ) + { + Mat m; + cv::read(n, m); + info->set(algo, pname.c_str(), p.type, &m, true); + } + else if( p.type == Param::MAT_VECTOR ) + { + vector mv; + cv::read(n, mv); + info->set(algo, pname.c_str(), p.type, &mv, true); + } + else if( p.type == Param::ALGORITHM ) + { + Ptr nestedAlgo = Algorithm::_create((string)n["name"]); + CV_Assert( !nestedAlgo.empty() ); + nestedAlgo->read(n); + info->set(algo, pname.c_str(), p.type, &nestedAlgo, true); + } + else + CV_Error( CV_StsUnsupportedFormat, "unknown/unsupported parameter type"); + } +} + +string AlgorithmInfo::name() const +{ + return data->_name; +} + +union GetSetParam +{ + int (Algorithm::*get_int)() const; + bool (Algorithm::*get_bool)() const; + double (Algorithm::*get_double)() const; + string (Algorithm::*get_string)() const; + Mat (Algorithm::*get_mat)() const; + vector (Algorithm::*get_mat_vector)() const; + Ptr (Algorithm::*get_algo)() const; + + void (Algorithm::*set_int)(int); + void (Algorithm::*set_bool)(bool); + void (Algorithm::*set_double)(double); + void (Algorithm::*set_string)(const string&); + void (Algorithm::*set_mat)(const Mat&); + void (Algorithm::*set_mat_vector)(const vector&); + void (Algorithm::*set_algo)(const Ptr&); +}; + +void AlgorithmInfo::set(Algorithm* algo, const char* parameter, int argType, const void* value, bool force) const +{ + const Param* p = findstr(data->params, parameter); + + if( !p ) + CV_Error_( CV_StsBadArg, ("No parameter '%s' is found", parameter ? parameter : "") ); + + if( !force && p->readonly ) + CV_Error_( CV_StsError, ("Parameter '%s' is readonly", parameter)); + + GetSetParam f; + f.set_int = p->setter; + + if( argType == Param::INT || argType == Param::BOOLEAN || argType == Param::REAL ) + { + CV_Assert( p->type == Param::INT || p->type == Param::REAL || p->type == Param::BOOLEAN ); + + if( p->type == Param::INT ) + { + int val = argType == Param::INT ? *(const int*)value : + argType == Param::BOOLEAN ? (int)*(const bool*)value : + saturate_cast(*(const double*)value); + if( p->setter ) + (algo->*f.set_int)(val); + else + *(int*)((uchar*)algo + p->offset) = val; + } + else if( p->type == Param::BOOLEAN ) + { + bool val = argType == Param::INT ? *(const int*)value != 0 : + argType == Param::BOOLEAN ? *(const bool*)value : + *(const double*)value != 0; + if( p->setter ) + (algo->*f.set_bool)(val); + else + *(bool*)((uchar*)algo + p->offset) = val; + } + else + { + double val = argType == Param::INT ? (double)*(const int*)value : + argType == Param::BOOLEAN ? (double)*(const bool*)value : + *(const double*)value; + if( p->setter ) + (algo->*f.set_double)(val); + else + *(double*)((uchar*)algo + p->offset) = val; + } + } + else if( argType == Param::STRING ) + { + CV_Assert( p->type == Param::STRING ); + + const string& val = *(const string*)value; + if( p->setter ) + (algo->*f.set_string)(val); + else + *(string*)((uchar*)algo + p->offset) = val; + } + else if( argType == Param::MAT ) + { + CV_Assert( p->type == Param::MAT ); + + const Mat& val = *(const Mat*)value; + if( p->setter ) + (algo->*f.set_mat)(val); + else + *(Mat*)((uchar*)algo + p->offset) = val; + } + else if( argType == Param::MAT_VECTOR ) + { + CV_Assert( p->type == Param::MAT_VECTOR ); + + const vector& val = *(const vector*)value; + if( p->setter ) + (algo->*f.set_mat_vector)(val); + else + *(vector*)((uchar*)algo + p->offset) = val; + } + else if( argType == Param::ALGORITHM ) + { + CV_Assert( p->type == Param::ALGORITHM ); + + const Ptr& val = *(const Ptr*)value; + if( p->setter ) + (algo->*f.set_algo)(val); + else + *(Ptr*)((uchar*)algo + p->offset) = val; + } + else + CV_Error(CV_StsBadArg, "Unknown/unsupported parameter type"); +} + +void AlgorithmInfo::get(const Algorithm* algo, const char* parameter, int argType, void* value) const +{ + const Param* p = findstr(data->params, parameter); + if( !p ) + CV_Error_( CV_StsBadArg, ("No parameter '%s' is found", parameter ? parameter : "") ); + + GetSetParam f; + f.get_int = p->getter; + + if( argType == Param::INT || argType == Param::BOOLEAN || argType == Param::REAL ) + { + if( p->type == Param::INT ) + { + CV_Assert( argType == Param::INT || argType == Param::REAL ); + int val = p->getter ? (algo->*f.get_int)() : *(int*)((uchar*)algo + p->offset); + + if( argType == Param::INT ) + *(int*)value = val; + else + *(double*)value = val; + } + else if( p->type == Param::BOOLEAN ) + { + CV_Assert( argType == Param::INT || argType == Param::BOOLEAN || argType == Param::REAL ); + bool val = p->getter ? (algo->*f.get_bool)() : *(bool*)((uchar*)algo + p->offset); + + if( argType == Param::INT ) + *(int*)value = (int)val; + else if( argType == Param::BOOLEAN ) + *(bool*)value = val; + else + *(double*)value = (int)val; + } + else + { + CV_Assert( argType == Param::REAL ); + double val = p->getter ? (algo->*f.get_double)() : *(double*)((uchar*)algo + p->offset); + + *(double*)value = val; + } + } + else if( argType == Param::STRING ) + { + CV_Assert( p->type == Param::STRING ); + + *(string*)value = p->getter ? (algo->*f.get_string)() : + *(string*)((uchar*)algo + p->offset); + } + else if( argType == Param::MAT ) + { + CV_Assert( p->type == Param::MAT ); + + *(Mat*)value = p->getter ? (algo->*f.get_mat)() : + *(Mat*)((uchar*)algo + p->offset); + } + else if( argType == Param::MAT_VECTOR ) + { + CV_Assert( p->type == Param::MAT_VECTOR ); + + *(vector*)value = p->getter ? (algo->*f.get_mat_vector)() : + *(vector*)((uchar*)algo + p->offset); + } + else if( argType == Param::ALGORITHM ) + { + CV_Assert( p->type == Param::ALGORITHM ); + + *(Ptr*)value = p->getter ? (algo->*f.get_algo)() : + *(Ptr*)((uchar*)algo + p->offset); + } + else + CV_Error(CV_StsBadArg, "Unknown/unsupported parameter type"); +} + + +int AlgorithmInfo::paramType(const char* parameter) const +{ + const Param* p = findstr(data->params, parameter); + if( !p ) + CV_Error_( CV_StsBadArg, ("No parameter '%s' is found", parameter ? parameter : "") ); + return p->type; +} + + +string AlgorithmInfo::paramHelp(const char* parameter) const +{ + const Param* p = findstr(data->params, parameter); + if( !p ) + CV_Error_( CV_StsBadArg, ("No parameter '%s' is found", parameter ? parameter : "") ); + return p->help; +} + + +void AlgorithmInfo::getParams(vector& names) const +{ + data->params.get_keys(names); +} + + +void AlgorithmInfo::addParam_(Algorithm& algo, const char* parameter, int argType, + void* value, bool readOnly, + Algorithm::Getter getter, Algorithm::Setter setter, + const string& help) +{ + CV_Assert( argType == Param::INT || argType == Param::BOOLEAN || + argType == Param::REAL || argType == Param::STRING || + argType == Param::MAT || argType == Param::MAT_VECTOR || + argType == Param::ALGORITHM ); + data->params.add(string(parameter), Param(argType, readOnly, + (int)((size_t)value - (size_t)(void*)&algo), + getter, setter, help)); +} + + +void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, + int& value, bool readOnly, + int (Algorithm::*getter)(), + void (Algorithm::*setter)(int), + const string& help) +{ + addParam_(algo, parameter, ParamType::type, &value, readOnly, + (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); +} + +void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, + bool& value, bool readOnly, + int (Algorithm::*getter)(), + void (Algorithm::*setter)(int), + const string& help) +{ + addParam_(algo, parameter, ParamType::type, &value, readOnly, + (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); +} + +void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, + double& value, bool readOnly, + double (Algorithm::*getter)(), + void (Algorithm::*setter)(double), + const string& help) +{ + addParam_(algo, parameter, ParamType::type, &value, readOnly, + (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); +} + +void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, + string& value, bool readOnly, + string (Algorithm::*getter)(), + void (Algorithm::*setter)(const string&), + const string& help) +{ + addParam_(algo, parameter, ParamType::type, &value, readOnly, + (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); +} + +void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, + Mat& value, bool readOnly, + Mat (Algorithm::*getter)(), + void (Algorithm::*setter)(const Mat&), + const string& help) +{ + addParam_(algo, parameter, ParamType::type, &value, readOnly, + (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); +} + +void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, + vector& value, bool readOnly, + vector (Algorithm::*getter)(), + void (Algorithm::*setter)(const vector&), + const string& help) +{ + addParam_(algo, parameter, ParamType >::type, &value, readOnly, + (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); +} + +void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, + Ptr& value, bool readOnly, + Ptr (Algorithm::*getter)(), + void (Algorithm::*setter)(const Ptr&), + const string& help) +{ + addParam_(algo, parameter, ParamType::type, &value, readOnly, + (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); +} + +} + +/* End of file. */ diff --git a/core/src/alloc.cpp b/core/src/alloc.cpp new file mode 100644 index 0000000..1944ed1 --- /dev/null +++ b/core/src/alloc.cpp @@ -0,0 +1,702 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#define CV_USE_SYSTEM_MALLOC 1 + +namespace cv +{ + +static void* OutOfMemoryError(size_t size) +{ + CV_Error_(CV_StsNoMem, ("Failed to allocate %lu bytes", (unsigned long)size)); + return 0; +} + +#if CV_USE_SYSTEM_MALLOC + +#if defined WIN32 || defined _WIN32 +void deleteThreadAllocData() {} +#endif + +void* fastMalloc( size_t size ) +{ + uchar* udata = (uchar*)malloc(size + sizeof(void*) + CV_MALLOC_ALIGN); + if(!udata) + return OutOfMemoryError(size); + uchar** adata = alignPtr((uchar**)udata + 1, CV_MALLOC_ALIGN); + adata[-1] = udata; + return adata; +} + +void fastFree(void* ptr) +{ + if(ptr) + { + uchar* udata = ((uchar**)ptr)[-1]; + CV_DbgAssert(udata < (uchar*)ptr && + ((uchar*)ptr - udata) <= (ptrdiff_t)(sizeof(void*)+CV_MALLOC_ALIGN)); + free(udata); + } +} + +#else //CV_USE_SYSTEM_MALLOC + +#if 0 +#define SANITY_CHECK(block) \ + CV_Assert(((size_t)(block) & (MEM_BLOCK_SIZE-1)) == 0 && \ + (unsigned)(block)->binIdx <= (unsigned)MAX_BIN && \ + (block)->signature == MEM_BLOCK_SIGNATURE) +#else +#define SANITY_CHECK(block) +#endif + +#define STAT(stmt) + +#ifdef WIN32 +struct CriticalSection +{ + CriticalSection() { InitializeCriticalSection(&cs); } + ~CriticalSection() { DeleteCriticalSection(&cs); } + void lock() { EnterCriticalSection(&cs); } + void unlock() { LeaveCriticalSection(&cs); } + bool trylock() { return TryEnterCriticalSection(&cs) != 0; } + + CRITICAL_SECTION cs; +}; + +void* SystemAlloc(size_t size) +{ + void* ptr = malloc(size); + return ptr ? ptr : OutOfMemoryError(size); +} + +void SystemFree(void* ptr, size_t) +{ + free(ptr); +} +#else //WIN32 + +#include + +struct CriticalSection +{ + CriticalSection() { pthread_mutex_init(&mutex, 0); } + ~CriticalSection() { pthread_mutex_destroy(&mutex); } + void lock() { pthread_mutex_lock(&mutex); } + void unlock() { pthread_mutex_unlock(&mutex); } + bool trylock() { return pthread_mutex_trylock(&mutex) == 0; } + + pthread_mutex_t mutex; +}; + +void* SystemAlloc(size_t size) +{ + #ifndef MAP_ANONYMOUS + #define MAP_ANONYMOUS MAP_ANON + #endif + void* ptr = 0; + ptr = mmap(ptr, size, (PROT_READ | PROT_WRITE), MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + return ptr != MAP_FAILED ? ptr : OutOfMemoryError(size); +} + +void SystemFree(void* ptr, size_t size) +{ + munmap(ptr, size); +} +#endif //WIN32 + +struct AutoLock +{ + AutoLock(CriticalSection& _cs) : cs(&_cs) { cs->lock(); } + ~AutoLock() { cs->unlock(); } + CriticalSection* cs; +}; + +const size_t MEM_BLOCK_SIGNATURE = 0x01234567; +const int MEM_BLOCK_SHIFT = 14; +const size_t MEM_BLOCK_SIZE = 1 << MEM_BLOCK_SHIFT; +const size_t HDR_SIZE = 128; +const size_t MAX_BLOCK_SIZE = MEM_BLOCK_SIZE - HDR_SIZE; +const int MAX_BIN = 28; + +static const int binSizeTab[MAX_BIN+1] = +{ 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 128, 160, 192, 256, 320, 384, 480, 544, 672, 768, +896, 1056, 1328, 1600, 2688, 4048, 5408, 8128, 16256 }; + +struct MallocTables +{ + void initBinTab() + { + int i, j = 0, n; + for( i = 0; i <= MAX_BIN; i++ ) + { + n = binSizeTab[i]>>3; + for( ; j <= n; j++ ) + binIdx[j] = (uchar)i; + } + } + int bin(size_t size) + { + assert( size <= MAX_BLOCK_SIZE ); + return binIdx[(size + 7)>>3]; + } + + MallocTables() + { + initBinTab(); + } + + uchar binIdx[MAX_BLOCK_SIZE/8+1]; +}; + +MallocTables mallocTables; + +struct Node +{ + Node* next; +}; + +struct ThreadData; + +struct Block +{ + Block(Block* _next) + { + signature = MEM_BLOCK_SIGNATURE; + prev = 0; + next = _next; + privateFreeList = publicFreeList = 0; + bumpPtr = endPtr = 0; + objSize = 0; + threadData = 0; + data = (uchar*)this + HDR_SIZE; + } + + ~Block() {} + + void init(Block* _prev, Block* _next, int _objSize, ThreadData* _threadData) + { + prev = _prev; + if(prev) + prev->next = this; + next = _next; + if(next) + next->prev = this; + objSize = _objSize; + binIdx = mallocTables.bin(objSize); + threadData = _threadData; + privateFreeList = publicFreeList = 0; + bumpPtr = data; + int nobjects = MAX_BLOCK_SIZE/objSize; + endPtr = bumpPtr + nobjects*objSize; + almostEmptyThreshold = (nobjects + 1)/2; + allocated = 0; + } + + bool isFilled() const { return allocated > almostEmptyThreshold; } + + size_t signature; + Block* prev; + Block* next; + Node* privateFreeList; + Node* publicFreeList; + uchar* bumpPtr; + uchar* endPtr; + uchar* data; + ThreadData* threadData; + int objSize; + int binIdx; + int allocated; + int almostEmptyThreshold; + CriticalSection cs; +}; + +struct BigBlock +{ + BigBlock(int bigBlockSize, BigBlock* _next) + { + first = alignPtr((Block*)(this+1), MEM_BLOCK_SIZE); + next = _next; + nblocks = (int)(((char*)this + bigBlockSize - (char*)first)/MEM_BLOCK_SIZE); + Block* p = 0; + for( int i = nblocks-1; i >= 0; i-- ) + p = ::new((uchar*)first + i*MEM_BLOCK_SIZE) Block(p); + } + + ~BigBlock() + { + for( int i = nblocks-1; i >= 0; i-- ) + ((Block*)((uchar*)first+i*MEM_BLOCK_SIZE))->~Block(); + } + + BigBlock* next; + Block* first; + int nblocks; +}; + +struct BlockPool +{ + BlockPool(int _bigBlockSize=1<<20) : pool(0), bigBlockSize(_bigBlockSize) + { + } + + ~BlockPool() + { + AutoLock lock(cs); + while( pool ) + { + BigBlock* nextBlock = pool->next; + pool->~BigBlock(); + SystemFree(pool, bigBlockSize); + pool = nextBlock; + } + } + + Block* alloc() + { + AutoLock lock(cs); + Block* block; + if( !freeBlocks ) + { + BigBlock* bblock = ::new(SystemAlloc(bigBlockSize)) BigBlock(bigBlockSize, pool); + assert( bblock != 0 ); + freeBlocks = bblock->first; + pool = bblock; + } + block = freeBlocks; + freeBlocks = freeBlocks->next; + if( freeBlocks ) + freeBlocks->prev = 0; + STAT(stat.bruttoBytes += MEM_BLOCK_SIZE); + return block; + } + + void free(Block* block) + { + AutoLock lock(cs); + block->prev = 0; + block->next = freeBlocks; + freeBlocks = block; + STAT(stat.bruttoBytes -= MEM_BLOCK_SIZE); + } + + CriticalSection cs; + Block* freeBlocks; + BigBlock* pool; + int bigBlockSize; + int blocksPerBigBlock; +}; + +BlockPool mallocPool; + +enum { START=0, FREE=1, GC=2 }; + +struct ThreadData +{ + ThreadData() { for(int i = 0; i <= MAX_BIN; i++) bins[i][START] = bins[i][FREE] = bins[i][GC] = 0; } + ~ThreadData() + { + // mark all the thread blocks as abandoned or even release them + for( int i = 0; i <= MAX_BIN; i++ ) + { + Block *bin = bins[i][START], *block = bin; + bins[i][START] = bins[i][FREE] = bins[i][GC] = 0; + if( block ) + { + do + { + Block* next = block->next; + int allocated = block->allocated; + { + AutoLock lock(block->cs); + block->next = block->prev = 0; + block->threadData = 0; + Node *node = block->publicFreeList; + for( ; node != 0; node = node->next ) + allocated--; + } + if( allocated == 0 ) + mallocPool.free(block); + block = next; + } + while( block != bin ); + } + } + } + + void moveBlockToFreeList( Block* block ) + { + int i = block->binIdx; + Block*& freePtr = bins[i][FREE]; + CV_DbgAssert( block->next->prev == block && block->prev->next == block ); + if( block != freePtr ) + { + Block*& gcPtr = bins[i][GC]; + if( gcPtr == block ) + gcPtr = block->next; + if( block->next != block ) + { + block->prev->next = block->next; + block->next->prev = block->prev; + } + block->next = freePtr->next; + block->prev = freePtr; + freePtr = block->next->prev = block->prev->next = block; + } + } + + Block* bins[MAX_BIN+1][3]; + +#ifdef WIN32 +#ifdef WINCE +# define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF) +#endif //WINCE + + static DWORD tlsKey; + static ThreadData* get() + { + ThreadData* data; + if( tlsKey == TLS_OUT_OF_INDEXES ) + tlsKey = TlsAlloc(); + data = (ThreadData*)TlsGetValue(tlsKey); + if( !data ) + { + data = new ThreadData; + TlsSetValue(tlsKey, data); + } + return data; + } +#else //WIN32 + static void deleteData(void* data) + { + delete (ThreadData*)data; + } + + static pthread_key_t tlsKey; + static ThreadData* get() + { + ThreadData* data; + if( !tlsKey ) + pthread_key_create(&tlsKey, deleteData); + data = (ThreadData*)pthread_getspecific(tlsKey); + if( !data ) + { + data = new ThreadData; + pthread_setspecific(tlsKey, data); + } + return data; + } +#endif //WIN32 +}; + +#ifdef WIN32 +DWORD ThreadData::tlsKey = TLS_OUT_OF_INDEXES; + +void deleteThreadAllocData() +{ + if( ThreadData::tlsKey != TLS_OUT_OF_INDEXES ) + delete (ThreadData*)TlsGetValue( ThreadData::tlsKey ); +} + +#else //WIN32 +pthread_key_t ThreadData::tlsKey = 0; +#endif //WIN32 + +#if 0 +static void checkList(ThreadData* tls, int idx) +{ + Block* block = tls->bins[idx][START]; + if( !block ) + { + CV_DbgAssert( tls->bins[idx][FREE] == 0 && tls->bins[idx][GC] == 0 ); + } + else + { + bool gcInside = false; + bool freeInside = false; + do + { + if( tls->bins[idx][FREE] == block ) + freeInside = true; + if( tls->bins[idx][GC] == block ) + gcInside = true; + block = block->next; + } + while( block != tls->bins[idx][START] ); + CV_DbgAssert( gcInside && freeInside ); + } +} +#else +#define checkList(tls, idx) +#endif + +void* fastMalloc( size_t size ) +{ + if( size > MAX_BLOCK_SIZE ) + { + size_t size1 = size + sizeof(uchar*)*2 + MEM_BLOCK_SIZE; + uchar* udata = (uchar*)SystemAlloc(size1); + uchar** adata = alignPtr((uchar**)udata + 2, MEM_BLOCK_SIZE); + adata[-1] = udata; + adata[-2] = (uchar*)size1; + return adata; + } + + { + ThreadData* tls = ThreadData::get(); + int idx = mallocTables.bin(size); + Block*& startPtr = tls->bins[idx][START]; + Block*& gcPtr = tls->bins[idx][GC]; + Block*& freePtr = tls->bins[idx][FREE], *block = freePtr; + checkList(tls, idx); + size = binSizeTab[idx]; + STAT( + stat.nettoBytes += size; + stat.mallocCalls++; + ); + uchar* data = 0; + + for(;;) + { + if( block ) + { + // try to find non-full block + for(;;) + { + CV_DbgAssert( block->next->prev == block && block->prev->next == block ); + if( block->bumpPtr ) + { + data = block->bumpPtr; + if( (block->bumpPtr += size) >= block->endPtr ) + block->bumpPtr = 0; + break; + } + + if( block->privateFreeList ) + { + data = (uchar*)block->privateFreeList; + block->privateFreeList = block->privateFreeList->next; + break; + } + + if( block == startPtr ) + break; + block = block->next; + } +#if 0 + avg_k += _k; + avg_nk++; + if( avg_nk == 1000 ) + { + printf("avg search iters per 1e3 allocs = %g\n", (double)avg_k/avg_nk ); + avg_k = avg_nk = 0; + } +#endif + + freePtr = block; + if( !data ) + { + block = gcPtr; + for( int k = 0; k < 2; k++ ) + { + SANITY_CHECK(block); + CV_DbgAssert( block->next->prev == block && block->prev->next == block ); + if( block->publicFreeList ) + { + { + AutoLock lock(block->cs); + block->privateFreeList = block->publicFreeList; + block->publicFreeList = 0; + } + Node* node = block->privateFreeList; + for(;node != 0; node = node->next) + --block->allocated; + data = (uchar*)block->privateFreeList; + block->privateFreeList = block->privateFreeList->next; + gcPtr = block->next; + if( block->allocated+1 <= block->almostEmptyThreshold ) + tls->moveBlockToFreeList(block); + break; + } + block = block->next; + } + if( !data ) + gcPtr = block; + } + } + + if( data ) + break; + block = mallocPool.alloc(); + block->init(startPtr ? startPtr->prev : block, startPtr ? startPtr : block, (int)size, tls); + if( !startPtr ) + startPtr = gcPtr = freePtr = block; + checkList(tls, block->binIdx); + SANITY_CHECK(block); + } + + ++block->allocated; + return data; + } +} + +void fastFree( void* ptr ) +{ + if( ((size_t)ptr & (MEM_BLOCK_SIZE-1)) == 0 ) + { + if( ptr != 0 ) + { + void* origPtr = ((void**)ptr)[-1]; + size_t sz = (size_t)((void**)ptr)[-2]; + SystemFree( origPtr, sz ); + } + return; + } + + { + ThreadData* tls = ThreadData::get(); + Node* node = (Node*)ptr; + Block* block = (Block*)((size_t)ptr & -(int)MEM_BLOCK_SIZE); + assert( block->signature == MEM_BLOCK_SIGNATURE ); + + if( block->threadData == tls ) + { + STAT( + stat.nettoBytes -= block->objSize; + stat.freeCalls++; + float ratio = (float)stat.nettoBytes/stat.bruttoBytes; + if( stat.minUsageRatio > ratio ) + stat.minUsageRatio = ratio; + ); + + SANITY_CHECK(block); + + bool prevFilled = block->isFilled(); + --block->allocated; + if( !block->isFilled() && (block->allocated == 0 || prevFilled) ) + { + if( block->allocated == 0 ) + { + int idx = block->binIdx; + Block*& startPtr = tls->bins[idx][START]; + Block*& freePtr = tls->bins[idx][FREE]; + Block*& gcPtr = tls->bins[idx][GC]; + + if( block == block->next ) + { + CV_DbgAssert( startPtr == block && freePtr == block && gcPtr == block ); + startPtr = freePtr = gcPtr = 0; + } + else + { + if( freePtr == block ) + freePtr = block->next; + if( gcPtr == block ) + gcPtr = block->next; + if( startPtr == block ) + startPtr = block->next; + block->prev->next = block->next; + block->next->prev = block->prev; + } + mallocPool.free(block); + checkList(tls, idx); + return; + } + + tls->moveBlockToFreeList(block); + } + node->next = block->privateFreeList; + block->privateFreeList = node; + } + else + { + AutoLock lock(block->cs); + SANITY_CHECK(block); + + node->next = block->publicFreeList; + block->publicFreeList = node; + if( block->threadData == 0 ) + { + // take ownership of the abandoned block. + // note that it can happen at the same time as + // ThreadData::deleteData() marks the blocks as abandoned, + // so this part of the algorithm needs to be checked for data races + int idx = block->binIdx; + block->threadData = tls; + Block*& startPtr = tls->bins[idx][START]; + + if( startPtr ) + { + block->next = startPtr; + block->prev = startPtr->prev; + block->next->prev = block->prev->next = block; + } + else + startPtr = tls->bins[idx][FREE] = tls->bins[idx][GC] = block; + } + } + } +} + +#endif //CV_USE_SYSTEM_MALLOC + +} + +CV_IMPL void cvSetMemoryManager( CvAllocFunc, CvFreeFunc, void * ) +{ + CV_Error( -1, "Custom memory allocator is not supported" ); +} + +CV_IMPL void* cvAlloc( size_t size ) +{ + return cv::fastMalloc( size ); +} + +CV_IMPL void cvFree_( void* ptr ) +{ + cv::fastFree( ptr ); +} + + +/* End of file. */ diff --git a/core/src/arithm.cpp b/core/src/arithm.cpp new file mode 100644 index 0000000..e252a28 --- /dev/null +++ b/core/src/arithm.cpp @@ -0,0 +1,2882 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +/* //////////////////////////////////////////////////////////////////// +// +// Arithmetic and logical operations: +, -, *, /, &, |, ^, ~, abs ... +// +// */ + +#include "precomp.hpp" + +namespace cv +{ + +#if ARITHM_USE_IPP +struct IPPArithmInitializer +{ + IPPArithmInitializer(void) + { + ippStaticInit(); + } +}; + +IPPArithmInitializer ippArithmInitializer; +#endif + +struct NOP {}; + +template +void vBinOp8(const T* src1, size_t step1, const T* src2, size_t step2, T* dst, size_t step, Size sz) +{ +#if CV_SSE2 + Op8 op8; +#endif + Op op; + + for( ; sz.height--; src1 += step1/sizeof(src1[0]), + src2 += step2/sizeof(src2[0]), + dst += step/sizeof(dst[0]) ) + { + int x = 0; + + #if CV_SSE2 + if( USE_SSE2 ) + { + for( ; x <= sz.width - 32; x += 32 ) + { + __m128i r0 = _mm_loadu_si128((const __m128i*)(src1 + x)); + __m128i r1 = _mm_loadu_si128((const __m128i*)(src1 + x + 16)); + r0 = op8(r0,_mm_loadu_si128((const __m128i*)(src2 + x))); + r1 = op8(r1,_mm_loadu_si128((const __m128i*)(src2 + x + 16))); + _mm_storeu_si128((__m128i*)(dst + x), r0); + _mm_storeu_si128((__m128i*)(dst + x + 16), r1); + } + for( ; x <= sz.width - 8; x += 8 ) + { + __m128i r0 = _mm_loadl_epi64((const __m128i*)(src1 + x)); + r0 = op8(r0,_mm_loadl_epi64((const __m128i*)(src2 + x))); + _mm_storel_epi64((__m128i*)(dst + x), r0); + } + } + #endif +#if CV_ENABLE_UNROLLED + for( ; x <= sz.width - 4; x += 4 ) + { + T v0 = op(src1[x], src2[x]); + T v1 = op(src1[x+1], src2[x+1]); + dst[x] = v0; dst[x+1] = v1; + v0 = op(src1[x+2], src2[x+2]); + v1 = op(src1[x+3], src2[x+3]); + dst[x+2] = v0; dst[x+3] = v1; + } +#endif + for( ; x < sz.width; x++ ) + dst[x] = op(src1[x], src2[x]); + } +} + +template +void vBinOp16(const T* src1, size_t step1, const T* src2, size_t step2, + T* dst, size_t step, Size sz) +{ +#if CV_SSE2 + Op16 op16; +#endif + Op op; + + for( ; sz.height--; src1 += step1/sizeof(src1[0]), + src2 += step2/sizeof(src2[0]), + dst += step/sizeof(dst[0]) ) + { + int x = 0; + + #if CV_SSE2 + if( USE_SSE2 ) + { + for( ; x <= sz.width - 16; x += 16 ) + { + __m128i r0 = _mm_loadu_si128((const __m128i*)(src1 + x)); + __m128i r1 = _mm_loadu_si128((const __m128i*)(src1 + x + 8)); + r0 = op16(r0,_mm_loadu_si128((const __m128i*)(src2 + x))); + r1 = op16(r1,_mm_loadu_si128((const __m128i*)(src2 + x + 8))); + _mm_storeu_si128((__m128i*)(dst + x), r0); + _mm_storeu_si128((__m128i*)(dst + x + 8), r1); + } + for( ; x <= sz.width - 4; x += 4 ) + { + __m128i r0 = _mm_loadl_epi64((const __m128i*)(src1 + x)); + r0 = op16(r0,_mm_loadl_epi64((const __m128i*)(src2 + x))); + _mm_storel_epi64((__m128i*)(dst + x), r0); + } + } + else + #endif + + for( ; x <= sz.width - 4; x += 4 ) + { + T v0 = op(src1[x], src2[x]); + T v1 = op(src1[x+1], src2[x+1]); + dst[x] = v0; dst[x+1] = v1; + v0 = op(src1[x+2], src2[x+2]); + v1 = op(src1[x+3], src2[x+3]); + dst[x+2] = v0; dst[x+3] = v1; + } + + for( ; x < sz.width; x++ ) + dst[x] = op(src1[x], src2[x]); + } +} + + +template +void vBinOp32s(const int* src1, size_t step1, const int* src2, size_t step2, + int* dst, size_t step, Size sz) +{ +#if CV_SSE2 + Op32 op32; +#endif + Op op; + + for( ; sz.height--; src1 += step1/sizeof(src1[0]), + src2 += step2/sizeof(src2[0]), + dst += step/sizeof(dst[0]) ) + { + int x = 0; + +#if CV_SSE2 + if( USE_SSE2 ) + { + if( (((size_t)src1|(size_t)src2|(size_t)dst)&15) == 0 ) + for( ; x <= sz.width - 8; x += 8 ) + { + __m128i r0 = _mm_load_si128((const __m128i*)(src1 + x)); + __m128i r1 = _mm_load_si128((const __m128i*)(src1 + x + 4)); + r0 = op32(r0,_mm_load_si128((const __m128i*)(src2 + x))); + r1 = op32(r1,_mm_load_si128((const __m128i*)(src2 + x + 4))); + _mm_store_si128((__m128i*)(dst + x), r0); + _mm_store_si128((__m128i*)(dst + x + 4), r1); + } + else + for( ; x <= sz.width - 8; x += 8 ) + { + __m128i r0 = _mm_loadu_si128((const __m128i*)(src1 + x)); + __m128i r1 = _mm_loadu_si128((const __m128i*)(src1 + x + 4)); + r0 = op32(r0,_mm_loadu_si128((const __m128i*)(src2 + x))); + r1 = op32(r1,_mm_loadu_si128((const __m128i*)(src2 + x + 4))); + _mm_storeu_si128((__m128i*)(dst + x), r0); + _mm_storeu_si128((__m128i*)(dst + x + 4), r1); + } + } +#endif +#if CV_ENABLE_UNROLLED + for( ; x <= sz.width - 4; x += 4 ) + { + int v0 = op(src1[x], src2[x]); + int v1 = op(src1[x+1], src2[x+1]); + dst[x] = v0; dst[x+1] = v1; + v0 = op(src1[x+2], src2[x+2]); + v1 = op(src1[x+3], src2[x+3]); + dst[x+2] = v0; dst[x+3] = v1; + } +#endif + for( ; x < sz.width; x++ ) + dst[x] = op(src1[x], src2[x]); + } +} + + +template +void vBinOp32f(const float* src1, size_t step1, const float* src2, size_t step2, + float* dst, size_t step, Size sz) +{ +#if CV_SSE2 + Op32 op32; +#endif + Op op; + + for( ; sz.height--; src1 += step1/sizeof(src1[0]), + src2 += step2/sizeof(src2[0]), + dst += step/sizeof(dst[0]) ) + { + int x = 0; + + #if CV_SSE2 + if( USE_SSE2 ) + { + if( (((size_t)src1|(size_t)src2|(size_t)dst)&15) == 0 ) + for( ; x <= sz.width - 8; x += 8 ) + { + __m128 r0 = _mm_load_ps(src1 + x); + __m128 r1 = _mm_load_ps(src1 + x + 4); + r0 = op32(r0,_mm_load_ps(src2 + x)); + r1 = op32(r1,_mm_load_ps(src2 + x + 4)); + _mm_store_ps(dst + x, r0); + _mm_store_ps(dst + x + 4, r1); + } + else + for( ; x <= sz.width - 8; x += 8 ) + { + __m128 r0 = _mm_loadu_ps(src1 + x); + __m128 r1 = _mm_loadu_ps(src1 + x + 4); + r0 = op32(r0,_mm_loadu_ps(src2 + x)); + r1 = op32(r1,_mm_loadu_ps(src2 + x + 4)); + _mm_storeu_ps(dst + x, r0); + _mm_storeu_ps(dst + x + 4, r1); + } + } + #endif +#if CV_ENABLE_UNROLLED + for( ; x <= sz.width - 4; x += 4 ) + { + float v0 = op(src1[x], src2[x]); + float v1 = op(src1[x+1], src2[x+1]); + dst[x] = v0; dst[x+1] = v1; + v0 = op(src1[x+2], src2[x+2]); + v1 = op(src1[x+3], src2[x+3]); + dst[x+2] = v0; dst[x+3] = v1; + } +#endif + for( ; x < sz.width; x++ ) + dst[x] = op(src1[x], src2[x]); + } +} + +template +void vBinOp64f(const double* src1, size_t step1, const double* src2, size_t step2, + double* dst, size_t step, Size sz) +{ +#if CV_SSE2 + Op64 op64; +#endif + Op op; + + for( ; sz.height--; src1 += step1/sizeof(src1[0]), + src2 += step2/sizeof(src2[0]), + dst += step/sizeof(dst[0]) ) + { + int x = 0; + + #if CV_SSE2 + if( USE_SSE2 && (((size_t)src1|(size_t)src2|(size_t)dst)&15) == 0 ) + for( ; x <= sz.width - 4; x += 4 ) + { + __m128d r0 = _mm_load_pd(src1 + x); + __m128d r1 = _mm_load_pd(src1 + x + 2); + r0 = op64(r0,_mm_load_pd(src2 + x)); + r1 = op64(r1,_mm_load_pd(src2 + x + 2)); + _mm_store_pd(dst + x, r0); + _mm_store_pd(dst + x + 2, r1); + } + else + #endif + for( ; x <= sz.width - 4; x += 4 ) + { + double v0 = op(src1[x], src2[x]); + double v1 = op(src1[x+1], src2[x+1]); + dst[x] = v0; dst[x+1] = v1; + v0 = op(src1[x+2], src2[x+2]); + v1 = op(src1[x+3], src2[x+3]); + dst[x+2] = v0; dst[x+3] = v1; + } + + for( ; x < sz.width; x++ ) + dst[x] = op(src1[x], src2[x]); + } +} + +#if CV_SSE2 + +struct _VAdd8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_adds_epu8(a,b); }}; +struct _VSub8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_subs_epu8(a,b); }}; +struct _VMin8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_min_epu8(a,b); }}; +struct _VMax8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_max_epu8(a,b); }}; +struct _VAbsDiff8u +{ + __m128i operator()(const __m128i& a, const __m128i& b) const + { return _mm_add_epi8(_mm_subs_epu8(a,b),_mm_subs_epu8(b,a)); } +}; + +struct _VAdd8s { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_adds_epi8(a,b); }}; +struct _VSub8s { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_subs_epi8(a,b); }}; +struct _VMin8s +{ + __m128i operator()(const __m128i& a, const __m128i& b) const + { + __m128i m = _mm_cmpgt_epi8(a, b); + return _mm_xor_si128(a, _mm_and_si128(_mm_xor_si128(a, b), m)); + } +}; +struct _VMax8s +{ + __m128i operator()(const __m128i& a, const __m128i& b) const + { + __m128i m = _mm_cmpgt_epi8(b, a); + return _mm_xor_si128(a, _mm_and_si128(_mm_xor_si128(a, b), m)); + } +}; +struct _VAbsDiff8s +{ + __m128i operator()(const __m128i& a, const __m128i& b) const + { + __m128i d = _mm_subs_epi8(a, b); + __m128i m = _mm_cmpgt_epi8(b, a); + return _mm_subs_epi8(_mm_xor_si128(d, m), m); + } +}; + +struct _VAdd16u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_adds_epu16(a,b); }}; +struct _VSub16u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_subs_epu16(a,b); }}; +struct _VMin16u +{ + __m128i operator()(const __m128i& a, const __m128i& b) const + { return _mm_subs_epu16(a,_mm_subs_epu16(a,b)); } +}; +struct _VMax16u +{ + __m128i operator()(const __m128i& a, const __m128i& b) const + { return _mm_adds_epu16(_mm_subs_epu16(a,b),b); } +}; +struct _VAbsDiff16u +{ + __m128i operator()(const __m128i& a, const __m128i& b) const + { return _mm_add_epi16(_mm_subs_epu16(a,b),_mm_subs_epu16(b,a)); } +}; + +struct _VAdd16s { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_adds_epi16(a,b); }}; +struct _VSub16s { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_subs_epi16(a,b); }}; +struct _VMin16s { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_min_epi16(a,b); }}; +struct _VMax16s { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_max_epi16(a,b); }}; +struct _VAbsDiff16s +{ + __m128i operator()(const __m128i& a, const __m128i& b) const + { + __m128i M = _mm_max_epi16(a,b), m = _mm_min_epi16(a,b); + return _mm_subs_epi16(M, m); + } +}; + +struct _VAdd32s { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_add_epi32(a,b); }}; +struct _VSub32s { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_sub_epi32(a,b); }}; +struct _VMin32s +{ + __m128i operator()(const __m128i& a, const __m128i& b) const + { + __m128i m = _mm_cmpgt_epi32(a, b); + return _mm_xor_si128(a, _mm_and_si128(_mm_xor_si128(a, b), m)); + } +}; +struct _VMax32s +{ + __m128i operator()(const __m128i& a, const __m128i& b) const + { + __m128i m = _mm_cmpgt_epi32(b, a); + return _mm_xor_si128(a, _mm_and_si128(_mm_xor_si128(a, b), m)); + } +}; +struct _VAbsDiff32s +{ + __m128i operator()(const __m128i& a, const __m128i& b) const + { + __m128i d = _mm_sub_epi32(a, b); + __m128i m = _mm_cmpgt_epi32(b, a); + return _mm_sub_epi32(_mm_xor_si128(d, m), m); + } +}; + +struct _VAdd32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_add_ps(a,b); }}; +struct _VSub32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_sub_ps(a,b); }}; +struct _VMin32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_min_ps(a,b); }}; +struct _VMax32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_max_ps(a,b); }}; +static int CV_DECL_ALIGNED(16) v32f_absmask[] = { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff }; +struct _VAbsDiff32f +{ + __m128 operator()(const __m128& a, const __m128& b) const + { + return _mm_and_ps(_mm_sub_ps(a,b), *(const __m128*)v32f_absmask); + } +}; + +struct _VAdd64f { __m128d operator()(const __m128d& a, const __m128d& b) const { return _mm_add_pd(a,b); }}; +struct _VSub64f { __m128d operator()(const __m128d& a, const __m128d& b) const { return _mm_sub_pd(a,b); }}; +struct _VMin64f { __m128d operator()(const __m128d& a, const __m128d& b) const { return _mm_min_pd(a,b); }}; +struct _VMax64f { __m128d operator()(const __m128d& a, const __m128d& b) const { return _mm_max_pd(a,b); }}; + +static int CV_DECL_ALIGNED(16) v64f_absmask[] = { 0xffffffff, 0x7fffffff, 0xffffffff, 0x7fffffff }; +struct _VAbsDiff64f +{ + __m128d operator()(const __m128d& a, const __m128d& b) const + { + return _mm_and_pd(_mm_sub_pd(a,b), *(const __m128d*)v64f_absmask); + } +}; + +struct _VAnd8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_and_si128(a,b); }}; +struct _VOr8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_or_si128(a,b); }}; +struct _VXor8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_xor_si128(a,b); }}; +struct _VNot8u { __m128i operator()(const __m128i& a, const __m128i&) const { return _mm_xor_si128(_mm_set1_epi32(-1),a); }}; + +#endif + +#if CV_SSE2 +#define IF_SIMD(op) op +#else +#define IF_SIMD(op) NOP +#endif + +template<> inline uchar OpAdd::operator ()(uchar a, uchar b) const +{ return CV_FAST_CAST_8U(a + b); } +template<> inline uchar OpSub::operator ()(uchar a, uchar b) const +{ return CV_FAST_CAST_8U(a - b); } + +template struct OpAbsDiff +{ + typedef T type1; + typedef T type2; + typedef T rtype; + T operator()(T a, T b) const { return (T)std::abs(a - b); } +}; + +template<> inline short OpAbsDiff::operator ()(short a, short b) const +{ return saturate_cast(std::abs(a - b)); } + +template<> inline schar OpAbsDiff::operator ()(schar a, schar b) const +{ return saturate_cast(std::abs(a - b)); } + +template struct OpAbsDiffS +{ + typedef T type1; + typedef WT type2; + typedef T rtype; + T operator()(T a, WT b) const { return saturate_cast(std::abs(a - b)); } +}; + +template struct OpAnd +{ + typedef T type1; + typedef T type2; + typedef T rtype; + T operator()( T a, T b ) const { return a & b; } +}; + +template struct OpOr +{ + typedef T type1; + typedef T type2; + typedef T rtype; + T operator()( T a, T b ) const { return a | b; } +}; + +template struct OpXor +{ + typedef T type1; + typedef T type2; + typedef T rtype; + T operator()( T a, T b ) const { return a ^ b; } +}; + +template struct OpNot +{ + typedef T type1; + typedef T type2; + typedef T rtype; + T operator()( T a, T ) const { return ~a; } +}; + +static inline void fixSteps(Size sz, size_t elemSize, size_t& step1, size_t& step2, size_t& step) +{ + if( sz.height == 1 ) + step1 = step2 = step = sz.width*elemSize; +} + +static void add8u( const uchar* src1, size_t step1, + const uchar* src2, size_t step2, + uchar* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiAdd_8u_C1RSfs(src1, (int)step1, src2, (int)step2, dst, (int)step, (IppiSize&)sz, 0), + (vBinOp8, IF_SIMD(_VAdd8u)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void add8s( const schar* src1, size_t step1, + const schar* src2, size_t step2, + schar* dst, size_t step, Size sz, void* ) +{ + vBinOp8, IF_SIMD(_VAdd8s)>(src1, step1, src2, step2, dst, step, sz); +} + +static void add16u( const ushort* src1, size_t step1, + const ushort* src2, size_t step2, + ushort* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiAdd_16u_C1RSfs(src1, (int)step1, src2, (int)step2, dst, (int)step, (IppiSize&)sz, 0), + (vBinOp16, IF_SIMD(_VAdd16u)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void add16s( const short* src1, size_t step1, + const short* src2, size_t step2, + short* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiAdd_16s_C1RSfs(src1, (int)step1, src2, (int)step2, dst, (int)step, (IppiSize&)sz, 0), + (vBinOp16, IF_SIMD(_VAdd16s)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void add32s( const int* src1, size_t step1, + const int* src2, size_t step2, + int* dst, size_t step, Size sz, void* ) +{ + vBinOp32s, IF_SIMD(_VAdd32s)>(src1, step1, src2, step2, dst, step, sz); +} + +static void add32f( const float* src1, size_t step1, + const float* src2, size_t step2, + float* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiAdd_32f_C1R(src1, (int)step1, src2, (int)step2, dst, (int)step, (IppiSize&)sz), + (vBinOp32f, IF_SIMD(_VAdd32f)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void add64f( const double* src1, size_t step1, + const double* src2, size_t step2, + double* dst, size_t step, Size sz, void* ) +{ + vBinOp64f, IF_SIMD(_VAdd64f)>(src1, step1, src2, step2, dst, step, sz); +} + +static void sub8u( const uchar* src1, size_t step1, + const uchar* src2, size_t step2, + uchar* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiSub_8u_C1RSfs(src2, (int)step2, src1, (int)step1, dst, (int)step, (IppiSize&)sz, 0), + (vBinOp8, IF_SIMD(_VSub8u)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void sub8s( const schar* src1, size_t step1, + const schar* src2, size_t step2, + schar* dst, size_t step, Size sz, void* ) +{ + vBinOp8, IF_SIMD(_VSub8s)>(src1, step1, src2, step2, dst, step, sz); +} + +static void sub16u( const ushort* src1, size_t step1, + const ushort* src2, size_t step2, + ushort* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiSub_16u_C1RSfs(src2, (int)step2, src1, (int)step1, dst, (int)step, (IppiSize&)sz, 0), + (vBinOp16, IF_SIMD(_VSub16u)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void sub16s( const short* src1, size_t step1, + const short* src2, size_t step2, + short* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiSub_16s_C1RSfs(src2, (int)step2, src1, (int)step1, dst, (int)step, (IppiSize&)sz, 0), + (vBinOp16, IF_SIMD(_VSub16s)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void sub32s( const int* src1, size_t step1, + const int* src2, size_t step2, + int* dst, size_t step, Size sz, void* ) +{ + vBinOp32s, IF_SIMD(_VSub32s)>(src1, step1, src2, step2, dst, step, sz); +} + +static void sub32f( const float* src1, size_t step1, + const float* src2, size_t step2, + float* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiSub_32f_C1R(src2, (int)step2, src1, (int)step1, dst, (int)step, (IppiSize&)sz), + (vBinOp32f, IF_SIMD(_VSub32f)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void sub64f( const double* src1, size_t step1, + const double* src2, size_t step2, + double* dst, size_t step, Size sz, void* ) +{ + vBinOp64f, IF_SIMD(_VSub64f)>(src1, step1, src2, step2, dst, step, sz); +} + +template<> inline uchar OpMin::operator ()(uchar a, uchar b) const { return CV_MIN_8U(a, b); } +template<> inline uchar OpMax::operator ()(uchar a, uchar b) const { return CV_MAX_8U(a, b); } + +static void max8u( const uchar* src1, size_t step1, + const uchar* src2, size_t step2, + uchar* dst, size_t step, Size sz, void* ) +{ +#if (ARITHM_USE_IPP == 1) + { + uchar* s1 = (uchar*)src1; + uchar* s2 = (uchar*)src2; + uchar* d = dst; + fixSteps(sz, sizeof(dst[0]), step1, step2, step); + for(int i = 0; i < sz.height; i++) + { + ippsMaxEvery_8u(s1, s2, d, sz.width); + s1 += step1; + s2 += step2; + d += step; + } + } +#else + vBinOp8, IF_SIMD(_VMax8u)>(src1, step1, src2, step2, dst, step, sz); +#endif + +// IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); +// ippiMaxEvery_8u_C1R(src1, (int)step1, src2, (int)step2, dst, (IppiSize&)sz), +// (vBinOp8, IF_SIMD(_VMax8u)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void max8s( const schar* src1, size_t step1, + const schar* src2, size_t step2, + schar* dst, size_t step, Size sz, void* ) +{ + vBinOp8, IF_SIMD(_VMax8s)>(src1, step1, src2, step2, dst, step, sz); +} + +static void max16u( const ushort* src1, size_t step1, + const ushort* src2, size_t step2, + ushort* dst, size_t step, Size sz, void* ) +{ +#if (ARITHM_USE_IPP == 1) + { + ushort* s1 = (ushort*)src1; + ushort* s2 = (ushort*)src2; + ushort* d = dst; + fixSteps(sz, sizeof(dst[0]), step1, step2, step); + for(int i = 0; i < sz.height; i++) + { + ippsMaxEvery_16u(s1, s2, d, sz.width); + s1 = (ushort*)((uchar*)s1 + step1); + s2 = (ushort*)((uchar*)s2 + step2); + d = (ushort*)((uchar*)d + step); + } + } +#else + vBinOp16, IF_SIMD(_VMax16u)>(src1, step1, src2, step2, dst, step, sz); +#endif + +// IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); +// ippiMaxEvery_16u_C1R(src1, (int)step1, src2, (int)step2, dst, (IppiSize&)sz), +// (vBinOp16, IF_SIMD(_VMax16u)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void max16s( const short* src1, size_t step1, + const short* src2, size_t step2, + short* dst, size_t step, Size sz, void* ) +{ + vBinOp16, IF_SIMD(_VMax16s)>(src1, step1, src2, step2, dst, step, sz); +} + +static void max32s( const int* src1, size_t step1, + const int* src2, size_t step2, + int* dst, size_t step, Size sz, void* ) +{ + vBinOp32s, IF_SIMD(_VMax32s)>(src1, step1, src2, step2, dst, step, sz); +} + +static void max32f( const float* src1, size_t step1, + const float* src2, size_t step2, + float* dst, size_t step, Size sz, void* ) +{ +#if (ARITHM_USE_IPP == 1) + { + float* s1 = (float*)src1; + float* s2 = (float*)src2; + float* d = dst; + fixSteps(sz, sizeof(dst[0]), step1, step2, step); + for(int i = 0; i < sz.height; i++) + { + ippsMaxEvery_32f(s1, s2, d, sz.width); + s1 = (float*)((uchar*)s1 + step1); + s2 = (float*)((uchar*)s2 + step2); + d = (float*)((uchar*)d + step); + } + } +#else + vBinOp32f, IF_SIMD(_VMax32f)>(src1, step1, src2, step2, dst, step, sz); +#endif +// IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); +// ippiMaxEvery_32f_C1R(src1, (int)step1, src2, (int)step2, dst, (IppiSize&)sz), +// (vBinOp32f, IF_SIMD(_VMax32f)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void max64f( const double* src1, size_t step1, + const double* src2, size_t step2, + double* dst, size_t step, Size sz, void* ) +{ + vBinOp64f, IF_SIMD(_VMax64f)>(src1, step1, src2, step2, dst, step, sz); +} + +static void min8u( const uchar* src1, size_t step1, + const uchar* src2, size_t step2, + uchar* dst, size_t step, Size sz, void* ) +{ +#if (ARITHM_USE_IPP == 1) + { + uchar* s1 = (uchar*)src1; + uchar* s2 = (uchar*)src2; + uchar* d = dst; + fixSteps(sz, sizeof(dst[0]), step1, step2, step); + for(int i = 0; i < sz.height; i++) + { + ippsMinEvery_8u(s1, s2, d, sz.width); + s1 += step1; + s2 += step2; + d += step; + } + } +#else + vBinOp8, IF_SIMD(_VMin8u)>(src1, step1, src2, step2, dst, step, sz); +#endif + +// IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); +// ippiMinEvery_8u_C1R(src1, (int)step1, src2, (int)step2, dst, (IppiSize&)sz), +// (vBinOp8, IF_SIMD(_VMin8u)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void min8s( const schar* src1, size_t step1, + const schar* src2, size_t step2, + schar* dst, size_t step, Size sz, void* ) +{ + vBinOp8, IF_SIMD(_VMin8s)>(src1, step1, src2, step2, dst, step, sz); +} + +static void min16u( const ushort* src1, size_t step1, + const ushort* src2, size_t step2, + ushort* dst, size_t step, Size sz, void* ) +{ +#if (ARITHM_USE_IPP == 1) + { + ushort* s1 = (ushort*)src1; + ushort* s2 = (ushort*)src2; + ushort* d = dst; + fixSteps(sz, sizeof(dst[0]), step1, step2, step); + for(int i = 0; i < sz.height; i++) + { + ippsMinEvery_16u(s1, s2, d, sz.width); + s1 = (ushort*)((uchar*)s1 + step1); + s2 = (ushort*)((uchar*)s2 + step2); + d = (ushort*)((uchar*)d + step); + } + } +#else + vBinOp16, IF_SIMD(_VMin16u)>(src1, step1, src2, step2, dst, step, sz); +#endif + +// IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); +// ippiMinEvery_16u_C1R(src1, (int)step1, src2, (int)step2, dst, (IppiSize&)sz), +// (vBinOp16, IF_SIMD(_VMin16u)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void min16s( const short* src1, size_t step1, + const short* src2, size_t step2, + short* dst, size_t step, Size sz, void* ) +{ + vBinOp16, IF_SIMD(_VMin16s)>(src1, step1, src2, step2, dst, step, sz); +} + +static void min32s( const int* src1, size_t step1, + const int* src2, size_t step2, + int* dst, size_t step, Size sz, void* ) +{ + vBinOp32s, IF_SIMD(_VMin32s)>(src1, step1, src2, step2, dst, step, sz); +} + +static void min32f( const float* src1, size_t step1, + const float* src2, size_t step2, + float* dst, size_t step, Size sz, void* ) +{ +#if (ARITHM_USE_IPP == 1) + { + float* s1 = (float*)src1; + float* s2 = (float*)src2; + float* d = dst; + fixSteps(sz, sizeof(dst[0]), step1, step2, step); + for(int i = 0; i < sz.height; i++) + { + ippsMinEvery_32f(s1, s2, d, sz.width); + s1 = (float*)((uchar*)s1 + step1); + s2 = (float*)((uchar*)s2 + step2); + d = (float*)((uchar*)d + step); + } + } +#else + vBinOp32f, IF_SIMD(_VMin32f)>(src1, step1, src2, step2, dst, step, sz); +#endif +// IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); +// ippiMinEvery_32f_C1R(src1, (int)step1, src2, (int)step2, dst, (IppiSize&)sz), +// (vBinOp32f, IF_SIMD(_VMin32f)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void min64f( const double* src1, size_t step1, + const double* src2, size_t step2, + double* dst, size_t step, Size sz, void* ) +{ + vBinOp64f, IF_SIMD(_VMin64f)>(src1, step1, src2, step2, dst, step, sz); +} + +static void absdiff8u( const uchar* src1, size_t step1, + const uchar* src2, size_t step2, + uchar* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiAbsDiff_8u_C1R(src1, (int)step1, src2, (int)step2, dst, (int)step, (IppiSize&)sz), + (vBinOp8, IF_SIMD(_VAbsDiff8u)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void absdiff8s( const schar* src1, size_t step1, + const schar* src2, size_t step2, + schar* dst, size_t step, Size sz, void* ) +{ + vBinOp8, IF_SIMD(_VAbsDiff8s)>(src1, step1, src2, step2, dst, step, sz); +} + +static void absdiff16u( const ushort* src1, size_t step1, + const ushort* src2, size_t step2, + ushort* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiAbsDiff_16u_C1R(src1, (int)step1, src2, (int)step2, dst, (int)step, (IppiSize&)sz), + (vBinOp16, IF_SIMD(_VAbsDiff16u)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void absdiff16s( const short* src1, size_t step1, + const short* src2, size_t step2, + short* dst, size_t step, Size sz, void* ) +{ + vBinOp16, IF_SIMD(_VAbsDiff16s)>(src1, step1, src2, step2, dst, step, sz); +} + +static void absdiff32s( const int* src1, size_t step1, + const int* src2, size_t step2, + int* dst, size_t step, Size sz, void* ) +{ + vBinOp32s, IF_SIMD(_VAbsDiff32s)>(src1, step1, src2, step2, dst, step, sz); +} + +static void absdiff32f( const float* src1, size_t step1, + const float* src2, size_t step2, + float* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiAbsDiff_32f_C1R(src1, (int)step1, src2, (int)step2, dst, (int)step, (IppiSize&)sz), + (vBinOp32f, IF_SIMD(_VAbsDiff32f)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void absdiff64f( const double* src1, size_t step1, + const double* src2, size_t step2, + double* dst, size_t step, Size sz, void* ) +{ + vBinOp64f, IF_SIMD(_VAbsDiff64f)>(src1, step1, src2, step2, dst, step, sz); +} + + +static void and8u( const uchar* src1, size_t step1, + const uchar* src2, size_t step2, + uchar* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiAnd_8u_C1R(src1, (int)step1, src2, (int)step2, dst, (int)step, (IppiSize&)sz), + (vBinOp8, IF_SIMD(_VAnd8u)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void or8u( const uchar* src1, size_t step1, + const uchar* src2, size_t step2, + uchar* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiOr_8u_C1R(src1, (int)step1, src2, (int)step2, dst, (int)step, (IppiSize&)sz), + (vBinOp8, IF_SIMD(_VOr8u)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void xor8u( const uchar* src1, size_t step1, + const uchar* src2, size_t step2, + uchar* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiXor_8u_C1R(src1, (int)step1, src2, (int)step2, dst, (int)step, (IppiSize&)sz), + (vBinOp8, IF_SIMD(_VXor8u)>(src1, step1, src2, step2, dst, step, sz))); +} + +static void not8u( const uchar* src1, size_t step1, + const uchar* src2, size_t step2, + uchar* dst, size_t step, Size sz, void* ) +{ + IF_IPP(fixSteps(sz, sizeof(dst[0]), step1, step2, step); + ippiNot_8u_C1R(src1, (int)step1, dst, (int)step, (IppiSize&)sz), + (vBinOp8, IF_SIMD(_VNot8u)>(src1, step1, src2, step2, dst, step, sz))); +} + +/****************************************************************************************\ +* logical operations * +\****************************************************************************************/ + +void convertAndUnrollScalar( const Mat& sc, int buftype, uchar* scbuf, size_t blocksize ) +{ + int scn = (int)sc.total(), cn = CV_MAT_CN(buftype); + size_t esz = CV_ELEM_SIZE(buftype); + getConvertFunc(sc.depth(), buftype)(sc.data, 0, 0, 0, scbuf, 0, Size(std::min(cn, scn), 1), 0); + // unroll the scalar + if( scn < cn ) + { + CV_Assert( scn == 1 ); + size_t esz1 = CV_ELEM_SIZE1(buftype); + for( size_t i = esz1; i < esz; i++ ) + scbuf[i] = scbuf[i - esz1]; + } + for( size_t i = esz; i < blocksize*esz; i++ ) + scbuf[i] = scbuf[i - esz]; +} + +static void binary_op(InputArray _src1, InputArray _src2, OutputArray _dst, + InputArray _mask, const BinaryFunc* tab, bool bitwise) +{ + int kind1 = _src1.kind(), kind2 = _src2.kind(); + Mat src1 = _src1.getMat(), src2 = _src2.getMat(); + bool haveMask = !_mask.empty(), haveScalar = false; + BinaryFunc func; + int c; + + if( src1.dims <= 2 && src2.dims <= 2 && kind1 == kind2 && + src1.size() == src2.size() && src1.type() == src2.type() && !haveMask ) + { + _dst.create(src1.size(), src1.type()); + Mat dst = _dst.getMat(); + if( bitwise ) + { + func = *tab; + c = (int)src1.elemSize(); + } + else + { + func = tab[src1.depth()]; + c = src1.channels(); + } + + Size sz = getContinuousSize(src1, src2, dst); + size_t len = sz.width*(size_t)c; + if( len == (size_t)(int)len ) + { + sz.width = (int)len; + func(src1.data, src1.step, src2.data, src2.step, dst.data, dst.step, sz, 0); + return; + } + } + + if( (kind1 == _InputArray::MATX) + (kind2 == _InputArray::MATX) == 1 || + src1.size != src2.size || src1.type() != src2.type() ) + { + if( checkScalar(src1, src2.type(), kind1, kind2) ) + // src1 is a scalar; swap it with src2 + swap(src1, src2); + else if( !checkScalar(src2, src1.type(), kind2, kind1) ) + CV_Error( CV_StsUnmatchedSizes, + "The operation is neither 'array op array' (where arrays have the same size and type), " + "nor 'array op scalar', nor 'scalar op array'" ); + haveScalar = true; + } + + size_t esz = src1.elemSize(); + size_t blocksize0 = (BLOCK_SIZE + esz-1)/esz; + int cn = src1.channels(); + BinaryFunc copymask = 0; + Mat mask; + bool reallocate = false; + + if( haveMask ) + { + mask = _mask.getMat(); + CV_Assert( (mask.type() == CV_8UC1 || mask.type() == CV_8SC1) ); + CV_Assert( mask.size == src1.size ); + copymask = getCopyMaskFunc(esz); + Mat tdst = _dst.getMat(); + reallocate = tdst.size != src1.size || tdst.type() != src1.type(); + } + + AutoBuffer _buf; + uchar *scbuf = 0, *maskbuf = 0; + + _dst.create(src1.dims, src1.size, src1.type()); + Mat dst = _dst.getMat(); + + // if this is mask operation and dst has been reallocated, + // we have to + if( haveMask && reallocate ) + dst = Scalar::all(0); + + if( bitwise ) + { + func = *tab; + c = (int)esz; + } + else + { + func = tab[src1.depth()]; + c = cn; + } + + if( !haveScalar ) + { + const Mat* arrays[] = { &src1, &src2, &dst, &mask, 0 }; + uchar* ptrs[4]; + + NAryMatIterator it(arrays, ptrs); + size_t total = it.size, blocksize = total; + + if( blocksize*c > INT_MAX ) + blocksize = INT_MAX/c; + + if( haveMask ) + { + blocksize = std::min(blocksize, blocksize0); + _buf.allocate(blocksize*esz); + maskbuf = _buf; + } + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( size_t j = 0; j < total; j += blocksize ) + { + int bsz = (int)MIN(total - j, blocksize); + + func( ptrs[0], 0, ptrs[1], 0, haveMask ? maskbuf : ptrs[2], 0, Size(bsz*c, 1), 0 ); + if( haveMask ) + { + copymask( maskbuf, 0, ptrs[3], 0, ptrs[2], 0, Size(bsz, 1), &esz ); + ptrs[3] += bsz; + } + + bsz *= (int)esz; + ptrs[0] += bsz; ptrs[1] += bsz; ptrs[2] += bsz; + } + } + } + else + { + const Mat* arrays[] = { &src1, &dst, &mask, 0 }; + uchar* ptrs[3]; + + NAryMatIterator it(arrays, ptrs); + size_t total = it.size, blocksize = std::min(total, blocksize0); + + _buf.allocate(blocksize*(haveMask ? 2 : 1)*esz + 32); + scbuf = _buf; + maskbuf = alignPtr(scbuf + blocksize*esz, 16); + + convertAndUnrollScalar( src2, src1.type(), scbuf, blocksize); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( size_t j = 0; j < total; j += blocksize ) + { + int bsz = (int)MIN(total - j, blocksize); + + func( ptrs[0], 0, scbuf, 0, haveMask ? maskbuf : ptrs[1], 0, Size(bsz*c, 1), 0 ); + if( haveMask ) + { + copymask( maskbuf, 0, ptrs[2], 0, ptrs[1], 0, Size(bsz, 1), &esz ); + ptrs[2] += bsz; + } + + bsz *= (int)esz; + ptrs[0] += bsz; ptrs[1] += bsz; + } + } + } +} + +static BinaryFunc maxTab[] = +{ + (BinaryFunc)GET_OPTIMIZED(max8u), (BinaryFunc)GET_OPTIMIZED(max8s), + (BinaryFunc)GET_OPTIMIZED(max16u), (BinaryFunc)GET_OPTIMIZED(max16s), + (BinaryFunc)GET_OPTIMIZED(max32s), + (BinaryFunc)GET_OPTIMIZED(max32f), (BinaryFunc)max64f, + 0 +}; + +static BinaryFunc minTab[] = +{ + (BinaryFunc)GET_OPTIMIZED(min8u), (BinaryFunc)GET_OPTIMIZED(min8s), + (BinaryFunc)GET_OPTIMIZED(min16u), (BinaryFunc)GET_OPTIMIZED(min16s), + (BinaryFunc)GET_OPTIMIZED(min32s), + (BinaryFunc)GET_OPTIMIZED(min32f), (BinaryFunc)min64f, + 0 +}; + +} + +void cv::bitwise_and(InputArray a, InputArray b, OutputArray c, InputArray mask) +{ + BinaryFunc f = (BinaryFunc)GET_OPTIMIZED(and8u); + binary_op(a, b, c, mask, &f, true); +} + +void cv::bitwise_or(InputArray a, InputArray b, OutputArray c, InputArray mask) +{ + BinaryFunc f = (BinaryFunc)GET_OPTIMIZED(or8u); + binary_op(a, b, c, mask, &f, true); +} + +void cv::bitwise_xor(InputArray a, InputArray b, OutputArray c, InputArray mask) +{ + BinaryFunc f = (BinaryFunc)GET_OPTIMIZED(xor8u); + binary_op(a, b, c, mask, &f, true); +} + +void cv::bitwise_not(InputArray a, OutputArray c, InputArray mask) +{ + BinaryFunc f = (BinaryFunc)GET_OPTIMIZED(not8u); + binary_op(a, a, c, mask, &f, true); +} + +void cv::max( InputArray src1, InputArray src2, OutputArray dst ) +{ + binary_op(src1, src2, dst, noArray(), maxTab, false ); +} + +void cv::min( InputArray src1, InputArray src2, OutputArray dst ) +{ + binary_op(src1, src2, dst, noArray(), minTab, false ); +} + +void cv::max(const Mat& src1, const Mat& src2, Mat& dst) +{ + OutputArray _dst(dst); + binary_op(src1, src2, _dst, noArray(), maxTab, false ); +} + +void cv::min(const Mat& src1, const Mat& src2, Mat& dst) +{ + OutputArray _dst(dst); + binary_op(src1, src2, _dst, noArray(), minTab, false ); +} + +void cv::max(const Mat& src1, double src2, Mat& dst) +{ + OutputArray _dst(dst); + binary_op(src1, src2, _dst, noArray(), maxTab, false ); +} + +void cv::min(const Mat& src1, double src2, Mat& dst) +{ + OutputArray _dst(dst); + binary_op(src1, src2, _dst, noArray(), minTab, false ); +} + +/****************************************************************************************\ +* add/subtract * +\****************************************************************************************/ + +namespace cv +{ + +static void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst, + InputArray _mask, int dtype, BinaryFunc* tab, bool muldiv=false, void* usrdata=0) +{ + int kind1 = _src1.kind(), kind2 = _src2.kind(); + Mat src1 = _src1.getMat(), src2 = _src2.getMat(); + bool haveMask = !_mask.empty(); + bool reallocate = false; + + if( kind1 == kind2 && src1.dims <= 2 && src2.dims <= 2 && + src1.size() == src2.size() && src1.type() == src2.type() && + !haveMask && ((!_dst.fixedType() && (dtype < 0 || CV_MAT_DEPTH(dtype) == src1.depth())) || + (_dst.fixedType() && _dst.type() == _src1.type())) ) + { + _dst.create(src1.size(), src1.type()); + Mat dst = _dst.getMat(); + Size sz = getContinuousSize(src1, src2, dst, src1.channels()); + tab[src1.depth()](src1.data, src1.step, src2.data, src2.step, dst.data, dst.step, sz, usrdata); + return; + } + + bool haveScalar = false, swapped12 = false; + + if( (kind1 == _InputArray::MATX) + (kind2 == _InputArray::MATX) == 1 || + src1.size != src2.size || src1.channels() != src2.channels() ) + { + if( checkScalar(src1, src2.type(), kind1, kind2) ) + { + // src1 is a scalar; swap it with src2 + swap(src1, src2); + swapped12 = true; + } + else if( !checkScalar(src2, src1.type(), kind2, kind1) ) + CV_Error( CV_StsUnmatchedSizes, + "The operation is neither 'array op array' (where arrays have the same size and the same number of channels), " + "nor 'array op scalar', nor 'scalar op array'" ); + haveScalar = true; + } + + int cn = src1.channels(), depth1 = src1.depth(), depth2 = src2.depth(), wtype; + BinaryFunc cvtsrc1 = 0, cvtsrc2 = 0, cvtdst = 0; + + if( dtype < 0 ) + { + if( _dst.fixedType() ) + dtype = _dst.type(); + else + { + if( !haveScalar && src1.type() != src2.type() ) + CV_Error(CV_StsBadArg, + "When the input arrays in add/subtract/multiply/divide functions have different types, " + "the output array type must be explicitly specified"); + dtype = src1.type(); + } + } + dtype = CV_MAT_DEPTH(dtype); + + if( depth1 == depth2 && dtype == depth1 ) + wtype = dtype; + else if( !muldiv ) + { + wtype = depth1 <= CV_8S && depth2 <= CV_8S ? CV_16S : + depth1 <= CV_32S && depth2 <= CV_32S ? CV_32S : std::max(depth1, depth2); + wtype = std::max(wtype, dtype); + + // when the result of addition should be converted to an integer type, + // and just one of the input arrays is floating-point, it makes sense to convert that input to integer type before the operation, + // instead of converting the other input to floating-point and then converting the operation result back to integers. + if( dtype < CV_32F && (depth1 < CV_32F || depth2 < CV_32F) ) + wtype = CV_32S; + } + else + { + wtype = std::max(depth1, std::max(depth2, CV_32F)); + wtype = std::max(wtype, dtype); + } + + cvtsrc1 = depth1 == wtype ? 0 : getConvertFunc(depth1, wtype); + cvtsrc2 = depth2 == depth1 ? cvtsrc1 : depth2 == wtype ? 0 : getConvertFunc(depth2, wtype); + cvtdst = dtype == wtype ? 0 : getConvertFunc(wtype, dtype); + + dtype = CV_MAKETYPE(dtype, cn); + wtype = CV_MAKETYPE(wtype, cn); + + size_t esz1 = src1.elemSize(), esz2 = src2.elemSize(); + size_t dsz = CV_ELEM_SIZE(dtype), wsz = CV_ELEM_SIZE(wtype); + size_t blocksize0 = (size_t)(BLOCK_SIZE + wsz-1)/wsz; + BinaryFunc copymask = 0; + Mat mask; + + if( haveMask ) + { + mask = _mask.getMat(); + CV_Assert( (mask.type() == CV_8UC1 || mask.type() == CV_8SC1) ); + CV_Assert( mask.size == src1.size ); + copymask = getCopyMaskFunc(dsz); + Mat tdst = _dst.getMat(); + reallocate = tdst.size != src1.size || tdst.type() != dtype; + } + + AutoBuffer _buf; + uchar *buf, *maskbuf = 0, *buf1 = 0, *buf2 = 0, *wbuf = 0; + size_t bufesz = (cvtsrc1 ? wsz : 0) + (cvtsrc2 || haveScalar ? wsz : 0) + (cvtdst ? wsz : 0) + (haveMask ? dsz : 0); + + _dst.create(src1.dims, src1.size, dtype); + Mat dst = _dst.getMat(); + + if( haveMask && reallocate ) + dst = Scalar::all(0); + + BinaryFunc func = tab[CV_MAT_DEPTH(wtype)]; + + if( !haveScalar ) + { + const Mat* arrays[] = { &src1, &src2, &dst, &mask, 0 }; + uchar* ptrs[4]; + + NAryMatIterator it(arrays, ptrs); + size_t total = it.size, blocksize = total; + + if( haveMask || cvtsrc1 || cvtsrc2 || cvtdst ) + blocksize = std::min(blocksize, blocksize0); + + _buf.allocate(bufesz*blocksize + 64); + buf = _buf; + if( cvtsrc1 ) + buf1 = buf, buf = alignPtr(buf + blocksize*wsz, 16); + if( cvtsrc2 ) + buf2 = buf, buf = alignPtr(buf + blocksize*wsz, 16); + wbuf = maskbuf = buf; + if( cvtdst ) + buf = alignPtr(buf + blocksize*wsz, 16); + if( haveMask ) + maskbuf = buf; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( size_t j = 0; j < total; j += blocksize ) + { + int bsz = (int)MIN(total - j, blocksize); + Size bszn(bsz*cn, 1); + const uchar *sptr1 = ptrs[0], *sptr2 = ptrs[1]; + uchar* dptr = ptrs[2]; + if( cvtsrc1 ) + { + cvtsrc1( sptr1, 0, 0, 0, buf1, 0, bszn, 0 ); + sptr1 = buf1; + } + if( ptrs[0] == ptrs[1] ) + sptr2 = sptr1; + else if( cvtsrc2 ) + { + cvtsrc2( sptr2, 0, 0, 0, buf2, 0, bszn, 0 ); + sptr2 = buf2; + } + + if( !haveMask && !cvtdst ) + func( sptr1, 0, sptr2, 0, dptr, 0, bszn, usrdata ); + else + { + func( sptr1, 0, sptr2, 0, wbuf, 0, bszn, usrdata ); + if( !haveMask ) + cvtdst( wbuf, 0, 0, 0, dptr, 0, bszn, 0 ); + else if( !cvtdst ) + { + copymask( wbuf, 0, ptrs[3], 0, dptr, 0, Size(bsz, 1), &dsz ); + ptrs[3] += bsz; + } + else + { + cvtdst( wbuf, 0, 0, 0, maskbuf, 0, bszn, 0 ); + copymask( maskbuf, 0, ptrs[3], 0, dptr, 0, Size(bsz, 1), &dsz ); + ptrs[3] += bsz; + } + } + ptrs[0] += bsz*esz1; ptrs[1] += bsz*esz2; ptrs[2] += bsz*dsz; + } + } + } + else + { + const Mat* arrays[] = { &src1, &dst, &mask, 0 }; + uchar* ptrs[3]; + + NAryMatIterator it(arrays, ptrs); + size_t total = it.size, blocksize = std::min(total, blocksize0); + + _buf.allocate(bufesz*blocksize + 64); + buf = _buf; + if( cvtsrc1 ) + buf1 = buf, buf = alignPtr(buf + blocksize*wsz, 16); + buf2 = buf; buf = alignPtr(buf + blocksize*wsz, 16); + wbuf = maskbuf = buf; + if( cvtdst ) + buf = alignPtr(buf + blocksize*wsz, 16); + if( haveMask ) + maskbuf = buf; + + convertAndUnrollScalar( src2, wtype, buf2, blocksize); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( size_t j = 0; j < total; j += blocksize ) + { + int bsz = (int)MIN(total - j, blocksize); + Size bszn(bsz*cn, 1); + const uchar *sptr1 = ptrs[0]; + const uchar* sptr2 = buf2; + uchar* dptr = ptrs[1]; + + if( cvtsrc1 ) + { + cvtsrc1( sptr1, 0, 0, 0, buf1, 0, bszn, 0 ); + sptr1 = buf1; + } + + if( swapped12 ) + std::swap(sptr1, sptr2); + + if( !haveMask && !cvtdst ) + func( sptr1, 0, sptr2, 0, dptr, 0, bszn, usrdata ); + else + { + func( sptr1, 0, sptr2, 0, wbuf, 0, bszn, usrdata ); + if( !haveMask ) + cvtdst( wbuf, 0, 0, 0, dptr, 0, bszn, 0 ); + else if( !cvtdst ) + { + copymask( wbuf, 0, ptrs[2], 0, dptr, 0, Size(bsz, 1), &dsz ); + ptrs[2] += bsz; + } + else + { + cvtdst( wbuf, 0, 0, 0, maskbuf, 0, bszn, 0 ); + copymask( maskbuf, 0, ptrs[2], 0, dptr, 0, Size(bsz, 1), &dsz ); + ptrs[2] += bsz; + } + } + ptrs[0] += bsz*esz1; ptrs[1] += bsz*dsz; + } + } + } +} + +static BinaryFunc addTab[] = +{ + (BinaryFunc)GET_OPTIMIZED(add8u), (BinaryFunc)GET_OPTIMIZED(add8s), + (BinaryFunc)GET_OPTIMIZED(add16u), (BinaryFunc)GET_OPTIMIZED(add16s), + (BinaryFunc)GET_OPTIMIZED(add32s), + (BinaryFunc)GET_OPTIMIZED(add32f), (BinaryFunc)add64f, + 0 +}; + +static BinaryFunc subTab[] = +{ + (BinaryFunc)GET_OPTIMIZED(sub8u), (BinaryFunc)GET_OPTIMIZED(sub8s), + (BinaryFunc)GET_OPTIMIZED(sub16u), (BinaryFunc)GET_OPTIMIZED(sub16s), + (BinaryFunc)GET_OPTIMIZED(sub32s), + (BinaryFunc)GET_OPTIMIZED(sub32f), (BinaryFunc)sub64f, + 0 +}; + +static BinaryFunc absdiffTab[] = +{ + (BinaryFunc)GET_OPTIMIZED(absdiff8u), (BinaryFunc)GET_OPTIMIZED(absdiff8s), + (BinaryFunc)GET_OPTIMIZED(absdiff16u), (BinaryFunc)GET_OPTIMIZED(absdiff16s), + (BinaryFunc)GET_OPTIMIZED(absdiff32s), + (BinaryFunc)GET_OPTIMIZED(absdiff32f), (BinaryFunc)absdiff64f, + 0 +}; + +} + +void cv::add( InputArray src1, InputArray src2, OutputArray dst, + InputArray mask, int dtype ) +{ + arithm_op(src1, src2, dst, mask, dtype, addTab ); +} + +void cv::subtract( InputArray src1, InputArray src2, OutputArray dst, + InputArray mask, int dtype ) +{ +#ifdef HAVE_TEGRA_OPTIMIZATION + if(mask.empty() && src1.depth() == CV_8U && src2.depth() == CV_8U && (dtype == CV_16S || (dtype == -1 && dst.fixedType() && dst.depth() == CV_16S))) + { + Mat _dst = dst.getMat(); + if(tegra::subtract_8u8u16s(src1.getMat(), src2.getMat(), _dst)) + return; + } +#endif + arithm_op(src1, src2, dst, mask, dtype, subTab ); +} + +void cv::absdiff( InputArray src1, InputArray src2, OutputArray dst ) +{ + arithm_op(src1, src2, dst, noArray(), -1, absdiffTab); +} + +/****************************************************************************************\ +* multiply/divide * +\****************************************************************************************/ + +namespace cv +{ + +template static void +mul_( const T* src1, size_t step1, const T* src2, size_t step2, + T* dst, size_t step, Size size, WT scale ) +{ + step1 /= sizeof(src1[0]); + step2 /= sizeof(src2[0]); + step /= sizeof(dst[0]); + + if( scale == (WT)1. ) + { + for( ; size.height--; src1 += step1, src2 += step2, dst += step ) + { + int i=0; + #if CV_ENABLE_UNROLLED + for(; i <= size.width - 4; i += 4 ) + { + T t0; + T t1; + t0 = saturate_cast(src1[i ] * src2[i ]); + t1 = saturate_cast(src1[i+1] * src2[i+1]); + dst[i ] = t0; + dst[i+1] = t1; + + t0 = saturate_cast(src1[i+2] * src2[i+2]); + t1 = saturate_cast(src1[i+3] * src2[i+3]); + dst[i+2] = t0; + dst[i+3] = t1; + } + #endif + for( ; i < size.width; i++ ) + dst[i] = saturate_cast(src1[i] * src2[i]); + } + } + else + { + for( ; size.height--; src1 += step1, src2 += step2, dst += step ) + { + int i = 0; + #if CV_ENABLE_UNROLLED + for(; i <= size.width - 4; i += 4 ) + { + T t0 = saturate_cast(scale*(WT)src1[i]*src2[i]); + T t1 = saturate_cast(scale*(WT)src1[i+1]*src2[i+1]); + dst[i] = t0; dst[i+1] = t1; + + t0 = saturate_cast(scale*(WT)src1[i+2]*src2[i+2]); + t1 = saturate_cast(scale*(WT)src1[i+3]*src2[i+3]); + dst[i+2] = t0; dst[i+3] = t1; + } + #endif + for( ; i < size.width; i++ ) + dst[i] = saturate_cast(scale*(WT)src1[i]*src2[i]); + } + } +} + +template static void +div_( const T* src1, size_t step1, const T* src2, size_t step2, + T* dst, size_t step, Size size, double scale ) +{ + step1 /= sizeof(src1[0]); + step2 /= sizeof(src2[0]); + step /= sizeof(dst[0]); + + for( ; size.height--; src1 += step1, src2 += step2, dst += step ) + { + int i = 0; + #if CV_ENABLE_UNROLLED + for( ; i <= size.width - 4; i += 4 ) + { + if( src2[i] != 0 && src2[i+1] != 0 && src2[i+2] != 0 && src2[i+3] != 0 ) + { + double a = (double)src2[i] * src2[i+1]; + double b = (double)src2[i+2] * src2[i+3]; + double d = scale/(a * b); + b *= d; + a *= d; + + T z0 = saturate_cast(src2[i+1] * ((double)src1[i] * b)); + T z1 = saturate_cast(src2[i] * ((double)src1[i+1] * b)); + T z2 = saturate_cast(src2[i+3] * ((double)src1[i+2] * a)); + T z3 = saturate_cast(src2[i+2] * ((double)src1[i+3] * a)); + + dst[i] = z0; dst[i+1] = z1; + dst[i+2] = z2; dst[i+3] = z3; + } + else + { + T z0 = src2[i] != 0 ? saturate_cast(src1[i]*scale/src2[i]) : 0; + T z1 = src2[i+1] != 0 ? saturate_cast(src1[i+1]*scale/src2[i+1]) : 0; + T z2 = src2[i+2] != 0 ? saturate_cast(src1[i+2]*scale/src2[i+2]) : 0; + T z3 = src2[i+3] != 0 ? saturate_cast(src1[i+3]*scale/src2[i+3]) : 0; + + dst[i] = z0; dst[i+1] = z1; + dst[i+2] = z2; dst[i+3] = z3; + } + } + #endif + for( ; i < size.width; i++ ) + dst[i] = src2[i] != 0 ? saturate_cast(src1[i]*scale/src2[i]) : 0; + } +} + +template static void +recip_( const T*, size_t, const T* src2, size_t step2, + T* dst, size_t step, Size size, double scale ) +{ + step2 /= sizeof(src2[0]); + step /= sizeof(dst[0]); + + for( ; size.height--; src2 += step2, dst += step ) + { + int i = 0; + #if CV_ENABLE_UNROLLED + for( ; i <= size.width - 4; i += 4 ) + { + if( src2[i] != 0 && src2[i+1] != 0 && src2[i+2] != 0 && src2[i+3] != 0 ) + { + double a = (double)src2[i] * src2[i+1]; + double b = (double)src2[i+2] * src2[i+3]; + double d = scale/(a * b); + b *= d; + a *= d; + + T z0 = saturate_cast(src2[i+1] * b); + T z1 = saturate_cast(src2[i] * b); + T z2 = saturate_cast(src2[i+3] * a); + T z3 = saturate_cast(src2[i+2] * a); + + dst[i] = z0; dst[i+1] = z1; + dst[i+2] = z2; dst[i+3] = z3; + } + else + { + T z0 = src2[i] != 0 ? saturate_cast(scale/src2[i]) : 0; + T z1 = src2[i+1] != 0 ? saturate_cast(scale/src2[i+1]) : 0; + T z2 = src2[i+2] != 0 ? saturate_cast(scale/src2[i+2]) : 0; + T z3 = src2[i+3] != 0 ? saturate_cast(scale/src2[i+3]) : 0; + + dst[i] = z0; dst[i+1] = z1; + dst[i+2] = z2; dst[i+3] = z3; + } + } + #endif + for( ; i < size.width; i++ ) + dst[i] = src2[i] != 0 ? saturate_cast(scale/src2[i]) : 0; + } +} + + +static void mul8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, + uchar* dst, size_t step, Size sz, void* scale) +{ + mul_(src1, step1, src2, step2, dst, step, sz, (float)*(const double*)scale); +} + +static void mul8s( const schar* src1, size_t step1, const schar* src2, size_t step2, + schar* dst, size_t step, Size sz, void* scale) +{ + mul_(src1, step1, src2, step2, dst, step, sz, (float)*(const double*)scale); +} + +static void mul16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, + ushort* dst, size_t step, Size sz, void* scale) +{ + mul_(src1, step1, src2, step2, dst, step, sz, (float)*(const double*)scale); +} + +static void mul16s( const short* src1, size_t step1, const short* src2, size_t step2, + short* dst, size_t step, Size sz, void* scale) +{ + mul_(src1, step1, src2, step2, dst, step, sz, (float)*(const double*)scale); +} + +static void mul32s( const int* src1, size_t step1, const int* src2, size_t step2, + int* dst, size_t step, Size sz, void* scale) +{ + mul_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void mul32f( const float* src1, size_t step1, const float* src2, size_t step2, + float* dst, size_t step, Size sz, void* scale) +{ + mul_(src1, step1, src2, step2, dst, step, sz, (float)*(const double*)scale); +} + +static void mul64f( const double* src1, size_t step1, const double* src2, size_t step2, + double* dst, size_t step, Size sz, void* scale) +{ + mul_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void div8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, + uchar* dst, size_t step, Size sz, void* scale) +{ + if( src1 ) + div_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); + else + recip_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void div8s( const schar* src1, size_t step1, const schar* src2, size_t step2, + schar* dst, size_t step, Size sz, void* scale) +{ + div_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void div16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, + ushort* dst, size_t step, Size sz, void* scale) +{ + div_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void div16s( const short* src1, size_t step1, const short* src2, size_t step2, + short* dst, size_t step, Size sz, void* scale) +{ + div_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void div32s( const int* src1, size_t step1, const int* src2, size_t step2, + int* dst, size_t step, Size sz, void* scale) +{ + div_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void div32f( const float* src1, size_t step1, const float* src2, size_t step2, + float* dst, size_t step, Size sz, void* scale) +{ + div_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void div64f( const double* src1, size_t step1, const double* src2, size_t step2, + double* dst, size_t step, Size sz, void* scale) +{ + div_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void recip8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, + uchar* dst, size_t step, Size sz, void* scale) +{ + recip_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void recip8s( const schar* src1, size_t step1, const schar* src2, size_t step2, + schar* dst, size_t step, Size sz, void* scale) +{ + recip_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void recip16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, + ushort* dst, size_t step, Size sz, void* scale) +{ + recip_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void recip16s( const short* src1, size_t step1, const short* src2, size_t step2, + short* dst, size_t step, Size sz, void* scale) +{ + recip_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void recip32s( const int* src1, size_t step1, const int* src2, size_t step2, + int* dst, size_t step, Size sz, void* scale) +{ + recip_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void recip32f( const float* src1, size_t step1, const float* src2, size_t step2, + float* dst, size_t step, Size sz, void* scale) +{ + recip_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + +static void recip64f( const double* src1, size_t step1, const double* src2, size_t step2, + double* dst, size_t step, Size sz, void* scale) +{ + recip_(src1, step1, src2, step2, dst, step, sz, *(const double*)scale); +} + + +static BinaryFunc mulTab[] = +{ + (BinaryFunc)mul8u, (BinaryFunc)mul8s, (BinaryFunc)mul16u, + (BinaryFunc)mul16s, (BinaryFunc)mul32s, (BinaryFunc)mul32f, + (BinaryFunc)mul64f, 0 +}; + +static BinaryFunc divTab[] = +{ + (BinaryFunc)div8u, (BinaryFunc)div8s, (BinaryFunc)div16u, + (BinaryFunc)div16s, (BinaryFunc)div32s, (BinaryFunc)div32f, + (BinaryFunc)div64f, 0 +}; + +static BinaryFunc recipTab[] = +{ + (BinaryFunc)recip8u, (BinaryFunc)recip8s, (BinaryFunc)recip16u, + (BinaryFunc)recip16s, (BinaryFunc)recip32s, (BinaryFunc)recip32f, + (BinaryFunc)recip64f, 0 +}; + + +} + +void cv::multiply(InputArray src1, InputArray src2, + OutputArray dst, double scale, int dtype) +{ + arithm_op(src1, src2, dst, noArray(), dtype, mulTab, true, &scale); +} + +void cv::divide(InputArray src1, InputArray src2, + OutputArray dst, double scale, int dtype) +{ + arithm_op(src1, src2, dst, noArray(), dtype, divTab, true, &scale); +} + +void cv::divide(double scale, InputArray src2, + OutputArray dst, int dtype) +{ + arithm_op(src2, src2, dst, noArray(), dtype, recipTab, true, &scale); +} + +/****************************************************************************************\ +* addWeighted * +\****************************************************************************************/ + +namespace cv +{ + +template static void +addWeighted_( const T* src1, size_t step1, const T* src2, size_t step2, + T* dst, size_t step, Size size, void* _scalars ) +{ + const double* scalars = (const double*)_scalars; + WT alpha = (WT)scalars[0], beta = (WT)scalars[1], gamma = (WT)scalars[2]; + step1 /= sizeof(src1[0]); + step2 /= sizeof(src2[0]); + step /= sizeof(dst[0]); + + for( ; size.height--; src1 += step1, src2 += step2, dst += step ) + { + int x = 0; + #if CV_ENABLE_UNROLLED + for( ; x <= size.width - 4; x += 4 ) + { + T t0 = saturate_cast(src1[x]*alpha + src2[x]*beta + gamma); + T t1 = saturate_cast(src1[x+1]*alpha + src2[x+1]*beta + gamma); + dst[x] = t0; dst[x+1] = t1; + + t0 = saturate_cast(src1[x+2]*alpha + src2[x+2]*beta + gamma); + t1 = saturate_cast(src1[x+3]*alpha + src2[x+3]*beta + gamma); + dst[x+2] = t0; dst[x+3] = t1; + } + #endif + for( ; x < size.width; x++ ) + dst[x] = saturate_cast(src1[x]*alpha + src2[x]*beta + gamma); + } +} + + +static void +addWeighted8u( const uchar* src1, size_t step1, + const uchar* src2, size_t step2, + uchar* dst, size_t step, Size size, + void* _scalars ) +{ + const double* scalars = (const double*)_scalars; + float alpha = (float)scalars[0], beta = (float)scalars[1], gamma = (float)scalars[2]; + + for( ; size.height--; src1 += step1, src2 += step2, dst += step ) + { + int x = 0; + +#if CV_SSE2 + if( USE_SSE2 ) + { + __m128 a4 = _mm_set1_ps(alpha), b4 = _mm_set1_ps(beta), g4 = _mm_set1_ps(gamma); + __m128i z = _mm_setzero_si128(); + + for( ; x <= size.width - 8; x += 8 ) + { + __m128i u = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(src1 + x)), z); + __m128i v = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(src2 + x)), z); + + __m128 u0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(u, z)); + __m128 u1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(u, z)); + __m128 v0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(v, z)); + __m128 v1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v, z)); + + u0 = _mm_add_ps(_mm_mul_ps(u0, a4), _mm_mul_ps(v0, b4)); + u1 = _mm_add_ps(_mm_mul_ps(u1, a4), _mm_mul_ps(v1, b4)); + u0 = _mm_add_ps(u0, g4); u1 = _mm_add_ps(u1, g4); + + u = _mm_packs_epi32(_mm_cvtps_epi32(u0), _mm_cvtps_epi32(u1)); + u = _mm_packus_epi16(u, u); + + _mm_storel_epi64((__m128i*)(dst + x), u); + } + } +#endif + #if CV_ENABLE_UNROLLED + for( ; x <= size.width - 4; x += 4 ) + { + float t0, t1; + t0 = CV_8TO32F(src1[x])*alpha + CV_8TO32F(src2[x])*beta + gamma; + t1 = CV_8TO32F(src1[x+1])*alpha + CV_8TO32F(src2[x+1])*beta + gamma; + + dst[x] = saturate_cast(t0); + dst[x+1] = saturate_cast(t1); + + t0 = CV_8TO32F(src1[x+2])*alpha + CV_8TO32F(src2[x+2])*beta + gamma; + t1 = CV_8TO32F(src1[x+3])*alpha + CV_8TO32F(src2[x+3])*beta + gamma; + + dst[x+2] = saturate_cast(t0); + dst[x+3] = saturate_cast(t1); + } + #endif + + for( ; x < size.width; x++ ) + { + float t0 = CV_8TO32F(src1[x])*alpha + CV_8TO32F(src2[x])*beta + gamma; + dst[x] = saturate_cast(t0); + } + } +} + +static void addWeighted8s( const schar* src1, size_t step1, const schar* src2, size_t step2, + schar* dst, size_t step, Size sz, void* scalars ) +{ + addWeighted_(src1, step1, src2, step2, dst, step, sz, scalars); +} + +static void addWeighted16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, + ushort* dst, size_t step, Size sz, void* scalars ) +{ + addWeighted_(src1, step1, src2, step2, dst, step, sz, scalars); +} + +static void addWeighted16s( const short* src1, size_t step1, const short* src2, size_t step2, + short* dst, size_t step, Size sz, void* scalars ) +{ + addWeighted_(src1, step1, src2, step2, dst, step, sz, scalars); +} + +static void addWeighted32s( const int* src1, size_t step1, const int* src2, size_t step2, + int* dst, size_t step, Size sz, void* scalars ) +{ + addWeighted_(src1, step1, src2, step2, dst, step, sz, scalars); +} + +static void addWeighted32f( const float* src1, size_t step1, const float* src2, size_t step2, + float* dst, size_t step, Size sz, void* scalars ) +{ + addWeighted_(src1, step1, src2, step2, dst, step, sz, scalars); +} + +static void addWeighted64f( const double* src1, size_t step1, const double* src2, size_t step2, + double* dst, size_t step, Size sz, void* scalars ) +{ + addWeighted_(src1, step1, src2, step2, dst, step, sz, scalars); +} + +static BinaryFunc addWeightedTab[] = +{ + (BinaryFunc)GET_OPTIMIZED(addWeighted8u), (BinaryFunc)GET_OPTIMIZED(addWeighted8s), (BinaryFunc)GET_OPTIMIZED(addWeighted16u), + (BinaryFunc)GET_OPTIMIZED(addWeighted16s), (BinaryFunc)GET_OPTIMIZED(addWeighted32s), (BinaryFunc)addWeighted32f, + (BinaryFunc)addWeighted64f, 0 +}; + +} + +void cv::addWeighted( InputArray src1, double alpha, InputArray src2, + double beta, double gamma, OutputArray dst, int dtype ) +{ + double scalars[] = {alpha, beta, gamma}; + arithm_op(src1, src2, dst, noArray(), dtype, addWeightedTab, true, scalars); +} + + +/****************************************************************************************\ +* compare * +\****************************************************************************************/ + +namespace cv +{ + +template static void +cmp_(const T* src1, size_t step1, const T* src2, size_t step2, + uchar* dst, size_t step, Size size, int code) +{ + step1 /= sizeof(src1[0]); + step2 /= sizeof(src2[0]); + if( code == CMP_GE || code == CMP_LT ) + { + std::swap(src1, src2); + std::swap(step1, step2); + code = code == CMP_GE ? CMP_LE : CMP_GT; + } + + if( code == CMP_GT || code == CMP_LE ) + { + int m = code == CMP_GT ? 0 : 255; + for( ; size.height--; src1 += step1, src2 += step2, dst += step ) + { + int x = 0; + #if CV_ENABLE_UNROLLED + for( ; x <= size.width - 4; x += 4 ) + { + int t0, t1; + t0 = -(src1[x] > src2[x]) ^ m; + t1 = -(src1[x+1] > src2[x+1]) ^ m; + dst[x] = (uchar)t0; dst[x+1] = (uchar)t1; + t0 = -(src1[x+2] > src2[x+2]) ^ m; + t1 = -(src1[x+3] > src2[x+3]) ^ m; + dst[x+2] = (uchar)t0; dst[x+3] = (uchar)t1; + } + #endif + for( ; x < size.width; x++ ) + dst[x] = (uchar)(-(src1[x] > src2[x]) ^ m); + } + } + else if( code == CMP_EQ || code == CMP_NE ) + { + int m = code == CMP_EQ ? 0 : 255; + for( ; size.height--; src1 += step1, src2 += step2, dst += step ) + { + int x = 0; + #if CV_ENABLE_UNROLLED + for( ; x <= size.width - 4; x += 4 ) + { + int t0, t1; + t0 = -(src1[x] == src2[x]) ^ m; + t1 = -(src1[x+1] == src2[x+1]) ^ m; + dst[x] = (uchar)t0; dst[x+1] = (uchar)t1; + t0 = -(src1[x+2] == src2[x+2]) ^ m; + t1 = -(src1[x+3] == src2[x+3]) ^ m; + dst[x+2] = (uchar)t0; dst[x+3] = (uchar)t1; + } + #endif + for( ; x < size.width; x++ ) + dst[x] = (uchar)(-(src1[x] == src2[x]) ^ m); + } + } +} + + +static void cmp8u(const uchar* src1, size_t step1, const uchar* src2, size_t step2, + uchar* dst, size_t step, Size size, void* _cmpop) +{ + //vz optimized cmp_(src1, step1, src2, step2, dst, step, size, *(int*)_cmpop); + int code = *(int*)_cmpop; + step1 /= sizeof(src1[0]); + step2 /= sizeof(src2[0]); + if( code == CMP_GE || code == CMP_LT ) + { + std::swap(src1, src2); + std::swap(step1, step2); + code = code == CMP_GE ? CMP_LE : CMP_GT; + } + + if( code == CMP_GT || code == CMP_LE ) + { + int m = code == CMP_GT ? 0 : 255; + for( ; size.height--; src1 += step1, src2 += step2, dst += step ) + { + int x =0; + #if CV_SSE2 + if( USE_SSE2 ){ + __m128i m128 = code == CMP_GT ? _mm_setzero_si128() : _mm_set1_epi8 (-1); + __m128i c128 = _mm_set1_epi8 (-128); + for( ; x <= size.width - 16; x += 16 ) + { + __m128i r00 = _mm_loadu_si128((const __m128i*)(src1 + x)); + __m128i r10 = _mm_loadu_si128((const __m128i*)(src2 + x)); + // no simd for 8u comparison, that's why we need the trick + r00 = _mm_sub_epi8(r00,c128); + r10 = _mm_sub_epi8(r10,c128); + + r00 =_mm_xor_si128(_mm_cmpgt_epi8(r00, r10), m128); + _mm_storeu_si128((__m128i*)(dst + x),r00); + + } + } + #endif + + for( ; x < size.width; x++ ){ + dst[x] = (uchar)(-(src1[x] > src2[x]) ^ m); + } + } + } + else if( code == CMP_EQ || code == CMP_NE ) + { + int m = code == CMP_EQ ? 0 : 255; + for( ; size.height--; src1 += step1, src2 += step2, dst += step ) + { + int x = 0; + #if CV_SSE2 + if( USE_SSE2 ){ + __m128i m128 = code == CMP_EQ ? _mm_setzero_si128() : _mm_set1_epi8 (-1); + for( ; x <= size.width - 16; x += 16 ) + { + __m128i r00 = _mm_loadu_si128((const __m128i*)(src1 + x)); + __m128i r10 = _mm_loadu_si128((const __m128i*)(src2 + x)); + r00 = _mm_xor_si128 ( _mm_cmpeq_epi8 (r00, r10), m128); + _mm_storeu_si128((__m128i*)(dst + x), r00); + } + } + #endif + for( ; x < size.width; x++ ) + dst[x] = (uchar)(-(src1[x] == src2[x]) ^ m); + } + } +} + +static void cmp8s(const schar* src1, size_t step1, const schar* src2, size_t step2, + uchar* dst, size_t step, Size size, void* _cmpop) +{ + cmp_(src1, step1, src2, step2, dst, step, size, *(int*)_cmpop); +} + +static void cmp16u(const ushort* src1, size_t step1, const ushort* src2, size_t step2, + uchar* dst, size_t step, Size size, void* _cmpop) +{ + cmp_(src1, step1, src2, step2, dst, step, size, *(int*)_cmpop); +} + +static void cmp16s(const short* src1, size_t step1, const short* src2, size_t step2, + uchar* dst, size_t step, Size size, void* _cmpop) +{ + //vz optimized cmp_(src1, step1, src2, step2, dst, step, size, *(int*)_cmpop); + + int code = *(int*)_cmpop; + step1 /= sizeof(src1[0]); + step2 /= sizeof(src2[0]); + if( code == CMP_GE || code == CMP_LT ) + { + std::swap(src1, src2); + std::swap(step1, step2); + code = code == CMP_GE ? CMP_LE : CMP_GT; + } + + if( code == CMP_GT || code == CMP_LE ) + { + int m = code == CMP_GT ? 0 : 255; + for( ; size.height--; src1 += step1, src2 += step2, dst += step ) + { + int x =0; + #if CV_SSE2 + if( USE_SSE2){// + __m128i m128 = code == CMP_GT ? _mm_setzero_si128() : _mm_set1_epi16 (-1); + for( ; x <= size.width - 16; x += 16 ) + { + __m128i r00 = _mm_loadu_si128((const __m128i*)(src1 + x)); + __m128i r10 = _mm_loadu_si128((const __m128i*)(src2 + x)); + r00 = _mm_xor_si128 ( _mm_cmpgt_epi16 (r00, r10), m128); + __m128i r01 = _mm_loadu_si128((const __m128i*)(src1 + x + 8)); + __m128i r11 = _mm_loadu_si128((const __m128i*)(src2 + x + 8)); + r01 = _mm_xor_si128 ( _mm_cmpgt_epi16 (r01, r11), m128); + r11 = _mm_packs_epi16(r00, r01); + _mm_storeu_si128((__m128i*)(dst + x), r11); + } + if( x <= size.width-8) + { + __m128i r00 = _mm_loadu_si128((const __m128i*)(src1 + x)); + __m128i r10 = _mm_loadu_si128((const __m128i*)(src2 + x)); + r00 = _mm_xor_si128 ( _mm_cmpgt_epi16 (r00, r10), m128); + r10 = _mm_packs_epi16(r00, r00); + _mm_storel_epi64((__m128i*)(dst + x), r10); + + x += 8; + } + } + #endif + + for( ; x < size.width; x++ ){ + dst[x] = (uchar)(-(src1[x] > src2[x]) ^ m); + } + } + } + else if( code == CMP_EQ || code == CMP_NE ) + { + int m = code == CMP_EQ ? 0 : 255; + for( ; size.height--; src1 += step1, src2 += step2, dst += step ) + { + int x = 0; + #if CV_SSE2 + if( USE_SSE2 ){ + __m128i m128 = code == CMP_EQ ? _mm_setzero_si128() : _mm_set1_epi16 (-1); + for( ; x <= size.width - 16; x += 16 ) + { + __m128i r00 = _mm_loadu_si128((const __m128i*)(src1 + x)); + __m128i r10 = _mm_loadu_si128((const __m128i*)(src2 + x)); + r00 = _mm_xor_si128 ( _mm_cmpeq_epi16 (r00, r10), m128); + __m128i r01 = _mm_loadu_si128((const __m128i*)(src1 + x + 8)); + __m128i r11 = _mm_loadu_si128((const __m128i*)(src2 + x + 8)); + r01 = _mm_xor_si128 ( _mm_cmpeq_epi16 (r01, r11), m128); + r11 = _mm_packs_epi16(r00, r01); + _mm_storeu_si128((__m128i*)(dst + x), r11); + } + if( x <= size.width - 8) + { + __m128i r00 = _mm_loadu_si128((const __m128i*)(src1 + x)); + __m128i r10 = _mm_loadu_si128((const __m128i*)(src2 + x)); + r00 = _mm_xor_si128 ( _mm_cmpeq_epi16 (r00, r10), m128); + r10 = _mm_packs_epi16(r00, r00); + _mm_storel_epi64((__m128i*)(dst + x), r10); + + x += 8; + } + } + #endif + for( ; x < size.width; x++ ) + dst[x] = (uchar)(-(src1[x] == src2[x]) ^ m); + } + } +} + +static void cmp32s(const int* src1, size_t step1, const int* src2, size_t step2, + uchar* dst, size_t step, Size size, void* _cmpop) +{ + cmp_(src1, step1, src2, step2, dst, step, size, *(int*)_cmpop); +} + +static void cmp32f(const float* src1, size_t step1, const float* src2, size_t step2, + uchar* dst, size_t step, Size size, void* _cmpop) +{ + cmp_(src1, step1, src2, step2, dst, step, size, *(int*)_cmpop); +} + +static void cmp64f(const double* src1, size_t step1, const double* src2, size_t step2, + uchar* dst, size_t step, Size size, void* _cmpop) +{ + cmp_(src1, step1, src2, step2, dst, step, size, *(int*)_cmpop); +} + +static BinaryFunc cmpTab[] = +{ + (BinaryFunc)GET_OPTIMIZED(cmp8u), (BinaryFunc)GET_OPTIMIZED(cmp8s), + (BinaryFunc)GET_OPTIMIZED(cmp16u), (BinaryFunc)GET_OPTIMIZED(cmp16s), + (BinaryFunc)GET_OPTIMIZED(cmp32s), + (BinaryFunc)GET_OPTIMIZED(cmp32f), (BinaryFunc)cmp64f, + 0 +}; + + +static double getMinVal(int depth) +{ + static const double tab[] = {0, -128, 0, -32768, INT_MIN, -FLT_MAX, -DBL_MAX, 0}; + return tab[depth]; +} + +static double getMaxVal(int depth) +{ + static const double tab[] = {255, 127, 65535, 32767, INT_MAX, FLT_MAX, DBL_MAX, 0}; + return tab[depth]; +} + +} + +void cv::compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op) +{ + CV_Assert( op == CMP_LT || op == CMP_LE || op == CMP_EQ || + op == CMP_NE || op == CMP_GE || op == CMP_GT ); + + int kind1 = _src1.kind(), kind2 = _src2.kind(); + Mat src1 = _src1.getMat(), src2 = _src2.getMat(); + + if( kind1 == kind2 && src1.dims <= 2 && src2.dims <= 2 && src1.size() == src2.size() && src1.type() == src2.type() ) + { + int cn = src1.channels(); + _dst.create(src1.size(), CV_8UC(cn)); + Mat dst = _dst.getMat(); + Size sz = getContinuousSize(src1, src2, dst, src1.channels()); + cmpTab[src1.depth()](src1.data, src1.step, src2.data, src2.step, dst.data, dst.step, sz, &op); + return; + } + + bool haveScalar = false; + + if( (kind1 == _InputArray::MATX) + (kind2 == _InputArray::MATX) == 1 || + src1.size != src2.size || src1.type() != src2.type() ) + { + if( checkScalar(src1, src2.type(), kind1, kind2) ) + { + // src1 is a scalar; swap it with src2 + swap(src1, src2); + op = op == CMP_LT ? CMP_GT : op == CMP_LE ? CMP_GE : + op == CMP_GE ? CMP_LE : op == CMP_GT ? CMP_LT : op; + } + else if( !checkScalar(src2, src1.type(), kind2, kind1) ) + CV_Error( CV_StsUnmatchedSizes, + "The operation is neither 'array op array' (where arrays have the same size and the same type), " + "nor 'array op scalar', nor 'scalar op array'" ); + haveScalar = true; + } + + + int cn = src1.channels(), depth1 = src1.depth(), depth2 = src2.depth(); + + _dst.create(src1.dims, src1.size, CV_8UC(cn)); + src1 = src1.reshape(1); src2 = src2.reshape(1); + Mat dst = _dst.getMat().reshape(1); + + size_t esz = src1.elemSize(); + size_t blocksize0 = (size_t)(BLOCK_SIZE + esz-1)/esz; + BinaryFunc func = cmpTab[depth1]; + + if( !haveScalar ) + { + const Mat* arrays[] = { &src1, &src2, &dst, 0 }; + uchar* ptrs[3]; + + NAryMatIterator it(arrays, ptrs); + size_t total = it.size; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + func( ptrs[0], 0, ptrs[1], 0, ptrs[2], 0, Size((int)total, 1), &op ); + } + else + { + const Mat* arrays[] = { &src1, &dst, 0 }; + uchar* ptrs[2]; + + NAryMatIterator it(arrays, ptrs); + size_t total = it.size, blocksize = std::min(total, blocksize0); + + AutoBuffer _buf(blocksize*esz); + uchar *buf = _buf; + + if( depth1 > CV_32S ) + convertAndUnrollScalar( src2, depth1, buf, blocksize ); + else + { + double fval=0; + getConvertFunc(depth2, CV_64F)(src2.data, 0, 0, 0, (uchar*)&fval, 0, Size(1,1), 0); + if( fval < getMinVal(depth1) ) + { + dst = Scalar::all(op == CMP_GT || op == CMP_GE || op == CMP_NE ? 255 : 0); + return; + } + + if( fval > getMaxVal(depth1) ) + { + dst = Scalar::all(op == CMP_LT || op == CMP_LE || op == CMP_NE ? 255 : 0); + return; + } + + int ival = cvRound(fval); + if( fval != ival ) + { + if( op == CMP_LT || op == CMP_GE ) + ival = cvCeil(fval); + else if( op == CMP_LE || op == CMP_GT ) + ival = cvFloor(fval); + else + { + dst = Scalar::all(op == CMP_NE ? 255 : 0); + return; + } + } + convertAndUnrollScalar(Mat(1, 1, CV_32S, &ival), depth1, buf, blocksize); + } + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( size_t j = 0; j < total; j += blocksize ) + { + int bsz = (int)MIN(total - j, blocksize); + func( ptrs[0], 0, buf, 0, ptrs[1], 0, Size(bsz, 1), &op); + ptrs[0] += bsz*esz; + ptrs[1] += bsz; + } + } + } +} + +/****************************************************************************************\ +* inRange * +\****************************************************************************************/ + +namespace cv +{ + +template static void +inRange_(const T* src1, size_t step1, const T* src2, size_t step2, + const T* src3, size_t step3, uchar* dst, size_t step, + Size size) +{ + step1 /= sizeof(src1[0]); + step2 /= sizeof(src2[0]); + step3 /= sizeof(src3[0]); + + for( ; size.height--; src1 += step1, src2 += step2, src3 += step3, dst += step ) + { + int x = 0; + #if CV_ENABLE_UNROLLED + for( ; x <= size.width - 4; x += 4 ) + { + int t0, t1; + t0 = src2[x] <= src1[x] && src1[x] <= src3[x]; + t1 = src2[x+1] <= src1[x+1] && src1[x+1] <= src3[x+1]; + dst[x] = (uchar)-t0; dst[x+1] = (uchar)-t1; + t0 = src2[x+2] <= src1[x+2] && src1[x+2] <= src3[x+2]; + t1 = src2[x+3] <= src1[x+3] && src1[x+3] <= src3[x+3]; + dst[x+2] = (uchar)-t0; dst[x+3] = (uchar)-t1; + } + #endif + for( ; x < size.width; x++ ) + dst[x] = (uchar)-(src2[x] <= src1[x] && src1[x] <= src3[x]); + } +} + + +static void inRange8u(const uchar* src1, size_t step1, const uchar* src2, size_t step2, + const uchar* src3, size_t step3, uchar* dst, size_t step, Size size) +{ + inRange_(src1, step1, src2, step2, src3, step3, dst, step, size); +} + +static void inRange8s(const schar* src1, size_t step1, const schar* src2, size_t step2, + const schar* src3, size_t step3, uchar* dst, size_t step, Size size) +{ + inRange_(src1, step1, src2, step2, src3, step3, dst, step, size); +} + +static void inRange16u(const ushort* src1, size_t step1, const ushort* src2, size_t step2, + const ushort* src3, size_t step3, uchar* dst, size_t step, Size size) +{ + inRange_(src1, step1, src2, step2, src3, step3, dst, step, size); +} + +static void inRange16s(const short* src1, size_t step1, const short* src2, size_t step2, + const short* src3, size_t step3, uchar* dst, size_t step, Size size) +{ + inRange_(src1, step1, src2, step2, src3, step3, dst, step, size); +} + +static void inRange32s(const int* src1, size_t step1, const int* src2, size_t step2, + const int* src3, size_t step3, uchar* dst, size_t step, Size size) +{ + inRange_(src1, step1, src2, step2, src3, step3, dst, step, size); +} + +static void inRange32f(const float* src1, size_t step1, const float* src2, size_t step2, + const float* src3, size_t step3, uchar* dst, size_t step, Size size) +{ + inRange_(src1, step1, src2, step2, src3, step3, dst, step, size); +} + +static void inRange64f(const double* src1, size_t step1, const double* src2, size_t step2, + const double* src3, size_t step3, uchar* dst, size_t step, Size size) +{ + inRange_(src1, step1, src2, step2, src3, step3, dst, step, size); +} + +static void inRangeReduce(const uchar* src, uchar* dst, size_t len, int cn) +{ + int k = cn % 4 ? cn % 4 : 4; + size_t i, j; + if( k == 1 ) + for( i = j = 0; i < len; i++, j += cn ) + dst[i] = src[j]; + else if( k == 2 ) + for( i = j = 0; i < len; i++, j += cn ) + dst[i] = src[j] & src[j+1]; + else if( k == 3 ) + for( i = j = 0; i < len; i++, j += cn ) + dst[i] = src[j] & src[j+1] & src[j+2]; + else + for( i = j = 0; i < len; i++, j += cn ) + dst[i] = src[j] & src[j+1] & src[j+2] & src[j+3]; + + for( ; k < cn; k += 4 ) + { + for( i = 0, j = k; i < len; i++, j += cn ) + dst[i] &= src[j] & src[j+1] & src[j+2] & src[j+3]; + } +} + +typedef void (*InRangeFunc)( const uchar* src1, size_t step1, const uchar* src2, size_t step2, + const uchar* src3, size_t step3, uchar* dst, size_t step, Size sz ); + +static InRangeFunc inRangeTab[] = +{ + (InRangeFunc)GET_OPTIMIZED(inRange8u), (InRangeFunc)GET_OPTIMIZED(inRange8s), (InRangeFunc)GET_OPTIMIZED(inRange16u), + (InRangeFunc)GET_OPTIMIZED(inRange16s), (InRangeFunc)GET_OPTIMIZED(inRange32s), (InRangeFunc)GET_OPTIMIZED(inRange32f), + (InRangeFunc)inRange64f, 0 +}; + +} + +void cv::inRange(InputArray _src, InputArray _lowerb, + InputArray _upperb, OutputArray _dst) +{ + int skind = _src.kind(), lkind = _lowerb.kind(), ukind = _upperb.kind(); + Mat src = _src.getMat(), lb = _lowerb.getMat(), ub = _upperb.getMat(); + + bool lbScalar = false, ubScalar = false; + + if( (lkind == _InputArray::MATX && skind != _InputArray::MATX) || + src.size != lb.size || src.type() != lb.type() ) + { + if( !checkScalar(lb, src.type(), lkind, skind) ) + CV_Error( CV_StsUnmatchedSizes, + "The lower bounary is neither an array of the same size and same type as src, nor a scalar"); + lbScalar = true; + } + + if( (ukind == _InputArray::MATX && skind != _InputArray::MATX) || + src.size != ub.size || src.type() != ub.type() ) + { + if( !checkScalar(ub, src.type(), ukind, skind) ) + CV_Error( CV_StsUnmatchedSizes, + "The upper bounary is neither an array of the same size and same type as src, nor a scalar"); + ubScalar = true; + } + + CV_Assert( ((int)lbScalar ^ (int)ubScalar) == 0 ); + + int cn = src.channels(), depth = src.depth(); + + size_t esz = src.elemSize(); + size_t blocksize0 = (size_t)(BLOCK_SIZE + esz-1)/esz; + + _dst.create(src.dims, src.size, CV_8U); + Mat dst = _dst.getMat(); + InRangeFunc func = inRangeTab[depth]; + + const Mat* arrays_sc[] = { &src, &dst, 0 }; + const Mat* arrays_nosc[] = { &src, &dst, &lb, &ub, 0 }; + uchar* ptrs[4]; + + NAryMatIterator it(lbScalar && ubScalar ? arrays_sc : arrays_nosc, ptrs); + size_t total = it.size, blocksize = std::min(total, blocksize0); + + AutoBuffer _buf(blocksize*(((int)lbScalar + (int)ubScalar)*esz + cn) + 2*cn*sizeof(int) + 128); + uchar *buf = _buf, *mbuf = buf, *lbuf = 0, *ubuf = 0; + buf = alignPtr(buf + blocksize*cn, 16); + + if( lbScalar && ubScalar ) + { + lbuf = buf; + ubuf = buf = alignPtr(buf + blocksize*esz, 16); + + CV_Assert( lb.type() == ub.type() ); + int scdepth = lb.depth(); + + if( scdepth != depth && depth < CV_32S ) + { + int* ilbuf = (int*)alignPtr(buf + blocksize*esz, 16); + int* iubuf = ilbuf + cn; + + BinaryFunc sccvtfunc = getConvertFunc(scdepth, CV_32S); + sccvtfunc(lb.data, 0, 0, 0, (uchar*)ilbuf, 0, Size(cn, 1), 0); + sccvtfunc(ub.data, 0, 0, 0, (uchar*)iubuf, 0, Size(cn, 1), 0); + int minval = cvRound(getMinVal(depth)), maxval = cvRound(getMaxVal(depth)); + + for( int k = 0; k < cn; k++ ) + { + if( ilbuf[k] > iubuf[k] || ilbuf[k] > maxval || iubuf[k] < minval ) + ilbuf[k] = minval+1, iubuf[k] = minval; + } + lb = Mat(cn, 1, CV_32S, ilbuf); + ub = Mat(cn, 1, CV_32S, iubuf); + } + + convertAndUnrollScalar( lb, src.type(), lbuf, blocksize ); + convertAndUnrollScalar( ub, src.type(), ubuf, blocksize ); + } + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( size_t j = 0; j < total; j += blocksize ) + { + int bsz = (int)MIN(total - j, blocksize); + size_t delta = bsz*esz; + uchar *lptr = lbuf, *uptr = ubuf; + if( !lbScalar ) + { + lptr = ptrs[2]; + ptrs[2] += delta; + } + if( !ubScalar ) + { + int idx = !lbScalar ? 3 : 2; + uptr = ptrs[idx]; + ptrs[idx] += delta; + } + func( ptrs[0], 0, lptr, 0, uptr, 0, cn == 1 ? ptrs[1] : mbuf, 0, Size(bsz*cn, 1)); + if( cn > 1 ) + inRangeReduce(mbuf, ptrs[1], bsz, cn); + ptrs[0] += delta; + ptrs[1] += bsz; + } + } +} + +/****************************************************************************************\ +* Earlier API: cvAdd etc. * +\****************************************************************************************/ + +CV_IMPL void +cvNot( const CvArr* srcarr, CvArr* dstarr ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + CV_Assert( src.size == dst.size && src.type() == dst.type() ); + cv::bitwise_not( src, dst ); +} + + +CV_IMPL void +cvAnd( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2), + dst = cv::cvarrToMat(dstarr), mask; + CV_Assert( src1.size == dst.size && src1.type() == dst.type() ); + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::bitwise_and( src1, src2, dst, mask ); +} + + +CV_IMPL void +cvOr( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2), + dst = cv::cvarrToMat(dstarr), mask; + CV_Assert( src1.size == dst.size && src1.type() == dst.type() ); + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::bitwise_or( src1, src2, dst, mask ); +} + + +CV_IMPL void +cvXor( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2), + dst = cv::cvarrToMat(dstarr), mask; + CV_Assert( src1.size == dst.size && src1.type() == dst.type() ); + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::bitwise_xor( src1, src2, dst, mask ); +} + + +CV_IMPL void +cvAndS( const CvArr* srcarr, CvScalar s, CvArr* dstarr, const CvArr* maskarr ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), mask; + CV_Assert( src.size == dst.size && src.type() == dst.type() ); + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::bitwise_and( src, (const cv::Scalar&)s, dst, mask ); +} + + +CV_IMPL void +cvOrS( const CvArr* srcarr, CvScalar s, CvArr* dstarr, const CvArr* maskarr ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), mask; + CV_Assert( src.size == dst.size && src.type() == dst.type() ); + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::bitwise_or( src, (const cv::Scalar&)s, dst, mask ); +} + + +CV_IMPL void +cvXorS( const CvArr* srcarr, CvScalar s, CvArr* dstarr, const CvArr* maskarr ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), mask; + CV_Assert( src.size == dst.size && src.type() == dst.type() ); + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::bitwise_xor( src, (const cv::Scalar&)s, dst, mask ); +} + + +CV_IMPL void cvAdd( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2), + dst = cv::cvarrToMat(dstarr), mask; + CV_Assert( src1.size == dst.size && src1.channels() == dst.channels() ); + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::add( src1, src2, dst, mask, dst.type() ); +} + + +CV_IMPL void cvSub( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2), + dst = cv::cvarrToMat(dstarr), mask; + CV_Assert( src1.size == dst.size && src1.channels() == dst.channels() ); + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::subtract( src1, src2, dst, mask, dst.type() ); +} + + +CV_IMPL void cvAddS( const CvArr* srcarr1, CvScalar value, CvArr* dstarr, const CvArr* maskarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), + dst = cv::cvarrToMat(dstarr), mask; + CV_Assert( src1.size == dst.size && src1.channels() == dst.channels() ); + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::add( src1, (const cv::Scalar&)value, dst, mask, dst.type() ); +} + + +CV_IMPL void cvSubRS( const CvArr* srcarr1, CvScalar value, CvArr* dstarr, const CvArr* maskarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), + dst = cv::cvarrToMat(dstarr), mask; + CV_Assert( src1.size == dst.size && src1.channels() == dst.channels() ); + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::subtract( (const cv::Scalar&)value, src1, dst, mask, dst.type() ); +} + + +CV_IMPL void cvMul( const CvArr* srcarr1, const CvArr* srcarr2, + CvArr* dstarr, double scale ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2), + dst = cv::cvarrToMat(dstarr); + CV_Assert( src1.size == dst.size && src1.channels() == dst.channels() ); + cv::multiply( src1, src2, dst, scale, dst.type() ); +} + + +CV_IMPL void cvDiv( const CvArr* srcarr1, const CvArr* srcarr2, + CvArr* dstarr, double scale ) +{ + cv::Mat src2 = cv::cvarrToMat(srcarr2), + dst = cv::cvarrToMat(dstarr), mask; + CV_Assert( src2.size == dst.size && src2.channels() == dst.channels() ); + + if( srcarr1 ) + cv::divide( cv::cvarrToMat(srcarr1), src2, dst, scale, dst.type() ); + else + cv::divide( scale, src2, dst, dst.type() ); +} + + +CV_IMPL void +cvAddWeighted( const CvArr* srcarr1, double alpha, + const CvArr* srcarr2, double beta, + double gamma, CvArr* dstarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2), + dst = cv::cvarrToMat(dstarr); + CV_Assert( src1.size == dst.size && src1.channels() == dst.channels() ); + cv::addWeighted( src1, alpha, src2, beta, gamma, dst, dst.type() ); +} + + +CV_IMPL void +cvAbsDiff( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr); + CV_Assert( src1.size == dst.size && src1.type() == dst.type() ); + + cv::absdiff( src1, cv::cvarrToMat(srcarr2), dst ); +} + + +CV_IMPL void +cvAbsDiffS( const CvArr* srcarr1, CvArr* dstarr, CvScalar scalar ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr); + CV_Assert( src1.size == dst.size && src1.type() == dst.type() ); + + cv::absdiff( src1, (const cv::Scalar&)scalar, dst ); +} + + +CV_IMPL void +cvInRange( const void* srcarr1, const void* srcarr2, + const void* srcarr3, void* dstarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr); + CV_Assert( src1.size == dst.size && dst.type() == CV_8U ); + + cv::inRange( src1, cv::cvarrToMat(srcarr2), cv::cvarrToMat(srcarr3), dst ); +} + + +CV_IMPL void +cvInRangeS( const void* srcarr1, CvScalar lowerb, CvScalar upperb, void* dstarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr); + CV_Assert( src1.size == dst.size && dst.type() == CV_8U ); + + cv::inRange( src1, (const cv::Scalar&)lowerb, (const cv::Scalar&)upperb, dst ); +} + + +CV_IMPL void +cvCmp( const void* srcarr1, const void* srcarr2, void* dstarr, int cmp_op ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr); + CV_Assert( src1.size == dst.size && dst.type() == CV_8U ); + + cv::compare( src1, cv::cvarrToMat(srcarr2), dst, cmp_op ); +} + + +CV_IMPL void +cvCmpS( const void* srcarr1, double value, void* dstarr, int cmp_op ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr); + CV_Assert( src1.size == dst.size && dst.type() == CV_8U ); + + cv::compare( src1, value, dst, cmp_op ); +} + + +CV_IMPL void +cvMin( const void* srcarr1, const void* srcarr2, void* dstarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr); + CV_Assert( src1.size == dst.size && src1.type() == dst.type() ); + + cv::min( src1, cv::cvarrToMat(srcarr2), dst ); +} + + +CV_IMPL void +cvMax( const void* srcarr1, const void* srcarr2, void* dstarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr); + CV_Assert( src1.size == dst.size && src1.type() == dst.type() ); + + cv::max( src1, cv::cvarrToMat(srcarr2), dst ); +} + + +CV_IMPL void +cvMinS( const void* srcarr1, double value, void* dstarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr); + CV_Assert( src1.size == dst.size && src1.type() == dst.type() ); + + cv::min( src1, value, dst ); +} + + +CV_IMPL void +cvMaxS( const void* srcarr1, double value, void* dstarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr); + CV_Assert( src1.size == dst.size && src1.type() == dst.type() ); + + cv::max( src1, value, dst ); +} + +/* End of file. */ diff --git a/core/src/array.cpp b/core/src/array.cpp new file mode 100644 index 0000000..c9060bf --- /dev/null +++ b/core/src/array.cpp @@ -0,0 +1,3206 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +/* //////////////////////////////////////////////////////////////////// +// +// CvMat, CvMatND, CvSparceMat and IplImage support functions +// (creation, deletion, copying, retrieving and setting elements etc.) +// +// */ + +#include "precomp.hpp" + + +static struct +{ + Cv_iplCreateImageHeader createHeader; + Cv_iplAllocateImageData allocateData; + Cv_iplDeallocate deallocate; + Cv_iplCreateROI createROI; + Cv_iplCloneImage cloneImage; +} +CvIPL; + +// Makes the library use native IPL image allocators +CV_IMPL void +cvSetIPLAllocators( Cv_iplCreateImageHeader createHeader, + Cv_iplAllocateImageData allocateData, + Cv_iplDeallocate deallocate, + Cv_iplCreateROI createROI, + Cv_iplCloneImage cloneImage ) +{ + int count = (createHeader != 0) + (allocateData != 0) + (deallocate != 0) + + (createROI != 0) + (cloneImage != 0); + + if( count != 0 && count != 5 ) + CV_Error( CV_StsBadArg, "Either all the pointers should be null or " + "they all should be non-null" ); + + CvIPL.createHeader = createHeader; + CvIPL.allocateData = allocateData; + CvIPL.deallocate = deallocate; + CvIPL.createROI = createROI; + CvIPL.cloneImage = cloneImage; +} + + +/****************************************************************************************\ +* CvMat creation and basic operations * +\****************************************************************************************/ + +// Creates CvMat and underlying data +CV_IMPL CvMat* +cvCreateMat( int height, int width, int type ) +{ + CvMat* arr = cvCreateMatHeader( height, width, type ); + cvCreateData( arr ); + + return arr; +} + + +static void icvCheckHuge( CvMat* arr ) +{ + if( (int64)arr->step*arr->rows > INT_MAX ) + arr->type &= ~CV_MAT_CONT_FLAG; +} + +// Creates CvMat header only +CV_IMPL CvMat* +cvCreateMatHeader( int rows, int cols, int type ) +{ + type = CV_MAT_TYPE(type); + + if( rows < 0 || cols <= 0 ) + CV_Error( CV_StsBadSize, "Non-positive width or height" ); + + int min_step = CV_ELEM_SIZE(type)*cols; + if( min_step <= 0 ) + CV_Error( CV_StsUnsupportedFormat, "Invalid matrix type" ); + + CvMat* arr = (CvMat*)cvAlloc( sizeof(*arr)); + + arr->step = min_step; + arr->type = CV_MAT_MAGIC_VAL | type | CV_MAT_CONT_FLAG; + arr->rows = rows; + arr->cols = cols; + arr->data.ptr = 0; + arr->refcount = 0; + arr->hdr_refcount = 1; + + icvCheckHuge( arr ); + return arr; +} + + +// Initializes CvMat header, allocated by the user +CV_IMPL CvMat* +cvInitMatHeader( CvMat* arr, int rows, int cols, + int type, void* data, int step ) +{ + if( !arr ) + CV_Error( CV_StsNullPtr, "" ); + + if( (unsigned)CV_MAT_DEPTH(type) > CV_DEPTH_MAX ) + CV_Error( CV_BadNumChannels, "" ); + + if( rows < 0 || cols <= 0 ) + CV_Error( CV_StsBadSize, "Non-positive cols or rows" ); + + type = CV_MAT_TYPE( type ); + arr->type = type | CV_MAT_MAGIC_VAL; + arr->rows = rows; + arr->cols = cols; + arr->data.ptr = (uchar*)data; + arr->refcount = 0; + arr->hdr_refcount = 0; + + int pix_size = CV_ELEM_SIZE(type); + int min_step = arr->cols*pix_size; + + if( step != CV_AUTOSTEP && step != 0 ) + { + if( step < min_step ) + CV_Error( CV_BadStep, "" ); + arr->step = step; + } + else + { + arr->step = min_step; + } + + arr->type = CV_MAT_MAGIC_VAL | type | + (arr->rows == 1 || arr->step == min_step ? CV_MAT_CONT_FLAG : 0); + + icvCheckHuge( arr ); + return arr; +} + + +// Deallocates the CvMat structure and underlying data +CV_IMPL void +cvReleaseMat( CvMat** array ) +{ + if( !array ) + CV_Error( CV_HeaderIsNull, "" ); + + if( *array ) + { + CvMat* arr = *array; + + if( !CV_IS_MAT_HDR_Z(arr) && !CV_IS_MATND_HDR(arr) ) + CV_Error( CV_StsBadFlag, "" ); + + *array = 0; + + cvDecRefData( arr ); + cvFree( &arr ); + } +} + + +// Creates a copy of matrix +CV_IMPL CvMat* +cvCloneMat( const CvMat* src ) +{ + if( !CV_IS_MAT_HDR( src )) + CV_Error( CV_StsBadArg, "Bad CvMat header" ); + + CvMat* dst = cvCreateMatHeader( src->rows, src->cols, src->type ); + + if( src->data.ptr ) + { + cvCreateData( dst ); + cvCopy( src, dst ); + } + + return dst; +} + + +/****************************************************************************************\ +* CvMatND creation and basic operations * +\****************************************************************************************/ + +CV_IMPL CvMatND* +cvInitMatNDHeader( CvMatND* mat, int dims, const int* sizes, + int type, void* data ) +{ + type = CV_MAT_TYPE(type); + int64 step = CV_ELEM_SIZE(type); + + if( !mat ) + CV_Error( CV_StsNullPtr, "NULL matrix header pointer" ); + + if( step == 0 ) + CV_Error( CV_StsUnsupportedFormat, "invalid array data type" ); + + if( !sizes ) + CV_Error( CV_StsNullPtr, "NULL pointer" ); + + if( dims <= 0 || dims > CV_MAX_DIM ) + CV_Error( CV_StsOutOfRange, + "non-positive or too large number of dimensions" ); + + for( int i = dims - 1; i >= 0; i-- ) + { + if( sizes[i] < 0 ) + CV_Error( CV_StsBadSize, "one of dimesion sizes is non-positive" ); + mat->dim[i].size = sizes[i]; + if( step > INT_MAX ) + CV_Error( CV_StsOutOfRange, "The array is too big" ); + mat->dim[i].step = (int)step; + step *= sizes[i]; + } + + mat->type = CV_MATND_MAGIC_VAL | (step <= INT_MAX ? CV_MAT_CONT_FLAG : 0) | type; + mat->dims = dims; + mat->data.ptr = (uchar*)data; + mat->refcount = 0; + mat->hdr_refcount = 0; + return mat; +} + + +// Creates CvMatND and underlying data +CV_IMPL CvMatND* +cvCreateMatND( int dims, const int* sizes, int type ) +{ + CvMatND* arr = cvCreateMatNDHeader( dims, sizes, type ); + cvCreateData( arr ); + + return arr; +} + + +// Creates CvMatND header only +CV_IMPL CvMatND* +cvCreateMatNDHeader( int dims, const int* sizes, int type ) +{ + if( dims <= 0 || dims > CV_MAX_DIM ) + CV_Error( CV_StsOutOfRange, + "non-positive or too large number of dimensions" ); + + CvMatND* arr = (CvMatND*)cvAlloc( sizeof(*arr) ); + + cvInitMatNDHeader( arr, dims, sizes, type, 0 ); + arr->hdr_refcount = 1; + return arr; +} + + +// Creates a copy of nD array +CV_IMPL CvMatND* +cvCloneMatND( const CvMatND* src ) +{ + if( !CV_IS_MATND_HDR( src )) + CV_Error( CV_StsBadArg, "Bad CvMatND header" ); + + CV_Assert( src->dims <= CV_MAX_DIM ); + int sizes[CV_MAX_DIM]; + + for( int i = 0; i < src->dims; i++ ) + sizes[i] = src->dim[i].size; + + CvMatND* dst = cvCreateMatNDHeader( src->dims, sizes, src->type ); + + if( src->data.ptr ) + { + cvCreateData( dst ); + cv::Mat _src(src), _dst(dst); + uchar* data0 = dst->data.ptr; + _src.copyTo(_dst); + CV_Assert(_dst.data == data0); + //cvCopy( src, dst ); + } + + return dst; +} + + +static CvMatND* +cvGetMatND( const CvArr* arr, CvMatND* matnd, int* coi ) +{ + CvMatND* result = 0; + + if( coi ) + *coi = 0; + + if( !matnd || !arr ) + CV_Error( CV_StsNullPtr, "NULL array pointer is passed" ); + + if( CV_IS_MATND_HDR(arr)) + { + if( !((CvMatND*)arr)->data.ptr ) + CV_Error( CV_StsNullPtr, "The matrix has NULL data pointer" ); + + result = (CvMatND*)arr; + } + else + { + CvMat stub, *mat = (CvMat*)arr; + + if( CV_IS_IMAGE_HDR( mat )) + mat = cvGetMat( mat, &stub, coi ); + + if( !CV_IS_MAT_HDR( mat )) + CV_Error( CV_StsBadArg, "Unrecognized or unsupported array type" ); + + if( !mat->data.ptr ) + CV_Error( CV_StsNullPtr, "Input array has NULL data pointer" ); + + matnd->data.ptr = mat->data.ptr; + matnd->refcount = 0; + matnd->hdr_refcount = 0; + matnd->type = mat->type; + matnd->dims = 2; + matnd->dim[0].size = mat->rows; + matnd->dim[0].step = mat->step; + matnd->dim[1].size = mat->cols; + matnd->dim[1].step = CV_ELEM_SIZE(mat->type); + result = matnd; + } + + return result; +} + + +// returns number of dimensions to iterate. +/* +Checks whether arrays have equal type, sizes (mask is optional array +that needs to have the same size, but 8uC1 or 8sC1 type). +Returns number of dimensions to iterate through: +0 means that all arrays are continuous, +1 means that all arrays are vectors of continuous arrays etc. +and the size of largest common continuous part of the arrays +*/ +CV_IMPL int +cvInitNArrayIterator( int count, CvArr** arrs, + const CvArr* mask, CvMatND* stubs, + CvNArrayIterator* iterator, int flags ) +{ + int dims = -1; + int i, j, size, dim0 = -1; + int64 step; + CvMatND* hdr0 = 0; + + if( count < 1 || count > CV_MAX_ARR ) + CV_Error( CV_StsOutOfRange, "Incorrect number of arrays" ); + + if( !arrs || !stubs ) + CV_Error( CV_StsNullPtr, "Some of required array pointers is NULL" ); + + if( !iterator ) + CV_Error( CV_StsNullPtr, "Iterator pointer is NULL" ); + + for( i = 0; i <= count; i++ ) + { + const CvArr* arr = i < count ? arrs[i] : mask; + CvMatND* hdr; + + if( !arr ) + { + if( i < count ) + CV_Error( CV_StsNullPtr, "Some of required array pointers is NULL" ); + break; + } + + if( CV_IS_MATND( arr )) + hdr = (CvMatND*)arr; + else + { + int coi = 0; + hdr = cvGetMatND( arr, stubs + i, &coi ); + if( coi != 0 ) + CV_Error( CV_BadCOI, "COI set is not allowed here" ); + } + + iterator->hdr[i] = hdr; + + if( i > 0 ) + { + if( hdr->dims != hdr0->dims ) + CV_Error( CV_StsUnmatchedSizes, + "Number of dimensions is the same for all arrays" ); + + if( i < count ) + { + switch( flags & (CV_NO_DEPTH_CHECK|CV_NO_CN_CHECK)) + { + case 0: + if( !CV_ARE_TYPES_EQ( hdr, hdr0 )) + CV_Error( CV_StsUnmatchedFormats, + "Data type is not the same for all arrays" ); + break; + case CV_NO_DEPTH_CHECK: + if( !CV_ARE_CNS_EQ( hdr, hdr0 )) + CV_Error( CV_StsUnmatchedFormats, + "Number of channels is not the same for all arrays" ); + break; + case CV_NO_CN_CHECK: + if( !CV_ARE_CNS_EQ( hdr, hdr0 )) + CV_Error( CV_StsUnmatchedFormats, + "Depth is not the same for all arrays" ); + break; + } + } + else + { + if( !CV_IS_MASK_ARR( hdr )) + CV_Error( CV_StsBadMask, "Mask should have 8uC1 or 8sC1 data type" ); + } + + if( !(flags & CV_NO_SIZE_CHECK) ) + { + for( j = 0; j < hdr->dims; j++ ) + if( hdr->dim[j].size != hdr0->dim[j].size ) + CV_Error( CV_StsUnmatchedSizes, + "Dimension sizes are the same for all arrays" ); + } + } + else + hdr0 = hdr; + + step = CV_ELEM_SIZE(hdr->type); + for( j = hdr->dims - 1; j > dim0; j-- ) + { + if( step != hdr->dim[j].step ) + break; + step *= hdr->dim[j].size; + } + + if( j == dim0 && step > INT_MAX ) + j++; + + if( j > dim0 ) + dim0 = j; + + iterator->hdr[i] = (CvMatND*)hdr; + iterator->ptr[i] = (uchar*)hdr->data.ptr; + } + + size = 1; + for( j = hdr0->dims - 1; j > dim0; j-- ) + size *= hdr0->dim[j].size; + + dims = dim0 + 1; + iterator->dims = dims; + iterator->count = count; + iterator->size = cvSize(size,1); + + for( i = 0; i < dims; i++ ) + iterator->stack[i] = hdr0->dim[i].size; + + return dims; +} + + +// returns zero value if iteration is finished, non-zero otherwise +CV_IMPL int cvNextNArraySlice( CvNArrayIterator* iterator ) +{ + assert( iterator != 0 ); + int i, dims, size = 0; + + for( dims = iterator->dims; dims > 0; dims-- ) + { + for( i = 0; i < iterator->count; i++ ) + iterator->ptr[i] += iterator->hdr[i]->dim[dims-1].step; + + if( --iterator->stack[dims-1] > 0 ) + break; + + size = iterator->hdr[0]->dim[dims-1].size; + + for( i = 0; i < iterator->count; i++ ) + iterator->ptr[i] -= (size_t)size*iterator->hdr[i]->dim[dims-1].step; + + iterator->stack[dims-1] = size; + } + + return dims > 0; +} + + +/****************************************************************************************\ +* CvSparseMat creation and basic operations * +\****************************************************************************************/ + + +// Creates CvMatND and underlying data +CV_IMPL CvSparseMat* +cvCreateSparseMat( int dims, const int* sizes, int type ) +{ + type = CV_MAT_TYPE( type ); + int pix_size1 = CV_ELEM_SIZE1(type); + int pix_size = pix_size1*CV_MAT_CN(type); + int i, size; + CvMemStorage* storage; + + if( pix_size == 0 ) + CV_Error( CV_StsUnsupportedFormat, "invalid array data type" ); + + if( dims <= 0 || dims > CV_MAX_DIM_HEAP ) + CV_Error( CV_StsOutOfRange, "bad number of dimensions" ); + + if( !sizes ) + CV_Error( CV_StsNullPtr, "NULL pointer" ); + + for( i = 0; i < dims; i++ ) + { + if( sizes[i] <= 0 ) + CV_Error( CV_StsBadSize, "one of dimesion sizes is non-positive" ); + } + + CvSparseMat* arr = (CvSparseMat*)cvAlloc(sizeof(*arr)+MAX(0,dims-CV_MAX_DIM)*sizeof(arr->size[0])); + + arr->type = CV_SPARSE_MAT_MAGIC_VAL | type; + arr->dims = dims; + arr->refcount = 0; + arr->hdr_refcount = 1; + memcpy( arr->size, sizes, dims*sizeof(sizes[0])); + + arr->valoffset = (int)cvAlign(sizeof(CvSparseNode), pix_size1); + arr->idxoffset = (int)cvAlign(arr->valoffset + pix_size, sizeof(int)); + size = (int)cvAlign(arr->idxoffset + dims*sizeof(int), sizeof(CvSetElem)); + + storage = cvCreateMemStorage( CV_SPARSE_MAT_BLOCK ); + arr->heap = cvCreateSet( 0, sizeof(CvSet), size, storage ); + + arr->hashsize = CV_SPARSE_HASH_SIZE0; + size = arr->hashsize*sizeof(arr->hashtable[0]); + + arr->hashtable = (void**)cvAlloc( size ); + memset( arr->hashtable, 0, size ); + + return arr; +} + + +// Creates CvMatND and underlying data +CV_IMPL void +cvReleaseSparseMat( CvSparseMat** array ) +{ + if( !array ) + CV_Error( CV_HeaderIsNull, "" ); + + if( *array ) + { + CvSparseMat* arr = *array; + + if( !CV_IS_SPARSE_MAT_HDR(arr) ) + CV_Error( CV_StsBadFlag, "" ); + + *array = 0; + + CvMemStorage* storage = arr->heap->storage; + cvReleaseMemStorage( &storage ); + cvFree( &arr->hashtable ); + cvFree( &arr ); + } +} + + +// Creates CvMatND and underlying data +CV_IMPL CvSparseMat* +cvCloneSparseMat( const CvSparseMat* src ) +{ + if( !CV_IS_SPARSE_MAT_HDR(src) ) + CV_Error( CV_StsBadArg, "Invalid sparse array header" ); + + CvSparseMat* dst = cvCreateSparseMat( src->dims, src->size, src->type ); + cvCopy( src, dst ); + return dst; +} + + +CvSparseNode* +cvInitSparseMatIterator( const CvSparseMat* mat, CvSparseMatIterator* iterator ) +{ + CvSparseNode* node = 0; + int idx; + + if( !CV_IS_SPARSE_MAT( mat )) + CV_Error( CV_StsBadArg, "Invalid sparse matrix header" ); + + if( !iterator ) + CV_Error( CV_StsNullPtr, "NULL iterator pointer" ); + + iterator->mat = (CvSparseMat*)mat; + iterator->node = 0; + + for( idx = 0; idx < mat->hashsize; idx++ ) + if( mat->hashtable[idx] ) + { + node = iterator->node = (CvSparseNode*)mat->hashtable[idx]; + break; + } + + iterator->curidx = idx; + return node; +} + +#define ICV_SPARSE_MAT_HASH_MULTIPLIER cv::SparseMat::HASH_SCALE + +static uchar* +icvGetNodePtr( CvSparseMat* mat, const int* idx, int* _type, + int create_node, unsigned* precalc_hashval ) +{ + uchar* ptr = 0; + int i, tabidx; + unsigned hashval = 0; + CvSparseNode *node; + assert( CV_IS_SPARSE_MAT( mat )); + + if( !precalc_hashval ) + { + for( i = 0; i < mat->dims; i++ ) + { + int t = idx[i]; + if( (unsigned)t >= (unsigned)mat->size[i] ) + CV_Error( CV_StsOutOfRange, "One of indices is out of range" ); + hashval = hashval*ICV_SPARSE_MAT_HASH_MULTIPLIER + t; + } + } + else + { + hashval = *precalc_hashval; + } + + tabidx = hashval & (mat->hashsize - 1); + hashval &= INT_MAX; + + if( create_node >= -1 ) + { + for( node = (CvSparseNode*)mat->hashtable[tabidx]; + node != 0; node = node->next ) + { + if( node->hashval == hashval ) + { + int* nodeidx = CV_NODE_IDX(mat,node); + for( i = 0; i < mat->dims; i++ ) + if( idx[i] != nodeidx[i] ) + break; + if( i == mat->dims ) + { + ptr = (uchar*)CV_NODE_VAL(mat,node); + break; + } + } + } + } + + if( !ptr && create_node ) + { + if( mat->heap->active_count >= mat->hashsize*CV_SPARSE_HASH_RATIO ) + { + void** newtable; + int newsize = MAX( mat->hashsize*2, CV_SPARSE_HASH_SIZE0); + int newrawsize = newsize*sizeof(newtable[0]); + + CvSparseMatIterator iterator; + assert( (newsize & (newsize - 1)) == 0 ); + + // resize hash table + newtable = (void**)cvAlloc( newrawsize ); + memset( newtable, 0, newrawsize ); + + node = cvInitSparseMatIterator( mat, &iterator ); + while( node ) + { + CvSparseNode* next = cvGetNextSparseNode( &iterator ); + int newidx = node->hashval & (newsize - 1); + node->next = (CvSparseNode*)newtable[newidx]; + newtable[newidx] = node; + node = next; + } + + cvFree( &mat->hashtable ); + mat->hashtable = newtable; + mat->hashsize = newsize; + tabidx = hashval & (newsize - 1); + } + + node = (CvSparseNode*)cvSetNew( mat->heap ); + node->hashval = hashval; + node->next = (CvSparseNode*)mat->hashtable[tabidx]; + mat->hashtable[tabidx] = node; + memcpy(CV_NODE_IDX(mat,node), idx, mat->dims*sizeof(idx[0])); + ptr = (uchar*)CV_NODE_VAL(mat,node); + if( create_node > 0 ) + memset( ptr, 0, CV_ELEM_SIZE(mat->type)); + } + + if( _type ) + *_type = CV_MAT_TYPE(mat->type); + + return ptr; +} + + +static void +icvDeleteNode( CvSparseMat* mat, const int* idx, unsigned* precalc_hashval ) +{ + int i, tabidx; + unsigned hashval = 0; + CvSparseNode *node, *prev = 0; + assert( CV_IS_SPARSE_MAT( mat )); + + if( !precalc_hashval ) + { + for( i = 0; i < mat->dims; i++ ) + { + int t = idx[i]; + if( (unsigned)t >= (unsigned)mat->size[i] ) + CV_Error( CV_StsOutOfRange, "One of indices is out of range" ); + hashval = hashval*ICV_SPARSE_MAT_HASH_MULTIPLIER + t; + } + } + else + { + hashval = *precalc_hashval; + } + + tabidx = hashval & (mat->hashsize - 1); + hashval &= INT_MAX; + + for( node = (CvSparseNode*)mat->hashtable[tabidx]; + node != 0; prev = node, node = node->next ) + { + if( node->hashval == hashval ) + { + int* nodeidx = CV_NODE_IDX(mat,node); + for( i = 0; i < mat->dims; i++ ) + if( idx[i] != nodeidx[i] ) + break; + if( i == mat->dims ) + break; + } + } + + if( node ) + { + if( prev ) + prev->next = node->next; + else + mat->hashtable[tabidx] = node->next; + cvSetRemoveByPtr( mat->heap, node ); + } +} + + +/****************************************************************************************\ +* Common for multiple array types operations * +\****************************************************************************************/ + +// Allocates underlying array data +CV_IMPL void +cvCreateData( CvArr* arr ) +{ + if( CV_IS_MAT_HDR_Z( arr )) + { + size_t step, total_size; + CvMat* mat = (CvMat*)arr; + step = mat->step; + + if( mat->rows == 0 || mat->cols == 0 ) + return; + + if( mat->data.ptr != 0 ) + CV_Error( CV_StsError, "Data is already allocated" ); + + if( step == 0 ) + step = CV_ELEM_SIZE(mat->type)*mat->cols; + + int64 _total_size = (int64)step*mat->rows + sizeof(int) + CV_MALLOC_ALIGN; + total_size = (size_t)_total_size; + if(_total_size != (int64)total_size) + CV_Error(CV_StsNoMem, "Too big buffer is allocated" ); + mat->refcount = (int*)cvAlloc( (size_t)total_size ); + mat->data.ptr = (uchar*)cvAlignPtr( mat->refcount + 1, CV_MALLOC_ALIGN ); + *mat->refcount = 1; + } + else if( CV_IS_IMAGE_HDR(arr)) + { + IplImage* img = (IplImage*)arr; + + if( img->imageData != 0 ) + CV_Error( CV_StsError, "Data is already allocated" ); + + if( !CvIPL.allocateData ) + { + img->imageData = img->imageDataOrigin = + (char*)cvAlloc( (size_t)img->imageSize ); + } + else + { + int depth = img->depth; + int width = img->width; + + if( img->depth == IPL_DEPTH_32F || img->depth == IPL_DEPTH_64F ) + { + img->width *= img->depth == IPL_DEPTH_32F ? sizeof(float) : sizeof(double); + img->depth = IPL_DEPTH_8U; + } + + CvIPL.allocateData( img, 0, 0 ); + + img->width = width; + img->depth = depth; + } + } + else if( CV_IS_MATND_HDR( arr )) + { + CvMatND* mat = (CvMatND*)arr; + int i; + size_t total_size = CV_ELEM_SIZE(mat->type); + + if( mat->dim[0].size == 0 ) + return; + + if( mat->data.ptr != 0 ) + CV_Error( CV_StsError, "Data is already allocated" ); + + if( CV_IS_MAT_CONT( mat->type )) + { + total_size = (size_t)mat->dim[0].size*(mat->dim[0].step != 0 ? + (size_t)mat->dim[0].step : total_size); + } + else + { + for( i = mat->dims - 1; i >= 0; i-- ) + { + size_t size = (size_t)mat->dim[i].step*mat->dim[i].size; + + if( total_size < size ) + total_size = size; + } + } + + mat->refcount = (int*)cvAlloc( total_size + + sizeof(int) + CV_MALLOC_ALIGN ); + mat->data.ptr = (uchar*)cvAlignPtr( mat->refcount + 1, CV_MALLOC_ALIGN ); + *mat->refcount = 1; + } + else + CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" ); +} + + +// Assigns external data to array +CV_IMPL void +cvSetData( CvArr* arr, void* data, int step ) +{ + int pix_size, min_step; + + if( CV_IS_MAT_HDR(arr) || CV_IS_MATND_HDR(arr) ) + cvReleaseData( arr ); + + if( CV_IS_MAT_HDR( arr )) + { + CvMat* mat = (CvMat*)arr; + + int type = CV_MAT_TYPE(mat->type); + pix_size = CV_ELEM_SIZE(type); + min_step = mat->cols*pix_size; + + if( step != CV_AUTOSTEP && step != 0 ) + { + if( step < min_step && data != 0 ) + CV_Error( CV_BadStep, "" ); + mat->step = step; + } + else + mat->step = min_step; + + mat->data.ptr = (uchar*)data; + mat->type = CV_MAT_MAGIC_VAL | type | + (mat->rows == 1 || mat->step == min_step ? CV_MAT_CONT_FLAG : 0); + icvCheckHuge( mat ); + } + else if( CV_IS_IMAGE_HDR( arr )) + { + IplImage* img = (IplImage*)arr; + + pix_size = ((img->depth & 255) >> 3)*img->nChannels; + min_step = img->width*pix_size; + + if( step != CV_AUTOSTEP && img->height > 1 ) + { + if( step < min_step && data != 0 ) + CV_Error( CV_BadStep, "" ); + img->widthStep = step; + } + else + { + img->widthStep = min_step; + } + + img->imageSize = img->widthStep * img->height; + img->imageData = img->imageDataOrigin = (char*)data; + + if( (((int)(size_t)data | step) & 7) == 0 && + cvAlign(img->width * pix_size, 8) == step ) + img->align = 8; + else + img->align = 4; + } + else if( CV_IS_MATND_HDR( arr )) + { + CvMatND* mat = (CvMatND*)arr; + int i; + int64 cur_step; + + if( step != CV_AUTOSTEP ) + CV_Error( CV_BadStep, + "For multidimensional array only CV_AUTOSTEP is allowed here" ); + + mat->data.ptr = (uchar*)data; + cur_step = CV_ELEM_SIZE(mat->type); + + for( i = mat->dims - 1; i >= 0; i-- ) + { + if( cur_step > INT_MAX ) + CV_Error( CV_StsOutOfRange, "The array is too big" ); + mat->dim[i].step = (int)cur_step; + cur_step *= mat->dim[i].size; + } + } + else + CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" ); +} + + +// Deallocates array's data +CV_IMPL void +cvReleaseData( CvArr* arr ) +{ + if( CV_IS_MAT_HDR( arr ) || CV_IS_MATND_HDR( arr )) + { + CvMat* mat = (CvMat*)arr; + cvDecRefData( mat ); + } + else if( CV_IS_IMAGE_HDR( arr )) + { + IplImage* img = (IplImage*)arr; + + if( !CvIPL.deallocate ) + { + char* ptr = img->imageDataOrigin; + img->imageData = img->imageDataOrigin = 0; + cvFree( &ptr ); + } + else + { + CvIPL.deallocate( img, IPL_IMAGE_DATA ); + } + } + else + CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" ); +} + + +// Retrieves essential information about image ROI or CvMat data +CV_IMPL void +cvGetRawData( const CvArr* arr, uchar** data, int* step, CvSize* roi_size ) +{ + if( CV_IS_MAT( arr )) + { + CvMat *mat = (CvMat*)arr; + + if( step ) + *step = mat->step; + + if( data ) + *data = mat->data.ptr; + + if( roi_size ) + *roi_size = cvGetMatSize( mat ); + } + else if( CV_IS_IMAGE( arr )) + { + IplImage* img = (IplImage*)arr; + + if( step ) + *step = img->widthStep; + + if( data ) + *data = cvPtr2D( img, 0, 0 ); + + if( roi_size ) + { + if( img->roi ) + { + *roi_size = cvSize( img->roi->width, img->roi->height ); + } + else + { + *roi_size = cvSize( img->width, img->height ); + } + } + } + else if( CV_IS_MATND( arr )) + { + CvMatND* mat = (CvMatND*)arr; + + if( !CV_IS_MAT_CONT( mat->type )) + CV_Error( CV_StsBadArg, "Only continuous nD arrays are supported here" ); + + if( data ) + *data = mat->data.ptr; + + if( roi_size || step ) + { + int i, size1 = mat->dim[0].size, size2 = 1; + + if( mat->dims > 2 ) + for( i = 1; i < mat->dims; i++ ) + size1 *= mat->dim[i].size; + else + size2 = mat->dim[1].size; + + if( roi_size ) + { + roi_size->width = size2; + roi_size->height = size1; + } + + if( step ) + *step = mat->dim[0].step; + } + } + else + CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" ); +} + + +CV_IMPL int +cvGetElemType( const CvArr* arr ) +{ + int type = -1; + if( CV_IS_MAT_HDR(arr) || CV_IS_MATND_HDR(arr) || CV_IS_SPARSE_MAT_HDR(arr)) + type = CV_MAT_TYPE( ((CvMat*)arr)->type ); + else if( CV_IS_IMAGE(arr)) + { + IplImage* img = (IplImage*)arr; + type = CV_MAKETYPE( IPL2CV_DEPTH(img->depth), img->nChannels ); + } + else + CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" ); + + return type; +} + + +// Returns a number of array dimensions +CV_IMPL int +cvGetDims( const CvArr* arr, int* sizes ) +{ + int dims = -1; + if( CV_IS_MAT_HDR( arr )) + { + CvMat* mat = (CvMat*)arr; + + dims = 2; + if( sizes ) + { + sizes[0] = mat->rows; + sizes[1] = mat->cols; + } + } + else if( CV_IS_IMAGE( arr )) + { + IplImage* img = (IplImage*)arr; + dims = 2; + + if( sizes ) + { + sizes[0] = img->height; + sizes[1] = img->width; + } + } + else if( CV_IS_MATND_HDR( arr )) + { + CvMatND* mat = (CvMatND*)arr; + dims = mat->dims; + + if( sizes ) + { + int i; + for( i = 0; i < dims; i++ ) + sizes[i] = mat->dim[i].size; + } + } + else if( CV_IS_SPARSE_MAT_HDR( arr )) + { + CvSparseMat* mat = (CvSparseMat*)arr; + dims = mat->dims; + + if( sizes ) + memcpy( sizes, mat->size, dims*sizeof(sizes[0])); + } + else + CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" ); + + return dims; +} + + +// Returns the size of particular array dimension +CV_IMPL int +cvGetDimSize( const CvArr* arr, int index ) +{ + int size = -1; + + if( CV_IS_MAT( arr )) + { + CvMat *mat = (CvMat*)arr; + + switch( index ) + { + case 0: + size = mat->rows; + break; + case 1: + size = mat->cols; + break; + default: + CV_Error( CV_StsOutOfRange, "bad dimension index" ); + } + } + else if( CV_IS_IMAGE( arr )) + { + IplImage* img = (IplImage*)arr; + + switch( index ) + { + case 0: + size = !img->roi ? img->height : img->roi->height; + break; + case 1: + size = !img->roi ? img->width : img->roi->width; + break; + default: + CV_Error( CV_StsOutOfRange, "bad dimension index" ); + } + } + else if( CV_IS_MATND_HDR( arr )) + { + CvMatND* mat = (CvMatND*)arr; + + if( (unsigned)index >= (unsigned)mat->dims ) + CV_Error( CV_StsOutOfRange, "bad dimension index" ); + + size = mat->dim[index].size; + } + else if( CV_IS_SPARSE_MAT_HDR( arr )) + { + CvSparseMat* mat = (CvSparseMat*)arr; + + if( (unsigned)index >= (unsigned)mat->dims ) + CV_Error( CV_StsOutOfRange, "bad dimension index" ); + + size = mat->size[index]; + } + else + CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" ); + + return size; +} + + +// Returns the size of CvMat or IplImage +CV_IMPL CvSize +cvGetSize( const CvArr* arr ) +{ + CvSize size = { 0, 0 }; + + if( CV_IS_MAT_HDR_Z( arr )) + { + CvMat *mat = (CvMat*)arr; + + size.width = mat->cols; + size.height = mat->rows; + } + else if( CV_IS_IMAGE_HDR( arr )) + { + IplImage* img = (IplImage*)arr; + + if( img->roi ) + { + size.width = img->roi->width; + size.height = img->roi->height; + } + else + { + size.width = img->width; + size.height = img->height; + } + } + else + CV_Error( CV_StsBadArg, "Array should be CvMat or IplImage" ); + + return size; +} + + +// Selects sub-array (no data is copied) +CV_IMPL CvMat* +cvGetSubRect( const CvArr* arr, CvMat* submat, CvRect rect ) +{ + CvMat* res = 0; + CvMat stub, *mat = (CvMat*)arr; + + if( !CV_IS_MAT( mat )) + mat = cvGetMat( mat, &stub ); + + if( !submat ) + CV_Error( CV_StsNullPtr, "" ); + + if( (rect.x|rect.y|rect.width|rect.height) < 0 ) + CV_Error( CV_StsBadSize, "" ); + + if( rect.x + rect.width > mat->cols || + rect.y + rect.height > mat->rows ) + CV_Error( CV_StsBadSize, "" ); + + { + /* + int* refcount = mat->refcount; + + if( refcount ) + ++*refcount; + + cvDecRefData( submat ); + */ + submat->data.ptr = mat->data.ptr + (size_t)rect.y*mat->step + + rect.x*CV_ELEM_SIZE(mat->type); + submat->step = mat->step; + submat->type = (mat->type & (rect.width < mat->cols ? ~CV_MAT_CONT_FLAG : -1)) | + (rect.height <= 1 ? CV_MAT_CONT_FLAG : 0); + submat->rows = rect.height; + submat->cols = rect.width; + submat->refcount = 0; + res = submat; + } + + return res; +} + + +// Selects array's row span. +CV_IMPL CvMat* +cvGetRows( const CvArr* arr, CvMat* submat, + int start_row, int end_row, int delta_row ) +{ + CvMat* res = 0; + CvMat stub, *mat = (CvMat*)arr; + + if( !CV_IS_MAT( mat )) + mat = cvGetMat( mat, &stub ); + + if( !submat ) + CV_Error( CV_StsNullPtr, "" ); + + if( (unsigned)start_row >= (unsigned)mat->rows || + (unsigned)end_row > (unsigned)mat->rows || delta_row <= 0 ) + CV_Error( CV_StsOutOfRange, "" ); + + { + /* + int* refcount = mat->refcount; + + if( refcount ) + ++*refcount; + + cvDecRefData( submat ); + */ + if( delta_row == 1 ) + { + submat->rows = end_row - start_row; + submat->step = mat->step; + } + else + { + submat->rows = (end_row - start_row + delta_row - 1)/delta_row; + submat->step = mat->step * delta_row; + } + + submat->cols = mat->cols; + submat->step &= submat->rows > 1 ? -1 : 0; + submat->data.ptr = mat->data.ptr + (size_t)start_row*mat->step; + submat->type = (mat->type | (submat->rows == 1 ? CV_MAT_CONT_FLAG : 0)) & + (delta_row != 1 && submat->rows > 1 ? ~CV_MAT_CONT_FLAG : -1); + submat->refcount = 0; + submat->hdr_refcount = 0; + res = submat; + } + + return res; +} + + +// Selects array's column span. +CV_IMPL CvMat* +cvGetCols( const CvArr* arr, CvMat* submat, int start_col, int end_col ) +{ + CvMat* res = 0; + CvMat stub, *mat = (CvMat*)arr; + int cols; + + if( !CV_IS_MAT( mat )) + mat = cvGetMat( mat, &stub ); + + if( !submat ) + CV_Error( CV_StsNullPtr, "" ); + + cols = mat->cols; + if( (unsigned)start_col >= (unsigned)cols || + (unsigned)end_col > (unsigned)cols ) + CV_Error( CV_StsOutOfRange, "" ); + + { + /* + int* refcount = mat->refcount; + + if( refcount ) + ++*refcount; + + cvDecRefData( submat ); + */ + submat->rows = mat->rows; + submat->cols = end_col - start_col; + submat->step = mat->step; + submat->data.ptr = mat->data.ptr + (size_t)start_col*CV_ELEM_SIZE(mat->type); + submat->type = mat->type & (submat->rows > 1 && submat->cols < cols ? ~CV_MAT_CONT_FLAG : -1); + submat->refcount = 0; + submat->hdr_refcount = 0; + res = submat; + } + + return res; +} + + +// Selects array diagonal +CV_IMPL CvMat* +cvGetDiag( const CvArr* arr, CvMat* submat, int diag ) +{ + CvMat* res = 0; + CvMat stub, *mat = (CvMat*)arr; + int len, pix_size; + + if( !CV_IS_MAT( mat )) + mat = cvGetMat( mat, &stub ); + + if( !submat ) + CV_Error( CV_StsNullPtr, "" ); + + pix_size = CV_ELEM_SIZE(mat->type); + + /*{ + int* refcount = mat->refcount; + + if( refcount ) + ++*refcount; + + cvDecRefData( submat ); + }*/ + + if( diag >= 0 ) + { + len = mat->cols - diag; + + if( len <= 0 ) + CV_Error( CV_StsOutOfRange, "" ); + + len = CV_IMIN( len, mat->rows ); + submat->data.ptr = mat->data.ptr + diag*pix_size; + } + else + { + len = mat->rows + diag; + + if( len <= 0 ) + CV_Error( CV_StsOutOfRange, "" ); + + len = CV_IMIN( len, mat->cols ); + submat->data.ptr = mat->data.ptr - diag*mat->step; + } + + submat->rows = len; + submat->cols = 1; + submat->step = mat->step + (submat->rows > 1 ? pix_size : 0); + submat->type = mat->type; + if( submat->rows > 1 ) + submat->type &= ~CV_MAT_CONT_FLAG; + else + submat->type |= CV_MAT_CONT_FLAG; + submat->refcount = 0; + submat->hdr_refcount = 0; + res = submat; + + return res; +} + + +/****************************************************************************************\ +* Operations on CvScalar and accessing array elements * +\****************************************************************************************/ + +// Converts CvScalar to specified type +CV_IMPL void +cvScalarToRawData( const CvScalar* scalar, void* data, int type, int extend_to_12 ) +{ + type = CV_MAT_TYPE(type); + int cn = CV_MAT_CN( type ); + int depth = type & CV_MAT_DEPTH_MASK; + + assert( scalar && data ); + if( (unsigned)(cn - 1) >= 4 ) + CV_Error( CV_StsOutOfRange, "The number of channels must be 1, 2, 3 or 4" ); + + switch( depth ) + { + case CV_8UC1: + while( cn-- ) + { + int t = cvRound( scalar->val[cn] ); + ((uchar*)data)[cn] = CV_CAST_8U(t); + } + break; + case CV_8SC1: + while( cn-- ) + { + int t = cvRound( scalar->val[cn] ); + ((char*)data)[cn] = CV_CAST_8S(t); + } + break; + case CV_16UC1: + while( cn-- ) + { + int t = cvRound( scalar->val[cn] ); + ((ushort*)data)[cn] = CV_CAST_16U(t); + } + break; + case CV_16SC1: + while( cn-- ) + { + int t = cvRound( scalar->val[cn] ); + ((short*)data)[cn] = CV_CAST_16S(t); + } + break; + case CV_32SC1: + while( cn-- ) + ((int*)data)[cn] = cvRound( scalar->val[cn] ); + break; + case CV_32FC1: + while( cn-- ) + ((float*)data)[cn] = (float)(scalar->val[cn]); + break; + case CV_64FC1: + while( cn-- ) + ((double*)data)[cn] = (double)(scalar->val[cn]); + break; + default: + assert(0); + CV_Error( CV_BadDepth, "" ); + } + + if( extend_to_12 ) + { + int pix_size = CV_ELEM_SIZE(type); + int offset = CV_ELEM_SIZE1(depth)*12; + + do + { + offset -= pix_size; + memcpy((char*)data + offset, data, pix_size); + } + while( offset > pix_size ); + } +} + + +// Converts data of specified type to CvScalar +CV_IMPL void +cvRawDataToScalar( const void* data, int flags, CvScalar* scalar ) +{ + int cn = CV_MAT_CN( flags ); + + assert( scalar && data ); + + if( (unsigned)(cn - 1) >= 4 ) + CV_Error( CV_StsOutOfRange, "The number of channels must be 1, 2, 3 or 4" ); + + memset( scalar->val, 0, sizeof(scalar->val)); + + switch( CV_MAT_DEPTH( flags )) + { + case CV_8U: + while( cn-- ) + scalar->val[cn] = CV_8TO32F(((uchar*)data)[cn]); + break; + case CV_8S: + while( cn-- ) + scalar->val[cn] = CV_8TO32F(((char*)data)[cn]); + break; + case CV_16U: + while( cn-- ) + scalar->val[cn] = ((ushort*)data)[cn]; + break; + case CV_16S: + while( cn-- ) + scalar->val[cn] = ((short*)data)[cn]; + break; + case CV_32S: + while( cn-- ) + scalar->val[cn] = ((int*)data)[cn]; + break; + case CV_32F: + while( cn-- ) + scalar->val[cn] = ((float*)data)[cn]; + break; + case CV_64F: + while( cn-- ) + scalar->val[cn] = ((double*)data)[cn]; + break; + default: + assert(0); + CV_Error( CV_BadDepth, "" ); + } +} + + +static double icvGetReal( const void* data, int type ) +{ + switch( type ) + { + case CV_8U: + return *(uchar*)data; + case CV_8S: + return *(char*)data; + case CV_16U: + return *(ushort*)data; + case CV_16S: + return *(short*)data; + case CV_32S: + return *(int*)data; + case CV_32F: + return *(float*)data; + case CV_64F: + return *(double*)data; + } + + return 0; +} + + +static void icvSetReal( double value, const void* data, int type ) +{ + if( type < CV_32F ) + { + int ivalue = cvRound(value); + switch( type ) + { + case CV_8U: + *(uchar*)data = CV_CAST_8U(ivalue); + break; + case CV_8S: + *(char*)data = CV_CAST_8S(ivalue); + break; + case CV_16U: + *(ushort*)data = CV_CAST_16U(ivalue); + break; + case CV_16S: + *(short*)data = CV_CAST_16S(ivalue); + break; + case CV_32S: + *(int*)data = CV_CAST_32S(ivalue); + break; + } + } + else + { + switch( type ) + { + case CV_32F: + *(float*)data = (float)value; + break; + case CV_64F: + *(double*)data = value; + break; + } + } +} + + +// Returns pointer to specified element of array (linear index is used) +CV_IMPL uchar* +cvPtr1D( const CvArr* arr, int idx, int* _type ) +{ + uchar* ptr = 0; + if( CV_IS_MAT( arr )) + { + CvMat* mat = (CvMat*)arr; + + int type = CV_MAT_TYPE(mat->type); + int pix_size = CV_ELEM_SIZE(type); + + if( _type ) + *_type = type; + + // the first part is mul-free sufficient check + // that the index is within the matrix + if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) && + (unsigned)idx >= (unsigned)(mat->rows*mat->cols)) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + if( CV_IS_MAT_CONT(mat->type)) + { + ptr = mat->data.ptr + (size_t)idx*pix_size; + } + else + { + int row, col; + if( mat->cols == 1 ) + row = idx, col = 0; + else + row = idx/mat->cols, col = idx - row*mat->cols; + ptr = mat->data.ptr + (size_t)row*mat->step + col*pix_size; + } + } + else if( CV_IS_IMAGE_HDR( arr )) + { + IplImage* img = (IplImage*)arr; + int width = !img->roi ? img->width : img->roi->width; + int y = idx/width, x = idx - y*width; + + ptr = cvPtr2D( arr, y, x, _type ); + } + else if( CV_IS_MATND( arr )) + { + CvMatND* mat = (CvMatND*)arr; + int j, type = CV_MAT_TYPE(mat->type); + size_t size = mat->dim[0].size; + + if( _type ) + *_type = type; + + for( j = 1; j < mat->dims; j++ ) + size *= mat->dim[j].size; + + if((unsigned)idx >= (unsigned)size ) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + if( CV_IS_MAT_CONT(mat->type)) + { + int pix_size = CV_ELEM_SIZE(type); + ptr = mat->data.ptr + (size_t)idx*pix_size; + } + else + { + ptr = mat->data.ptr; + for( j = mat->dims - 1; j >= 0; j-- ) + { + int sz = mat->dim[j].size; + if( sz ) + { + int t = idx/sz; + ptr += (idx - t*sz)*mat->dim[j].step; + idx = t; + } + } + } + } + else if( CV_IS_SPARSE_MAT( arr )) + { + CvSparseMat* m = (CvSparseMat*)arr; + if( m->dims == 1 ) + ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, _type, 1, 0 ); + else + { + int i, n = m->dims; + CV_DbgAssert( n <= CV_MAX_DIM_HEAP ); + int _idx[CV_MAX_DIM_HEAP]; + + for( i = n - 1; i >= 0; i-- ) + { + int t = idx / m->size[i]; + _idx[i] = idx - t*m->size[i]; + idx = t; + } + ptr = icvGetNodePtr( (CvSparseMat*)arr, _idx, _type, 1, 0 ); + } + } + else + { + CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" ); + } + + return ptr; +} + + +// Returns pointer to specified element of 2d array +CV_IMPL uchar* +cvPtr2D( const CvArr* arr, int y, int x, int* _type ) +{ + uchar* ptr = 0; + if( CV_IS_MAT( arr )) + { + CvMat* mat = (CvMat*)arr; + int type; + + if( (unsigned)y >= (unsigned)(mat->rows) || + (unsigned)x >= (unsigned)(mat->cols) ) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + type = CV_MAT_TYPE(mat->type); + if( _type ) + *_type = type; + + ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type); + } + else if( CV_IS_IMAGE( arr )) + { + IplImage* img = (IplImage*)arr; + int pix_size = (img->depth & 255) >> 3; + int width, height; + ptr = (uchar*)img->imageData; + + if( img->dataOrder == 0 ) + pix_size *= img->nChannels; + + if( img->roi ) + { + width = img->roi->width; + height = img->roi->height; + + ptr += img->roi->yOffset*img->widthStep + + img->roi->xOffset*pix_size; + + if( img->dataOrder ) + { + int coi = img->roi->coi; + if( !coi ) + CV_Error( CV_BadCOI, + "COI must be non-null in case of planar images" ); + ptr += (coi - 1)*img->imageSize; + } + } + else + { + width = img->width; + height = img->height; + } + + if( (unsigned)y >= (unsigned)height || + (unsigned)x >= (unsigned)width ) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + ptr += y*img->widthStep + x*pix_size; + + if( _type ) + { + int type = IPL2CV_DEPTH(img->depth); + if( type < 0 || (unsigned)(img->nChannels - 1) > 3 ) + CV_Error( CV_StsUnsupportedFormat, "" ); + + *_type = CV_MAKETYPE( type, img->nChannels ); + } + } + else if( CV_IS_MATND( arr )) + { + CvMatND* mat = (CvMatND*)arr; + + if( mat->dims != 2 || + (unsigned)y >= (unsigned)(mat->dim[0].size) || + (unsigned)x >= (unsigned)(mat->dim[1].size) ) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + ptr = mat->data.ptr + (size_t)y*mat->dim[0].step + x*mat->dim[1].step; + if( _type ) + *_type = CV_MAT_TYPE(mat->type); + } + else if( CV_IS_SPARSE_MAT( arr )) + { + int idx[] = { y, x }; + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, _type, 1, 0 ); + } + else + { + CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" ); + } + + return ptr; +} + + +// Returns pointer to specified element of 3d array +CV_IMPL uchar* +cvPtr3D( const CvArr* arr, int z, int y, int x, int* _type ) +{ + uchar* ptr = 0; + if( CV_IS_MATND( arr )) + { + CvMatND* mat = (CvMatND*)arr; + + if( mat->dims != 3 || + (unsigned)z >= (unsigned)(mat->dim[0].size) || + (unsigned)y >= (unsigned)(mat->dim[1].size) || + (unsigned)x >= (unsigned)(mat->dim[2].size) ) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + ptr = mat->data.ptr + (size_t)z*mat->dim[0].step + + (size_t)y*mat->dim[1].step + x*mat->dim[2].step; + + if( _type ) + *_type = CV_MAT_TYPE(mat->type); + } + else if( CV_IS_SPARSE_MAT( arr )) + { + int idx[] = { z, y, x }; + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, _type, 1, 0 ); + } + else + { + CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" ); + } + + return ptr; +} + + +// Returns pointer to specified element of n-d array +CV_IMPL uchar* +cvPtrND( const CvArr* arr, const int* idx, int* _type, + int create_node, unsigned* precalc_hashval ) +{ + uchar* ptr = 0; + if( !idx ) + CV_Error( CV_StsNullPtr, "NULL pointer to indices" ); + + if( CV_IS_SPARSE_MAT( arr )) + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, + _type, create_node, precalc_hashval ); + else if( CV_IS_MATND( arr )) + { + CvMatND* mat = (CvMatND*)arr; + int i; + ptr = mat->data.ptr; + + for( i = 0; i < mat->dims; i++ ) + { + if( (unsigned)idx[i] >= (unsigned)(mat->dim[i].size) ) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + ptr += (size_t)idx[i]*mat->dim[i].step; + } + + if( _type ) + *_type = CV_MAT_TYPE(mat->type); + } + else if( CV_IS_MAT_HDR(arr) || CV_IS_IMAGE_HDR(arr) ) + ptr = cvPtr2D( arr, idx[0], idx[1], _type ); + else + CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" ); + + return ptr; +} + + +// Returns specifed element of n-D array given linear index +CV_IMPL CvScalar +cvGet1D( const CvArr* arr, int idx ) +{ + CvScalar scalar = {{0,0,0,0}}; + int type = 0; + uchar* ptr; + + if( CV_IS_MAT( arr ) && CV_IS_MAT_CONT( ((CvMat*)arr)->type )) + { + CvMat* mat = (CvMat*)arr; + + type = CV_MAT_TYPE(mat->type); + int pix_size = CV_ELEM_SIZE(type); + + // the first part is mul-free sufficient check + // that the index is within the matrix + if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) && + (unsigned)idx >= (unsigned)(mat->rows*mat->cols)) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + ptr = mat->data.ptr + (size_t)idx*pix_size; + } + else if( !CV_IS_SPARSE_MAT( arr ) || ((CvSparseMat*)arr)->dims > 1 ) + ptr = cvPtr1D( arr, idx, &type ); + else + ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, &type, 0, 0 ); + + if( ptr ) + cvRawDataToScalar( ptr, type, &scalar ); + + return scalar; +} + + +// Returns specifed element of 2D array +CV_IMPL CvScalar +cvGet2D( const CvArr* arr, int y, int x ) +{ + CvScalar scalar = {{0,0,0,0}}; + int type = 0; + uchar* ptr; + + if( CV_IS_MAT( arr )) + { + CvMat* mat = (CvMat*)arr; + + if( (unsigned)y >= (unsigned)(mat->rows) || + (unsigned)x >= (unsigned)(mat->cols) ) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + type = CV_MAT_TYPE(mat->type); + ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type); + } + else if( !CV_IS_SPARSE_MAT( arr )) + ptr = cvPtr2D( arr, y, x, &type ); + else + { + int idx[] = { y, x }; + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 ); + } + + if( ptr ) + cvRawDataToScalar( ptr, type, &scalar ); + + return scalar; +} + + +// Returns specifed element of 3D array +CV_IMPL CvScalar +cvGet3D( const CvArr* arr, int z, int y, int x ) +{ + CvScalar scalar = {{0,0,0,0}}; + int type = 0; + uchar* ptr; + + if( !CV_IS_SPARSE_MAT( arr )) + ptr = cvPtr3D( arr, z, y, x, &type ); + else + { + int idx[] = { z, y, x }; + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 ); + } + + if( ptr ) + cvRawDataToScalar( ptr, type, &scalar ); + return scalar; +} + + +// Returns specifed element of nD array +CV_IMPL CvScalar +cvGetND( const CvArr* arr, const int* idx ) +{ + CvScalar scalar = {{0,0,0,0}}; + int type = 0; + uchar* ptr; + + if( !CV_IS_SPARSE_MAT( arr )) + ptr = cvPtrND( arr, idx, &type ); + else + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 ); + + if( ptr ) + cvRawDataToScalar( ptr, type, &scalar ); + + return scalar; +} + + +// Returns specifed element of n-D array given linear index +CV_IMPL double +cvGetReal1D( const CvArr* arr, int idx ) +{ + double value = 0; + int type = 0; + uchar* ptr; + + if( CV_IS_MAT( arr ) && CV_IS_MAT_CONT( ((CvMat*)arr)->type )) + { + CvMat* mat = (CvMat*)arr; + + type = CV_MAT_TYPE(mat->type); + int pix_size = CV_ELEM_SIZE(type); + + // the first part is mul-free sufficient check + // that the index is within the matrix + if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) && + (unsigned)idx >= (unsigned)(mat->rows*mat->cols)) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + ptr = mat->data.ptr + (size_t)idx*pix_size; + } + else if( !CV_IS_SPARSE_MAT( arr ) || ((CvSparseMat*)arr)->dims > 1 ) + ptr = cvPtr1D( arr, idx, &type ); + else + ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, &type, 0, 0 ); + + if( ptr ) + { + if( CV_MAT_CN( type ) > 1 ) + CV_Error( CV_BadNumChannels, "cvGetReal* support only single-channel arrays" ); + + value = icvGetReal( ptr, type ); + } + return value; +} + + +// Returns specifed element of 2D array +CV_IMPL double +cvGetReal2D( const CvArr* arr, int y, int x ) +{ + double value = 0; + int type = 0; + uchar* ptr; + + if( CV_IS_MAT( arr )) + { + CvMat* mat = (CvMat*)arr; + + if( (unsigned)y >= (unsigned)(mat->rows) || + (unsigned)x >= (unsigned)(mat->cols) ) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + type = CV_MAT_TYPE(mat->type); + ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type); + } + else if( !CV_IS_SPARSE_MAT( arr )) + ptr = cvPtr2D( arr, y, x, &type ); + else + { + int idx[] = { y, x }; + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 ); + } + + if( ptr ) + { + if( CV_MAT_CN( type ) > 1 ) + CV_Error( CV_BadNumChannels, "cvGetReal* support only single-channel arrays" ); + + value = icvGetReal( ptr, type ); + } + + return value; +} + + +// Returns specifed element of 3D array +CV_IMPL double +cvGetReal3D( const CvArr* arr, int z, int y, int x ) +{ + double value = 0; + int type = 0; + uchar* ptr; + + if( !CV_IS_SPARSE_MAT( arr )) + ptr = cvPtr3D( arr, z, y, x, &type ); + else + { + int idx[] = { z, y, x }; + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 ); + } + + if( ptr ) + { + if( CV_MAT_CN( type ) > 1 ) + CV_Error( CV_BadNumChannels, "cvGetReal* support only single-channel arrays" ); + + value = icvGetReal( ptr, type ); + } + + return value; +} + + +// Returns specifed element of nD array +CV_IMPL double +cvGetRealND( const CvArr* arr, const int* idx ) +{ + double value = 0; + int type = 0; + uchar* ptr; + + if( !CV_IS_SPARSE_MAT( arr )) + ptr = cvPtrND( arr, idx, &type ); + else + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 ); + + if( ptr ) + { + if( CV_MAT_CN( type ) > 1 ) + CV_Error( CV_BadNumChannels, "cvGetReal* support only single-channel arrays" ); + + value = icvGetReal( ptr, type ); + } + + return value; +} + + +// Assigns new value to specifed element of nD array given linear index +CV_IMPL void +cvSet1D( CvArr* arr, int idx, CvScalar scalar ) +{ + int type = 0; + uchar* ptr; + + if( CV_IS_MAT( arr ) && CV_IS_MAT_CONT( ((CvMat*)arr)->type )) + { + CvMat* mat = (CvMat*)arr; + + type = CV_MAT_TYPE(mat->type); + int pix_size = CV_ELEM_SIZE(type); + + // the first part is mul-free sufficient check + // that the index is within the matrix + if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) && + (unsigned)idx >= (unsigned)(mat->rows*mat->cols)) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + ptr = mat->data.ptr + (size_t)idx*pix_size; + } + else if( !CV_IS_SPARSE_MAT( arr ) || ((CvSparseMat*)arr)->dims > 1 ) + ptr = cvPtr1D( arr, idx, &type ); + else + ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, &type, -1, 0 ); + + cvScalarToRawData( &scalar, ptr, type ); +} + + +// Assigns new value to specifed element of 2D array +CV_IMPL void +cvSet2D( CvArr* arr, int y, int x, CvScalar scalar ) +{ + int type = 0; + uchar* ptr; + + if( CV_IS_MAT( arr )) + { + CvMat* mat = (CvMat*)arr; + + if( (unsigned)y >= (unsigned)(mat->rows) || + (unsigned)x >= (unsigned)(mat->cols) ) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + type = CV_MAT_TYPE(mat->type); + ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type); + } + else if( !CV_IS_SPARSE_MAT( arr )) + ptr = cvPtr2D( arr, y, x, &type ); + else + { + int idx[] = { y, x }; + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 ); + } + cvScalarToRawData( &scalar, ptr, type ); +} + + +// Assigns new value to specifed element of 3D array +CV_IMPL void +cvSet3D( CvArr* arr, int z, int y, int x, CvScalar scalar ) +{ + int type = 0; + uchar* ptr; + + if( !CV_IS_SPARSE_MAT( arr )) + ptr = cvPtr3D( arr, z, y, x, &type ); + else + { + int idx[] = { z, y, x }; + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 ); + } + cvScalarToRawData( &scalar, ptr, type ); +} + + +// Assigns new value to specifed element of nD array +CV_IMPL void +cvSetND( CvArr* arr, const int* idx, CvScalar scalar ) +{ + int type = 0; + uchar* ptr; + + if( !CV_IS_SPARSE_MAT( arr )) + ptr = cvPtrND( arr, idx, &type ); + else + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 ); + cvScalarToRawData( &scalar, ptr, type ); +} + + +CV_IMPL void +cvSetReal1D( CvArr* arr, int idx, double value ) +{ + int type = 0; + uchar* ptr; + + if( CV_IS_MAT( arr ) && CV_IS_MAT_CONT( ((CvMat*)arr)->type )) + { + CvMat* mat = (CvMat*)arr; + + type = CV_MAT_TYPE(mat->type); + int pix_size = CV_ELEM_SIZE(type); + + // the first part is mul-free sufficient check + // that the index is within the matrix + if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) && + (unsigned)idx >= (unsigned)(mat->rows*mat->cols)) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + ptr = mat->data.ptr + (size_t)idx*pix_size; + } + else if( !CV_IS_SPARSE_MAT( arr ) || ((CvSparseMat*)arr)->dims > 1 ) + ptr = cvPtr1D( arr, idx, &type ); + else + ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, &type, -1, 0 ); + + if( CV_MAT_CN( type ) > 1 ) + CV_Error( CV_BadNumChannels, "cvSetReal* support only single-channel arrays" ); + + if( ptr ) + icvSetReal( value, ptr, type ); +} + + +CV_IMPL void +cvSetReal2D( CvArr* arr, int y, int x, double value ) +{ + int type = 0; + uchar* ptr; + + if( CV_IS_MAT( arr )) + { + CvMat* mat = (CvMat*)arr; + + if( (unsigned)y >= (unsigned)(mat->rows) || + (unsigned)x >= (unsigned)(mat->cols) ) + CV_Error( CV_StsOutOfRange, "index is out of range" ); + + type = CV_MAT_TYPE(mat->type); + ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type); + } + else if( !CV_IS_SPARSE_MAT( arr )) + { + ptr = cvPtr2D( arr, y, x, &type ); + } + else + { + int idx[] = { y, x }; + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 ); + } + if( CV_MAT_CN( type ) > 1 ) + CV_Error( CV_BadNumChannels, "cvSetReal* support only single-channel arrays" ); + + if( ptr ) + icvSetReal( value, ptr, type ); +} + + +CV_IMPL void +cvSetReal3D( CvArr* arr, int z, int y, int x, double value ) +{ + int type = 0; + uchar* ptr; + + if( !CV_IS_SPARSE_MAT( arr )) + ptr = cvPtr3D( arr, z, y, x, &type ); + else + { + int idx[] = { z, y, x }; + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 ); + } + if( CV_MAT_CN( type ) > 1 ) + CV_Error( CV_BadNumChannels, "cvSetReal* support only single-channel arrays" ); + + if( ptr ) + icvSetReal( value, ptr, type ); +} + + +CV_IMPL void +cvSetRealND( CvArr* arr, const int* idx, double value ) +{ + int type = 0; + uchar* ptr; + + if( !CV_IS_SPARSE_MAT( arr )) + ptr = cvPtrND( arr, idx, &type ); + else + ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 ); + + if( CV_MAT_CN( type ) > 1 ) + CV_Error( CV_BadNumChannels, "cvSetReal* support only single-channel arrays" ); + + if( ptr ) + icvSetReal( value, ptr, type ); +} + + +CV_IMPL void +cvClearND( CvArr* arr, const int* idx ) +{ + if( !CV_IS_SPARSE_MAT( arr )) + { + int type; + uchar* ptr; + ptr = cvPtrND( arr, idx, &type ); + if( ptr ) + memset( ptr, 0, CV_ELEM_SIZE(type) ); + } + else + icvDeleteNode( (CvSparseMat*)arr, idx, 0 ); +} + + +/****************************************************************************************\ +* Conversion to CvMat or IplImage * +\****************************************************************************************/ + +// convert array (CvMat or IplImage) to CvMat +CV_IMPL CvMat* +cvGetMat( const CvArr* array, CvMat* mat, + int* pCOI, int allowND ) +{ + CvMat* result = 0; + CvMat* src = (CvMat*)array; + int coi = 0; + + if( !mat || !src ) + CV_Error( CV_StsNullPtr, "NULL array pointer is passed" ); + + if( CV_IS_MAT_HDR(src)) + { + if( !src->data.ptr ) + CV_Error( CV_StsNullPtr, "The matrix has NULL data pointer" ); + + result = (CvMat*)src; + } + else if( CV_IS_IMAGE_HDR(src) ) + { + const IplImage* img = (const IplImage*)src; + int depth, order; + + if( img->imageData == 0 ) + CV_Error( CV_StsNullPtr, "The image has NULL data pointer" ); + + depth = IPL2CV_DEPTH( img->depth ); + if( depth < 0 ) + CV_Error( CV_BadDepth, "" ); + + order = img->dataOrder & (img->nChannels > 1 ? -1 : 0); + + if( img->roi ) + { + if( order == IPL_DATA_ORDER_PLANE ) + { + int type = depth; + + if( img->roi->coi == 0 ) + CV_Error( CV_StsBadFlag, + "Images with planar data layout should be used with COI selected" ); + + cvInitMatHeader( mat, img->roi->height, + img->roi->width, type, + img->imageData + (img->roi->coi-1)*img->imageSize + + img->roi->yOffset*img->widthStep + + img->roi->xOffset*CV_ELEM_SIZE(type), + img->widthStep ); + } + else /* pixel order */ + { + int type = CV_MAKETYPE( depth, img->nChannels ); + coi = img->roi->coi; + + if( img->nChannels > CV_CN_MAX ) + CV_Error( CV_BadNumChannels, + "The image is interleaved and has over CV_CN_MAX channels" ); + + cvInitMatHeader( mat, img->roi->height, img->roi->width, + type, img->imageData + + img->roi->yOffset*img->widthStep + + img->roi->xOffset*CV_ELEM_SIZE(type), + img->widthStep ); + } + } + else + { + int type = CV_MAKETYPE( depth, img->nChannels ); + + if( order != IPL_DATA_ORDER_PIXEL ) + CV_Error( CV_StsBadFlag, "Pixel order should be used with coi == 0" ); + + cvInitMatHeader( mat, img->height, img->width, type, + img->imageData, img->widthStep ); + } + + result = mat; + } + else if( allowND && CV_IS_MATND_HDR(src) ) + { + CvMatND* matnd = (CvMatND*)src; + int i; + int size1 = matnd->dim[0].size, size2 = 1; + + if( !src->data.ptr ) + CV_Error( CV_StsNullPtr, "Input array has NULL data pointer" ); + + if( !CV_IS_MAT_CONT( matnd->type )) + CV_Error( CV_StsBadArg, "Only continuous nD arrays are supported here" ); + + if( matnd->dims > 2 ) + for( i = 1; i < matnd->dims; i++ ) + size2 *= matnd->dim[i].size; + else + size2 = matnd->dims == 1 ? 1 : matnd->dim[1].size; + + mat->refcount = 0; + mat->hdr_refcount = 0; + mat->data.ptr = matnd->data.ptr; + mat->rows = size1; + mat->cols = size2; + mat->type = CV_MAT_TYPE(matnd->type) | CV_MAT_MAGIC_VAL | CV_MAT_CONT_FLAG; + mat->step = size2*CV_ELEM_SIZE(matnd->type); + mat->step &= size1 > 1 ? -1 : 0; + + icvCheckHuge( mat ); + result = mat; + } + else + CV_Error( CV_StsBadFlag, "Unrecognized or unsupported array type" ); + + if( pCOI ) + *pCOI = coi; + + return result; +} + + +CV_IMPL CvArr* +cvReshapeMatND( const CvArr* arr, + int sizeof_header, CvArr* _header, + int new_cn, int new_dims, int* new_sizes ) +{ + CvArr* result = 0; + int dims, coi = 0; + + if( !arr || !_header ) + CV_Error( CV_StsNullPtr, "NULL pointer to array or destination header" ); + + if( new_cn == 0 && new_dims == 0 ) + CV_Error( CV_StsBadArg, "None of array parameters is changed: dummy call?" ); + + dims = cvGetDims( arr ); + + if( new_dims == 0 ) + { + new_sizes = 0; + new_dims = dims; + } + else if( new_dims == 1 ) + { + new_sizes = 0; + } + else + { + if( new_dims <= 0 || new_dims > CV_MAX_DIM ) + CV_Error( CV_StsOutOfRange, "Non-positive or too large number of dimensions" ); + if( !new_sizes ) + CV_Error( CV_StsNullPtr, "New dimension sizes are not specified" ); + } + + if( new_dims <= 2 ) + { + CvMat* mat = (CvMat*)arr; + CvMat header; + int* refcount = 0; + int hdr_refcount = 0; + int total_width, new_rows, cn; + + if( sizeof_header != sizeof(CvMat) && sizeof_header != sizeof(CvMatND) ) + CV_Error( CV_StsBadArg, "The output header should be CvMat or CvMatND" ); + + if( mat == (CvMat*)_header ) + { + refcount = mat->refcount; + hdr_refcount = mat->hdr_refcount; + } + + if( !CV_IS_MAT( mat )) + mat = cvGetMat( mat, &header, &coi, 1 ); + + cn = CV_MAT_CN( mat->type ); + total_width = mat->cols * cn; + + if( new_cn == 0 ) + new_cn = cn; + + if( new_sizes ) + new_rows = new_sizes[0]; + else if( new_dims == 1 ) + new_rows = total_width*mat->rows/new_cn; + else + { + new_rows = mat->rows; + if( new_cn > total_width ) + new_rows = mat->rows * total_width / new_cn; + } + + if( new_rows != mat->rows ) + { + int total_size = total_width * mat->rows; + + if( !CV_IS_MAT_CONT( mat->type )) + CV_Error( CV_BadStep, + "The matrix is not continuous so the number of rows can not be changed" ); + + total_width = total_size / new_rows; + + if( total_width * new_rows != total_size ) + CV_Error( CV_StsBadArg, "The total number of matrix elements " + "is not divisible by the new number of rows" ); + } + + header.rows = new_rows; + header.cols = total_width / new_cn; + + if( header.cols * new_cn != total_width || + (new_sizes && header.cols != new_sizes[1]) ) + CV_Error( CV_StsBadArg, "The total matrix width is not " + "divisible by the new number of columns" ); + + header.type = (mat->type & ~CV_MAT_TYPE_MASK) | CV_MAKETYPE(mat->type, new_cn); + header.step = header.cols * CV_ELEM_SIZE(mat->type); + header.step &= new_rows > 1 ? -1 : 0; + header.refcount = refcount; + header.hdr_refcount = hdr_refcount; + + if( sizeof_header == sizeof(CvMat) ) + *(CvMat*)_header = header; + else + { + CvMatND* __header = (CvMatND*)_header; + cvGetMatND(&header, __header, 0); + if( new_dims > 0 ) + __header->dims = new_dims; + } + } + else + { + CvMatND* header = (CvMatND*)_header; + + if( sizeof_header != sizeof(CvMatND)) + CV_Error( CV_StsBadSize, "The output header should be CvMatND" ); + + if( !new_sizes ) + { + if( !CV_IS_MATND( arr )) + CV_Error( CV_StsBadArg, "The input array must be CvMatND" ); + + { + CvMatND* mat = (CvMatND*)arr; + assert( new_cn > 0 ); + int last_dim_size = mat->dim[mat->dims-1].size*CV_MAT_CN(mat->type); + int new_size = last_dim_size/new_cn; + + if( new_size*new_cn != last_dim_size ) + CV_Error( CV_StsBadArg, + "The last dimension full size is not divisible by new number of channels"); + + if( mat != header ) + { + memcpy( header, mat, sizeof(*header)); + header->refcount = 0; + header->hdr_refcount = 0; + } + + header->dim[header->dims-1].size = new_size; + header->type = (header->type & ~CV_MAT_TYPE_MASK) | CV_MAKETYPE(header->type, new_cn); + } + } + else + { + CvMatND stub; + CvMatND* mat = (CvMatND*)arr; + int i, size1, size2; + int step; + + if( new_cn != 0 ) + CV_Error( CV_StsBadArg, + "Simultaneous change of shape and number of channels is not supported. " + "Do it by 2 separate calls" ); + + if( !CV_IS_MATND( mat )) + { + cvGetMatND( mat, &stub, &coi ); + mat = &stub; + } + + if( CV_IS_MAT_CONT( mat->type )) + CV_Error( CV_StsBadArg, "Non-continuous nD arrays are not supported" ); + + size1 = mat->dim[0].size; + for( i = 1; i < dims; i++ ) + size1 *= mat->dim[i].size; + + size2 = 1; + for( i = 0; i < new_dims; i++ ) + { + if( new_sizes[i] <= 0 ) + CV_Error( CV_StsBadSize, + "One of new dimension sizes is non-positive" ); + size2 *= new_sizes[i]; + } + + if( size1 != size2 ) + CV_Error( CV_StsBadSize, + "Number of elements in the original and reshaped array is different" ); + + if( header != mat ) + { + header->refcount = 0; + header->hdr_refcount = 0; + } + + header->dims = new_dims; + header->type = mat->type; + header->data.ptr = mat->data.ptr; + step = CV_ELEM_SIZE(header->type); + + for( i = new_dims - 1; i >= 0; i-- ) + { + header->dim[i].size = new_sizes[i]; + header->dim[i].step = step; + step *= new_sizes[i]; + } + } + } + + if( coi ) + CV_Error( CV_BadCOI, "COI is not supported by this operation" ); + + result = _header; + return result; +} + + +CV_IMPL CvMat* +cvReshape( const CvArr* array, CvMat* header, + int new_cn, int new_rows ) +{ + CvMat* result = 0; + CvMat *mat = (CvMat*)array; + int total_width, new_width; + + if( !header ) + CV_Error( CV_StsNullPtr, "" ); + + if( !CV_IS_MAT( mat )) + { + int coi = 0; + mat = cvGetMat( mat, header, &coi, 1 ); + if( coi ) + CV_Error( CV_BadCOI, "COI is not supported" ); + } + + if( new_cn == 0 ) + new_cn = CV_MAT_CN(mat->type); + else if( (unsigned)(new_cn - 1) > 3 ) + CV_Error( CV_BadNumChannels, "" ); + + if( mat != header ) + { + int hdr_refcount = header->hdr_refcount; + *header = *mat; + header->refcount = 0; + header->hdr_refcount = hdr_refcount; + } + + total_width = mat->cols * CV_MAT_CN( mat->type ); + + if( (new_cn > total_width || total_width % new_cn != 0) && new_rows == 0 ) + new_rows = mat->rows * total_width / new_cn; + + if( new_rows == 0 || new_rows == mat->rows ) + { + header->rows = mat->rows; + header->step = mat->step; + } + else + { + int total_size = total_width * mat->rows; + if( !CV_IS_MAT_CONT( mat->type )) + CV_Error( CV_BadStep, + "The matrix is not continuous, thus its number of rows can not be changed" ); + + if( (unsigned)new_rows > (unsigned)total_size ) + CV_Error( CV_StsOutOfRange, "Bad new number of rows" ); + + total_width = total_size / new_rows; + + if( total_width * new_rows != total_size ) + CV_Error( CV_StsBadArg, "The total number of matrix elements " + "is not divisible by the new number of rows" ); + + header->rows = new_rows; + header->step = total_width * CV_ELEM_SIZE1(mat->type); + } + + new_width = total_width / new_cn; + + if( new_width * new_cn != total_width ) + CV_Error( CV_BadNumChannels, + "The total width is not divisible by the new number of channels" ); + + header->cols = new_width; + header->type = (mat->type & ~CV_MAT_TYPE_MASK) | CV_MAKETYPE(mat->type, new_cn); + + result = header; + return result; +} + + +// convert array (CvMat or IplImage) to IplImage +CV_IMPL IplImage* +cvGetImage( const CvArr* array, IplImage* img ) +{ + IplImage* result = 0; + const IplImage* src = (const IplImage*)array; + int depth; + + if( !img ) + CV_Error( CV_StsNullPtr, "" ); + + if( !CV_IS_IMAGE_HDR(src) ) + { + const CvMat* mat = (const CvMat*)src; + + if( !CV_IS_MAT_HDR(mat)) + CV_Error( CV_StsBadFlag, "" ); + + if( mat->data.ptr == 0 ) + CV_Error( CV_StsNullPtr, "" ); + + depth = cvIplDepth(mat->type); + + cvInitImageHeader( img, cvSize(mat->cols, mat->rows), + depth, CV_MAT_CN(mat->type) ); + cvSetData( img, mat->data.ptr, mat->step ); + + result = img; + } + else + { + result = (IplImage*)src; + } + + return result; +} + + +/****************************************************************************************\ +* IplImage-specific functions * +\****************************************************************************************/ + +static IplROI* icvCreateROI( int coi, int xOffset, int yOffset, int width, int height ) +{ + IplROI *roi = 0; + if( !CvIPL.createROI ) + { + roi = (IplROI*)cvAlloc( sizeof(*roi)); + + roi->coi = coi; + roi->xOffset = xOffset; + roi->yOffset = yOffset; + roi->width = width; + roi->height = height; + } + else + { + roi = CvIPL.createROI( coi, xOffset, yOffset, width, height ); + } + + return roi; +} + +static void +icvGetColorModel( int nchannels, const char** colorModel, const char** channelSeq ) +{ + static const char* tab[][2] = + { + {"GRAY", "GRAY"}, + {"",""}, + {"RGB","BGR"}, + {"RGB","BGRA"} + }; + + nchannels--; + *colorModel = *channelSeq = ""; + + if( (unsigned)nchannels <= 3 ) + { + *colorModel = tab[nchannels][0]; + *channelSeq = tab[nchannels][1]; + } +} + + +// create IplImage header +CV_IMPL IplImage * +cvCreateImageHeader( CvSize size, int depth, int channels ) +{ + IplImage *img = 0; + + if( !CvIPL.createHeader ) + { + img = (IplImage *)cvAlloc( sizeof( *img )); + cvInitImageHeader( img, size, depth, channels, IPL_ORIGIN_TL, + CV_DEFAULT_IMAGE_ROW_ALIGN ); + } + else + { + const char *colorModel, *channelSeq; + + icvGetColorModel( channels, &colorModel, &channelSeq ); + + img = CvIPL.createHeader( channels, 0, depth, (char*)colorModel, (char*)channelSeq, + IPL_DATA_ORDER_PIXEL, IPL_ORIGIN_TL, + CV_DEFAULT_IMAGE_ROW_ALIGN, + size.width, size.height, 0, 0, 0, 0 ); + } + + return img; +} + + +// create IplImage header and allocate underlying data +CV_IMPL IplImage * +cvCreateImage( CvSize size, int depth, int channels ) +{ + IplImage *img = cvCreateImageHeader( size, depth, channels ); + assert( img ); + cvCreateData( img ); + + return img; +} + + +// initalize IplImage header, allocated by the user +CV_IMPL IplImage* +cvInitImageHeader( IplImage * image, CvSize size, int depth, + int channels, int origin, int align ) +{ + const char *colorModel, *channelSeq; + + if( !image ) + CV_Error( CV_HeaderIsNull, "null pointer to header" ); + + memset( image, 0, sizeof( *image )); + image->nSize = sizeof( *image ); + + icvGetColorModel( channels, &colorModel, &channelSeq ); + strncpy( image->colorModel, colorModel, 4 ); + strncpy( image->channelSeq, channelSeq, 4 ); + + if( size.width < 0 || size.height < 0 ) + CV_Error( CV_BadROISize, "Bad input roi" ); + + if( (depth != (int)IPL_DEPTH_1U && depth != (int)IPL_DEPTH_8U && + depth != (int)IPL_DEPTH_8S && depth != (int)IPL_DEPTH_16U && + depth != (int)IPL_DEPTH_16S && depth != (int)IPL_DEPTH_32S && + depth != (int)IPL_DEPTH_32F && depth != (int)IPL_DEPTH_64F) || + channels < 0 ) + CV_Error( CV_BadDepth, "Unsupported format" ); + if( origin != CV_ORIGIN_BL && origin != CV_ORIGIN_TL ) + CV_Error( CV_BadOrigin, "Bad input origin" ); + + if( align != 4 && align != 8 ) + CV_Error( CV_BadAlign, "Bad input align" ); + + image->width = size.width; + image->height = size.height; + + if( image->roi ) + { + image->roi->coi = 0; + image->roi->xOffset = image->roi->yOffset = 0; + image->roi->width = size.width; + image->roi->height = size.height; + } + + image->nChannels = MAX( channels, 1 ); + image->depth = depth; + image->align = align; + image->widthStep = (((image->width * image->nChannels * + (image->depth & ~IPL_DEPTH_SIGN) + 7)/8)+ align - 1) & (~(align - 1)); + image->origin = origin; + image->imageSize = image->widthStep * image->height; + + return image; +} + + +CV_IMPL void +cvReleaseImageHeader( IplImage** image ) +{ + if( !image ) + CV_Error( CV_StsNullPtr, "" ); + + if( *image ) + { + IplImage* img = *image; + *image = 0; + + if( !CvIPL.deallocate ) + { + cvFree( &img->roi ); + cvFree( &img ); + } + else + { + CvIPL.deallocate( img, IPL_IMAGE_HEADER | IPL_IMAGE_ROI ); + } + } +} + + +CV_IMPL void +cvReleaseImage( IplImage ** image ) +{ + if( !image ) + CV_Error( CV_StsNullPtr, "" ); + + if( *image ) + { + IplImage* img = *image; + *image = 0; + + cvReleaseData( img ); + cvReleaseImageHeader( &img ); + } +} + + +CV_IMPL void +cvSetImageROI( IplImage* image, CvRect rect ) +{ + if( !image ) + CV_Error( CV_HeaderIsNull, "" ); + + // allow zero ROI width or height + CV_Assert( rect.width >= 0 && rect.height >= 0 && + rect.x < image->width && rect.y < image->height && + rect.x + rect.width >= (int)(rect.width > 0) && + rect.y + rect.height >= (int)(rect.height > 0) ); + + rect.width += rect.x; + rect.height += rect.y; + + rect.x = std::max(rect.x, 0); + rect.y = std::max(rect.y, 0); + rect.width = std::min(rect.width, image->width); + rect.height = std::min(rect.height, image->height); + + rect.width -= rect.x; + rect.height -= rect.y; + + if( image->roi ) + { + image->roi->xOffset = rect.x; + image->roi->yOffset = rect.y; + image->roi->width = rect.width; + image->roi->height = rect.height; + } + else + image->roi = icvCreateROI( 0, rect.x, rect.y, rect.width, rect.height ); +} + + +CV_IMPL void +cvResetImageROI( IplImage* image ) +{ + if( !image ) + CV_Error( CV_HeaderIsNull, "" ); + + if( image->roi ) + { + if( !CvIPL.deallocate ) + { + cvFree( &image->roi ); + } + else + { + CvIPL.deallocate( image, IPL_IMAGE_ROI ); + image->roi = 0; + } + } +} + + +CV_IMPL CvRect +cvGetImageROI( const IplImage* img ) +{ + CvRect rect = { 0, 0, 0, 0 }; + if( !img ) + CV_Error( CV_StsNullPtr, "Null pointer to image" ); + + if( img->roi ) + rect = cvRect( img->roi->xOffset, img->roi->yOffset, + img->roi->width, img->roi->height ); + else + rect = cvRect( 0, 0, img->width, img->height ); + + return rect; +} + + +CV_IMPL void +cvSetImageCOI( IplImage* image, int coi ) +{ + if( !image ) + CV_Error( CV_HeaderIsNull, "" ); + + if( (unsigned)coi > (unsigned)(image->nChannels) ) + CV_Error( CV_BadCOI, "" ); + + if( image->roi || coi != 0 ) + { + if( image->roi ) + { + image->roi->coi = coi; + } + else + { + image->roi = icvCreateROI( coi, 0, 0, image->width, image->height ); + } + } +} + + +CV_IMPL int +cvGetImageCOI( const IplImage* image ) +{ + if( !image ) + CV_Error( CV_HeaderIsNull, "" ); + + return image->roi ? image->roi->coi : 0; +} + + +CV_IMPL IplImage* +cvCloneImage( const IplImage* src ) +{ + IplImage* dst = 0; + + if( !CV_IS_IMAGE_HDR( src )) + CV_Error( CV_StsBadArg, "Bad image header" ); + + if( !CvIPL.cloneImage ) + { + dst = (IplImage*)cvAlloc( sizeof(*dst)); + + memcpy( dst, src, sizeof(*src)); + dst->imageData = dst->imageDataOrigin = 0; + dst->roi = 0; + + if( src->roi ) + { + dst->roi = icvCreateROI( src->roi->coi, src->roi->xOffset, + src->roi->yOffset, src->roi->width, src->roi->height ); + } + + if( src->imageData ) + { + int size = src->imageSize; + cvCreateData( dst ); + memcpy( dst->imageData, src->imageData, size ); + } + } + else + dst = CvIPL.cloneImage( src ); + + return dst; +} + + +/****************************************************************************************\ +* Additional operations on CvTermCriteria * +\****************************************************************************************/ + +CV_IMPL CvTermCriteria +cvCheckTermCriteria( CvTermCriteria criteria, double default_eps, + int default_max_iters ) +{ + CvTermCriteria crit; + + crit.type = CV_TERMCRIT_ITER|CV_TERMCRIT_EPS; + crit.max_iter = default_max_iters; + crit.epsilon = (float)default_eps; + + if( (criteria.type & ~(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER)) != 0 ) + CV_Error( CV_StsBadArg, + "Unknown type of term criteria" ); + + if( (criteria.type & CV_TERMCRIT_ITER) != 0 ) + { + if( criteria.max_iter <= 0 ) + CV_Error( CV_StsBadArg, + "Iterations flag is set and maximum number of iterations is <= 0" ); + crit.max_iter = criteria.max_iter; + } + + if( (criteria.type & CV_TERMCRIT_EPS) != 0 ) + { + if( criteria.epsilon < 0 ) + CV_Error( CV_StsBadArg, "Accuracy flag is set and epsilon is < 0" ); + + crit.epsilon = criteria.epsilon; + } + + if( (criteria.type & (CV_TERMCRIT_EPS | CV_TERMCRIT_ITER)) == 0 ) + CV_Error( CV_StsBadArg, + "Neither accuracy nor maximum iterations " + "number flags are set in criteria type" ); + + crit.epsilon = (float)MAX( 0, crit.epsilon ); + crit.max_iter = MAX( 1, crit.max_iter ); + + return crit; +} + +namespace cv +{ + +template<> void Ptr::delete_obj() +{ cvReleaseMat(&obj); } + +template<> void Ptr::delete_obj() +{ cvReleaseImage(&obj); } + +template<> void Ptr::delete_obj() +{ cvReleaseMatND(&obj); } + +template<> void Ptr::delete_obj() +{ cvReleaseSparseMat(&obj); } + +template<> void Ptr::delete_obj() +{ cvReleaseMemStorage(&obj); } + +template<> void Ptr::delete_obj() +{ cvReleaseFileStorage(&obj); } + +} + +/* End of file. */ diff --git a/core/src/cmdparser.cpp b/core/src/cmdparser.cpp new file mode 100644 index 0000000..d7be054 --- /dev/null +++ b/core/src/cmdparser.cpp @@ -0,0 +1,384 @@ +#include "precomp.hpp" + +#include +#include + +using namespace std; +using namespace cv; + +namespace { +#if 0 +static void helpParser() +{ + printf("\nThe CommandLineParser class is designed for command line arguments parsing\n" + "Keys map: \n" + "Before you start to work with CommandLineParser you have to create a map for keys.\n" + " It will look like this\n" + " const char* keys =\n" + " {\n" + " { s| string| 123asd |string parameter}\n" + " { d| digit | 100 |digit parameter }\n" + " { c|noCamera|false |without camera }\n" + " { 1| |some text|help }\n" + " { 2| |333 |another help }\n" + " };\n" + "Usage syntax: \n" + " \"{\" - start of parameter string.\n" + " \"}\" - end of parameter string\n" + " \"|\" - separator between short name, full name, default value and help\n" + "Supported syntax: \n" + " --key1=arg1 \n" + " -key2=arg2 \n" + "Usage: \n" + " Imagine that the input parameters are next:\n" + " -s=string_value --digit=250 --noCamera lena.jpg 10000\n" + " CommandLineParser parser(argc, argv, keys) - create a parser object\n" + " parser.get(\"s\" or \"string\") will return you first parameter value\n" + " parser.get(\"s\", false or \"string\", false) will return you first parameter value\n" + " without spaces in end and begin\n" + " parser.get(\"d\" or \"digit\") will return you second parameter value.\n" + " It also works with 'unsigned int', 'double', and 'float' types>\n" + " parser.get(\"c\" or \"noCamera\") will return you true .\n" + " If you enter this key in commandline>\n" + " It return you false otherwise.\n" + " parser.get(\"1\") will return you the first argument without parameter (lena.jpg) \n" + " parser.get(\"2\") will return you the second argument without parameter (10000)\n" + " It also works with 'unsigned int', 'double', and 'float' types \n" + ); +} +#endif + +vector split_string(const string& str, const string& delimiters) +{ + vector res; + + string split_str = str; + size_t pos_delim = split_str.find(delimiters); + + while ( pos_delim != string::npos) + { + if (pos_delim == 0) + { + res.push_back(""); + split_str.erase(0, 1); + } + else + { + res.push_back(split_str.substr(0, pos_delim)); + split_str.erase(0, pos_delim + 1); + } + + pos_delim = split_str.find(delimiters); + } + + res.push_back(split_str); + + return res; +} + +string del_space(string name) +{ + while ((name.find_first_of(' ') == 0) && (name.length() > 0)) + name.erase(0, 1); + + while ((name.find_last_of(' ') == (name.length() - 1)) && (name.length() > 0)) + name.erase(name.end() - 1, name.end()); + + return name; +} + +}//namespace + +CommandLineParser::CommandLineParser(int argc, const char* const argv[], const char* keys) +{ + std::string keys_buffer; + std::string values_buffer; + std::string buffer; + std::string curName; + std::vector keysVector; + std::vector paramVector; + std::map >::iterator it; + size_t flagPosition; + int currentIndex = 1; + //bool isFound = false; + bool withNoKey = false; + bool hasValueThroughEq = false; + + keys_buffer = keys; + while (!keys_buffer.empty()) + { + + flagPosition = keys_buffer.find_first_of('}'); + flagPosition++; + buffer = keys_buffer.substr(0, flagPosition); + keys_buffer.erase(0, flagPosition); + + flagPosition = buffer.find('{'); + if (flagPosition != buffer.npos) + buffer.erase(flagPosition, (flagPosition + 1)); + + flagPosition = buffer.find('}'); + if (flagPosition != buffer.npos) + buffer.erase(flagPosition); + + paramVector = split_string(buffer, "|"); + while (paramVector.size() < 4) paramVector.push_back(""); + + buffer = paramVector[0]; + buffer += '|' + paramVector[1]; + + //if (buffer == "") CV_ERROR(CV_StsBadArg, "In CommandLineParser need set short and full name"); + + paramVector.erase(paramVector.begin(), paramVector.begin() + 2); + data[buffer] = paramVector; + } + + buffer.clear(); + keys_buffer.clear(); + paramVector.clear(); + for (int i = 1; i < argc; i++) + { + if (!argv[i]) + break; + curName = argv[i]; + if (curName.find('-') == 0 && ((curName[1] < '0') || (curName[1] > '9'))) + { + while (curName.find('-') == 0) + curName.erase(curName.begin(), (curName.begin() + 1)); + } + else + withNoKey = true; + if (curName.find('=') != curName.npos) + { + hasValueThroughEq = true; + buffer = curName; + curName.erase(curName.find('=')); + buffer.erase(0, (buffer.find('=') + 1)); + } + + values_buffer = del_space(values_buffer); + + for(it = data.begin(); it != data.end(); it++) + { + keys_buffer = it->first; + keysVector = split_string(keys_buffer, "|"); + + for (size_t j = 0; j < keysVector.size(); j++) keysVector[j] = del_space(keysVector[j]); + + values_buffer = it->second[0]; + if (((curName == keysVector[0]) || (curName == keysVector[1])) && hasValueThroughEq) + { + it->second[0] = buffer; + //isFound = true; + break; + } + + if (!hasValueThroughEq && ((curName == keysVector[0]) || (curName == keysVector[1])) + && ( + values_buffer.find("false") != values_buffer.npos || + values_buffer == "" + )) + { + it->second[0] = "true"; + //isFound = true; + break; + } + + if (!hasValueThroughEq && (values_buffer.find("false") == values_buffer.npos) && + ((curName == keysVector[0]) || (curName == keysVector[1]))) + { + it->second[0] = argv[++i]; + //isFound = true; + break; + } + + + if (withNoKey) + { + std::string noKeyStr = it->first; + if(atoi(noKeyStr.c_str()) == currentIndex) + { + it->second[0] = curName; + currentIndex++; + //isFound = true; + break; + } + } + } + + withNoKey = false; + hasValueThroughEq = false; + //isFound = false; + } +} + +bool CommandLineParser::has(const std::string& keys) +{ + std::map >::iterator it; + std::vector keysVector; + + for(it = data.begin(); it != data.end(); it++) + { + keysVector = split_string(it->first, "|"); + for (size_t i = 0; i < keysVector.size(); i++) keysVector[i] = del_space(keysVector[i]); + + if (keysVector.size() == 1) keysVector.push_back(""); + + if ((del_space(keys).compare(keysVector[0]) == 0) || + (del_space(keys).compare(keysVector[1]) == 0)) + return true; + } + + return false; +} + +std::string CommandLineParser::getString(const std::string& keys) +{ + std::map >::iterator it; + std::vector valueVector; + + for(it = data.begin(); it != data.end(); it++) + { + valueVector = split_string(it->first, "|"); + for (size_t i = 0; i < valueVector.size(); i++) valueVector[i] = del_space(valueVector[i]); + + if (valueVector.size() == 1) valueVector.push_back(""); + + if ((del_space(keys).compare(valueVector[0]) == 0) || + (del_space(keys).compare(valueVector[1]) == 0)) + return it->second[0]; + } + return string(); +} + +template + _Tp CommandLineParser::fromStringNumber(const std::string& str)//the default conversion function for numbers +{ + return getData<_Tp>(str); +} + + void CommandLineParser::printParams() + { + int col_p = 30; + int col_d = 50; + + std::map >::iterator it; + std::vector keysVector; + std::string buf; + for(it = data.begin(); it != data.end(); it++) + { + keysVector = split_string(it->first, "|"); + for (size_t i = 0; i < keysVector.size(); i++) keysVector[i] = del_space(keysVector[i]); + + cout << " "; + buf = ""; + if (keysVector[0] != "") + { + buf = "-" + keysVector[0]; + if (keysVector[1] != "") buf += ", --" + keysVector[1]; + } + else if (keysVector[1] != "") buf += "--" + keysVector[1]; + if (del_space(it->second[0]) != "") buf += "=[" + del_space(it->second[0]) + "]"; + + cout << setw(col_p-2) << left << buf; + + if ((int)buf.length() > col_p-2) + { + cout << endl << " "; + cout << setw(col_p-2) << left << " "; + } + + buf = ""; + if (del_space(it->second[1]) != "") buf += del_space(it->second[1]); + + for(;;) + { + bool tr = ((int)buf.length() > col_d-2) ? true: false; + std::string::size_type pos = 0; + + if (tr) + { + pos = buf.find_first_of(' '); + for(;;) + { + if (buf.find_first_of(' ', pos + 1 ) < (std::string::size_type)(col_d-2) && + buf.find_first_of(' ', pos + 1 ) != std::string::npos) + pos = buf.find_first_of(' ', pos + 1); + else + break; + } + pos++; + cout << setw(col_d-2) << left << buf.substr(0, pos) << endl; + } + else + { + cout << setw(col_d-2) << left << buf<< endl; + break; + } + + buf.erase(0, pos); + cout << " "; + cout << setw(col_p-2) << left << " "; + } + } + } + +template<> +bool CommandLineParser::get(const std::string& name, bool space_delete) +{ + std::string str_buf = getString(name); + + if (space_delete && str_buf != "") + { + str_buf = del_space(str_buf); + } + + if (str_buf == "true") + return true; + + return false; +} +template<> +std::string CommandLineParser::analyzeValue(const std::string& str, bool space_delete) +{ + if (space_delete) + { + return del_space(str); + } + return str; +} + +template<> +int CommandLineParser::analyzeValue(const std::string& str, bool /*space_delete*/) +{ + return fromStringNumber(str); +} + +template<> +unsigned int CommandLineParser::analyzeValue(const std::string& str, bool /*space_delete*/) +{ + return fromStringNumber(str); +} + +template<> +uint64 CommandLineParser::analyzeValue(const std::string& str, bool /*space_delete*/) +{ + return fromStringNumber(str); +} + +template<> +float CommandLineParser::analyzeValue(const std::string& str, bool /*space_delete*/) +{ + return fromStringNumber(str); +} + +template<> +double CommandLineParser::analyzeValue(const std::string& str, bool /*space_delete*/) +{ + return fromStringNumber(str); +} diff --git a/core/src/convert.cpp b/core/src/convert.cpp new file mode 100644 index 0000000..8f3fb77 --- /dev/null +++ b/core/src/convert.cpp @@ -0,0 +1,1434 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +namespace cv +{ + +/****************************************************************************************\ +* split & merge * +\****************************************************************************************/ + +template static void +split_( const T* src, T** dst, int len, int cn ) +{ + int k = cn % 4 ? cn % 4 : 4; + int i, j; + if( k == 1 ) + { + T* dst0 = dst[0]; + for( i = j = 0; i < len; i++, j += cn ) + dst0[i] = src[j]; + } + else if( k == 2 ) + { + T *dst0 = dst[0], *dst1 = dst[1]; + for( i = j = 0; i < len; i++, j += cn ) + { + dst0[i] = src[j]; + dst1[i] = src[j+1]; + } + } + else if( k == 3 ) + { + T *dst0 = dst[0], *dst1 = dst[1], *dst2 = dst[2]; + for( i = j = 0; i < len; i++, j += cn ) + { + dst0[i] = src[j]; + dst1[i] = src[j+1]; + dst2[i] = src[j+2]; + } + } + else + { + T *dst0 = dst[0], *dst1 = dst[1], *dst2 = dst[2], *dst3 = dst[3]; + for( i = j = 0; i < len; i++, j += cn ) + { + dst0[i] = src[j]; dst1[i] = src[j+1]; + dst2[i] = src[j+2]; dst3[i] = src[j+3]; + } + } + + for( ; k < cn; k += 4 ) + { + T *dst0 = dst[k], *dst1 = dst[k+1], *dst2 = dst[k+2], *dst3 = dst[k+3]; + for( i = 0, j = k; i < len; i++, j += cn ) + { + dst0[i] = src[j]; dst1[i] = src[j+1]; + dst2[i] = src[j+2]; dst3[i] = src[j+3]; + } + } +} + +template static void +merge_( const T** src, T* dst, int len, int cn ) +{ + int k = cn % 4 ? cn % 4 : 4; + int i, j; + if( k == 1 ) + { + const T* src0 = src[0]; + for( i = j = 0; i < len; i++, j += cn ) + dst[j] = src0[i]; + } + else if( k == 2 ) + { + const T *src0 = src[0], *src1 = src[1]; + for( i = j = 0; i < len; i++, j += cn ) + { + dst[j] = src0[i]; + dst[j+1] = src1[i]; + } + } + else if( k == 3 ) + { + const T *src0 = src[0], *src1 = src[1], *src2 = src[2]; + for( i = j = 0; i < len; i++, j += cn ) + { + dst[j] = src0[i]; + dst[j+1] = src1[i]; + dst[j+2] = src2[i]; + } + } + else + { + const T *src0 = src[0], *src1 = src[1], *src2 = src[2], *src3 = src[3]; + for( i = j = 0; i < len; i++, j += cn ) + { + dst[j] = src0[i]; dst[j+1] = src1[i]; + dst[j+2] = src2[i]; dst[j+3] = src3[i]; + } + } + + for( ; k < cn; k += 4 ) + { + const T *src0 = src[k], *src1 = src[k+1], *src2 = src[k+2], *src3 = src[k+3]; + for( i = 0, j = k; i < len; i++, j += cn ) + { + dst[j] = src0[i]; dst[j+1] = src1[i]; + dst[j+2] = src2[i]; dst[j+3] = src3[i]; + } + } +} + +static void split8u(const uchar* src, uchar** dst, int len, int cn ) +{ + split_(src, dst, len, cn); +} + +static void split16u(const ushort* src, ushort** dst, int len, int cn ) +{ + split_(src, dst, len, cn); +} + +static void split32s(const int* src, int** dst, int len, int cn ) +{ + split_(src, dst, len, cn); +} + +static void split64s(const int64* src, int64** dst, int len, int cn ) +{ + split_(src, dst, len, cn); +} + +static void merge8u(const uchar** src, uchar* dst, int len, int cn ) +{ + merge_(src, dst, len, cn); +} + +static void merge16u(const ushort** src, ushort* dst, int len, int cn ) +{ + merge_(src, dst, len, cn); +} + +static void merge32s(const int** src, int* dst, int len, int cn ) +{ + merge_(src, dst, len, cn); +} + +static void merge64s(const int64** src, int64* dst, int len, int cn ) +{ + merge_(src, dst, len, cn); +} + +typedef void (*SplitFunc)(const uchar* src, uchar** dst, int len, int cn); +typedef void (*MergeFunc)(const uchar** src, uchar* dst, int len, int cn); + +static SplitFunc splitTab[] = +{ + (SplitFunc)GET_OPTIMIZED(split8u), (SplitFunc)GET_OPTIMIZED(split8u), (SplitFunc)GET_OPTIMIZED(split16u), (SplitFunc)GET_OPTIMIZED(split16u), + (SplitFunc)GET_OPTIMIZED(split32s), (SplitFunc)GET_OPTIMIZED(split32s), (SplitFunc)GET_OPTIMIZED(split64s), 0 +}; + +static MergeFunc mergeTab[] = +{ + (MergeFunc)GET_OPTIMIZED(merge8u), (MergeFunc)GET_OPTIMIZED(merge8u), (MergeFunc)GET_OPTIMIZED(merge16u), (MergeFunc)GET_OPTIMIZED(merge16u), + (MergeFunc)GET_OPTIMIZED(merge32s), (MergeFunc)GET_OPTIMIZED(merge32s), (MergeFunc)GET_OPTIMIZED(merge64s), 0 +}; + +} + +void cv::split(const Mat& src, Mat* mv) +{ + int k, depth = src.depth(), cn = src.channels(); + if( cn == 1 ) + { + src.copyTo(mv[0]); + return; + } + + SplitFunc func = splitTab[depth]; + CV_Assert( func != 0 ); + + int esz = (int)src.elemSize(), esz1 = (int)src.elemSize1(); + int blocksize0 = (BLOCK_SIZE + esz-1)/esz; + AutoBuffer _buf((cn+1)*(sizeof(Mat*) + sizeof(uchar*)) + 16); + const Mat** arrays = (const Mat**)(uchar*)_buf; + uchar** ptrs = (uchar**)alignPtr(arrays + cn + 1, 16); + + arrays[0] = &src; + for( k = 0; k < cn; k++ ) + { + mv[k].create(src.dims, src.size, depth); + arrays[k+1] = &mv[k]; + } + + NAryMatIterator it(arrays, ptrs, cn+1); + int total = (int)it.size, blocksize = cn <= 4 ? total : std::min(total, blocksize0); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( int j = 0; j < total; j += blocksize ) + { + int bsz = std::min(total - j, blocksize); + func( ptrs[0], &ptrs[1], bsz, cn ); + + if( j + blocksize < total ) + { + ptrs[0] += bsz*esz; + for( k = 0; k < cn; k++ ) + ptrs[k+1] += bsz*esz1; + } + } + } +} + +void cv::split(InputArray _m, OutputArrayOfArrays _mv) +{ + Mat m = _m.getMat(); + if( m.empty() ) + { + _mv.release(); + return; + } + CV_Assert( !_mv.fixedType() || CV_MAT_TYPE(_mv.flags) == m.depth() ); + _mv.create(m.channels(), 1, m.depth()); + Mat* dst = &_mv.getMatRef(0); + split(m, dst); +} + +void cv::merge(const Mat* mv, size_t n, OutputArray _dst) +{ + CV_Assert( mv && n > 0 ); + + int depth = mv[0].depth(); + bool allch1 = true; + int k, cn = 0; + size_t i; + + for( i = 0; i < n; i++ ) + { + CV_Assert(mv[i].size == mv[0].size && mv[i].depth() == depth); + allch1 = allch1 && mv[i].channels() == 1; + cn += mv[i].channels(); + } + + CV_Assert( 0 < cn && cn <= CV_CN_MAX ); + _dst.create(mv[0].dims, mv[0].size, CV_MAKETYPE(depth, cn)); + Mat dst = _dst.getMat(); + + if( n == 1 ) + { + mv[0].copyTo(dst); + return; + } + + if( !allch1 ) + { + AutoBuffer pairs(cn*2); + int j, ni=0; + + for( i = 0, j = 0; i < n; i++, j += ni ) + { + ni = mv[i].channels(); + for( k = 0; k < ni; k++ ) + { + pairs[(j+k)*2] = j + k; + pairs[(j+k)*2+1] = j + k; + } + } + mixChannels( mv, n, &dst, 1, &pairs[0], cn ); + return; + } + + size_t esz = dst.elemSize(), esz1 = dst.elemSize1(); + int blocksize0 = (int)((BLOCK_SIZE + esz-1)/esz); + AutoBuffer _buf((cn+1)*(sizeof(Mat*) + sizeof(uchar*)) + 16); + const Mat** arrays = (const Mat**)(uchar*)_buf; + uchar** ptrs = (uchar**)alignPtr(arrays + cn + 1, 16); + + arrays[0] = &dst; + for( k = 0; k < cn; k++ ) + arrays[k+1] = &mv[k]; + + NAryMatIterator it(arrays, ptrs, cn+1); + int total = (int)it.size, blocksize = cn <= 4 ? total : std::min(total, blocksize0); + MergeFunc func = mergeTab[depth]; + + for( i = 0; i < it.nplanes; i++, ++it ) + { + for( int j = 0; j < total; j += blocksize ) + { + int bsz = std::min(total - j, blocksize); + func( (const uchar**)&ptrs[1], ptrs[0], bsz, cn ); + + if( j + blocksize < total ) + { + ptrs[0] += bsz*esz; + for( int t = 0; t < cn; t++ ) + ptrs[t+1] += bsz*esz1; + } + } + } +} + +void cv::merge(InputArrayOfArrays _mv, OutputArray _dst) +{ + vector mv; + _mv.getMatVector(mv); + merge(!mv.empty() ? &mv[0] : 0, mv.size(), _dst); +} + +/****************************************************************************************\ +* Generalized split/merge: mixing channels * +\****************************************************************************************/ + +namespace cv +{ + +template static void +mixChannels_( const T** src, const int* sdelta, + T** dst, const int* ddelta, + int len, int npairs ) +{ + int i, k; + for( k = 0; k < npairs; k++ ) + { + const T* s = src[k]; + T* d = dst[k]; + int ds = sdelta[k], dd = ddelta[k]; + if( s ) + { + for( i = 0; i <= len - 2; i += 2, s += ds*2, d += dd*2 ) + { + T t0 = s[0], t1 = s[ds]; + d[0] = t0; d[dd] = t1; + } + if( i < len ) + d[0] = s[0]; + } + else + { + for( i = 0; i <= len - 2; i += 2, d += dd*2 ) + d[0] = d[dd] = 0; + if( i < len ) + d[0] = 0; + } + } +} + + +static void mixChannels8u( const uchar** src, const int* sdelta, + uchar** dst, const int* ddelta, + int len, int npairs ) +{ + mixChannels_(src, sdelta, dst, ddelta, len, npairs); +} + +static void mixChannels16u( const ushort** src, const int* sdelta, + ushort** dst, const int* ddelta, + int len, int npairs ) +{ + mixChannels_(src, sdelta, dst, ddelta, len, npairs); +} + +static void mixChannels32s( const int** src, const int* sdelta, + int** dst, const int* ddelta, + int len, int npairs ) +{ + mixChannels_(src, sdelta, dst, ddelta, len, npairs); +} + +static void mixChannels64s( const int64** src, const int* sdelta, + int64** dst, const int* ddelta, + int len, int npairs ) +{ + mixChannels_(src, sdelta, dst, ddelta, len, npairs); +} + +typedef void (*MixChannelsFunc)( const uchar** src, const int* sdelta, + uchar** dst, const int* ddelta, int len, int npairs ); + +static MixChannelsFunc mixchTab[] = +{ + (MixChannelsFunc)mixChannels8u, (MixChannelsFunc)mixChannels8u, (MixChannelsFunc)mixChannels16u, + (MixChannelsFunc)mixChannels16u, (MixChannelsFunc)mixChannels32s, (MixChannelsFunc)mixChannels32s, + (MixChannelsFunc)mixChannels64s, 0 +}; + +} + +void cv::mixChannels( const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_t npairs ) +{ + if( npairs == 0 ) + return; + CV_Assert( src && nsrcs > 0 && dst && ndsts > 0 && fromTo && npairs > 0 ); + + size_t i, j, k, esz1 = dst[0].elemSize1(); + int depth = dst[0].depth(); + + AutoBuffer buf((nsrcs + ndsts + 1)*(sizeof(Mat*) + sizeof(uchar*)) + npairs*(sizeof(uchar*)*2 + sizeof(int)*6)); + const Mat** arrays = (const Mat**)(uchar*)buf; + uchar** ptrs = (uchar**)(arrays + nsrcs + ndsts); + const uchar** srcs = (const uchar**)(ptrs + nsrcs + ndsts + 1); + uchar** dsts = (uchar**)(srcs + npairs); + int* tab = (int*)(dsts + npairs); + int *sdelta = (int*)(tab + npairs*4), *ddelta = sdelta + npairs; + + for( i = 0; i < nsrcs; i++ ) + arrays[i] = &src[i]; + for( i = 0; i < ndsts; i++ ) + arrays[i + nsrcs] = &dst[i]; + ptrs[nsrcs + ndsts] = 0; + + for( i = 0; i < npairs; i++ ) + { + int i0 = fromTo[i*2], i1 = fromTo[i*2+1]; + if( i0 >= 0 ) + { + for( j = 0; j < nsrcs; i0 -= src[j].channels(), j++ ) + if( i0 < src[j].channels() ) + break; + CV_Assert(j < nsrcs && src[j].depth() == depth); + tab[i*4] = (int)j; tab[i*4+1] = (int)(i0*esz1); + sdelta[i] = src[j].channels(); + } + else + { + tab[i*4] = (int)(nsrcs + ndsts); tab[i*4+1] = 0; + sdelta[i] = 0; + } + + for( j = 0; j < ndsts; i1 -= dst[j].channels(), j++ ) + if( i1 < dst[j].channels() ) + break; + CV_Assert(i1 >= 0 && j < ndsts && dst[j].depth() == depth); + tab[i*4+2] = (int)(j + nsrcs); tab[i*4+3] = (int)(i1*esz1); + ddelta[i] = dst[j].channels(); + } + + NAryMatIterator it(arrays, ptrs, (int)(nsrcs + ndsts)); + int total = (int)it.size, blocksize = std::min(total, (int)((BLOCK_SIZE + esz1-1)/esz1)); + MixChannelsFunc func = mixchTab[depth]; + + for( i = 0; i < it.nplanes; i++, ++it ) + { + for( k = 0; k < npairs; k++ ) + { + srcs[k] = ptrs[tab[k*4]] + tab[k*4+1]; + dsts[k] = ptrs[tab[k*4+2]] + tab[k*4+3]; + } + + for( int t = 0; t < total; t += blocksize ) + { + int bsz = std::min(total - t, blocksize); + func( srcs, sdelta, dsts, ddelta, bsz, (int)npairs ); + + if( t + blocksize < total ) + for( k = 0; k < npairs; k++ ) + { + srcs[k] += blocksize*sdelta[k]*esz1; + dsts[k] += blocksize*ddelta[k]*esz1; + } + } + } +} + + +void cv::mixChannels(const vector& src, vector& dst, + const int* fromTo, size_t npairs) +{ + mixChannels(!src.empty() ? &src[0] : 0, src.size(), + !dst.empty() ? &dst[0] : 0, dst.size(), fromTo, npairs); +} + +void cv::mixChannels(InputArrayOfArrays src, InputArrayOfArrays dst, + const vector& fromTo) +{ + if(fromTo.empty()) + return; + bool src_is_mat = src.kind() != _InputArray::STD_VECTOR_MAT && + src.kind() != _InputArray::STD_VECTOR_VECTOR; + bool dst_is_mat = dst.kind() != _InputArray::STD_VECTOR_MAT && + dst.kind() != _InputArray::STD_VECTOR_VECTOR; + int i; + int nsrc = src_is_mat ? 1 : (int)src.total(); + int ndst = dst_is_mat ? 1 : (int)dst.total(); + + CV_Assert(fromTo.size()%2 == 0 && nsrc > 0 && ndst > 0); + cv::AutoBuffer _buf(nsrc + ndst); + Mat* buf = _buf; + for( i = 0; i < nsrc; i++ ) + buf[i] = src.getMat(src_is_mat ? -1 : i); + for( i = 0; i < ndst; i++ ) + buf[nsrc + i] = dst.getMat(dst_is_mat ? -1 : i); + mixChannels(&buf[0], nsrc, &buf[nsrc], ndst, &fromTo[0], fromTo.size()/2); +} + +void cv::extractChannel(InputArray _src, OutputArray _dst, int coi) +{ + Mat src = _src.getMat(); + CV_Assert( 0 <= coi && coi < src.channels() ); + _dst.create(src.dims, &src.size[0], src.depth()); + Mat dst = _dst.getMat(); + int ch[] = { coi, 0 }; + mixChannels(&src, 1, &dst, 1, ch, 1); +} + +void cv::insertChannel(InputArray _src, InputOutputArray _dst, int coi) +{ + Mat src = _src.getMat(), dst = _dst.getMat(); + CV_Assert( src.size == dst.size && src.depth() == dst.depth() ); + CV_Assert( 0 <= coi && coi < dst.channels() && src.channels() == 1 ); + int ch[] = { 0, coi }; + mixChannels(&src, 1, &dst, 1, ch, 1); +} + +/****************************************************************************************\ +* convertScale[Abs] * +\****************************************************************************************/ + +namespace cv +{ + +template static void +cvtScaleAbs_( const T* src, size_t sstep, + DT* dst, size_t dstep, Size size, + WT scale, WT shift ) +{ + +#pragma mark ANUVIS team debugging + CV_Error( CV_StsBadArg, "cvtScaleAbs_ on ln:565 was called" ); + + + sstep /= sizeof(src[0]); + dstep /= sizeof(dst[0]); + + for( ; size.height--; src += sstep, dst += dstep ) + { + int x = 0; + #if CV_ENABLE_UNROLLED + for( ; x <= size.width - 4; x += 4 ) + { + DT t0, t1; + t0 = saturate_cast
(std::abs(src[x]*scale + shift)); + t1 = saturate_cast
(std::abs(src[x+1]*scale + shift)); + dst[x] = t0; dst[x+1] = t1; + t0 = saturate_cast
(std::abs(src[x+2]*scale + shift)); + t1 = saturate_cast
(std::abs(src[x+3]*scale + shift)); + dst[x+2] = t0; dst[x+3] = t1; + } + #endif + for( ; x < size.width; x++ ) + dst[x] = saturate_cast
(std::abs(src[x]*scale + shift)); + } +} + + +template static void +cvtScale_( const T* src, size_t sstep, + DT* dst, size_t dstep, Size size, + WT scale, WT shift ) +{ + +#pragma mark ANUVIS team debugging +#ifdef ANUVIS_TEST + CV_Error( CV_StsBadArg, "cvtScale_ on ln:605 was called" ); +#endif + + sstep /= sizeof(src[0]); + dstep /= sizeof(dst[0]); + + for( ; size.height--; src += sstep, dst += dstep ) + { + int x = 0; + #if CV_ENABLE_UNROLLED + for( ; x <= size.width - 4; x += 4 ) + { + DT t0, t1; + t0 = saturate_cast
(src[x]*scale + shift); + t1 = saturate_cast
(src[x+1]*scale + shift); + dst[x] = t0; dst[x+1] = t1; + t0 = saturate_cast
(src[x+2]*scale + shift); + t1 = saturate_cast
(src[x+3]*scale + shift); + dst[x+2] = t0; dst[x+3] = t1; + } + #endif + + for( ; x < size.width; x++ ) + dst[x] = saturate_cast
(src[x]*scale + shift); + } +} + +//vz optimized template specialization +template<> void +cvtScale_( const short* src, size_t sstep, + short* dst, size_t dstep, Size size, + float scale, float shift ) +{ + +#pragma mark ANUVIS team debugging + CV_Error( CV_StsBadArg, "cvtScale_ on ln:633 was called" ); + + sstep /= sizeof(src[0]); + dstep /= sizeof(dst[0]); + + for( ; size.height--; src += sstep, dst += dstep ) + { + int x = 0; + #if CV_SSE2 + if(USE_SSE2) + { + __m128 scale128 = _mm_set1_ps (scale); + __m128 shift128 = _mm_set1_ps (shift); + for(; x <= size.width - 8; x += 8 ) + { + __m128i r0 = _mm_loadl_epi64((const __m128i*)(src + x)); + __m128i r1 = _mm_loadl_epi64((const __m128i*)(src + x + 4)); + __m128 rf0 =_mm_cvtepi32_ps(_mm_srai_epi32(_mm_unpacklo_epi16(r0, r0), 16)); + __m128 rf1 =_mm_cvtepi32_ps(_mm_srai_epi32(_mm_unpacklo_epi16(r1, r1), 16)); + rf0 = _mm_add_ps(_mm_mul_ps(rf0, scale128), shift128); + rf1 = _mm_add_ps(_mm_mul_ps(rf1, scale128), shift128); + r0 = _mm_cvtps_epi32(rf0); + r1 = _mm_cvtps_epi32(rf1); + r0 = _mm_packs_epi32(r0, r1); + _mm_storeu_si128((__m128i*)(dst + x), r0); + } + } + #endif + + for(; x < size.width; x++ ) + dst[x] = saturate_cast(src[x]*scale + shift); + } +} + +template<> void +cvtScale_( const short* src, size_t sstep, + int* dst, size_t dstep, Size size, + float scale, float shift ) +{ + +#pragma mark ANUVIS team debugging + CV_Error( CV_StsBadArg, "cvtScale_ on ln:674 was called" ); + + sstep /= sizeof(src[0]); + dstep /= sizeof(dst[0]); + + for( ; size.height--; src += sstep, dst += dstep ) + { + int x = 0; + + #if CV_SSE2 + if(USE_SSE2)//~5X + { + __m128 scale128 = _mm_set1_ps (scale); + __m128 shift128 = _mm_set1_ps (shift); + for(; x <= size.width - 8; x += 8 ) + { + __m128i r0 = _mm_loadl_epi64((const __m128i*)(src + x)); + __m128i r1 = _mm_loadl_epi64((const __m128i*)(src + x + 4)); + __m128 rf0 =_mm_cvtepi32_ps(_mm_srai_epi32(_mm_unpacklo_epi16(r0, r0), 16)); + __m128 rf1 =_mm_cvtepi32_ps(_mm_srai_epi32(_mm_unpacklo_epi16(r1, r1), 16)); + rf0 = _mm_add_ps(_mm_mul_ps(rf0, scale128), shift128); + rf1 = _mm_add_ps(_mm_mul_ps(rf1, scale128), shift128); + r0 = _mm_cvtps_epi32(rf0); + r1 = _mm_cvtps_epi32(rf1); + + _mm_storeu_si128((__m128i*)(dst + x), r0); + _mm_storeu_si128((__m128i*)(dst + x + 4), r1); + } + } + #endif + + //We will wait Haswell + /* + #if CV_AVX + if(USE_AVX)//2X - bad variant + { + ////TODO:AVX implementation (optimization?) required + __m256 scale256 = _mm256_set1_ps (scale); + __m256 shift256 = _mm256_set1_ps (shift); + for(; x <= size.width - 8; x += 8 ) + { + __m256i buf = _mm256_set_epi32((int)(*(src+x+7)),(int)(*(src+x+6)),(int)(*(src+x+5)),(int)(*(src+x+4)),(int)(*(src+x+3)),(int)(*(src+x+2)),(int)(*(src+x+1)),(int)(*(src+x))); + __m256 r0 = _mm256_add_ps( _mm256_mul_ps(_mm256_cvtepi32_ps (buf), scale256), shift256); + __m256i res = _mm256_cvtps_epi32(r0); + _mm256_storeu_si256 ((__m256i*)(dst+x), res); + } + } + #endif*/ + + for(; x < size.width; x++ ) + dst[x] = saturate_cast(src[x]*scale + shift); + } +} + +template static void +cvt_( const T* src, size_t sstep, + DT* dst, size_t dstep, Size size ) +{ +#pragma mark ANUVIS team debugging +#ifdef ANUVIS_TEST + CV_Error( CV_StsBadArg, "cvt_ on ln:734 was called" ); +#endif + + sstep /= sizeof(src[0]); + dstep /= sizeof(dst[0]); + + for( ; size.height--; src += sstep, dst += dstep ) + { + int x = 0; + #if CV_ENABLE_UNROLLED + for( ; x <= size.width - 4; x += 4 ) + { + DT t0, t1; + t0 = saturate_cast
(src[x]); + t1 = saturate_cast
(src[x+1]); + dst[x] = t0; dst[x+1] = t1; + t0 = saturate_cast
(src[x+2]); + t1 = saturate_cast
(src[x+3]); + dst[x+2] = t0; dst[x+3] = t1; + } + #endif + for( ; x < size.width; x++ ) + dst[x] = saturate_cast
(src[x]); + } +} + +//vz optimized template specialization, test Core_ConvertScale/ElemWiseTest +template<> void +cvt_( const float* src, size_t sstep, + short* dst, size_t dstep, Size size ) +{ + #pragma mark ANUVIS team debugging + #ifdef ANUVIS_TEST + CV_Error( CV_StsBadArg, "cvt_ on ln:769 was called" ); + #endif + + sstep /= sizeof(src[0]); + dstep /= sizeof(dst[0]); + + for( ; size.height--; src += sstep, dst += dstep ) + { + int x = 0; + #if CV_SSE2 + + if(USE_SSE2){ + for( ; x <= size.width - 8; x += 8 ) + { + __m128 src128 = _mm_loadu_ps (src + x); + __m128i src_int128 = _mm_cvtps_epi32 (src128); + + src128 = _mm_loadu_ps (src + x + 4); + __m128i src1_int128 = _mm_cvtps_epi32 (src128); + + src1_int128 = _mm_packs_epi32(src_int128, src1_int128); + _mm_storeu_si128((__m128i*)(dst + x),src1_int128); + } + } + #endif + + #if CV_NEON //~4.5X + + + #pragma mark ANUVIS team debugging NEON version + #if ANUVIS_TEST + CV_Error( CV_StsBadArg, "cvt_ float->short using Neon was called!" ); + #endif + + if (cv::useOptimized()) { + + for( ; x <= size.width - 8; x += 8 ){ + //pull down first half + float32x4_t src128 = vld1q_f32((const float32_t*)(src + x)); + + //convert it from float to int + int32x4_t src_int128 = vcvtq_s32_f32(src128); + + //vector saturate narrow integer + int16x4_t src0_int64 = vqmovn_s32(src_int128); + + //pull down second half and repeat + src128 = vld1q_f32((const float32_t*)(src + x + 4)); + src_int128 = vcvtq_s32_f32(src128); + int16x4_t src1_int64 = vqmovn_s32(src_int128); + + //stick it together + int16x8_t res_int128 = vcombine_s16(src0_int64,src1_int64); + + //store it + vst1q_s16((int16_t*) dst + x, res_int128); + + + } + + } + + #endif + + //resume normal operations with new packed SIMD (note that if there is a SIMD version being used x will already be set to size.width so the next loop won't be executed) + for( ; x < size.width; x++ ) + dst[x] = saturate_cast(src[x]); + } + +} + + +template static void +cpy_( const T* src, size_t sstep, T* dst, size_t dstep, Size size ) +{ + sstep /= sizeof(src[0]); + dstep /= sizeof(dst[0]); + + for( ; size.height--; src += sstep, dst += dstep ) + memcpy(dst, src, size.width*sizeof(src[0])); +} + +#define DEF_CVT_SCALE_ABS_FUNC(suffix, tfunc, stype, dtype, wtype) \ +static void cvtScaleAbs##suffix( const stype* src, size_t sstep, const uchar*, size_t, \ + dtype* dst, size_t dstep, Size size, double* scale) \ +{ \ + tfunc(src, sstep, dst, dstep, size, (wtype)scale[0], (wtype)scale[1]); \ +} + +#define DEF_CVT_SCALE_FUNC(suffix, stype, dtype, wtype) \ +static void cvtScale##suffix( const stype* src, size_t sstep, const uchar*, size_t, \ +dtype* dst, size_t dstep, Size size, double* scale) \ +{ \ + cvtScale_(src, sstep, dst, dstep, size, (wtype)scale[0], (wtype)scale[1]); \ +} + + +#define DEF_CVT_FUNC(suffix, stype, dtype) \ +static void cvt##suffix( const stype* src, size_t sstep, const uchar*, size_t, \ + dtype* dst, size_t dstep, Size size, double*) \ +{ \ + cvt_(src, sstep, dst, dstep, size); \ +} + +#define DEF_CPY_FUNC(suffix, stype) \ +static void cvt##suffix( const stype* src, size_t sstep, const uchar*, size_t, \ +stype* dst, size_t dstep, Size size, double*) \ +{ \ + cpy_(src, sstep, dst, dstep, size); \ +} + + +DEF_CVT_SCALE_ABS_FUNC(8u, cvtScaleAbs_, uchar, uchar, float); +DEF_CVT_SCALE_ABS_FUNC(8s8u, cvtScaleAbs_, schar, uchar, float); +DEF_CVT_SCALE_ABS_FUNC(16u8u, cvtScaleAbs_, ushort, uchar, float); +DEF_CVT_SCALE_ABS_FUNC(16s8u, cvtScaleAbs_, short, uchar, float); +DEF_CVT_SCALE_ABS_FUNC(32s8u, cvtScaleAbs_, int, uchar, float); +DEF_CVT_SCALE_ABS_FUNC(32f8u, cvtScaleAbs_, float, uchar, float); +DEF_CVT_SCALE_ABS_FUNC(64f8u, cvtScaleAbs_, double, uchar, float); + +DEF_CVT_SCALE_FUNC(8u, uchar, uchar, float); +DEF_CVT_SCALE_FUNC(8s8u, schar, uchar, float); +DEF_CVT_SCALE_FUNC(16u8u, ushort, uchar, float); +DEF_CVT_SCALE_FUNC(16s8u, short, uchar, float); +DEF_CVT_SCALE_FUNC(32s8u, int, uchar, float); +DEF_CVT_SCALE_FUNC(32f8u, float, uchar, float); +DEF_CVT_SCALE_FUNC(64f8u, double, uchar, float); + +DEF_CVT_SCALE_FUNC(8u8s, uchar, schar, float); +DEF_CVT_SCALE_FUNC(8s, schar, schar, float); +DEF_CVT_SCALE_FUNC(16u8s, ushort, schar, float); +DEF_CVT_SCALE_FUNC(16s8s, short, schar, float); +DEF_CVT_SCALE_FUNC(32s8s, int, schar, float); +DEF_CVT_SCALE_FUNC(32f8s, float, schar, float); +DEF_CVT_SCALE_FUNC(64f8s, double, schar, float); + +DEF_CVT_SCALE_FUNC(8u16u, uchar, ushort, float); +DEF_CVT_SCALE_FUNC(8s16u, schar, ushort, float); +DEF_CVT_SCALE_FUNC(16u, ushort, ushort, float); +DEF_CVT_SCALE_FUNC(16s16u, short, ushort, float); +DEF_CVT_SCALE_FUNC(32s16u, int, ushort, float); +DEF_CVT_SCALE_FUNC(32f16u, float, ushort, float); +DEF_CVT_SCALE_FUNC(64f16u, double, ushort, float); + +DEF_CVT_SCALE_FUNC(8u16s, uchar, short, float); +DEF_CVT_SCALE_FUNC(8s16s, schar, short, float); +DEF_CVT_SCALE_FUNC(16u16s, ushort, short, float); +DEF_CVT_SCALE_FUNC(16s, short, short, float); +DEF_CVT_SCALE_FUNC(32s16s, int, short, float); +DEF_CVT_SCALE_FUNC(32f16s, float, short, float); +DEF_CVT_SCALE_FUNC(64f16s, double, short, float); + +DEF_CVT_SCALE_FUNC(8u32s, uchar, int, float); +DEF_CVT_SCALE_FUNC(8s32s, schar, int, float); +DEF_CVT_SCALE_FUNC(16u32s, ushort, int, float); +DEF_CVT_SCALE_FUNC(16s32s, short, int, float); +DEF_CVT_SCALE_FUNC(32s, int, int, double); +DEF_CVT_SCALE_FUNC(32f32s, float, int, float); +DEF_CVT_SCALE_FUNC(64f32s, double, int, double); + +DEF_CVT_SCALE_FUNC(8u32f, uchar, float, float); +DEF_CVT_SCALE_FUNC(8s32f, schar, float, float); +DEF_CVT_SCALE_FUNC(16u32f, ushort, float, float); +DEF_CVT_SCALE_FUNC(16s32f, short, float, float); +DEF_CVT_SCALE_FUNC(32s32f, int, float, double); +DEF_CVT_SCALE_FUNC(32f, float, float, float); +DEF_CVT_SCALE_FUNC(64f32f, double, float, double); + +DEF_CVT_SCALE_FUNC(8u64f, uchar, double, double); +DEF_CVT_SCALE_FUNC(8s64f, schar, double, double); +DEF_CVT_SCALE_FUNC(16u64f, ushort, double, double); +DEF_CVT_SCALE_FUNC(16s64f, short, double, double); +DEF_CVT_SCALE_FUNC(32s64f, int, double, double); +DEF_CVT_SCALE_FUNC(32f64f, float, double, double); +DEF_CVT_SCALE_FUNC(64f, double, double, double); + +DEF_CPY_FUNC(8u, uchar); +DEF_CVT_FUNC(8s8u, schar, uchar); +DEF_CVT_FUNC(16u8u, ushort, uchar); +DEF_CVT_FUNC(16s8u, short, uchar); +DEF_CVT_FUNC(32s8u, int, uchar); +DEF_CVT_FUNC(32f8u, float, uchar); +DEF_CVT_FUNC(64f8u, double, uchar); + +DEF_CVT_FUNC(8u8s, uchar, schar); +DEF_CVT_FUNC(16u8s, ushort, schar); +DEF_CVT_FUNC(16s8s, short, schar); +DEF_CVT_FUNC(32s8s, int, schar); +DEF_CVT_FUNC(32f8s, float, schar); +DEF_CVT_FUNC(64f8s, double, schar); + +DEF_CVT_FUNC(8u16u, uchar, ushort); +DEF_CVT_FUNC(8s16u, schar, ushort); +DEF_CPY_FUNC(16u, ushort); +DEF_CVT_FUNC(16s16u, short, ushort); +DEF_CVT_FUNC(32s16u, int, ushort); +DEF_CVT_FUNC(32f16u, float, ushort); +DEF_CVT_FUNC(64f16u, double, ushort); + +DEF_CVT_FUNC(8u16s, uchar, short); +DEF_CVT_FUNC(8s16s, schar, short); +DEF_CVT_FUNC(16u16s, ushort, short); +DEF_CVT_FUNC(32s16s, int, short); +DEF_CVT_FUNC(32f16s, float, short); +DEF_CVT_FUNC(64f16s, double, short); + +DEF_CVT_FUNC(8u32s, uchar, int); +DEF_CVT_FUNC(8s32s, schar, int); +DEF_CVT_FUNC(16u32s, ushort, int); +DEF_CVT_FUNC(16s32s, short, int); +DEF_CPY_FUNC(32s, int); +DEF_CVT_FUNC(32f32s, float, int); +DEF_CVT_FUNC(64f32s, double, int); + +DEF_CVT_FUNC(8u32f, uchar, float); +DEF_CVT_FUNC(8s32f, schar, float); +DEF_CVT_FUNC(16u32f, ushort, float); +DEF_CVT_FUNC(16s32f, short, float); +DEF_CVT_FUNC(32s32f, int, float); +DEF_CVT_FUNC(64f32f, double, float); + +DEF_CVT_FUNC(8u64f, uchar, double); +DEF_CVT_FUNC(8s64f, schar, double); +DEF_CVT_FUNC(16u64f, ushort, double); +DEF_CVT_FUNC(16s64f, short, double); +DEF_CVT_FUNC(32s64f, int, double); +DEF_CVT_FUNC(32f64f, float, double); +DEF_CPY_FUNC(64s, int64); + +static BinaryFunc cvtScaleAbsTab[] = +{ + (BinaryFunc)cvtScaleAbs8u, (BinaryFunc)cvtScaleAbs8s8u, (BinaryFunc)cvtScaleAbs16u8u, + (BinaryFunc)cvtScaleAbs16s8u, (BinaryFunc)cvtScaleAbs32s8u, (BinaryFunc)cvtScaleAbs32f8u, + (BinaryFunc)cvtScaleAbs64f8u, 0 +}; + +static BinaryFunc cvtScaleTab[][8] = +{ + { + (BinaryFunc)GET_OPTIMIZED(cvtScale8u), (BinaryFunc)GET_OPTIMIZED(cvtScale8s8u), (BinaryFunc)GET_OPTIMIZED(cvtScale16u8u), + (BinaryFunc)GET_OPTIMIZED(cvtScale16s8u), (BinaryFunc)GET_OPTIMIZED(cvtScale32s8u), (BinaryFunc)GET_OPTIMIZED(cvtScale32f8u), + (BinaryFunc)cvtScale64f8u, 0 + }, + { + (BinaryFunc)GET_OPTIMIZED(cvtScale8u8s), (BinaryFunc)GET_OPTIMIZED(cvtScale8s), (BinaryFunc)GET_OPTIMIZED(cvtScale16u8s), + (BinaryFunc)GET_OPTIMIZED(cvtScale16s8s), (BinaryFunc)GET_OPTIMIZED(cvtScale32s8s), (BinaryFunc)GET_OPTIMIZED(cvtScale32f8s), + (BinaryFunc)cvtScale64f8s, 0 + }, + { + (BinaryFunc)GET_OPTIMIZED(cvtScale8u16u), (BinaryFunc)GET_OPTIMIZED(cvtScale8s16u), (BinaryFunc)GET_OPTIMIZED(cvtScale16u), + (BinaryFunc)GET_OPTIMIZED(cvtScale16s16u), (BinaryFunc)GET_OPTIMIZED(cvtScale32s16u), (BinaryFunc)GET_OPTIMIZED(cvtScale32f16u), + (BinaryFunc)cvtScale64f16u, 0 + }, + { + (BinaryFunc)GET_OPTIMIZED(cvtScale8u16s), (BinaryFunc)GET_OPTIMIZED(cvtScale8s16s), (BinaryFunc)GET_OPTIMIZED(cvtScale16u16s), + (BinaryFunc)GET_OPTIMIZED(cvtScale16s), (BinaryFunc)GET_OPTIMIZED(cvtScale32s16s), (BinaryFunc)GET_OPTIMIZED(cvtScale32f16s), + (BinaryFunc)cvtScale64f16s, 0 + }, + { + (BinaryFunc)GET_OPTIMIZED(cvtScale8u32s), (BinaryFunc)GET_OPTIMIZED(cvtScale8s32s), (BinaryFunc)GET_OPTIMIZED(cvtScale16u32s), + (BinaryFunc)GET_OPTIMIZED(cvtScale16s32s), (BinaryFunc)GET_OPTIMIZED(cvtScale32s), (BinaryFunc)GET_OPTIMIZED(cvtScale32f32s), + (BinaryFunc)cvtScale64f32s, 0 + }, + { + (BinaryFunc)GET_OPTIMIZED(cvtScale8u32f), (BinaryFunc)GET_OPTIMIZED(cvtScale8s32f), (BinaryFunc)GET_OPTIMIZED(cvtScale16u32f), + (BinaryFunc)GET_OPTIMIZED(cvtScale16s32f), (BinaryFunc)GET_OPTIMIZED(cvtScale32s32f), (BinaryFunc)GET_OPTIMIZED(cvtScale32f), + (BinaryFunc)cvtScale64f32f, 0 + }, + { + (BinaryFunc)cvtScale8u64f, (BinaryFunc)cvtScale8s64f, (BinaryFunc)cvtScale16u64f, + (BinaryFunc)cvtScale16s64f, (BinaryFunc)cvtScale32s64f, (BinaryFunc)cvtScale32f64f, + (BinaryFunc)cvtScale64f, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0 + } +}; + +static BinaryFunc cvtTab[][8] = +{ + { + (BinaryFunc)(cvt8u), (BinaryFunc)GET_OPTIMIZED(cvt8s8u), (BinaryFunc)GET_OPTIMIZED(cvt16u8u), + (BinaryFunc)GET_OPTIMIZED(cvt16s8u), (BinaryFunc)GET_OPTIMIZED(cvt32s8u), (BinaryFunc)GET_OPTIMIZED(cvt32f8u), + (BinaryFunc)GET_OPTIMIZED(cvt64f8u), 0 + }, + { + (BinaryFunc)GET_OPTIMIZED(cvt8u8s), (BinaryFunc)cvt8u, (BinaryFunc)GET_OPTIMIZED(cvt16u8s), + (BinaryFunc)GET_OPTIMIZED(cvt16s8s), (BinaryFunc)GET_OPTIMIZED(cvt32s8s), (BinaryFunc)GET_OPTIMIZED(cvt32f8s), + (BinaryFunc)GET_OPTIMIZED(cvt64f8s), 0 + }, + { + (BinaryFunc)GET_OPTIMIZED(cvt8u16u), (BinaryFunc)GET_OPTIMIZED(cvt8s16u), (BinaryFunc)cvt16u, + (BinaryFunc)GET_OPTIMIZED(cvt16s16u), (BinaryFunc)GET_OPTIMIZED(cvt32s16u), (BinaryFunc)GET_OPTIMIZED(cvt32f16u), + (BinaryFunc)GET_OPTIMIZED(cvt64f16u), 0 + }, + { + (BinaryFunc)GET_OPTIMIZED(cvt8u16s), (BinaryFunc)GET_OPTIMIZED(cvt8s16s), (BinaryFunc)GET_OPTIMIZED(cvt16u16s), + (BinaryFunc)cvt16u, (BinaryFunc)GET_OPTIMIZED(cvt32s16s), (BinaryFunc)GET_OPTIMIZED(cvt32f16s), + (BinaryFunc)GET_OPTIMIZED(cvt64f16s), 0 + }, + { + (BinaryFunc)GET_OPTIMIZED(cvt8u32s), (BinaryFunc)GET_OPTIMIZED(cvt8s32s), (BinaryFunc)GET_OPTIMIZED(cvt16u32s), + (BinaryFunc)GET_OPTIMIZED(cvt16s32s), (BinaryFunc)cvt32s, (BinaryFunc)GET_OPTIMIZED(cvt32f32s), + (BinaryFunc)GET_OPTIMIZED(cvt64f32s), 0 + }, + { + (BinaryFunc)GET_OPTIMIZED(cvt8u32f), (BinaryFunc)GET_OPTIMIZED(cvt8s32f), (BinaryFunc)GET_OPTIMIZED(cvt16u32f), + (BinaryFunc)GET_OPTIMIZED(cvt16s32f), (BinaryFunc)GET_OPTIMIZED(cvt32s32f), (BinaryFunc)cvt32s, + (BinaryFunc)GET_OPTIMIZED(cvt64f32f), 0 + }, + { + (BinaryFunc)GET_OPTIMIZED(cvt8u64f), (BinaryFunc)GET_OPTIMIZED(cvt8s64f), (BinaryFunc)GET_OPTIMIZED(cvt16u64f), + (BinaryFunc)GET_OPTIMIZED(cvt16s64f), (BinaryFunc)GET_OPTIMIZED(cvt32s64f), (BinaryFunc)GET_OPTIMIZED(cvt32f64f), + (BinaryFunc)(cvt64s), 0 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0 + } +}; + +BinaryFunc getConvertFunc(int sdepth, int ddepth) +{ + return cvtTab[CV_MAT_DEPTH(ddepth)][CV_MAT_DEPTH(sdepth)]; +} + +BinaryFunc getConvertScaleFunc(int sdepth, int ddepth) +{ + return cvtScaleTab[CV_MAT_DEPTH(ddepth)][CV_MAT_DEPTH(sdepth)]; +} + +} + +void cv::convertScaleAbs( InputArray _src, OutputArray _dst, double alpha, double beta ) +{ + Mat src = _src.getMat(); + int cn = src.channels(); + double scale[] = {alpha, beta}; + _dst.create( src.dims, src.size, CV_8UC(cn) ); + Mat dst = _dst.getMat(); + BinaryFunc func = cvtScaleAbsTab[src.depth()]; + CV_Assert( func != 0 ); + + if( src.dims <= 2 ) + { + Size sz = getContinuousSize(src, dst, cn); + func( src.data, src.step, 0, 0, dst.data, dst.step, sz, scale ); + } + else + { + const Mat* arrays[] = {&src, &dst, 0}; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs); + Size sz((int)it.size*cn, 1); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + func( ptrs[0], 0, 0, 0, ptrs[1], 0, sz, scale ); + } +} + +void cv::Mat::convertTo(OutputArray _dst, int _type, double alpha, double beta) const +{ + bool noScale = fabs(alpha-1) < DBL_EPSILON && fabs(beta) < DBL_EPSILON; + + if( _type < 0 ) + _type = _dst.fixedType() ? _dst.type() : type(); + else + _type = CV_MAKETYPE(CV_MAT_DEPTH(_type), channels()); + + int sdepth = depth(), ddepth = CV_MAT_DEPTH(_type); + if( sdepth == ddepth && noScale ) + { + copyTo(_dst); + return; + } + + Mat src = *this; + + BinaryFunc func = noScale ? getConvertFunc(sdepth, ddepth) : getConvertScaleFunc(sdepth, ddepth); + double scale[] = {alpha, beta}; + int cn = channels(); + CV_Assert( func != 0 ); + + if( dims <= 2 ) + { + _dst.create( size(), _type ); + Mat dst = _dst.getMat(); + Size sz = getContinuousSize(src, dst, cn); + func( src.data, src.step, 0, 0, dst.data, dst.step, sz, scale ); + } + else + { + _dst.create( dims, size, _type ); + Mat dst = _dst.getMat(); + const Mat* arrays[] = {&src, &dst, 0}; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs); + Size sz((int)(it.size*cn), 1); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + func(ptrs[0], 0, 0, 0, ptrs[1], 0, sz, scale); + } +} + +/****************************************************************************************\ +* LUT Transform * +\****************************************************************************************/ + +namespace cv +{ + +template static void +LUT8u_( const uchar* src, const T* lut, T* dst, int len, int cn, int lutcn ) +{ + if( lutcn == 1 ) + { + for( int i = 0; i < len*cn; i++ ) + dst[i] = lut[src[i]]; + } + else + { + for( int i = 0; i < len*cn; i += cn ) + for( int k = 0; k < cn; k++ ) + dst[i+k] = lut[src[i+k]*cn+k]; + } +} + +static void LUT8u_8u( const uchar* src, const uchar* lut, uchar* dst, int len, int cn, int lutcn ) +{ + LUT8u_( src, lut, dst, len, cn, lutcn ); +} + +static void LUT8u_8s( const uchar* src, const schar* lut, schar* dst, int len, int cn, int lutcn ) +{ + LUT8u_( src, lut, dst, len, cn, lutcn ); +} + +static void LUT8u_16u( const uchar* src, const ushort* lut, ushort* dst, int len, int cn, int lutcn ) +{ + LUT8u_( src, lut, dst, len, cn, lutcn ); +} + +static void LUT8u_16s( const uchar* src, const short* lut, short* dst, int len, int cn, int lutcn ) +{ + LUT8u_( src, lut, dst, len, cn, lutcn ); +} + +static void LUT8u_32s( const uchar* src, const int* lut, int* dst, int len, int cn, int lutcn ) +{ + LUT8u_( src, lut, dst, len, cn, lutcn ); +} + +static void LUT8u_32f( const uchar* src, const float* lut, float* dst, int len, int cn, int lutcn ) +{ + LUT8u_( src, lut, dst, len, cn, lutcn ); +} + +static void LUT8u_64f( const uchar* src, const double* lut, double* dst, int len, int cn, int lutcn ) +{ + LUT8u_( src, lut, dst, len, cn, lutcn ); +} + +typedef void (*LUTFunc)( const uchar* src, const uchar* lut, uchar* dst, int len, int cn, int lutcn ); + +static LUTFunc lutTab[] = +{ + (LUTFunc)LUT8u_8u, (LUTFunc)LUT8u_8s, (LUTFunc)LUT8u_16u, (LUTFunc)LUT8u_16s, + (LUTFunc)LUT8u_32s, (LUTFunc)LUT8u_32f, (LUTFunc)LUT8u_64f, 0 +}; + +} + +void cv::LUT( InputArray _src, InputArray _lut, OutputArray _dst, int interpolation ) +{ + Mat src = _src.getMat(), lut = _lut.getMat(); + CV_Assert( interpolation == 0 ); + int cn = src.channels(); + int lutcn = lut.channels(); + + CV_Assert( (lutcn == cn || lutcn == 1) && + lut.total() == 256 && lut.isContinuous() && + (src.depth() == CV_8U || src.depth() == CV_8S) ); + _dst.create( src.dims, src.size, CV_MAKETYPE(lut.depth(), cn)); + Mat dst = _dst.getMat(); + + LUTFunc func = lutTab[lut.depth()]; + CV_Assert( func != 0 ); + + const Mat* arrays[] = {&src, &dst, 0}; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs); + int len = (int)it.size; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + func(ptrs[0], lut.data, ptrs[1], len, cn, lutcn); +} + + +void cv::normalize( InputArray _src, OutputArray _dst, double a, double b, + int norm_type, int rtype, InputArray _mask ) +{ + Mat src = _src.getMat(), mask = _mask.getMat(); + + double scale = 1, shift = 0; + if( norm_type == CV_MINMAX ) + { + double smin = 0, smax = 0; + double dmin = MIN( a, b ), dmax = MAX( a, b ); + minMaxLoc( _src, &smin, &smax, 0, 0, mask ); + scale = (dmax - dmin)*(smax - smin > DBL_EPSILON ? 1./(smax - smin) : 0); + shift = dmin - smin*scale; + } + else if( norm_type == CV_L2 || norm_type == CV_L1 || norm_type == CV_C ) + { + scale = norm( src, norm_type, mask ); + scale = scale > DBL_EPSILON ? a/scale : 0.; + shift = 0; + } + else + CV_Error( CV_StsBadArg, "Unknown/unsupported norm type" ); + + if( rtype < 0 ) + rtype = _dst.fixedType() ? _dst.depth() : src.depth(); + + _dst.create(src.dims, src.size, CV_MAKETYPE(rtype, src.channels())); + Mat dst = _dst.getMat(); + + if( !mask.data ) + src.convertTo( dst, rtype, scale, shift ); + else + { + Mat temp; + src.convertTo( temp, rtype, scale, shift ); + temp.copyTo( dst, mask ); + } +} + +CV_IMPL void +cvSplit( const void* srcarr, void* dstarr0, void* dstarr1, void* dstarr2, void* dstarr3 ) +{ + void* dptrs[] = { dstarr0, dstarr1, dstarr2, dstarr3 }; + cv::Mat src = cv::cvarrToMat(srcarr); + int i, j, nz = 0; + for( i = 0; i < 4; i++ ) + nz += dptrs[i] != 0; + CV_Assert( nz > 0 ); + cv::vector dvec(nz); + cv::vector pairs(nz*2); + + for( i = j = 0; i < 4; i++ ) + { + if( dptrs[i] != 0 ) + { + dvec[j] = cv::cvarrToMat(dptrs[i]); + CV_Assert( dvec[j].size() == src.size() ); + CV_Assert( dvec[j].depth() == src.depth() ); + CV_Assert( dvec[j].channels() == 1 ); + CV_Assert( i < src.channels() ); + pairs[j*2] = i; + pairs[j*2+1] = j; + j++; + } + } + if( nz == src.channels() ) + cv::split( src, dvec ); + else + { + cv::mixChannels( &src, 1, &dvec[0], nz, &pairs[0], nz ); + } +} + + +CV_IMPL void +cvMerge( const void* srcarr0, const void* srcarr1, const void* srcarr2, + const void* srcarr3, void* dstarr ) +{ + const void* sptrs[] = { srcarr0, srcarr1, srcarr2, srcarr3 }; + cv::Mat dst = cv::cvarrToMat(dstarr); + int i, j, nz = 0; + for( i = 0; i < 4; i++ ) + nz += sptrs[i] != 0; + CV_Assert( nz > 0 ); + cv::vector svec(nz); + cv::vector pairs(nz*2); + + for( i = j = 0; i < 4; i++ ) + { + if( sptrs[i] != 0 ) + { + svec[j] = cv::cvarrToMat(sptrs[i]); + CV_Assert( svec[j].size == dst.size && + svec[j].depth() == dst.depth() && + svec[j].channels() == 1 && i < dst.channels() ); + pairs[j*2] = j; + pairs[j*2+1] = i; + j++; + } + } + + if( nz == dst.channels() ) + cv::merge( svec, dst ); + else + { + cv::mixChannels( &svec[0], nz, &dst, 1, &pairs[0], nz ); + } +} + + +CV_IMPL void +cvMixChannels( const CvArr** src, int src_count, + CvArr** dst, int dst_count, + const int* from_to, int pair_count ) +{ + cv::AutoBuffer buf(src_count + dst_count); + + int i; + for( i = 0; i < src_count; i++ ) + buf[i] = cv::cvarrToMat(src[i]); + for( i = 0; i < dst_count; i++ ) + buf[i+src_count] = cv::cvarrToMat(dst[i]); + cv::mixChannels(&buf[0], src_count, &buf[src_count], dst_count, from_to, pair_count); +} + +CV_IMPL void +cvConvertScaleAbs( const void* srcarr, void* dstarr, + double scale, double shift ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + CV_Assert( src.size == dst.size && dst.type() == CV_8UC(src.channels())); + cv::convertScaleAbs( src, dst, scale, shift ); +} + +CV_IMPL void +cvConvertScale( const void* srcarr, void* dstarr, + double scale, double shift ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + CV_Assert( src.size == dst.size && src.channels() == dst.channels() ); + src.convertTo(dst, dst.type(), scale, shift); +} + +CV_IMPL void cvLUT( const void* srcarr, void* dstarr, const void* lutarr ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), lut = cv::cvarrToMat(lutarr); + + CV_Assert( dst.size() == src.size() && dst.type() == CV_MAKETYPE(lut.depth(), src.channels()) ); + cv::LUT( src, lut, dst ); +} + +CV_IMPL void cvNormalize( const CvArr* srcarr, CvArr* dstarr, + double a, double b, int norm_type, const CvArr* maskarr ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), mask; + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + CV_Assert( dst.size() == src.size() && src.channels() == dst.channels() ); + cv::normalize( src, dst, a, b, norm_type, dst.type(), mask ); +} + +/* End of file. */ \ No newline at end of file diff --git a/core/src/copy.cpp b/core/src/copy.cpp new file mode 100644 index 0000000..84bc224 --- /dev/null +++ b/core/src/copy.cpp @@ -0,0 +1,630 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +/* //////////////////////////////////////////////////////////////////// +// +// Mat basic operations: Copy, Set +// +// */ + +#include "precomp.hpp" + +namespace cv +{ + +template static void +copyMask_(const uchar* _src, size_t sstep, const uchar* mask, size_t mstep, uchar* _dst, size_t dstep, Size size) +{ + for( ; size.height--; mask += mstep, _src += sstep, _dst += dstep ) + { + const T* src = (const T*)_src; + T* dst = (T*)_dst; + int x = 0; + #if CV_ENABLE_UNROLLED + for( ; x <= size.width - 4; x += 4 ) + { + if( mask[x] ) + dst[x] = src[x]; + if( mask[x+1] ) + dst[x+1] = src[x+1]; + if( mask[x+2] ) + dst[x+2] = src[x+2]; + if( mask[x+3] ) + dst[x+3] = src[x+3]; + } + #endif + for( ; x < size.width; x++ ) + if( mask[x] ) + dst[x] = src[x]; + } +} + +template<> void +copyMask_(const uchar* _src, size_t sstep, const uchar* mask, size_t mstep, uchar* _dst, size_t dstep, Size size) +{ + for( ; size.height--; mask += mstep, _src += sstep, _dst += dstep ) + { + const uchar* src = (const uchar*)_src; + uchar* dst = (uchar*)_dst; + int x = 0; + #if CV_SSE4_2 + if(USE_SSE4_2)// + { + __m128i zero = _mm_setzero_si128 (); + + for( ; x <= size.width - 16; x += 16 ) + { + const __m128i rSrc = _mm_lddqu_si128((const __m128i*)(src+x)); + __m128i _mask = _mm_lddqu_si128((const __m128i*)(mask+x)); + __m128i rDst = _mm_lddqu_si128((__m128i*)(dst+x)); + __m128i _negMask = _mm_cmpeq_epi8(_mask, zero); + rDst = _mm_blendv_epi8(rSrc, rDst, _negMask); + _mm_storeu_si128((__m128i*)(dst + x), rDst); + } + } + #endif + for( ; x < size.width; x++ ) + if( mask[x] ) + dst[x] = src[x]; + } +} + +template<> void +copyMask_(const uchar* _src, size_t sstep, const uchar* mask, size_t mstep, uchar* _dst, size_t dstep, Size size) +{ + for( ; size.height--; mask += mstep, _src += sstep, _dst += dstep ) + { + const ushort* src = (const ushort*)_src; + ushort* dst = (ushort*)_dst; + int x = 0; + #if CV_SSE4_2 + if(USE_SSE4_2)// + { + __m128i zero = _mm_setzero_si128 (); + for( ; x <= size.width - 8; x += 8 ) + { + const __m128i rSrc =_mm_lddqu_si128((const __m128i*)(src+x)); + __m128i _mask = _mm_loadl_epi64((const __m128i*)(mask+x)); + _mask = _mm_unpacklo_epi8(_mask, _mask); + __m128i rDst = _mm_lddqu_si128((const __m128i*)(dst+x)); + __m128i _negMask = _mm_cmpeq_epi8(_mask, zero); + rDst = _mm_blendv_epi8(rSrc, rDst, _negMask); + _mm_storeu_si128((__m128i*)(dst + x), rDst); + } + } + #endif + for( ; x < size.width; x++ ) + if( mask[x] ) + dst[x] = src[x]; + } +} + +static void +copyMaskGeneric(const uchar* _src, size_t sstep, const uchar* mask, size_t mstep, uchar* _dst, size_t dstep, Size size, void* _esz) +{ + size_t k, esz = *(size_t*)_esz; + for( ; size.height--; mask += mstep, _src += sstep, _dst += dstep ) + { + const uchar* src = _src; + uchar* dst = _dst; + int x = 0; + for( ; x < size.width; x++, src += esz, dst += esz ) + { + if( !mask[x] ) + continue; + for( k = 0; k < esz; k++ ) + dst[k] = src[k]; + } + } +} + + +#define DEF_COPY_MASK(suffix, type) \ +static void copyMask##suffix(const uchar* src, size_t sstep, const uchar* mask, size_t mstep, \ + uchar* dst, size_t dstep, Size size, void*) \ +{ \ + copyMask_(src, sstep, mask, mstep, dst, dstep, size); \ +} + + +DEF_COPY_MASK(8u, uchar); +DEF_COPY_MASK(16u, ushort); +DEF_COPY_MASK(8uC3, Vec3b); +DEF_COPY_MASK(32s, int); +DEF_COPY_MASK(16uC3, Vec3s); +DEF_COPY_MASK(32sC2, Vec2i); +DEF_COPY_MASK(32sC3, Vec3i); +DEF_COPY_MASK(32sC4, Vec4i); +DEF_COPY_MASK(32sC6, Vec6i); +DEF_COPY_MASK(32sC8, Vec8i); + +BinaryFunc copyMaskTab[] = +{ + 0, + copyMask8u, + copyMask16u, + copyMask8uC3, + copyMask32s, + 0, + copyMask16uC3, + 0, + copyMask32sC2, + 0, 0, 0, + copyMask32sC3, + 0, 0, 0, + copyMask32sC4, + 0, 0, 0, 0, 0, 0, 0, + copyMask32sC6, + 0, 0, 0, 0, 0, 0, 0, + copyMask32sC8 +}; + +BinaryFunc getCopyMaskFunc(size_t esz) +{ + return esz <= 32 && copyMaskTab[esz] ? copyMaskTab[esz] : copyMaskGeneric; +} + +/* dst = src */ +void Mat::copyTo( OutputArray _dst ) const +{ + int dtype = _dst.type(); + if( _dst.fixedType() && dtype != type() ) + { + convertTo( _dst, dtype ); + return; + } + + if( empty() ) + { + _dst.release(); + return; + } + + if( dims <= 2 ) + { + _dst.create( rows, cols, type() ); + Mat dst = _dst.getMat(); + if( data == dst.data ) + return; + + if( rows > 0 && cols > 0 ) + { + const uchar* sptr = data; + uchar* dptr = dst.data; + + // to handle the copying 1xn matrix => nx1 std vector. + Size sz = size() == dst.size() ? + getContinuousSize(*this, dst) : + getContinuousSize(*this); + size_t len = sz.width*elemSize(); + + for( ; sz.height--; sptr += step, dptr += dst.step ) + memcpy( dptr, sptr, len ); + } + return; + } + + _dst.create( dims, size, type() ); + Mat dst = _dst.getMat(); + if( data == dst.data ) + return; + + if( total() != 0 ) + { + const Mat* arrays[] = { this, &dst }; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs, 2); + size_t sz = it.size*elemSize(); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + memcpy(ptrs[1], ptrs[0], sz); + } +} + +void Mat::copyTo( OutputArray _dst, InputArray _mask ) const +{ + Mat mask = _mask.getMat(); + if( !mask.data ) + { + copyTo(_dst); + return; + } + + int cn = channels(), mcn = mask.channels(); + CV_Assert( mask.depth() == CV_8U && (mcn == 1 || mcn == cn) ); + bool colorMask = mcn > 1; + + size_t esz = colorMask ? elemSize1() : elemSize(); + BinaryFunc copymask = getCopyMaskFunc(esz); + + uchar* data0 = _dst.getMat().data; + _dst.create( dims, size, type() ); + Mat dst = _dst.getMat(); + + if( dst.data != data0 ) // do not leave dst uninitialized + dst = Scalar(0); + + if( dims <= 2 ) + { + Size sz = getContinuousSize(*this, dst, mask, mcn); + copymask(data, step, mask.data, mask.step, dst.data, dst.step, sz, &esz); + return; + } + + const Mat* arrays[] = { this, &dst, &mask, 0 }; + uchar* ptrs[3]; + NAryMatIterator it(arrays, ptrs); + Size sz((int)(it.size*mcn), 1); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + copymask(ptrs[0], 0, ptrs[2], 0, ptrs[1], 0, sz, &esz); +} + +Mat& Mat::operator = (const Scalar& s) +{ + const Mat* arrays[] = { this }; + uchar* dptr; + NAryMatIterator it(arrays, &dptr, 1); + size_t elsize = it.size*elemSize(); + + if( s[0] == 0 && s[1] == 0 && s[2] == 0 && s[3] == 0 ) + { + for( size_t i = 0; i < it.nplanes; i++, ++it ) + memset( dptr, 0, elsize ); + } + else + { + if( it.nplanes > 0 ) + { + double scalar[12]; + scalarToRawData(s, scalar, type(), 12); + size_t blockSize = 12*elemSize1(); + + for( size_t j = 0; j < elsize; j += blockSize ) + { + size_t sz = MIN(blockSize, elsize - j); + memcpy( dptr + j, scalar, sz ); + } + } + + for( size_t i = 1; i < it.nplanes; i++ ) + { + ++it; + memcpy( dptr, data, elsize ); + } + } + return *this; +} + + +Mat& Mat::setTo(InputArray _value, InputArray _mask) +{ + if( !data ) + return *this; + + Mat value = _value.getMat(), mask = _mask.getMat(); + + CV_Assert( checkScalar(value, type(), _value.kind(), _InputArray::MAT )); + CV_Assert( mask.empty() || mask.type() == CV_8U ); + + size_t esz = elemSize(); + BinaryFunc copymask = getCopyMaskFunc(esz); + + const Mat* arrays[] = { this, !mask.empty() ? &mask : 0, 0 }; + uchar* ptrs[2]={0,0}; + NAryMatIterator it(arrays, ptrs); + int totalsz = (int)it.size, blockSize0 = std::min(totalsz, (int)((BLOCK_SIZE + esz-1)/esz)); + AutoBuffer _scbuf(blockSize0*esz + 32); + uchar* scbuf = alignPtr((uchar*)_scbuf, (int)sizeof(double)); + convertAndUnrollScalar( value, type(), scbuf, blockSize0 ); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( int j = 0; j < totalsz; j += blockSize0 ) + { + Size sz(std::min(blockSize0, totalsz - j), 1); + size_t blockSize = sz.width*esz; + if( ptrs[1] ) + { + copymask(scbuf, 0, ptrs[1], 0, ptrs[0], 0, sz, &esz); + ptrs[1] += sz.width; + } + else + memcpy(ptrs[0], scbuf, blockSize); + ptrs[0] += blockSize; + } + } + return *this; +} + + +static void +flipHoriz( const uchar* src, size_t sstep, uchar* dst, size_t dstep, Size size, size_t esz ) +{ + int i, j, limit = (int)(((size.width + 1)/2)*esz); + AutoBuffer _tab(size.width*esz); + int* tab = _tab; + + for( i = 0; i < size.width; i++ ) + for( size_t k = 0; k < esz; k++ ) + tab[i*esz + k] = (int)((size.width - i - 1)*esz + k); + + for( ; size.height--; src += sstep, dst += dstep ) + { + for( i = 0; i < limit; i++ ) + { + j = tab[i]; + uchar t0 = src[i], t1 = src[j]; + dst[i] = t1; dst[j] = t0; + } + } +} + +static void +flipVert( const uchar* src0, size_t sstep, uchar* dst0, size_t dstep, Size size, size_t esz ) +{ + const uchar* src1 = src0 + (size.height - 1)*sstep; + uchar* dst1 = dst0 + (size.height - 1)*dstep; + size.width *= (int)esz; + + for( int y = 0; y < (size.height + 1)/2; y++, src0 += sstep, src1 -= sstep, + dst0 += dstep, dst1 -= dstep ) + { + int i = 0; + if( ((size_t)src0|(size_t)dst0|(size_t)src1|(size_t)dst1) % sizeof(int) == 0 ) + { + for( ; i <= size.width - 16; i += 16 ) + { + int t0 = ((int*)(src0 + i))[0]; + int t1 = ((int*)(src1 + i))[0]; + + ((int*)(dst0 + i))[0] = t1; + ((int*)(dst1 + i))[0] = t0; + + t0 = ((int*)(src0 + i))[1]; + t1 = ((int*)(src1 + i))[1]; + + ((int*)(dst0 + i))[1] = t1; + ((int*)(dst1 + i))[1] = t0; + + t0 = ((int*)(src0 + i))[2]; + t1 = ((int*)(src1 + i))[2]; + + ((int*)(dst0 + i))[2] = t1; + ((int*)(dst1 + i))[2] = t0; + + t0 = ((int*)(src0 + i))[3]; + t1 = ((int*)(src1 + i))[3]; + + ((int*)(dst0 + i))[3] = t1; + ((int*)(dst1 + i))[3] = t0; + } + + for( ; i <= size.width - 4; i += 4 ) + { + int t0 = ((int*)(src0 + i))[0]; + int t1 = ((int*)(src1 + i))[0]; + + ((int*)(dst0 + i))[0] = t1; + ((int*)(dst1 + i))[0] = t0; + } + } + + for( ; i < size.width; i++ ) + { + uchar t0 = src0[i]; + uchar t1 = src1[i]; + + dst0[i] = t1; + dst1[i] = t0; + } + } +} + +void flip( InputArray _src, OutputArray _dst, int flip_mode ) +{ + Mat src = _src.getMat(); + + CV_Assert( src.dims <= 2 ); + _dst.create( src.size(), src.type() ); + Mat dst = _dst.getMat(); + size_t esz = src.elemSize(); + + if( flip_mode <= 0 ) + flipVert( src.data, src.step, dst.data, dst.step, src.size(), esz ); + else + flipHoriz( src.data, src.step, dst.data, dst.step, src.size(), esz ); + + if( flip_mode < 0 ) + flipHoriz( dst.data, dst.step, dst.data, dst.step, dst.size(), esz ); +} + + +void repeat(InputArray _src, int ny, int nx, OutputArray _dst) +{ + Mat src = _src.getMat(); + CV_Assert( src.dims <= 2 ); + + _dst.create(src.rows*ny, src.cols*nx, src.type()); + Mat dst = _dst.getMat(); + Size ssize = src.size(), dsize = dst.size(); + int esz = (int)src.elemSize(); + int x, y; + ssize.width *= esz; dsize.width *= esz; + + for( y = 0; y < ssize.height; y++ ) + { + for( x = 0; x < dsize.width; x += ssize.width ) + memcpy( dst.data + y*dst.step + x, src.data + y*src.step, ssize.width ); + } + + for( ; y < dsize.height; y++ ) + memcpy( dst.data + y*dst.step, dst.data + (y - ssize.height)*dst.step, dsize.width ); +} + +Mat repeat(const Mat& src, int ny, int nx) +{ + if( nx == 1 && ny == 1 ) + return src; + Mat dst; + repeat(src, ny, nx, dst); + return dst; +} + +} + +/* dst = src */ +CV_IMPL void +cvCopy( const void* srcarr, void* dstarr, const void* maskarr ) +{ + if( CV_IS_SPARSE_MAT(srcarr) && CV_IS_SPARSE_MAT(dstarr)) + { + CV_Assert( maskarr == 0 ); + CvSparseMat* src1 = (CvSparseMat*)srcarr; + CvSparseMat* dst1 = (CvSparseMat*)dstarr; + CvSparseMatIterator iterator; + CvSparseNode* node; + + dst1->dims = src1->dims; + memcpy( dst1->size, src1->size, src1->dims*sizeof(src1->size[0])); + dst1->valoffset = src1->valoffset; + dst1->idxoffset = src1->idxoffset; + cvClearSet( dst1->heap ); + + if( src1->heap->active_count >= dst1->hashsize*CV_SPARSE_HASH_RATIO ) + { + cvFree( &dst1->hashtable ); + dst1->hashsize = src1->hashsize; + dst1->hashtable = + (void**)cvAlloc( dst1->hashsize*sizeof(dst1->hashtable[0])); + } + + memset( dst1->hashtable, 0, dst1->hashsize*sizeof(dst1->hashtable[0])); + + for( node = cvInitSparseMatIterator( src1, &iterator ); + node != 0; node = cvGetNextSparseNode( &iterator )) + { + CvSparseNode* node_copy = (CvSparseNode*)cvSetNew( dst1->heap ); + int tabidx = node->hashval & (dst1->hashsize - 1); + memcpy( node_copy, node, dst1->heap->elem_size ); + node_copy->next = (CvSparseNode*)dst1->hashtable[tabidx]; + dst1->hashtable[tabidx] = node_copy; + } + return; + } + cv::Mat src = cv::cvarrToMat(srcarr, false, true, 1), dst = cv::cvarrToMat(dstarr, false, true, 1); + CV_Assert( src.depth() == dst.depth() && src.size == dst.size ); + + int coi1 = 0, coi2 = 0; + if( CV_IS_IMAGE(srcarr) ) + coi1 = cvGetImageCOI((const IplImage*)srcarr); + if( CV_IS_IMAGE(dstarr) ) + coi2 = cvGetImageCOI((const IplImage*)dstarr); + + if( coi1 || coi2 ) + { + CV_Assert( (coi1 != 0 || src.channels() == 1) && + (coi2 != 0 || dst.channels() == 1) ); + + int pair[] = { std::max(coi1-1, 0), std::max(coi2-1, 0) }; + cv::mixChannels( &src, 1, &dst, 1, pair, 1 ); + return; + } + else + CV_Assert( src.channels() == dst.channels() ); + + if( !maskarr ) + src.copyTo(dst); + else + src.copyTo(dst, cv::cvarrToMat(maskarr)); +} + +CV_IMPL void +cvSet( void* arr, CvScalar value, const void* maskarr ) +{ + cv::Mat m = cv::cvarrToMat(arr); + if( !maskarr ) + m = value; + else + m.setTo(cv::Scalar(value), cv::cvarrToMat(maskarr)); +} + +CV_IMPL void +cvSetZero( CvArr* arr ) +{ + if( CV_IS_SPARSE_MAT(arr) ) + { + CvSparseMat* mat1 = (CvSparseMat*)arr; + cvClearSet( mat1->heap ); + if( mat1->hashtable ) + memset( mat1->hashtable, 0, mat1->hashsize*sizeof(mat1->hashtable[0])); + return; + } + cv::Mat m = cv::cvarrToMat(arr); + m = cv::Scalar(0); +} + +CV_IMPL void +cvFlip( const CvArr* srcarr, CvArr* dstarr, int flip_mode ) +{ + cv::Mat src = cv::cvarrToMat(srcarr); + cv::Mat dst; + + if (!dstarr) + dst = src; + else + dst = cv::cvarrToMat(dstarr); + + CV_Assert( src.type() == dst.type() && src.size() == dst.size() ); + cv::flip( src, dst, flip_mode ); +} + +CV_IMPL void +cvRepeat( const CvArr* srcarr, CvArr* dstarr ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + CV_Assert( src.type() == dst.type() && + dst.rows % src.rows == 0 && dst.cols % src.cols == 0 ); + cv::repeat(src, dst.rows/src.rows, dst.cols/src.cols, dst); +} + +/* End of file. */ diff --git a/core/src/cuda/matrix_operations.cu b/core/src/cuda/matrix_operations.cu new file mode 100644 index 0000000..f475136 --- /dev/null +++ b/core/src/cuda/matrix_operations.cu @@ -0,0 +1,342 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "opencv2/gpu/device/saturate_cast.hpp" +#include "opencv2/gpu/device/transform.hpp" +#include "opencv2/gpu/device/functional.hpp" + +namespace cv { namespace gpu { namespace device +{ + void writeScalar(const uchar*); + void writeScalar(const schar*); + void writeScalar(const ushort*); + void writeScalar(const short int*); + void writeScalar(const int*); + void writeScalar(const float*); + void writeScalar(const double*); + void convert_gpu(PtrStepSzb, int, PtrStepSzb, int, double, double, cudaStream_t); +}}} + +namespace cv { namespace gpu { namespace device +{ + template struct shift_and_sizeof; + template <> struct shift_and_sizeof { enum { shift = 0 }; }; + template <> struct shift_and_sizeof { enum { shift = 0 }; }; + template <> struct shift_and_sizeof { enum { shift = 1 }; }; + template <> struct shift_and_sizeof { enum { shift = 1 }; }; + template <> struct shift_and_sizeof { enum { shift = 2 }; }; + template <> struct shift_and_sizeof { enum { shift = 2 }; }; + template <> struct shift_and_sizeof { enum { shift = 3 }; }; + + /////////////////////////////////////////////////////////////////////////// + ////////////////////////////////// CopyTo ///////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + template void copyToWithMask(PtrStepSzb src, PtrStepSzb dst, int cn, PtrStepSzb mask, bool colorMask, cudaStream_t stream) + { + if (colorMask) + cv::gpu::device::transform((PtrStepSz)src, (PtrStepSz)dst, identity(), SingleMask(mask), stream); + else + cv::gpu::device::transform((PtrStepSz)src, (PtrStepSz)dst, identity(), SingleMaskChannels(mask, cn), stream); + } + + void copyToWithMask_gpu(PtrStepSzb src, PtrStepSzb dst, size_t elemSize1, int cn, PtrStepSzb mask, bool colorMask, cudaStream_t stream) + { + typedef void (*func_t)(PtrStepSzb src, PtrStepSzb dst, int cn, PtrStepSzb mask, bool colorMask, cudaStream_t stream); + + static func_t tab[] = + { + 0, + copyToWithMask, + copyToWithMask, + 0, + copyToWithMask, + 0, + 0, + 0, + copyToWithMask + }; + + tab[elemSize1](src, dst, cn, mask, colorMask, stream); + } + + /////////////////////////////////////////////////////////////////////////// + ////////////////////////////////// SetTo ////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + __constant__ uchar scalar_8u[4]; + __constant__ schar scalar_8s[4]; + __constant__ ushort scalar_16u[4]; + __constant__ short scalar_16s[4]; + __constant__ int scalar_32s[4]; + __constant__ float scalar_32f[4]; + __constant__ double scalar_64f[4]; + + template __device__ __forceinline__ T readScalar(int i); + template <> __device__ __forceinline__ uchar readScalar(int i) {return scalar_8u[i];} + template <> __device__ __forceinline__ schar readScalar(int i) {return scalar_8s[i];} + template <> __device__ __forceinline__ ushort readScalar(int i) {return scalar_16u[i];} + template <> __device__ __forceinline__ short readScalar(int i) {return scalar_16s[i];} + template <> __device__ __forceinline__ int readScalar(int i) {return scalar_32s[i];} + template <> __device__ __forceinline__ float readScalar(int i) {return scalar_32f[i];} + template <> __device__ __forceinline__ double readScalar(int i) {return scalar_64f[i];} + + void writeScalar(const uchar* vals) + { + cudaSafeCall( cudaMemcpyToSymbol(scalar_8u, vals, sizeof(uchar) * 4) ); + } + void writeScalar(const schar* vals) + { + cudaSafeCall( cudaMemcpyToSymbol(scalar_8s, vals, sizeof(schar) * 4) ); + } + void writeScalar(const ushort* vals) + { + cudaSafeCall( cudaMemcpyToSymbol(scalar_16u, vals, sizeof(ushort) * 4) ); + } + void writeScalar(const short* vals) + { + cudaSafeCall( cudaMemcpyToSymbol(scalar_16s, vals, sizeof(short) * 4) ); + } + void writeScalar(const int* vals) + { + cudaSafeCall( cudaMemcpyToSymbol(scalar_32s, vals, sizeof(int) * 4) ); + } + void writeScalar(const float* vals) + { + cudaSafeCall( cudaMemcpyToSymbol(scalar_32f, vals, sizeof(float) * 4) ); + } + void writeScalar(const double* vals) + { + cudaSafeCall( cudaMemcpyToSymbol(scalar_64f, vals, sizeof(double) * 4) ); + } + + template + __global__ void set_to_without_mask(T* mat, int cols, int rows, size_t step, int channels) + { + size_t x = blockIdx.x * blockDim.x + threadIdx.x; + size_t y = blockIdx.y * blockDim.y + threadIdx.y; + + if ((x < cols * channels ) && (y < rows)) + { + size_t idx = y * ( step >> shift_and_sizeof::shift ) + x; + mat[idx] = readScalar(x % channels); + } + } + + template + __global__ void set_to_with_mask(T* mat, const uchar* mask, int cols, int rows, size_t step, int channels, size_t step_mask) + { + size_t x = blockIdx.x * blockDim.x + threadIdx.x; + size_t y = blockIdx.y * blockDim.y + threadIdx.y; + + if ((x < cols * channels ) && (y < rows)) + if (mask[y * step_mask + x / channels] != 0) + { + size_t idx = y * ( step >> shift_and_sizeof::shift ) + x; + mat[idx] = readScalar(x % channels); + } + } + template + void set_to_gpu(PtrStepSzb mat, const T* scalar, PtrStepSzb mask, int channels, cudaStream_t stream) + { + writeScalar(scalar); + + dim3 threadsPerBlock(32, 8, 1); + dim3 numBlocks (mat.cols * channels / threadsPerBlock.x + 1, mat.rows / threadsPerBlock.y + 1, 1); + + set_to_with_mask<<>>((T*)mat.data, (uchar*)mask.data, mat.cols, mat.rows, mat.step, channels, mask.step); + cudaSafeCall( cudaGetLastError() ); + + if (stream == 0) + cudaSafeCall ( cudaDeviceSynchronize() ); + } + + template void set_to_gpu(PtrStepSzb mat, const uchar* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const schar* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const ushort* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const short* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const int* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const float* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const double* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + + template + void set_to_gpu(PtrStepSzb mat, const T* scalar, int channels, cudaStream_t stream) + { + writeScalar(scalar); + + dim3 threadsPerBlock(32, 8, 1); + dim3 numBlocks (mat.cols * channels / threadsPerBlock.x + 1, mat.rows / threadsPerBlock.y + 1, 1); + + set_to_without_mask<<>>((T*)mat.data, mat.cols, mat.rows, mat.step, channels); + cudaSafeCall( cudaGetLastError() ); + + if (stream == 0) + cudaSafeCall ( cudaDeviceSynchronize() ); + } + + template void set_to_gpu(PtrStepSzb mat, const uchar* scalar, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const schar* scalar, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const ushort* scalar, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const short* scalar, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const int* scalar, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const float* scalar, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const double* scalar, int channels, cudaStream_t stream); + + /////////////////////////////////////////////////////////////////////////// + //////////////////////////////// ConvertTo //////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + template struct Convertor : unary_function + { + Convertor(double alpha_, double beta_) : alpha(alpha_), beta(beta_) {} + + __device__ __forceinline__ D operator()(const T& src) const + { + return saturate_cast(alpha * src + beta); + } + + double alpha, beta; + }; + + namespace detail + { + template struct ConvertTraitsDispatcher : DefaultTransformFunctorTraits + { + }; + template struct ConvertTraitsDispatcher<1, 1, F> : DefaultTransformFunctorTraits + { + enum { smart_shift = 8 }; + }; + template struct ConvertTraitsDispatcher<1, 2, F> : DefaultTransformFunctorTraits + { + enum { smart_shift = 4 }; + }; + template struct ConvertTraitsDispatcher<1, 4, F> : DefaultTransformFunctorTraits + { + enum { smart_block_dim_y = 8 }; + enum { smart_shift = 4 }; + }; + + template struct ConvertTraitsDispatcher<2, 2, F> : DefaultTransformFunctorTraits + { + enum { smart_shift = 4 }; + }; + template struct ConvertTraitsDispatcher<2, 4, F> : DefaultTransformFunctorTraits + { + enum { smart_shift = 2 }; + }; + + template struct ConvertTraitsDispatcher<4, 2, F> : DefaultTransformFunctorTraits + { + enum { smart_block_dim_y = 8 }; + enum { smart_shift = 4 }; + }; + template struct ConvertTraitsDispatcher<4, 4, F> : DefaultTransformFunctorTraits + { + enum { smart_block_dim_y = 8 }; + enum { smart_shift = 2 }; + }; + + template struct ConvertTraits : ConvertTraitsDispatcher + { + }; + } + + template struct TransformFunctorTraits< Convertor > : detail::ConvertTraits< Convertor > + { + }; + + template + void cvt_(PtrStepSzb src, PtrStepSzb dst, double alpha, double beta, cudaStream_t stream) + { + cudaSafeCall( cudaSetDoubleForDevice(&alpha) ); + cudaSafeCall( cudaSetDoubleForDevice(&beta) ); + Convertor op(alpha, beta); + cv::gpu::device::transform((PtrStepSz)src, (PtrStepSz)dst, op, WithOutMask(), stream); + } + +#if defined __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wmissing-declarations" +#endif + + void convert_gpu(PtrStepSzb src, int sdepth, PtrStepSzb dst, int ddepth, double alpha, double beta, cudaStream_t stream) + { + typedef void (*caller_t)(PtrStepSzb src, PtrStepSzb dst, double alpha, double beta, cudaStream_t stream); + + static const caller_t tab[8][8] = + { + {cvt_, cvt_, cvt_, cvt_, + cvt_, cvt_, cvt_, 0}, + + {cvt_, cvt_, cvt_, cvt_, + cvt_, cvt_, cvt_, 0}, + + {cvt_, cvt_, cvt_, cvt_, + cvt_, cvt_, cvt_, 0}, + + {cvt_, cvt_, cvt_, cvt_, + cvt_, cvt_, cvt_, 0}, + + {cvt_, cvt_, cvt_, + cvt_, cvt_, cvt_, cvt_, 0}, + + {cvt_, cvt_, cvt_, + cvt_, cvt_, cvt_, cvt_, 0}, + + {cvt_, cvt_, cvt_, + cvt_, cvt_, cvt_, cvt_, 0}, + + {0,0,0,0,0,0,0,0} + }; + + caller_t func = tab[sdepth][ddepth]; + if (!func) + cv::gpu::error("Unsupported convert operation", __FILE__, __LINE__, "convert_gpu"); + + func(src, dst, alpha, beta, stream); + } + +#if defined __clang__ +# pragma clang diagnostic pop +#endif +}}} // namespace cv { namespace gpu { namespace device diff --git a/core/src/datastructs.cpp b/core/src/datastructs.cpp new file mode 100644 index 0000000..9438fa2 --- /dev/null +++ b/core/src/datastructs.cpp @@ -0,0 +1,4060 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +#define ICV_FREE_PTR(storage) \ + ((schar*)(storage)->top + (storage)->block_size - (storage)->free_space) + +#define ICV_ALIGNED_SEQ_BLOCK_SIZE \ + (int)cvAlign(sizeof(CvSeqBlock), CV_STRUCT_ALIGN) + +CV_INLINE int +cvAlignLeft( int size, int align ) +{ + return size & -align; +} + +#define CV_GET_LAST_ELEM( seq, block ) \ + ((block)->data + ((block)->count - 1)*((seq)->elem_size)) + +#define CV_SWAP_ELEMS(a,b,elem_size) \ +{ \ + int k; \ + for( k = 0; k < elem_size; k++ ) \ + { \ + char t0 = (a)[k]; \ + char t1 = (b)[k]; \ + (a)[k] = t1; \ + (b)[k] = t0; \ + } \ +} + +#define ICV_SHIFT_TAB_MAX 32 +static const schar icvPower2ShiftTab[] = +{ + 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5 +}; + +/****************************************************************************************\ +* Functions for manipulating memory storage - list of memory blocks * +\****************************************************************************************/ + +/* Initialize allocated storage: */ +static void +icvInitMemStorage( CvMemStorage* storage, int block_size ) +{ + if( !storage ) + CV_Error( CV_StsNullPtr, "" ); + + if( block_size <= 0 ) + block_size = CV_STORAGE_BLOCK_SIZE; + + block_size = cvAlign( block_size, CV_STRUCT_ALIGN ); + assert( sizeof(CvMemBlock) % CV_STRUCT_ALIGN == 0 ); + + memset( storage, 0, sizeof( *storage )); + storage->signature = CV_STORAGE_MAGIC_VAL; + storage->block_size = block_size; +} + + +/* Create root memory storage: */ +CV_IMPL CvMemStorage* +cvCreateMemStorage( int block_size ) +{ + CvMemStorage* storage = (CvMemStorage *)cvAlloc( sizeof( CvMemStorage )); + icvInitMemStorage( storage, block_size ); + return storage; +} + + +/* Create child memory storage: */ +CV_IMPL CvMemStorage * +cvCreateChildMemStorage( CvMemStorage * parent ) +{ + if( !parent ) + CV_Error( CV_StsNullPtr, "" ); + + CvMemStorage* storage = cvCreateMemStorage(parent->block_size); + storage->parent = parent; + + return storage; +} + + +/* Release all blocks of the storage (or return them to parent, if any): */ +static void +icvDestroyMemStorage( CvMemStorage* storage ) +{ + int k = 0; + + CvMemBlock *block; + CvMemBlock *dst_top = 0; + + if( !storage ) + CV_Error( CV_StsNullPtr, "" ); + + if( storage->parent ) + dst_top = storage->parent->top; + + for( block = storage->bottom; block != 0; k++ ) + { + CvMemBlock *temp = block; + + block = block->next; + if( storage->parent ) + { + if( dst_top ) + { + temp->prev = dst_top; + temp->next = dst_top->next; + if( temp->next ) + temp->next->prev = temp; + dst_top = dst_top->next = temp; + } + else + { + dst_top = storage->parent->bottom = storage->parent->top = temp; + temp->prev = temp->next = 0; + storage->free_space = storage->block_size - sizeof( *temp ); + } + } + else + { + cvFree( &temp ); + } + } + + storage->top = storage->bottom = 0; + storage->free_space = 0; +} + + +/* Release memory storage: */ +CV_IMPL void +cvReleaseMemStorage( CvMemStorage** storage ) +{ + if( !storage ) + CV_Error( CV_StsNullPtr, "" ); + + CvMemStorage* st = *storage; + *storage = 0; + if( st ) + { + icvDestroyMemStorage( st ); + cvFree( &st ); + } +} + + +/* Clears memory storage (return blocks to the parent, if any): */ +CV_IMPL void +cvClearMemStorage( CvMemStorage * storage ) +{ + if( !storage ) + CV_Error( CV_StsNullPtr, "" ); + + if( storage->parent ) + icvDestroyMemStorage( storage ); + else + { + storage->top = storage->bottom; + storage->free_space = storage->bottom ? storage->block_size - sizeof(CvMemBlock) : 0; + } +} + + +/* Moves stack pointer to next block. + If no blocks, allocate new one and link it to the storage: */ +static void +icvGoNextMemBlock( CvMemStorage * storage ) +{ + if( !storage ) + CV_Error( CV_StsNullPtr, "" ); + + if( !storage->top || !storage->top->next ) + { + CvMemBlock *block; + + if( !(storage->parent) ) + { + block = (CvMemBlock *)cvAlloc( storage->block_size ); + } + else + { + CvMemStorage *parent = storage->parent; + CvMemStoragePos parent_pos; + + cvSaveMemStoragePos( parent, &parent_pos ); + icvGoNextMemBlock( parent ); + + block = parent->top; + cvRestoreMemStoragePos( parent, &parent_pos ); + + if( block == parent->top ) /* the single allocated block */ + { + assert( parent->bottom == block ); + parent->top = parent->bottom = 0; + parent->free_space = 0; + } + else + { + /* cut the block from the parent's list of blocks */ + parent->top->next = block->next; + if( block->next ) + block->next->prev = parent->top; + } + } + + /* link block */ + block->next = 0; + block->prev = storage->top; + + if( storage->top ) + storage->top->next = block; + else + storage->top = storage->bottom = block; + } + + if( storage->top->next ) + storage->top = storage->top->next; + storage->free_space = storage->block_size - sizeof(CvMemBlock); + assert( storage->free_space % CV_STRUCT_ALIGN == 0 ); +} + + +/* Remember memory storage position: */ +CV_IMPL void +cvSaveMemStoragePos( const CvMemStorage * storage, CvMemStoragePos * pos ) +{ + if( !storage || !pos ) + CV_Error( CV_StsNullPtr, "" ); + + pos->top = storage->top; + pos->free_space = storage->free_space; +} + + +/* Restore memory storage position: */ +CV_IMPL void +cvRestoreMemStoragePos( CvMemStorage * storage, CvMemStoragePos * pos ) +{ + if( !storage || !pos ) + CV_Error( CV_StsNullPtr, "" ); + if( pos->free_space > storage->block_size ) + CV_Error( CV_StsBadSize, "" ); + + /* + // this breaks icvGoNextMemBlock, so comment it off for now + if( storage->parent && (!pos->top || pos->top->next) ) + { + CvMemBlock* save_bottom; + if( !pos->top ) + save_bottom = 0; + else + { + save_bottom = storage->bottom; + storage->bottom = pos->top->next; + pos->top->next = 0; + storage->bottom->prev = 0; + } + icvDestroyMemStorage( storage ); + storage->bottom = save_bottom; + }*/ + + storage->top = pos->top; + storage->free_space = pos->free_space; + + if( !storage->top ) + { + storage->top = storage->bottom; + storage->free_space = storage->top ? storage->block_size - sizeof(CvMemBlock) : 0; + } +} + + +/* Allocate continuous buffer of the specified size in the storage: */ +CV_IMPL void* +cvMemStorageAlloc( CvMemStorage* storage, size_t size ) +{ + schar *ptr = 0; + if( !storage ) + CV_Error( CV_StsNullPtr, "NULL storage pointer" ); + + if( size > INT_MAX ) + CV_Error( CV_StsOutOfRange, "Too large memory block is requested" ); + + assert( storage->free_space % CV_STRUCT_ALIGN == 0 ); + + if( (size_t)storage->free_space < size ) + { + size_t max_free_space = cvAlignLeft(storage->block_size - sizeof(CvMemBlock), CV_STRUCT_ALIGN); + if( max_free_space < size ) + CV_Error( CV_StsOutOfRange, "requested size is negative or too big" ); + + icvGoNextMemBlock( storage ); + } + + ptr = ICV_FREE_PTR(storage); + assert( (size_t)ptr % CV_STRUCT_ALIGN == 0 ); + storage->free_space = cvAlignLeft(storage->free_space - (int)size, CV_STRUCT_ALIGN ); + + return ptr; +} + + +CV_IMPL CvString +cvMemStorageAllocString( CvMemStorage* storage, const char* ptr, int len ) +{ + CvString str; + + str.len = len >= 0 ? len : (int)strlen(ptr); + str.ptr = (char*)cvMemStorageAlloc( storage, str.len + 1 ); + memcpy( str.ptr, ptr, str.len ); + str.ptr[str.len] = '\0'; + + return str; +} + + +/****************************************************************************************\ +* Sequence implementation * +\****************************************************************************************/ + +/* Create empty sequence: */ +CV_IMPL CvSeq * +cvCreateSeq( int seq_flags, size_t header_size, size_t elem_size, CvMemStorage* storage ) +{ + CvSeq *seq = 0; + + if( !storage ) + CV_Error( CV_StsNullPtr, "" ); + if( header_size < sizeof( CvSeq ) || elem_size <= 0 ) + CV_Error( CV_StsBadSize, "" ); + + /* allocate sequence header */ + seq = (CvSeq*)cvMemStorageAlloc( storage, header_size ); + memset( seq, 0, header_size ); + + seq->header_size = (int)header_size; + seq->flags = (seq_flags & ~CV_MAGIC_MASK) | CV_SEQ_MAGIC_VAL; + { + int elemtype = CV_MAT_TYPE(seq_flags); + int typesize = CV_ELEM_SIZE(elemtype); + + if( elemtype != CV_SEQ_ELTYPE_GENERIC && elemtype != CV_USRTYPE1 && + typesize != 0 && typesize != (int)elem_size ) + CV_Error( CV_StsBadSize, + "Specified element size doesn't match to the size of the specified element type " + "(try to use 0 for element type)" ); + } + seq->elem_size = (int)elem_size; + seq->storage = storage; + + cvSetSeqBlockSize( seq, (int)((1 << 10)/elem_size) ); + + return seq; +} + + +/* adjusts field of sequence. It determines how much the sequence + grows if there are no free space inside the sequence buffers */ +CV_IMPL void +cvSetSeqBlockSize( CvSeq *seq, int delta_elements ) +{ + int elem_size; + int useful_block_size; + + if( !seq || !seq->storage ) + CV_Error( CV_StsNullPtr, "" ); + if( delta_elements < 0 ) + CV_Error( CV_StsOutOfRange, "" ); + + useful_block_size = cvAlignLeft(seq->storage->block_size - sizeof(CvMemBlock) - + sizeof(CvSeqBlock), CV_STRUCT_ALIGN); + elem_size = seq->elem_size; + + if( delta_elements == 0 ) + { + delta_elements = (1 << 10) / elem_size; + delta_elements = MAX( delta_elements, 1 ); + } + if( delta_elements * elem_size > useful_block_size ) + { + delta_elements = useful_block_size / elem_size; + if( delta_elements == 0 ) + CV_Error( CV_StsOutOfRange, "Storage block size is too small " + "to fit the sequence elements" ); + } + + seq->delta_elems = delta_elements; +} + + +/* Find a sequence element by its index: */ +CV_IMPL schar* +cvGetSeqElem( const CvSeq *seq, int index ) +{ + CvSeqBlock *block; + int count, total = seq->total; + + if( (unsigned)index >= (unsigned)total ) + { + index += index < 0 ? total : 0; + index -= index >= total ? total : 0; + if( (unsigned)index >= (unsigned)total ) + return 0; + } + + block = seq->first; + if( index + index <= total ) + { + while( index >= (count = block->count) ) + { + block = block->next; + index -= count; + } + } + else + { + do + { + block = block->prev; + total -= block->count; + } + while( index < total ); + index -= total; + } + + return block->data + index * seq->elem_size; +} + + +/* Calculate index of a sequence element: */ +CV_IMPL int +cvSeqElemIdx( const CvSeq* seq, const void* _element, CvSeqBlock** _block ) +{ + const schar *element = (const schar *)_element; + int elem_size; + int id = -1; + CvSeqBlock *first_block; + CvSeqBlock *block; + + if( !seq || !element ) + CV_Error( CV_StsNullPtr, "" ); + + block = first_block = seq->first; + elem_size = seq->elem_size; + + for( ;; ) + { + if( (unsigned)(element - block->data) < (unsigned) (block->count * elem_size) ) + { + if( _block ) + *_block = block; + if( elem_size <= ICV_SHIFT_TAB_MAX && (id = icvPower2ShiftTab[elem_size - 1]) >= 0 ) + id = (int)((size_t)(element - block->data) >> id); + else + id = (int)((size_t)(element - block->data) / elem_size); + id += block->start_index - seq->first->start_index; + break; + } + block = block->next; + if( block == first_block ) + break; + } + + return id; +} + + +CV_IMPL int +cvSliceLength( CvSlice slice, const CvSeq* seq ) +{ + int total = seq->total; + int length = slice.end_index - slice.start_index; + + if( length != 0 ) + { + if( slice.start_index < 0 ) + slice.start_index += total; + if( slice.end_index <= 0 ) + slice.end_index += total; + + length = slice.end_index - slice.start_index; + } + + while( length < 0 ) + length += total; + if( length > total ) + length = total; + + return length; +} + + +/* Copy all sequence elements into single continuous array: */ +CV_IMPL void* +cvCvtSeqToArray( const CvSeq *seq, void *array, CvSlice slice ) +{ + int elem_size, total; + CvSeqReader reader; + char *dst = (char*)array; + + if( !seq || !array ) + CV_Error( CV_StsNullPtr, "" ); + + elem_size = seq->elem_size; + total = cvSliceLength( slice, seq )*elem_size; + + if( total == 0 ) + return 0; + + cvStartReadSeq( seq, &reader, 0 ); + cvSetSeqReaderPos( &reader, slice.start_index, 0 ); + + do + { + int count = (int)(reader.block_max - reader.ptr); + if( count > total ) + count = total; + + memcpy( dst, reader.ptr, count ); + dst += count; + reader.block = reader.block->next; + reader.ptr = reader.block->data; + reader.block_max = reader.ptr + reader.block->count*elem_size; + total -= count; + } + while( total > 0 ); + + return array; +} + + +/* Construct a sequence from an array without copying any data. + NB: The resultant sequence cannot grow beyond its initial size: */ +CV_IMPL CvSeq* +cvMakeSeqHeaderForArray( int seq_flags, int header_size, int elem_size, + void *array, int total, CvSeq *seq, CvSeqBlock * block ) +{ + CvSeq* result = 0; + + if( elem_size <= 0 || header_size < (int)sizeof( CvSeq ) || total < 0 ) + CV_Error( CV_StsBadSize, "" ); + + if( !seq || ((!array || !block) && total > 0) ) + CV_Error( CV_StsNullPtr, "" ); + + memset( seq, 0, header_size ); + + seq->header_size = header_size; + seq->flags = (seq_flags & ~CV_MAGIC_MASK) | CV_SEQ_MAGIC_VAL; + { + int elemtype = CV_MAT_TYPE(seq_flags); + int typesize = CV_ELEM_SIZE(elemtype); + + if( elemtype != CV_SEQ_ELTYPE_GENERIC && + typesize != 0 && typesize != elem_size ) + CV_Error( CV_StsBadSize, + "Element size doesn't match to the size of predefined element type " + "(try to use 0 for sequence element type)" ); + } + seq->elem_size = elem_size; + seq->total = total; + seq->block_max = seq->ptr = (schar *) array + total * elem_size; + + if( total > 0 ) + { + seq->first = block; + block->prev = block->next = block; + block->start_index = 0; + block->count = total; + block->data = (schar *) array; + } + + result = seq; + + return result; +} + + +/* The function allocates space for at least one more sequence element. + If there are free sequence blocks (seq->free_blocks != 0) + they are reused, otherwise the space is allocated in the storage: */ +static void +icvGrowSeq( CvSeq *seq, int in_front_of ) +{ + CvSeqBlock *block; + + if( !seq ) + CV_Error( CV_StsNullPtr, "" ); + block = seq->free_blocks; + + if( !block ) + { + int elem_size = seq->elem_size; + int delta_elems = seq->delta_elems; + CvMemStorage *storage = seq->storage; + + if( seq->total >= delta_elems*4 ) + cvSetSeqBlockSize( seq, delta_elems*2 ); + + if( !storage ) + CV_Error( CV_StsNullPtr, "The sequence has NULL storage pointer" ); + + /* If there is a free space just after last allocated block + and it is big enough then enlarge the last block. + This can happen only if the new block is added to the end of sequence: */ + if( (unsigned)(ICV_FREE_PTR(storage) - seq->block_max) < CV_STRUCT_ALIGN && + storage->free_space >= seq->elem_size && !in_front_of ) + { + int delta = storage->free_space / elem_size; + + delta = MIN( delta, delta_elems ) * elem_size; + seq->block_max += delta; + storage->free_space = cvAlignLeft((int)(((schar*)storage->top + storage->block_size) - + seq->block_max), CV_STRUCT_ALIGN ); + return; + } + else + { + int delta = elem_size * delta_elems + ICV_ALIGNED_SEQ_BLOCK_SIZE; + + /* Try to allocate elements: */ + if( storage->free_space < delta ) + { + int small_block_size = MAX(1, delta_elems/3)*elem_size + + ICV_ALIGNED_SEQ_BLOCK_SIZE; + /* try to allocate smaller part */ + if( storage->free_space >= small_block_size + CV_STRUCT_ALIGN ) + { + delta = (storage->free_space - ICV_ALIGNED_SEQ_BLOCK_SIZE)/seq->elem_size; + delta = delta*seq->elem_size + ICV_ALIGNED_SEQ_BLOCK_SIZE; + } + else + { + icvGoNextMemBlock( storage ); + assert( storage->free_space >= delta ); + } + } + + block = (CvSeqBlock*)cvMemStorageAlloc( storage, delta ); + block->data = (schar*)cvAlignPtr( block + 1, CV_STRUCT_ALIGN ); + block->count = delta - ICV_ALIGNED_SEQ_BLOCK_SIZE; + block->prev = block->next = 0; + } + } + else + { + seq->free_blocks = block->next; + } + + if( !(seq->first) ) + { + seq->first = block; + block->prev = block->next = block; + } + else + { + block->prev = seq->first->prev; + block->next = seq->first; + block->prev->next = block->next->prev = block; + } + + /* For free blocks the field means + * total number of bytes in the block. + * + * For used blocks it means current number + * of sequence elements in the block: + */ + assert( block->count % seq->elem_size == 0 && block->count > 0 ); + + if( !in_front_of ) + { + seq->ptr = block->data; + seq->block_max = block->data + block->count; + block->start_index = block == block->prev ? 0 : + block->prev->start_index + block->prev->count; + } + else + { + int delta = block->count / seq->elem_size; + block->data += block->count; + + if( block != block->prev ) + { + assert( seq->first->start_index == 0 ); + seq->first = block; + } + else + { + seq->block_max = seq->ptr = block->data; + } + + block->start_index = 0; + + for( ;; ) + { + block->start_index += delta; + block = block->next; + if( block == seq->first ) + break; + } + } + + block->count = 0; +} + +/* Recycle a sequence block: */ +static void +icvFreeSeqBlock( CvSeq *seq, int in_front_of ) +{ + CvSeqBlock *block = seq->first; + + assert( (in_front_of ? block : block->prev)->count == 0 ); + + if( block == block->prev ) /* single block case */ + { + block->count = (int)(seq->block_max - block->data) + block->start_index * seq->elem_size; + block->data = seq->block_max - block->count; + seq->first = 0; + seq->ptr = seq->block_max = 0; + seq->total = 0; + } + else + { + if( !in_front_of ) + { + block = block->prev; + assert( seq->ptr == block->data ); + + block->count = (int)(seq->block_max - seq->ptr); + seq->block_max = seq->ptr = block->prev->data + + block->prev->count * seq->elem_size; + } + else + { + int delta = block->start_index; + + block->count = delta * seq->elem_size; + block->data -= block->count; + + /* Update start indices of sequence blocks: */ + for( ;; ) + { + block->start_index -= delta; + block = block->next; + if( block == seq->first ) + break; + } + + seq->first = block->next; + } + + block->prev->next = block->next; + block->next->prev = block->prev; + } + + assert( block->count > 0 && block->count % seq->elem_size == 0 ); + block->next = seq->free_blocks; + seq->free_blocks = block; +} + + +/****************************************************************************************\ +* Sequence Writer implementation * +\****************************************************************************************/ + +/* Initialize sequence writer: */ +CV_IMPL void +cvStartAppendToSeq( CvSeq *seq, CvSeqWriter * writer ) +{ + if( !seq || !writer ) + CV_Error( CV_StsNullPtr, "" ); + + memset( writer, 0, sizeof( *writer )); + writer->header_size = sizeof( CvSeqWriter ); + + writer->seq = seq; + writer->block = seq->first ? seq->first->prev : 0; + writer->ptr = seq->ptr; + writer->block_max = seq->block_max; +} + + +/* Initialize sequence writer: */ +CV_IMPL void +cvStartWriteSeq( int seq_flags, int header_size, + int elem_size, CvMemStorage * storage, CvSeqWriter * writer ) +{ + if( !storage || !writer ) + CV_Error( CV_StsNullPtr, "" ); + + CvSeq* seq = cvCreateSeq( seq_flags, header_size, elem_size, storage ); + cvStartAppendToSeq( seq, writer ); +} + + +/* Update sequence header: */ +CV_IMPL void +cvFlushSeqWriter( CvSeqWriter * writer ) +{ + if( !writer ) + CV_Error( CV_StsNullPtr, "" ); + + CvSeq* seq = writer->seq; + seq->ptr = writer->ptr; + + if( writer->block ) + { + int total = 0; + CvSeqBlock *first_block = writer->seq->first; + CvSeqBlock *block = first_block; + + writer->block->count = (int)((writer->ptr - writer->block->data) / seq->elem_size); + assert( writer->block->count > 0 ); + + do + { + total += block->count; + block = block->next; + } + while( block != first_block ); + + writer->seq->total = total; + } +} + + +/* Calls icvFlushSeqWriter and finishes writing process: */ +CV_IMPL CvSeq * +cvEndWriteSeq( CvSeqWriter * writer ) +{ + if( !writer ) + CV_Error( CV_StsNullPtr, "" ); + + cvFlushSeqWriter( writer ); + CvSeq* seq = writer->seq; + + /* Truncate the last block: */ + if( writer->block && writer->seq->storage ) + { + CvMemStorage *storage = seq->storage; + schar *storage_block_max = (schar *) storage->top + storage->block_size; + + assert( writer->block->count > 0 ); + + if( (unsigned)((storage_block_max - storage->free_space) + - seq->block_max) < CV_STRUCT_ALIGN ) + { + storage->free_space = cvAlignLeft((int)(storage_block_max - seq->ptr), CV_STRUCT_ALIGN); + seq->block_max = seq->ptr; + } + } + + writer->ptr = 0; + return seq; +} + + +/* Create new sequence block: */ +CV_IMPL void +cvCreateSeqBlock( CvSeqWriter * writer ) +{ + if( !writer || !writer->seq ) + CV_Error( CV_StsNullPtr, "" ); + + CvSeq* seq = writer->seq; + + cvFlushSeqWriter( writer ); + + icvGrowSeq( seq, 0 ); + + writer->block = seq->first->prev; + writer->ptr = seq->ptr; + writer->block_max = seq->block_max; +} + + +/****************************************************************************************\ +* Sequence Reader implementation * +\****************************************************************************************/ + +/* Initialize sequence reader: */ +CV_IMPL void +cvStartReadSeq( const CvSeq *seq, CvSeqReader * reader, int reverse ) +{ + CvSeqBlock *first_block; + CvSeqBlock *last_block; + + if( reader ) + { + reader->seq = 0; + reader->block = 0; + reader->ptr = reader->block_max = reader->block_min = 0; + } + + if( !seq || !reader ) + CV_Error( CV_StsNullPtr, "" ); + + reader->header_size = sizeof( CvSeqReader ); + reader->seq = (CvSeq*)seq; + + first_block = seq->first; + + if( first_block ) + { + last_block = first_block->prev; + reader->ptr = first_block->data; + reader->prev_elem = CV_GET_LAST_ELEM( seq, last_block ); + reader->delta_index = seq->first->start_index; + + if( reverse ) + { + schar *temp = reader->ptr; + + reader->ptr = reader->prev_elem; + reader->prev_elem = temp; + + reader->block = last_block; + } + else + { + reader->block = first_block; + } + + reader->block_min = reader->block->data; + reader->block_max = reader->block_min + reader->block->count * seq->elem_size; + } + else + { + reader->delta_index = 0; + reader->block = 0; + + reader->ptr = reader->prev_elem = reader->block_min = reader->block_max = 0; + } +} + + +/* Change the current reading block + * to the previous or to the next: + */ +CV_IMPL void +cvChangeSeqBlock( void* _reader, int direction ) +{ + CvSeqReader* reader = (CvSeqReader*)_reader; + + if( !reader ) + CV_Error( CV_StsNullPtr, "" ); + + if( direction > 0 ) + { + reader->block = reader->block->next; + reader->ptr = reader->block->data; + } + else + { + reader->block = reader->block->prev; + reader->ptr = CV_GET_LAST_ELEM( reader->seq, reader->block ); + } + reader->block_min = reader->block->data; + reader->block_max = reader->block_min + reader->block->count * reader->seq->elem_size; +} + + +/* Return the current reader position: */ +CV_IMPL int +cvGetSeqReaderPos( CvSeqReader* reader ) +{ + int elem_size; + int index = -1; + + if( !reader || !reader->ptr ) + CV_Error( CV_StsNullPtr, "" ); + + elem_size = reader->seq->elem_size; + if( elem_size <= ICV_SHIFT_TAB_MAX && (index = icvPower2ShiftTab[elem_size - 1]) >= 0 ) + index = (int)((reader->ptr - reader->block_min) >> index); + else + index = (int)((reader->ptr - reader->block_min) / elem_size); + + index += reader->block->start_index - reader->delta_index; + + return index; +} + + +/* Set reader position to given position, + * either absolute or relative to the + * current one: + */ +CV_IMPL void +cvSetSeqReaderPos( CvSeqReader* reader, int index, int is_relative ) +{ + CvSeqBlock *block; + int elem_size, count, total; + + if( !reader || !reader->seq ) + CV_Error( CV_StsNullPtr, "" ); + + total = reader->seq->total; + elem_size = reader->seq->elem_size; + + if( !is_relative ) + { + if( index < 0 ) + { + if( index < -total ) + CV_Error( CV_StsOutOfRange, "" ); + index += total; + } + else if( index >= total ) + { + index -= total; + if( index >= total ) + CV_Error( CV_StsOutOfRange, "" ); + } + + block = reader->seq->first; + if( index >= (count = block->count) ) + { + if( index + index <= total ) + { + do + { + block = block->next; + index -= count; + } + while( index >= (count = block->count) ); + } + else + { + do + { + block = block->prev; + total -= block->count; + } + while( index < total ); + index -= total; + } + } + reader->ptr = block->data + index * elem_size; + if( reader->block != block ) + { + reader->block = block; + reader->block_min = block->data; + reader->block_max = block->data + block->count * elem_size; + } + } + else + { + schar* ptr = reader->ptr; + index *= elem_size; + block = reader->block; + + if( index > 0 ) + { + while( ptr + index >= reader->block_max ) + { + int delta = (int)(reader->block_max - ptr); + index -= delta; + reader->block = block = block->next; + reader->block_min = ptr = block->data; + reader->block_max = block->data + block->count*elem_size; + } + reader->ptr = ptr + index; + } + else + { + while( ptr + index < reader->block_min ) + { + int delta = (int)(ptr - reader->block_min); + index += delta; + reader->block = block = block->prev; + reader->block_min = block->data; + reader->block_max = ptr = block->data + block->count*elem_size; + } + reader->ptr = ptr + index; + } + } +} + + +/* Push element onto the sequence: */ +CV_IMPL schar* +cvSeqPush( CvSeq *seq, const void *element ) +{ + schar *ptr = 0; + size_t elem_size; + + if( !seq ) + CV_Error( CV_StsNullPtr, "" ); + + elem_size = seq->elem_size; + ptr = seq->ptr; + + if( ptr >= seq->block_max ) + { + icvGrowSeq( seq, 0 ); + + ptr = seq->ptr; + assert( ptr + elem_size <= seq->block_max /*&& ptr == seq->block_min */ ); + } + + if( element ) + memcpy( ptr, element, elem_size ); + seq->first->prev->count++; + seq->total++; + seq->ptr = ptr + elem_size; + + return ptr; +} + + +/* Pop last element off of the sequence: */ +CV_IMPL void +cvSeqPop( CvSeq *seq, void *element ) +{ + schar *ptr; + int elem_size; + + if( !seq ) + CV_Error( CV_StsNullPtr, "" ); + if( seq->total <= 0 ) + CV_Error( CV_StsBadSize, "" ); + + elem_size = seq->elem_size; + seq->ptr = ptr = seq->ptr - elem_size; + + if( element ) + memcpy( element, ptr, elem_size ); + seq->ptr = ptr; + seq->total--; + + if( --(seq->first->prev->count) == 0 ) + { + icvFreeSeqBlock( seq, 0 ); + assert( seq->ptr == seq->block_max ); + } +} + + +/* Push element onto the front of the sequence: */ +CV_IMPL schar* +cvSeqPushFront( CvSeq *seq, const void *element ) +{ + schar* ptr = 0; + int elem_size; + CvSeqBlock *block; + + if( !seq ) + CV_Error( CV_StsNullPtr, "" ); + + elem_size = seq->elem_size; + block = seq->first; + + if( !block || block->start_index == 0 ) + { + icvGrowSeq( seq, 1 ); + + block = seq->first; + assert( block->start_index > 0 ); + } + + ptr = block->data -= elem_size; + + if( element ) + memcpy( ptr, element, elem_size ); + block->count++; + block->start_index--; + seq->total++; + + return ptr; +} + + +/* Shift out first element of the sequence: */ +CV_IMPL void +cvSeqPopFront( CvSeq *seq, void *element ) +{ + int elem_size; + CvSeqBlock *block; + + if( !seq ) + CV_Error( CV_StsNullPtr, "" ); + if( seq->total <= 0 ) + CV_Error( CV_StsBadSize, "" ); + + elem_size = seq->elem_size; + block = seq->first; + + if( element ) + memcpy( element, block->data, elem_size ); + block->data += elem_size; + block->start_index++; + seq->total--; + + if( --(block->count) == 0 ) + icvFreeSeqBlock( seq, 1 ); +} + +/* Insert new element in middle of sequence: */ +CV_IMPL schar* +cvSeqInsert( CvSeq *seq, int before_index, const void *element ) +{ + int elem_size; + int block_size; + CvSeqBlock *block; + int delta_index; + int total; + schar* ret_ptr = 0; + + if( !seq ) + CV_Error( CV_StsNullPtr, "" ); + + total = seq->total; + before_index += before_index < 0 ? total : 0; + before_index -= before_index > total ? total : 0; + + if( (unsigned)before_index > (unsigned)total ) + CV_Error( CV_StsOutOfRange, "" ); + + if( before_index == total ) + { + ret_ptr = cvSeqPush( seq, element ); + } + else if( before_index == 0 ) + { + ret_ptr = cvSeqPushFront( seq, element ); + } + else + { + elem_size = seq->elem_size; + + if( before_index >= total >> 1 ) + { + schar *ptr = seq->ptr + elem_size; + + if( ptr > seq->block_max ) + { + icvGrowSeq( seq, 0 ); + + ptr = seq->ptr + elem_size; + assert( ptr <= seq->block_max ); + } + + delta_index = seq->first->start_index; + block = seq->first->prev; + block->count++; + block_size = (int)(ptr - block->data); + + while( before_index < block->start_index - delta_index ) + { + CvSeqBlock *prev_block = block->prev; + + memmove( block->data + elem_size, block->data, block_size - elem_size ); + block_size = prev_block->count * elem_size; + memcpy( block->data, prev_block->data + block_size - elem_size, elem_size ); + block = prev_block; + + /* Check that we don't fall into an infinite loop: */ + assert( block != seq->first->prev ); + } + + before_index = (before_index - block->start_index + delta_index) * elem_size; + memmove( block->data + before_index + elem_size, block->data + before_index, + block_size - before_index - elem_size ); + + ret_ptr = block->data + before_index; + + if( element ) + memcpy( ret_ptr, element, elem_size ); + seq->ptr = ptr; + } + else + { + block = seq->first; + + if( block->start_index == 0 ) + { + icvGrowSeq( seq, 1 ); + + block = seq->first; + } + + delta_index = block->start_index; + block->count++; + block->start_index--; + block->data -= elem_size; + + while( before_index > block->start_index - delta_index + block->count ) + { + CvSeqBlock *next_block = block->next; + + block_size = block->count * elem_size; + memmove( block->data, block->data + elem_size, block_size - elem_size ); + memcpy( block->data + block_size - elem_size, next_block->data, elem_size ); + block = next_block; + + /* Check that we don't fall into an infinite loop: */ + assert( block != seq->first ); + } + + before_index = (before_index - block->start_index + delta_index) * elem_size; + memmove( block->data, block->data + elem_size, before_index - elem_size ); + + ret_ptr = block->data + before_index - elem_size; + + if( element ) + memcpy( ret_ptr, element, elem_size ); + } + + seq->total = total + 1; + } + + return ret_ptr; +} + + +/* Removes element from sequence: */ +CV_IMPL void +cvSeqRemove( CvSeq *seq, int index ) +{ + schar *ptr; + int elem_size; + int block_size; + CvSeqBlock *block; + int delta_index; + int total, front = 0; + + if( !seq ) + CV_Error( CV_StsNullPtr, "" ); + + total = seq->total; + + index += index < 0 ? total : 0; + index -= index >= total ? total : 0; + + if( (unsigned) index >= (unsigned) total ) + CV_Error( CV_StsOutOfRange, "Invalid index" ); + + if( index == total - 1 ) + { + cvSeqPop( seq, 0 ); + } + else if( index == 0 ) + { + cvSeqPopFront( seq, 0 ); + } + else + { + block = seq->first; + elem_size = seq->elem_size; + delta_index = block->start_index; + while( block->start_index - delta_index + block->count <= index ) + block = block->next; + + ptr = block->data + (index - block->start_index + delta_index) * elem_size; + + front = index < total >> 1; + if( !front ) + { + block_size = block->count * elem_size - (int)(ptr - block->data); + + while( block != seq->first->prev ) /* while not the last block */ + { + CvSeqBlock *next_block = block->next; + + memmove( ptr, ptr + elem_size, block_size - elem_size ); + memcpy( ptr + block_size - elem_size, next_block->data, elem_size ); + block = next_block; + ptr = block->data; + block_size = block->count * elem_size; + } + + memmove( ptr, ptr + elem_size, block_size - elem_size ); + seq->ptr -= elem_size; + } + else + { + ptr += elem_size; + block_size = (int)(ptr - block->data); + + while( block != seq->first ) + { + CvSeqBlock *prev_block = block->prev; + + memmove( block->data + elem_size, block->data, block_size - elem_size ); + block_size = prev_block->count * elem_size; + memcpy( block->data, prev_block->data + block_size - elem_size, elem_size ); + block = prev_block; + } + + memmove( block->data + elem_size, block->data, block_size - elem_size ); + block->data += elem_size; + block->start_index++; + } + + seq->total = total - 1; + if( --block->count == 0 ) + icvFreeSeqBlock( seq, front ); + } +} + + +/* Add several elements to the beginning or end of a sequence: */ +CV_IMPL void +cvSeqPushMulti( CvSeq *seq, const void *_elements, int count, int front ) +{ + char *elements = (char *) _elements; + + if( !seq ) + CV_Error( CV_StsNullPtr, "NULL sequence pointer" ); + if( count < 0 ) + CV_Error( CV_StsBadSize, "number of removed elements is negative" ); + + int elem_size = seq->elem_size; + + if( !front ) + { + while( count > 0 ) + { + int delta = (int)((seq->block_max - seq->ptr) / elem_size); + + delta = MIN( delta, count ); + if( delta > 0 ) + { + seq->first->prev->count += delta; + seq->total += delta; + count -= delta; + delta *= elem_size; + if( elements ) + { + memcpy( seq->ptr, elements, delta ); + elements += delta; + } + seq->ptr += delta; + } + + if( count > 0 ) + icvGrowSeq( seq, 0 ); + } + } + else + { + CvSeqBlock* block = seq->first; + + while( count > 0 ) + { + int delta; + + if( !block || block->start_index == 0 ) + { + icvGrowSeq( seq, 1 ); + + block = seq->first; + assert( block->start_index > 0 ); + } + + delta = MIN( block->start_index, count ); + count -= delta; + block->start_index -= delta; + block->count += delta; + seq->total += delta; + delta *= elem_size; + block->data -= delta; + + if( elements ) + memcpy( block->data, elements + count*elem_size, delta ); + } + } +} + + +/* Remove several elements from the end of sequence: */ +CV_IMPL void +cvSeqPopMulti( CvSeq *seq, void *_elements, int count, int front ) +{ + char *elements = (char *) _elements; + + if( !seq ) + CV_Error( CV_StsNullPtr, "NULL sequence pointer" ); + if( count < 0 ) + CV_Error( CV_StsBadSize, "number of removed elements is negative" ); + + count = MIN( count, seq->total ); + + if( !front ) + { + if( elements ) + elements += count * seq->elem_size; + + while( count > 0 ) + { + int delta = seq->first->prev->count; + + delta = MIN( delta, count ); + assert( delta > 0 ); + + seq->first->prev->count -= delta; + seq->total -= delta; + count -= delta; + delta *= seq->elem_size; + seq->ptr -= delta; + + if( elements ) + { + elements -= delta; + memcpy( elements, seq->ptr, delta ); + } + + if( seq->first->prev->count == 0 ) + icvFreeSeqBlock( seq, 0 ); + } + } + else + { + while( count > 0 ) + { + int delta = seq->first->count; + + delta = MIN( delta, count ); + assert( delta > 0 ); + + seq->first->count -= delta; + seq->total -= delta; + count -= delta; + seq->first->start_index += delta; + delta *= seq->elem_size; + + if( elements ) + { + memcpy( elements, seq->first->data, delta ); + elements += delta; + } + + seq->first->data += delta; + if( seq->first->count == 0 ) + icvFreeSeqBlock( seq, 1 ); + } + } +} + + +/* Remove all elements from a sequence: */ +CV_IMPL void +cvClearSeq( CvSeq *seq ) +{ + if( !seq ) + CV_Error( CV_StsNullPtr, "" ); + cvSeqPopMulti( seq, 0, seq->total ); +} + + +CV_IMPL CvSeq* +cvSeqSlice( const CvSeq* seq, CvSlice slice, CvMemStorage* storage, int copy_data ) +{ + CvSeq* subseq = 0; + int elem_size, count, length; + CvSeqReader reader; + CvSeqBlock *block, *first_block = 0, *last_block = 0; + + if( !CV_IS_SEQ(seq) ) + CV_Error( CV_StsBadArg, "Invalid sequence header" ); + + if( !storage ) + { + storage = seq->storage; + if( !storage ) + CV_Error( CV_StsNullPtr, "NULL storage pointer" ); + } + + elem_size = seq->elem_size; + length = cvSliceLength( slice, seq ); + if( slice.start_index < 0 ) + slice.start_index += seq->total; + else if( slice.start_index >= seq->total ) + slice.start_index -= seq->total; + if( (unsigned)length > (unsigned)seq->total || + ((unsigned)slice.start_index >= (unsigned)seq->total && length != 0) ) + CV_Error( CV_StsOutOfRange, "Bad sequence slice" ); + + subseq = cvCreateSeq( seq->flags, seq->header_size, elem_size, storage ); + + if( length > 0 ) + { + cvStartReadSeq( seq, &reader, 0 ); + cvSetSeqReaderPos( &reader, slice.start_index, 0 ); + count = (int)((reader.block_max - reader.ptr)/elem_size); + + do + { + int bl = MIN( count, length ); + + if( !copy_data ) + { + block = (CvSeqBlock*)cvMemStorageAlloc( storage, sizeof(*block) ); + if( !first_block ) + { + first_block = subseq->first = block->prev = block->next = block; + block->start_index = 0; + } + else + { + block->prev = last_block; + block->next = first_block; + last_block->next = first_block->prev = block; + block->start_index = last_block->start_index + last_block->count; + } + last_block = block; + block->data = reader.ptr; + block->count = bl; + subseq->total += bl; + } + else + cvSeqPushMulti( subseq, reader.ptr, bl, 0 ); + length -= bl; + reader.block = reader.block->next; + reader.ptr = reader.block->data; + count = reader.block->count; + } + while( length > 0 ); + } + + return subseq; +} + + +// Remove slice from the middle of the sequence. +// !!! TODO !!! Implement more efficient algorithm +CV_IMPL void +cvSeqRemoveSlice( CvSeq* seq, CvSlice slice ) +{ + int total, length; + + if( !CV_IS_SEQ(seq) ) + CV_Error( CV_StsBadArg, "Invalid sequence header" ); + + length = cvSliceLength( slice, seq ); + total = seq->total; + + if( slice.start_index < 0 ) + slice.start_index += total; + else if( slice.start_index >= total ) + slice.start_index -= total; + + if( (unsigned)slice.start_index >= (unsigned)total ) + CV_Error( CV_StsOutOfRange, "start slice index is out of range" ); + + slice.end_index = slice.start_index + length; + + if( slice.end_index < total ) + { + CvSeqReader reader_to, reader_from; + int elem_size = seq->elem_size; + + cvStartReadSeq( seq, &reader_to ); + cvStartReadSeq( seq, &reader_from ); + + if( slice.start_index > total - slice.end_index ) + { + int i, count = seq->total - slice.end_index; + cvSetSeqReaderPos( &reader_to, slice.start_index ); + cvSetSeqReaderPos( &reader_from, slice.end_index ); + + for( i = 0; i < count; i++ ) + { + memcpy( reader_to.ptr, reader_from.ptr, elem_size ); + CV_NEXT_SEQ_ELEM( elem_size, reader_to ); + CV_NEXT_SEQ_ELEM( elem_size, reader_from ); + } + + cvSeqPopMulti( seq, 0, slice.end_index - slice.start_index ); + } + else + { + int i, count = slice.start_index; + cvSetSeqReaderPos( &reader_to, slice.end_index ); + cvSetSeqReaderPos( &reader_from, slice.start_index ); + + for( i = 0; i < count; i++ ) + { + CV_PREV_SEQ_ELEM( elem_size, reader_to ); + CV_PREV_SEQ_ELEM( elem_size, reader_from ); + + memcpy( reader_to.ptr, reader_from.ptr, elem_size ); + } + + cvSeqPopMulti( seq, 0, slice.end_index - slice.start_index, 1 ); + } + } + else + { + cvSeqPopMulti( seq, 0, total - slice.start_index ); + cvSeqPopMulti( seq, 0, slice.end_index - total, 1 ); + } +} + + +// Insert a sequence into the middle of another sequence: +// !!! TODO !!! Implement more efficient algorithm +CV_IMPL void +cvSeqInsertSlice( CvSeq* seq, int index, const CvArr* from_arr ) +{ + CvSeqReader reader_to, reader_from; + int i, elem_size, total, from_total; + CvSeq from_header, *from = (CvSeq*)from_arr; + CvSeqBlock block; + + if( !CV_IS_SEQ(seq) ) + CV_Error( CV_StsBadArg, "Invalid destination sequence header" ); + + if( !CV_IS_SEQ(from)) + { + CvMat* mat = (CvMat*)from; + if( !CV_IS_MAT(mat)) + CV_Error( CV_StsBadArg, "Source is not a sequence nor matrix" ); + + if( !CV_IS_MAT_CONT(mat->type) || (mat->rows != 1 && mat->cols != 1) ) + CV_Error( CV_StsBadArg, "The source array must be 1d coninuous vector" ); + + from = cvMakeSeqHeaderForArray( CV_SEQ_KIND_GENERIC, sizeof(from_header), + CV_ELEM_SIZE(mat->type), + mat->data.ptr, mat->cols + mat->rows - 1, + &from_header, &block ); + } + + if( seq->elem_size != from->elem_size ) + CV_Error( CV_StsUnmatchedSizes, + "Source and destination sequence element sizes are different." ); + + from_total = from->total; + + if( from_total == 0 ) + return; + + total = seq->total; + index += index < 0 ? total : 0; + index -= index > total ? total : 0; + + if( (unsigned)index > (unsigned)total ) + CV_Error( CV_StsOutOfRange, "" ); + + elem_size = seq->elem_size; + + if( index < (total >> 1) ) + { + cvSeqPushMulti( seq, 0, from_total, 1 ); + + cvStartReadSeq( seq, &reader_to ); + cvStartReadSeq( seq, &reader_from ); + cvSetSeqReaderPos( &reader_from, from_total ); + + for( i = 0; i < index; i++ ) + { + memcpy( reader_to.ptr, reader_from.ptr, elem_size ); + CV_NEXT_SEQ_ELEM( elem_size, reader_to ); + CV_NEXT_SEQ_ELEM( elem_size, reader_from ); + } + } + else + { + cvSeqPushMulti( seq, 0, from_total ); + + cvStartReadSeq( seq, &reader_to ); + cvStartReadSeq( seq, &reader_from ); + cvSetSeqReaderPos( &reader_from, total ); + cvSetSeqReaderPos( &reader_to, seq->total ); + + for( i = 0; i < total - index; i++ ) + { + CV_PREV_SEQ_ELEM( elem_size, reader_to ); + CV_PREV_SEQ_ELEM( elem_size, reader_from ); + memcpy( reader_to.ptr, reader_from.ptr, elem_size ); + } + } + + cvStartReadSeq( from, &reader_from ); + cvSetSeqReaderPos( &reader_to, index ); + + for( i = 0; i < from_total; i++ ) + { + memcpy( reader_to.ptr, reader_from.ptr, elem_size ); + CV_NEXT_SEQ_ELEM( elem_size, reader_to ); + CV_NEXT_SEQ_ELEM( elem_size, reader_from ); + } +} + +// Sort the sequence using user-specified comparison function. +// The semantics is similar to qsort() function. +// The code is based on BSD system qsort(): +// * Copyright (c) 1992, 1993 +// * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software +// * must display the following acknowledgement: +// * This product includes software developed by the University of +// * California, Berkeley and its contributors. +// * 4. Neither the name of the University nor the names of its contributors +// * may be used to endorse or promote products derived from this software +// * without specific prior written permission. +// * +// * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + +typedef struct CvSeqReaderPos +{ + CvSeqBlock* block; + schar* ptr; + schar* block_min; + schar* block_max; +} +CvSeqReaderPos; + +#define CV_SAVE_READER_POS( reader, pos ) \ +{ \ + (pos).block = (reader).block; \ + (pos).ptr = (reader).ptr; \ + (pos).block_min = (reader).block_min; \ + (pos).block_max = (reader).block_max; \ +} + +#define CV_RESTORE_READER_POS( reader, pos )\ +{ \ + (reader).block = (pos).block; \ + (reader).ptr = (pos).ptr; \ + (reader).block_min = (pos).block_min; \ + (reader).block_max = (pos).block_max; \ +} + +inline schar* +icvMed3( schar* a, schar* b, schar* c, CvCmpFunc cmp_func, void* aux ) +{ + return cmp_func(a, b, aux) < 0 ? + (cmp_func(b, c, aux) < 0 ? b : cmp_func(a, c, aux) < 0 ? c : a) + :(cmp_func(b, c, aux) > 0 ? b : cmp_func(a, c, aux) < 0 ? a : c); +} + +CV_IMPL void +cvSeqSort( CvSeq* seq, CvCmpFunc cmp_func, void* aux ) +{ + int elem_size; + int isort_thresh = 7; + CvSeqReader left, right; + int sp = 0; + + struct + { + CvSeqReaderPos lb; + CvSeqReaderPos ub; + } + stack[48]; + + if( !CV_IS_SEQ(seq) ) + CV_Error( !seq ? CV_StsNullPtr : CV_StsBadArg, "Bad input sequence" ); + + if( !cmp_func ) + CV_Error( CV_StsNullPtr, "Null compare function" ); + + if( seq->total <= 1 ) + return; + + elem_size = seq->elem_size; + isort_thresh *= elem_size; + + cvStartReadSeq( seq, &left, 0 ); + right = left; + CV_SAVE_READER_POS( left, stack[0].lb ); + CV_PREV_SEQ_ELEM( elem_size, right ); + CV_SAVE_READER_POS( right, stack[0].ub ); + + while( sp >= 0 ) + { + CV_RESTORE_READER_POS( left, stack[sp].lb ); + CV_RESTORE_READER_POS( right, stack[sp].ub ); + sp--; + + for(;;) + { + int i, n, m; + CvSeqReader ptr, ptr2; + + if( left.block == right.block ) + n = (int)(right.ptr - left.ptr) + elem_size; + else + { + n = cvGetSeqReaderPos( &right ); + n = (n - cvGetSeqReaderPos( &left ) + 1)*elem_size; + } + + if( n <= isort_thresh ) + { + insert_sort: + ptr = ptr2 = left; + CV_NEXT_SEQ_ELEM( elem_size, ptr ); + CV_NEXT_SEQ_ELEM( elem_size, right ); + while( ptr.ptr != right.ptr ) + { + ptr2.ptr = ptr.ptr; + if( ptr2.block != ptr.block ) + { + ptr2.block = ptr.block; + ptr2.block_min = ptr.block_min; + ptr2.block_max = ptr.block_max; + } + while( ptr2.ptr != left.ptr ) + { + schar* cur = ptr2.ptr; + CV_PREV_SEQ_ELEM( elem_size, ptr2 ); + if( cmp_func( ptr2.ptr, cur, aux ) <= 0 ) + break; + CV_SWAP_ELEMS( ptr2.ptr, cur, elem_size ); + } + CV_NEXT_SEQ_ELEM( elem_size, ptr ); + } + break; + } + else + { + CvSeqReader left0, left1, right0, right1; + CvSeqReader tmp0, tmp1; + schar *m1, *m2, *m3, *pivot; + int swap_cnt = 0; + int l, l0, l1, r, r0, r1; + + left0 = tmp0 = left; + right0 = right1 = right; + n /= elem_size; + + if( n > 40 ) + { + int d = n / 8; + schar *p1, *p2, *p3; + p1 = tmp0.ptr; + cvSetSeqReaderPos( &tmp0, d, 1 ); + p2 = tmp0.ptr; + cvSetSeqReaderPos( &tmp0, d, 1 ); + p3 = tmp0.ptr; + m1 = icvMed3( p1, p2, p3, cmp_func, aux ); + cvSetSeqReaderPos( &tmp0, (n/2) - d*3, 1 ); + p1 = tmp0.ptr; + cvSetSeqReaderPos( &tmp0, d, 1 ); + p2 = tmp0.ptr; + cvSetSeqReaderPos( &tmp0, d, 1 ); + p3 = tmp0.ptr; + m2 = icvMed3( p1, p2, p3, cmp_func, aux ); + cvSetSeqReaderPos( &tmp0, n - 1 - d*3 - n/2, 1 ); + p1 = tmp0.ptr; + cvSetSeqReaderPos( &tmp0, d, 1 ); + p2 = tmp0.ptr; + cvSetSeqReaderPos( &tmp0, d, 1 ); + p3 = tmp0.ptr; + m3 = icvMed3( p1, p2, p3, cmp_func, aux ); + } + else + { + m1 = tmp0.ptr; + cvSetSeqReaderPos( &tmp0, n/2, 1 ); + m2 = tmp0.ptr; + cvSetSeqReaderPos( &tmp0, n - 1 - n/2, 1 ); + m3 = tmp0.ptr; + } + + pivot = icvMed3( m1, m2, m3, cmp_func, aux ); + left = left0; + if( pivot != left.ptr ) + { + CV_SWAP_ELEMS( pivot, left.ptr, elem_size ); + pivot = left.ptr; + } + CV_NEXT_SEQ_ELEM( elem_size, left ); + left1 = left; + + for(;;) + { + while( left.ptr != right.ptr && (r = cmp_func(left.ptr, pivot, aux)) <= 0 ) + { + if( r == 0 ) + { + if( left1.ptr != left.ptr ) + CV_SWAP_ELEMS( left1.ptr, left.ptr, elem_size ); + swap_cnt = 1; + CV_NEXT_SEQ_ELEM( elem_size, left1 ); + } + CV_NEXT_SEQ_ELEM( elem_size, left ); + } + + while( left.ptr != right.ptr && (r = cmp_func(right.ptr,pivot, aux)) >= 0 ) + { + if( r == 0 ) + { + if( right1.ptr != right.ptr ) + CV_SWAP_ELEMS( right1.ptr, right.ptr, elem_size ); + swap_cnt = 1; + CV_PREV_SEQ_ELEM( elem_size, right1 ); + } + CV_PREV_SEQ_ELEM( elem_size, right ); + } + + if( left.ptr == right.ptr ) + { + r = cmp_func(left.ptr, pivot, aux); + if( r == 0 ) + { + if( left1.ptr != left.ptr ) + CV_SWAP_ELEMS( left1.ptr, left.ptr, elem_size ); + swap_cnt = 1; + CV_NEXT_SEQ_ELEM( elem_size, left1 ); + } + if( r <= 0 ) + { + CV_NEXT_SEQ_ELEM( elem_size, left ); + } + else + { + CV_PREV_SEQ_ELEM( elem_size, right ); + } + break; + } + + CV_SWAP_ELEMS( left.ptr, right.ptr, elem_size ); + CV_NEXT_SEQ_ELEM( elem_size, left ); + r = left.ptr == right.ptr; + CV_PREV_SEQ_ELEM( elem_size, right ); + swap_cnt = 1; + if( r ) + break; + } + + if( swap_cnt == 0 ) + { + left = left0, right = right0; + goto insert_sort; + } + + l = cvGetSeqReaderPos( &left ); + if( l == 0 ) + l = seq->total; + l0 = cvGetSeqReaderPos( &left0 ); + l1 = cvGetSeqReaderPos( &left1 ); + if( l1 == 0 ) + l1 = seq->total; + + n = MIN( l - l1, l1 - l0 ); + if( n > 0 ) + { + tmp0 = left0; + tmp1 = left; + cvSetSeqReaderPos( &tmp1, 0-n, 1 ); + for( i = 0; i < n; i++ ) + { + CV_SWAP_ELEMS( tmp0.ptr, tmp1.ptr, elem_size ); + CV_NEXT_SEQ_ELEM( elem_size, tmp0 ); + CV_NEXT_SEQ_ELEM( elem_size, tmp1 ); + } + } + + r = cvGetSeqReaderPos( &right ); + r0 = cvGetSeqReaderPos( &right0 ); + r1 = cvGetSeqReaderPos( &right1 ); + m = MIN( r0 - r1, r1 - r ); + if( m > 0 ) + { + tmp0 = left; + tmp1 = right0; + cvSetSeqReaderPos( &tmp1, 1-m, 1 ); + for( i = 0; i < m; i++ ) + { + CV_SWAP_ELEMS( tmp0.ptr, tmp1.ptr, elem_size ); + CV_NEXT_SEQ_ELEM( elem_size, tmp0 ); + CV_NEXT_SEQ_ELEM( elem_size, tmp1 ); + } + } + + n = l - l1; + m = r1 - r; + if( n > 1 ) + { + if( m > 1 ) + { + if( n > m ) + { + sp++; + CV_SAVE_READER_POS( left0, stack[sp].lb ); + cvSetSeqReaderPos( &left0, n - 1, 1 ); + CV_SAVE_READER_POS( left0, stack[sp].ub ); + left = right = right0; + cvSetSeqReaderPos( &left, 1 - m, 1 ); + } + else + { + sp++; + CV_SAVE_READER_POS( right0, stack[sp].ub ); + cvSetSeqReaderPos( &right0, 1 - m, 1 ); + CV_SAVE_READER_POS( right0, stack[sp].lb ); + left = right = left0; + cvSetSeqReaderPos( &right, n - 1, 1 ); + } + } + else + { + left = right = left0; + cvSetSeqReaderPos( &right, n - 1, 1 ); + } + } + else if( m > 1 ) + { + left = right = right0; + cvSetSeqReaderPos( &left, 1 - m, 1 ); + } + else + break; + } + } + } +} + + +CV_IMPL schar* +cvSeqSearch( CvSeq* seq, const void* _elem, CvCmpFunc cmp_func, + int is_sorted, int* _idx, void* userdata ) +{ + schar* result = 0; + const schar* elem = (const schar*)_elem; + int idx = -1; + int i, j; + + if( _idx ) + *_idx = idx; + + if( !CV_IS_SEQ(seq) ) + CV_Error( !seq ? CV_StsNullPtr : CV_StsBadArg, "Bad input sequence" ); + + if( !elem ) + CV_Error( CV_StsNullPtr, "Null element pointer" ); + + int elem_size = seq->elem_size; + int total = seq->total; + + if( total == 0 ) + return 0; + + if( !is_sorted ) + { + CvSeqReader reader; + cvStartReadSeq( seq, &reader, 0 ); + + if( cmp_func ) + { + for( i = 0; i < total; i++ ) + { + if( cmp_func( elem, reader.ptr, userdata ) == 0 ) + break; + CV_NEXT_SEQ_ELEM( elem_size, reader ); + } + } + else if( (elem_size & (sizeof(int)-1)) == 0 ) + { + for( i = 0; i < total; i++ ) + { + for( j = 0; j < elem_size; j += sizeof(int) ) + { + if( *(const int*)(reader.ptr + j) != *(const int*)(elem + j) ) + break; + } + if( j == elem_size ) + break; + CV_NEXT_SEQ_ELEM( elem_size, reader ); + } + } + else + { + for( i = 0; i < total; i++ ) + { + for( j = 0; j < elem_size; j++ ) + { + if( reader.ptr[j] != elem[j] ) + break; + } + if( j == elem_size ) + break; + CV_NEXT_SEQ_ELEM( elem_size, reader ); + } + } + + idx = i; + if( i < total ) + result = reader.ptr; + } + else + { + if( !cmp_func ) + CV_Error( CV_StsNullPtr, "Null compare function" ); + + i = 0, j = total; + + while( j > i ) + { + int k = (i+j)>>1, code; + schar* ptr = cvGetSeqElem( seq, k ); + code = cmp_func( elem, ptr, userdata ); + if( !code ) + { + result = ptr; + idx = k; + if( _idx ) + *_idx = idx; + return result; + } + if( code < 0 ) + j = k; + else + i = k+1; + } + idx = j; + } + + if( _idx ) + *_idx = idx; + + return result; +} + + +CV_IMPL void +cvSeqInvert( CvSeq* seq ) +{ + CvSeqReader left_reader, right_reader; + int elem_size; + int i, count; + + cvStartReadSeq( seq, &left_reader, 0 ); + cvStartReadSeq( seq, &right_reader, 1 ); + elem_size = seq->elem_size; + count = seq->total >> 1; + + for( i = 0; i < count; i++ ) + { + CV_SWAP_ELEMS( left_reader.ptr, right_reader.ptr, elem_size ); + CV_NEXT_SEQ_ELEM( elem_size, left_reader ); + CV_PREV_SEQ_ELEM( elem_size, right_reader ); + } +} + + +typedef struct CvPTreeNode +{ + struct CvPTreeNode* parent; + schar* element; + int rank; +} +CvPTreeNode; + + +// This function splits the input sequence or set into one or more equivalence classes. +// is_equal(a,b,...) returns non-zero if the two sequence elements +// belong to the same class. The function returns sequence of integers - +// 0-based class indexes for each element. +// +// The algorithm is described in "Introduction to Algorithms" +// by Cormen, Leiserson and Rivest, chapter "Data structures for disjoint sets" +CV_IMPL int +cvSeqPartition( const CvSeq* seq, CvMemStorage* storage, CvSeq** labels, + CvCmpFunc is_equal, void* userdata ) +{ + CvSeq* result = 0; + CvMemStorage* temp_storage = 0; + int class_idx = 0; + + CvSeqWriter writer; + CvSeqReader reader, reader0; + CvSeq* nodes; + int i, j; + int is_set; + + if( !labels ) + CV_Error( CV_StsNullPtr, "" ); + + if( !seq || !is_equal ) + CV_Error( CV_StsNullPtr, "" ); + + if( !storage ) + storage = seq->storage; + + if( !storage ) + CV_Error( CV_StsNullPtr, "" ); + + is_set = CV_IS_SET(seq); + + temp_storage = cvCreateChildMemStorage( storage ); + + nodes = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPTreeNode), temp_storage ); + + cvStartReadSeq( seq, &reader ); + memset( &writer, 0, sizeof(writer)); + cvStartAppendToSeq( nodes, &writer ); + + // Initial O(N) pass. Make a forest of single-vertex trees. + for( i = 0; i < seq->total; i++ ) + { + CvPTreeNode node = { 0, 0, 0 }; + if( !is_set || CV_IS_SET_ELEM( reader.ptr )) + node.element = reader.ptr; + CV_WRITE_SEQ_ELEM( node, writer ); + CV_NEXT_SEQ_ELEM( seq->elem_size, reader ); + } + + cvEndWriteSeq( &writer ); + + // Because in the next loop we will iterate + // through all the sequence nodes each time, + // we do not need to initialize reader every time: + cvStartReadSeq( nodes, &reader ); + cvStartReadSeq( nodes, &reader0 ); + + // The main O(N^2) pass. Merge connected components. + for( i = 0; i < nodes->total; i++ ) + { + CvPTreeNode* node = (CvPTreeNode*)(reader0.ptr); + CvPTreeNode* root = node; + CV_NEXT_SEQ_ELEM( nodes->elem_size, reader0 ); + + if( !node->element ) + continue; + + // find root + while( root->parent ) + root = root->parent; + + for( j = 0; j < nodes->total; j++ ) + { + CvPTreeNode* node2 = (CvPTreeNode*)reader.ptr; + + if( node2->element && node2 != node && + is_equal( node->element, node2->element, userdata )) + { + CvPTreeNode* root2 = node2; + + // unite both trees + while( root2->parent ) + root2 = root2->parent; + + if( root2 != root ) + { + if( root->rank > root2->rank ) + root2->parent = root; + else + { + root->parent = root2; + root2->rank += root->rank == root2->rank; + root = root2; + } + assert( root->parent == 0 ); + + // Compress path from node2 to the root: + while( node2->parent ) + { + CvPTreeNode* temp = node2; + node2 = node2->parent; + temp->parent = root; + } + + // Compress path from node to the root: + node2 = node; + while( node2->parent ) + { + CvPTreeNode* temp = node2; + node2 = node2->parent; + temp->parent = root; + } + } + } + + CV_NEXT_SEQ_ELEM( sizeof(*node), reader ); + } + } + + // Final O(N) pass (Enumerate classes) + // Reuse reader one more time + result = cvCreateSeq( 0, sizeof(CvSeq), sizeof(int), storage ); + cvStartAppendToSeq( result, &writer ); + + for( i = 0; i < nodes->total; i++ ) + { + CvPTreeNode* node = (CvPTreeNode*)reader.ptr; + int idx = -1; + + if( node->element ) + { + while( node->parent ) + node = node->parent; + if( node->rank >= 0 ) + node->rank = ~class_idx++; + idx = ~node->rank; + } + + CV_NEXT_SEQ_ELEM( sizeof(*node), reader ); + CV_WRITE_SEQ_ELEM( idx, writer ); + } + + cvEndWriteSeq( &writer ); + + if( labels ) + *labels = result; + + cvReleaseMemStorage( &temp_storage ); + return class_idx; +} + + +/****************************************************************************************\ +* Set implementation * +\****************************************************************************************/ + +/* Creates empty set: */ +CV_IMPL CvSet* +cvCreateSet( int set_flags, int header_size, int elem_size, CvMemStorage * storage ) +{ + if( !storage ) + CV_Error( CV_StsNullPtr, "" ); + if( header_size < (int)sizeof( CvSet ) || + elem_size < (int)sizeof(void*)*2 || + (elem_size & (sizeof(void*)-1)) != 0 ) + CV_Error( CV_StsBadSize, "" ); + + CvSet* set = (CvSet*) cvCreateSeq( set_flags, header_size, elem_size, storage ); + set->flags = (set->flags & ~CV_MAGIC_MASK) | CV_SET_MAGIC_VAL; + + return set; +} + + +/* Add new element to the set: */ +CV_IMPL int +cvSetAdd( CvSet* set, CvSetElem* element, CvSetElem** inserted_element ) +{ + int id = -1; + CvSetElem *free_elem; + + if( !set ) + CV_Error( CV_StsNullPtr, "" ); + + if( !(set->free_elems) ) + { + int count = set->total; + int elem_size = set->elem_size; + schar *ptr; + icvGrowSeq( (CvSeq *) set, 0 ); + + set->free_elems = (CvSetElem*) (ptr = set->ptr); + for( ; ptr + elem_size <= set->block_max; ptr += elem_size, count++ ) + { + ((CvSetElem*)ptr)->flags = count | CV_SET_ELEM_FREE_FLAG; + ((CvSetElem*)ptr)->next_free = (CvSetElem*)(ptr + elem_size); + } + assert( count <= CV_SET_ELEM_IDX_MASK+1 ); + ((CvSetElem*)(ptr - elem_size))->next_free = 0; + set->first->prev->count += count - set->total; + set->total = count; + set->ptr = set->block_max; + } + + free_elem = set->free_elems; + set->free_elems = free_elem->next_free; + + id = free_elem->flags & CV_SET_ELEM_IDX_MASK; + if( element ) + memcpy( free_elem, element, set->elem_size ); + + free_elem->flags = id; + set->active_count++; + + if( inserted_element ) + *inserted_element = free_elem; + + return id; +} + + +/* Remove element from a set given element index: */ +CV_IMPL void +cvSetRemove( CvSet* set, int index ) +{ + CvSetElem* elem = cvGetSetElem( set, index ); + if( elem ) + cvSetRemoveByPtr( set, elem ); + else if( !set ) + CV_Error( CV_StsNullPtr, "" ); +} + + +/* Remove all elements from a set: */ +CV_IMPL void +cvClearSet( CvSet* set ) +{ + cvClearSeq( (CvSeq*)set ); + set->free_elems = 0; + set->active_count = 0; +} + + +/****************************************************************************************\ +* Graph implementation * +\****************************************************************************************/ + +/* Create a new graph: */ +CV_IMPL CvGraph * +cvCreateGraph( int graph_type, int header_size, + int vtx_size, int edge_size, CvMemStorage * storage ) +{ + CvGraph *graph = 0; + CvSet *edges = 0; + CvSet *vertices = 0; + + if( header_size < (int) sizeof( CvGraph ) + || edge_size < (int) sizeof( CvGraphEdge ) + || vtx_size < (int) sizeof( CvGraphVtx ) + ){ + CV_Error( CV_StsBadSize, "" ); + } + + vertices = cvCreateSet( graph_type, header_size, vtx_size, storage ); + edges = cvCreateSet( CV_SEQ_KIND_GENERIC | CV_SEQ_ELTYPE_GRAPH_EDGE, + sizeof( CvSet ), edge_size, storage ); + + graph = (CvGraph*)vertices; + graph->edges = edges; + + return graph; +} + + +/* Remove all vertices and edges from a graph: */ +CV_IMPL void +cvClearGraph( CvGraph * graph ) +{ + if( !graph ) + CV_Error( CV_StsNullPtr, "" ); + + cvClearSet( graph->edges ); + cvClearSet( (CvSet*)graph ); +} + + +/* Add a vertex to a graph: */ +CV_IMPL int +cvGraphAddVtx( CvGraph* graph, const CvGraphVtx* _vertex, CvGraphVtx** _inserted_vertex ) +{ + CvGraphVtx *vertex = 0; + int index = -1; + + if( !graph ) + CV_Error( CV_StsNullPtr, "" ); + + vertex = (CvGraphVtx*)cvSetNew((CvSet*)graph); + if( vertex ) + { + if( _vertex ) + memcpy( vertex + 1, _vertex + 1, graph->elem_size - sizeof(CvGraphVtx) ); + vertex->first = 0; + index = vertex->flags; + } + + if( _inserted_vertex ) + *_inserted_vertex = vertex; + + return index; +} + + +/* Remove a vertex from the graph together with its incident edges: */ +CV_IMPL int +cvGraphRemoveVtxByPtr( CvGraph* graph, CvGraphVtx* vtx ) +{ + int count = -1; + + if( !graph || !vtx ) + CV_Error( CV_StsNullPtr, "" ); + + if( !CV_IS_SET_ELEM(vtx)) + CV_Error( CV_StsBadArg, "The vertex does not belong to the graph" ); + + count = graph->edges->active_count; + for( ;; ) + { + CvGraphEdge *edge = vtx->first; + if( !edge ) + break; + cvGraphRemoveEdgeByPtr( graph, edge->vtx[0], edge->vtx[1] ); + } + count -= graph->edges->active_count; + cvSetRemoveByPtr( (CvSet*)graph, vtx ); + + return count; +} + + +/* Remove a vertex from the graph together with its incident edges: */ +CV_IMPL int +cvGraphRemoveVtx( CvGraph* graph, int index ) +{ + int count = -1; + CvGraphVtx *vtx = 0; + + if( !graph ) + CV_Error( CV_StsNullPtr, "" ); + + vtx = cvGetGraphVtx( graph, index ); + if( !vtx ) + CV_Error( CV_StsBadArg, "The vertex is not found" ); + + count = graph->edges->active_count; + for( ;; ) + { + CvGraphEdge *edge = vtx->first; + count++; + + if( !edge ) + break; + cvGraphRemoveEdgeByPtr( graph, edge->vtx[0], edge->vtx[1] ); + } + count -= graph->edges->active_count; + cvSetRemoveByPtr( (CvSet*)graph, vtx ); + + return count; +} + + +/* Find a graph edge given pointers to the ending vertices: */ +CV_IMPL CvGraphEdge* +cvFindGraphEdgeByPtr( const CvGraph* graph, + const CvGraphVtx* start_vtx, + const CvGraphVtx* end_vtx ) +{ + int ofs = 0; + + if( !graph || !start_vtx || !end_vtx ) + CV_Error( CV_StsNullPtr, "" ); + + if( start_vtx == end_vtx ) + return 0; + + if( !CV_IS_GRAPH_ORIENTED( graph ) && + (start_vtx->flags & CV_SET_ELEM_IDX_MASK) > (end_vtx->flags & CV_SET_ELEM_IDX_MASK) ) + { + const CvGraphVtx* t; + CV_SWAP( start_vtx, end_vtx, t ); + } + + CvGraphEdge* edge = start_vtx->first; + for( ; edge; edge = edge->next[ofs] ) + { + ofs = start_vtx == edge->vtx[1]; + assert( ofs == 1 || start_vtx == edge->vtx[0] ); + if( edge->vtx[1] == end_vtx ) + break; + } + + return edge; +} + + +/* Find an edge in the graph given indices of the ending vertices: */ +CV_IMPL CvGraphEdge * +cvFindGraphEdge( const CvGraph* graph, int start_idx, int end_idx ) +{ + CvGraphVtx *start_vtx; + CvGraphVtx *end_vtx; + + if( !graph ) + CV_Error( CV_StsNullPtr, "graph pointer is NULL" ); + + start_vtx = cvGetGraphVtx( graph, start_idx ); + end_vtx = cvGetGraphVtx( graph, end_idx ); + + return cvFindGraphEdgeByPtr( graph, start_vtx, end_vtx ); +} + + +/* Given two vertices, return the edge + * connecting them, creating it if it + * did not already exist: + */ +CV_IMPL int +cvGraphAddEdgeByPtr( CvGraph* graph, + CvGraphVtx* start_vtx, CvGraphVtx* end_vtx, + const CvGraphEdge* _edge, + CvGraphEdge ** _inserted_edge ) +{ + CvGraphEdge *edge = 0; + int result = -1; + int delta; + + if( !graph ) + CV_Error( CV_StsNullPtr, "graph pointer is NULL" ); + + if( !CV_IS_GRAPH_ORIENTED( graph ) && + (start_vtx->flags & CV_SET_ELEM_IDX_MASK) > (end_vtx->flags & CV_SET_ELEM_IDX_MASK) ) + { + CvGraphVtx* t; + CV_SWAP( start_vtx, end_vtx, t ); + } + + edge = cvFindGraphEdgeByPtr( graph, start_vtx, end_vtx ); + if( edge ) + { + result = 0; + if( _inserted_edge ) + *_inserted_edge = edge; + return result; + } + + if( start_vtx == end_vtx ) + CV_Error( start_vtx ? CV_StsBadArg : CV_StsNullPtr, + "vertex pointers coinside (or set to NULL)" ); + + edge = (CvGraphEdge*)cvSetNew( (CvSet*)(graph->edges) ); + assert( edge->flags >= 0 ); + + edge->vtx[0] = start_vtx; + edge->vtx[1] = end_vtx; + edge->next[0] = start_vtx->first; + edge->next[1] = end_vtx->first; + start_vtx->first = end_vtx->first = edge; + + delta = graph->edges->elem_size - sizeof(*edge); + if( _edge ) + { + if( delta > 0 ) + memcpy( edge + 1, _edge + 1, delta ); + edge->weight = _edge->weight; + } + else + { + if( delta > 0 ) + memset( edge + 1, 0, delta ); + edge->weight = 1.f; + } + + result = 1; + + if( _inserted_edge ) + *_inserted_edge = edge; + + return result; +} + +/* Given two vertices, return the edge + * connecting them, creating it if it + * did not already exist: + */ +CV_IMPL int +cvGraphAddEdge( CvGraph* graph, + int start_idx, int end_idx, + const CvGraphEdge* _edge, + CvGraphEdge ** _inserted_edge ) +{ + CvGraphVtx *start_vtx; + CvGraphVtx *end_vtx; + + if( !graph ) + CV_Error( CV_StsNullPtr, "" ); + + start_vtx = cvGetGraphVtx( graph, start_idx ); + end_vtx = cvGetGraphVtx( graph, end_idx ); + + return cvGraphAddEdgeByPtr( graph, start_vtx, end_vtx, _edge, _inserted_edge ); +} + + +/* Remove the graph edge connecting two given vertices: */ +CV_IMPL void +cvGraphRemoveEdgeByPtr( CvGraph* graph, CvGraphVtx* start_vtx, CvGraphVtx* end_vtx ) +{ + int ofs, prev_ofs; + CvGraphEdge *edge, *next_edge, *prev_edge; + + if( !graph || !start_vtx || !end_vtx ) + CV_Error( CV_StsNullPtr, "" ); + + if( start_vtx == end_vtx ) + return; + + if( !CV_IS_GRAPH_ORIENTED( graph ) && + (start_vtx->flags & CV_SET_ELEM_IDX_MASK) > (end_vtx->flags & CV_SET_ELEM_IDX_MASK) ) + { + CvGraphVtx* t; + CV_SWAP( start_vtx, end_vtx, t ); + } + + for( ofs = prev_ofs = 0, prev_edge = 0, edge = start_vtx->first; edge != 0; + prev_ofs = ofs, prev_edge = edge, edge = edge->next[ofs] ) + { + ofs = start_vtx == edge->vtx[1]; + assert( ofs == 1 || start_vtx == edge->vtx[0] ); + if( edge->vtx[1] == end_vtx ) + break; + } + + if( !edge ) + return; + + next_edge = edge->next[ofs]; + if( prev_edge ) + prev_edge->next[prev_ofs] = next_edge; + else + start_vtx->first = next_edge; + + for( ofs = prev_ofs = 0, prev_edge = 0, edge = end_vtx->first; edge != 0; + prev_ofs = ofs, prev_edge = edge, edge = edge->next[ofs] ) + { + ofs = end_vtx == edge->vtx[1]; + assert( ofs == 1 || end_vtx == edge->vtx[0] ); + if( edge->vtx[0] == start_vtx ) + break; + } + + assert( edge != 0 ); + + next_edge = edge->next[ofs]; + if( prev_edge ) + prev_edge->next[prev_ofs] = next_edge; + else + end_vtx->first = next_edge; + + cvSetRemoveByPtr( graph->edges, edge ); +} + + +/* Remove the graph edge connecting two given vertices: */ +CV_IMPL void +cvGraphRemoveEdge( CvGraph* graph, int start_idx, int end_idx ) +{ + CvGraphVtx *start_vtx; + CvGraphVtx *end_vtx; + + if( !graph ) + CV_Error( CV_StsNullPtr, "" ); + + start_vtx = cvGetGraphVtx( graph, start_idx ); + end_vtx = cvGetGraphVtx( graph, end_idx ); + + cvGraphRemoveEdgeByPtr( graph, start_vtx, end_vtx ); +} + + +/* Count number of edges incident to a given vertex: */ +CV_IMPL int +cvGraphVtxDegreeByPtr( const CvGraph* graph, const CvGraphVtx* vertex ) +{ + CvGraphEdge *edge; + int count; + + if( !graph || !vertex ) + CV_Error( CV_StsNullPtr, "" ); + + for( edge = vertex->first, count = 0; edge; ) + { + count++; + edge = CV_NEXT_GRAPH_EDGE( edge, vertex ); + } + + return count; +} + + +/* Count number of edges incident to a given vertex: */ +CV_IMPL int +cvGraphVtxDegree( const CvGraph* graph, int vtx_idx ) +{ + CvGraphVtx *vertex; + CvGraphEdge *edge; + int count; + + if( !graph ) + CV_Error( CV_StsNullPtr, "" ); + + vertex = cvGetGraphVtx( graph, vtx_idx ); + if( !vertex ) + CV_Error( CV_StsObjectNotFound, "" ); + + for( edge = vertex->first, count = 0; edge; ) + { + count++; + edge = CV_NEXT_GRAPH_EDGE( edge, vertex ); + } + + return count; +} + + +typedef struct CvGraphItem +{ + CvGraphVtx* vtx; + CvGraphEdge* edge; +} +CvGraphItem; + + +static void +icvSeqElemsClearFlags( CvSeq* seq, int offset, int clear_mask ) +{ + CvSeqReader reader; + int i, total, elem_size; + + if( !seq ) + CV_Error( CV_StsNullPtr, "" ); + + elem_size = seq->elem_size; + total = seq->total; + + if( (unsigned)offset > (unsigned)elem_size ) + CV_Error( CV_StsBadArg, "" ); + + cvStartReadSeq( seq, &reader ); + + for( i = 0; i < total; i++ ) + { + int* flag_ptr = (int*)(reader.ptr + offset); + *flag_ptr &= ~clear_mask; + + CV_NEXT_SEQ_ELEM( elem_size, reader ); + } +} + + +static schar* +icvSeqFindNextElem( CvSeq* seq, int offset, int mask, + int value, int* start_index ) +{ + schar* elem_ptr = 0; + + CvSeqReader reader; + int total, elem_size, index; + + if( !seq || !start_index ) + CV_Error( CV_StsNullPtr, "" ); + + elem_size = seq->elem_size; + total = seq->total; + index = *start_index; + + if( (unsigned)offset > (unsigned)elem_size ) + CV_Error( CV_StsBadArg, "" ); + + if( total == 0 ) + return 0; + + if( (unsigned)index >= (unsigned)total ) + { + index %= total; + index += index < 0 ? total : 0; + } + + cvStartReadSeq( seq, &reader ); + + if( index != 0 ) + cvSetSeqReaderPos( &reader, index ); + + for( index = 0; index < total; index++ ) + { + int* flag_ptr = (int*)(reader.ptr + offset); + if( (*flag_ptr & mask) == value ) + break; + + CV_NEXT_SEQ_ELEM( elem_size, reader ); + } + + if( index < total ) + { + elem_ptr = reader.ptr; + *start_index = index; + } + + return elem_ptr; +} + +#define CV_FIELD_OFFSET( field, structtype ) ((int)(size_t)&((structtype*)0)->field) + +CV_IMPL CvGraphScanner* +cvCreateGraphScanner( CvGraph* graph, CvGraphVtx* vtx, int mask ) +{ + if( !graph ) + CV_Error( CV_StsNullPtr, "Null graph pointer" ); + + CV_Assert( graph->storage != 0 ); + + CvGraphScanner* scanner = (CvGraphScanner*)cvAlloc( sizeof(*scanner) ); + memset( scanner, 0, sizeof(*scanner)); + + scanner->graph = graph; + scanner->mask = mask; + scanner->vtx = vtx; + scanner->index = vtx == 0 ? 0 : -1; + + CvMemStorage* child_storage = cvCreateChildMemStorage( graph->storage ); + + scanner->stack = cvCreateSeq( 0, sizeof(CvSet), + sizeof(CvGraphItem), child_storage ); + + icvSeqElemsClearFlags( (CvSeq*)graph, + CV_FIELD_OFFSET( flags, CvGraphVtx), + CV_GRAPH_ITEM_VISITED_FLAG| + CV_GRAPH_SEARCH_TREE_NODE_FLAG ); + + icvSeqElemsClearFlags( (CvSeq*)(graph->edges), + CV_FIELD_OFFSET( flags, CvGraphEdge), + CV_GRAPH_ITEM_VISITED_FLAG ); + + return scanner; +} + + +CV_IMPL void +cvReleaseGraphScanner( CvGraphScanner** scanner ) +{ + if( !scanner ) + CV_Error( CV_StsNullPtr, "Null double pointer to graph scanner" ); + + if( *scanner ) + { + if( (*scanner)->stack ) + cvReleaseMemStorage( &((*scanner)->stack->storage)); + cvFree( scanner ); + } +} + + +CV_IMPL int +cvNextGraphItem( CvGraphScanner* scanner ) +{ + int code = -1; + CvGraphVtx* vtx; + CvGraphVtx* dst; + CvGraphEdge* edge; + CvGraphItem item; + + if( !scanner || !(scanner->stack)) + CV_Error( CV_StsNullPtr, "Null graph scanner" ); + + dst = scanner->dst; + vtx = scanner->vtx; + edge = scanner->edge; + + for(;;) + { + for(;;) + { + if( dst && !CV_IS_GRAPH_VERTEX_VISITED(dst) ) + { + scanner->vtx = vtx = dst; + edge = vtx->first; + dst->flags |= CV_GRAPH_ITEM_VISITED_FLAG; + + if((scanner->mask & CV_GRAPH_VERTEX)) + { + scanner->vtx = vtx; + scanner->edge = vtx->first; + scanner->dst = 0; + code = CV_GRAPH_VERTEX; + return code; + } + } + + while( edge ) + { + dst = edge->vtx[vtx == edge->vtx[0]]; + + if( !CV_IS_GRAPH_EDGE_VISITED(edge) ) + { + // Check that the edge is outgoing: + if( !CV_IS_GRAPH_ORIENTED( scanner->graph ) || dst != edge->vtx[0] ) + { + edge->flags |= CV_GRAPH_ITEM_VISITED_FLAG; + + if( !CV_IS_GRAPH_VERTEX_VISITED(dst) ) + { + item.vtx = vtx; + item.edge = edge; + + vtx->flags |= CV_GRAPH_SEARCH_TREE_NODE_FLAG; + + cvSeqPush( scanner->stack, &item ); + + if( scanner->mask & CV_GRAPH_TREE_EDGE ) + { + code = CV_GRAPH_TREE_EDGE; + scanner->vtx = vtx; + scanner->dst = dst; + scanner->edge = edge; + return code; + } + break; + } + else + { + if( scanner->mask & (CV_GRAPH_BACK_EDGE| + CV_GRAPH_CROSS_EDGE| + CV_GRAPH_FORWARD_EDGE) ) + { + code = (dst->flags & CV_GRAPH_SEARCH_TREE_NODE_FLAG) ? + CV_GRAPH_BACK_EDGE : + (edge->flags & CV_GRAPH_FORWARD_EDGE_FLAG) ? + CV_GRAPH_FORWARD_EDGE : CV_GRAPH_CROSS_EDGE; + edge->flags &= ~CV_GRAPH_FORWARD_EDGE_FLAG; + if( scanner->mask & code ) + { + scanner->vtx = vtx; + scanner->dst = dst; + scanner->edge = edge; + return code; + } + } + } + } + else if( (dst->flags & (CV_GRAPH_ITEM_VISITED_FLAG| + CV_GRAPH_SEARCH_TREE_NODE_FLAG)) == + (CV_GRAPH_ITEM_VISITED_FLAG| + CV_GRAPH_SEARCH_TREE_NODE_FLAG)) + { + edge->flags |= CV_GRAPH_FORWARD_EDGE_FLAG; + } + } + + edge = CV_NEXT_GRAPH_EDGE( edge, vtx ); + } + + if( !edge ) /* need to backtrack */ + { + if( scanner->stack->total == 0 ) + { + if( scanner->index >= 0 ) + vtx = 0; + else + scanner->index = 0; + break; + } + cvSeqPop( scanner->stack, &item ); + vtx = item.vtx; + vtx->flags &= ~CV_GRAPH_SEARCH_TREE_NODE_FLAG; + edge = item.edge; + dst = 0; + + if( scanner->mask & CV_GRAPH_BACKTRACKING ) + { + scanner->vtx = vtx; + scanner->edge = edge; + scanner->dst = edge->vtx[vtx == edge->vtx[0]]; + code = CV_GRAPH_BACKTRACKING; + return code; + } + } + } + + if( !vtx ) + { + vtx = (CvGraphVtx*)icvSeqFindNextElem( (CvSeq*)(scanner->graph), + CV_FIELD_OFFSET( flags, CvGraphVtx ), CV_GRAPH_ITEM_VISITED_FLAG|INT_MIN, + 0, &(scanner->index) ); + + if( !vtx ) + { + code = CV_GRAPH_OVER; + break; + } + } + + dst = vtx; + if( scanner->mask & CV_GRAPH_NEW_TREE ) + { + scanner->dst = dst; + scanner->edge = 0; + scanner->vtx = 0; + code = CV_GRAPH_NEW_TREE; + break; + } + } + + return code; +} + + +CV_IMPL CvGraph* +cvCloneGraph( const CvGraph* graph, CvMemStorage* storage ) +{ + int* flag_buffer = 0; + CvGraphVtx** ptr_buffer = 0; + CvGraph* result = 0; + + int i, k; + int vtx_size, edge_size; + CvSeqReader reader; + + if( !CV_IS_GRAPH(graph)) + CV_Error( CV_StsBadArg, "Invalid graph pointer" ); + + if( !storage ) + storage = graph->storage; + + if( !storage ) + CV_Error( CV_StsNullPtr, "NULL storage pointer" ); + + vtx_size = graph->elem_size; + edge_size = graph->edges->elem_size; + + flag_buffer = (int*)cvAlloc( graph->total*sizeof(flag_buffer[0])); + ptr_buffer = (CvGraphVtx**)cvAlloc( graph->total*sizeof(ptr_buffer[0])); + result = cvCreateGraph( graph->flags, graph->header_size, + vtx_size, edge_size, storage ); + memcpy( result + sizeof(CvGraph), graph + sizeof(CvGraph), + graph->header_size - sizeof(CvGraph)); + + // Pass 1. Save flags, copy vertices: + cvStartReadSeq( (CvSeq*)graph, &reader ); + for( i = 0, k = 0; i < graph->total; i++ ) + { + if( CV_IS_SET_ELEM( reader.ptr )) + { + CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr; + CvGraphVtx* dstvtx = 0; + cvGraphAddVtx( result, vtx, &dstvtx ); + flag_buffer[k] = dstvtx->flags = vtx->flags; + vtx->flags = k; + ptr_buffer[k++] = dstvtx; + } + CV_NEXT_SEQ_ELEM( vtx_size, reader ); + } + + // Pass 2. Copy edges: + cvStartReadSeq( (CvSeq*)graph->edges, &reader ); + for( i = 0; i < graph->edges->total; i++ ) + { + if( CV_IS_SET_ELEM( reader.ptr )) + { + CvGraphEdge* edge = (CvGraphEdge*)reader.ptr; + CvGraphEdge* dstedge = 0; + CvGraphVtx* new_org = ptr_buffer[edge->vtx[0]->flags]; + CvGraphVtx* new_dst = ptr_buffer[edge->vtx[1]->flags]; + cvGraphAddEdgeByPtr( result, new_org, new_dst, edge, &dstedge ); + dstedge->flags = edge->flags; + } + CV_NEXT_SEQ_ELEM( edge_size, reader ); + } + + // Pass 3. Restore flags: + cvStartReadSeq( (CvSeq*)graph, &reader ); + for( i = 0, k = 0; i < graph->edges->total; i++ ) + { + if( CV_IS_SET_ELEM( reader.ptr )) + { + CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr; + vtx->flags = flag_buffer[k++]; + } + CV_NEXT_SEQ_ELEM( vtx_size, reader ); + } + + cvFree( &flag_buffer ); + cvFree( &ptr_buffer ); + + if( cvGetErrStatus() < 0 ) + result = 0; + + return result; +} + + +/****************************************************************************************\ +* Working with sequence tree * +\****************************************************************************************/ + +// Gather pointers to all the sequences, accessible from the , to the single sequence. +CV_IMPL CvSeq* +cvTreeToNodeSeq( const void* first, int header_size, CvMemStorage* storage ) +{ + CvSeq* allseq = 0; + CvTreeNodeIterator iterator; + + if( !storage ) + CV_Error( CV_StsNullPtr, "NULL storage pointer" ); + + allseq = cvCreateSeq( 0, header_size, sizeof(first), storage ); + + if( first ) + { + cvInitTreeNodeIterator( &iterator, first, INT_MAX ); + + for(;;) + { + void* node = cvNextTreeNode( &iterator ); + if( !node ) + break; + cvSeqPush( allseq, &node ); + } + } + + + + return allseq; +} + + +typedef struct CvTreeNode +{ + int flags; /* micsellaneous flags */ + int header_size; /* size of sequence header */ + struct CvTreeNode* h_prev; /* previous sequence */ + struct CvTreeNode* h_next; /* next sequence */ + struct CvTreeNode* v_prev; /* 2nd previous sequence */ + struct CvTreeNode* v_next; /* 2nd next sequence */ +} +CvTreeNode; + + + +// Insert contour into tree given certain parent sequence. +// If parent is equal to frame (the most external contour), +// then added contour will have null pointer to parent: +CV_IMPL void +cvInsertNodeIntoTree( void* _node, void* _parent, void* _frame ) +{ + CvTreeNode* node = (CvTreeNode*)_node; + CvTreeNode* parent = (CvTreeNode*)_parent; + + if( !node || !parent ) + CV_Error( CV_StsNullPtr, "" ); + + node->v_prev = _parent != _frame ? parent : 0; + node->h_next = parent->v_next; + + assert( parent->v_next != node ); + + if( parent->v_next ) + parent->v_next->h_prev = node; + parent->v_next = node; +} + + +// Remove contour from tree, together with the contour's children: +CV_IMPL void +cvRemoveNodeFromTree( void* _node, void* _frame ) +{ + CvTreeNode* node = (CvTreeNode*)_node; + CvTreeNode* frame = (CvTreeNode*)_frame; + + if( !node ) + CV_Error( CV_StsNullPtr, "" ); + + if( node == frame ) + CV_Error( CV_StsBadArg, "frame node could not be deleted" ); + + if( node->h_next ) + node->h_next->h_prev = node->h_prev; + + if( node->h_prev ) + node->h_prev->h_next = node->h_next; + else + { + CvTreeNode* parent = node->v_prev; + if( !parent ) + parent = frame; + + if( parent ) + { + assert( parent->v_next == node ); + parent->v_next = node->h_next; + } + } +} + + +CV_IMPL void +cvInitTreeNodeIterator( CvTreeNodeIterator* treeIterator, + const void* first, int max_level ) +{ + if( !treeIterator || !first ) + CV_Error( CV_StsNullPtr, "" ); + + if( max_level < 0 ) + CV_Error( CV_StsOutOfRange, "" ); + + treeIterator->node = (void*)first; + treeIterator->level = 0; + treeIterator->max_level = max_level; +} + + +CV_IMPL void* +cvNextTreeNode( CvTreeNodeIterator* treeIterator ) +{ + CvTreeNode* prevNode = 0; + CvTreeNode* node; + int level; + + if( !treeIterator ) + CV_Error( CV_StsNullPtr, "NULL iterator pointer" ); + + prevNode = node = (CvTreeNode*)treeIterator->node; + level = treeIterator->level; + + if( node ) + { + if( node->v_next && level+1 < treeIterator->max_level ) + { + node = node->v_next; + level++; + } + else + { + while( node->h_next == 0 ) + { + node = node->v_prev; + if( --level < 0 ) + { + node = 0; + break; + } + } + node = node && treeIterator->max_level != 0 ? node->h_next : 0; + } + } + + treeIterator->node = node; + treeIterator->level = level; + return prevNode; +} + + +CV_IMPL void* +cvPrevTreeNode( CvTreeNodeIterator* treeIterator ) +{ + CvTreeNode* prevNode = 0; + CvTreeNode* node; + int level; + + if( !treeIterator ) + CV_Error( CV_StsNullPtr, "" ); + + prevNode = node = (CvTreeNode*)treeIterator->node; + level = treeIterator->level; + + if( node ) + { + if( !node->h_prev ) + { + node = node->v_prev; + if( --level < 0 ) + node = 0; + } + else + { + node = node->h_prev; + + while( node->v_next && level < treeIterator->max_level ) + { + node = node->v_next; + level++; + + while( node->h_next ) + node = node->h_next; + } + } + } + + treeIterator->node = node; + treeIterator->level = level; + return prevNode; +} + + +namespace cv +{ + +// This is reimplementation of kd-trees from cvkdtree*.* by Xavier Delacour, cleaned-up and +// adopted to work with the new OpenCV data structures. It's in cxcore to be shared by +// both cv (CvFeatureTree) and ml (kNN). + +// The algorithm is taken from: +// J.S. Beis and D.G. Lowe. Shape indexing using approximate nearest-neighbor search +// in highdimensional spaces. In Proc. IEEE Conf. Comp. Vision Patt. Recog., +// pages 1000--1006, 1997. http://citeseer.ist.psu.edu/beis97shape.html + +const int MAX_TREE_DEPTH = 32; + +KDTree::KDTree() +{ + maxDepth = -1; + normType = NORM_L2; +} + +KDTree::KDTree(InputArray _points, bool _copyData) +{ + maxDepth = -1; + normType = NORM_L2; + build(_points, _copyData); +} + +KDTree::KDTree(InputArray _points, InputArray _labels, bool _copyData) +{ + maxDepth = -1; + normType = NORM_L2; + build(_points, _labels, _copyData); +} + +struct SubTree +{ + SubTree() : first(0), last(0), nodeIdx(0), depth(0) {} + SubTree(int _first, int _last, int _nodeIdx, int _depth) + : first(_first), last(_last), nodeIdx(_nodeIdx), depth(_depth) {} + int first; + int last; + int nodeIdx; + int depth; +}; + + +static float +medianPartition( size_t* ofs, int a, int b, const float* vals ) +{ + int k, a0 = a, b0 = b; + int middle = (a + b)/2; + while( b > a ) + { + int i0 = a, i1 = (a+b)/2, i2 = b; + float v0 = vals[ofs[i0]], v1 = vals[ofs[i1]], v2 = vals[ofs[i2]]; + int ip = v0 < v1 ? (v1 < v2 ? i1 : v0 < v2 ? i2 : i0) : + v0 < v2 ? i0 : (v1 < v2 ? i2 : i1); + float pivot = vals[ofs[ip]]; + std::swap(ofs[ip], ofs[i2]); + + for( i1 = i0, i0--; i1 <= i2; i1++ ) + if( vals[ofs[i1]] <= pivot ) + { + i0++; + std::swap(ofs[i0], ofs[i1]); + } + if( i0 == middle ) + break; + if( i0 > middle ) + b = i0 - (b == i0); + else + a = i0; + } + + float pivot = vals[ofs[middle]]; + int less = 0, more = 0; + for( k = a0; k < middle; k++ ) + { + CV_Assert(vals[ofs[k]] <= pivot); + less += vals[ofs[k]] < pivot; + } + for( k = b0; k > middle; k-- ) + { + CV_Assert(vals[ofs[k]] >= pivot); + more += vals[ofs[k]] > pivot; + } + CV_Assert(std::abs(more - less) <= 1); + + return vals[ofs[middle]]; +} + +static void +computeSums( const Mat& points, const size_t* ofs, int a, int b, double* sums ) +{ + int i, j, dims = points.cols; + const float* data = points.ptr(0); + for( j = 0; j < dims; j++ ) + sums[j*2] = sums[j*2+1] = 0; + for( i = a; i <= b; i++ ) + { + const float* row = data + ofs[i]; + for( j = 0; j < dims; j++ ) + { + double t = row[j], s = sums[j*2] + t, s2 = sums[j*2+1] + t*t; + sums[j*2] = s; sums[j*2+1] = s2; + } + } +} + + +void KDTree::build(InputArray _points, bool _copyData) +{ + build(_points, noArray(), _copyData); +} + + +void KDTree::build(InputArray __points, InputArray __labels, bool _copyData) +{ + Mat _points = __points.getMat(), _labels = __labels.getMat(); + CV_Assert(_points.type() == CV_32F && !_points.empty()); + vector().swap(nodes); + + if( !_copyData ) + points = _points; + else + { + points.release(); + points.create(_points.size(), _points.type()); + } + + int i, j, n = _points.rows, ptdims = _points.cols, top = 0; + const float* data = _points.ptr(0); + float* dstdata = points.ptr(0); + size_t step = _points.step1(); + size_t dstep = points.step1(); + int ptpos = 0; + labels.resize(n); + const int* _labels_data = 0; + + if( !_labels.empty() ) + { + int nlabels = _labels.checkVector(1, CV_32S, true); + CV_Assert(nlabels == n); + _labels_data = (const int*)_labels.data; + } + + Mat sumstack(MAX_TREE_DEPTH*2, ptdims*2, CV_64F); + SubTree stack[MAX_TREE_DEPTH*2]; + + vector _ptofs(n); + size_t* ptofs = &_ptofs[0]; + + for( i = 0; i < n; i++ ) + ptofs[i] = i*step; + + nodes.push_back(Node()); + computeSums(points, ptofs, 0, n-1, sumstack.ptr(top)); + stack[top++] = SubTree(0, n-1, 0, 0); + int _maxDepth = 0; + + while( --top >= 0 ) + { + int first = stack[top].first, last = stack[top].last; + int depth = stack[top].depth, nidx = stack[top].nodeIdx; + int count = last - first + 1, dim = -1; + const double* sums = sumstack.ptr(top); + double invCount = 1./count, maxVar = -1.; + + if( count == 1 ) + { + int idx0 = (int)(ptofs[first]/step); + int idx = _copyData ? ptpos++ : idx0; + nodes[nidx].idx = ~idx; + if( _copyData ) + { + const float* src = data + ptofs[first]; + float* dst = dstdata + idx*dstep; + for( j = 0; j < ptdims; j++ ) + dst[j] = src[j]; + } + labels[idx] = _labels_data ? _labels_data[idx0] : idx0; + _maxDepth = std::max(_maxDepth, depth); + continue; + } + + // find the dimensionality with the biggest variance + for( j = 0; j < ptdims; j++ ) + { + double m = sums[j*2]*invCount; + double varj = sums[j*2+1]*invCount - m*m; + if( maxVar < varj ) + { + maxVar = varj; + dim = j; + } + } + + int left = (int)nodes.size(), right = left + 1; + nodes.push_back(Node()); + nodes.push_back(Node()); + nodes[nidx].idx = dim; + nodes[nidx].left = left; + nodes[nidx].right = right; + nodes[nidx].boundary = medianPartition(ptofs, first, last, data + dim); + + int middle = (first + last)/2; + double *lsums = (double*)sums, *rsums = lsums + ptdims*2; + computeSums(points, ptofs, middle+1, last, rsums); + for( j = 0; j < ptdims*2; j++ ) + lsums[j] = sums[j] - rsums[j]; + stack[top++] = SubTree(first, middle, left, depth+1); + stack[top++] = SubTree(middle+1, last, right, depth+1); + } + maxDepth = _maxDepth; +} + + +struct PQueueElem +{ + PQueueElem() : dist(0), idx(0) {} + PQueueElem(float _dist, int _idx) : dist(_dist), idx(_idx) {} + float dist; + int idx; +}; + + +int KDTree::findNearest(InputArray _vec, int K, int emax, + OutputArray _neighborsIdx, OutputArray _neighbors, + OutputArray _dist, OutputArray _labels) const + +{ + Mat vecmat = _vec.getMat(); + CV_Assert( vecmat.isContinuous() && vecmat.type() == CV_32F && vecmat.total() == (size_t)points.cols ); + const float* vec = vecmat.ptr(); + K = std::min(K, points.rows); + int ptdims = points.cols; + + CV_Assert(K > 0 && (normType == NORM_L2 || normType == NORM_L1)); + + AutoBuffer _buf((K+1)*(sizeof(float) + sizeof(int))); + int* idx = (int*)(uchar*)_buf; + float* dist = (float*)(idx + K + 1); + int i, j, ncount = 0, e = 0; + + int qsize = 0, maxqsize = 1 << 10; + AutoBuffer _pqueue(maxqsize*sizeof(PQueueElem)); + PQueueElem* pqueue = (PQueueElem*)(uchar*)_pqueue; + emax = std::max(emax, 1); + + for( e = 0; e < emax; ) + { + float d, alt_d = 0.f; + int nidx; + + if( e == 0 ) + nidx = 0; + else + { + // take the next node from the priority queue + if( qsize == 0 ) + break; + nidx = pqueue[0].idx; + alt_d = pqueue[0].dist; + if( --qsize > 0 ) + { + std::swap(pqueue[0], pqueue[qsize]); + d = pqueue[0].dist; + for( i = 0;;) + { + int left = i*2 + 1, right = i*2 + 2; + if( left >= qsize ) + break; + if( right < qsize && pqueue[right].dist < pqueue[left].dist ) + left = right; + if( pqueue[left].dist >= d ) + break; + std::swap(pqueue[i], pqueue[left]); + i = left; + } + } + + if( ncount == K && alt_d > dist[ncount-1] ) + continue; + } + + for(;;) + { + if( nidx < 0 ) + break; + const Node& n = nodes[nidx]; + + if( n.idx < 0 ) + { + i = ~n.idx; + const float* row = points.ptr(i); + if( normType == NORM_L2 ) + for( j = 0, d = 0.f; j < ptdims; j++ ) + { + float t = vec[j] - row[j]; + d += t*t; + } + else + for( j = 0, d = 0.f; j < ptdims; j++ ) + d += std::abs(vec[j] - row[j]); + + dist[ncount] = d; + idx[ncount] = i; + for( i = ncount-1; i >= 0; i-- ) + { + if( dist[i] <= d ) + break; + std::swap(dist[i], dist[i+1]); + std::swap(idx[i], idx[i+1]); + } + ncount += ncount < K; + e++; + break; + } + + int alt; + if( vec[n.idx] <= n.boundary ) + { + nidx = n.left; + alt = n.right; + } + else + { + nidx = n.right; + alt = n.left; + } + + d = vec[n.idx] - n.boundary; + if( normType == NORM_L2 ) + d = d*d + alt_d; + else + d = std::abs(d) + alt_d; + // subtree prunning + if( ncount == K && d > dist[ncount-1] ) + continue; + // add alternative subtree to the priority queue + pqueue[qsize] = PQueueElem(d, alt); + for( i = qsize; i > 0; ) + { + int parent = (i-1)/2; + if( parent < 0 || pqueue[parent].dist <= d ) + break; + std::swap(pqueue[i], pqueue[parent]); + i = parent; + } + qsize += qsize+1 < maxqsize; + } + } + + K = std::min(K, ncount); + if( _neighborsIdx.needed() ) + { + _neighborsIdx.create(K, 1, CV_32S, -1, true); + Mat nidx = _neighborsIdx.getMat(); + Mat(nidx.size(), CV_32S, &idx[0]).copyTo(nidx); + } + if( _dist.needed() ) + sqrt(Mat(K, 1, CV_32F, dist), _dist); + + if( _neighbors.needed() || _labels.needed() ) + getPoints(Mat(K, 1, CV_32S, idx), _neighbors, _labels); + return K; +} + + +void KDTree::findOrthoRange(InputArray _lowerBound, + InputArray _upperBound, + OutputArray _neighborsIdx, + OutputArray _neighbors, + OutputArray _labels ) const +{ + int ptdims = points.cols; + Mat lowerBound = _lowerBound.getMat(), upperBound = _upperBound.getMat(); + CV_Assert( lowerBound.size == upperBound.size && + lowerBound.isContinuous() && + upperBound.isContinuous() && + lowerBound.type() == upperBound.type() && + lowerBound.type() == CV_32F && + lowerBound.total() == (size_t)ptdims ); + const float* L = lowerBound.ptr(); + const float* R = upperBound.ptr(); + + vector idx; + AutoBuffer _stack(MAX_TREE_DEPTH*2 + 1); + int* stack = _stack; + int top = 0; + + stack[top++] = 0; + + while( --top >= 0 ) + { + int nidx = stack[top]; + if( nidx < 0 ) + break; + const Node& n = nodes[nidx]; + if( n.idx < 0 ) + { + int j, i = ~n.idx; + const float* row = points.ptr(i); + for( j = 0; j < ptdims; j++ ) + if( row[j] < L[j] || row[j] >= R[j] ) + break; + if( j == ptdims ) + idx.push_back(i); + continue; + } + if( L[n.idx] <= n.boundary ) + stack[top++] = n.left; + if( R[n.idx] > n.boundary ) + stack[top++] = n.right; + } + + if( _neighborsIdx.needed() ) + { + _neighborsIdx.create((int)idx.size(), 1, CV_32S, -1, true); + Mat nidx = _neighborsIdx.getMat(); + Mat(nidx.size(), CV_32S, &idx[0]).copyTo(nidx); + } + getPoints( idx, _neighbors, _labels ); +} + + +void KDTree::getPoints(InputArray _idx, OutputArray _pts, OutputArray _labels) const +{ + Mat idxmat = _idx.getMat(), pts, labelsmat; + CV_Assert( idxmat.isContinuous() && idxmat.type() == CV_32S && + (idxmat.cols == 1 || idxmat.rows == 1) ); + const int* idx = idxmat.ptr(); + int* dstlabels = 0; + + int ptdims = points.cols; + int i, nidx = (int)idxmat.total(); + if( nidx == 0 ) + { + _pts.release(); + _labels.release(); + return; + } + + if( _pts.needed() ) + { + _pts.create( nidx, ptdims, points.type()); + pts = _pts.getMat(); + } + + if(_labels.needed()) + { + _labels.create(nidx, 1, CV_32S, -1, true); + labelsmat = _labels.getMat(); + CV_Assert( labelsmat.isContinuous() ); + dstlabels = labelsmat.ptr(); + } + const int* srclabels = !labels.empty() ? &labels[0] : 0; + + for( i = 0; i < nidx; i++ ) + { + int k = idx[i]; + CV_Assert( (unsigned)k < (unsigned)points.rows ); + const float* src = points.ptr(k); + if( pts.data ) + std::copy(src, src + ptdims, pts.ptr(i)); + if( dstlabels ) + dstlabels[i] = srclabels ? srclabels[k] : k; + } +} + + +const float* KDTree::getPoint(int ptidx, int* label) const +{ + CV_Assert( (unsigned)ptidx < (unsigned)points.rows); + if(label) + *label = labels[ptidx]; + return points.ptr(ptidx); +} + + +int KDTree::dims() const +{ + return !points.empty() ? points.cols : 0; +} + +//////////////////////////////////////////////////////////////////////////////// + +schar* seqPush( CvSeq* seq, const void* element ) +{ + return cvSeqPush(seq, element); +} + +schar* seqPushFront( CvSeq* seq, const void* element ) +{ + return cvSeqPushFront(seq, element); +} + +void seqPop( CvSeq* seq, void* element ) +{ + cvSeqPop(seq, element); +} + +void seqPopFront( CvSeq* seq, void* element ) +{ + cvSeqPopFront(seq, element); +} + +void seqRemove( CvSeq* seq, int index ) +{ + cvSeqRemove(seq, index); +} + +void clearSeq( CvSeq* seq ) +{ + cvClearSeq(seq); +} + +schar* getSeqElem( const CvSeq* seq, int index ) +{ + return cvGetSeqElem(seq, index); +} + +void seqRemoveSlice( CvSeq* seq, CvSlice slice ) +{ + return cvSeqRemoveSlice(seq, slice); +} + +void seqInsertSlice( CvSeq* seq, int before_index, const CvArr* from_arr ) +{ + cvSeqInsertSlice(seq, before_index, from_arr); +} + +} + +/* End of file. */ diff --git a/core/src/drawing.cpp b/core/src/drawing.cpp new file mode 100644 index 0000000..50e51fb --- /dev/null +++ b/core/src/drawing.cpp @@ -0,0 +1,2519 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +namespace cv +{ + +enum { XY_SHIFT = 16, XY_ONE = 1 << XY_SHIFT, DRAWING_STORAGE_BLOCK = (1<<12) - 256 }; + +struct PolyEdge +{ + PolyEdge() : y0(0), y1(0), x(0), dx(0), next(0) {} + //PolyEdge(int _y0, int _y1, int _x, int _dx) : y0(_y0), y1(_y1), x(_x), dx(_dx) {} + + int y0, y1; + int x, dx; + PolyEdge *next; +}; + +static void +CollectPolyEdges( Mat& img, const Point* v, int npts, + vector& edges, const void* color, int line_type, + int shift, Point offset=Point() ); + +static void +FillEdgeCollection( Mat& img, vector& edges, const void* color ); + +static void +PolyLine( Mat& img, const Point* v, int npts, bool closed, + const void* color, int thickness, int line_type, int shift ); + +static void +FillConvexPoly( Mat& img, const Point* v, int npts, + const void* color, int line_type, int shift ); + +/****************************************************************************************\ +* Lines * +\****************************************************************************************/ + +bool clipLine( Size img_size, Point& pt1, Point& pt2 ) +{ + int64 x1, y1, x2, y2; + int c1, c2; + int64 right = img_size.width-1, bottom = img_size.height-1; + + if( img_size.width <= 0 || img_size.height <= 0 ) + return false; + + x1 = pt1.x; y1 = pt1.y; x2 = pt2.x; y2 = pt2.y; + c1 = (x1 < 0) + (x1 > right) * 2 + (y1 < 0) * 4 + (y1 > bottom) * 8; + c2 = (x2 < 0) + (x2 > right) * 2 + (y2 < 0) * 4 + (y2 > bottom) * 8; + + if( (c1 & c2) == 0 && (c1 | c2) != 0 ) + { + int64 a; + if( c1 & 12 ) + { + a = c1 < 8 ? 0 : bottom; + x1 += (a - y1) * (x2 - x1) / (y2 - y1); + y1 = a; + c1 = (x1 < 0) + (x1 > right) * 2; + } + if( c2 & 12 ) + { + a = c2 < 8 ? 0 : bottom; + x2 += (a - y2) * (x2 - x1) / (y2 - y1); + y2 = a; + c2 = (x2 < 0) + (x2 > right) * 2; + } + if( (c1 & c2) == 0 && (c1 | c2) != 0 ) + { + if( c1 ) + { + a = c1 == 1 ? 0 : right; + y1 += (a - x1) * (y2 - y1) / (x2 - x1); + x1 = a; + c1 = 0; + } + if( c2 ) + { + a = c2 == 1 ? 0 : right; + y2 += (a - x2) * (y2 - y1) / (x2 - x1); + x2 = a; + c2 = 0; + } + } + + assert( (c1 & c2) != 0 || (x1 | y1 | x2 | y2) >= 0 ); + + pt1.x = (int)x1; + pt1.y = (int)y1; + pt2.x = (int)x2; + pt2.y = (int)y2; + } + + return (c1 | c2) == 0; +} + +bool clipLine( Rect img_rect, Point& pt1, Point& pt2 ) +{ + Point tl = img_rect.tl(); + pt1 -= tl; pt2 -= tl; + bool inside = clipLine(img_rect.size(), pt1, pt2); + pt1 += tl; pt2 += tl; + + return inside; +} + +/* + Initializes line iterator. + Returns number of points on the line or negative number if error. +*/ +LineIterator::LineIterator(const Mat& img, Point pt1, Point pt2, + int connectivity, bool left_to_right) +{ + count = -1; + + CV_Assert( connectivity == 8 || connectivity == 4 ); + + if( (unsigned)pt1.x >= (unsigned)(img.cols) || + (unsigned)pt2.x >= (unsigned)(img.cols) || + (unsigned)pt1.y >= (unsigned)(img.rows) || + (unsigned)pt2.y >= (unsigned)(img.rows) ) + { + if( !clipLine( img.size(), pt1, pt2 ) ) + { + ptr = img.data; + err = plusDelta = minusDelta = plusStep = minusStep = count = 0; + return; + } + } + + int bt_pix0 = (int)img.elemSize(), bt_pix = bt_pix0; + size_t istep = img.step; + + int dx = pt2.x - pt1.x; + int dy = pt2.y - pt1.y; + int s = dx < 0 ? -1 : 0; + + if( left_to_right ) + { + dx = (dx ^ s) - s; + dy = (dy ^ s) - s; + pt1.x ^= (pt1.x ^ pt2.x) & s; + pt1.y ^= (pt1.y ^ pt2.y) & s; + } + else + { + dx = (dx ^ s) - s; + bt_pix = (bt_pix ^ s) - s; + } + + ptr = (uchar*)(img.data + pt1.y * istep + pt1.x * bt_pix0); + + s = dy < 0 ? -1 : 0; + dy = (dy ^ s) - s; + istep = (istep ^ s) - s; + + s = dy > dx ? -1 : 0; + + /* conditional swaps */ + dx ^= dy & s; + dy ^= dx & s; + dx ^= dy & s; + + bt_pix ^= istep & s; + istep ^= bt_pix & s; + bt_pix ^= istep & s; + + if( connectivity == 8 ) + { + assert( dx >= 0 && dy >= 0 ); + + err = dx - (dy + dy); + plusDelta = dx + dx; + minusDelta = -(dy + dy); + plusStep = (int)istep; + minusStep = bt_pix; + count = dx + 1; + } + else /* connectivity == 4 */ + { + assert( dx >= 0 && dy >= 0 ); + + err = 0; + plusDelta = (dx + dx) + (dy + dy); + minusDelta = -(dy + dy); + plusStep = (int)istep - bt_pix; + minusStep = bt_pix; + count = dx + dy + 1; + } + + this->ptr0 = img.data; + this->step = (int)img.step; + this->elemSize = bt_pix0; +} + +static void +Line( Mat& img, Point pt1, Point pt2, + const void* _color, int connectivity = 8 ) +{ + if( connectivity == 0 ) + connectivity = 8; + if( connectivity == 1 ) + connectivity = 4; + + LineIterator iterator(img, pt1, pt2, connectivity, true); + int i, count = iterator.count; + int pix_size = (int)img.elemSize(); + const uchar* color = (const uchar*)_color; + + for( i = 0; i < count; i++, ++iterator ) + { + uchar* ptr = *iterator; + if( pix_size == 1 ) + ptr[0] = color[0]; + else if( pix_size == 3 ) + { + ptr[0] = color[0]; + ptr[1] = color[1]; + ptr[2] = color[2]; + } + else + memcpy( *iterator, color, pix_size ); + } +} + + +/* Correction table depent on the slope */ +static const uchar SlopeCorrTable[] = { + 181, 181, 181, 182, 182, 183, 184, 185, 187, 188, 190, 192, 194, 196, 198, 201, + 203, 206, 209, 211, 214, 218, 221, 224, 227, 231, 235, 238, 242, 246, 250, 254 +}; + +/* Gaussian for antialiasing filter */ +static const int FilterTable[] = { + 168, 177, 185, 194, 202, 210, 218, 224, 231, 236, 241, 246, 249, 252, 254, 254, + 254, 254, 252, 249, 246, 241, 236, 231, 224, 218, 210, 202, 194, 185, 177, 168, + 158, 149, 140, 131, 122, 114, 105, 97, 89, 82, 75, 68, 62, 56, 50, 45, + 40, 36, 32, 28, 25, 22, 19, 16, 14, 12, 11, 9, 8, 7, 5, 5 +}; + +static void +LineAA( Mat& img, Point pt1, Point pt2, const void* color ) +{ + int dx, dy; + int ecount, scount = 0; + int slope; + int ax, ay; + int x_step, y_step; + int i, j; + int ep_table[9]; + int cb = ((uchar*)color)[0], cg = ((uchar*)color)[1], cr = ((uchar*)color)[2]; + int _cb, _cg, _cr; + int nch = img.channels(); + uchar* ptr = img.data; + size_t step = img.step; + Size size = img.size(); + + if( !((nch == 1 || nch == 3) && img.depth() == CV_8U) ) + { + Line(img, pt1, pt2, color); + return; + } + + pt1.x -= XY_ONE*2; + pt1.y -= XY_ONE*2; + pt2.x -= XY_ONE*2; + pt2.y -= XY_ONE*2; + ptr += img.step*2 + 2*nch; + + size.width = ((size.width - 5) << XY_SHIFT) + 1; + size.height = ((size.height - 5) << XY_SHIFT) + 1; + + if( !clipLine( size, pt1, pt2 )) + return; + + dx = pt2.x - pt1.x; + dy = pt2.y - pt1.y; + + j = dx < 0 ? -1 : 0; + ax = (dx ^ j) - j; + i = dy < 0 ? -1 : 0; + ay = (dy ^ i) - i; + + if( ax > ay ) + { + dx = ax; + dy = (dy ^ j) - j; + pt1.x ^= pt2.x & j; + pt2.x ^= pt1.x & j; + pt1.x ^= pt2.x & j; + pt1.y ^= pt2.y & j; + pt2.y ^= pt1.y & j; + pt1.y ^= pt2.y & j; + + x_step = XY_ONE; + y_step = (int) (((int64) dy << XY_SHIFT) / (ax | 1)); + pt2.x += XY_ONE; + ecount = (pt2.x >> XY_SHIFT) - (pt1.x >> XY_SHIFT); + j = -(pt1.x & (XY_ONE - 1)); + pt1.y += (int) ((((int64) y_step) * j) >> XY_SHIFT) + (XY_ONE >> 1); + slope = (y_step >> (XY_SHIFT - 5)) & 0x3f; + slope ^= (y_step < 0 ? 0x3f : 0); + + /* Get 4-bit fractions for end-point adjustments */ + i = (pt1.x >> (XY_SHIFT - 7)) & 0x78; + j = (pt2.x >> (XY_SHIFT - 7)) & 0x78; + } + else + { + dy = ay; + dx = (dx ^ i) - i; + pt1.x ^= pt2.x & i; + pt2.x ^= pt1.x & i; + pt1.x ^= pt2.x & i; + pt1.y ^= pt2.y & i; + pt2.y ^= pt1.y & i; + pt1.y ^= pt2.y & i; + + x_step = (int) (((int64) dx << XY_SHIFT) / (ay | 1)); + y_step = XY_ONE; + pt2.y += XY_ONE; + ecount = (pt2.y >> XY_SHIFT) - (pt1.y >> XY_SHIFT); + j = -(pt1.y & (XY_ONE - 1)); + pt1.x += (int) ((((int64) x_step) * j) >> XY_SHIFT) + (XY_ONE >> 1); + slope = (x_step >> (XY_SHIFT - 5)) & 0x3f; + slope ^= (x_step < 0 ? 0x3f : 0); + + /* Get 4-bit fractions for end-point adjustments */ + i = (pt1.y >> (XY_SHIFT - 7)) & 0x78; + j = (pt2.y >> (XY_SHIFT - 7)) & 0x78; + } + + slope = (slope & 0x20) ? 0x100 : SlopeCorrTable[slope]; + + /* Calc end point correction table */ + { + int t0 = slope << 7; + int t1 = ((0x78 - i) | 4) * slope; + int t2 = (j | 4) * slope; + + ep_table[0] = 0; + ep_table[8] = slope; + ep_table[1] = ep_table[3] = ((((j - i) & 0x78) | 4) * slope >> 8) & 0x1ff; + ep_table[2] = (t1 >> 8) & 0x1ff; + ep_table[4] = ((((j - i) + 0x80) | 4) * slope >> 8) & 0x1ff; + ep_table[5] = ((t1 + t0) >> 8) & 0x1ff; + ep_table[6] = (t2 >> 8) & 0x1ff; + ep_table[7] = ((t2 + t0) >> 8) & 0x1ff; + } + + if( nch == 3 ) + { + #define ICV_PUT_POINT() \ + { \ + _cb = tptr[0]; \ + _cb += ((cb - _cb)*a + 127)>> 8;\ + _cg = tptr[1]; \ + _cg += ((cg - _cg)*a + 127)>> 8;\ + _cr = tptr[2]; \ + _cr += ((cr - _cr)*a + 127)>> 8;\ + tptr[0] = (uchar)_cb; \ + tptr[1] = (uchar)_cg; \ + tptr[2] = (uchar)_cr; \ + } + if( ax > ay ) + { + ptr += (pt1.x >> XY_SHIFT) * 3; + + while( ecount >= 0 ) + { + uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step; + + int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + + (((ecount >= 2) + 1) & (ecount | 2))]; + int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31; + + a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; + ICV_PUT_POINT(); + ICV_PUT_POINT(); + + tptr += step; + a = (ep_corr * FilterTable[dist] >> 8) & 0xff; + ICV_PUT_POINT(); + ICV_PUT_POINT(); + + tptr += step; + a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; + ICV_PUT_POINT(); + ICV_PUT_POINT(); + + pt1.y += y_step; + ptr += 3; + scount++; + ecount--; + } + } + else + { + ptr += (pt1.y >> XY_SHIFT) * step; + + while( ecount >= 0 ) + { + uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1) * 3; + + int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + + (((ecount >= 2) + 1) & (ecount | 2))]; + int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31; + + a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; + ICV_PUT_POINT(); + ICV_PUT_POINT(); + + tptr += 3; + a = (ep_corr * FilterTable[dist] >> 8) & 0xff; + ICV_PUT_POINT(); + ICV_PUT_POINT(); + + tptr += 3; + a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; + ICV_PUT_POINT(); + ICV_PUT_POINT(); + + pt1.x += x_step; + ptr += step; + scount++; + ecount--; + } + } + #undef ICV_PUT_POINT + } + else + { + #define ICV_PUT_POINT() \ + { \ + _cb = tptr[0]; \ + _cb += ((cb - _cb)*a + 127)>> 8;\ + tptr[0] = (uchar)_cb; \ + } + + if( ax > ay ) + { + ptr += (pt1.x >> XY_SHIFT); + + while( ecount >= 0 ) + { + uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step; + + int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + + (((ecount >= 2) + 1) & (ecount | 2))]; + int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31; + + a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; + ICV_PUT_POINT(); + ICV_PUT_POINT(); + + tptr += step; + a = (ep_corr * FilterTable[dist] >> 8) & 0xff; + ICV_PUT_POINT(); + ICV_PUT_POINT(); + + tptr += step; + a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; + ICV_PUT_POINT(); + ICV_PUT_POINT(); + + pt1.y += y_step; + ptr++; + scount++; + ecount--; + } + } + else + { + ptr += (pt1.y >> XY_SHIFT) * step; + + while( ecount >= 0 ) + { + uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1); + + int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + + (((ecount >= 2) + 1) & (ecount | 2))]; + int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31; + + a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; + ICV_PUT_POINT(); + ICV_PUT_POINT(); + + tptr++; + a = (ep_corr * FilterTable[dist] >> 8) & 0xff; + ICV_PUT_POINT(); + ICV_PUT_POINT(); + + tptr++; + a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; + ICV_PUT_POINT(); + ICV_PUT_POINT(); + + pt1.x += x_step; + ptr += step; + scount++; + ecount--; + } + } + #undef ICV_PUT_POINT + } +} + + +static void +Line2( Mat& img, Point pt1, Point pt2, const void* color ) +{ + int dx, dy; + int ecount; + int ax, ay; + int i, j, x, y; + int x_step, y_step; + int cb = ((uchar*)color)[0]; + int cg = ((uchar*)color)[1]; + int cr = ((uchar*)color)[2]; + int pix_size = (int)img.elemSize(); + uchar *ptr = img.data, *tptr; + size_t step = img.step; + Size size = img.size(), sizeScaled(size.width*XY_ONE, size.height*XY_ONE); + + //assert( img && (nch == 1 || nch == 3) && img.depth() == CV_8U ); + + if( !clipLine( sizeScaled, pt1, pt2 )) + return; + + dx = pt2.x - pt1.x; + dy = pt2.y - pt1.y; + + j = dx < 0 ? -1 : 0; + ax = (dx ^ j) - j; + i = dy < 0 ? -1 : 0; + ay = (dy ^ i) - i; + + if( ax > ay ) + { + dx = ax; + dy = (dy ^ j) - j; + pt1.x ^= pt2.x & j; + pt2.x ^= pt1.x & j; + pt1.x ^= pt2.x & j; + pt1.y ^= pt2.y & j; + pt2.y ^= pt1.y & j; + pt1.y ^= pt2.y & j; + + x_step = XY_ONE; + y_step = (int) (((int64) dy << XY_SHIFT) / (ax | 1)); + ecount = (pt2.x - pt1.x) >> XY_SHIFT; + } + else + { + dy = ay; + dx = (dx ^ i) - i; + pt1.x ^= pt2.x & i; + pt2.x ^= pt1.x & i; + pt1.x ^= pt2.x & i; + pt1.y ^= pt2.y & i; + pt2.y ^= pt1.y & i; + pt1.y ^= pt2.y & i; + + x_step = (int) (((int64) dx << XY_SHIFT) / (ay | 1)); + y_step = XY_ONE; + ecount = (pt2.y - pt1.y) >> XY_SHIFT; + } + + pt1.x += (XY_ONE >> 1); + pt1.y += (XY_ONE >> 1); + + if( pix_size == 3 ) + { + #define ICV_PUT_POINT(_x,_y) \ + x = (_x); y = (_y); \ + if( 0 <= x && x < size.width && \ + 0 <= y && y < size.height ) \ + { \ + tptr = ptr + y*step + x*3; \ + tptr[0] = (uchar)cb; \ + tptr[1] = (uchar)cg; \ + tptr[2] = (uchar)cr; \ + } + + ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT, + (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT); + + if( ax > ay ) + { + pt1.x >>= XY_SHIFT; + + while( ecount >= 0 ) + { + ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT); + pt1.x++; + pt1.y += y_step; + ecount--; + } + } + else + { + pt1.y >>= XY_SHIFT; + + while( ecount >= 0 ) + { + ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y); + pt1.x += x_step; + pt1.y++; + ecount--; + } + } + + #undef ICV_PUT_POINT + } + else if( pix_size == 1 ) + { + #define ICV_PUT_POINT(_x,_y) \ + x = (_x); y = (_y); \ + if( 0 <= x && x < size.width && \ + 0 <= y && y < size.height ) \ + { \ + tptr = ptr + y*step + x;\ + tptr[0] = (uchar)cb; \ + } + + ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT, + (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT); + + if( ax > ay ) + { + pt1.x >>= XY_SHIFT; + + while( ecount >= 0 ) + { + ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT); + pt1.x++; + pt1.y += y_step; + ecount--; + } + } + else + { + pt1.y >>= XY_SHIFT; + + while( ecount >= 0 ) + { + ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y); + pt1.x += x_step; + pt1.y++; + ecount--; + } + } + + #undef ICV_PUT_POINT + } + else + { + #define ICV_PUT_POINT(_x,_y) \ + x = (_x); y = (_y); \ + if( 0 <= x && x < size.width && \ + 0 <= y && y < size.height ) \ + { \ + tptr = ptr + y*step + x*pix_size;\ + for( j = 0; j < pix_size; j++ ) \ + tptr[j] = ((uchar*)color)[j]; \ + } + + ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT, + (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT); + + if( ax > ay ) + { + pt1.x >>= XY_SHIFT; + + while( ecount >= 0 ) + { + ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT); + pt1.x++; + pt1.y += y_step; + ecount--; + } + } + else + { + pt1.y >>= XY_SHIFT; + + while( ecount >= 0 ) + { + ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y); + pt1.x += x_step; + pt1.y++; + ecount--; + } + } + + #undef ICV_PUT_POINT + } +} + + +/****************************************************************************************\ +* Antialiazed Elliptic Arcs via Antialiazed Lines * +\****************************************************************************************/ + +static const float SinTable[] = + { 0.0000000f, 0.0174524f, 0.0348995f, 0.0523360f, 0.0697565f, 0.0871557f, + 0.1045285f, 0.1218693f, 0.1391731f, 0.1564345f, 0.1736482f, 0.1908090f, + 0.2079117f, 0.2249511f, 0.2419219f, 0.2588190f, 0.2756374f, 0.2923717f, + 0.3090170f, 0.3255682f, 0.3420201f, 0.3583679f, 0.3746066f, 0.3907311f, + 0.4067366f, 0.4226183f, 0.4383711f, 0.4539905f, 0.4694716f, 0.4848096f, + 0.5000000f, 0.5150381f, 0.5299193f, 0.5446390f, 0.5591929f, 0.5735764f, + 0.5877853f, 0.6018150f, 0.6156615f, 0.6293204f, 0.6427876f, 0.6560590f, + 0.6691306f, 0.6819984f, 0.6946584f, 0.7071068f, 0.7193398f, 0.7313537f, + 0.7431448f, 0.7547096f, 0.7660444f, 0.7771460f, 0.7880108f, 0.7986355f, + 0.8090170f, 0.8191520f, 0.8290376f, 0.8386706f, 0.8480481f, 0.8571673f, + 0.8660254f, 0.8746197f, 0.8829476f, 0.8910065f, 0.8987940f, 0.9063078f, + 0.9135455f, 0.9205049f, 0.9271839f, 0.9335804f, 0.9396926f, 0.9455186f, + 0.9510565f, 0.9563048f, 0.9612617f, 0.9659258f, 0.9702957f, 0.9743701f, + 0.9781476f, 0.9816272f, 0.9848078f, 0.9876883f, 0.9902681f, 0.9925462f, + 0.9945219f, 0.9961947f, 0.9975641f, 0.9986295f, 0.9993908f, 0.9998477f, + 1.0000000f, 0.9998477f, 0.9993908f, 0.9986295f, 0.9975641f, 0.9961947f, + 0.9945219f, 0.9925462f, 0.9902681f, 0.9876883f, 0.9848078f, 0.9816272f, + 0.9781476f, 0.9743701f, 0.9702957f, 0.9659258f, 0.9612617f, 0.9563048f, + 0.9510565f, 0.9455186f, 0.9396926f, 0.9335804f, 0.9271839f, 0.9205049f, + 0.9135455f, 0.9063078f, 0.8987940f, 0.8910065f, 0.8829476f, 0.8746197f, + 0.8660254f, 0.8571673f, 0.8480481f, 0.8386706f, 0.8290376f, 0.8191520f, + 0.8090170f, 0.7986355f, 0.7880108f, 0.7771460f, 0.7660444f, 0.7547096f, + 0.7431448f, 0.7313537f, 0.7193398f, 0.7071068f, 0.6946584f, 0.6819984f, + 0.6691306f, 0.6560590f, 0.6427876f, 0.6293204f, 0.6156615f, 0.6018150f, + 0.5877853f, 0.5735764f, 0.5591929f, 0.5446390f, 0.5299193f, 0.5150381f, + 0.5000000f, 0.4848096f, 0.4694716f, 0.4539905f, 0.4383711f, 0.4226183f, + 0.4067366f, 0.3907311f, 0.3746066f, 0.3583679f, 0.3420201f, 0.3255682f, + 0.3090170f, 0.2923717f, 0.2756374f, 0.2588190f, 0.2419219f, 0.2249511f, + 0.2079117f, 0.1908090f, 0.1736482f, 0.1564345f, 0.1391731f, 0.1218693f, + 0.1045285f, 0.0871557f, 0.0697565f, 0.0523360f, 0.0348995f, 0.0174524f, + 0.0000000f, -0.0174524f, -0.0348995f, -0.0523360f, -0.0697565f, -0.0871557f, + -0.1045285f, -0.1218693f, -0.1391731f, -0.1564345f, -0.1736482f, -0.1908090f, + -0.2079117f, -0.2249511f, -0.2419219f, -0.2588190f, -0.2756374f, -0.2923717f, + -0.3090170f, -0.3255682f, -0.3420201f, -0.3583679f, -0.3746066f, -0.3907311f, + -0.4067366f, -0.4226183f, -0.4383711f, -0.4539905f, -0.4694716f, -0.4848096f, + -0.5000000f, -0.5150381f, -0.5299193f, -0.5446390f, -0.5591929f, -0.5735764f, + -0.5877853f, -0.6018150f, -0.6156615f, -0.6293204f, -0.6427876f, -0.6560590f, + -0.6691306f, -0.6819984f, -0.6946584f, -0.7071068f, -0.7193398f, -0.7313537f, + -0.7431448f, -0.7547096f, -0.7660444f, -0.7771460f, -0.7880108f, -0.7986355f, + -0.8090170f, -0.8191520f, -0.8290376f, -0.8386706f, -0.8480481f, -0.8571673f, + -0.8660254f, -0.8746197f, -0.8829476f, -0.8910065f, -0.8987940f, -0.9063078f, + -0.9135455f, -0.9205049f, -0.9271839f, -0.9335804f, -0.9396926f, -0.9455186f, + -0.9510565f, -0.9563048f, -0.9612617f, -0.9659258f, -0.9702957f, -0.9743701f, + -0.9781476f, -0.9816272f, -0.9848078f, -0.9876883f, -0.9902681f, -0.9925462f, + -0.9945219f, -0.9961947f, -0.9975641f, -0.9986295f, -0.9993908f, -0.9998477f, + -1.0000000f, -0.9998477f, -0.9993908f, -0.9986295f, -0.9975641f, -0.9961947f, + -0.9945219f, -0.9925462f, -0.9902681f, -0.9876883f, -0.9848078f, -0.9816272f, + -0.9781476f, -0.9743701f, -0.9702957f, -0.9659258f, -0.9612617f, -0.9563048f, + -0.9510565f, -0.9455186f, -0.9396926f, -0.9335804f, -0.9271839f, -0.9205049f, + -0.9135455f, -0.9063078f, -0.8987940f, -0.8910065f, -0.8829476f, -0.8746197f, + -0.8660254f, -0.8571673f, -0.8480481f, -0.8386706f, -0.8290376f, -0.8191520f, + -0.8090170f, -0.7986355f, -0.7880108f, -0.7771460f, -0.7660444f, -0.7547096f, + -0.7431448f, -0.7313537f, -0.7193398f, -0.7071068f, -0.6946584f, -0.6819984f, + -0.6691306f, -0.6560590f, -0.6427876f, -0.6293204f, -0.6156615f, -0.6018150f, + -0.5877853f, -0.5735764f, -0.5591929f, -0.5446390f, -0.5299193f, -0.5150381f, + -0.5000000f, -0.4848096f, -0.4694716f, -0.4539905f, -0.4383711f, -0.4226183f, + -0.4067366f, -0.3907311f, -0.3746066f, -0.3583679f, -0.3420201f, -0.3255682f, + -0.3090170f, -0.2923717f, -0.2756374f, -0.2588190f, -0.2419219f, -0.2249511f, + -0.2079117f, -0.1908090f, -0.1736482f, -0.1564345f, -0.1391731f, -0.1218693f, + -0.1045285f, -0.0871557f, -0.0697565f, -0.0523360f, -0.0348995f, -0.0174524f, + -0.0000000f, 0.0174524f, 0.0348995f, 0.0523360f, 0.0697565f, 0.0871557f, + 0.1045285f, 0.1218693f, 0.1391731f, 0.1564345f, 0.1736482f, 0.1908090f, + 0.2079117f, 0.2249511f, 0.2419219f, 0.2588190f, 0.2756374f, 0.2923717f, + 0.3090170f, 0.3255682f, 0.3420201f, 0.3583679f, 0.3746066f, 0.3907311f, + 0.4067366f, 0.4226183f, 0.4383711f, 0.4539905f, 0.4694716f, 0.4848096f, + 0.5000000f, 0.5150381f, 0.5299193f, 0.5446390f, 0.5591929f, 0.5735764f, + 0.5877853f, 0.6018150f, 0.6156615f, 0.6293204f, 0.6427876f, 0.6560590f, + 0.6691306f, 0.6819984f, 0.6946584f, 0.7071068f, 0.7193398f, 0.7313537f, + 0.7431448f, 0.7547096f, 0.7660444f, 0.7771460f, 0.7880108f, 0.7986355f, + 0.8090170f, 0.8191520f, 0.8290376f, 0.8386706f, 0.8480481f, 0.8571673f, + 0.8660254f, 0.8746197f, 0.8829476f, 0.8910065f, 0.8987940f, 0.9063078f, + 0.9135455f, 0.9205049f, 0.9271839f, 0.9335804f, 0.9396926f, 0.9455186f, + 0.9510565f, 0.9563048f, 0.9612617f, 0.9659258f, 0.9702957f, 0.9743701f, + 0.9781476f, 0.9816272f, 0.9848078f, 0.9876883f, 0.9902681f, 0.9925462f, + 0.9945219f, 0.9961947f, 0.9975641f, 0.9986295f, 0.9993908f, 0.9998477f, + 1.0000000f +}; + + +static void +sincos( int angle, float& cosval, float& sinval ) +{ + angle += (angle < 0 ? 360 : 0); + sinval = SinTable[angle]; + cosval = SinTable[450 - angle]; +} + +/* + constructs polygon that represents elliptic arc. +*/ +void ellipse2Poly( Point center, Size axes, int angle, + int arc_start, int arc_end, + int delta, vector& pts ) +{ + float alpha, beta; + double size_a = axes.width, size_b = axes.height; + double cx = center.x, cy = center.y; + Point prevPt(INT_MIN,INT_MIN); + int i; + + while( angle < 0 ) + angle += 360; + while( angle > 360 ) + angle -= 360; + + if( arc_start > arc_end ) + { + i = arc_start; + arc_start = arc_end; + arc_end = i; + } + while( arc_start < 0 ) + { + arc_start += 360; + arc_end += 360; + } + while( arc_end > 360 ) + { + arc_end -= 360; + arc_start -= 360; + } + if( arc_end - arc_start > 360 ) + { + arc_start = 0; + arc_end = 360; + } + sincos( angle, alpha, beta ); + pts.resize(0); + + for( i = arc_start; i < arc_end + delta; i += delta ) + { + double x, y; + angle = i; + if( angle > arc_end ) + angle = arc_end; + if( angle < 0 ) + angle += 360; + + x = size_a * SinTable[450-angle]; + y = size_b * SinTable[angle]; + Point pt; + pt.x = cvRound( cx + x * alpha - y * beta ); + pt.y = cvRound( cy + x * beta + y * alpha ); + if( pt != prevPt ) + pts.push_back(pt); + } + + if( pts.size() < 2 ) + pts.push_back(pts[0]); +} + + +static void +EllipseEx( Mat& img, Point center, Size axes, + int angle, int arc_start, int arc_end, + const void* color, int thickness, int line_type ) +{ + axes.width = std::abs(axes.width), axes.height = std::abs(axes.height); + int delta = (std::max(axes.width,axes.height)+(XY_ONE>>1))>>XY_SHIFT; + delta = delta < 3 ? 90 : delta < 10 ? 30 : delta < 15 ? 18 : 5; + + vector v; + ellipse2Poly( center, axes, angle, arc_start, arc_end, delta, v ); + + if( thickness >= 0 ) + PolyLine( img, &v[0], (int)v.size(), false, color, thickness, line_type, XY_SHIFT ); + else if( arc_end - arc_start >= 360 ) + FillConvexPoly( img, &v[0], (int)v.size(), color, line_type, XY_SHIFT ); + else + { + v.push_back(center); + vector edges; + CollectPolyEdges( img, &v[0], (int)v.size(), edges, color, line_type, XY_SHIFT ); + FillEdgeCollection( img, edges, color ); + } +} + + +/****************************************************************************************\ +* Polygons filling * +\****************************************************************************************/ + +/* helper macros: filling horizontal row */ +#define ICV_HLINE( ptr, xl, xr, color, pix_size ) \ +{ \ + uchar* hline_ptr = (uchar*)(ptr) + (xl)*(pix_size); \ + uchar* hline_max_ptr = (uchar*)(ptr) + (xr)*(pix_size); \ + \ + for( ; hline_ptr <= hline_max_ptr; hline_ptr += (pix_size))\ + { \ + int hline_j; \ + for( hline_j = 0; hline_j < (pix_size); hline_j++ ) \ + { \ + hline_ptr[hline_j] = ((uchar*)color)[hline_j]; \ + } \ + } \ +} + + +/* filling convex polygon. v - array of vertices, ntps - number of points */ +static void +FillConvexPoly( Mat& img, const Point* v, int npts, const void* color, int line_type, int shift ) +{ + struct + { + int idx, di; + int x, dx, ye; + } + edge[2]; + + int delta = shift ? 1 << (shift - 1) : 0; + int i, y, imin = 0, left = 0, right = 1, x1, x2; + int edges = npts; + int xmin, xmax, ymin, ymax; + uchar* ptr = img.data; + Size size = img.size(); + int pix_size = (int)img.elemSize(); + Point p0; + int delta1, delta2; + + if( line_type < CV_AA ) + delta1 = delta2 = XY_ONE >> 1; + else + delta1 = XY_ONE - 1, delta2 = 0; + + p0 = v[npts - 1]; + p0.x <<= XY_SHIFT - shift; + p0.y <<= XY_SHIFT - shift; + + assert( 0 <= shift && shift <= XY_SHIFT ); + xmin = xmax = v[0].x; + ymin = ymax = v[0].y; + + for( i = 0; i < npts; i++ ) + { + Point p = v[i]; + if( p.y < ymin ) + { + ymin = p.y; + imin = i; + } + + ymax = std::max( ymax, p.y ); + xmax = std::max( xmax, p.x ); + xmin = MIN( xmin, p.x ); + + p.x <<= XY_SHIFT - shift; + p.y <<= XY_SHIFT - shift; + + if( line_type <= 8 ) + { + if( shift == 0 ) + { + Point pt0, pt1; + pt0.x = p0.x >> XY_SHIFT; + pt0.y = p0.y >> XY_SHIFT; + pt1.x = p.x >> XY_SHIFT; + pt1.y = p.y >> XY_SHIFT; + Line( img, pt0, pt1, color, line_type ); + } + else + Line2( img, p0, p, color ); + } + else + LineAA( img, p0, p, color ); + p0 = p; + } + + xmin = (xmin + delta) >> shift; + xmax = (xmax + delta) >> shift; + ymin = (ymin + delta) >> shift; + ymax = (ymax + delta) >> shift; + + if( npts < 3 || xmax < 0 || ymax < 0 || xmin >= size.width || ymin >= size.height ) + return; + + ymax = MIN( ymax, size.height - 1 ); + edge[0].idx = edge[1].idx = imin; + + edge[0].ye = edge[1].ye = y = ymin; + edge[0].di = 1; + edge[1].di = npts - 1; + + ptr += img.step*y; + + do + { + if( line_type < CV_AA || y < ymax || y == ymin ) + { + for( i = 0; i < 2; i++ ) + { + if( y >= edge[i].ye ) + { + int idx = edge[i].idx, di = edge[i].di; + int xs = 0, xe, ye, ty = 0; + + for(;;) + { + ty = (v[idx].y + delta) >> shift; + if( ty > y || edges == 0 ) + break; + xs = v[idx].x; + idx += di; + idx -= ((idx < npts) - 1) & npts; /* idx -= idx >= npts ? npts : 0 */ + edges--; + } + + ye = ty; + xs <<= XY_SHIFT - shift; + xe = v[idx].x << (XY_SHIFT - shift); + + /* no more edges */ + if( y >= ye ) + return; + + edge[i].ye = ye; + edge[i].dx = ((xe - xs)*2 + (ye - y)) / (2 * (ye - y)); + edge[i].x = xs; + edge[i].idx = idx; + } + } + } + + if( edge[left].x > edge[right].x ) + { + left ^= 1; + right ^= 1; + } + + x1 = edge[left].x; + x2 = edge[right].x; + + if( y >= 0 ) + { + int xx1 = (x1 + delta1) >> XY_SHIFT; + int xx2 = (x2 + delta2) >> XY_SHIFT; + + if( xx2 >= 0 && xx1 < size.width ) + { + if( xx1 < 0 ) + xx1 = 0; + if( xx2 >= size.width ) + xx2 = size.width - 1; + ICV_HLINE( ptr, xx1, xx2, color, pix_size ); + } + } + + x1 += edge[left].dx; + x2 += edge[right].dx; + + edge[left].x = x1; + edge[right].x = x2; + ptr += img.step; + } + while( ++y <= ymax ); +} + + +/******** Arbitrary polygon **********/ + +static void +CollectPolyEdges( Mat& img, const Point* v, int count, vector& edges, + const void* color, int line_type, int shift, Point offset ) +{ + int i, delta = offset.y + (shift ? 1 << (shift - 1) : 0); + Point pt0 = v[count-1], pt1; + pt0.x = (pt0.x + offset.x) << (XY_SHIFT - shift); + pt0.y = (pt0.y + delta) >> shift; + + edges.reserve( edges.size() + count ); + + for( i = 0; i < count; i++, pt0 = pt1 ) + { + Point t0, t1; + PolyEdge edge; + + pt1 = v[i]; + pt1.x = (pt1.x + offset.x) << (XY_SHIFT - shift); + pt1.y = (pt1.y + delta) >> shift; + + if( line_type < CV_AA ) + { + t0.y = pt0.y; t1.y = pt1.y; + t0.x = (pt0.x + (XY_ONE >> 1)) >> XY_SHIFT; + t1.x = (pt1.x + (XY_ONE >> 1)) >> XY_SHIFT; + Line( img, t0, t1, color, line_type ); + } + else + { + t0.x = pt0.x; t1.x = pt1.x; + t0.y = pt0.y << XY_SHIFT; + t1.y = pt1.y << XY_SHIFT; + LineAA( img, t0, t1, color ); + } + + if( pt0.y == pt1.y ) + continue; + + if( pt0.y < pt1.y ) + { + edge.y0 = pt0.y; + edge.y1 = pt1.y; + edge.x = pt0.x; + } + else + { + edge.y0 = pt1.y; + edge.y1 = pt0.y; + edge.x = pt1.x; + } + edge.dx = (pt1.x - pt0.x) / (pt1.y - pt0.y); + edges.push_back(edge); + } +} + +struct CmpEdges +{ + bool operator ()(const PolyEdge& e1, const PolyEdge& e2) + { + return e1.y0 - e2.y0 ? e1.y0 < e2.y0 : + e1.x - e2.x ? e1.x < e2.x : e1.dx < e2.dx; + } +}; + +/**************** helper macros and functions for sequence/contour processing ***********/ + +static void +FillEdgeCollection( Mat& img, vector& edges, const void* color ) +{ + PolyEdge tmp; + int i, y, total = (int)edges.size(); + Size size = img.size(); + PolyEdge* e; + int y_max = INT_MIN, x_max = INT_MIN, y_min = INT_MAX, x_min = INT_MAX; + int pix_size = (int)img.elemSize(); + + if( total < 2 ) + return; + + for( i = 0; i < total; i++ ) + { + PolyEdge& e1 = edges[i]; + assert( e1.y0 < e1.y1 ); + y_min = std::min( y_min, e1.y0 ); + y_max = std::max( y_max, e1.y1 ); + x_min = std::min( x_min, e1.x ); + x_max = std::max( x_max, e1.x ); + } + + if( y_max < 0 || y_min >= size.height || x_max < 0 || x_min >= (size.width<y0; y < y_max; y++ ) + { + PolyEdge *last, *prelast, *keep_prelast; + int sort_flag = 0; + int draw = 0; + int clipline = y < 0; + + prelast = &tmp; + last = tmp.next; + while( last || e->y0 == y ) + { + if( last && last->y1 == y ) + { + // exclude edge if y reachs its lower point + prelast->next = last->next; + last = last->next; + continue; + } + keep_prelast = prelast; + if( last && (e->y0 > y || last->x < e->x) ) + { + // go to the next edge in active list + prelast = last; + last = last->next; + } + else if( i < total ) + { + // insert new edge into active list if y reachs its upper point + prelast->next = e; + e->next = last; + prelast = e; + e = &edges[++i]; + } + else + break; + + if( draw ) + { + if( !clipline ) + { + // convert x's from fixed-point to image coordinates + uchar *timg = img.data + y * img.step; + int x1 = keep_prelast->x; + int x2 = prelast->x; + + if( x1 > x2 ) + { + int t = x1; + + x1 = x2; + x2 = t; + } + + x1 = (x1 + XY_ONE - 1) >> XY_SHIFT; + x2 = x2 >> XY_SHIFT; + + // clip and draw the line + if( x1 < size.width && x2 >= 0 ) + { + if( x1 < 0 ) + x1 = 0; + if( x2 >= size.width ) + x2 = size.width - 1; + ICV_HLINE( timg, x1, x2, color, pix_size ); + } + } + keep_prelast->x += keep_prelast->dx; + prelast->x += prelast->dx; + } + draw ^= 1; + } + + // sort edges (using bubble sort) + keep_prelast = 0; + + do + { + prelast = &tmp; + last = tmp.next; + + while( last != keep_prelast && last->next != 0 ) + { + PolyEdge *te = last->next; + + // swap edges + if( last->x > te->x ) + { + prelast->next = te; + last->next = te->next; + te->next = last; + prelast = te; + sort_flag = 1; + } + else + { + prelast = last; + last = te; + } + } + keep_prelast = prelast; + } + while( sort_flag && keep_prelast != tmp.next && keep_prelast != &tmp ); + } +} + + +/* draws simple or filled circle */ +static void +Circle( Mat& img, Point center, int radius, const void* color, int fill ) +{ + Size size = img.size(); + size_t step = img.step; + int pix_size = (int)img.elemSize(); + uchar* ptr = img.data; + int err = 0, dx = radius, dy = 0, plus = 1, minus = (radius << 1) - 1; + int inside = center.x >= radius && center.x < size.width - radius && + center.y >= radius && center.y < size.height - radius; + + #define ICV_PUT_POINT( ptr, x ) \ + memcpy( ptr + (x)*pix_size, color, pix_size ); + + while( dx >= dy ) + { + int mask; + int y11 = center.y - dy, y12 = center.y + dy, y21 = center.y - dx, y22 = center.y + dx; + int x11 = center.x - dx, x12 = center.x + dx, x21 = center.x - dy, x22 = center.x + dy; + + if( inside ) + { + uchar *tptr0 = ptr + y11 * step; + uchar *tptr1 = ptr + y12 * step; + + if( !fill ) + { + ICV_PUT_POINT( tptr0, x11 ); + ICV_PUT_POINT( tptr1, x11 ); + ICV_PUT_POINT( tptr0, x12 ); + ICV_PUT_POINT( tptr1, x12 ); + } + else + { + ICV_HLINE( tptr0, x11, x12, color, pix_size ); + ICV_HLINE( tptr1, x11, x12, color, pix_size ); + } + + tptr0 = ptr + y21 * step; + tptr1 = ptr + y22 * step; + + if( !fill ) + { + ICV_PUT_POINT( tptr0, x21 ); + ICV_PUT_POINT( tptr1, x21 ); + ICV_PUT_POINT( tptr0, x22 ); + ICV_PUT_POINT( tptr1, x22 ); + } + else + { + ICV_HLINE( tptr0, x21, x22, color, pix_size ); + ICV_HLINE( tptr1, x21, x22, color, pix_size ); + } + } + else if( x11 < size.width && x12 >= 0 && y21 < size.height && y22 >= 0 ) + { + if( fill ) + { + x11 = std::max( x11, 0 ); + x12 = MIN( x12, size.width - 1 ); + } + + if( (unsigned)y11 < (unsigned)size.height ) + { + uchar *tptr = ptr + y11 * step; + + if( !fill ) + { + if( x11 >= 0 ) + ICV_PUT_POINT( tptr, x11 ); + if( x12 < size.width ) + ICV_PUT_POINT( tptr, x12 ); + } + else + ICV_HLINE( tptr, x11, x12, color, pix_size ); + } + + if( (unsigned)y12 < (unsigned)size.height ) + { + uchar *tptr = ptr + y12 * step; + + if( !fill ) + { + if( x11 >= 0 ) + ICV_PUT_POINT( tptr, x11 ); + if( x12 < size.width ) + ICV_PUT_POINT( tptr, x12 ); + } + else + ICV_HLINE( tptr, x11, x12, color, pix_size ); + } + + if( x21 < size.width && x22 >= 0 ) + { + if( fill ) + { + x21 = std::max( x21, 0 ); + x22 = MIN( x22, size.width - 1 ); + } + + if( (unsigned)y21 < (unsigned)size.height ) + { + uchar *tptr = ptr + y21 * step; + + if( !fill ) + { + if( x21 >= 0 ) + ICV_PUT_POINT( tptr, x21 ); + if( x22 < size.width ) + ICV_PUT_POINT( tptr, x22 ); + } + else + ICV_HLINE( tptr, x21, x22, color, pix_size ); + } + + if( (unsigned)y22 < (unsigned)size.height ) + { + uchar *tptr = ptr + y22 * step; + + if( !fill ) + { + if( x21 >= 0 ) + ICV_PUT_POINT( tptr, x21 ); + if( x22 < size.width ) + ICV_PUT_POINT( tptr, x22 ); + } + else + ICV_HLINE( tptr, x21, x22, color, pix_size ); + } + } + } + dy++; + err += plus; + plus += 2; + + mask = (err <= 0) - 1; + + err -= minus & mask; + dx += mask; + minus -= mask & 2; + } + + #undef ICV_PUT_POINT +} + + +static void +ThickLine( Mat& img, Point p0, Point p1, const void* color, + int thickness, int line_type, int flags, int shift ) +{ + static const double INV_XY_ONE = 1./XY_ONE; + + p0.x <<= XY_SHIFT - shift; + p0.y <<= XY_SHIFT - shift; + p1.x <<= XY_SHIFT - shift; + p1.y <<= XY_SHIFT - shift; + + if( thickness <= 1 ) + { + if( line_type < CV_AA ) + { + if( line_type == 1 || line_type == 4 || shift == 0 ) + { + p0.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT; + p0.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT; + p1.x = (p1.x + (XY_ONE>>1)) >> XY_SHIFT; + p1.y = (p1.y + (XY_ONE>>1)) >> XY_SHIFT; + Line( img, p0, p1, color, line_type ); + } + else + Line2( img, p0, p1, color ); + } + else + LineAA( img, p0, p1, color ); + } + else + { + Point pt[4], dp = Point(0,0); + double dx = (p0.x - p1.x)*INV_XY_ONE, dy = (p1.y - p0.y)*INV_XY_ONE; + double r = dx * dx + dy * dy; + int i, oddThickness = thickness & 1; + thickness <<= XY_SHIFT - 1; + + if( fabs(r) > DBL_EPSILON ) + { + r = (thickness + oddThickness*XY_ONE*0.5)/std::sqrt(r); + dp.x = cvRound( dy * r ); + dp.y = cvRound( dx * r ); + + pt[0].x = p0.x + dp.x; + pt[0].y = p0.y + dp.y; + pt[1].x = p0.x - dp.x; + pt[1].y = p0.y - dp.y; + pt[2].x = p1.x - dp.x; + pt[2].y = p1.y - dp.y; + pt[3].x = p1.x + dp.x; + pt[3].y = p1.y + dp.y; + + FillConvexPoly( img, pt, 4, color, line_type, XY_SHIFT ); + } + + for( i = 0; i < 2; i++ ) + { + if( flags & (i+1) ) + { + if( line_type < CV_AA ) + { + Point center; + center.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT; + center.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT; + Circle( img, center, (thickness + (XY_ONE>>1)) >> XY_SHIFT, color, 1 ); + } + else + { + EllipseEx( img, p0, cvSize(thickness, thickness), + 0, 0, 360, color, -1, line_type ); + } + } + p0 = p1; + } + } +} + + +static void +PolyLine( Mat& img, const Point* v, int count, bool is_closed, + const void* color, int thickness, + int line_type, int shift ) +{ + if( !v || count <= 0 ) + return; + + int i = is_closed ? count - 1 : 0; + int flags = 2 + !is_closed; + Point p0; + CV_Assert( 0 <= shift && shift <= XY_SHIFT && thickness >= 0 ); + + p0 = v[i]; + for( i = !is_closed; i < count; i++ ) + { + Point p = v[i]; + ThickLine( img, p0, p, color, thickness, line_type, flags, shift ); + p0 = p; + flags = 2; + } +} + +/****************************************************************************************\ +* External functions * +\****************************************************************************************/ + +void line( Mat& img, Point pt1, Point pt2, const Scalar& color, + int thickness, int line_type, int shift ) +{ + if( line_type == CV_AA && img.depth() != CV_8U ) + line_type = 8; + + CV_Assert( 0 <= thickness && thickness <= 255 ); + CV_Assert( 0 <= shift && shift <= XY_SHIFT ); + + double buf[4]; + scalarToRawData( color, buf, img.type(), 0 ); + ThickLine( img, pt1, pt2, buf, thickness, line_type, 3, shift ); +} + +void rectangle( Mat& img, Point pt1, Point pt2, + const Scalar& color, int thickness, + int lineType, int shift ) +{ + if( lineType == CV_AA && img.depth() != CV_8U ) + lineType = 8; + + CV_Assert( thickness <= 255 ); + CV_Assert( 0 <= shift && shift <= XY_SHIFT ); + + double buf[4]; + scalarToRawData(color, buf, img.type(), 0); + + Point pt[4]; + + pt[0] = pt1; + pt[1].x = pt2.x; + pt[1].y = pt1.y; + pt[2] = pt2; + pt[3].x = pt1.x; + pt[3].y = pt2.y; + + if( thickness >= 0 ) + PolyLine( img, pt, 4, true, buf, thickness, lineType, shift ); + else + FillConvexPoly( img, pt, 4, buf, lineType, shift ); +} + + +void rectangle( Mat& img, Rect rec, + const Scalar& color, int thickness, + int lineType, int shift ) +{ + CV_Assert( 0 <= shift && shift <= XY_SHIFT ); + if( rec.area() > 0 ) + rectangle( img, rec.tl(), rec.br() - Point(1<= 0 && thickness <= 255 && + 0 <= shift && shift <= XY_SHIFT ); + + double buf[4]; + scalarToRawData(color, buf, img.type(), 0); + + if( thickness > 1 || line_type >= CV_AA ) + { + center.x <<= XY_SHIFT - shift; + center.y <<= XY_SHIFT - shift; + radius <<= XY_SHIFT - shift; + EllipseEx( img, center, Size(radius, radius), + 0, 0, 360, buf, thickness, line_type ); + } + else + Circle( img, center, radius, buf, thickness < 0 ); +} + + +void ellipse( Mat& img, Point center, Size axes, + double angle, double start_angle, double end_angle, + const Scalar& color, int thickness, int line_type, int shift ) +{ + if( line_type == CV_AA && img.depth() != CV_8U ) + line_type = 8; + + CV_Assert( axes.width >= 0 && axes.height >= 0 && + thickness <= 255 && 0 <= shift && shift <= XY_SHIFT ); + + double buf[4]; + scalarToRawData(color, buf, img.type(), 0); + + int _angle = cvRound(angle); + int _start_angle = cvRound(start_angle); + int _end_angle = cvRound(end_angle); + center.x <<= XY_SHIFT - shift; + center.y <<= XY_SHIFT - shift; + axes.width <<= XY_SHIFT - shift; + axes.height <<= XY_SHIFT - shift; + + EllipseEx( img, center, axes, _angle, _start_angle, + _end_angle, buf, thickness, line_type ); +} + +void ellipse(Mat& img, const RotatedRect& box, const Scalar& color, + int thickness, int lineType) +{ + if( lineType == CV_AA && img.depth() != CV_8U ) + lineType = 8; + + CV_Assert( box.size.width >= 0 && box.size.height >= 0 && + thickness <= 255 ); + + double buf[4]; + scalarToRawData(color, buf, img.type(), 0); + + int _angle = cvRound(box.angle); + Point center(cvRound(box.center.x*(1 << XY_SHIFT)), + cvRound(box.center.y*(1 << XY_SHIFT))); + Size axes(cvRound(box.size.width*(1 << (XY_SHIFT - 1))), + cvRound(box.size.height*(1 << (XY_SHIFT - 1)))); + EllipseEx( img, center, axes, _angle, 0, 360, buf, thickness, lineType ); +} + +void fillConvexPoly( Mat& img, const Point* pts, int npts, + const Scalar& color, int line_type, int shift ) +{ + if( !pts || npts <= 0 ) + return; + + if( line_type == CV_AA && img.depth() != CV_8U ) + line_type = 8; + + double buf[4]; + CV_Assert( 0 <= shift && shift <= XY_SHIFT ); + scalarToRawData(color, buf, img.type(), 0); + FillConvexPoly( img, pts, npts, buf, line_type, shift ); +} + + +void fillPoly( Mat& img, const Point** pts, const int* npts, int ncontours, + const Scalar& color, int line_type, + int shift, Point offset ) +{ + if( line_type == CV_AA && img.depth() != CV_8U ) + line_type = 8; + + CV_Assert( pts && npts && ncontours >= 0 && 0 <= shift && shift <= XY_SHIFT ); + + double buf[4]; + scalarToRawData(color, buf, img.type(), 0); + + vector edges; + + int i, total = 0; + for( i = 0; i < ncontours; i++ ) + total += npts[i]; + + edges.reserve( total + 1 ); + for( i = 0; i < ncontours; i++ ) + CollectPolyEdges( img, pts[i], npts[i], edges, buf, line_type, shift, offset ); + + FillEdgeCollection(img, edges, buf); +} + + +void polylines( Mat& img, const Point* const* pts, const int* npts, int ncontours, bool isClosed, + const Scalar& color, int thickness, int line_type, int shift ) +{ + if( line_type == CV_AA && img.depth() != CV_8U ) + line_type = 8; + + CV_Assert( pts && npts && ncontours >= 0 && + 0 <= thickness && thickness <= 255 && + 0 <= shift && shift <= XY_SHIFT ); + + double buf[4]; + scalarToRawData( color, buf, img.type(), 0 ); + + for( int i = 0; i < ncontours; i++ ) + PolyLine( img, pts[i], npts[i], isClosed, buf, thickness, line_type, shift ); +} + + +enum { FONT_SIZE_SHIFT=8, FONT_ITALIC_ALPHA=(1 << 8), + FONT_ITALIC_DIGIT=(2 << 8), FONT_ITALIC_PUNCT=(4 << 8), + FONT_ITALIC_BRACES=(8 << 8), FONT_HAVE_GREEK=(16 << 8), + FONT_HAVE_CYRILLIC=(32 << 8) }; + +static const int HersheyPlain[] = { +(5 + 4*16) + FONT_HAVE_GREEK, +199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220, +200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192, +215, 190, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, +14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 193, 84, +194, 85, 86, 87, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, +112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, +195, 223, 196, 88 }; + +static const int HersheyPlainItalic[] = { +(5 + 4*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK, +199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220, +200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192, +215, 190, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, +64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 193, 84, +194, 85, 86, 87, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, +162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, +195, 223, 196, 88 }; + +static const int HersheyComplexSmall[] = { +(6 + 7*16) + FONT_HAVE_GREEK, +1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220, +1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 2213, 1241, 1238, 1242, +1215, 1273, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, +1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1223, 1084, +1224, 1247, 586, 1249, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, +1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, +1225, 1229, 1226, 1246 }; + +static const int HersheyComplexSmallItalic[] = { +(6 + 7*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK, +1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220, +1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 1213, 1241, 1238, 1242, +1215, 1273, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, +1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1223, 1084, +1224, 1247, 586, 1249, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, +1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, +1225, 1229, 1226, 1246 }; + +static const int HersheySimplex[] = { +(9 + 12*16) + FONT_HAVE_GREEK, +2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720, +700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692, +715, 690, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, +514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 693, 584, +694, 2247, 586, 2249, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, +612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, +695, 723, 696, 2246 }; + +static const int HersheyDuplex[] = { +(9 + 12*16) + FONT_HAVE_GREEK, +2199, 2714, 2728, 2732, 2719, 2733, 2718, 2727, 2721, 2722, 2723, 2725, 2711, 2724, 2710, 2720, +2700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2712, 2713, 2730, 2726, 2731, +2715, 2734, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513, +2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2525, 2526, 2223, 2084, +2224, 2247, 587, 2249, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611, +2612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, 2626, +2225, 2229, 2226, 2246 }; + +static const int HersheyComplex[] = { +(9 + 12*16) + FONT_HAVE_GREEK + FONT_HAVE_CYRILLIC, +2199, 2214, 2217, 2275, 2274, 2271, 2272, 2216, 2221, 2222, 2219, 2232, 2211, 2231, 2210, 2220, +2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2212, 2213, 2241, 2238, 2242, +2215, 2273, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, +2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2223, 2084, +2224, 2247, 587, 2249, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111, +2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126, +2225, 2229, 2226, 2246 }; + +static const int HersheyComplexItalic[] = { +(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + FONT_ITALIC_PUNCT + +FONT_HAVE_GREEK + FONT_HAVE_CYRILLIC, +2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220, +2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242, +2765, 2273, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, +2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2223, 2084, +2224, 2247, 587, 2249, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, +2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176, +2225, 2229, 2226, 2246 }; + +static const int HersheyTriplex[] = { +(9 + 12*16) + FONT_HAVE_GREEK, +2199, 3214, 3228, 3232, 3219, 3233, 3218, 3227, 3221, 3222, 3223, 3225, 3211, 3224, 3210, 3220, +3200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3212, 3213, 3230, 3226, 3231, +3215, 3234, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013, +2014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 2223, 2084, +2224, 2247, 587, 2249, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111, +3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126, +2225, 2229, 2226, 2246 }; + +static const int HersheyTriplexItalic[] = { +(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + +FONT_ITALIC_PUNCT + FONT_HAVE_GREEK, +2199, 3264, 3278, 3282, 3269, 3233, 3268, 3277, 3271, 3272, 3223, 3225, 3261, 3224, 3260, 3270, +3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3262, 3263, 3230, 3226, 3231, +3265, 3234, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063, +2064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 2223, 2084, +2224, 2247, 587, 2249, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161, +3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3175, 3176, +2225, 2229, 2226, 2246 }; + +static const int HersheyScriptSimplex[] = { +(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK, +2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720, +700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692, +715, 690, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, +564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 693, 584, +694, 2247, 586, 2249, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, +662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, +695, 723, 696, 2246 }; + +static const int HersheyScriptComplex[] = { +(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + FONT_ITALIC_PUNCT + FONT_HAVE_GREEK, +2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220, +2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242, +2215, 2273, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, +2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2223, 2084, +2224, 2247, 586, 2249, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, +2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676, +2225, 2229, 2226, 2246 }; + + +static const int* getFontData(int fontFace) +{ + bool isItalic = (fontFace & FONT_ITALIC) != 0; + const int* ascii = 0; + + switch( fontFace & 15 ) + { + case FONT_HERSHEY_SIMPLEX: + ascii = HersheySimplex; + break; + case FONT_HERSHEY_PLAIN: + ascii = !isItalic ? HersheyPlain : HersheyPlainItalic; + break; + case FONT_HERSHEY_DUPLEX: + ascii = HersheyDuplex; + break; + case FONT_HERSHEY_COMPLEX: + ascii = !isItalic ? HersheyComplex : HersheyComplexItalic; + break; + case FONT_HERSHEY_TRIPLEX: + ascii = !isItalic ? HersheyTriplex : HersheyTriplexItalic; + break; + case FONT_HERSHEY_COMPLEX_SMALL: + ascii = !isItalic ? HersheyComplexSmall : HersheyComplexSmallItalic; + break; + case FONT_HERSHEY_SCRIPT_SIMPLEX: + ascii = HersheyScriptSimplex; + break; + case FONT_HERSHEY_SCRIPT_COMPLEX: + ascii = HersheyScriptComplex; + break; + default: + CV_Error( CV_StsOutOfRange, "Unknown font type" ); + } + return ascii; +} + + +void putText( Mat& img, const string& text, Point org, + int fontFace, double fontScale, Scalar color, + int thickness, int line_type, bool bottomLeftOrigin ) + +{ + const int* ascii = getFontData(fontFace); + + double buf[4]; + scalarToRawData(color, buf, img.type(), 0); + + int base_line = -(ascii[0] & 15); + int hscale = cvRound(fontScale*XY_ONE), vscale = hscale; + + if( line_type == CV_AA && img.depth() != CV_8U ) + line_type = 8; + + if( bottomLeftOrigin ) + vscale = -vscale; + + int view_x = org.x << XY_SHIFT; + int view_y = (org.y << XY_SHIFT) + base_line*vscale; + vector pts; + pts.reserve(1 << 10); + const char **faces = cv::g_HersheyGlyphs; + + for( int i = 0; text[i] != '\0'; i++ ) + { + int c = (uchar)text[i]; + Point p; + + if( c >= 127 || c < ' ' ) + c = '?'; + + const char* ptr = faces[ascii[(c-' ')+1]]; + p.x = (uchar)ptr[0] - 'R'; + p.y = (uchar)ptr[1] - 'R'; + int dx = p.y*hscale; + view_x -= p.x*hscale; + pts.resize(0); + + for( ptr += 2;; ) + { + if( *ptr == ' ' || !*ptr ) + { + if( pts.size() > 1 ) + PolyLine( img, &pts[0], (int)pts.size(), false, buf, thickness, line_type, XY_SHIFT ); + if( !*ptr++ ) + break; + pts.resize(0); + } + else + { + p.x = (uchar)ptr[0] - 'R'; + p.y = (uchar)ptr[1] - 'R'; + ptr += 2; + pts.push_back(Point(p.x*hscale + view_x, p.y*vscale + view_y)); + } + } + view_x += dx; + } +} + +Size getTextSize( const string& text, int fontFace, double fontScale, int thickness, int* _base_line) +{ + Size size; + double view_x = 0; + const char **faces = cv::g_HersheyGlyphs; + const int* ascii = getFontData(fontFace); + + int base_line = (ascii[0] & 15); + int cap_line = (ascii[0] >> 4) & 15; + size.height = cvRound((cap_line + base_line)*fontScale + (thickness+1)/2); + + for( int i = 0; text[i] != '\0'; i++ ) + { + int c = (uchar)text[i]; + Point p; + + if( c >= 127 || c < ' ' ) + c = '?'; + + const char* ptr = faces[ascii[(c-' ')+1]]; + p.x = (uchar)ptr[0] - 'R'; + p.y = (uchar)ptr[1] - 'R'; + view_x += (p.y - p.x)*fontScale; + } + + size.width = cvRound(view_x + thickness); + if( _base_line ) + *_base_line = cvRound(base_line*fontScale + thickness*0.5); + return size; +} + +} + + +void cv::fillConvexPoly(InputOutputArray _img, InputArray _points, + const Scalar& color, int lineType, int shift) +{ + Mat img = _img.getMat(), points = _points.getMat(); + CV_Assert(points.checkVector(2, CV_32S) >= 0); + fillConvexPoly(img, (const Point*)points.data, points.rows*points.cols*points.channels()/2, color, lineType, shift); +} + + +void cv::fillPoly(InputOutputArray _img, InputArrayOfArrays pts, + const Scalar& color, int lineType, int shift, Point offset) +{ + Mat img = _img.getMat(); + int i, ncontours = (int)pts.total(); + if( ncontours == 0 ) + return; + AutoBuffer _ptsptr(ncontours); + AutoBuffer _npts(ncontours); + Point** ptsptr = _ptsptr; + int* npts = _npts; + + for( i = 0; i < ncontours; i++ ) + { + Mat p = pts.getMat(i); + CV_Assert(p.checkVector(2, CV_32S) >= 0); + ptsptr[i] = (Point*)p.data; + npts[i] = p.rows*p.cols*p.channels()/2; + } + fillPoly(img, (const Point**)ptsptr, npts, (int)ncontours, color, lineType, shift, offset); +} + + +void cv::polylines(InputOutputArray _img, InputArrayOfArrays pts, + bool isClosed, const Scalar& color, + int thickness, int lineType, int shift ) +{ + Mat img = _img.getMat(); + bool manyContours = pts.kind() == _InputArray::STD_VECTOR_VECTOR || + pts.kind() == _InputArray::STD_VECTOR_MAT; + int i, ncontours = manyContours ? (int)pts.total() : 1; + if( ncontours == 0 ) + return; + AutoBuffer _ptsptr(ncontours); + AutoBuffer _npts(ncontours); + Point** ptsptr = _ptsptr; + int* npts = _npts; + + for( i = 0; i < ncontours; i++ ) + { + Mat p = pts.getMat(manyContours ? i : -1); + if( p.total() == 0 ) + continue; + CV_Assert(p.checkVector(2, CV_32S) >= 0); + ptsptr[i] = (Point*)p.data; + npts[i] = p.rows*p.cols*p.channels()/2; + } + polylines(img, (const Point**)ptsptr, npts, (int)ncontours, isClosed, color, thickness, lineType, shift); +} + +namespace +{ +using namespace cv; + +static void addChildContour(InputArrayOfArrays contours, + size_t ncontours, + const Vec4i* hierarchy, + int i, vector& seq, + vector& block) +{ + for( ; i >= 0; i = hierarchy[i][0] ) + { + Mat ci = contours.getMat(i); + cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point), + !ci.empty() ? (void*)ci.data : 0, (int)ci.total(), + &seq[i], &block[i] ); + + int h_next = hierarchy[i][0], h_prev = hierarchy[i][1], + v_next = hierarchy[i][2], v_prev = hierarchy[i][3]; + seq[i].h_next = (size_t)h_next < ncontours ? &seq[h_next] : 0; + seq[i].h_prev = (size_t)h_prev < ncontours ? &seq[h_prev] : 0; + seq[i].v_next = (size_t)v_next < ncontours ? &seq[v_next] : 0; + seq[i].v_prev = (size_t)v_prev < ncontours ? &seq[v_prev] : 0; + + if( v_next >= 0 ) + addChildContour(contours, ncontours, hierarchy, v_next, seq, block); + } +} +} + +void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours, + int contourIdx, const Scalar& color, int thickness, + int lineType, InputArray _hierarchy, + int maxLevel, Point offset ) +{ + Mat image = _image.getMat(), hierarchy = _hierarchy.getMat(); + CvMat _cimage = image; + + size_t ncontours = _contours.total(); + size_t i = 0, first = 0, last = ncontours; + vector seq; + vector block; + + if( !last ) + return; + + seq.resize(last); + block.resize(last); + + for( i = first; i < last; i++ ) + seq[i].first = 0; + + if( contourIdx >= 0 ) + { + CV_Assert( 0 <= contourIdx && contourIdx < (int)last ); + first = contourIdx; + last = contourIdx + 1; + } + + for( i = first; i < last; i++ ) + { + Mat ci = _contours.getMat((int)i); + if( ci.empty() ) + continue; + int npoints = ci.checkVector(2, CV_32S); + CV_Assert( npoints > 0 ); + cvMakeSeqHeaderForArray( CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point), + ci.data, npoints, &seq[i], &block[i] ); + } + + if( hierarchy.empty() || maxLevel == 0 ) + for( i = first; i < last; i++ ) + { + seq[i].h_next = i < last-1 ? &seq[i+1] : 0; + seq[i].h_prev = i > first ? &seq[i-1] : 0; + } + else + { + size_t count = last - first; + CV_Assert(hierarchy.total() == ncontours && hierarchy.type() == CV_32SC4 ); + const Vec4i* h = hierarchy.ptr(); + + if( count == ncontours ) + { + for( i = first; i < last; i++ ) + { + int h_next = h[i][0], h_prev = h[i][1], + v_next = h[i][2], v_prev = h[i][3]; + seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0; + seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0; + seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0; + seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0; + } + } + else + { + int child = h[first][2]; + if( child >= 0 ) + { + addChildContour(_contours, ncontours, h, child, seq, block); + seq[first].v_next = &seq[child]; + } + } + } + + cvDrawContours( &_cimage, &seq[first], color, color, contourIdx >= 0 ? + -maxLevel : maxLevel, thickness, lineType, offset ); +} + + + +static const int CodeDeltas[8][2] = +{ {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} }; + +#define CV_ADJUST_EDGE_COUNT( count, seq ) \ + ((count) -= ((count) == (seq)->total && !CV_IS_SEQ_CLOSED(seq))) + +CV_IMPL void +cvDrawContours( void* _img, CvSeq* contour, + CvScalar _externalColor, CvScalar _holeColor, + int maxLevel, int thickness, + int line_type, CvPoint _offset ) +{ + CvSeq *contour0 = contour, *h_next = 0; + CvTreeNodeIterator iterator; + cv::vector edges; + cv::vector pts; + cv::Scalar externalColor = _externalColor, holeColor = _holeColor; + cv::Mat img = cv::cvarrToMat(_img); + cv::Point offset = _offset; + double ext_buf[4], hole_buf[4]; + + if( line_type == CV_AA && img.depth() != CV_8U ) + line_type = 8; + + if( !contour ) + return; + + CV_Assert( thickness <= 255 ); + + scalarToRawData( externalColor, ext_buf, img.type(), 0 ); + scalarToRawData( holeColor, hole_buf, img.type(), 0 ); + + maxLevel = MAX(maxLevel, INT_MIN+2); + maxLevel = MIN(maxLevel, INT_MAX-1); + + if( maxLevel < 0 ) + { + h_next = contour->h_next; + contour->h_next = 0; + maxLevel = -maxLevel+1; + } + + cvInitTreeNodeIterator( &iterator, contour, maxLevel ); + while( (contour = (CvSeq*)cvNextTreeNode( &iterator )) != 0 ) + { + CvSeqReader reader; + int i, count = contour->total; + int elem_type = CV_MAT_TYPE(contour->flags); + void* clr = (contour->flags & CV_SEQ_FLAG_HOLE) == 0 ? ext_buf : hole_buf; + + cvStartReadSeq( contour, &reader, 0 ); + if( thickness < 0 ) + pts.resize(0); + + if( CV_IS_SEQ_CHAIN_CONTOUR( contour )) + { + cv::Point pt = ((CvChain*)contour)->origin; + cv::Point prev_pt = pt; + char prev_code = reader.ptr ? reader.ptr[0] : '\0'; + + prev_pt += offset; + + for( i = 0; i < count; i++ ) + { + char code; + CV_READ_SEQ_ELEM( code, reader ); + + assert( (code & ~7) == 0 ); + + if( code != prev_code ) + { + prev_code = code; + if( thickness >= 0 ) + cv::ThickLine( img, prev_pt, pt, clr, thickness, line_type, 2, 0 ); + else + pts.push_back(pt); + prev_pt = pt; + } + + pt.x += CodeDeltas[(int)code][0]; + pt.y += CodeDeltas[(int)code][1]; + } + + if( thickness >= 0 ) + cv::ThickLine( img, prev_pt, + cv::Point(((CvChain*)contour)->origin) + offset, + clr, thickness, line_type, 2, 0 ); + else + cv::CollectPolyEdges(img, &pts[0], (int)pts.size(), + edges, ext_buf, line_type, 0, offset); + } + else if( CV_IS_SEQ_POLYLINE( contour )) + { + CV_Assert( elem_type == CV_32SC2 ); + cv::Point pt1, pt2; + int shift = 0; + + count -= !CV_IS_SEQ_CLOSED(contour); + CV_READ_SEQ_ELEM( pt1, reader ); + pt1 += offset; + if( thickness < 0 ) + pts.push_back(pt1); + + for( i = 0; i < count; i++ ) + { + CV_READ_SEQ_ELEM( pt2, reader ); + pt2 += offset; + if( thickness >= 0 ) + cv::ThickLine( img, pt1, pt2, clr, thickness, line_type, 2, shift ); + else + pts.push_back(pt2); + pt1 = pt2; + } + if( thickness < 0 ) + cv::CollectPolyEdges( img, &pts[0], (int)pts.size(), + edges, ext_buf, line_type, 0, cv::Point() ); + } + } + + if( thickness < 0 ) + cv::FillEdgeCollection( img, edges, ext_buf ); + + if( h_next && contour0 ) + contour0->h_next = h_next; +} + +CV_IMPL int +cvClipLine( CvSize size, CvPoint* pt1, CvPoint* pt2 ) +{ + CV_Assert( pt1 && pt2 ); + return cv::clipLine( size, *(cv::Point*)pt1, *(cv::Point*)pt2 ); +} + + +CV_IMPL int +cvEllipse2Poly( CvPoint center, CvSize axes, int angle, + int arc_start, int arc_end, CvPoint* _pts, int delta ) +{ + cv::vector pts; + cv::ellipse2Poly( center, axes, angle, arc_start, arc_end, delta, pts ); + memcpy( _pts, &pts[0], pts.size()*sizeof(_pts[0]) ); + return (int)pts.size(); +} + +CV_IMPL CvScalar +cvColorToScalar( double packed_color, int type ) +{ + CvScalar scalar; + + if( CV_MAT_DEPTH( type ) == CV_8U ) + { + int icolor = cvRound( packed_color ); + if( CV_MAT_CN( type ) > 1 ) + { + scalar.val[0] = icolor & 255; + scalar.val[1] = (icolor >> 8) & 255; + scalar.val[2] = (icolor >> 16) & 255; + scalar.val[3] = (icolor >> 24) & 255; + } + else + { + scalar.val[0] = CV_CAST_8U( icolor ); + scalar.val[1] = scalar.val[2] = scalar.val[3] = 0; + } + } + else if( CV_MAT_DEPTH( type ) == CV_8S ) + { + int icolor = cvRound( packed_color ); + if( CV_MAT_CN( type ) > 1 ) + { + scalar.val[0] = (char)icolor; + scalar.val[1] = (char)(icolor >> 8); + scalar.val[2] = (char)(icolor >> 16); + scalar.val[3] = (char)(icolor >> 24); + } + else + { + scalar.val[0] = CV_CAST_8S( icolor ); + scalar.val[1] = scalar.val[2] = scalar.val[3] = 0; + } + } + else + { + int cn = CV_MAT_CN( type ); + switch( cn ) + { + case 1: + scalar.val[0] = packed_color; + scalar.val[1] = scalar.val[2] = scalar.val[3] = 0; + break; + case 2: + scalar.val[0] = scalar.val[1] = packed_color; + scalar.val[2] = scalar.val[3] = 0; + break; + case 3: + scalar.val[0] = scalar.val[1] = scalar.val[2] = packed_color; + scalar.val[3] = 0; + break; + default: + scalar.val[0] = scalar.val[1] = + scalar.val[2] = scalar.val[3] = packed_color; + break; + } + } + + return scalar; +} + +CV_IMPL int +cvInitLineIterator( const CvArr* img, CvPoint pt1, CvPoint pt2, + CvLineIterator* iterator, int connectivity, + int left_to_right ) +{ + CV_Assert( iterator != 0 ); + cv::LineIterator li(cv::cvarrToMat(img), pt1, pt2, connectivity, left_to_right!=0); + + iterator->err = li.err; + iterator->minus_delta = li.minusDelta; + iterator->plus_delta = li.plusDelta; + iterator->minus_step = li.minusStep; + iterator->plus_step = li.plusStep; + iterator->ptr = li.ptr; + + return li.count; +} + +CV_IMPL void +cvLine( CvArr* _img, CvPoint pt1, CvPoint pt2, CvScalar color, + int thickness, int line_type, int shift ) +{ + cv::Mat img = cv::cvarrToMat(_img); + cv::line( img, pt1, pt2, color, thickness, line_type, shift ); +} + +CV_IMPL void +cvRectangle( CvArr* _img, CvPoint pt1, CvPoint pt2, + CvScalar color, int thickness, + int line_type, int shift ) +{ + cv::Mat img = cv::cvarrToMat(_img); + cv::rectangle( img, pt1, pt2, color, thickness, line_type, shift ); +} + +CV_IMPL void +cvRectangleR( CvArr* _img, CvRect rec, + CvScalar color, int thickness, + int line_type, int shift ) +{ + cv::Mat img = cv::cvarrToMat(_img); + cv::rectangle( img, rec, color, thickness, line_type, shift ); +} + +CV_IMPL void +cvCircle( CvArr* _img, CvPoint center, int radius, + CvScalar color, int thickness, int line_type, int shift ) +{ + cv::Mat img = cv::cvarrToMat(_img); + cv::circle( img, center, radius, color, thickness, line_type, shift ); +} + +CV_IMPL void +cvEllipse( CvArr* _img, CvPoint center, CvSize axes, + double angle, double start_angle, double end_angle, + CvScalar color, int thickness, int line_type, int shift ) +{ + cv::Mat img = cv::cvarrToMat(_img); + cv::ellipse( img, center, axes, angle, start_angle, end_angle, + color, thickness, line_type, shift ); +} + +CV_IMPL void +cvFillConvexPoly( CvArr* _img, const CvPoint *pts, int npts, + CvScalar color, int line_type, int shift ) +{ + cv::Mat img = cv::cvarrToMat(_img); + cv::fillConvexPoly( img, (const cv::Point*)pts, npts, + color, line_type, shift ); +} + +CV_IMPL void +cvFillPoly( CvArr* _img, CvPoint **pts, const int *npts, int ncontours, + CvScalar color, int line_type, int shift ) +{ + cv::Mat img = cv::cvarrToMat(_img); + + cv::fillPoly( img, (const cv::Point**)pts, npts, ncontours, color, line_type, shift ); +} + +CV_IMPL void +cvPolyLine( CvArr* _img, CvPoint **pts, const int *npts, + int ncontours, int closed, CvScalar color, + int thickness, int line_type, int shift ) +{ + cv::Mat img = cv::cvarrToMat(_img); + + cv::polylines( img, (const cv::Point**)pts, npts, ncontours, + closed != 0, color, thickness, line_type, shift ); +} + +CV_IMPL void +cvPutText( CvArr* _img, const char *text, CvPoint org, const CvFont *_font, CvScalar color ) +{ + cv::Mat img = cv::cvarrToMat(_img); + CV_Assert( text != 0 && _font != 0); + cv::putText( img, text, org, _font->font_face, (_font->hscale+_font->vscale)*0.5, + color, _font->thickness, _font->line_type, + CV_IS_IMAGE(_img) && ((IplImage*)_img)->origin != 0 ); +} + + +CV_IMPL void +cvInitFont( CvFont *font, int font_face, double hscale, double vscale, + double shear, int thickness, int line_type ) +{ + CV_Assert( font != 0 && hscale > 0 && vscale > 0 && thickness >= 0 ); + + font->ascii = cv::getFontData(font_face); + font->font_face = font_face; + font->hscale = (float)hscale; + font->vscale = (float)vscale; + font->thickness = thickness; + font->shear = (float)shear; + font->greek = font->cyrillic = 0; + font->line_type = line_type; +} + +CV_IMPL void +cvGetTextSize( const char *text, const CvFont *_font, CvSize *_size, int *_base_line ) +{ + CV_Assert(text != 0 && _font != 0); + cv::Size size = cv::getTextSize( text, _font->font_face, (_font->hscale + _font->vscale)*0.5, + _font->thickness, _base_line ); + if( _size ) + *_size = size; +} + +/* End of file. */ diff --git a/core/src/dxt.cpp b/core/src/dxt.cpp new file mode 100644 index 0000000..04e9010 --- /dev/null +++ b/core/src/dxt.cpp @@ -0,0 +1,2639 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +namespace cv +{ + +// On Win64 optimized versions of DFT and DCT fail the tests (fixed in VS2010) +#if defined _MSC_VER && !defined CV_ICC && defined _M_X64 && _MSC_VER < 1600 +# pragma optimize("", off) +# pragma warning(disable: 4748) +#endif + +/****************************************************************************************\ + Discrete Fourier Transform +\****************************************************************************************/ + +#define CV_MAX_LOCAL_DFT_SIZE (1 << 15) + +static unsigned char bitrevTab[] = +{ + 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, + 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, + 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, + 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, + 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, + 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, + 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, + 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, + 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, + 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, + 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, + 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, + 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, + 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, + 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, + 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff +}; + +static const double DFTTab[][2] = +{ +{ 1.00000000000000000, 0.00000000000000000 }, +{-1.00000000000000000, 0.00000000000000000 }, +{ 0.00000000000000000, 1.00000000000000000 }, +{ 0.70710678118654757, 0.70710678118654746 }, +{ 0.92387953251128674, 0.38268343236508978 }, +{ 0.98078528040323043, 0.19509032201612825 }, +{ 0.99518472667219693, 0.09801714032956060 }, +{ 0.99879545620517241, 0.04906767432741802 }, +{ 0.99969881869620425, 0.02454122852291229 }, +{ 0.99992470183914450, 0.01227153828571993 }, +{ 0.99998117528260111, 0.00613588464915448 }, +{ 0.99999529380957619, 0.00306795676296598 }, +{ 0.99999882345170188, 0.00153398018628477 }, +{ 0.99999970586288223, 0.00076699031874270 }, +{ 0.99999992646571789, 0.00038349518757140 }, +{ 0.99999998161642933, 0.00019174759731070 }, +{ 0.99999999540410733, 0.00009587379909598 }, +{ 0.99999999885102686, 0.00004793689960307 }, +{ 0.99999999971275666, 0.00002396844980842 }, +{ 0.99999999992818922, 0.00001198422490507 }, +{ 0.99999999998204725, 0.00000599211245264 }, +{ 0.99999999999551181, 0.00000299605622633 }, +{ 0.99999999999887801, 0.00000149802811317 }, +{ 0.99999999999971945, 0.00000074901405658 }, +{ 0.99999999999992983, 0.00000037450702829 }, +{ 0.99999999999998246, 0.00000018725351415 }, +{ 0.99999999999999567, 0.00000009362675707 }, +{ 0.99999999999999889, 0.00000004681337854 }, +{ 0.99999999999999978, 0.00000002340668927 }, +{ 0.99999999999999989, 0.00000001170334463 }, +{ 1.00000000000000000, 0.00000000585167232 }, +{ 1.00000000000000000, 0.00000000292583616 } +}; + +#define BitRev(i,shift) \ + ((int)((((unsigned)bitrevTab[(i)&255] << 24)+ \ + ((unsigned)bitrevTab[((i)>> 8)&255] << 16)+ \ + ((unsigned)bitrevTab[((i)>>16)&255] << 8)+ \ + ((unsigned)bitrevTab[((i)>>24)])) >> (shift))) + +static int +DFTFactorize( int n, int* factors ) +{ + int nf = 0, f, i, j; + + if( n <= 5 ) + { + factors[0] = n; + return 1; + } + + f = (((n - 1)^n)+1) >> 1; + if( f > 1 ) + { + factors[nf++] = f; + n = f == n ? 1 : n/f; + } + + for( f = 3; n > 1; ) + { + int d = n/f; + if( d*f == n ) + { + factors[nf++] = f; + n = d; + } + else + { + f += 2; + if( f*f > n ) + break; + } + } + + if( n > 1 ) + factors[nf++] = n; + + f = (factors[0] & 1) == 0; + for( i = f; i < (nf+f)/2; i++ ) + CV_SWAP( factors[i], factors[nf-i-1+f], j ); + + return nf; +} + +static void +DFTInit( int n0, int nf, int* factors, int* itab, int elem_size, void* _wave, int inv_itab ) +{ + int digits[34], radix[34]; + int n = factors[0], m = 0; + int* itab0 = itab; + int i, j, k; + Complex w, w1; + double t; + + if( n0 <= 5 ) + { + itab[0] = 0; + itab[n0-1] = n0-1; + + if( n0 != 4 ) + { + for( i = 1; i < n0-1; i++ ) + itab[i] = i; + } + else + { + itab[1] = 2; + itab[2] = 1; + } + if( n0 == 5 ) + { + if( elem_size == sizeof(Complex) ) + ((Complex*)_wave)[0] = Complex(1.,0.); + else + ((Complex*)_wave)[0] = Complex(1.f,0.f); + } + if( n0 != 4 ) + return; + m = 2; + } + else + { + // radix[] is initialized from index 'nf' down to zero + assert (nf < 34); + radix[nf] = 1; + digits[nf] = 0; + for( i = 0; i < nf; i++ ) + { + digits[i] = 0; + radix[nf-i-1] = radix[nf-i]*factors[nf-i-1]; + } + + if( inv_itab && factors[0] != factors[nf-1] ) + itab = (int*)_wave; + + if( (n & 1) == 0 ) + { + int a = radix[1], na2 = n*a>>1, na4 = na2 >> 1; + for( m = 0; (unsigned)(1 << m) < (unsigned)n; m++ ) + ; + if( n <= 2 ) + { + itab[0] = 0; + itab[1] = na2; + } + else if( n <= 256 ) + { + int shift = 10 - m; + for( i = 0; i <= n - 4; i += 4 ) + { + j = (bitrevTab[i>>2]>>shift)*a; + itab[i] = j; + itab[i+1] = j + na2; + itab[i+2] = j + na4; + itab[i+3] = j + na2 + na4; + } + } + else + { + int shift = 34 - m; + for( i = 0; i < n; i += 4 ) + { + int i4 = i >> 2; + j = BitRev(i4,shift)*a; + itab[i] = j; + itab[i+1] = j + na2; + itab[i+2] = j + na4; + itab[i+3] = j + na2 + na4; + } + } + + digits[1]++; + + if( nf >= 2 ) + { + for( i = n, j = radix[2]; i < n0; ) + { + for( k = 0; k < n; k++ ) + itab[i+k] = itab[k] + j; + if( (i += n) >= n0 ) + break; + j += radix[2]; + for( k = 1; ++digits[k] >= factors[k]; k++ ) + { + digits[k] = 0; + j += radix[k+2] - radix[k]; + } + } + } + } + else + { + for( i = 0, j = 0;; ) + { + itab[i] = j; + if( ++i >= n0 ) + break; + j += radix[1]; + for( k = 0; ++digits[k] >= factors[k]; k++ ) + { + digits[k] = 0; + j += radix[k+2] - radix[k]; + } + } + } + + if( itab != itab0 ) + { + itab0[0] = 0; + for( i = n0 & 1; i < n0; i += 2 ) + { + int k0 = itab[i]; + int k1 = itab[i+1]; + itab0[k0] = i; + itab0[k1] = i+1; + } + } + } + + if( (n0 & (n0-1)) == 0 ) + { + w.re = w1.re = DFTTab[m][0]; + w.im = w1.im = -DFTTab[m][1]; + } + else + { + t = -CV_PI*2/n0; + w.im = w1.im = sin(t); + w.re = w1.re = std::sqrt(1. - w1.im*w1.im); + } + n = (n0+1)/2; + + if( elem_size == sizeof(Complex) ) + { + Complex* wave = (Complex*)_wave; + + wave[0].re = 1.; + wave[0].im = 0.; + + if( (n0 & 1) == 0 ) + { + wave[n].re = -1.; + wave[n].im = 0; + } + + for( i = 1; i < n; i++ ) + { + wave[i] = w; + wave[n0-i].re = w.re; + wave[n0-i].im = -w.im; + + t = w.re*w1.re - w.im*w1.im; + w.im = w.re*w1.im + w.im*w1.re; + w.re = t; + } + } + else + { + Complex* wave = (Complex*)_wave; + assert( elem_size == sizeof(Complex) ); + + wave[0].re = 1.f; + wave[0].im = 0.f; + + if( (n0 & 1) == 0 ) + { + wave[n].re = -1.f; + wave[n].im = 0.f; + } + + for( i = 1; i < n; i++ ) + { + wave[i].re = (float)w.re; + wave[i].im = (float)w.im; + wave[n0-i].re = (float)w.re; + wave[n0-i].im = (float)-w.im; + + t = w.re*w1.re - w.im*w1.im; + w.im = w.re*w1.im + w.im*w1.re; + w.re = t; + } + } +} + +template struct DFT_VecR4 +{ + int operator()(Complex*, int, int, int&, const Complex*) const { return 1; } +}; + +#if CV_SSE3 + +// optimized radix-4 transform +template<> struct DFT_VecR4 +{ + int operator()(Complex* dst, int N, int n0, int& _dw0, const Complex* wave) const + { + int n = 1, i, j, nx, dw, dw0 = _dw0; + __m128 z = _mm_setzero_ps(), x02=z, x13=z, w01=z, w23=z, y01, y23, t0, t1; + Cv32suf t; t.i = 0x80000000; + __m128 neg0_mask = _mm_load_ss(&t.f); + __m128 neg3_mask = _mm_shuffle_ps(neg0_mask, neg0_mask, _MM_SHUFFLE(0,1,2,3)); + + for( ; n*4 <= N; ) + { + nx = n; + n *= 4; + dw0 /= 4; + + for( i = 0; i < n0; i += n ) + { + Complexf *v0, *v1; + + v0 = dst + i; + v1 = v0 + nx*2; + + x02 = _mm_loadl_pi(x02, (const __m64*)&v0[0]); + x13 = _mm_loadl_pi(x13, (const __m64*)&v0[nx]); + x02 = _mm_loadh_pi(x02, (const __m64*)&v1[0]); + x13 = _mm_loadh_pi(x13, (const __m64*)&v1[nx]); + + y01 = _mm_add_ps(x02, x13); + y23 = _mm_sub_ps(x02, x13); + t1 = _mm_xor_ps(_mm_shuffle_ps(y01, y23, _MM_SHUFFLE(2,3,3,2)), neg3_mask); + t0 = _mm_movelh_ps(y01, y23); + y01 = _mm_add_ps(t0, t1); + y23 = _mm_sub_ps(t0, t1); + + _mm_storel_pi((__m64*)&v0[0], y01); + _mm_storeh_pi((__m64*)&v0[nx], y01); + _mm_storel_pi((__m64*)&v1[0], y23); + _mm_storeh_pi((__m64*)&v1[nx], y23); + + for( j = 1, dw = dw0; j < nx; j++, dw += dw0 ) + { + v0 = dst + i + j; + v1 = v0 + nx*2; + + x13 = _mm_loadl_pi(x13, (const __m64*)&v0[nx]); + w23 = _mm_loadl_pi(w23, (const __m64*)&wave[dw*2]); + x13 = _mm_loadh_pi(x13, (const __m64*)&v1[nx]); // x1, x3 = r1 i1 r3 i3 + w23 = _mm_loadh_pi(w23, (const __m64*)&wave[dw*3]); // w2, w3 = wr2 wi2 wr3 wi3 + + t0 = _mm_mul_ps(_mm_moveldup_ps(x13), w23); + t1 = _mm_mul_ps(_mm_movehdup_ps(x13), _mm_shuffle_ps(w23, w23, _MM_SHUFFLE(2,3,0,1))); + x13 = _mm_addsub_ps(t0, t1); + // re(x1*w2), im(x1*w2), re(x3*w3), im(x3*w3) + x02 = _mm_loadl_pi(x02, (const __m64*)&v1[0]); // x2 = r2 i2 + w01 = _mm_loadl_pi(w01, (const __m64*)&wave[dw]); // w1 = wr1 wi1 + x02 = _mm_shuffle_ps(x02, x02, _MM_SHUFFLE(0,0,1,1)); + w01 = _mm_shuffle_ps(w01, w01, _MM_SHUFFLE(1,0,0,1)); + x02 = _mm_mul_ps(x02, w01); + x02 = _mm_addsub_ps(x02, _mm_movelh_ps(x02, x02)); + // re(x0) im(x0) re(x2*w1), im(x2*w1) + x02 = _mm_loadl_pi(x02, (const __m64*)&v0[0]); + + y01 = _mm_add_ps(x02, x13); + y23 = _mm_sub_ps(x02, x13); + t1 = _mm_xor_ps(_mm_shuffle_ps(y01, y23, _MM_SHUFFLE(2,3,3,2)), neg3_mask); + t0 = _mm_movelh_ps(y01, y23); + y01 = _mm_add_ps(t0, t1); + y23 = _mm_sub_ps(t0, t1); + + _mm_storel_pi((__m64*)&v0[0], y01); + _mm_storeh_pi((__m64*)&v0[nx], y01); + _mm_storel_pi((__m64*)&v1[0], y23); + _mm_storeh_pi((__m64*)&v1[nx], y23); + } + } + } + + _dw0 = dw0; + return n; + } +}; + +#endif + +#ifdef HAVE_IPP +static void ippsDFTFwd_CToC( const Complex* src, Complex* dst, + const void* spec, uchar* buf) +{ + ippsDFTFwd_CToC_32fc( (const Ipp32fc*)src, (Ipp32fc*)dst, + (const IppsDFTSpec_C_32fc*)spec, buf); +} + +static void ippsDFTFwd_CToC( const Complex* src, Complex* dst, + const void* spec, uchar* buf) +{ + ippsDFTFwd_CToC_64fc( (const Ipp64fc*)src, (Ipp64fc*)dst, + (const IppsDFTSpec_C_64fc*)spec, buf); +} + +static void ippsDFTInv_CToC( const Complex* src, Complex* dst, + const void* spec, uchar* buf) +{ + ippsDFTInv_CToC_32fc( (const Ipp32fc*)src, (Ipp32fc*)dst, + (const IppsDFTSpec_C_32fc*)spec, buf); +} + +static void ippsDFTInv_CToC( const Complex* src, Complex* dst, + const void* spec, uchar* buf) +{ + ippsDFTInv_CToC_64fc( (const Ipp64fc*)src, (Ipp64fc*)dst, + (const IppsDFTSpec_C_64fc*)spec, buf); +} + +static void ippsDFTFwd_RToPack( const float* src, float* dst, + const void* spec, uchar* buf) +{ + ippsDFTFwd_RToPack_32f( src, dst, (const IppsDFTSpec_R_32f*)spec, buf); +} + +static void ippsDFTFwd_RToPack( const double* src, double* dst, + const void* spec, uchar* buf) +{ + ippsDFTFwd_RToPack_64f( src, dst, (const IppsDFTSpec_R_64f*)spec, buf); +} + +static void ippsDFTInv_PackToR( const float* src, float* dst, + const void* spec, uchar* buf) +{ + ippsDFTInv_PackToR_32f( src, dst, (const IppsDFTSpec_R_32f*)spec, buf); +} + +static void ippsDFTInv_PackToR( const double* src, double* dst, + const void* spec, uchar* buf) +{ + ippsDFTInv_PackToR_64f( src, dst, (const IppsDFTSpec_R_64f*)spec, buf); +} +#endif + +enum { DFT_NO_PERMUTE=256, DFT_COMPLEX_INPUT_OR_OUTPUT=512 }; + +// mixed-radix complex discrete Fourier transform: double-precision version +template static void +DFT( const Complex* src, Complex* dst, int n, + int nf, const int* factors, const int* itab, + const Complex* wave, int tab_size, + const void* +#ifdef HAVE_IPP + spec +#endif + , Complex* buf, + int flags, double _scale ) +{ + static const T sin_120 = (T)0.86602540378443864676372317075294; + static const T fft5_2 = (T)0.559016994374947424102293417182819; + static const T fft5_3 = (T)-0.951056516295153572116439333379382; + static const T fft5_4 = (T)-1.538841768587626701285145288018455; + static const T fft5_5 = (T)0.363271264002680442947733378740309; + + int n0 = n, f_idx, nx; + int inv = flags & DFT_INVERSE; + int dw0 = tab_size, dw; + int i, j, k; + Complex t; + T scale = (T)_scale; + int tab_step; + +#ifdef HAVE_IPP + if( spec ) + { + if( !inv ) + ippsDFTFwd_CToC( src, dst, spec, (uchar*)buf ); + else + ippsDFTInv_CToC( src, dst, spec, (uchar*)buf ); + return; + } +#endif + + tab_step = tab_size == n ? 1 : tab_size == n*2 ? 2 : tab_size/n; + + // 0. shuffle data + if( dst != src ) + { + assert( (flags & DFT_NO_PERMUTE) == 0 ); + if( !inv ) + { + for( i = 0; i <= n - 2; i += 2, itab += 2*tab_step ) + { + int k0 = itab[0], k1 = itab[tab_step]; + assert( (unsigned)k0 < (unsigned)n && (unsigned)k1 < (unsigned)n ); + dst[i] = src[k0]; dst[i+1] = src[k1]; + } + + if( i < n ) + dst[n-1] = src[n-1]; + } + else + { + for( i = 0; i <= n - 2; i += 2, itab += 2*tab_step ) + { + int k0 = itab[0], k1 = itab[tab_step]; + assert( (unsigned)k0 < (unsigned)n && (unsigned)k1 < (unsigned)n ); + t.re = src[k0].re; t.im = -src[k0].im; + dst[i] = t; + t.re = src[k1].re; t.im = -src[k1].im; + dst[i+1] = t; + } + + if( i < n ) + { + t.re = src[n-1].re; t.im = -src[n-1].im; + dst[i] = t; + } + } + } + else + { + if( (flags & DFT_NO_PERMUTE) == 0 ) + { + CV_Assert( factors[0] == factors[nf-1] ); + if( nf == 1 ) + { + if( (n & 3) == 0 ) + { + int n2 = n/2; + Complex* dsth = dst + n2; + + for( i = 0; i < n2; i += 2, itab += tab_step*2 ) + { + j = itab[0]; + assert( (unsigned)j < (unsigned)n2 ); + + CV_SWAP(dst[i+1], dsth[j], t); + if( j > i ) + { + CV_SWAP(dst[i], dst[j], t); + CV_SWAP(dsth[i+1], dsth[j+1], t); + } + } + } + // else do nothing + } + else + { + for( i = 0; i < n; i++, itab += tab_step ) + { + j = itab[0]; + assert( (unsigned)j < (unsigned)n ); + if( j > i ) + CV_SWAP(dst[i], dst[j], t); + } + } + } + + if( inv ) + { + for( i = 0; i <= n - 2; i += 2 ) + { + T t0 = -dst[i].im; + T t1 = -dst[i+1].im; + dst[i].im = t0; dst[i+1].im = t1; + } + + if( i < n ) + dst[n-1].im = -dst[n-1].im; + } + } + + n = 1; + // 1. power-2 transforms + if( (factors[0] & 1) == 0 ) + { + if( factors[0] >= 4 && checkHardwareSupport(CV_CPU_SSE3)) + { + DFT_VecR4 vr4; + n = vr4(dst, factors[0], n0, dw0, wave); + } + + // radix-4 transform + for( ; n*4 <= factors[0]; ) + { + nx = n; + n *= 4; + dw0 /= 4; + + for( i = 0; i < n0; i += n ) + { + Complex *v0, *v1; + T r0, i0, r1, i1, r2, i2, r3, i3, r4, i4; + + v0 = dst + i; + v1 = v0 + nx*2; + + r0 = v1[0].re; i0 = v1[0].im; + r4 = v1[nx].re; i4 = v1[nx].im; + + r1 = r0 + r4; i1 = i0 + i4; + r3 = i0 - i4; i3 = r4 - r0; + + r2 = v0[0].re; i2 = v0[0].im; + r4 = v0[nx].re; i4 = v0[nx].im; + + r0 = r2 + r4; i0 = i2 + i4; + r2 -= r4; i2 -= i4; + + v0[0].re = r0 + r1; v0[0].im = i0 + i1; + v1[0].re = r0 - r1; v1[0].im = i0 - i1; + v0[nx].re = r2 + r3; v0[nx].im = i2 + i3; + v1[nx].re = r2 - r3; v1[nx].im = i2 - i3; + + for( j = 1, dw = dw0; j < nx; j++, dw += dw0 ) + { + v0 = dst + i + j; + v1 = v0 + nx*2; + + r2 = v0[nx].re*wave[dw*2].re - v0[nx].im*wave[dw*2].im; + i2 = v0[nx].re*wave[dw*2].im + v0[nx].im*wave[dw*2].re; + r0 = v1[0].re*wave[dw].im + v1[0].im*wave[dw].re; + i0 = v1[0].re*wave[dw].re - v1[0].im*wave[dw].im; + r3 = v1[nx].re*wave[dw*3].im + v1[nx].im*wave[dw*3].re; + i3 = v1[nx].re*wave[dw*3].re - v1[nx].im*wave[dw*3].im; + + r1 = i0 + i3; i1 = r0 + r3; + r3 = r0 - r3; i3 = i3 - i0; + r4 = v0[0].re; i4 = v0[0].im; + + r0 = r4 + r2; i0 = i4 + i2; + r2 = r4 - r2; i2 = i4 - i2; + + v0[0].re = r0 + r1; v0[0].im = i0 + i1; + v1[0].re = r0 - r1; v1[0].im = i0 - i1; + v0[nx].re = r2 + r3; v0[nx].im = i2 + i3; + v1[nx].re = r2 - r3; v1[nx].im = i2 - i3; + } + } + } + + for( ; n < factors[0]; ) + { + // do the remaining radix-2 transform + nx = n; + n *= 2; + dw0 /= 2; + + for( i = 0; i < n0; i += n ) + { + Complex* v = dst + i; + T r0 = v[0].re + v[nx].re; + T i0 = v[0].im + v[nx].im; + T r1 = v[0].re - v[nx].re; + T i1 = v[0].im - v[nx].im; + v[0].re = r0; v[0].im = i0; + v[nx].re = r1; v[nx].im = i1; + + for( j = 1, dw = dw0; j < nx; j++, dw += dw0 ) + { + v = dst + i + j; + r1 = v[nx].re*wave[dw].re - v[nx].im*wave[dw].im; + i1 = v[nx].im*wave[dw].re + v[nx].re*wave[dw].im; + r0 = v[0].re; i0 = v[0].im; + + v[0].re = r0 + r1; v[0].im = i0 + i1; + v[nx].re = r0 - r1; v[nx].im = i0 - i1; + } + } + } + } + + // 2. all the other transforms + for( f_idx = (factors[0]&1) ? 0 : 1; f_idx < nf; f_idx++ ) + { + int factor = factors[f_idx]; + nx = n; + n *= factor; + dw0 /= factor; + + if( factor == 3 ) + { + // radix-3 + for( i = 0; i < n0; i += n ) + { + Complex* v = dst + i; + + T r1 = v[nx].re + v[nx*2].re; + T i1 = v[nx].im + v[nx*2].im; + T r0 = v[0].re; + T i0 = v[0].im; + T r2 = sin_120*(v[nx].im - v[nx*2].im); + T i2 = sin_120*(v[nx*2].re - v[nx].re); + v[0].re = r0 + r1; v[0].im = i0 + i1; + r0 -= (T)0.5*r1; i0 -= (T)0.5*i1; + v[nx].re = r0 + r2; v[nx].im = i0 + i2; + v[nx*2].re = r0 - r2; v[nx*2].im = i0 - i2; + + for( j = 1, dw = dw0; j < nx; j++, dw += dw0 ) + { + v = dst + i + j; + r0 = v[nx].re*wave[dw].re - v[nx].im*wave[dw].im; + i0 = v[nx].re*wave[dw].im + v[nx].im*wave[dw].re; + i2 = v[nx*2].re*wave[dw*2].re - v[nx*2].im*wave[dw*2].im; + r2 = v[nx*2].re*wave[dw*2].im + v[nx*2].im*wave[dw*2].re; + r1 = r0 + i2; i1 = i0 + r2; + + r2 = sin_120*(i0 - r2); i2 = sin_120*(i2 - r0); + r0 = v[0].re; i0 = v[0].im; + v[0].re = r0 + r1; v[0].im = i0 + i1; + r0 -= (T)0.5*r1; i0 -= (T)0.5*i1; + v[nx].re = r0 + r2; v[nx].im = i0 + i2; + v[nx*2].re = r0 - r2; v[nx*2].im = i0 - i2; + } + } + } + else if( factor == 5 ) + { + // radix-5 + for( i = 0; i < n0; i += n ) + { + for( j = 0, dw = 0; j < nx; j++, dw += dw0 ) + { + Complex* v0 = dst + i + j; + Complex* v1 = v0 + nx*2; + Complex* v2 = v1 + nx*2; + + T r0, i0, r1, i1, r2, i2, r3, i3, r4, i4, r5, i5; + + r3 = v0[nx].re*wave[dw].re - v0[nx].im*wave[dw].im; + i3 = v0[nx].re*wave[dw].im + v0[nx].im*wave[dw].re; + r2 = v2[0].re*wave[dw*4].re - v2[0].im*wave[dw*4].im; + i2 = v2[0].re*wave[dw*4].im + v2[0].im*wave[dw*4].re; + + r1 = r3 + r2; i1 = i3 + i2; + r3 -= r2; i3 -= i2; + + r4 = v1[nx].re*wave[dw*3].re - v1[nx].im*wave[dw*3].im; + i4 = v1[nx].re*wave[dw*3].im + v1[nx].im*wave[dw*3].re; + r0 = v1[0].re*wave[dw*2].re - v1[0].im*wave[dw*2].im; + i0 = v1[0].re*wave[dw*2].im + v1[0].im*wave[dw*2].re; + + r2 = r4 + r0; i2 = i4 + i0; + r4 -= r0; i4 -= i0; + + r0 = v0[0].re; i0 = v0[0].im; + r5 = r1 + r2; i5 = i1 + i2; + + v0[0].re = r0 + r5; v0[0].im = i0 + i5; + + r0 -= (T)0.25*r5; i0 -= (T)0.25*i5; + r1 = fft5_2*(r1 - r2); i1 = fft5_2*(i1 - i2); + r2 = -fft5_3*(i3 + i4); i2 = fft5_3*(r3 + r4); + + i3 *= -fft5_5; r3 *= fft5_5; + i4 *= -fft5_4; r4 *= fft5_4; + + r5 = r2 + i3; i5 = i2 + r3; + r2 -= i4; i2 -= r4; + + r3 = r0 + r1; i3 = i0 + i1; + r0 -= r1; i0 -= i1; + + v0[nx].re = r3 + r2; v0[nx].im = i3 + i2; + v2[0].re = r3 - r2; v2[0].im = i3 - i2; + + v1[0].re = r0 + r5; v1[0].im = i0 + i5; + v1[nx].re = r0 - r5; v1[nx].im = i0 - i5; + } + } + } + else + { + // radix-"factor" - an odd number + int p, q, factor2 = (factor - 1)/2; + int d, dd, dw_f = tab_size/factor; + Complex* a = buf; + Complex* b = buf + factor2; + + for( i = 0; i < n0; i += n ) + { + for( j = 0, dw = 0; j < nx; j++, dw += dw0 ) + { + Complex* v = dst + i + j; + Complex v_0 = v[0]; + Complex vn_0 = v_0; + + if( j == 0 ) + { + for( p = 1, k = nx; p <= factor2; p++, k += nx ) + { + T r0 = v[k].re + v[n-k].re; + T i0 = v[k].im - v[n-k].im; + T r1 = v[k].re - v[n-k].re; + T i1 = v[k].im + v[n-k].im; + + vn_0.re += r0; vn_0.im += i1; + a[p-1].re = r0; a[p-1].im = i0; + b[p-1].re = r1; b[p-1].im = i1; + } + } + else + { + const Complex* wave_ = wave + dw*factor; + d = dw; + + for( p = 1, k = nx; p <= factor2; p++, k += nx, d += dw ) + { + T r2 = v[k].re*wave[d].re - v[k].im*wave[d].im; + T i2 = v[k].re*wave[d].im + v[k].im*wave[d].re; + + T r1 = v[n-k].re*wave_[-d].re - v[n-k].im*wave_[-d].im; + T i1 = v[n-k].re*wave_[-d].im + v[n-k].im*wave_[-d].re; + + T r0 = r2 + r1; + T i0 = i2 - i1; + r1 = r2 - r1; + i1 = i2 + i1; + + vn_0.re += r0; vn_0.im += i1; + a[p-1].re = r0; a[p-1].im = i0; + b[p-1].re = r1; b[p-1].im = i1; + } + } + + v[0] = vn_0; + + for( p = 1, k = nx; p <= factor2; p++, k += nx ) + { + Complex s0 = v_0, s1 = v_0; + d = dd = dw_f*p; + + for( q = 0; q < factor2; q++ ) + { + T r0 = wave[d].re * a[q].re; + T i0 = wave[d].im * a[q].im; + T r1 = wave[d].re * b[q].im; + T i1 = wave[d].im * b[q].re; + + s1.re += r0 + i0; s0.re += r0 - i0; + s1.im += r1 - i1; s0.im += r1 + i1; + + d += dd; + d -= -(d >= tab_size) & tab_size; + } + + v[k] = s0; + v[n-k] = s1; + } + } + } + } + } + + if( scale != 1 ) + { + T re_scale = scale, im_scale = scale; + if( inv ) + im_scale = -im_scale; + + for( i = 0; i < n0; i++ ) + { + T t0 = dst[i].re*re_scale; + T t1 = dst[i].im*im_scale; + dst[i].re = t0; + dst[i].im = t1; + } + } + else if( inv ) + { + for( i = 0; i <= n0 - 2; i += 2 ) + { + T t0 = -dst[i].im; + T t1 = -dst[i+1].im; + dst[i].im = t0; + dst[i+1].im = t1; + } + + if( i < n0 ) + dst[n0-1].im = -dst[n0-1].im; + } +} + + +/* FFT of real vector + output vector format: + re(0), re(1), im(1), ... , re(n/2-1), im((n+1)/2-1) [, re((n+1)/2)] OR ... + re(0), 0, re(1), im(1), ..., re(n/2-1), im((n+1)/2-1) [, re((n+1)/2), 0] */ +template static void +RealDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab, + const Complex* wave, int tab_size, const void* +#ifdef HAVE_IPP + spec +#endif + , + Complex* buf, int flags, double _scale ) +{ + int complex_output = (flags & DFT_COMPLEX_INPUT_OR_OUTPUT) != 0; + T scale = (T)_scale; + int j, n2 = n >> 1; + dst += complex_output; + +#ifdef HAVE_IPP + if( spec ) + { + ippsDFTFwd_RToPack( src, dst, spec, (uchar*)buf ); + goto finalize; + } +#endif + assert( tab_size == n ); + + if( n == 1 ) + { + dst[0] = src[0]*scale; + } + else if( n == 2 ) + { + T t = (src[0] + src[1])*scale; + dst[1] = (src[0] - src[1])*scale; + dst[0] = t; + } + else if( n & 1 ) + { + dst -= complex_output; + Complex* _dst = (Complex*)dst; + _dst[0].re = src[0]*scale; + _dst[0].im = 0; + for( j = 1; j < n; j += 2 ) + { + T t0 = src[itab[j]]*scale; + T t1 = src[itab[j+1]]*scale; + _dst[j].re = t0; + _dst[j].im = 0; + _dst[j+1].re = t1; + _dst[j+1].im = 0; + } + DFT( _dst, _dst, n, nf, factors, itab, wave, + tab_size, 0, buf, DFT_NO_PERMUTE, 1 ); + if( !complex_output ) + dst[1] = dst[0]; + } + else + { + T t0, t; + T h1_re, h1_im, h2_re, h2_im; + T scale2 = scale*(T)0.5; + factors[0] >>= 1; + + DFT( (Complex*)src, (Complex*)dst, n2, nf - (factors[0] == 1), + factors + (factors[0] == 1), + itab, wave, tab_size, 0, buf, 0, 1 ); + factors[0] <<= 1; + + t = dst[0] - dst[1]; + dst[0] = (dst[0] + dst[1])*scale; + dst[1] = t*scale; + + t0 = dst[n2]; + t = dst[n-1]; + dst[n-1] = dst[1]; + + for( j = 2, wave++; j < n2; j += 2, wave++ ) + { + /* calc odd */ + h2_re = scale2*(dst[j+1] + t); + h2_im = scale2*(dst[n-j] - dst[j]); + + /* calc even */ + h1_re = scale2*(dst[j] + dst[n-j]); + h1_im = scale2*(dst[j+1] - t); + + /* rotate */ + t = h2_re*wave->re - h2_im*wave->im; + h2_im = h2_re*wave->im + h2_im*wave->re; + h2_re = t; + t = dst[n-j-1]; + + dst[j-1] = h1_re + h2_re; + dst[n-j-1] = h1_re - h2_re; + dst[j] = h1_im + h2_im; + dst[n-j] = h2_im - h1_im; + } + + if( j <= n2 ) + { + dst[n2-1] = t0*scale; + dst[n2] = -t*scale; + } + } + +#ifdef HAVE_IPP +finalize: +#endif + if( complex_output && (n & 1) == 0 ) + { + dst[-1] = dst[0]; + dst[0] = 0; + if( (n & 1) == 0 ) + dst[n] = 0; + } +} + +/* Inverse FFT of complex conjugate-symmetric vector + input vector format: + re[0], re[1], im[1], ... , re[n/2-1], im[n/2-1], re[n/2] OR + re(0), 0, re(1), im(1), ..., re(n/2-1), im((n+1)/2-1) [, re((n+1)/2), 0] */ +template static void +CCSIDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab, + const Complex* wave, int tab_size, + const void* +#ifdef HAVE_IPP + spec +#endif + , Complex* buf, + int flags, double _scale ) +{ + int complex_input = (flags & DFT_COMPLEX_INPUT_OR_OUTPUT) != 0; + int j, k, n2 = (n+1) >> 1; + T scale = (T)_scale; + T save_s1 = 0.; + T t0, t1, t2, t3, t; + + assert( tab_size == n ); + + if( complex_input ) + { + assert( src != dst ); + save_s1 = src[1]; + ((T*)src)[1] = src[0]; + src++; + } +#ifdef HAVE_IPP + if( spec ) + { + ippsDFTInv_PackToR( src, dst, spec, (uchar*)buf ); + goto finalize; + } +#endif + if( n == 1 ) + { + dst[0] = (T)(src[0]*scale); + } + else if( n == 2 ) + { + t = (src[0] + src[1])*scale; + dst[1] = (src[0] - src[1])*scale; + dst[0] = t; + } + else if( n & 1 ) + { + Complex* _src = (Complex*)(src-1); + Complex* _dst = (Complex*)dst; + + _dst[0].re = src[0]; + _dst[0].im = 0; + for( j = 1; j < n2; j++ ) + { + int k0 = itab[j], k1 = itab[n-j]; + t0 = _src[j].re; t1 = _src[j].im; + _dst[k0].re = t0; _dst[k0].im = -t1; + _dst[k1].re = t0; _dst[k1].im = t1; + } + + DFT( _dst, _dst, n, nf, factors, itab, wave, + tab_size, 0, buf, DFT_NO_PERMUTE, 1. ); + dst[0] *= scale; + for( j = 1; j < n; j += 2 ) + { + t0 = dst[j*2]*scale; + t1 = dst[j*2+2]*scale; + dst[j] = t0; + dst[j+1] = t1; + } + } + else + { + int inplace = src == dst; + const Complex* w = wave; + + t = src[1]; + t0 = (src[0] + src[n-1]); + t1 = (src[n-1] - src[0]); + dst[0] = t0; + dst[1] = t1; + + for( j = 2, w++; j < n2; j += 2, w++ ) + { + T h1_re, h1_im, h2_re, h2_im; + + h1_re = (t + src[n-j-1]); + h1_im = (src[j] - src[n-j]); + + h2_re = (t - src[n-j-1]); + h2_im = (src[j] + src[n-j]); + + t = h2_re*w->re + h2_im*w->im; + h2_im = h2_im*w->re - h2_re*w->im; + h2_re = t; + + t = src[j+1]; + t0 = h1_re - h2_im; + t1 = -h1_im - h2_re; + t2 = h1_re + h2_im; + t3 = h1_im - h2_re; + + if( inplace ) + { + dst[j] = t0; + dst[j+1] = t1; + dst[n-j] = t2; + dst[n-j+1]= t3; + } + else + { + int j2 = j >> 1; + k = itab[j2]; + dst[k] = t0; + dst[k+1] = t1; + k = itab[n2-j2]; + dst[k] = t2; + dst[k+1]= t3; + } + } + + if( j <= n2 ) + { + t0 = t*2; + t1 = src[n2]*2; + + if( inplace ) + { + dst[n2] = t0; + dst[n2+1] = t1; + } + else + { + k = itab[n2]; + dst[k*2] = t0; + dst[k*2+1] = t1; + } + } + + factors[0] >>= 1; + DFT( (Complex*)dst, (Complex*)dst, n2, + nf - (factors[0] == 1), + factors + (factors[0] == 1), itab, + wave, tab_size, 0, buf, + inplace ? 0 : DFT_NO_PERMUTE, 1. ); + factors[0] <<= 1; + + for( j = 0; j < n; j += 2 ) + { + t0 = dst[j]*scale; + t1 = dst[j+1]*(-scale); + dst[j] = t0; + dst[j+1] = t1; + } + } + +#ifdef HAVE_IPP +finalize: +#endif + if( complex_input ) + ((T*)src)[0] = (T)save_s1; +} + +static void +CopyColumn( const uchar* _src, size_t src_step, + uchar* _dst, size_t dst_step, + int len, size_t elem_size ) +{ + int i, t0, t1; + const int* src = (const int*)_src; + int* dst = (int*)_dst; + src_step /= sizeof(src[0]); + dst_step /= sizeof(dst[0]); + + if( elem_size == sizeof(int) ) + { + for( i = 0; i < len; i++, src += src_step, dst += dst_step ) + dst[0] = src[0]; + } + else if( elem_size == sizeof(int)*2 ) + { + for( i = 0; i < len; i++, src += src_step, dst += dst_step ) + { + t0 = src[0]; t1 = src[1]; + dst[0] = t0; dst[1] = t1; + } + } + else if( elem_size == sizeof(int)*4 ) + { + for( i = 0; i < len; i++, src += src_step, dst += dst_step ) + { + t0 = src[0]; t1 = src[1]; + dst[0] = t0; dst[1] = t1; + t0 = src[2]; t1 = src[3]; + dst[2] = t0; dst[3] = t1; + } + } +} + + +static void +CopyFrom2Columns( const uchar* _src, size_t src_step, + uchar* _dst0, uchar* _dst1, + int len, size_t elem_size ) +{ + int i, t0, t1; + const int* src = (const int*)_src; + int* dst0 = (int*)_dst0; + int* dst1 = (int*)_dst1; + src_step /= sizeof(src[0]); + + if( elem_size == sizeof(int) ) + { + for( i = 0; i < len; i++, src += src_step ) + { + t0 = src[0]; t1 = src[1]; + dst0[i] = t0; dst1[i] = t1; + } + } + else if( elem_size == sizeof(int)*2 ) + { + for( i = 0; i < len*2; i += 2, src += src_step ) + { + t0 = src[0]; t1 = src[1]; + dst0[i] = t0; dst0[i+1] = t1; + t0 = src[2]; t1 = src[3]; + dst1[i] = t0; dst1[i+1] = t1; + } + } + else if( elem_size == sizeof(int)*4 ) + { + for( i = 0; i < len*4; i += 4, src += src_step ) + { + t0 = src[0]; t1 = src[1]; + dst0[i] = t0; dst0[i+1] = t1; + t0 = src[2]; t1 = src[3]; + dst0[i+2] = t0; dst0[i+3] = t1; + t0 = src[4]; t1 = src[5]; + dst1[i] = t0; dst1[i+1] = t1; + t0 = src[6]; t1 = src[7]; + dst1[i+2] = t0; dst1[i+3] = t1; + } + } +} + + +static void +CopyTo2Columns( const uchar* _src0, const uchar* _src1, + uchar* _dst, size_t dst_step, + int len, size_t elem_size ) +{ + int i, t0, t1; + const int* src0 = (const int*)_src0; + const int* src1 = (const int*)_src1; + int* dst = (int*)_dst; + dst_step /= sizeof(dst[0]); + + if( elem_size == sizeof(int) ) + { + for( i = 0; i < len; i++, dst += dst_step ) + { + t0 = src0[i]; t1 = src1[i]; + dst[0] = t0; dst[1] = t1; + } + } + else if( elem_size == sizeof(int)*2 ) + { + for( i = 0; i < len*2; i += 2, dst += dst_step ) + { + t0 = src0[i]; t1 = src0[i+1]; + dst[0] = t0; dst[1] = t1; + t0 = src1[i]; t1 = src1[i+1]; + dst[2] = t0; dst[3] = t1; + } + } + else if( elem_size == sizeof(int)*4 ) + { + for( i = 0; i < len*4; i += 4, dst += dst_step ) + { + t0 = src0[i]; t1 = src0[i+1]; + dst[0] = t0; dst[1] = t1; + t0 = src0[i+2]; t1 = src0[i+3]; + dst[2] = t0; dst[3] = t1; + t0 = src1[i]; t1 = src1[i+1]; + dst[4] = t0; dst[5] = t1; + t0 = src1[i+2]; t1 = src1[i+3]; + dst[6] = t0; dst[7] = t1; + } + } +} + + +static void +ExpandCCS( uchar* _ptr, int len, int elem_size ) +{ + int i; + _ptr -= elem_size; + memcpy( _ptr, _ptr + elem_size, elem_size ); + memset( _ptr + elem_size, 0, elem_size ); + if( (len & 1) == 0 ) + memset( _ptr + (len+1)*elem_size, 0, elem_size ); + + if( elem_size == sizeof(float) ) + { + Complex* ptr = (Complex*)_ptr; + + for( i = 1; i < (len+1)/2; i++ ) + { + Complex t; + t.re = ptr[i].re; + t.im = -ptr[i].im; + ptr[len-i] = t; + } + } + else + { + Complex* ptr = (Complex*)_ptr; + + for( i = 1; i < (len+1)/2; i++ ) + { + Complex t; + t.re = ptr[i].re; + t.im = -ptr[i].im; + ptr[len-i] = t; + } + } +} + + +typedef void (*DFTFunc)( + const void* src, void* dst, int n, int nf, int* factors, + const int* itab, const void* wave, int tab_size, + const void* spec, void* buf, int inv, double scale ); + +static void DFT_32f( const Complexf* src, Complexf* dst, int n, + int nf, const int* factors, const int* itab, + const Complexf* wave, int tab_size, + const void* spec, Complexf* buf, + int flags, double scale ) +{ + DFT(src, dst, n, nf, factors, itab, wave, tab_size, spec, buf, flags, scale); +} + +static void DFT_64f( const Complexd* src, Complexd* dst, int n, + int nf, const int* factors, const int* itab, + const Complexd* wave, int tab_size, + const void* spec, Complexd* buf, + int flags, double scale ) +{ + DFT(src, dst, n, nf, factors, itab, wave, tab_size, spec, buf, flags, scale); +} + + +static void RealDFT_32f( const float* src, float* dst, int n, int nf, int* factors, + const int* itab, const Complexf* wave, int tab_size, const void* spec, + Complexf* buf, int flags, double scale ) +{ + RealDFT( src, dst, n, nf, factors, itab, wave, tab_size, spec, buf, flags, scale); +} + +static void RealDFT_64f( const double* src, double* dst, int n, int nf, int* factors, + const int* itab, const Complexd* wave, int tab_size, const void* spec, + Complexd* buf, int flags, double scale ) +{ + RealDFT( src, dst, n, nf, factors, itab, wave, tab_size, spec, buf, flags, scale); +} + +static void CCSIDFT_32f( const float* src, float* dst, int n, int nf, int* factors, + const int* itab, const Complexf* wave, int tab_size, const void* spec, + Complexf* buf, int flags, double scale ) +{ + CCSIDFT( src, dst, n, nf, factors, itab, wave, tab_size, spec, buf, flags, scale); +} + +static void CCSIDFT_64f( const double* src, double* dst, int n, int nf, int* factors, + const int* itab, const Complexd* wave, int tab_size, const void* spec, + Complexd* buf, int flags, double scale ) +{ + CCSIDFT( src, dst, n, nf, factors, itab, wave, tab_size, spec, buf, flags, scale); +} + +} + + +void cv::dft( InputArray _src0, OutputArray _dst, int flags, int nonzero_rows ) +{ + static DFTFunc dft_tbl[6] = + { + (DFTFunc)DFT_32f, + (DFTFunc)RealDFT_32f, + (DFTFunc)CCSIDFT_32f, + (DFTFunc)DFT_64f, + (DFTFunc)RealDFT_64f, + (DFTFunc)CCSIDFT_64f + }; + + AutoBuffer buf; + void *spec = 0; + + Mat src0 = _src0.getMat(), src = src0; + int prev_len = 0, stage = 0; + bool inv = (flags & DFT_INVERSE) != 0; + int nf = 0, real_transform = src.channels() == 1 || (inv && (flags & DFT_REAL_OUTPUT)!=0); + int type = src.type(), depth = src.depth(); + int elem_size = (int)src.elemSize1(), complex_elem_size = elem_size*2; + int factors[34]; + bool inplace_transform = false; +#ifdef HAVE_IPP + void *spec_r = 0, *spec_c = 0; + int ipp_norm_flag = !(flags & DFT_SCALE) ? 8 : inv ? 2 : 1; +#endif + + CV_Assert( type == CV_32FC1 || type == CV_32FC2 || type == CV_64FC1 || type == CV_64FC2 ); + + if( !inv && src.channels() == 1 && (flags & DFT_COMPLEX_OUTPUT) ) + _dst.create( src.size(), CV_MAKETYPE(depth, 2) ); + else if( inv && src.channels() == 2 && (flags & DFT_REAL_OUTPUT) ) + _dst.create( src.size(), depth ); + else + _dst.create( src.size(), type ); + + Mat dst = _dst.getMat(); + + if( !real_transform ) + elem_size = complex_elem_size; + + if( src.cols == 1 && nonzero_rows > 0 ) + CV_Error( CV_StsNotImplemented, + "This mode (using nonzero_rows with a single-column matrix) breaks the function's logic, so it is prohibited.\n" + "For fast convolution/correlation use 2-column matrix or single-row matrix instead" ); + + // determine, which transform to do first - row-wise + // (stage 0) or column-wise (stage 1) transform + if( !(flags & DFT_ROWS) && src.rows > 1 && + ((src.cols == 1 && (!src.isContinuous() || !dst.isContinuous())) || + (src.cols > 1 && inv && real_transform)) ) + stage = 1; + + for(;;) + { + double scale = 1; + uchar* wave = 0; + int* itab = 0; + uchar* ptr; + int i, len, count, sz = 0; + int use_buf = 0, odd_real = 0; + DFTFunc dft_func; + + if( stage == 0 ) // row-wise transform + { + len = !inv ? src.cols : dst.cols; + count = src.rows; + if( len == 1 && !(flags & DFT_ROWS) ) + { + len = !inv ? src.rows : dst.rows; + count = 1; + } + odd_real = real_transform && (len & 1); + } + else + { + len = dst.rows; + count = !inv ? src0.cols : dst.cols; + sz = 2*len*complex_elem_size; + } + + spec = 0; +#ifdef HAVE_IPP + if( len*count >= 64 ) // use IPP DFT if available + { + int ipp_sz = 0; + + if( real_transform && stage == 0 ) + { + if( depth == CV_32F ) + { + if( spec_r ) + IPPI_CALL( ippsDFTFree_R_32f( (IppsDFTSpec_R_32f*)spec_r )); + IPPI_CALL( ippsDFTInitAlloc_R_32f( + (IppsDFTSpec_R_32f**)&spec_r, len, ipp_norm_flag, ippAlgHintNone )); + IPPI_CALL( ippsDFTGetBufSize_R_32f( (IppsDFTSpec_R_32f*)spec_r, &ipp_sz )); + } + else + { + if( spec_r ) + IPPI_CALL( ippsDFTFree_R_64f( (IppsDFTSpec_R_64f*)spec_r )); + IPPI_CALL( ippsDFTInitAlloc_R_64f( + (IppsDFTSpec_R_64f**)&spec_r, len, ipp_norm_flag, ippAlgHintNone )); + IPPI_CALL( ippsDFTGetBufSize_R_64f( (IppsDFTSpec_R_64f*)spec_r, &ipp_sz )); + } + spec = spec_r; + } + else + { + if( depth == CV_32F ) + { + if( spec_c ) + IPPI_CALL( ippsDFTFree_C_32fc( (IppsDFTSpec_C_32fc*)spec_c )); + IPPI_CALL( ippsDFTInitAlloc_C_32fc( + (IppsDFTSpec_C_32fc**)&spec_c, len, ipp_norm_flag, ippAlgHintNone )); + IPPI_CALL( ippsDFTGetBufSize_C_32fc( (IppsDFTSpec_C_32fc*)spec_c, &ipp_sz )); + } + else + { + if( spec_c ) + IPPI_CALL( ippsDFTFree_C_64fc( (IppsDFTSpec_C_64fc*)spec_c )); + IPPI_CALL( ippsDFTInitAlloc_C_64fc( + (IppsDFTSpec_C_64fc**)&spec_c, len, ipp_norm_flag, ippAlgHintNone )); + IPPI_CALL( ippsDFTGetBufSize_C_64fc( (IppsDFTSpec_C_64fc*)spec_c, &ipp_sz )); + } + spec = spec_c; + } + + sz += ipp_sz; + } + else +#endif + { + if( len != prev_len ) + nf = DFTFactorize( len, factors ); + + inplace_transform = factors[0] == factors[nf-1]; + sz += len*(complex_elem_size + sizeof(int)); + i = nf > 1 && (factors[0] & 1) == 0; + if( (factors[i] & 1) != 0 && factors[i] > 5 ) + sz += (factors[i]+1)*complex_elem_size; + + if( (stage == 0 && ((src.data == dst.data && !inplace_transform) || odd_real)) || + (stage == 1 && !inplace_transform) ) + { + use_buf = 1; + sz += len*complex_elem_size; + } + } + + ptr = (uchar*)buf; + buf.allocate( sz + 32 ); + if( ptr != (uchar*)buf ) + prev_len = 0; // because we release the buffer, + // force recalculation of + // twiddle factors and permutation table + ptr = (uchar*)buf; + if( !spec ) + { + wave = ptr; + ptr += len*complex_elem_size; + itab = (int*)ptr; + ptr = (uchar*)cvAlignPtr( ptr + len*sizeof(int), 16 ); + + if( len != prev_len || (!inplace_transform && inv && real_transform)) + DFTInit( len, nf, factors, itab, complex_elem_size, + wave, stage == 0 && inv && real_transform ); + // otherwise reuse the tables calculated on the previous stage + } + + if( stage == 0 ) + { + uchar* tmp_buf = 0; + int dptr_offset = 0; + int dst_full_len = len*elem_size; + int _flags = (int)inv + (src.channels() != dst.channels() ? + DFT_COMPLEX_INPUT_OR_OUTPUT : 0); + if( use_buf ) + { + tmp_buf = ptr; + ptr += len*complex_elem_size; + if( odd_real && !inv && len > 1 && + !(_flags & DFT_COMPLEX_INPUT_OR_OUTPUT)) + dptr_offset = elem_size; + } + + if( !inv && (_flags & DFT_COMPLEX_INPUT_OR_OUTPUT) ) + dst_full_len += (len & 1) ? elem_size : complex_elem_size; + + dft_func = dft_tbl[(!real_transform ? 0 : !inv ? 1 : 2) + (depth == CV_64F)*3]; + + if( count > 1 && !(flags & DFT_ROWS) && (!inv || !real_transform) ) + stage = 1; + else if( flags & CV_DXT_SCALE ) + scale = 1./(len * (flags & DFT_ROWS ? 1 : count)); + + if( nonzero_rows <= 0 || nonzero_rows > count ) + nonzero_rows = count; + + for( i = 0; i < nonzero_rows; i++ ) + { + uchar* sptr = src.data + i*src.step; + uchar* dptr0 = dst.data + i*dst.step; + uchar* dptr = dptr0; + + if( tmp_buf ) + dptr = tmp_buf; + + dft_func( sptr, dptr, len, nf, factors, itab, wave, len, spec, ptr, _flags, scale ); + if( dptr != dptr0 ) + memcpy( dptr0, dptr + dptr_offset, dst_full_len ); + } + + for( ; i < count; i++ ) + { + uchar* dptr0 = dst.data + i*dst.step; + memset( dptr0, 0, dst_full_len ); + } + + if( stage != 1 ) + break; + src = dst; + } + else + { + int a = 0, b = count; + uchar *buf0, *buf1, *dbuf0, *dbuf1; + uchar* sptr0 = src.data; + uchar* dptr0 = dst.data; + buf0 = ptr; + ptr += len*complex_elem_size; + buf1 = ptr; + ptr += len*complex_elem_size; + dbuf0 = buf0, dbuf1 = buf1; + + if( use_buf ) + { + dbuf1 = ptr; + dbuf0 = buf1; + ptr += len*complex_elem_size; + } + + dft_func = dft_tbl[(depth == CV_64F)*3]; + + if( real_transform && inv && src.cols > 1 ) + stage = 0; + else if( flags & CV_DXT_SCALE ) + scale = 1./(len * count); + + if( real_transform ) + { + int even; + a = 1; + even = (count & 1) == 0; + b = (count+1)/2; + if( !inv ) + { + memset( buf0, 0, len*complex_elem_size ); + CopyColumn( sptr0, src.step, buf0, complex_elem_size, len, elem_size ); + sptr0 += dst.channels()*elem_size; + if( even ) + { + memset( buf1, 0, len*complex_elem_size ); + CopyColumn( sptr0 + (count-2)*elem_size, src.step, + buf1, complex_elem_size, len, elem_size ); + } + } + else if( src.channels() == 1 ) + { + CopyColumn( sptr0, src.step, buf0 + elem_size, elem_size, len, elem_size ); + ExpandCCS( buf0 + elem_size, len, elem_size ); + if( even ) + { + CopyColumn( sptr0 + (count-1)*elem_size, src.step, + buf1 + elem_size, elem_size, len, elem_size ); + ExpandCCS( buf1 + elem_size, len, elem_size ); + } + sptr0 += elem_size; + } + else + { + CopyColumn( sptr0, src.step, buf0, complex_elem_size, len, complex_elem_size ); + if( even ) + { + CopyColumn( sptr0 + b*complex_elem_size, src.step, + buf1, complex_elem_size, len, complex_elem_size ); + } + sptr0 += complex_elem_size; + } + + if( even ) + dft_func( buf1, dbuf1, len, nf, factors, itab, + wave, len, spec, ptr, inv, scale ); + dft_func( buf0, dbuf0, len, nf, factors, itab, + wave, len, spec, ptr, inv, scale ); + + if( dst.channels() == 1 ) + { + if( !inv ) + { + // copy the half of output vector to the first/last column. + // before doing that, defgragment the vector + memcpy( dbuf0 + elem_size, dbuf0, elem_size ); + CopyColumn( dbuf0 + elem_size, elem_size, dptr0, + dst.step, len, elem_size ); + if( even ) + { + memcpy( dbuf1 + elem_size, dbuf1, elem_size ); + CopyColumn( dbuf1 + elem_size, elem_size, + dptr0 + (count-1)*elem_size, + dst.step, len, elem_size ); + } + dptr0 += elem_size; + } + else + { + // copy the real part of the complex vector to the first/last column + CopyColumn( dbuf0, complex_elem_size, dptr0, dst.step, len, elem_size ); + if( even ) + CopyColumn( dbuf1, complex_elem_size, dptr0 + (count-1)*elem_size, + dst.step, len, elem_size ); + dptr0 += elem_size; + } + } + else + { + assert( !inv ); + CopyColumn( dbuf0, complex_elem_size, dptr0, + dst.step, len, complex_elem_size ); + if( even ) + CopyColumn( dbuf1, complex_elem_size, + dptr0 + b*complex_elem_size, + dst.step, len, complex_elem_size ); + dptr0 += complex_elem_size; + } + } + + for( i = a; i < b; i += 2 ) + { + if( i+1 < b ) + { + CopyFrom2Columns( sptr0, src.step, buf0, buf1, len, complex_elem_size ); + dft_func( buf1, dbuf1, len, nf, factors, itab, + wave, len, spec, ptr, inv, scale ); + } + else + CopyColumn( sptr0, src.step, buf0, complex_elem_size, len, complex_elem_size ); + + dft_func( buf0, dbuf0, len, nf, factors, itab, + wave, len, spec, ptr, inv, scale ); + + if( i+1 < b ) + CopyTo2Columns( dbuf0, dbuf1, dptr0, dst.step, len, complex_elem_size ); + else + CopyColumn( dbuf0, complex_elem_size, dptr0, dst.step, len, complex_elem_size ); + sptr0 += 2*complex_elem_size; + dptr0 += 2*complex_elem_size; + } + + if( stage != 0 ) + break; + src = dst; + } + } + +#ifdef HAVE_IPP + if( spec_c ) + { + if( depth == CV_32F ) + ippsDFTFree_C_32fc( (IppsDFTSpec_C_32fc*)spec_c ); + else + ippsDFTFree_C_64fc( (IppsDFTSpec_C_64fc*)spec_c ); + } + + if( spec_r ) + { + if( depth == CV_32F ) + ippsDFTFree_R_32f( (IppsDFTSpec_R_32f*)spec_r ); + else + ippsDFTFree_R_64f( (IppsDFTSpec_R_64f*)spec_r ); + } +#endif +} + + +void cv::idft( InputArray src, OutputArray dst, int flags, int nonzero_rows ) +{ + dft( src, dst, flags | DFT_INVERSE, nonzero_rows ); +} + +void cv::mulSpectrums( InputArray _srcA, InputArray _srcB, + OutputArray _dst, int flags, bool conjB ) +{ + Mat srcA = _srcA.getMat(), srcB = _srcB.getMat(); + int depth = srcA.depth(), cn = srcA.channels(), type = srcA.type(); + int rows = srcA.rows, cols = srcA.cols; + int j, k; + + CV_Assert( type == srcB.type() && srcA.size() == srcB.size() ); + CV_Assert( type == CV_32FC1 || type == CV_32FC2 || type == CV_64FC1 || type == CV_64FC2 ); + + _dst.create( srcA.rows, srcA.cols, type ); + Mat dst = _dst.getMat(); + + bool is_1d = (flags & DFT_ROWS) || (rows == 1 || (cols == 1 && + srcA.isContinuous() && srcB.isContinuous() && dst.isContinuous())); + + if( is_1d && !(flags & DFT_ROWS) ) + cols = cols + rows - 1, rows = 1; + + int ncols = cols*cn; + int j0 = cn == 1; + int j1 = ncols - (cols % 2 == 0 && cn == 1); + + if( depth == CV_32F ) + { + const float* dataA = (const float*)srcA.data; + const float* dataB = (const float*)srcB.data; + float* dataC = (float*)dst.data; + + size_t stepA = srcA.step/sizeof(dataA[0]); + size_t stepB = srcB.step/sizeof(dataB[0]); + size_t stepC = dst.step/sizeof(dataC[0]); + + if( !is_1d && cn == 1 ) + { + for( k = 0; k < (cols % 2 ? 1 : 2); k++ ) + { + if( k == 1 ) + dataA += cols - 1, dataB += cols - 1, dataC += cols - 1; + dataC[0] = dataA[0]*dataB[0]; + if( rows % 2 == 0 ) + dataC[(rows-1)*stepC] = dataA[(rows-1)*stepA]*dataB[(rows-1)*stepB]; + if( !conjB ) + for( j = 1; j <= rows - 2; j += 2 ) + { + double re = (double)dataA[j*stepA]*dataB[j*stepB] - + (double)dataA[(j+1)*stepA]*dataB[(j+1)*stepB]; + double im = (double)dataA[j*stepA]*dataB[(j+1)*stepB] + + (double)dataA[(j+1)*stepA]*dataB[j*stepB]; + dataC[j*stepC] = (float)re; dataC[(j+1)*stepC] = (float)im; + } + else + for( j = 1; j <= rows - 2; j += 2 ) + { + double re = (double)dataA[j*stepA]*dataB[j*stepB] + + (double)dataA[(j+1)*stepA]*dataB[(j+1)*stepB]; + double im = (double)dataA[(j+1)*stepA]*dataB[j*stepB] - + (double)dataA[j*stepA]*dataB[(j+1)*stepB]; + dataC[j*stepC] = (float)re; dataC[(j+1)*stepC] = (float)im; + } + if( k == 1 ) + dataA -= cols - 1, dataB -= cols - 1, dataC -= cols - 1; + } + } + + for( ; rows--; dataA += stepA, dataB += stepB, dataC += stepC ) + { + if( is_1d && cn == 1 ) + { + dataC[0] = dataA[0]*dataB[0]; + if( cols % 2 == 0 ) + dataC[j1] = dataA[j1]*dataB[j1]; + } + + if( !conjB ) + for( j = j0; j < j1; j += 2 ) + { + double re = (double)dataA[j]*dataB[j] - (double)dataA[j+1]*dataB[j+1]; + double im = (double)dataA[j+1]*dataB[j] + (double)dataA[j]*dataB[j+1]; + dataC[j] = (float)re; dataC[j+1] = (float)im; + } + else + for( j = j0; j < j1; j += 2 ) + { + double re = (double)dataA[j]*dataB[j] + (double)dataA[j+1]*dataB[j+1]; + double im = (double)dataA[j+1]*dataB[j] - (double)dataA[j]*dataB[j+1]; + dataC[j] = (float)re; dataC[j+1] = (float)im; + } + } + } + else + { + const double* dataA = (const double*)srcA.data; + const double* dataB = (const double*)srcB.data; + double* dataC = (double*)dst.data; + + size_t stepA = srcA.step/sizeof(dataA[0]); + size_t stepB = srcB.step/sizeof(dataB[0]); + size_t stepC = dst.step/sizeof(dataC[0]); + + if( !is_1d && cn == 1 ) + { + for( k = 0; k < (cols % 2 ? 1 : 2); k++ ) + { + if( k == 1 ) + dataA += cols - 1, dataB += cols - 1, dataC += cols - 1; + dataC[0] = dataA[0]*dataB[0]; + if( rows % 2 == 0 ) + dataC[(rows-1)*stepC] = dataA[(rows-1)*stepA]*dataB[(rows-1)*stepB]; + if( !conjB ) + for( j = 1; j <= rows - 2; j += 2 ) + { + double re = dataA[j*stepA]*dataB[j*stepB] - + dataA[(j+1)*stepA]*dataB[(j+1)*stepB]; + double im = dataA[j*stepA]*dataB[(j+1)*stepB] + + dataA[(j+1)*stepA]*dataB[j*stepB]; + dataC[j*stepC] = re; dataC[(j+1)*stepC] = im; + } + else + for( j = 1; j <= rows - 2; j += 2 ) + { + double re = dataA[j*stepA]*dataB[j*stepB] + + dataA[(j+1)*stepA]*dataB[(j+1)*stepB]; + double im = dataA[(j+1)*stepA]*dataB[j*stepB] - + dataA[j*stepA]*dataB[(j+1)*stepB]; + dataC[j*stepC] = re; dataC[(j+1)*stepC] = im; + } + if( k == 1 ) + dataA -= cols - 1, dataB -= cols - 1, dataC -= cols - 1; + } + } + + for( ; rows--; dataA += stepA, dataB += stepB, dataC += stepC ) + { + if( is_1d && cn == 1 ) + { + dataC[0] = dataA[0]*dataB[0]; + if( cols % 2 == 0 ) + dataC[j1] = dataA[j1]*dataB[j1]; + } + + if( !conjB ) + for( j = j0; j < j1; j += 2 ) + { + double re = dataA[j]*dataB[j] - dataA[j+1]*dataB[j+1]; + double im = dataA[j+1]*dataB[j] + dataA[j]*dataB[j+1]; + dataC[j] = re; dataC[j+1] = im; + } + else + for( j = j0; j < j1; j += 2 ) + { + double re = dataA[j]*dataB[j] + dataA[j+1]*dataB[j+1]; + double im = dataA[j+1]*dataB[j] - dataA[j]*dataB[j+1]; + dataC[j] = re; dataC[j+1] = im; + } + } + } +} + + +/****************************************************************************************\ + Discrete Cosine Transform +\****************************************************************************************/ + +namespace cv +{ + +/* DCT is calculated using DFT, as described here: + http://www.ece.utexas.edu/~bevans/courses/ee381k/lectures/09_DCT/lecture9/: +*/ +template static void +DCT( const T* src, int src_step, T* dft_src, T* dft_dst, T* dst, int dst_step, + int n, int nf, int* factors, const int* itab, const Complex* dft_wave, + const Complex* dct_wave, const void* spec, Complex* buf ) +{ + static const T sin_45 = (T)0.70710678118654752440084436210485; + int j, n2 = n >> 1; + + src_step /= sizeof(src[0]); + dst_step /= sizeof(dst[0]); + T* dst1 = dst + (n-1)*dst_step; + + if( n == 1 ) + { + dst[0] = src[0]; + return; + } + + for( j = 0; j < n2; j++, src += src_step*2 ) + { + dft_src[j] = src[0]; + dft_src[n-j-1] = src[src_step]; + } + + RealDFT( dft_src, dft_dst, n, nf, factors, + itab, dft_wave, n, spec, buf, 0, 1.0 ); + src = dft_dst; + + dst[0] = (T)(src[0]*dct_wave->re*sin_45); + dst += dst_step; + for( j = 1, dct_wave++; j < n2; j++, dct_wave++, + dst += dst_step, dst1 -= dst_step ) + { + T t0 = dct_wave->re*src[j*2-1] - dct_wave->im*src[j*2]; + T t1 = -dct_wave->im*src[j*2-1] - dct_wave->re*src[j*2]; + dst[0] = t0; + dst1[0] = t1; + } + + dst[0] = src[n-1]*dct_wave->re; +} + + +template static void +IDCT( const T* src, int src_step, T* dft_src, T* dft_dst, T* dst, int dst_step, + int n, int nf, int* factors, const int* itab, const Complex* dft_wave, + const Complex* dct_wave, const void* spec, Complex* buf ) +{ + static const T sin_45 = (T)0.70710678118654752440084436210485; + int j, n2 = n >> 1; + + src_step /= sizeof(src[0]); + dst_step /= sizeof(dst[0]); + const T* src1 = src + (n-1)*src_step; + + if( n == 1 ) + { + dst[0] = src[0]; + return; + } + + dft_src[0] = (T)(src[0]*2*dct_wave->re*sin_45); + src += src_step; + for( j = 1, dct_wave++; j < n2; j++, dct_wave++, + src += src_step, src1 -= src_step ) + { + T t0 = dct_wave->re*src[0] - dct_wave->im*src1[0]; + T t1 = -dct_wave->im*src[0] - dct_wave->re*src1[0]; + dft_src[j*2-1] = t0; + dft_src[j*2] = t1; + } + + dft_src[n-1] = (T)(src[0]*2*dct_wave->re); + CCSIDFT( dft_src, dft_dst, n, nf, factors, itab, + dft_wave, n, spec, buf, 0, 1.0 ); + + for( j = 0; j < n2; j++, dst += dst_step*2 ) + { + dst[0] = dft_dst[j]; + dst[dst_step] = dft_dst[n-j-1]; + } +} + + +static void +DCTInit( int n, int elem_size, void* _wave, int inv ) +{ + static const double DctScale[] = + { + 0.707106781186547570, 0.500000000000000000, 0.353553390593273790, + 0.250000000000000000, 0.176776695296636890, 0.125000000000000000, + 0.088388347648318447, 0.062500000000000000, 0.044194173824159223, + 0.031250000000000000, 0.022097086912079612, 0.015625000000000000, + 0.011048543456039806, 0.007812500000000000, 0.005524271728019903, + 0.003906250000000000, 0.002762135864009952, 0.001953125000000000, + 0.001381067932004976, 0.000976562500000000, 0.000690533966002488, + 0.000488281250000000, 0.000345266983001244, 0.000244140625000000, + 0.000172633491500622, 0.000122070312500000, 0.000086316745750311, + 0.000061035156250000, 0.000043158372875155, 0.000030517578125000 + }; + + int i; + Complex w, w1; + double t, scale; + + if( n == 1 ) + return; + + assert( (n&1) == 0 ); + + if( (n & (n - 1)) == 0 ) + { + int m; + for( m = 0; (unsigned)(1 << m) < (unsigned)n; m++ ) + ; + scale = (!inv ? 2 : 1)*DctScale[m]; + w1.re = DFTTab[m+2][0]; + w1.im = -DFTTab[m+2][1]; + } + else + { + t = 1./(2*n); + scale = (!inv ? 2 : 1)*std::sqrt(t); + w1.im = sin(-CV_PI*t); + w1.re = std::sqrt(1. - w1.im*w1.im); + } + n >>= 1; + + if( elem_size == sizeof(Complex) ) + { + Complex* wave = (Complex*)_wave; + + w.re = scale; + w.im = 0.; + + for( i = 0; i <= n; i++ ) + { + wave[i] = w; + t = w.re*w1.re - w.im*w1.im; + w.im = w.re*w1.im + w.im*w1.re; + w.re = t; + } + } + else + { + Complex* wave = (Complex*)_wave; + assert( elem_size == sizeof(Complex) ); + + w.re = (float)scale; + w.im = 0.f; + + for( i = 0; i <= n; i++ ) + { + wave[i].re = (float)w.re; + wave[i].im = (float)w.im; + t = w.re*w1.re - w.im*w1.im; + w.im = w.re*w1.im + w.im*w1.re; + w.re = t; + } + } +} + + +typedef void (*DCTFunc)(const void* src, int src_step, void* dft_src, + void* dft_dst, void* dst, int dst_step, int n, + int nf, int* factors, const int* itab, const void* dft_wave, + const void* dct_wave, const void* spec, void* buf ); + +static void DCT_32f(const float* src, int src_step, float* dft_src, float* dft_dst, + float* dst, int dst_step, int n, int nf, int* factors, const int* itab, + const Complexf* dft_wave, const Complexf* dct_wave, const void* spec, Complexf* buf ) +{ + DCT(src, src_step, dft_src, dft_dst, dst, dst_step, + n, nf, factors, itab, dft_wave, dct_wave, spec, buf); +} + +static void IDCT_32f(const float* src, int src_step, float* dft_src, float* dft_dst, + float* dst, int dst_step, int n, int nf, int* factors, const int* itab, + const Complexf* dft_wave, const Complexf* dct_wave, const void* spec, Complexf* buf ) +{ + IDCT(src, src_step, dft_src, dft_dst, dst, dst_step, + n, nf, factors, itab, dft_wave, dct_wave, spec, buf); +} + +static void DCT_64f(const double* src, int src_step, double* dft_src, double* dft_dst, + double* dst, int dst_step, int n, int nf, int* factors, const int* itab, + const Complexd* dft_wave, const Complexd* dct_wave, const void* spec, Complexd* buf ) +{ + DCT(src, src_step, dft_src, dft_dst, dst, dst_step, + n, nf, factors, itab, dft_wave, dct_wave, spec, buf); +} + +static void IDCT_64f(const double* src, int src_step, double* dft_src, double* dft_dst, + double* dst, int dst_step, int n, int nf, int* factors, const int* itab, + const Complexd* dft_wave, const Complexd* dct_wave, const void* spec, Complexd* buf ) +{ + IDCT(src, src_step, dft_src, dft_dst, dst, dst_step, + n, nf, factors, itab, dft_wave, dct_wave, spec, buf); +} + +} + +void cv::dct( InputArray _src0, OutputArray _dst, int flags ) +{ + static DCTFunc dct_tbl[4] = + { + (DCTFunc)DCT_32f, + (DCTFunc)IDCT_32f, + (DCTFunc)DCT_64f, + (DCTFunc)IDCT_64f + }; + + bool inv = (flags & DCT_INVERSE) != 0; + Mat src0 = _src0.getMat(), src = src0; + int type = src.type(), depth = src.depth(); + void /* *spec_dft = 0, */ *spec = 0; + + double scale = 1.; + int prev_len = 0, nf = 0, stage, end_stage; + uchar *src_dft_buf = 0, *dst_dft_buf = 0; + uchar *dft_wave = 0, *dct_wave = 0; + int* itab = 0; + uchar* ptr = 0; + int elem_size = (int)src.elemSize(), complex_elem_size = elem_size*2; + int factors[34], inplace_transform; + int i, len, count; + AutoBuffer buf; + + CV_Assert( type == CV_32FC1 || type == CV_64FC1 ); + _dst.create( src.rows, src.cols, type ); + Mat dst = _dst.getMat(); + + DCTFunc dct_func = dct_tbl[(int)inv + (depth == CV_64F)*2]; + + if( (flags & DFT_ROWS) || src.rows == 1 || + (src.cols == 1 && (src.isContinuous() && dst.isContinuous()))) + { + stage = end_stage = 0; + } + else + { + stage = src.cols == 1; + end_stage = 1; + } + + for( ; stage <= end_stage; stage++ ) + { + uchar *sptr = src.data, *dptr = dst.data; + size_t sstep0, sstep1, dstep0, dstep1; + + if( stage == 0 ) + { + len = src.cols; + count = src.rows; + if( len == 1 && !(flags & DFT_ROWS) ) + { + len = src.rows; + count = 1; + } + sstep0 = src.step; + dstep0 = dst.step; + sstep1 = dstep1 = elem_size; + } + else + { + len = dst.rows; + count = dst.cols; + sstep1 = src.step; + dstep1 = dst.step; + sstep0 = dstep0 = elem_size; + } + + if( len != prev_len ) + { + int sz; + + if( len > 1 && (len & 1) ) + CV_Error( CV_StsNotImplemented, "Odd-size DCT\'s are not implemented" ); + + sz = len*elem_size; + sz += (len/2 + 1)*complex_elem_size; + + spec = 0; + inplace_transform = 1; + /*if( len*count >= 64 && DFTInitAlloc_R_32f_p ) + { + int ipp_sz = 0; + if( depth == CV_32F ) + { + if( spec_dft ) + IPPI_CALL( DFTFree_R_32f_p( spec_dft )); + IPPI_CALL( DFTInitAlloc_R_32f_p( &spec_dft, len, 8, cvAlgHintNone )); + IPPI_CALL( DFTGetBufSize_R_32f_p( spec_dft, &ipp_sz )); + } + else + { + if( spec_dft ) + IPPI_CALL( DFTFree_R_64f_p( spec_dft )); + IPPI_CALL( DFTInitAlloc_R_64f_p( &spec_dft, len, 8, cvAlgHintNone )); + IPPI_CALL( DFTGetBufSize_R_64f_p( spec_dft, &ipp_sz )); + } + spec = spec_dft; + sz += ipp_sz; + } + else*/ + { + sz += len*(complex_elem_size + sizeof(int)) + complex_elem_size; + + nf = DFTFactorize( len, factors ); + inplace_transform = factors[0] == factors[nf-1]; + + i = nf > 1 && (factors[0] & 1) == 0; + if( (factors[i] & 1) != 0 && factors[i] > 5 ) + sz += (factors[i]+1)*complex_elem_size; + + if( !inplace_transform ) + sz += len*elem_size; + } + + buf.allocate( sz + 32 ); + ptr = (uchar*)buf; + + if( !spec ) + { + dft_wave = ptr; + ptr += len*complex_elem_size; + itab = (int*)ptr; + ptr = (uchar*)cvAlignPtr( ptr + len*sizeof(int), 16 ); + DFTInit( len, nf, factors, itab, complex_elem_size, dft_wave, inv ); + } + + dct_wave = ptr; + ptr += (len/2 + 1)*complex_elem_size; + src_dft_buf = dst_dft_buf = ptr; + ptr += len*elem_size; + if( !inplace_transform ) + { + dst_dft_buf = ptr; + ptr += len*elem_size; + } + DCTInit( len, complex_elem_size, dct_wave, inv ); + if( !inv ) + scale += scale; + prev_len = len; + } + // otherwise reuse the tables calculated on the previous stage + for( i = 0; i < count; i++ ) + { + dct_func( sptr + i*sstep0, (int)sstep1, src_dft_buf, dst_dft_buf, + dptr + i*dstep0, (int)dstep1, len, nf, factors, + itab, dft_wave, dct_wave, spec, ptr ); + } + src = dst; + } +} + + +void cv::idct( InputArray src, OutputArray dst, int flags ) +{ + dct( src, dst, flags | DCT_INVERSE ); +} + +namespace cv +{ + +static const int optimalDFTSizeTab[] = { +1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36, 40, 45, 48, +50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, +162, 180, 192, 200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, +384, 400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675, 720, +729, 750, 768, 800, 810, 864, 900, 960, 972, 1000, 1024, 1080, 1125, 1152, 1200, +1215, 1250, 1280, 1296, 1350, 1440, 1458, 1500, 1536, 1600, 1620, 1728, 1800, 1875, +1920, 1944, 2000, 2025, 2048, 2160, 2187, 2250, 2304, 2400, 2430, 2500, 2560, 2592, +2700, 2880, 2916, 3000, 3072, 3125, 3200, 3240, 3375, 3456, 3600, 3645, 3750, 3840, +3888, 4000, 4050, 4096, 4320, 4374, 4500, 4608, 4800, 4860, 5000, 5120, 5184, 5400, +5625, 5760, 5832, 6000, 6075, 6144, 6250, 6400, 6480, 6561, 6750, 6912, 7200, 7290, +7500, 7680, 7776, 8000, 8100, 8192, 8640, 8748, 9000, 9216, 9375, 9600, 9720, 10000, +10125, 10240, 10368, 10800, 10935, 11250, 11520, 11664, 12000, 12150, 12288, 12500, +12800, 12960, 13122, 13500, 13824, 14400, 14580, 15000, 15360, 15552, 15625, 16000, +16200, 16384, 16875, 17280, 17496, 18000, 18225, 18432, 18750, 19200, 19440, 19683, +20000, 20250, 20480, 20736, 21600, 21870, 22500, 23040, 23328, 24000, 24300, 24576, +25000, 25600, 25920, 26244, 27000, 27648, 28125, 28800, 29160, 30000, 30375, 30720, +31104, 31250, 32000, 32400, 32768, 32805, 33750, 34560, 34992, 36000, 36450, 36864, +37500, 38400, 38880, 39366, 40000, 40500, 40960, 41472, 43200, 43740, 45000, 46080, +46656, 46875, 48000, 48600, 49152, 50000, 50625, 51200, 51840, 52488, 54000, 54675, +55296, 56250, 57600, 58320, 59049, 60000, 60750, 61440, 62208, 62500, 64000, 64800, +65536, 65610, 67500, 69120, 69984, 72000, 72900, 73728, 75000, 76800, 77760, 78125, +78732, 80000, 81000, 81920, 82944, 84375, 86400, 87480, 90000, 91125, 92160, 93312, +93750, 96000, 97200, 98304, 98415, 100000, 101250, 102400, 103680, 104976, 108000, +109350, 110592, 112500, 115200, 116640, 118098, 120000, 121500, 122880, 124416, 125000, +128000, 129600, 131072, 131220, 135000, 138240, 139968, 140625, 144000, 145800, 147456, +150000, 151875, 153600, 155520, 156250, 157464, 160000, 162000, 163840, 164025, 165888, +168750, 172800, 174960, 177147, 180000, 182250, 184320, 186624, 187500, 192000, 194400, +196608, 196830, 200000, 202500, 204800, 207360, 209952, 216000, 218700, 221184, 225000, +230400, 233280, 234375, 236196, 240000, 243000, 245760, 248832, 250000, 253125, 256000, +259200, 262144, 262440, 270000, 273375, 276480, 279936, 281250, 288000, 291600, 294912, +295245, 300000, 303750, 307200, 311040, 312500, 314928, 320000, 324000, 327680, 328050, +331776, 337500, 345600, 349920, 354294, 360000, 364500, 368640, 373248, 375000, 384000, +388800, 390625, 393216, 393660, 400000, 405000, 409600, 414720, 419904, 421875, 432000, +437400, 442368, 450000, 455625, 460800, 466560, 468750, 472392, 480000, 486000, 491520, +492075, 497664, 500000, 506250, 512000, 518400, 524288, 524880, 531441, 540000, 546750, +552960, 559872, 562500, 576000, 583200, 589824, 590490, 600000, 607500, 614400, 622080, +625000, 629856, 640000, 648000, 655360, 656100, 663552, 675000, 691200, 699840, 703125, +708588, 720000, 729000, 737280, 746496, 750000, 759375, 768000, 777600, 781250, 786432, +787320, 800000, 810000, 819200, 820125, 829440, 839808, 843750, 864000, 874800, 884736, +885735, 900000, 911250, 921600, 933120, 937500, 944784, 960000, 972000, 983040, 984150, +995328, 1000000, 1012500, 1024000, 1036800, 1048576, 1049760, 1062882, 1080000, 1093500, +1105920, 1119744, 1125000, 1152000, 1166400, 1171875, 1179648, 1180980, 1200000, +1215000, 1228800, 1244160, 1250000, 1259712, 1265625, 1280000, 1296000, 1310720, +1312200, 1327104, 1350000, 1366875, 1382400, 1399680, 1406250, 1417176, 1440000, +1458000, 1474560, 1476225, 1492992, 1500000, 1518750, 1536000, 1555200, 1562500, +1572864, 1574640, 1594323, 1600000, 1620000, 1638400, 1640250, 1658880, 1679616, +1687500, 1728000, 1749600, 1769472, 1771470, 1800000, 1822500, 1843200, 1866240, +1875000, 1889568, 1920000, 1944000, 1953125, 1966080, 1968300, 1990656, 2000000, +2025000, 2048000, 2073600, 2097152, 2099520, 2109375, 2125764, 2160000, 2187000, +2211840, 2239488, 2250000, 2278125, 2304000, 2332800, 2343750, 2359296, 2361960, +2400000, 2430000, 2457600, 2460375, 2488320, 2500000, 2519424, 2531250, 2560000, +2592000, 2621440, 2624400, 2654208, 2657205, 2700000, 2733750, 2764800, 2799360, +2812500, 2834352, 2880000, 2916000, 2949120, 2952450, 2985984, 3000000, 3037500, +3072000, 3110400, 3125000, 3145728, 3149280, 3188646, 3200000, 3240000, 3276800, +3280500, 3317760, 3359232, 3375000, 3456000, 3499200, 3515625, 3538944, 3542940, +3600000, 3645000, 3686400, 3732480, 3750000, 3779136, 3796875, 3840000, 3888000, +3906250, 3932160, 3936600, 3981312, 4000000, 4050000, 4096000, 4100625, 4147200, +4194304, 4199040, 4218750, 4251528, 4320000, 4374000, 4423680, 4428675, 4478976, +4500000, 4556250, 4608000, 4665600, 4687500, 4718592, 4723920, 4782969, 4800000, +4860000, 4915200, 4920750, 4976640, 5000000, 5038848, 5062500, 5120000, 5184000, +5242880, 5248800, 5308416, 5314410, 5400000, 5467500, 5529600, 5598720, 5625000, +5668704, 5760000, 5832000, 5859375, 5898240, 5904900, 5971968, 6000000, 6075000, +6144000, 6220800, 6250000, 6291456, 6298560, 6328125, 6377292, 6400000, 6480000, +6553600, 6561000, 6635520, 6718464, 6750000, 6834375, 6912000, 6998400, 7031250, +7077888, 7085880, 7200000, 7290000, 7372800, 7381125, 7464960, 7500000, 7558272, +7593750, 7680000, 7776000, 7812500, 7864320, 7873200, 7962624, 7971615, 8000000, +8100000, 8192000, 8201250, 8294400, 8388608, 8398080, 8437500, 8503056, 8640000, +8748000, 8847360, 8857350, 8957952, 9000000, 9112500, 9216000, 9331200, 9375000, +9437184, 9447840, 9565938, 9600000, 9720000, 9765625, 9830400, 9841500, 9953280, +10000000, 10077696, 10125000, 10240000, 10368000, 10485760, 10497600, 10546875, 10616832, +10628820, 10800000, 10935000, 11059200, 11197440, 11250000, 11337408, 11390625, 11520000, +11664000, 11718750, 11796480, 11809800, 11943936, 12000000, 12150000, 12288000, 12301875, +12441600, 12500000, 12582912, 12597120, 12656250, 12754584, 12800000, 12960000, 13107200, +13122000, 13271040, 13286025, 13436928, 13500000, 13668750, 13824000, 13996800, 14062500, +14155776, 14171760, 14400000, 14580000, 14745600, 14762250, 14929920, 15000000, 15116544, +15187500, 15360000, 15552000, 15625000, 15728640, 15746400, 15925248, 15943230, 16000000, +16200000, 16384000, 16402500, 16588800, 16777216, 16796160, 16875000, 17006112, 17280000, +17496000, 17578125, 17694720, 17714700, 17915904, 18000000, 18225000, 18432000, 18662400, +18750000, 18874368, 18895680, 18984375, 19131876, 19200000, 19440000, 19531250, 19660800, +19683000, 19906560, 20000000, 20155392, 20250000, 20480000, 20503125, 20736000, 20971520, +20995200, 21093750, 21233664, 21257640, 21600000, 21870000, 22118400, 22143375, 22394880, +22500000, 22674816, 22781250, 23040000, 23328000, 23437500, 23592960, 23619600, 23887872, +23914845, 24000000, 24300000, 24576000, 24603750, 24883200, 25000000, 25165824, 25194240, +25312500, 25509168, 25600000, 25920000, 26214400, 26244000, 26542080, 26572050, 26873856, +27000000, 27337500, 27648000, 27993600, 28125000, 28311552, 28343520, 28800000, 29160000, +29296875, 29491200, 29524500, 29859840, 30000000, 30233088, 30375000, 30720000, 31104000, +31250000, 31457280, 31492800, 31640625, 31850496, 31886460, 32000000, 32400000, 32768000, +32805000, 33177600, 33554432, 33592320, 33750000, 34012224, 34171875, 34560000, 34992000, +35156250, 35389440, 35429400, 35831808, 36000000, 36450000, 36864000, 36905625, 37324800, +37500000, 37748736, 37791360, 37968750, 38263752, 38400000, 38880000, 39062500, 39321600, +39366000, 39813120, 39858075, 40000000, 40310784, 40500000, 40960000, 41006250, 41472000, +41943040, 41990400, 42187500, 42467328, 42515280, 43200000, 43740000, 44236800, 44286750, +44789760, 45000000, 45349632, 45562500, 46080000, 46656000, 46875000, 47185920, 47239200, +47775744, 47829690, 48000000, 48600000, 48828125, 49152000, 49207500, 49766400, 50000000, +50331648, 50388480, 50625000, 51018336, 51200000, 51840000, 52428800, 52488000, 52734375, +53084160, 53144100, 53747712, 54000000, 54675000, 55296000, 55987200, 56250000, 56623104, +56687040, 56953125, 57600000, 58320000, 58593750, 58982400, 59049000, 59719680, 60000000, +60466176, 60750000, 61440000, 61509375, 62208000, 62500000, 62914560, 62985600, 63281250, +63700992, 63772920, 64000000, 64800000, 65536000, 65610000, 66355200, 66430125, 67108864, +67184640, 67500000, 68024448, 68343750, 69120000, 69984000, 70312500, 70778880, 70858800, +71663616, 72000000, 72900000, 73728000, 73811250, 74649600, 75000000, 75497472, 75582720, +75937500, 76527504, 76800000, 77760000, 78125000, 78643200, 78732000, 79626240, 79716150, +80000000, 80621568, 81000000, 81920000, 82012500, 82944000, 83886080, 83980800, 84375000, +84934656, 85030560, 86400000, 87480000, 87890625, 88473600, 88573500, 89579520, 90000000, +90699264, 91125000, 92160000, 93312000, 93750000, 94371840, 94478400, 94921875, 95551488, +95659380, 96000000, 97200000, 97656250, 98304000, 98415000, 99532800, 100000000, +100663296, 100776960, 101250000, 102036672, 102400000, 102515625, 103680000, 104857600, +104976000, 105468750, 106168320, 106288200, 107495424, 108000000, 109350000, 110592000, +110716875, 111974400, 112500000, 113246208, 113374080, 113906250, 115200000, 116640000, +117187500, 117964800, 118098000, 119439360, 119574225, 120000000, 120932352, 121500000, +122880000, 123018750, 124416000, 125000000, 125829120, 125971200, 126562500, 127401984, +127545840, 128000000, 129600000, 131072000, 131220000, 132710400, 132860250, 134217728, +134369280, 135000000, 136048896, 136687500, 138240000, 139968000, 140625000, 141557760, +141717600, 143327232, 144000000, 145800000, 146484375, 147456000, 147622500, 149299200, +150000000, 150994944, 151165440, 151875000, 153055008, 153600000, 155520000, 156250000, +157286400, 157464000, 158203125, 159252480, 159432300, 160000000, 161243136, 162000000, +163840000, 164025000, 165888000, 167772160, 167961600, 168750000, 169869312, 170061120, +170859375, 172800000, 174960000, 175781250, 176947200, 177147000, 179159040, 180000000, +181398528, 182250000, 184320000, 184528125, 186624000, 187500000, 188743680, 188956800, +189843750, 191102976, 191318760, 192000000, 194400000, 195312500, 196608000, 196830000, +199065600, 199290375, 200000000, 201326592, 201553920, 202500000, 204073344, 204800000, +205031250, 207360000, 209715200, 209952000, 210937500, 212336640, 212576400, 214990848, +216000000, 218700000, 221184000, 221433750, 223948800, 225000000, 226492416, 226748160, +227812500, 230400000, 233280000, 234375000, 235929600, 236196000, 238878720, 239148450, +240000000, 241864704, 243000000, 244140625, 245760000, 246037500, 248832000, 250000000, +251658240, 251942400, 253125000, 254803968, 255091680, 256000000, 259200000, 262144000, +262440000, 263671875, 265420800, 265720500, 268435456, 268738560, 270000000, 272097792, +273375000, 276480000, 279936000, 281250000, 283115520, 283435200, 284765625, 286654464, +288000000, 291600000, 292968750, 294912000, 295245000, 298598400, 300000000, 301989888, +302330880, 303750000, 306110016, 307200000, 307546875, 311040000, 312500000, 314572800, +314928000, 316406250, 318504960, 318864600, 320000000, 322486272, 324000000, 327680000, +328050000, 331776000, 332150625, 335544320, 335923200, 337500000, 339738624, 340122240, +341718750, 345600000, 349920000, 351562500, 353894400, 354294000, 358318080, 360000000, +362797056, 364500000, 368640000, 369056250, 373248000, 375000000, 377487360, 377913600, +379687500, 382205952, 382637520, 384000000, 388800000, 390625000, 393216000, 393660000, +398131200, 398580750, 400000000, 402653184, 403107840, 405000000, 408146688, 409600000, +410062500, 414720000, 419430400, 419904000, 421875000, 424673280, 425152800, 429981696, +432000000, 437400000, 439453125, 442368000, 442867500, 447897600, 450000000, 452984832, +453496320, 455625000, 460800000, 466560000, 468750000, 471859200, 472392000, 474609375, +477757440, 478296900, 480000000, 483729408, 486000000, 488281250, 491520000, 492075000, +497664000, 500000000, 503316480, 503884800, 506250000, 509607936, 510183360, 512000000, +512578125, 518400000, 524288000, 524880000, 527343750, 530841600, 531441000, 536870912, +537477120, 540000000, 544195584, 546750000, 552960000, 553584375, 559872000, 562500000, +566231040, 566870400, 569531250, 573308928, 576000000, 583200000, 585937500, 589824000, +590490000, 597196800, 597871125, 600000000, 603979776, 604661760, 607500000, 612220032, +614400000, 615093750, 622080000, 625000000, 629145600, 629856000, 632812500, 637009920, +637729200, 640000000, 644972544, 648000000, 655360000, 656100000, 663552000, 664301250, +671088640, 671846400, 675000000, 679477248, 680244480, 683437500, 691200000, 699840000, +703125000, 707788800, 708588000, 716636160, 720000000, 725594112, 729000000, 732421875, +737280000, 738112500, 746496000, 750000000, 754974720, 755827200, 759375000, 764411904, +765275040, 768000000, 777600000, 781250000, 786432000, 787320000, 791015625, 796262400, +797161500, 800000000, 805306368, 806215680, 810000000, 816293376, 819200000, 820125000, +829440000, 838860800, 839808000, 843750000, 849346560, 850305600, 854296875, 859963392, +864000000, 874800000, 878906250, 884736000, 885735000, 895795200, 900000000, 905969664, +906992640, 911250000, 921600000, 922640625, 933120000, 937500000, 943718400, 944784000, +949218750, 955514880, 956593800, 960000000, 967458816, 972000000, 976562500, 983040000, +984150000, 995328000, 996451875, 1000000000, 1006632960, 1007769600, 1012500000, +1019215872, 1020366720, 1024000000, 1025156250, 1036800000, 1048576000, 1049760000, +1054687500, 1061683200, 1062882000, 1073741824, 1074954240, 1080000000, 1088391168, +1093500000, 1105920000, 1107168750, 1119744000, 1125000000, 1132462080, 1133740800, +1139062500, 1146617856, 1152000000, 1166400000, 1171875000, 1179648000, 1180980000, +1194393600, 1195742250, 1200000000, 1207959552, 1209323520, 1215000000, 1220703125, +1224440064, 1228800000, 1230187500, 1244160000, 1250000000, 1258291200, 1259712000, +1265625000, 1274019840, 1275458400, 1280000000, 1289945088, 1296000000, 1310720000, +1312200000, 1318359375, 1327104000, 1328602500, 1342177280, 1343692800, 1350000000, +1358954496, 1360488960, 1366875000, 1382400000, 1399680000, 1406250000, 1415577600, +1417176000, 1423828125, 1433272320, 1440000000, 1451188224, 1458000000, 1464843750, +1474560000, 1476225000, 1492992000, 1500000000, 1509949440, 1511654400, 1518750000, +1528823808, 1530550080, 1536000000, 1537734375, 1555200000, 1562500000, 1572864000, +1574640000, 1582031250, 1592524800, 1594323000, 1600000000, 1610612736, 1612431360, +1620000000, 1632586752, 1638400000, 1640250000, 1658880000, 1660753125, 1677721600, +1679616000, 1687500000, 1698693120, 1700611200, 1708593750, 1719926784, 1728000000, +1749600000, 1757812500, 1769472000, 1771470000, 1791590400, 1800000000, 1811939328, +1813985280, 1822500000, 1843200000, 1845281250, 1866240000, 1875000000, 1887436800, +1889568000, 1898437500, 1911029760, 1913187600, 1920000000, 1934917632, 1944000000, +1953125000, 1966080000, 1968300000, 1990656000, 1992903750, 2000000000, 2013265920, +2015539200, 2025000000, 2038431744, 2040733440, 2048000000, 2050312500, 2073600000, +2097152000, 2099520000, 2109375000, 2123366400, 2125764000 +}; + +} + +int cv::getOptimalDFTSize( int size0 ) +{ + int a = 0, b = sizeof(optimalDFTSizeTab)/sizeof(optimalDFTSizeTab[0]) - 1; + if( (unsigned)size0 >= (unsigned)optimalDFTSizeTab[b] ) + return -1; + + while( a < b ) + { + int c = (a + b) >> 1; + if( size0 <= optimalDFTSizeTab[c] ) + b = c; + else + a = c+1; + } + + return optimalDFTSizeTab[b]; +} + +CV_IMPL void +cvDFT( const CvArr* srcarr, CvArr* dstarr, int flags, int nonzero_rows ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst0 = cv::cvarrToMat(dstarr), dst = dst0; + int _flags = ((flags & CV_DXT_INVERSE) ? cv::DFT_INVERSE : 0) | + ((flags & CV_DXT_SCALE) ? cv::DFT_SCALE : 0) | + ((flags & CV_DXT_ROWS) ? cv::DFT_ROWS : 0); + + CV_Assert( src.size == dst.size ); + + if( src.type() != dst.type() ) + { + if( dst.channels() == 2 ) + _flags |= cv::DFT_COMPLEX_OUTPUT; + else + _flags |= cv::DFT_REAL_OUTPUT; + } + + cv::dft( src, dst, _flags, nonzero_rows ); + CV_Assert( dst.data == dst0.data ); // otherwise it means that the destination size or type was incorrect +} + + +CV_IMPL void +cvMulSpectrums( const CvArr* srcAarr, const CvArr* srcBarr, + CvArr* dstarr, int flags ) +{ + cv::Mat srcA = cv::cvarrToMat(srcAarr), + srcB = cv::cvarrToMat(srcBarr), + dst = cv::cvarrToMat(dstarr); + CV_Assert( srcA.size == dst.size && srcA.type() == dst.type() ); + + cv::mulSpectrums(srcA, srcB, dst, + (flags & CV_DXT_ROWS) ? cv::DFT_ROWS : 0, + (flags & CV_DXT_MUL_CONJ) != 0 ); +} + + +CV_IMPL void +cvDCT( const CvArr* srcarr, CvArr* dstarr, int flags ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + CV_Assert( src.size == dst.size && src.type() == dst.type() ); + int _flags = ((flags & CV_DXT_INVERSE) ? cv::DCT_INVERSE : 0) | + ((flags & CV_DXT_ROWS) ? cv::DCT_ROWS : 0); + cv::dct( src, dst, _flags ); +} + + +CV_IMPL int +cvGetOptimalDFTSize( int size0 ) +{ + return cv::getOptimalDFTSize(size0); +} + +/* End of file. */ diff --git a/core/src/gpumat.cpp b/core/src/gpumat.cpp new file mode 100644 index 0000000..07d7363 --- /dev/null +++ b/core/src/gpumat.cpp @@ -0,0 +1,1457 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include "opencv2/core/gpumat.hpp" +#include + +#ifdef HAVE_CUDA + #include + #include + #include + + #define CUDART_MINIMUM_REQUIRED_VERSION 4010 + #define NPP_MINIMUM_REQUIRED_VERSION 4100 + + #if (CUDART_VERSION < CUDART_MINIMUM_REQUIRED_VERSION) + #error "Insufficient Cuda Runtime library version, please update it." + #endif + + #if (NPP_VERSION_MAJOR * 1000 + NPP_VERSION_MINOR * 100 + NPP_VERSION_BUILD < NPP_MINIMUM_REQUIRED_VERSION) + #error "Insufficient NPP version, please update it." + #endif +#endif + +using namespace std; +using namespace cv; +using namespace cv::gpu; + +//////////////////////////////// Initialization & Info //////////////////////// + +namespace +{ + // Compares value to set using the given comparator. Returns true if + // there is at least one element x in the set satisfying to: x cmp value + // predicate. + template + bool compareToSet(const std::string& set_as_str, int value, Comparer cmp) + { + if (set_as_str.find_first_not_of(" ") == string::npos) + return false; + + std::stringstream stream(set_as_str); + int cur_value; + + while (!stream.eof()) + { + stream >> cur_value; + if (cmp(cur_value, value)) + return true; + } + + return false; + } +} + +bool cv::gpu::TargetArchs::builtWith(cv::gpu::FeatureSet feature_set) +{ +#ifdef HAVE_CUDA + return ::compareToSet(CUDA_ARCH_FEATURES, feature_set, std::greater_equal()); +#else + (void)feature_set; + return false; +#endif +} + +bool cv::gpu::TargetArchs::has(int major, int minor) +{ + return hasPtx(major, minor) || hasBin(major, minor); +} + +bool cv::gpu::TargetArchs::hasPtx(int major, int minor) +{ +#ifdef HAVE_CUDA + return ::compareToSet(CUDA_ARCH_PTX, major * 10 + minor, std::equal_to()); +#else + (void)major; + (void)minor; + return false; +#endif +} + +bool cv::gpu::TargetArchs::hasBin(int major, int minor) +{ +#if defined (HAVE_CUDA) + return ::compareToSet(CUDA_ARCH_BIN, major * 10 + minor, std::equal_to()); +#else + (void)major; + (void)minor; + return false; +#endif +} + +bool cv::gpu::TargetArchs::hasEqualOrLessPtx(int major, int minor) +{ +#ifdef HAVE_CUDA + return ::compareToSet(CUDA_ARCH_PTX, major * 10 + minor, + std::less_equal()); +#else + (void)major; + (void)minor; + return false; +#endif +} + +bool cv::gpu::TargetArchs::hasEqualOrGreater(int major, int minor) +{ + return hasEqualOrGreaterPtx(major, minor) || + hasEqualOrGreaterBin(major, minor); +} + +bool cv::gpu::TargetArchs::hasEqualOrGreaterPtx(int major, int minor) +{ +#ifdef HAVE_CUDA + return ::compareToSet(CUDA_ARCH_PTX, major * 10 + minor, + std::greater_equal()); +#else + (void)major; + (void)minor; + return false; +#endif +} + +bool cv::gpu::TargetArchs::hasEqualOrGreaterBin(int major, int minor) +{ +#ifdef HAVE_CUDA + return ::compareToSet(CUDA_ARCH_BIN, major * 10 + minor, + std::greater_equal()); +#else + (void)major; + (void)minor; + return false; +#endif +} + +#ifndef HAVE_CUDA + +#define throw_nogpu CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support") + +int cv::gpu::getCudaEnabledDeviceCount() { return 0; } + +void cv::gpu::setDevice(int) { throw_nogpu; } +int cv::gpu::getDevice() { throw_nogpu; return 0; } + +void cv::gpu::resetDevice() { throw_nogpu; } + +size_t cv::gpu::DeviceInfo::freeMemory() const { throw_nogpu; return 0; } +size_t cv::gpu::DeviceInfo::totalMemory() const { throw_nogpu; return 0; } + +bool cv::gpu::DeviceInfo::supports(cv::gpu::FeatureSet) const { throw_nogpu; return false; } + +bool cv::gpu::DeviceInfo::isCompatible() const { throw_nogpu; return false; } + +void cv::gpu::DeviceInfo::query() { throw_nogpu; } +void cv::gpu::DeviceInfo::queryMemory(size_t&, size_t&) const { throw_nogpu; } + +void cv::gpu::printCudaDeviceInfo(int) { throw_nogpu; } +void cv::gpu::printShortCudaDeviceInfo(int) { throw_nogpu; } + +#undef throw_nogpu + +#else // HAVE_CUDA + +namespace +{ +#if defined(__GNUC__) + #define cudaSafeCall(expr) ___cudaSafeCall(expr, __FILE__, __LINE__, __func__) + #define nppSafeCall(expr) ___nppSafeCall(expr, __FILE__, __LINE__, __func__) +#else /* defined(__CUDACC__) || defined(__MSVC__) */ + #define cudaSafeCall(expr) ___cudaSafeCall(expr, __FILE__, __LINE__) + #define nppSafeCall(expr) ___nppSafeCall(expr, __FILE__, __LINE__) +#endif + + inline void ___cudaSafeCall(cudaError_t err, const char *file, const int line, const char *func = "") + { + if (cudaSuccess != err) + cv::gpu::error(cudaGetErrorString(err), file, line, func); + } + + inline void ___nppSafeCall(int err, const char *file, const int line, const char *func = "") + { + if (err < 0) + { + std::ostringstream msg; + msg << "NPP API Call Error: " << err; + cv::gpu::error(msg.str().c_str(), file, line, func); + } + } +} + +int cv::gpu::getCudaEnabledDeviceCount() +{ + int count; + cudaError_t error = cudaGetDeviceCount( &count ); + + if (error == cudaErrorInsufficientDriver) + return -1; + + if (error == cudaErrorNoDevice) + return 0; + + cudaSafeCall(error); + return count; +} + +void cv::gpu::setDevice(int device) +{ + cudaSafeCall( cudaSetDevice( device ) ); +} + +int cv::gpu::getDevice() +{ + int device; + cudaSafeCall( cudaGetDevice( &device ) ); + return device; +} + +void cv::gpu::resetDevice() +{ + cudaSafeCall( cudaDeviceReset() ); +} + +size_t cv::gpu::DeviceInfo::freeMemory() const +{ + size_t free_memory, total_memory; + queryMemory(free_memory, total_memory); + return free_memory; +} + +size_t cv::gpu::DeviceInfo::totalMemory() const +{ + size_t free_memory, total_memory; + queryMemory(free_memory, total_memory); + return total_memory; +} + +bool cv::gpu::DeviceInfo::supports(cv::gpu::FeatureSet feature_set) const +{ + int version = majorVersion() * 10 + minorVersion(); + return version >= feature_set; +} + +bool cv::gpu::DeviceInfo::isCompatible() const +{ + // Check PTX compatibility + if (TargetArchs::hasEqualOrLessPtx(majorVersion(), minorVersion())) + return true; + + // Check BIN compatibility + for (int i = minorVersion(); i >= 0; --i) + if (TargetArchs::hasBin(majorVersion(), i)) + return true; + + return false; +} + +void cv::gpu::DeviceInfo::query() +{ + cudaDeviceProp prop; + cudaSafeCall(cudaGetDeviceProperties(&prop, device_id_)); + name_ = prop.name; + multi_processor_count_ = prop.multiProcessorCount; + majorVersion_ = prop.major; + minorVersion_ = prop.minor; + sharedMemPerBlock_ = prop.sharedMemPerBlock; +} + +void cv::gpu::DeviceInfo::queryMemory(size_t& free_memory, size_t& total_memory) const +{ + int prev_device_id = getDevice(); + if (prev_device_id != device_id_) + setDevice(device_id_); + + cudaSafeCall(cudaMemGetInfo(&free_memory, &total_memory)); + + if (prev_device_id != device_id_) + setDevice(prev_device_id); +} + +namespace +{ + template void getCudaAttribute(T *attribute, CUdevice_attribute device_attribute, int device) + { + *attribute = T(); + //CUresult error = CUDA_SUCCESS;// = cuDeviceGetAttribute( attribute, device_attribute, device ); why link erros under ubuntu?? + CUresult error = cuDeviceGetAttribute( attribute, device_attribute, device ); + if( CUDA_SUCCESS == error ) + return; + + printf("Driver API error = %04d\n", error); + cv::gpu::error("driver API error", __FILE__, __LINE__); + } + + int convertSMVer2Cores(int major, int minor) + { + // Defines for GPU Architecture types (using the SM version to determine the # of cores per SM + typedef struct { + int SM; // 0xMm (hexidecimal notation), M = SM Major version, and m = SM minor version + int Cores; + } SMtoCores; + + SMtoCores gpuArchCoresPerSM[] = { { 0x10, 8 }, { 0x11, 8 }, { 0x12, 8 }, { 0x13, 8 }, { 0x20, 32 }, { 0x21, 48 }, {0x30, 192}, { -1, -1 } }; + + int index = 0; + while (gpuArchCoresPerSM[index].SM != -1) + { + if (gpuArchCoresPerSM[index].SM == ((major << 4) + minor) ) + return gpuArchCoresPerSM[index].Cores; + index++; + } + printf("MapSMtoCores undefined SMversion %d.%d!\n", major, minor); + return -1; + } +} + +void cv::gpu::printCudaDeviceInfo(int device) +{ + int count = getCudaEnabledDeviceCount(); + bool valid = (device >= 0) && (device < count); + + int beg = valid ? device : 0; + int end = valid ? device+1 : count; + + printf("*** CUDA Device Query (Runtime API) version (CUDART static linking) *** \n\n"); + printf("Device count: %d\n", count); + + int driverVersion = 0, runtimeVersion = 0; + cudaSafeCall( cudaDriverGetVersion(&driverVersion) ); + cudaSafeCall( cudaRuntimeGetVersion(&runtimeVersion) ); + + const char *computeMode[] = { + "Default (multiple host threads can use ::cudaSetDevice() with device simultaneously)", + "Exclusive (only one host thread in one process is able to use ::cudaSetDevice() with this device)", + "Prohibited (no host thread can use ::cudaSetDevice() with this device)", + "Exclusive Process (many threads in one process is able to use ::cudaSetDevice() with this device)", + "Unknown", + NULL + }; + + for(int dev = beg; dev < end; ++dev) + { + cudaDeviceProp prop; + cudaSafeCall( cudaGetDeviceProperties(&prop, dev) ); + + printf("\nDevice %d: \"%s\"\n", dev, prop.name); + printf(" CUDA Driver Version / Runtime Version %d.%d / %d.%d\n", driverVersion/1000, driverVersion%100, runtimeVersion/1000, runtimeVersion%100); + printf(" CUDA Capability Major/Minor version number: %d.%d\n", prop.major, prop.minor); + printf(" Total amount of global memory: %.0f MBytes (%llu bytes)\n", (float)prop.totalGlobalMem/1048576.0f, (unsigned long long) prop.totalGlobalMem); + printf(" (%2d) Multiprocessors x (%2d) CUDA Cores/MP: %d CUDA Cores\n", + prop.multiProcessorCount, convertSMVer2Cores(prop.major, prop.minor), + convertSMVer2Cores(prop.major, prop.minor) * prop.multiProcessorCount); + printf(" GPU Clock Speed: %.2f GHz\n", prop.clockRate * 1e-6f); + + // This is not available in the CUDA Runtime API, so we make the necessary calls the driver API to support this for output + int memoryClock, memBusWidth, L2CacheSize; + getCudaAttribute( &memoryClock, CU_DEVICE_ATTRIBUTE_MEMORY_CLOCK_RATE, dev ); + getCudaAttribute( &memBusWidth, CU_DEVICE_ATTRIBUTE_GLOBAL_MEMORY_BUS_WIDTH, dev ); + getCudaAttribute( &L2CacheSize, CU_DEVICE_ATTRIBUTE_L2_CACHE_SIZE, dev ); + + printf(" Memory Clock rate: %.2f Mhz\n", memoryClock * 1e-3f); + printf(" Memory Bus Width: %d-bit\n", memBusWidth); + if (L2CacheSize) + printf(" L2 Cache Size: %d bytes\n", L2CacheSize); + + printf(" Max Texture Dimension Size (x,y,z) 1D=(%d), 2D=(%d,%d), 3D=(%d,%d,%d)\n", + prop.maxTexture1D, prop.maxTexture2D[0], prop.maxTexture2D[1], + prop.maxTexture3D[0], prop.maxTexture3D[1], prop.maxTexture3D[2]); + printf(" Max Layered Texture Size (dim) x layers 1D=(%d) x %d, 2D=(%d,%d) x %d\n", + prop.maxTexture1DLayered[0], prop.maxTexture1DLayered[1], + prop.maxTexture2DLayered[0], prop.maxTexture2DLayered[1], prop.maxTexture2DLayered[2]); + + printf(" Total amount of constant memory: %u bytes\n", (int)prop.totalConstMem); + printf(" Total amount of shared memory per block: %u bytes\n", (int)prop.sharedMemPerBlock); + printf(" Total number of registers available per block: %d\n", prop.regsPerBlock); + printf(" Warp size: %d\n", prop.warpSize); + printf(" Maximum number of threads per block: %d\n", prop.maxThreadsPerBlock); + printf(" Maximum sizes of each dimension of a block: %d x %d x %d\n", prop.maxThreadsDim[0], prop.maxThreadsDim[1], prop.maxThreadsDim[2]); + printf(" Maximum sizes of each dimension of a grid: %d x %d x %d\n", prop.maxGridSize[0], prop.maxGridSize[1], prop.maxGridSize[2]); + printf(" Maximum memory pitch: %u bytes\n", (int)prop.memPitch); + printf(" Texture alignment: %u bytes\n", (int)prop.textureAlignment); + + printf(" Concurrent copy and execution: %s with %d copy engine(s)\n", (prop.deviceOverlap ? "Yes" : "No"), prop.asyncEngineCount); + printf(" Run time limit on kernels: %s\n", prop.kernelExecTimeoutEnabled ? "Yes" : "No"); + printf(" Integrated GPU sharing Host Memory: %s\n", prop.integrated ? "Yes" : "No"); + printf(" Support host page-locked memory mapping: %s\n", prop.canMapHostMemory ? "Yes" : "No"); + + printf(" Concurrent kernel execution: %s\n", prop.concurrentKernels ? "Yes" : "No"); + printf(" Alignment requirement for Surfaces: %s\n", prop.surfaceAlignment ? "Yes" : "No"); + printf(" Device has ECC support enabled: %s\n", prop.ECCEnabled ? "Yes" : "No"); + printf(" Device is using TCC driver mode: %s\n", prop.tccDriver ? "Yes" : "No"); + printf(" Device supports Unified Addressing (UVA): %s\n", prop.unifiedAddressing ? "Yes" : "No"); + printf(" Device PCI Bus ID / PCI location ID: %d / %d\n", prop.pciBusID, prop.pciDeviceID ); + printf(" Compute Mode:\n"); + printf(" %s \n", computeMode[prop.computeMode]); + } + + printf("\n"); + printf("deviceQuery, CUDA Driver = CUDART"); + printf(", CUDA Driver Version = %d.%d", driverVersion / 1000, driverVersion % 100); + printf(", CUDA Runtime Version = %d.%d", runtimeVersion/1000, runtimeVersion%100); + printf(", NumDevs = %d\n\n", count); + fflush(stdout); +} + +void cv::gpu::printShortCudaDeviceInfo(int device) +{ + int count = getCudaEnabledDeviceCount(); + bool valid = (device >= 0) && (device < count); + + int beg = valid ? device : 0; + int end = valid ? device+1 : count; + + int driverVersion = 0, runtimeVersion = 0; + cudaSafeCall( cudaDriverGetVersion(&driverVersion) ); + cudaSafeCall( cudaRuntimeGetVersion(&runtimeVersion) ); + + for(int dev = beg; dev < end; ++dev) + { + cudaDeviceProp prop; + cudaSafeCall( cudaGetDeviceProperties(&prop, dev) ); + + const char *arch_str = prop.major < 2 ? " (not Fermi)" : ""; + printf("Device %d: \"%s\" %.0fMb", dev, prop.name, (float)prop.totalGlobalMem/1048576.0f); + printf(", sm_%d%d%s, %d cores", prop.major, prop.minor, arch_str, convertSMVer2Cores(prop.major, prop.minor) * prop.multiProcessorCount); + printf(", Driver/Runtime ver.%d.%d/%d.%d\n", driverVersion/1000, driverVersion%100, runtimeVersion/1000, runtimeVersion%100); + } + fflush(stdout); +} + +#endif // HAVE_CUDA + +//////////////////////////////// GpuMat /////////////////////////////// + +cv::gpu::GpuMat::GpuMat(const GpuMat& m) + : flags(m.flags), rows(m.rows), cols(m.cols), step(m.step), data(m.data), refcount(m.refcount), datastart(m.datastart), dataend(m.dataend) +{ + if (refcount) + CV_XADD(refcount, 1); +} + +cv::gpu::GpuMat::GpuMat(int rows_, int cols_, int type_, void* data_, size_t step_) : + flags(Mat::MAGIC_VAL + (type_ & TYPE_MASK)), rows(rows_), cols(cols_), + step(step_), data((uchar*)data_), refcount(0), + datastart((uchar*)data_), dataend((uchar*)data_) +{ + size_t minstep = cols * elemSize(); + + if (step == Mat::AUTO_STEP) + { + step = minstep; + flags |= Mat::CONTINUOUS_FLAG; + } + else + { + if (rows == 1) + step = minstep; + + CV_DbgAssert(step >= minstep); + + flags |= step == minstep ? Mat::CONTINUOUS_FLAG : 0; + } + dataend += step * (rows - 1) + minstep; +} + +cv::gpu::GpuMat::GpuMat(Size size_, int type_, void* data_, size_t step_) : + flags(Mat::MAGIC_VAL + (type_ & TYPE_MASK)), rows(size_.height), cols(size_.width), + step(step_), data((uchar*)data_), refcount(0), + datastart((uchar*)data_), dataend((uchar*)data_) +{ + size_t minstep = cols * elemSize(); + + if (step == Mat::AUTO_STEP) + { + step = minstep; + flags |= Mat::CONTINUOUS_FLAG; + } + else + { + if (rows == 1) + step = minstep; + + CV_DbgAssert(step >= minstep); + + flags |= step == minstep ? Mat::CONTINUOUS_FLAG : 0; + } + dataend += step * (rows - 1) + minstep; +} + +cv::gpu::GpuMat::GpuMat(const GpuMat& m, Range _rowRange, Range _colRange) +{ + flags = m.flags; + step = m.step; refcount = m.refcount; + data = m.data; datastart = m.datastart; dataend = m.dataend; + + if (_rowRange == Range::all()) + rows = m.rows; + else + { + CV_Assert(0 <= _rowRange.start && _rowRange.start <= _rowRange.end && _rowRange.end <= m.rows); + + rows = _rowRange.size(); + data += step*_rowRange.start; + } + + if (_colRange == Range::all()) + cols = m.cols; + else + { + CV_Assert(0 <= _colRange.start && _colRange.start <= _colRange.end && _colRange.end <= m.cols); + + cols = _colRange.size(); + data += _colRange.start*elemSize(); + flags &= cols < m.cols ? ~Mat::CONTINUOUS_FLAG : -1; + } + + if (rows == 1) + flags |= Mat::CONTINUOUS_FLAG; + + if (refcount) + CV_XADD(refcount, 1); + + if (rows <= 0 || cols <= 0) + rows = cols = 0; +} + +cv::gpu::GpuMat::GpuMat(const GpuMat& m, Rect roi) : + flags(m.flags), rows(roi.height), cols(roi.width), + step(m.step), data(m.data + roi.y*step), refcount(m.refcount), + datastart(m.datastart), dataend(m.dataend) +{ + flags &= roi.width < m.cols ? ~Mat::CONTINUOUS_FLAG : -1; + data += roi.x * elemSize(); + + CV_Assert(0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows); + + if (refcount) + CV_XADD(refcount, 1); + + if (rows <= 0 || cols <= 0) + rows = cols = 0; +} + +cv::gpu::GpuMat::GpuMat(const Mat& m) : + flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0) +{ + upload(m); +} + +GpuMat& cv::gpu::GpuMat::operator = (const GpuMat& m) +{ + if (this != &m) + { + GpuMat temp(m); + swap(temp); + } + + return *this; +} + +void cv::gpu::GpuMat::swap(GpuMat& b) +{ + std::swap(flags, b.flags); + std::swap(rows, b.rows); + std::swap(cols, b.cols); + std::swap(step, b.step); + std::swap(data, b.data); + std::swap(datastart, b.datastart); + std::swap(dataend, b.dataend); + std::swap(refcount, b.refcount); +} + +void cv::gpu::GpuMat::locateROI(Size& wholeSize, Point& ofs) const +{ + size_t esz = elemSize(); + ptrdiff_t delta1 = data - datastart; + ptrdiff_t delta2 = dataend - datastart; + + CV_DbgAssert(step > 0); + + if (delta1 == 0) + ofs.x = ofs.y = 0; + else + { + ofs.y = static_cast(delta1 / step); + ofs.x = static_cast((delta1 - step * ofs.y) / esz); + + CV_DbgAssert(data == datastart + ofs.y * step + ofs.x * esz); + } + + size_t minstep = (ofs.x + cols) * esz; + + wholeSize.height = std::max(static_cast((delta2 - minstep) / step + 1), ofs.y + rows); + wholeSize.width = std::max(static_cast((delta2 - step * (wholeSize.height - 1)) / esz), ofs.x + cols); +} + +GpuMat& cv::gpu::GpuMat::adjustROI(int dtop, int dbottom, int dleft, int dright) +{ + Size wholeSize; + Point ofs; + locateROI(wholeSize, ofs); + + size_t esz = elemSize(); + + int row1 = std::max(ofs.y - dtop, 0); + int row2 = std::min(ofs.y + rows + dbottom, wholeSize.height); + + int col1 = std::max(ofs.x - dleft, 0); + int col2 = std::min(ofs.x + cols + dright, wholeSize.width); + + data += (row1 - ofs.y) * step + (col1 - ofs.x) * esz; + rows = row2 - row1; + cols = col2 - col1; + + if (esz * cols == step || rows == 1) + flags |= Mat::CONTINUOUS_FLAG; + else + flags &= ~Mat::CONTINUOUS_FLAG; + + return *this; +} + +GpuMat cv::gpu::GpuMat::reshape(int new_cn, int new_rows) const +{ + GpuMat hdr = *this; + + int cn = channels(); + if (new_cn == 0) + new_cn = cn; + + int total_width = cols * cn; + + if ((new_cn > total_width || total_width % new_cn != 0) && new_rows == 0) + new_rows = rows * total_width / new_cn; + + if (new_rows != 0 && new_rows != rows) + { + int total_size = total_width * rows; + + if (!isContinuous()) + CV_Error(CV_BadStep, "The matrix is not continuous, thus its number of rows can not be changed"); + + if ((unsigned)new_rows > (unsigned)total_size) + CV_Error(CV_StsOutOfRange, "Bad new number of rows"); + + total_width = total_size / new_rows; + + if (total_width * new_rows != total_size) + CV_Error(CV_StsBadArg, "The total number of matrix elements is not divisible by the new number of rows"); + + hdr.rows = new_rows; + hdr.step = total_width * elemSize1(); + } + + int new_width = total_width / new_cn; + + if (new_width * new_cn != total_width) + CV_Error(CV_BadNumChannels, "The total width is not divisible by the new number of channels"); + + hdr.cols = new_width; + hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((new_cn - 1) << CV_CN_SHIFT); + + return hdr; +} + +cv::Mat::Mat(const GpuMat& m) : flags(0), dims(0), rows(0), cols(0), data(0), refcount(0), datastart(0), dataend(0), datalimit(0), allocator(0), size(&rows) +{ + m.download(*this); +} + +namespace +{ + class GpuFuncTable + { + public: + virtual ~GpuFuncTable() {} + + virtual void copy(const Mat& src, GpuMat& dst) const = 0; + virtual void copy(const GpuMat& src, Mat& dst) const = 0; + virtual void copy(const GpuMat& src, GpuMat& dst) const = 0; + + virtual void copyWithMask(const GpuMat& src, GpuMat& dst, const GpuMat& mask) const = 0; + + virtual void convert(const GpuMat& src, GpuMat& dst) const = 0; + virtual void convert(const GpuMat& src, GpuMat& dst, double alpha, double beta) const = 0; + + virtual void setTo(GpuMat& m, Scalar s, const GpuMat& mask) const = 0; + + virtual void mallocPitch(void** devPtr, size_t* step, size_t width, size_t height) const = 0; + virtual void free(void* devPtr) const = 0; + }; +} + +#ifndef HAVE_CUDA + +namespace +{ + class EmptyFuncTable : public GpuFuncTable + { + public: + void copy(const Mat&, GpuMat&) const { CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support"); } + void copy(const GpuMat&, Mat&) const { CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support"); } + void copy(const GpuMat&, GpuMat&) const { CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support"); } + + void copyWithMask(const GpuMat&, GpuMat&, const GpuMat&) const { CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support"); } + + void convert(const GpuMat&, GpuMat&) const { CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support"); } + void convert(const GpuMat&, GpuMat&, double, double) const { CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support"); } + + void setTo(GpuMat&, Scalar, const GpuMat&) const { CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support"); } + + void mallocPitch(void**, size_t*, size_t, size_t) const { CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support"); } + void free(void*) const {} + }; + + const GpuFuncTable* gpuFuncTable() + { + static EmptyFuncTable empty; + return ∅ + } +} + +#else // HAVE_CUDA + +namespace cv { namespace gpu { namespace device +{ + void copyToWithMask_gpu(PtrStepSzb src, PtrStepSzb dst, size_t elemSize1, int cn, PtrStepSzb mask, bool colorMask, cudaStream_t stream); + + template + void set_to_gpu(PtrStepSzb mat, const T* scalar, int channels, cudaStream_t stream); + + template + void set_to_gpu(PtrStepSzb mat, const T* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + + void convert_gpu(PtrStepSzb src, int sdepth, PtrStepSzb dst, int ddepth, double alpha, double beta, cudaStream_t stream); +}}} + +namespace +{ + template void kernelSetCaller(GpuMat& src, Scalar s, cudaStream_t stream) + { + Scalar_ sf = s; + cv::gpu::device::set_to_gpu(src, sf.val, src.channels(), stream); + } + + template void kernelSetCaller(GpuMat& src, Scalar s, const GpuMat& mask, cudaStream_t stream) + { + Scalar_ sf = s; + cv::gpu::device::set_to_gpu(src, sf.val, mask, src.channels(), stream); + } +} + + +namespace cv { namespace gpu +{ + CV_EXPORTS void copyWithMask(const cv::gpu::GpuMat&, cv::gpu::GpuMat&, const cv::gpu::GpuMat&, CUstream_st*); + CV_EXPORTS void convertTo(const cv::gpu::GpuMat&, cv::gpu::GpuMat&); + CV_EXPORTS void convertTo(const cv::gpu::GpuMat&, cv::gpu::GpuMat&, double, double, CUstream_st*); + CV_EXPORTS void setTo(cv::gpu::GpuMat&, cv::Scalar, CUstream_st*); + CV_EXPORTS void setTo(cv::gpu::GpuMat&, cv::Scalar, const cv::gpu::GpuMat&, CUstream_st*); + CV_EXPORTS void setTo(cv::gpu::GpuMat&, cv::Scalar); + CV_EXPORTS void setTo(cv::gpu::GpuMat&, cv::Scalar, const cv::gpu::GpuMat&); +}} + + +namespace cv { namespace gpu +{ + void copyWithMask(const GpuMat& src, GpuMat& dst, const GpuMat& mask, cudaStream_t stream = 0) + { + CV_Assert(src.size() == dst.size() && src.type() == dst.type()); + CV_Assert(src.size() == mask.size() && mask.depth() == CV_8U && (mask.channels() == 1 || mask.channels() == src.channels())); + + cv::gpu::device::copyToWithMask_gpu(src.reshape(1), dst.reshape(1), src.elemSize1(), src.channels(), mask.reshape(1), mask.channels() != 1, stream); + } + + void convertTo(const GpuMat& src, GpuMat& dst) + { + cv::gpu::device::convert_gpu(src.reshape(1), src.depth(), dst.reshape(1), dst.depth(), 1.0, 0.0, 0); + } + + void convertTo(const GpuMat& src, GpuMat& dst, double alpha, double beta, cudaStream_t stream = 0) + { + cv::gpu::device::convert_gpu(src.reshape(1), src.depth(), dst.reshape(1), dst.depth(), alpha, beta, stream); + } + + void setTo(GpuMat& src, Scalar s, cudaStream_t stream) + { + typedef void (*caller_t)(GpuMat& src, Scalar s, cudaStream_t stream); + + static const caller_t callers[] = + { + kernelSetCaller, kernelSetCaller, kernelSetCaller, kernelSetCaller, kernelSetCaller, + kernelSetCaller, kernelSetCaller + }; + + callers[src.depth()](src, s, stream); + } + + void setTo(GpuMat& src, Scalar s, const GpuMat& mask, cudaStream_t stream) + { + typedef void (*caller_t)(GpuMat& src, Scalar s, const GpuMat& mask, cudaStream_t stream); + + static const caller_t callers[] = + { + kernelSetCaller, kernelSetCaller, kernelSetCaller, kernelSetCaller, kernelSetCaller, + kernelSetCaller, kernelSetCaller + }; + + callers[src.depth()](src, s, mask, stream); + } + + void setTo(GpuMat& src, Scalar s) + { + setTo(src, s, 0); + } + + void setTo(GpuMat& src, Scalar s, const GpuMat& mask) + { + setTo(src, s, mask, 0); + } +}} + +namespace +{ + template struct NPPTypeTraits; + template<> struct NPPTypeTraits { typedef Npp8u npp_type; }; + template<> struct NPPTypeTraits { typedef Npp8s npp_type; }; + template<> struct NPPTypeTraits { typedef Npp16u npp_type; }; + template<> struct NPPTypeTraits { typedef Npp16s npp_type; }; + template<> struct NPPTypeTraits { typedef Npp32s npp_type; }; + template<> struct NPPTypeTraits { typedef Npp32f npp_type; }; + template<> struct NPPTypeTraits { typedef Npp64f npp_type; }; + + ////////////////////////////////////////////////////////////////////////// + // Convert + + template struct NppConvertFunc + { + typedef typename NPPTypeTraits::npp_type src_t; + typedef typename NPPTypeTraits::npp_type dst_t; + + typedef NppStatus (*func_ptr)(const src_t* pSrc, int nSrcStep, dst_t* pDst, int nDstStep, NppiSize oSizeROI); + }; + template struct NppConvertFunc + { + typedef typename NPPTypeTraits::npp_type dst_t; + + typedef NppStatus (*func_ptr)(const Npp32f* pSrc, int nSrcStep, dst_t* pDst, int nDstStep, NppiSize oSizeROI, NppRoundMode eRoundMode); + }; + + template::func_ptr func> struct NppCvt + { + typedef typename NPPTypeTraits::npp_type src_t; + typedef typename NPPTypeTraits::npp_type dst_t; + + static void call(const GpuMat& src, GpuMat& dst) + { + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; + + nppSafeCall( func(src.ptr(), static_cast(src.step), dst.ptr(), static_cast(dst.step), sz) ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + }; + template::func_ptr func> struct NppCvt + { + typedef typename NPPTypeTraits::npp_type dst_t; + + static void call(const GpuMat& src, GpuMat& dst) + { + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; + + nppSafeCall( func(src.ptr(), static_cast(src.step), dst.ptr(), static_cast(dst.step), sz, NPP_RND_NEAR) ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // Set + + template struct NppSetFunc + { + typedef typename NPPTypeTraits::npp_type src_t; + + typedef NppStatus (*func_ptr)(const src_t values[], src_t* pSrc, int nSrcStep, NppiSize oSizeROI); + }; + template struct NppSetFunc + { + typedef typename NPPTypeTraits::npp_type src_t; + + typedef NppStatus (*func_ptr)(src_t val, src_t* pSrc, int nSrcStep, NppiSize oSizeROI); + }; + template struct NppSetFunc + { + typedef NppStatus (*func_ptr)(Npp8s values[], Npp8s* pSrc, int nSrcStep, NppiSize oSizeROI); + }; + template<> struct NppSetFunc + { + typedef NppStatus (*func_ptr)(Npp8s val, Npp8s* pSrc, int nSrcStep, NppiSize oSizeROI); + }; + + template::func_ptr func> struct NppSet + { + typedef typename NPPTypeTraits::npp_type src_t; + + static void call(GpuMat& src, Scalar s) + { + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; + + Scalar_ nppS = s; + + nppSafeCall( func(nppS.val, src.ptr(), static_cast(src.step), sz) ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + }; + template::func_ptr func> struct NppSet + { + typedef typename NPPTypeTraits::npp_type src_t; + + static void call(GpuMat& src, Scalar s) + { + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; + + Scalar_ nppS = s; + + nppSafeCall( func(nppS[0], src.ptr(), static_cast(src.step), sz) ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + }; + + template struct NppSetMaskFunc + { + typedef typename NPPTypeTraits::npp_type src_t; + + typedef NppStatus (*func_ptr)(const src_t values[], src_t* pSrc, int nSrcStep, NppiSize oSizeROI, const Npp8u* pMask, int nMaskStep); + }; + template struct NppSetMaskFunc + { + typedef typename NPPTypeTraits::npp_type src_t; + + typedef NppStatus (*func_ptr)(src_t val, src_t* pSrc, int nSrcStep, NppiSize oSizeROI, const Npp8u* pMask, int nMaskStep); + }; + + template::func_ptr func> struct NppSetMask + { + typedef typename NPPTypeTraits::npp_type src_t; + + static void call(GpuMat& src, Scalar s, const GpuMat& mask) + { + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; + + Scalar_ nppS = s; + + nppSafeCall( func(nppS.val, src.ptr(), static_cast(src.step), sz, mask.ptr(), static_cast(mask.step)) ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + }; + template::func_ptr func> struct NppSetMask + { + typedef typename NPPTypeTraits::npp_type src_t; + + static void call(GpuMat& src, Scalar s, const GpuMat& mask) + { + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; + + Scalar_ nppS = s; + + nppSafeCall( func(nppS[0], src.ptr(), static_cast(src.step), sz, mask.ptr(), static_cast(mask.step)) ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // CopyMasked + + template struct NppCopyMaskedFunc + { + typedef typename NPPTypeTraits::npp_type src_t; + + typedef NppStatus (*func_ptr)(const src_t* pSrc, int nSrcStep, src_t* pDst, int nDstStep, NppiSize oSizeROI, const Npp8u* pMask, int nMaskStep); + }; + + template::func_ptr func> struct NppCopyMasked + { + typedef typename NPPTypeTraits::npp_type src_t; + + static void call(const GpuMat& src, GpuMat& dst, const GpuMat& mask, cudaStream_t /*stream*/) + { + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; + + nppSafeCall( func(src.ptr(), static_cast(src.step), dst.ptr(), static_cast(dst.step), sz, mask.ptr(), static_cast(mask.step)) ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + }; + + template static inline bool isAligned(const T* ptr, size_t size) + { + return reinterpret_cast(ptr) % size == 0; + } + + ////////////////////////////////////////////////////////////////////////// + // CudaFuncTable + + class CudaFuncTable : public GpuFuncTable + { + public: + void copy(const Mat& src, GpuMat& dst) const + { + cudaSafeCall( cudaMemcpy2D(dst.data, dst.step, src.data, src.step, src.cols * src.elemSize(), src.rows, cudaMemcpyHostToDevice) ); + } + void copy(const GpuMat& src, Mat& dst) const + { + cudaSafeCall( cudaMemcpy2D(dst.data, dst.step, src.data, src.step, src.cols * src.elemSize(), src.rows, cudaMemcpyDeviceToHost) ); + } + void copy(const GpuMat& src, GpuMat& dst) const + { + cudaSafeCall( cudaMemcpy2D(dst.data, dst.step, src.data, src.step, src.cols * src.elemSize(), src.rows, cudaMemcpyDeviceToDevice) ); + } + + void copyWithMask(const GpuMat& src, GpuMat& dst, const GpuMat& mask) const + { + CV_Assert(src.depth() <= CV_64F && src.channels() <= 4); + CV_Assert(src.size() == dst.size() && src.type() == dst.type()); + CV_Assert(src.size() == mask.size() && mask.depth() == CV_8U && (mask.channels() == 1 || mask.channels() == src.channels())); + + if (src.depth() == CV_64F) + { + if (!TargetArchs::builtWith(NATIVE_DOUBLE) || !DeviceInfo().supports(NATIVE_DOUBLE)) + CV_Error(CV_StsUnsupportedFormat, "The device doesn't support double"); + } + + typedef void (*func_t)(const GpuMat& src, GpuMat& dst, const GpuMat& mask, cudaStream_t stream); + static const func_t funcs[7][4] = + { + /* 8U */ {NppCopyMasked::call, cv::gpu::copyWithMask, NppCopyMasked::call, NppCopyMasked::call}, + /* 8S */ {cv::gpu::copyWithMask , cv::gpu::copyWithMask, cv::gpu::copyWithMask , cv::gpu::copyWithMask }, + /* 16U */ {NppCopyMasked::call, cv::gpu::copyWithMask, NppCopyMasked::call, NppCopyMasked::call}, + /* 16S */ {NppCopyMasked::call, cv::gpu::copyWithMask, NppCopyMasked::call, NppCopyMasked::call}, + /* 32S */ {NppCopyMasked::call, cv::gpu::copyWithMask, NppCopyMasked::call, NppCopyMasked::call}, + /* 32F */ {NppCopyMasked::call, cv::gpu::copyWithMask, NppCopyMasked::call, NppCopyMasked::call}, + /* 64F */ {cv::gpu::copyWithMask , cv::gpu::copyWithMask, cv::gpu::copyWithMask , cv::gpu::copyWithMask } + }; + + const func_t func = mask.channels() == src.channels() ? funcs[src.depth()][src.channels() - 1] : cv::gpu::copyWithMask; + + func(src, dst, mask, 0); + } + + void convert(const GpuMat& src, GpuMat& dst) const + { + typedef void (*func_t)(const GpuMat& src, GpuMat& dst); + static const func_t funcs[7][7][4] = + { + { + /* 8U -> 8U */ {0, 0, 0, 0}, + /* 8U -> 8S */ {cv::gpu::convertTo , cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo }, + /* 8U -> 16U */ {NppCvt::call, cv::gpu::convertTo, cv::gpu::convertTo, NppCvt::call}, + /* 8U -> 16S */ {NppCvt::call, cv::gpu::convertTo, cv::gpu::convertTo, NppCvt::call}, + /* 8U -> 32S */ {cv::gpu::convertTo , cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo }, + /* 8U -> 32F */ {NppCvt::call, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo }, + /* 8U -> 64F */ {cv::gpu::convertTo , cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo } + }, + { + /* 8S -> 8U */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 8S -> 8S */ {0,0,0,0}, + /* 8S -> 16U */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 8S -> 16S */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 8S -> 32S */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 8S -> 32F */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 8S -> 64F */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo} + }, + { + /* 16U -> 8U */ {NppCvt::call, cv::gpu::convertTo, cv::gpu::convertTo, NppCvt::call}, + /* 16U -> 8S */ {cv::gpu::convertTo , cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo }, + /* 16U -> 16U */ {0,0,0,0}, + /* 16U -> 16S */ {cv::gpu::convertTo , cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo }, + /* 16U -> 32S */ {NppCvt::call, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo }, + /* 16U -> 32F */ {NppCvt::call, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo }, + /* 16U -> 64F */ {cv::gpu::convertTo , cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo } + }, + { + /* 16S -> 8U */ {NppCvt::call, cv::gpu::convertTo, cv::gpu::convertTo, NppCvt::call}, + /* 16S -> 8S */ {cv::gpu::convertTo , cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo }, + /* 16S -> 16U */ {cv::gpu::convertTo , cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo }, + /* 16S -> 16S */ {0,0,0,0}, + /* 16S -> 32S */ {NppCvt::call, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo }, + /* 16S -> 32F */ {NppCvt::call, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo }, + /* 16S -> 64F */ {cv::gpu::convertTo , cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo } + }, + { + /* 32S -> 8U */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 32S -> 8S */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 32S -> 16U */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 32S -> 16S */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 32S -> 32S */ {0,0,0,0}, + /* 32S -> 32F */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 32S -> 64F */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo} + }, + { + /* 32F -> 8U */ {NppCvt::call, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 32F -> 8S */ {cv::gpu::convertTo , cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 32F -> 16U */ {NppCvt::call, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 32F -> 16S */ {NppCvt::call, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 32F -> 32S */ {cv::gpu::convertTo , cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 32F -> 32F */ {0,0,0,0}, + /* 32F -> 64F */ {cv::gpu::convertTo , cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo} + }, + { + /* 64F -> 8U */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 64F -> 8S */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 64F -> 16U */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 64F -> 16S */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 64F -> 32S */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 64F -> 32F */ {cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo, cv::gpu::convertTo}, + /* 64F -> 64F */ {0,0,0,0} + } + }; + + CV_Assert(src.depth() <= CV_64F && src.channels() <= 4); + CV_Assert(dst.depth() <= CV_64F); + CV_Assert(src.size() == dst.size() && src.channels() == dst.channels()); + + if (src.depth() == CV_64F || dst.depth() == CV_64F) + { + if (!TargetArchs::builtWith(NATIVE_DOUBLE) || !DeviceInfo().supports(NATIVE_DOUBLE)) + CV_Error(CV_StsUnsupportedFormat, "The device doesn't support double"); + } + + bool aligned = isAligned(src.data, 16) && isAligned(dst.data, 16); + if (!aligned) + { + cv::gpu::convertTo(src, dst); + return; + } + + const func_t func = funcs[src.depth()][dst.depth()][src.channels() - 1]; + CV_DbgAssert(func != 0); + + func(src, dst); + } + + void convert(const GpuMat& src, GpuMat& dst, double alpha, double beta) const + { + CV_Assert(src.depth() <= CV_64F && src.channels() <= 4); + CV_Assert(dst.depth() <= CV_64F); + + if (src.depth() == CV_64F || dst.depth() == CV_64F) + { + if (!TargetArchs::builtWith(NATIVE_DOUBLE) || !DeviceInfo().supports(NATIVE_DOUBLE)) + CV_Error(CV_StsUnsupportedFormat, "The device doesn't support double"); + } + + cv::gpu::convertTo(src, dst, alpha, beta); + } + + void setTo(GpuMat& m, Scalar s, const GpuMat& mask) const + { + if (mask.empty()) + { + if (s[0] == 0.0 && s[1] == 0.0 && s[2] == 0.0 && s[3] == 0.0) + { + cudaSafeCall( cudaMemset2D(m.data, m.step, 0, m.cols * m.elemSize(), m.rows) ); + return; + } + + if (m.depth() == CV_8U) + { + int cn = m.channels(); + + if (cn == 1 || (cn == 2 && s[0] == s[1]) || (cn == 3 && s[0] == s[1] && s[0] == s[2]) || (cn == 4 && s[0] == s[1] && s[0] == s[2] && s[0] == s[3])) + { + int val = saturate_cast(s[0]); + cudaSafeCall( cudaMemset2D(m.data, m.step, val, m.cols * m.elemSize(), m.rows) ); + return; + } + } + + typedef void (*func_t)(GpuMat& src, Scalar s); + static const func_t funcs[7][4] = + { + {NppSet::call, cv::gpu::setTo , cv::gpu::setTo , NppSet::call}, + {NppSet::call, NppSet::call, NppSet::call, NppSet::call}, + {NppSet::call, NppSet::call, cv::gpu::setTo , NppSet::call}, + {NppSet::call, NppSet::call, cv::gpu::setTo , NppSet::call}, + {NppSet::call, cv::gpu::setTo , cv::gpu::setTo , NppSet::call}, + {NppSet::call, cv::gpu::setTo , cv::gpu::setTo , NppSet::call}, + {cv::gpu::setTo , cv::gpu::setTo , cv::gpu::setTo , cv::gpu::setTo } + }; + + CV_Assert(m.depth() <= CV_64F && m.channels() <= 4); + + if (m.depth() == CV_64F) + { + if (!TargetArchs::builtWith(NATIVE_DOUBLE) || !DeviceInfo().supports(NATIVE_DOUBLE)) + CV_Error(CV_StsUnsupportedFormat, "The device doesn't support double"); + } + + funcs[m.depth()][m.channels() - 1](m, s); + } + else + { + typedef void (*func_t)(GpuMat& src, Scalar s, const GpuMat& mask); + static const func_t funcs[7][4] = + { + {NppSetMask::call, cv::gpu::setTo, cv::gpu::setTo, NppSetMask::call}, + {cv::gpu::setTo , cv::gpu::setTo, cv::gpu::setTo, cv::gpu::setTo }, + {NppSetMask::call, cv::gpu::setTo, cv::gpu::setTo, NppSetMask::call}, + {NppSetMask::call, cv::gpu::setTo, cv::gpu::setTo, NppSetMask::call}, + {NppSetMask::call, cv::gpu::setTo, cv::gpu::setTo, NppSetMask::call}, + {NppSetMask::call, cv::gpu::setTo, cv::gpu::setTo, NppSetMask::call}, + {cv::gpu::setTo , cv::gpu::setTo, cv::gpu::setTo, cv::gpu::setTo } + }; + + CV_Assert(m.depth() <= CV_64F && m.channels() <= 4); + + if (m.depth() == CV_64F) + { + if (!TargetArchs::builtWith(NATIVE_DOUBLE) || !DeviceInfo().supports(NATIVE_DOUBLE)) + CV_Error(CV_StsUnsupportedFormat, "The device doesn't support double"); + } + + funcs[m.depth()][m.channels() - 1](m, s, mask); + } + } + + void mallocPitch(void** devPtr, size_t* step, size_t width, size_t height) const + { + cudaSafeCall( cudaMallocPitch(devPtr, step, width, height) ); + } + + void free(void* devPtr) const + { + cudaFree(devPtr); + } + }; + + const GpuFuncTable* gpuFuncTable() + { + static CudaFuncTable funcTable; + return &funcTable; + } +} + +#endif // HAVE_CUDA + +void cv::gpu::GpuMat::upload(const Mat& m) +{ + CV_DbgAssert(!m.empty()); + + create(m.size(), m.type()); + + gpuFuncTable()->copy(m, *this); +} + +void cv::gpu::GpuMat::download(Mat& m) const +{ + CV_DbgAssert(!empty()); + + m.create(size(), type()); + + gpuFuncTable()->copy(*this, m); +} + +void cv::gpu::GpuMat::copyTo(GpuMat& m) const +{ + CV_DbgAssert(!empty()); + + m.create(size(), type()); + + gpuFuncTable()->copy(*this, m); +} + +void cv::gpu::GpuMat::copyTo(GpuMat& mat, const GpuMat& mask) const +{ + if (mask.empty()) + copyTo(mat); + else + { + mat.create(size(), type()); + + gpuFuncTable()->copyWithMask(*this, mat, mask); + } +} + +void cv::gpu::GpuMat::convertTo(GpuMat& dst, int rtype, double alpha, double beta) const +{ + bool noScale = fabs(alpha - 1) < numeric_limits::epsilon() && fabs(beta) < numeric_limits::epsilon(); + + if (rtype < 0) + rtype = type(); + else + rtype = CV_MAKETYPE(CV_MAT_DEPTH(rtype), channels()); + + int sdepth = depth(); + int ddepth = CV_MAT_DEPTH(rtype); + if (sdepth == ddepth && noScale) + { + copyTo(dst); + return; + } + + GpuMat temp; + const GpuMat* psrc = this; + if (sdepth != ddepth && psrc == &dst) + { + temp = *this; + psrc = &temp; + } + + dst.create(size(), rtype); + + if (noScale) + gpuFuncTable()->convert(*psrc, dst); + else + gpuFuncTable()->convert(*psrc, dst, alpha, beta); +} + +GpuMat& cv::gpu::GpuMat::setTo(Scalar s, const GpuMat& mask) +{ + CV_Assert(mask.empty() || mask.type() == CV_8UC1); + CV_DbgAssert(!empty()); + + gpuFuncTable()->setTo(*this, s, mask); + + return *this; +} + +void cv::gpu::GpuMat::create(int _rows, int _cols, int _type) +{ + _type &= TYPE_MASK; + + if (rows == _rows && cols == _cols && type() == _type && data) + return; + + if (data) + release(); + + CV_DbgAssert(_rows >= 0 && _cols >= 0); + + if (_rows > 0 && _cols > 0) + { + flags = Mat::MAGIC_VAL + _type; + rows = _rows; + cols = _cols; + + size_t esz = elemSize(); + + void* devPtr; + gpuFuncTable()->mallocPitch(&devPtr, &step, esz * cols, rows); + + // Single row must be continuous + if (rows == 1) + step = esz * cols; + + if (esz * cols == step) + flags |= Mat::CONTINUOUS_FLAG; + + int64 _nettosize = static_cast(step) * rows; + size_t nettosize = static_cast(_nettosize); + + datastart = data = static_cast(devPtr); + dataend = data + nettosize; + + refcount = static_cast(fastMalloc(sizeof(*refcount))); + *refcount = 1; + } +} + +void cv::gpu::GpuMat::release() +{ + if (refcount && CV_XADD(refcount, -1) == 1) + { + fastFree(refcount); + + gpuFuncTable()->free(datastart); + } + + data = datastart = dataend = 0; + step = rows = cols = 0; + refcount = 0; +} + +//////////////////////////////////////////////////////////////////////// +// Error handling + +void cv::gpu::error(const char *error_string, const char *file, const int line, const char *func) +{ + int code = CV_GpuApiCallError; + + if (uncaught_exception()) + { + const char* errorStr = cvErrorStr(code); + const char* function = func ? func : "unknown function"; + + cerr << "OpenCV Error: " << errorStr << "(" << error_string << ") in " << function << ", file " << file << ", line " << line; + cerr.flush(); + } + else + cv::error( cv::Exception(code, error_string, func, file, line) ); +} diff --git a/core/src/lapack.cpp b/core/src/lapack.cpp new file mode 100644 index 0000000..3f743f7 --- /dev/null +++ b/core/src/lapack.cpp @@ -0,0 +1,1894 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +namespace cv +{ + +/****************************************************************************************\ +* LU & Cholesky implementation for small matrices * +\****************************************************************************************/ + +template static inline int +LUImpl(_Tp* A, size_t astep, int m, _Tp* b, size_t bstep, int n) +{ + int i, j, k, p = 1; + astep /= sizeof(A[0]); + bstep /= sizeof(b[0]); + + for( i = 0; i < m; i++ ) + { + k = i; + + for( j = i+1; j < m; j++ ) + if( std::abs(A[j*astep + i]) > std::abs(A[k*astep + i]) ) + k = j; + + if( std::abs(A[k*astep + i]) < std::numeric_limits<_Tp>::epsilon() ) + return 0; + + if( k != i ) + { + for( j = i; j < m; j++ ) + std::swap(A[i*astep + j], A[k*astep + j]); + if( b ) + for( j = 0; j < n; j++ ) + std::swap(b[i*bstep + j], b[k*bstep + j]); + p = -p; + } + + _Tp d = -1/A[i*astep + i]; + + for( j = i+1; j < m; j++ ) + { + _Tp alpha = A[j*astep + i]*d; + + for( k = i+1; k < m; k++ ) + A[j*astep + k] += alpha*A[i*astep + k]; + + if( b ) + for( k = 0; k < n; k++ ) + b[j*bstep + k] += alpha*b[i*bstep + k]; + } + + A[i*astep + i] = -d; + } + + if( b ) + { + for( i = m-1; i >= 0; i-- ) + for( j = 0; j < n; j++ ) + { + _Tp s = b[i*bstep + j]; + for( k = i+1; k < m; k++ ) + s -= A[i*astep + k]*b[k*bstep + j]; + b[i*bstep + j] = s*A[i*astep + i]; + } + } + + return p; +} + + +int LU(float* A, size_t astep, int m, float* b, size_t bstep, int n) +{ + return LUImpl(A, astep, m, b, bstep, n); +} + + +int LU(double* A, size_t astep, int m, double* b, size_t bstep, int n) +{ + return LUImpl(A, astep, m, b, bstep, n); +} + + +template static inline bool +CholImpl(_Tp* A, size_t astep, int m, _Tp* b, size_t bstep, int n) +{ + _Tp* L = A; + int i, j, k; + double s; + astep /= sizeof(A[0]); + bstep /= sizeof(b[0]); + + for( i = 0; i < m; i++ ) + { + for( j = 0; j < i; j++ ) + { + s = A[i*astep + j]; + for( k = 0; k < j; k++ ) + s -= L[i*astep + k]*L[j*astep + k]; + L[i*astep + j] = (_Tp)(s*L[j*astep + j]); + } + s = A[i*astep + i]; + for( k = 0; k < j; k++ ) + { + double t = L[i*astep + k]; + s -= t*t; + } + if( s < std::numeric_limits<_Tp>::epsilon() ) + return false; + L[i*astep + i] = (_Tp)(1./std::sqrt(s)); + } + + if( !b ) + return true; + + // LLt x = b + // 1: L y = b + // 2. Lt x = y + + /* + [ L00 ] y0 b0 + [ L10 L11 ] y1 = b1 + [ L20 L21 L22 ] y2 b2 + [ L30 L31 L32 L33 ] y3 b3 + + [ L00 L10 L20 L30 ] x0 y0 + [ L11 L21 L31 ] x1 = y1 + [ L22 L32 ] x2 y2 + [ L33 ] x3 y3 + */ + + for( i = 0; i < m; i++ ) + { + for( j = 0; j < n; j++ ) + { + s = b[i*bstep + j]; + for( k = 0; k < i; k++ ) + s -= L[i*astep + k]*b[k*bstep + j]; + b[i*bstep + j] = (_Tp)(s*L[i*astep + i]); + } + } + + for( i = m-1; i >= 0; i-- ) + { + for( j = 0; j < n; j++ ) + { + s = b[i*bstep + j]; + for( k = m-1; k > i; k-- ) + s -= L[k*astep + i]*b[k*bstep + j]; + b[i*bstep + j] = (_Tp)(s*L[i*astep + i]); + } + } + + return true; +} + + +bool Cholesky(float* A, size_t astep, int m, float* b, size_t bstep, int n) +{ + return CholImpl(A, astep, m, b, bstep, n); +} + +bool Cholesky(double* A, size_t astep, int m, double* b, size_t bstep, int n) +{ + return CholImpl(A, astep, m, b, bstep, n); +} + + +template static inline _Tp hypot(_Tp a, _Tp b) +{ + a = std::abs(a); + b = std::abs(b); + if( a > b ) + { + b /= a; + return a*std::sqrt(1 + b*b); + } + if( b > 0 ) + { + a /= b; + return b*std::sqrt(1 + a*a); + } + return 0; +} + + +template bool +JacobiImpl_( _Tp* A, size_t astep, _Tp* W, _Tp* V, size_t vstep, int n, uchar* buf ) +{ + const _Tp eps = std::numeric_limits<_Tp>::epsilon(); + int i, j, k, m; + + astep /= sizeof(A[0]); + if( V ) + { + vstep /= sizeof(V[0]); + for( i = 0; i < n; i++ ) + { + for( j = 0; j < n; j++ ) + V[i*vstep + j] = (_Tp)0; + V[i*vstep + i] = (_Tp)1; + } + } + + int iters, maxIters = n*n*30; + + int* indR = (int*)alignPtr(buf, sizeof(int)); + int* indC = indR + n; + _Tp mv = (_Tp)0; + + for( k = 0; k < n; k++ ) + { + W[k] = A[(astep + 1)*k]; + if( k < n - 1 ) + { + for( m = k+1, mv = std::abs(A[astep*k + m]), i = k+2; i < n; i++ ) + { + _Tp val = std::abs(A[astep*k+i]); + if( mv < val ) + mv = val, m = i; + } + indR[k] = m; + } + if( k > 0 ) + { + for( m = 0, mv = std::abs(A[k]), i = 1; i < k; i++ ) + { + _Tp val = std::abs(A[astep*i+k]); + if( mv < val ) + mv = val, m = i; + } + indC[k] = m; + } + } + + if( n > 1 ) for( iters = 0; iters < maxIters; iters++ ) + { + // find index (k,l) of pivot p + for( k = 0, mv = std::abs(A[indR[0]]), i = 1; i < n-1; i++ ) + { + _Tp val = std::abs(A[astep*i + indR[i]]); + if( mv < val ) + mv = val, k = i; + } + int l = indR[k]; + for( i = 1; i < n; i++ ) + { + _Tp val = std::abs(A[astep*indC[i] + i]); + if( mv < val ) + mv = val, k = indC[i], l = i; + } + + _Tp p = A[astep*k + l]; + if( std::abs(p) <= eps ) + break; + _Tp y = (_Tp)((W[l] - W[k])*0.5); + _Tp t = std::abs(y) + hypot(p, y); + _Tp s = hypot(p, t); + _Tp c = t/s; + s = p/s; t = (p/t)*p; + if( y < 0 ) + s = -s, t = -t; + A[astep*k + l] = 0; + + W[k] -= t; + W[l] += t; + + _Tp a0, b0; + +#undef rotate +#define rotate(v0, v1) a0 = v0, b0 = v1, v0 = a0*c - b0*s, v1 = a0*s + b0*c + + // rotate rows and columns k and l + for( i = 0; i < k; i++ ) + rotate(A[astep*i+k], A[astep*i+l]); + for( i = k+1; i < l; i++ ) + rotate(A[astep*k+i], A[astep*i+l]); + for( i = l+1; i < n; i++ ) + rotate(A[astep*k+i], A[astep*l+i]); + + // rotate eigenvectors + if( V ) + for( i = 0; i < n; i++ ) + rotate(V[vstep*k+i], V[vstep*l+i]); + +#undef rotate + + for( j = 0; j < 2; j++ ) + { + int idx = j == 0 ? k : l; + if( idx < n - 1 ) + { + for( m = idx+1, mv = std::abs(A[astep*idx + m]), i = idx+2; i < n; i++ ) + { + _Tp val = std::abs(A[astep*idx+i]); + if( mv < val ) + mv = val, m = i; + } + indR[idx] = m; + } + if( idx > 0 ) + { + for( m = 0, mv = std::abs(A[idx]), i = 1; i < idx; i++ ) + { + _Tp val = std::abs(A[astep*i+idx]); + if( mv < val ) + mv = val, m = i; + } + indC[idx] = m; + } + } + } + + // sort eigenvalues & eigenvectors + for( k = 0; k < n-1; k++ ) + { + m = k; + for( i = k+1; i < n; i++ ) + { + if( W[m] < W[i] ) + m = i; + } + if( k != m ) + { + std::swap(W[m], W[k]); + if( V ) + for( i = 0; i < n; i++ ) + std::swap(V[vstep*m + i], V[vstep*k + i]); + } + } + + return true; +} + +static bool Jacobi( float* S, size_t sstep, float* e, float* E, size_t estep, int n, uchar* buf ) +{ + return JacobiImpl_(S, sstep, e, E, estep, n, buf); +} + +static bool Jacobi( double* S, size_t sstep, double* e, double* E, size_t estep, int n, uchar* buf ) +{ + return JacobiImpl_(S, sstep, e, E, estep, n, buf); +} + + +template struct VBLAS +{ + int dot(const T*, const T*, int, T*) const { return 0; } + int givens(T*, T*, int, T, T) const { return 0; } + int givensx(T*, T*, int, T, T, T*, T*) const { return 0; } +}; + +#if CV_SSE2 +template<> inline int VBLAS::dot(const float* a, const float* b, int n, float* result) const +{ + if( n < 8 ) + return 0; + int k = 0; + __m128 s0 = _mm_setzero_ps(), s1 = _mm_setzero_ps(); + for( ; k <= n - 8; k += 8 ) + { + __m128 a0 = _mm_load_ps(a + k), a1 = _mm_load_ps(a + k + 4); + __m128 b0 = _mm_load_ps(b + k), b1 = _mm_load_ps(b + k + 4); + + s0 = _mm_add_ps(s0, _mm_mul_ps(a0, b0)); + s1 = _mm_add_ps(s1, _mm_mul_ps(a1, b1)); + } + s0 = _mm_add_ps(s0, s1); + float sbuf[4]; + _mm_storeu_ps(sbuf, s0); + *result = sbuf[0] + sbuf[1] + sbuf[2] + sbuf[3]; + return k; +} + + +template<> inline int VBLAS::givens(float* a, float* b, int n, float c, float s) const +{ + if( n < 4 ) + return 0; + int k = 0; + __m128 c4 = _mm_set1_ps(c), s4 = _mm_set1_ps(s); + for( ; k <= n - 4; k += 4 ) + { + __m128 a0 = _mm_load_ps(a + k); + __m128 b0 = _mm_load_ps(b + k); + __m128 t0 = _mm_add_ps(_mm_mul_ps(a0, c4), _mm_mul_ps(b0, s4)); + __m128 t1 = _mm_sub_ps(_mm_mul_ps(b0, c4), _mm_mul_ps(a0, s4)); + _mm_store_ps(a + k, t0); + _mm_store_ps(b + k, t1); + } + return k; +} + + +template<> inline int VBLAS::givensx(float* a, float* b, int n, float c, float s, + float* anorm, float* bnorm) const +{ + if( n < 4 ) + return 0; + int k = 0; + __m128 c4 = _mm_set1_ps(c), s4 = _mm_set1_ps(s); + __m128 sa = _mm_setzero_ps(), sb = _mm_setzero_ps(); + for( ; k <= n - 4; k += 4 ) + { + __m128 a0 = _mm_load_ps(a + k); + __m128 b0 = _mm_load_ps(b + k); + __m128 t0 = _mm_add_ps(_mm_mul_ps(a0, c4), _mm_mul_ps(b0, s4)); + __m128 t1 = _mm_sub_ps(_mm_mul_ps(b0, c4), _mm_mul_ps(a0, s4)); + _mm_store_ps(a + k, t0); + _mm_store_ps(b + k, t1); + sa = _mm_add_ps(sa, _mm_mul_ps(t0, t0)); + sb = _mm_add_ps(sb, _mm_mul_ps(t1, t1)); + } + float abuf[4], bbuf[4]; + _mm_storeu_ps(abuf, sa); + _mm_storeu_ps(bbuf, sb); + *anorm = abuf[0] + abuf[1] + abuf[2] + abuf[3]; + *bnorm = bbuf[0] + bbuf[1] + bbuf[2] + bbuf[3]; + return k; +} + + +template<> inline int VBLAS::dot(const double* a, const double* b, int n, double* result) const +{ + if( n < 4 ) + return 0; + int k = 0; + __m128d s0 = _mm_setzero_pd(), s1 = _mm_setzero_pd(); + for( ; k <= n - 4; k += 4 ) + { + __m128d a0 = _mm_load_pd(a + k), a1 = _mm_load_pd(a + k + 2); + __m128d b0 = _mm_load_pd(b + k), b1 = _mm_load_pd(b + k + 2); + + s0 = _mm_add_pd(s0, _mm_mul_pd(a0, b0)); + s1 = _mm_add_pd(s1, _mm_mul_pd(a1, b1)); + } + s0 = _mm_add_pd(s0, s1); + double sbuf[2]; + _mm_storeu_pd(sbuf, s0); + *result = sbuf[0] + sbuf[1]; + return k; +} + + +template<> inline int VBLAS::givens(double* a, double* b, int n, double c, double s) const +{ + int k = 0; + __m128d c2 = _mm_set1_pd(c), s2 = _mm_set1_pd(s); + for( ; k <= n - 2; k += 2 ) + { + __m128d a0 = _mm_load_pd(a + k); + __m128d b0 = _mm_load_pd(b + k); + __m128d t0 = _mm_add_pd(_mm_mul_pd(a0, c2), _mm_mul_pd(b0, s2)); + __m128d t1 = _mm_sub_pd(_mm_mul_pd(b0, c2), _mm_mul_pd(a0, s2)); + _mm_store_pd(a + k, t0); + _mm_store_pd(b + k, t1); + } + return k; +} + + +template<> inline int VBLAS::givensx(double* a, double* b, int n, double c, double s, + double* anorm, double* bnorm) const +{ + int k = 0; + __m128d c2 = _mm_set1_pd(c), s2 = _mm_set1_pd(s); + __m128d sa = _mm_setzero_pd(), sb = _mm_setzero_pd(); + for( ; k <= n - 2; k += 2 ) + { + __m128d a0 = _mm_load_pd(a + k); + __m128d b0 = _mm_load_pd(b + k); + __m128d t0 = _mm_add_pd(_mm_mul_pd(a0, c2), _mm_mul_pd(b0, s2)); + __m128d t1 = _mm_sub_pd(_mm_mul_pd(b0, c2), _mm_mul_pd(a0, s2)); + _mm_store_pd(a + k, t0); + _mm_store_pd(b + k, t1); + sa = _mm_add_pd(sa, _mm_mul_pd(t0, t0)); + sb = _mm_add_pd(sb, _mm_mul_pd(t1, t1)); + } + double abuf[2], bbuf[2]; + _mm_storeu_pd(abuf, sa); + _mm_storeu_pd(bbuf, sb); + *anorm = abuf[0] + abuf[1]; + *bnorm = bbuf[0] + bbuf[1]; + return k; +} +#endif + +template void +JacobiSVDImpl_(_Tp* At, size_t astep, _Tp* _W, _Tp* Vt, size_t vstep, int m, int n, int n1, double minval) +{ + VBLAS<_Tp> vblas; + AutoBuffer Wbuf(n); + double* W = Wbuf; + _Tp eps = DBL_EPSILON*10; + int i, j, k, iter, max_iter = std::max(m, 30); + _Tp c, s; + double sd; + astep /= sizeof(At[0]); + vstep /= sizeof(Vt[0]); + + for( i = 0; i < n; i++ ) + { + for( k = 0, sd = 0; k < m; k++ ) + { + _Tp t = At[i*astep + k]; + sd += (double)t*t; + } + W[i] = sd; + + if( Vt ) + { + for( k = 0; k < n; k++ ) + Vt[i*vstep + k] = 0; + Vt[i*vstep + i] = 1; + } + } + + for( iter = 0; iter < max_iter; iter++ ) + { + bool changed = false; + + for( i = 0; i < n-1; i++ ) + for( j = i+1; j < n; j++ ) + { + _Tp *Ai = At + i*astep, *Aj = At + j*astep; + double a = W[i], p = 0, b = W[j]; + + for( k = 0; k < m; k++ ) + p += (double)Ai[k]*Aj[k]; + + if( std::abs(p) <= eps*std::sqrt((double)a*b) ) + continue; + + p *= 2; + double beta = a - b, gamma = hypot((double)p, beta), delta; + if( beta < 0 ) + { + delta = (gamma - beta)*0.5; + s = (_Tp)std::sqrt(delta/gamma); + c = (_Tp)(p/(gamma*s*2)); + } + else + { + c = (_Tp)std::sqrt((gamma + beta)/(gamma*2)); + s = (_Tp)(p/(gamma*c*2)); + delta = p*p*0.5/(gamma + beta); + } + + W[i] += delta; + W[j] -= delta; + + if( iter % 2 != 0 && W[i] > 0 && W[j] > 0 ) + { + k = vblas.givens(Ai, Aj, m, c, s); + + for( ; k < m; k++ ) + { + _Tp t0 = c*Ai[k] + s*Aj[k]; + _Tp t1 = -s*Ai[k] + c*Aj[k]; + Ai[k] = t0; Aj[k] = t1; + } + } + else + { + a = b = 0; + for( k = 0; k < m; k++ ) + { + _Tp t0 = c*Ai[k] + s*Aj[k]; + _Tp t1 = -s*Ai[k] + c*Aj[k]; + Ai[k] = t0; Aj[k] = t1; + + a += (double)t0*t0; b += (double)t1*t1; + } + W[i] = a; W[j] = b; + } + + changed = true; + + if( Vt ) + { + _Tp *Vi = Vt + i*vstep, *Vj = Vt + j*vstep; + k = vblas.givens(Vi, Vj, n, c, s); + + for( ; k < n; k++ ) + { + _Tp t0 = c*Vi[k] + s*Vj[k]; + _Tp t1 = -s*Vi[k] + c*Vj[k]; + Vi[k] = t0; Vj[k] = t1; + } + } + } + if( !changed ) + break; + } + + for( i = 0; i < n; i++ ) + { + for( k = 0, sd = 0; k < m; k++ ) + { + _Tp t = At[i*astep + k]; + sd += (double)t*t; + } + W[i] = std::sqrt(sd); + } + + for( i = 0; i < n-1; i++ ) + { + j = i; + for( k = i+1; k < n; k++ ) + { + if( W[j] < W[k] ) + j = k; + } + if( i != j ) + { + std::swap(W[i], W[j]); + if( Vt ) + { + for( k = 0; k < m; k++ ) + std::swap(At[i*astep + k], At[j*astep + k]); + + for( k = 0; k < n; k++ ) + std::swap(Vt[i*vstep + k], Vt[j*vstep + k]); + } + } + } + + for( i = 0; i < n; i++ ) + _W[i] = (_Tp)W[i]; + + if( !Vt ) + return; + + RNG rng(0x12345678); + for( i = 0; i < n1; i++ ) + { + sd = i < n ? W[i] : 0; + + while( sd <= minval ) + { + // if we got a zero singular value, then in order to get the corresponding left singular vector + // we generate a random vector, project it to the previously computed left singular vectors, + // subtract the projection and normalize the difference. + const _Tp val0 = (_Tp)(1./m); + for( k = 0; k < m; k++ ) + { + _Tp val = (rng.next() & 256) != 0 ? val0 : -val0; + At[i*astep + k] = val; + } + for( iter = 0; iter < 2; iter++ ) + { + for( j = 0; j < i; j++ ) + { + sd = 0; + for( k = 0; k < m; k++ ) + sd += At[i*astep + k]*At[j*astep + k]; + _Tp asum = 0; + for( k = 0; k < m; k++ ) + { + _Tp t = (_Tp)(At[i*astep + k] - sd*At[j*astep + k]); + At[i*astep + k] = t; + asum += std::abs(t); + } + asum = asum ? 1/asum : 0; + for( k = 0; k < m; k++ ) + At[i*astep + k] *= asum; + } + } + sd = 0; + for( k = 0; k < m; k++ ) + { + _Tp t = At[i*astep + k]; + sd += (double)t*t; + } + sd = std::sqrt(sd); + } + + s = (_Tp)(1/sd); + for( k = 0; k < m; k++ ) + At[i*astep + k] *= s; + } +} + + +static void JacobiSVD(float* At, size_t astep, float* W, float* Vt, size_t vstep, int m, int n, int n1=-1) +{ + JacobiSVDImpl_(At, astep, W, Vt, vstep, m, n, !Vt ? 0 : n1 < 0 ? n : n1, FLT_MIN); +} + +static void JacobiSVD(double* At, size_t astep, double* W, double* Vt, size_t vstep, int m, int n, int n1=-1) +{ + JacobiSVDImpl_(At, astep, W, Vt, vstep, m, n, !Vt ? 0 : n1 < 0 ? n : n1, DBL_MIN); +} + +/* y[0:m,0:n] += diag(a[0:1,0:m]) * x[0:m,0:n] */ +template static void +MatrAXPY( int m, int n, const T1* x, int dx, + const T2* a, int inca, T3* y, int dy ) +{ + int i, j; + for( i = 0; i < m; i++, x += dx, y += dy ) + { + T2 s = a[i*inca]; + j=0; + #if CV_ENABLE_UNROLLED + for(; j <= n - 4; j += 4 ) + { + T3 t0 = (T3)(y[j] + s*x[j]); + T3 t1 = (T3)(y[j+1] + s*x[j+1]); + y[j] = t0; + y[j+1] = t1; + t0 = (T3)(y[j+2] + s*x[j+2]); + t1 = (T3)(y[j+3] + s*x[j+3]); + y[j+2] = t0; + y[j+3] = t1; + } + #endif + for( ; j < n; j++ ) + y[j] = (T3)(y[j] + s*x[j]); + } +} + +template static void +SVBkSbImpl_( int m, int n, const T* w, int incw, + const T* u, int ldu, bool uT, + const T* v, int ldv, bool vT, + const T* b, int ldb, int nb, + T* x, int ldx, double* buffer, T eps ) +{ + double threshold = 0; + int udelta0 = uT ? ldu : 1, udelta1 = uT ? 1 : ldu; + int vdelta0 = vT ? ldv : 1, vdelta1 = vT ? 1 : ldv; + int i, j, nm = std::min(m, n); + + if( !b ) + nb = m; + + for( i = 0; i < n; i++ ) + for( j = 0; j < nb; j++ ) + x[i*ldx + j] = 0; + + for( i = 0; i < nm; i++ ) + threshold += w[i*incw]; + threshold *= eps; + + // v * inv(w) * uT * b + for( i = 0; i < nm; i++, u += udelta0, v += vdelta0 ) + { + double wi = w[i*incw]; + if( (double)std::abs(wi) <= threshold ) + continue; + wi = 1/wi; + + if( nb == 1 ) + { + double s = 0; + if( b ) + for( j = 0; j < m; j++ ) + s += u[j*udelta1]*b[j*ldb]; + else + s = u[0]; + s *= wi; + + for( j = 0; j < n; j++ ) + x[j*ldx] = (T)(x[j*ldx] + s*v[j*vdelta1]); + } + else + { + if( b ) + { + for( j = 0; j < nb; j++ ) + buffer[j] = 0; + MatrAXPY( m, nb, b, ldb, u, udelta1, buffer, 0 ); + for( j = 0; j < nb; j++ ) + buffer[j] *= wi; + } + else + { + for( j = 0; j < nb; j++ ) + buffer[j] = u[j*udelta1]*wi; + } + MatrAXPY( n, nb, buffer, 0, v, vdelta1, x, ldx ); + } + } +} + +static void +SVBkSb( int m, int n, const float* w, size_t wstep, + const float* u, size_t ustep, bool uT, + const float* v, size_t vstep, bool vT, + const float* b, size_t bstep, int nb, + float* x, size_t xstep, uchar* buffer ) +{ + SVBkSbImpl_(m, n, w, wstep ? (int)(wstep/sizeof(w[0])) : 1, + u, (int)(ustep/sizeof(u[0])), uT, + v, (int)(vstep/sizeof(v[0])), vT, + b, (int)(bstep/sizeof(b[0])), nb, + x, (int)(xstep/sizeof(x[0])), + (double*)alignPtr(buffer, sizeof(double)), (float)(DBL_EPSILON*2) ); +} + +static void +SVBkSb( int m, int n, const double* w, size_t wstep, + const double* u, size_t ustep, bool uT, + const double* v, size_t vstep, bool vT, + const double* b, size_t bstep, int nb, + double* x, size_t xstep, uchar* buffer ) +{ + SVBkSbImpl_(m, n, w, wstep ? (int)(wstep/sizeof(w[0])) : 1, + u, (int)(ustep/sizeof(u[0])), uT, + v, (int)(vstep/sizeof(v[0])), vT, + b, (int)(bstep/sizeof(b[0])), nb, + x, (int)(xstep/sizeof(x[0])), + (double*)alignPtr(buffer, sizeof(double)), DBL_EPSILON*2 ); +} + +} + +/****************************************************************************************\ +* Determinant of the matrix * +\****************************************************************************************/ + +#define det2(m) ((double)m(0,0)*m(1,1) - (double)m(0,1)*m(1,0)) +#define det3(m) (m(0,0)*((double)m(1,1)*m(2,2) - (double)m(1,2)*m(2,1)) - \ + m(0,1)*((double)m(1,0)*m(2,2) - (double)m(1,2)*m(2,0)) + \ + m(0,2)*((double)m(1,0)*m(2,1) - (double)m(1,1)*m(2,0))) + +double cv::determinant( InputArray _mat ) +{ + Mat mat = _mat.getMat(); + double result = 0; + int type = mat.type(), rows = mat.rows; + size_t step = mat.step; + const uchar* m = mat.data; + + CV_Assert( mat.rows == mat.cols && (type == CV_32F || type == CV_64F)); + + #define Mf(y, x) ((float*)(m + y*step))[x] + #define Md(y, x) ((double*)(m + y*step))[x] + + if( type == CV_32F ) + { + if( rows == 2 ) + result = det2(Mf); + else if( rows == 3 ) + result = det3(Mf); + else if( rows == 1 ) + result = Mf(0,0); + else + { + size_t bufSize = rows*rows*sizeof(float); + AutoBuffer buffer(bufSize); + Mat a(rows, rows, CV_32F, (uchar*)buffer); + mat.copyTo(a); + + result = LU((float*)a.data, a.step, rows, 0, 0, 0); + if( result ) + { + for( int i = 0; i < rows; i++ ) + result *= ((const float*)(a.data + a.step*i))[i]; + result = 1./result; + } + } + } + else + { + if( rows == 2 ) + result = det2(Md); + else if( rows == 3 ) + result = det3(Md); + else if( rows == 1 ) + result = Md(0,0); + else + { + size_t bufSize = rows*rows*sizeof(double); + AutoBuffer buffer(bufSize); + Mat a(rows, rows, CV_64F, (uchar*)buffer); + mat.copyTo(a); + + result = LU((double*)a.data, a.step, rows, 0, 0, 0); + if( result ) + { + for( int i = 0; i < rows; i++ ) + result *= ((const double*)(a.data + a.step*i))[i]; + result = 1./result; + } + } + } + + #undef Mf + #undef Md + + return result; +} + +/****************************************************************************************\ +* Inverse (or pseudo-inverse) of a matrix * +\****************************************************************************************/ + +#define Sf( y, x ) ((float*)(srcdata + y*srcstep))[x] +#define Sd( y, x ) ((double*)(srcdata + y*srcstep))[x] +#define Df( y, x ) ((float*)(dstdata + y*dststep))[x] +#define Dd( y, x ) ((double*)(dstdata + y*dststep))[x] + +double cv::invert( InputArray _src, OutputArray _dst, int method ) +{ + bool result = false; + Mat src = _src.getMat(); + int type = src.type(); + + CV_Assert(type == CV_32F || type == CV_64F); + + size_t esz = CV_ELEM_SIZE(type); + int m = src.rows, n = src.cols; + + if( method == DECOMP_SVD ) + { + int nm = std::min(m, n); + + AutoBuffer _buf((m*nm + nm + nm*n)*esz + sizeof(double)); + uchar* buf = alignPtr((uchar*)_buf, (int)esz); + Mat u(m, nm, type, buf); + Mat w(nm, 1, type, u.data + m*nm*esz); + Mat vt(nm, n, type, w.data + nm*esz); + + SVD::compute(src, w, u, vt); + SVD::backSubst(w, u, vt, Mat(), _dst); + return type == CV_32F ? + (((float*)w.data)[0] >= FLT_EPSILON ? + ((float*)w.data)[n-1]/((float*)w.data)[0] : 0) : + (((double*)w.data)[0] >= DBL_EPSILON ? + ((double*)w.data)[n-1]/((double*)w.data)[0] : 0); + } + + CV_Assert( m == n ); + + if( method == DECOMP_EIG ) + { + AutoBuffer _buf((n*n*2 + n)*esz + sizeof(double)); + uchar* buf = alignPtr((uchar*)_buf, (int)esz); + Mat u(n, n, type, buf); + Mat w(n, 1, type, u.data + n*n*esz); + Mat vt(n, n, type, w.data + n*esz); + + eigen(src, w, vt); + transpose(vt, u); + SVD::backSubst(w, u, vt, Mat(), _dst); + return type == CV_32F ? + (((float*)w.data)[0] >= FLT_EPSILON ? + ((float*)w.data)[n-1]/((float*)w.data)[0] : 0) : + (((double*)w.data)[0] >= DBL_EPSILON ? + ((double*)w.data)[n-1]/((double*)w.data)[0] : 0); + } + + CV_Assert( method == DECOMP_LU || method == DECOMP_CHOLESKY ); + + _dst.create( n, n, type ); + Mat dst = _dst.getMat(); + + if( n <= 3 ) + { + uchar* srcdata = src.data; + uchar* dstdata = dst.data; + size_t srcstep = src.step; + size_t dststep = dst.step; + + if( n == 2 ) + { + if( type == CV_32FC1 ) + { + double d = det2(Sf); + if( d != 0. ) + { + result = true; + d = 1./d; + + #if CV_SSE2 + if(USE_SSE2) + { + __m128 zero = _mm_setzero_ps(); + __m128 t0 = _mm_loadl_pi(zero, (const __m64*)srcdata); //t0 = sf(0,0) sf(0,1) + __m128 t1 = _mm_loadh_pi(zero, (const __m64*)(srcdata+srcstep)); //t1 = sf(1,0) sf(1,1) + __m128 s0 = _mm_or_ps(t0, t1); + __m128 det =_mm_set1_ps((float)d); + s0 = _mm_mul_ps(s0, det); + static const uchar CV_DECL_ALIGNED(16) inv[16] = {0,0,0,0,0,0,0,0x80,0,0,0,0x80,0,0,0,0}; + __m128 pattern = _mm_load_ps((const float*)inv); + s0 = _mm_xor_ps(s0, pattern);//==-1*s0 + s0 = _mm_shuffle_ps(s0, s0, _MM_SHUFFLE(0,2,1,3)); + _mm_storel_pi((__m64*)dstdata, s0); + _mm_storeh_pi((__m64*)((float*)(dstdata+dststep)), s0); + } + else + #endif + { + double t0, t1; + t0 = Sf(0,0)*d; + t1 = Sf(1,1)*d; + Df(1,1) = (float)t0; + Df(0,0) = (float)t1; + t0 = -Sf(0,1)*d; + t1 = -Sf(1,0)*d; + Df(0,1) = (float)t0; + Df(1,0) = (float)t1; + } + + } + } + else + { + double d = det2(Sd); + if( d != 0. ) + { + result = true; + d = 1./d; + #if CV_SSE2 + if(USE_SSE2) + { + __m128d s0 = _mm_loadu_pd((const double*)srcdata); //s0 = sf(0,0) sf(0,1) + __m128d s1 = _mm_loadu_pd ((const double*)(srcdata+srcstep));//s1 = sf(1,0) sf(1,1) + __m128d sm = _mm_unpacklo_pd(s0, _mm_load_sd((const double*)(srcdata+srcstep)+1)); //sm = sf(0,0) sf(1,1) - main diagonal + __m128d ss = _mm_shuffle_pd(s0, s1, _MM_SHUFFLE2(0,1)); //ss = sf(0,1) sf(1,0) - secondary diagonal + __m128d det = _mm_load1_pd((const double*)&d); + sm = _mm_mul_pd(sm, det); + + static const uchar CV_DECL_ALIGNED(16) inv[8] = {0,0,0,0,0,0,0,0x80}; + __m128d pattern = _mm_load1_pd((double*)inv); + ss = _mm_mul_pd(ss, det); + ss = _mm_xor_pd(ss, pattern);//==-1*ss + + s0 = _mm_shuffle_pd(sm, ss, _MM_SHUFFLE2(0,1)); + s1 = _mm_shuffle_pd(ss, sm, _MM_SHUFFLE2(0,1)); + _mm_storeu_pd((double*)dstdata, s0); + _mm_storeu_pd((double*)(dstdata+dststep), s1); + } + else + #endif + { + double t0, t1; + t0 = Sd(0,0)*d; + t1 = Sd(1,1)*d; + Dd(1,1) = t0; + Dd(0,0) = t1; + t0 = -Sd(0,1)*d; + t1 = -Sd(1,0)*d; + Dd(0,1) = t0; + Dd(1,0) = t1; + } + } + } + } + else if( n == 3 ) + { + #pragma mark ANUVIS team debugging SSE2 version + //#ifdef ANUVIS_TEST + CV_Error( CV_StsBadArg, "cv::invert on float was called!" ); + //#endif + + if( type == CV_32FC1 ) + { + double d = det3(Sf); + if( d != 0. ) + { + float CV_DECL_ALIGNED(16) t[12]; + + result = true; + d = 1./d; + #if CV_SSE2 + if(USE_SSE2) + { + __m128 det =_mm_set1_ps((float)d); + __m128 s0 = _mm_loadu_ps((const float*)srcdata);//s0 = Sf(0,0) Sf(0,1) Sf(0,2) *** + __m128 s1 = _mm_loadu_ps((const float*)(srcdata+srcstep));//s1 = Sf(1,0) Sf(1,1) Sf(1,2) *** + __m128 s2 = _mm_set_ps(0.f, Sf(2,2), Sf(2,1), Sf(2,0)); //s2 = Sf(2,0) Sf(2,1) Sf(2,2) *** + + __m128 r0 = _mm_shuffle_ps(s1,s1,_MM_SHUFFLE(3,0,2,1)); //r0 = Sf(1,1) Sf(1,2) Sf(1,0) *** + __m128 r1 = _mm_shuffle_ps(s2,s2,_MM_SHUFFLE(3,1,0,2)); //r1 = Sf(2,2) Sf(2,0) Sf(2,1) *** + __m128 r2 = _mm_shuffle_ps(s2,s2,_MM_SHUFFLE(3,0,2,1)); //r2 = Sf(2,1) Sf(2,2) Sf(2,0) *** + + __m128 t0 = _mm_mul_ps(s0, r0);//t0 = Sf(0,0)*Sf(1,1) Sf(0,1)*Sf(1,2) Sf(0,2)*Sf(1,0) *** + __m128 t1 = _mm_mul_ps(s0, r1);//t1 = Sf(0,0)*Sf(2,2) Sf(0,1)*Sf(2,0) Sf(0,2)*Sf(2,1) *** + __m128 t2 = _mm_mul_ps(s1, r2);//t2 = Sf(1,0)*Sf(2,1) Sf(1,1)*Sf(2,2) Sf(1,2)*Sf(2,0) *** + + __m128 r3 = _mm_shuffle_ps(s0,s0,_MM_SHUFFLE(3,0,2,1));//r3 = Sf(0,1) Sf(0,2) Sf(0,0) *** + __m128 r4 = _mm_shuffle_ps(s0,s0,_MM_SHUFFLE(3,1,0,2));//r4 = Sf(0,2) Sf(0,0) Sf(0,1) *** + + __m128 t00 = _mm_mul_ps(s1, r3);//t00 = Sf(1,0)*Sf(0,1) Sf(1,1)*Sf(0,2) Sf(1,2)*Sf(0,0) *** + __m128 t11 = _mm_mul_ps(s2, r4);//t11 = Sf(2,0)*Sf(0,2) Sf(2,1)*Sf(0,0) Sf(2,2)*Sf(0,1) *** + __m128 t22 = _mm_mul_ps(s2, r0);//t22 = Sf(2,0)*Sf(1,1) Sf(2,1)*Sf(1,2) Sf(2,2)*Sf(1,0) *** + + t0 = _mm_mul_ps(_mm_sub_ps(t0,t00), det);//Sf(0,0)*Sf(1,1) Sf(0,1)*Sf(1,2) Sf(0,2)*Sf(1,0) *** + //-Sf(1,0)*Sf(0,1) -Sf(1,1)*Sf(0,2) -Sf(1,2)*Sf(0,0) + t1 = _mm_mul_ps(_mm_sub_ps(t1,t11), det);//Sf(0,0)*Sf(2,2) Sf(0,1)*Sf(2,0) Sf(0,2)*Sf(2,1) *** + //-Sf(2,0)*Sf(0,2) -Sf(2,1)*Sf(0,0) -Sf(2,2)*Sf(0,1) + t2 = _mm_mul_ps(_mm_sub_ps(t2,t22), det);//Sf(1,0)*Sf(2,1) Sf(1,1)*Sf(2,2) Sf(1,2)*Sf(2,0) *** + //-Sf(2,0)*Sf(1,1) -Sf(2,1)*Sf(1,2) -Sf(2,2)*Sf(1,0) + _mm_store_ps(t, t0); + _mm_store_ps(t+4, t1); + _mm_store_ps(t+8, t2); + + Df(0,0) = t[9]; Df(0,1) = t[6]; Df(0,2) = t[1]; + Df(1,0) = t[10]; Df(1,1) = t[4]; Df(1,2) = t[2]; + Df(2,0) = t[8]; Df(2,1) = t[5]; Df(2,2) = t[0]; + } + else + #endif + { + t[0] = (float)(((double)Sf(1,1) * Sf(2,2) - (double)Sf(1,2) * Sf(2,1)) * d); + t[1] = (float)(((double)Sf(0,2) * Sf(2,1) - (double)Sf(0,1) * Sf(2,2)) * d); + t[2] = (float)(((double)Sf(0,1) * Sf(1,2) - (double)Sf(0,2) * Sf(1,1)) * d); + + t[3] = (float)(((double)Sf(1,2) * Sf(2,0) - (double)Sf(1,0) * Sf(2,2)) * d); + t[4] = (float)(((double)Sf(0,0) * Sf(2,2) - (double)Sf(0,2) * Sf(2,0)) * d); + t[5] = (float)(((double)Sf(0,2) * Sf(1,0) - (double)Sf(0,0) * Sf(1,2)) * d); + + t[6] = (float)(((double)Sf(1,0) * Sf(2,1) - (double)Sf(1,1) * Sf(2,0)) * d); + t[7] = (float)(((double)Sf(0,1) * Sf(2,0) - (double)Sf(0,0) * Sf(2,1)) * d); + t[8] = (float)(((double)Sf(0,0) * Sf(1,1) - (double)Sf(0,1) * Sf(1,0)) * d); + + Df(0,0) = t[0]; Df(0,1) = t[1]; Df(0,2) = t[2]; + Df(1,0) = t[3]; Df(1,1) = t[4]; Df(1,2) = t[5]; + Df(2,0) = t[6]; Df(2,1) = t[7]; Df(2,2) = t[8]; + } + } + } + else + { + double d = det3(Sd); + if( d != 0. ) + { + result = true; + d = 1./d; + double t[9]; + + t[0] = (Sd(1,1) * Sd(2,2) - Sd(1,2) * Sd(2,1)) * d; + t[1] = (Sd(0,2) * Sd(2,1) - Sd(0,1) * Sd(2,2)) * d; + t[2] = (Sd(0,1) * Sd(1,2) - Sd(0,2) * Sd(1,1)) * d; + + t[3] = (Sd(1,2) * Sd(2,0) - Sd(1,0) * Sd(2,2)) * d; + t[4] = (Sd(0,0) * Sd(2,2) - Sd(0,2) * Sd(2,0)) * d; + t[5] = (Sd(0,2) * Sd(1,0) - Sd(0,0) * Sd(1,2)) * d; + + t[6] = (Sd(1,0) * Sd(2,1) - Sd(1,1) * Sd(2,0)) * d; + t[7] = (Sd(0,1) * Sd(2,0) - Sd(0,0) * Sd(2,1)) * d; + t[8] = (Sd(0,0) * Sd(1,1) - Sd(0,1) * Sd(1,0)) * d; + + Dd(0,0) = t[0]; Dd(0,1) = t[1]; Dd(0,2) = t[2]; + Dd(1,0) = t[3]; Dd(1,1) = t[4]; Dd(1,2) = t[5]; + Dd(2,0) = t[6]; Dd(2,1) = t[7]; Dd(2,2) = t[8]; + } + } + } + else + { + assert( n == 1 ); + + if( type == CV_32FC1 ) + { + double d = Sf(0,0); + if( d != 0. ) + { + result = true; + Df(0,0) = (float)(1./d); + } + } + else + { + double d = Sd(0,0); + if( d != 0. ) + { + result = true; + Dd(0,0) = 1./d; + } + } + } + if( !result ) + dst = Scalar(0); + return result; + } + + int elem_size = CV_ELEM_SIZE(type); + AutoBuffer buf(n*n*elem_size); + Mat src1(n, n, type, (uchar*)buf); + src.copyTo(src1); + setIdentity(dst); + + if( method == DECOMP_LU && type == CV_32F ) + result = LU((float*)src1.data, src1.step, n, (float*)dst.data, dst.step, n) != 0; + else if( method == DECOMP_LU && type == CV_64F ) + result = LU((double*)src1.data, src1.step, n, (double*)dst.data, dst.step, n) != 0; + else if( method == DECOMP_CHOLESKY && type == CV_32F ) + result = Cholesky((float*)src1.data, src1.step, n, (float*)dst.data, dst.step, n); + else + result = Cholesky((double*)src1.data, src1.step, n, (double*)dst.data, dst.step, n); + + if( !result ) + dst = Scalar(0); + + return result; +} + + + +/****************************************************************************************\ +* Solving a linear system * +\****************************************************************************************/ + +bool cv::solve( InputArray _src, InputArray _src2arg, OutputArray _dst, int method ) +{ + bool result = true; + Mat src = _src.getMat(), _src2 = _src2arg.getMat(); + int type = src.type(); + bool is_normal = (method & DECOMP_NORMAL) != 0; + + CV_Assert( type == _src2.type() && (type == CV_32F || type == CV_64F) ); + + method &= ~DECOMP_NORMAL; + CV_Assert( (method != DECOMP_LU && method != DECOMP_CHOLESKY) || + is_normal || src.rows == src.cols ); + + // check case of a single equation and small matrix + if( (method == DECOMP_LU || method == DECOMP_CHOLESKY) && !is_normal && + src.rows <= 3 && src.rows == src.cols && _src2.cols == 1 ) + { + _dst.create( src.cols, _src2.cols, src.type() ); + Mat dst = _dst.getMat(); + + #define bf(y) ((float*)(bdata + y*src2step))[0] + #define bd(y) ((double*)(bdata + y*src2step))[0] + + uchar* srcdata = src.data; + uchar* bdata = _src2.data; + uchar* dstdata = dst.data; + size_t srcstep = src.step; + size_t src2step = _src2.step; + size_t dststep = dst.step; + + if( src.rows == 2 ) + { + if( type == CV_32FC1 ) + { + double d = det2(Sf); + if( d != 0. ) + { + double t; + d = 1./d; + t = (float)(((double)bf(0)*Sf(1,1) - (double)bf(1)*Sf(0,1))*d); + Df(1,0) = (float)(((double)bf(1)*Sf(0,0) - (double)bf(0)*Sf(1,0))*d); + Df(0,0) = (float)t; + } + else + result = false; + } + else + { + double d = det2(Sd); + if( d != 0. ) + { + double t; + d = 1./d; + t = (bd(0)*Sd(1,1) - bd(1)*Sd(0,1))*d; + Dd(1,0) = (bd(1)*Sd(0,0) - bd(0)*Sd(1,0))*d; + Dd(0,0) = t; + } + else + result = false; + } + } + else if( src.rows == 3 ) + { + if( type == CV_32FC1 ) + { + double d = det3(Sf); + if( d != 0. ) + { + float t[3]; + d = 1./d; + + t[0] = (float)(d* + (bf(0)*((double)Sf(1,1)*Sf(2,2) - (double)Sf(1,2)*Sf(2,1)) - + Sf(0,1)*((double)bf(1)*Sf(2,2) - (double)Sf(1,2)*bf(2)) + + Sf(0,2)*((double)bf(1)*Sf(2,1) - (double)Sf(1,1)*bf(2)))); + + t[1] = (float)(d* + (Sf(0,0)*(double)(bf(1)*Sf(2,2) - (double)Sf(1,2)*bf(2)) - + bf(0)*((double)Sf(1,0)*Sf(2,2) - (double)Sf(1,2)*Sf(2,0)) + + Sf(0,2)*((double)Sf(1,0)*bf(2) - (double)bf(1)*Sf(2,0)))); + + t[2] = (float)(d* + (Sf(0,0)*((double)Sf(1,1)*bf(2) - (double)bf(1)*Sf(2,1)) - + Sf(0,1)*((double)Sf(1,0)*bf(2) - (double)bf(1)*Sf(2,0)) + + bf(0)*((double)Sf(1,0)*Sf(2,1) - (double)Sf(1,1)*Sf(2,0)))); + + Df(0,0) = t[0]; + Df(1,0) = t[1]; + Df(2,0) = t[2]; + } + else + result = false; + } + else + { + double d = det3(Sd); + if( d != 0. ) + { + double t[9]; + + d = 1./d; + + t[0] = ((Sd(1,1) * Sd(2,2) - Sd(1,2) * Sd(2,1))*bd(0) + + (Sd(0,2) * Sd(2,1) - Sd(0,1) * Sd(2,2))*bd(1) + + (Sd(0,1) * Sd(1,2) - Sd(0,2) * Sd(1,1))*bd(2))*d; + + t[1] = ((Sd(1,2) * Sd(2,0) - Sd(1,0) * Sd(2,2))*bd(0) + + (Sd(0,0) * Sd(2,2) - Sd(0,2) * Sd(2,0))*bd(1) + + (Sd(0,2) * Sd(1,0) - Sd(0,0) * Sd(1,2))*bd(2))*d; + + t[2] = ((Sd(1,0) * Sd(2,1) - Sd(1,1) * Sd(2,0))*bd(0) + + (Sd(0,1) * Sd(2,0) - Sd(0,0) * Sd(2,1))*bd(1) + + (Sd(0,0) * Sd(1,1) - Sd(0,1) * Sd(1,0))*bd(2))*d; + + Dd(0,0) = t[0]; + Dd(1,0) = t[1]; + Dd(2,0) = t[2]; + } + else + result = false; + } + } + else + { + assert( src.rows == 1 ); + + if( type == CV_32FC1 ) + { + double d = Sf(0,0); + if( d != 0. ) + Df(0,0) = (float)(bf(0)/d); + else + result = false; + } + else + { + double d = Sd(0,0); + if( d != 0. ) + Dd(0,0) = (bd(0)/d); + else + result = false; + } + } + return result; + } + + if( method == DECOMP_QR ) + method = DECOMP_SVD; + + int m = src.rows, m_ = m, n = src.cols, nb = _src2.cols; + size_t esz = CV_ELEM_SIZE(type), bufsize = 0; + size_t vstep = alignSize(n*esz, 16); + size_t astep = method == DECOMP_SVD && !is_normal ? alignSize(m*esz, 16) : vstep; + AutoBuffer buffer; + + Mat src2 = _src2; + _dst.create( src.cols, src2.cols, src.type() ); + Mat dst = _dst.getMat(); + + if( m < n ) + CV_Error(CV_StsBadArg, "The function can not solve under-determined linear systems" ); + + if( m == n ) + is_normal = false; + else if( is_normal ) + { + m_ = n; + if( method == DECOMP_SVD ) + method = DECOMP_EIG; + } + + size_t asize = astep*(method == DECOMP_SVD || is_normal ? n : m); + bufsize += asize + 32; + + if( is_normal ) + bufsize += n*nb*esz; + + if( method == DECOMP_SVD || method == DECOMP_EIG ) + bufsize += n*5*esz + n*vstep + nb*sizeof(double) + 32; + + buffer.allocate(bufsize); + uchar* ptr = alignPtr((uchar*)buffer, 16); + + Mat a(m_, n, type, ptr, astep); + + if( is_normal ) + mulTransposed(src, a, true); + else if( method != DECOMP_SVD ) + src.copyTo(a); + else + { + a = Mat(n, m_, type, ptr, astep); + transpose(src, a); + } + ptr += asize; + + if( !is_normal ) + { + if( method == DECOMP_LU || method == DECOMP_CHOLESKY ) + src2.copyTo(dst); + } + else + { + // a'*b + if( method == DECOMP_LU || method == DECOMP_CHOLESKY ) + gemm( src, src2, 1, Mat(), 0, dst, GEMM_1_T ); + else + { + Mat tmp(n, nb, type, ptr); + ptr += n*nb*esz; + gemm( src, src2, 1, Mat(), 0, tmp, GEMM_1_T ); + src2 = tmp; + } + } + + if( method == DECOMP_LU ) + { + if( type == CV_32F ) + result = LU(a.ptr(), a.step, n, dst.ptr(), dst.step, nb) != 0; + else + result = LU(a.ptr(), a.step, n, dst.ptr(), dst.step, nb) != 0; + } + else if( method == DECOMP_CHOLESKY ) + { + if( type == CV_32F ) + result = Cholesky(a.ptr(), a.step, n, dst.ptr(), dst.step, nb); + else + result = Cholesky(a.ptr(), a.step, n, dst.ptr(), dst.step, nb); + } + else + { + ptr = alignPtr(ptr, 16); + Mat v(n, n, type, ptr, vstep), w(n, 1, type, ptr + vstep*n), u; + ptr += n*(vstep + esz); + + if( method == DECOMP_EIG ) + { + if( type == CV_32F ) + Jacobi(a.ptr(), a.step, w.ptr(), v.ptr(), v.step, n, ptr); + else + Jacobi(a.ptr(), a.step, w.ptr(), v.ptr(), v.step, n, ptr); + u = v; + } + else + { + if( type == CV_32F ) + JacobiSVD(a.ptr(), a.step, w.ptr(), v.ptr(), v.step, m_, n); + else + JacobiSVD(a.ptr(), a.step, w.ptr(), v.ptr(), v.step, m_, n); + u = a; + } + + if( type == CV_32F ) + { + SVBkSb(m_, n, w.ptr(), 0, u.ptr(), u.step, true, + v.ptr(), v.step, true, src2.ptr(), + src2.step, nb, dst.ptr(), dst.step, ptr); + } + else + { + SVBkSb(m_, n, w.ptr(), 0, u.ptr(), u.step, true, + v.ptr(), v.step, true, src2.ptr(), + src2.step, nb, dst.ptr(), dst.step, ptr); + } + result = true; + } + + if( !result ) + dst = Scalar(0); + + return result; +} + + +/////////////////// finding eigenvalues and eigenvectors of a symmetric matrix /////////////// + +bool cv::eigen( InputArray _src, bool computeEvects, OutputArray _evals, OutputArray _evects ) +{ + Mat src = _src.getMat(); + int type = src.type(); + int n = src.rows; + + CV_Assert( src.rows == src.cols ); + CV_Assert (type == CV_32F || type == CV_64F); + + Mat v; + if( computeEvects ) + { + _evects.create(n, n, type); + v = _evects.getMat(); + } + + size_t elemSize = src.elemSize(), astep = alignSize(n*elemSize, 16); + AutoBuffer buf(n*astep + n*5*elemSize + 32); + uchar* ptr = alignPtr((uchar*)buf, 16); + Mat a(n, n, type, ptr, astep), w(n, 1, type, ptr + astep*n); + ptr += astep*n + elemSize*n; + src.copyTo(a); + bool ok = type == CV_32F ? + Jacobi(a.ptr(), a.step, w.ptr(), v.ptr(), v.step, n, ptr) : + Jacobi(a.ptr(), a.step, w.ptr(), v.ptr(), v.step, n, ptr); + + w.copyTo(_evals); + return ok; +} + +bool cv::eigen( InputArray src, OutputArray evals, int, int ) +{ + return eigen(src, false, evals, noArray()); +} + +bool cv::eigen( InputArray src, OutputArray evals, OutputArray evects, int, int) +{ + return eigen(src, true, evals, evects); +} + +namespace cv +{ + +static void _SVDcompute( InputArray _aarr, OutputArray _w, + OutputArray _u, OutputArray _vt, int flags ) +{ + Mat src = _aarr.getMat(); + int m = src.rows, n = src.cols; + int type = src.type(); + bool compute_uv = _u.needed() || _vt.needed(); + bool full_uv = (flags & SVD::FULL_UV) != 0; + + CV_Assert( type == CV_32F || type == CV_64F ); + + if( flags & SVD::NO_UV ) + { + _u.release(); + _vt.release(); + compute_uv = full_uv = false; + } + + bool at = false; + if( m < n ) + { + std::swap(m, n); + at = true; + } + + int urows = full_uv ? m : n; + size_t esz = src.elemSize(), astep = alignSize(m*esz, 16), vstep = alignSize(n*esz, 16); + AutoBuffer _buf(urows*astep + n*vstep + n*esz + 32); + uchar* buf = alignPtr((uchar*)_buf, 16); + Mat temp_a(n, m, type, buf, astep); + Mat temp_w(n, 1, type, buf + urows*astep); + Mat temp_u(urows, m, type, buf, astep), temp_v; + + if( compute_uv ) + temp_v = Mat(n, n, type, alignPtr(buf + urows*astep + n*esz, 16), vstep); + + if( urows > n ) + temp_u = Scalar::all(0); + + if( !at ) + transpose(src, temp_a); + else + src.copyTo(temp_a); + + if( type == CV_32F ) + { + JacobiSVD(temp_a.ptr(), temp_u.step, temp_w.ptr(), + temp_v.ptr(), temp_v.step, m, n, compute_uv ? urows : 0); + } + else + { + JacobiSVD(temp_a.ptr(), temp_u.step, temp_w.ptr(), + temp_v.ptr(), temp_v.step, m, n, compute_uv ? urows : 0); + } + temp_w.copyTo(_w); + if( compute_uv ) + { + if( !at ) + { + transpose(temp_u, _u); + temp_v.copyTo(_vt); + } + else + { + transpose(temp_v, _u); + temp_u.copyTo(_vt); + } + } +} + + +void SVD::compute( InputArray a, OutputArray w, OutputArray u, OutputArray vt, int flags ) +{ + _SVDcompute(a, w, u, vt, flags); +} + +void SVD::compute( InputArray a, OutputArray w, int flags ) +{ + _SVDcompute(a, w, noArray(), noArray(), flags); +} + +void SVD::backSubst( InputArray _w, InputArray _u, InputArray _vt, + InputArray _rhs, OutputArray _dst ) +{ + Mat w = _w.getMat(), u = _u.getMat(), vt = _vt.getMat(), rhs = _rhs.getMat(); + int type = w.type(), esz = (int)w.elemSize(); + int m = u.rows, n = vt.cols, nb = rhs.data ? rhs.cols : m, nm = std::min(m, n); + size_t wstep = w.rows == 1 ? (size_t)esz : w.cols == 1 ? (size_t)w.step : (size_t)w.step + esz; + AutoBuffer buffer(nb*sizeof(double) + 16); + CV_Assert( w.type() == u.type() && u.type() == vt.type() && u.data && vt.data && w.data ); + CV_Assert( u.cols >= nm && vt.rows >= nm && + (w.size() == Size(nm, 1) || w.size() == Size(1, nm) || w.size() == Size(vt.rows, u.cols)) ); + CV_Assert( rhs.data == 0 || (rhs.type() == type && rhs.rows == m) ); + + _dst.create( n, nb, type ); + Mat dst = _dst.getMat(); + if( type == CV_32F ) + SVBkSb(m, n, w.ptr(), wstep, u.ptr(), u.step, false, + vt.ptr(), vt.step, true, rhs.ptr(), rhs.step, nb, + dst.ptr(), dst.step, buffer); + else if( type == CV_64F ) + SVBkSb(m, n, w.ptr(), wstep, u.ptr(), u.step, false, + vt.ptr(), vt.step, true, rhs.ptr(), rhs.step, nb, + dst.ptr(), dst.step, buffer); + else + CV_Error( CV_StsUnsupportedFormat, "" ); +} + + +SVD& SVD::operator ()(InputArray a, int flags) +{ + _SVDcompute(a, w, u, vt, flags); + return *this; +} + + +void SVD::backSubst( InputArray rhs, OutputArray dst ) const +{ + backSubst( w, u, vt, rhs, dst ); +} + +} + + +void cv::SVDecomp(InputArray src, OutputArray w, OutputArray u, OutputArray vt, int flags) +{ + SVD::compute(src, w, u, vt, flags); +} + +void cv::SVBackSubst(InputArray w, InputArray u, InputArray vt, InputArray rhs, OutputArray dst) +{ + SVD::backSubst(w, u, vt, rhs, dst); +} + + +CV_IMPL double +cvDet( const CvArr* arr ) +{ + if( CV_IS_MAT(arr) && ((CvMat*)arr)->rows <= 3 ) + { + CvMat* mat = (CvMat*)arr; + int type = CV_MAT_TYPE(mat->type); + int rows = mat->rows; + uchar* m = mat->data.ptr; + int step = mat->step; + CV_Assert( rows == mat->cols ); + + #define Mf(y, x) ((float*)(m + y*step))[x] + #define Md(y, x) ((double*)(m + y*step))[x] + + if( type == CV_32F ) + { + if( rows == 2 ) + return det2(Mf); + if( rows == 3 ) + return det3(Mf); + } + else if( type == CV_64F ) + { + if( rows == 2 ) + return det2(Md); + if( rows == 3 ) + return det3(Md); + } + return cv::determinant(cv::Mat(mat)); + } + return cv::determinant(cv::cvarrToMat(arr)); +} + + +CV_IMPL double +cvInvert( const CvArr* srcarr, CvArr* dstarr, int method ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + CV_Assert( src.type() == dst.type() && src.rows == dst.cols && src.cols == dst.rows ); + return cv::invert( src, dst, method == CV_CHOLESKY ? cv::DECOMP_CHOLESKY : + method == CV_SVD ? cv::DECOMP_SVD : + method == CV_SVD_SYM ? cv::DECOMP_EIG : cv::DECOMP_LU ); +} + + +CV_IMPL int +cvSolve( const CvArr* Aarr, const CvArr* barr, CvArr* xarr, int method ) +{ + cv::Mat A = cv::cvarrToMat(Aarr), b = cv::cvarrToMat(barr), x = cv::cvarrToMat(xarr); + + CV_Assert( A.type() == x.type() && A.cols == x.rows && x.cols == b.cols ); + bool is_normal = (method & CV_NORMAL) != 0; + method &= ~CV_NORMAL; + return cv::solve( A, b, x, (method == CV_CHOLESKY ? cv::DECOMP_CHOLESKY : + method == CV_SVD ? cv::DECOMP_SVD : + method == CV_SVD_SYM ? cv::DECOMP_EIG : + A.rows > A.cols ? cv::DECOMP_QR : cv::DECOMP_LU) + (is_normal ? cv::DECOMP_NORMAL : 0) ); +} + + +CV_IMPL void +cvEigenVV( CvArr* srcarr, CvArr* evectsarr, CvArr* evalsarr, double, + int lowindex, int highindex) +{ + cv::Mat src = cv::cvarrToMat(srcarr), evals0 = cv::cvarrToMat(evalsarr), evals = evals0; + if( evectsarr ) + { + cv::Mat evects0 = cv::cvarrToMat(evectsarr), evects = evects0; + eigen(src, evals, evects, lowindex, highindex); + if( evects0.data != evects.data ) + { + uchar* p = evects0.data; + evects.convertTo(evects0, evects0.type()); + CV_Assert( p == evects0.data ); + } + } + else + eigen(src, evals, lowindex, highindex); + if( evals0.data != evals.data ) + { + uchar* p = evals0.data; + if( evals0.size() == evals.size() ) + evals.convertTo(evals0, evals0.type()); + else if( evals0.type() == evals.type() ) + cv::transpose(evals, evals0); + else + cv::Mat(evals.t()).convertTo(evals0, evals0.type()); + CV_Assert( p == evals0.data ); + } +} + + +CV_IMPL void +cvSVD( CvArr* aarr, CvArr* warr, CvArr* uarr, CvArr* varr, int flags ) +{ + cv::Mat a = cv::cvarrToMat(aarr), w = cv::cvarrToMat(warr), u, v; + int m = a.rows, n = a.cols, type = a.type(), mn = std::max(m, n), nm = std::min(m, n); + + CV_Assert( w.type() == type && + (w.size() == cv::Size(nm,1) || w.size() == cv::Size(1, nm) || + w.size() == cv::Size(nm, nm) || w.size() == cv::Size(n, m)) ); + + cv::SVD svd; + + if( w.size() == cv::Size(nm, 1) ) + svd.w = cv::Mat(nm, 1, type, w.data ); + else if( w.isContinuous() ) + svd.w = w; + + if( uarr ) + { + u = cv::cvarrToMat(uarr); + CV_Assert( u.type() == type ); + svd.u = u; + } + + if( varr ) + { + v = cv::cvarrToMat(varr); + CV_Assert( v.type() == type ); + svd.vt = v; + } + + svd(a, ((flags & CV_SVD_MODIFY_A) ? cv::SVD::MODIFY_A : 0) | + ((!svd.u.data && !svd.vt.data) ? cv::SVD::NO_UV : 0) | + ((m != n && (svd.u.size() == cv::Size(mn, mn) || + svd.vt.size() == cv::Size(mn, mn))) ? cv::SVD::FULL_UV : 0)); + + if( u.data ) + { + if( flags & CV_SVD_U_T ) + cv::transpose( svd.u, u ); + else if( u.data != svd.u.data ) + { + CV_Assert( u.size() == svd.u.size() ); + svd.u.copyTo(u); + } + } + + if( v.data ) + { + if( !(flags & CV_SVD_V_T) ) + cv::transpose( svd.vt, v ); + else if( v.data != svd.vt.data ) + { + CV_Assert( v.size() == svd.vt.size() ); + svd.vt.copyTo(v); + } + } + + if( w.data != svd.w.data ) + { + if( w.size() == svd.w.size() ) + svd.w.copyTo(w); + else + { + w = cv::Scalar(0); + cv::Mat wd = w.diag(); + svd.w.copyTo(wd); + } + } +} + + +CV_IMPL void +cvSVBkSb( const CvArr* warr, const CvArr* uarr, + const CvArr* varr, const CvArr* rhsarr, + CvArr* dstarr, int flags ) +{ + cv::Mat w = cv::cvarrToMat(warr), u = cv::cvarrToMat(uarr), + v = cv::cvarrToMat(varr), rhs, + dst = cv::cvarrToMat(dstarr), dst0 = dst; + if( flags & CV_SVD_U_T ) + { + cv::Mat tmp; + transpose(u, tmp); + u = tmp; + } + if( !(flags & CV_SVD_V_T) ) + { + cv::Mat tmp; + transpose(v, tmp); + v = tmp; + } + if( rhsarr ) + rhs = cv::cvarrToMat(rhsarr); + + cv::SVD::backSubst(w, u, v, rhs, dst); + CV_Assert( dst.data == dst0.data ); +} \ No newline at end of file diff --git a/core/src/mathfuncs.cpp b/core/src/mathfuncs.cpp new file mode 100644 index 0000000..e391b15 --- /dev/null +++ b/core/src/mathfuncs.cpp @@ -0,0 +1,2559 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + + +namespace cv +{ + +static const int MAX_BLOCK_SIZE = 1024; +typedef void (*MathFunc)(const void* src, void* dst, int len); + +static const float atan2_p1 = 0.9997878412794807f*(float)(180/CV_PI); +static const float atan2_p3 = -0.3258083974640975f*(float)(180/CV_PI); +static const float atan2_p5 = 0.1555786518463281f*(float)(180/CV_PI); +static const float atan2_p7 = -0.04432655554792128f*(float)(180/CV_PI); + +float fastAtan2( float y, float x ) +{ + float ax = std::abs(x), ay = std::abs(y); + float a, c, c2; + if( ax >= ay ) + { + c = ay/(ax + (float)DBL_EPSILON); + c2 = c*c; + a = (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c; + } + else + { + c = ax/(ay + (float)DBL_EPSILON); + c2 = c*c; + a = 90.f - (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c; + } + if( x < 0 ) + a = 180.f - a; + if( y < 0 ) + a = 360.f - a; + return a; +} + +static void FastAtan2_32f(const float *Y, const float *X, float *angle, int len, bool angleInDegrees=true ) +{ + int i = 0; + float scale = angleInDegrees ? 1 : (float)(CV_PI/180); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if (tegra::FastAtan2_32f(Y, X, angle, len, scale)) + return; +#endif + +#if CV_SSE2 + if( USE_SSE2 ) + { + Cv32suf iabsmask; iabsmask.i = 0x7fffffff; + __m128 eps = _mm_set1_ps((float)DBL_EPSILON), absmask = _mm_set1_ps(iabsmask.f); + __m128 _90 = _mm_set1_ps(90.f), _180 = _mm_set1_ps(180.f), _360 = _mm_set1_ps(360.f); + __m128 z = _mm_setzero_ps(), scale4 = _mm_set1_ps(scale); + __m128 p1 = _mm_set1_ps(atan2_p1), p3 = _mm_set1_ps(atan2_p3); + __m128 p5 = _mm_set1_ps(atan2_p5), p7 = _mm_set1_ps(atan2_p7); + + for( ; i <= len - 4; i += 4 ) + { + __m128 x = _mm_loadu_ps(X + i), y = _mm_loadu_ps(Y + i); + __m128 ax = _mm_and_ps(x, absmask), ay = _mm_and_ps(y, absmask); + __m128 mask = _mm_cmplt_ps(ax, ay); + __m128 tmin = _mm_min_ps(ax, ay), tmax = _mm_max_ps(ax, ay); + __m128 c = _mm_div_ps(tmin, _mm_add_ps(tmax, eps)); + __m128 c2 = _mm_mul_ps(c, c); + __m128 a = _mm_mul_ps(c2, p7); + a = _mm_mul_ps(_mm_add_ps(a, p5), c2); + a = _mm_mul_ps(_mm_add_ps(a, p3), c2); + a = _mm_mul_ps(_mm_add_ps(a, p1), c); + + __m128 b = _mm_sub_ps(_90, a); + a = _mm_xor_ps(a, _mm_and_ps(_mm_xor_ps(a, b), mask)); + + b = _mm_sub_ps(_180, a); + mask = _mm_cmplt_ps(x, z); + a = _mm_xor_ps(a, _mm_and_ps(_mm_xor_ps(a, b), mask)); + + b = _mm_sub_ps(_360, a); + mask = _mm_cmplt_ps(y, z); + a = _mm_xor_ps(a, _mm_and_ps(_mm_xor_ps(a, b), mask)); + + a = _mm_mul_ps(a, scale4); + _mm_storeu_ps(angle + i, a); + } + } +#endif + + for( ; i < len; i++ ) + { + float x = X[i], y = Y[i]; + float ax = std::abs(x), ay = std::abs(y); + float a, c, c2; + if( ax >= ay ) + { + c = ay/(ax + (float)DBL_EPSILON); + c2 = c*c; + a = (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c; + } + else + { + c = ax/(ay + (float)DBL_EPSILON); + c2 = c*c; + a = 90.f - (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c; + } + if( x < 0 ) + a = 180.f - a; + if( y < 0 ) + a = 360.f - a; + angle[i] = (float)(a*scale); + } +} + + +/* ************************************************************************** *\ + Fast cube root by Ken Turkowski + (http://www.worldserver.com/turk/computergraphics/papers.html) +\* ************************************************************************** */ +float cubeRoot( float value ) +{ + float fr; + Cv32suf v, m; + int ix, s; + int ex, shx; + + v.f = value; + ix = v.i & 0x7fffffff; + s = v.i & 0x80000000; + ex = (ix >> 23) - 127; + shx = ex % 3; + shx -= shx >= 0 ? 3 : 0; + ex = (ex - shx) / 3; /* exponent of cube root */ + v.i = (ix & ((1<<23)-1)) | ((shx + 127)<<23); + fr = v.f; + + /* 0.125 <= fr < 1.0 */ + /* Use quartic rational polynomial with error < 2^(-24) */ + fr = (float)(((((45.2548339756803022511987494 * fr + + 192.2798368355061050458134625) * fr + + 119.1654824285581628956914143) * fr + + 13.43250139086239872172837314) * fr + + 0.1636161226585754240958355063)/ + ((((14.80884093219134573786480845 * fr + + 151.9714051044435648658557668) * fr + + 168.5254414101568283957668343) * fr + + 33.9905941350215598754191872) * fr + + 1.0)); + + /* fr *= 2^ex * sign */ + m.f = value; + v.f = fr; + v.i = (v.i + (ex << 23) + s) & (m.i*2 != 0 ? -1 : 0); + return v.f; +} + +static void Magnitude_32f(const float* x, const float* y, float* mag, int len) +{ + int i = 0; + +#if CV_SSE + if( USE_SSE2 ) + { + for( ; i <= len - 8; i += 8 ) + { + __m128 x0 = _mm_loadu_ps(x + i), x1 = _mm_loadu_ps(x + i + 4); + __m128 y0 = _mm_loadu_ps(y + i), y1 = _mm_loadu_ps(y + i + 4); + x0 = _mm_add_ps(_mm_mul_ps(x0, x0), _mm_mul_ps(y0, y0)); + x1 = _mm_add_ps(_mm_mul_ps(x1, x1), _mm_mul_ps(y1, y1)); + x0 = _mm_sqrt_ps(x0); x1 = _mm_sqrt_ps(x1); + _mm_storeu_ps(mag + i, x0); _mm_storeu_ps(mag + i + 4, x1); + } + } +#endif + + for( ; i < len; i++ ) + { + float x0 = x[i], y0 = y[i]; + mag[i] = std::sqrt(x0*x0 + y0*y0); + } +} + +static void Magnitude_64f(const double* x, const double* y, double* mag, int len) +{ + int i = 0; + +#if CV_SSE2 + if( USE_SSE2 ) + { + for( ; i <= len - 4; i += 4 ) + { + __m128d x0 = _mm_loadu_pd(x + i), x1 = _mm_loadu_pd(x + i + 2); + __m128d y0 = _mm_loadu_pd(y + i), y1 = _mm_loadu_pd(y + i + 2); + x0 = _mm_add_pd(_mm_mul_pd(x0, x0), _mm_mul_pd(y0, y0)); + x1 = _mm_add_pd(_mm_mul_pd(x1, x1), _mm_mul_pd(y1, y1)); + x0 = _mm_sqrt_pd(x0); x1 = _mm_sqrt_pd(x1); + _mm_storeu_pd(mag + i, x0); _mm_storeu_pd(mag + i + 2, x1); + } + } +#endif + + for( ; i < len; i++ ) + { + double x0 = x[i], y0 = y[i]; + mag[i] = std::sqrt(x0*x0 + y0*y0); + } +} + + +static void InvSqrt_32f(const float* src, float* dst, int len) +{ + int i = 0; + +#if CV_SSE + if( USE_SSE2 ) + { + __m128 _0_5 = _mm_set1_ps(0.5f), _1_5 = _mm_set1_ps(1.5f); + if( (((size_t)src|(size_t)dst) & 15) == 0 ) + for( ; i <= len - 8; i += 8 ) + { + __m128 t0 = _mm_load_ps(src + i), t1 = _mm_load_ps(src + i + 4); + __m128 h0 = _mm_mul_ps(t0, _0_5), h1 = _mm_mul_ps(t1, _0_5); + t0 = _mm_rsqrt_ps(t0); t1 = _mm_rsqrt_ps(t1); + t0 = _mm_mul_ps(t0, _mm_sub_ps(_1_5, _mm_mul_ps(_mm_mul_ps(t0,t0),h0))); + t1 = _mm_mul_ps(t1, _mm_sub_ps(_1_5, _mm_mul_ps(_mm_mul_ps(t1,t1),h1))); + _mm_store_ps(dst + i, t0); _mm_store_ps(dst + i + 4, t1); + } + else + for( ; i <= len - 8; i += 8 ) + { + __m128 t0 = _mm_loadu_ps(src + i), t1 = _mm_loadu_ps(src + i + 4); + __m128 h0 = _mm_mul_ps(t0, _0_5), h1 = _mm_mul_ps(t1, _0_5); + t0 = _mm_rsqrt_ps(t0); t1 = _mm_rsqrt_ps(t1); + t0 = _mm_mul_ps(t0, _mm_sub_ps(_1_5, _mm_mul_ps(_mm_mul_ps(t0,t0),h0))); + t1 = _mm_mul_ps(t1, _mm_sub_ps(_1_5, _mm_mul_ps(_mm_mul_ps(t1,t1),h1))); + _mm_storeu_ps(dst + i, t0); _mm_storeu_ps(dst + i + 4, t1); + } + } +#endif + + for( ; i < len; i++ ) + dst[i] = 1/std::sqrt(src[i]); +} + + +static void InvSqrt_64f(const double* src, double* dst, int len) +{ + for( int i = 0; i < len; i++ ) + dst[i] = 1/std::sqrt(src[i]); +} + + +static void Sqrt_32f(const float* src, float* dst, int len) +{ + int i = 0; + +#if CV_SSE + if( USE_SSE2 ) + { + if( (((size_t)src|(size_t)dst) & 15) == 0 ) + for( ; i <= len - 8; i += 8 ) + { + __m128 t0 = _mm_load_ps(src + i), t1 = _mm_load_ps(src + i + 4); + t0 = _mm_sqrt_ps(t0); t1 = _mm_sqrt_ps(t1); + _mm_store_ps(dst + i, t0); _mm_store_ps(dst + i + 4, t1); + } + else + for( ; i <= len - 8; i += 8 ) + { + __m128 t0 = _mm_loadu_ps(src + i), t1 = _mm_loadu_ps(src + i + 4); + t0 = _mm_sqrt_ps(t0); t1 = _mm_sqrt_ps(t1); + _mm_storeu_ps(dst + i, t0); _mm_storeu_ps(dst + i + 4, t1); + } + } +#endif + + for( ; i < len; i++ ) + dst[i] = std::sqrt(src[i]); +} + + +static void Sqrt_64f(const double* src, double* dst, int len) +{ + int i = 0; + +#if CV_SSE2 + if( USE_SSE2 ) + { + if( (((size_t)src|(size_t)dst) & 15) == 0 ) + for( ; i <= len - 4; i += 4 ) + { + __m128d t0 = _mm_load_pd(src + i), t1 = _mm_load_pd(src + i + 2); + t0 = _mm_sqrt_pd(t0); t1 = _mm_sqrt_pd(t1); + _mm_store_pd(dst + i, t0); _mm_store_pd(dst + i + 2, t1); + } + else + for( ; i <= len - 4; i += 4 ) + { + __m128d t0 = _mm_loadu_pd(src + i), t1 = _mm_loadu_pd(src + i + 2); + t0 = _mm_sqrt_pd(t0); t1 = _mm_sqrt_pd(t1); + _mm_storeu_pd(dst + i, t0); _mm_storeu_pd(dst + i + 2, t1); + } + } +#endif + + for( ; i < len; i++ ) + dst[i] = std::sqrt(src[i]); +} + + +/****************************************************************************************\ +* Cartezian -> Polar * +\****************************************************************************************/ + +void magnitude( InputArray src1, InputArray src2, OutputArray dst ) +{ + Mat X = src1.getMat(), Y = src2.getMat(); + int type = X.type(), depth = X.depth(), cn = X.channels(); + CV_Assert( X.size == Y.size && type == Y.type() && (depth == CV_32F || depth == CV_64F)); + dst.create(X.dims, X.size, X.type()); + Mat Mag = dst.getMat(); + + const Mat* arrays[] = {&X, &Y, &Mag, 0}; + uchar* ptrs[3]; + NAryMatIterator it(arrays, ptrs); + int len = (int)it.size*cn; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + if( depth == CV_32F ) + { + const float *x = (const float*)ptrs[0], *y = (const float*)ptrs[1]; + float *mag = (float*)ptrs[2]; + Magnitude_32f( x, y, mag, len ); + } + else + { + const double *x = (const double*)ptrs[0], *y = (const double*)ptrs[1]; + double *mag = (double*)ptrs[2]; + Magnitude_64f( x, y, mag, len ); + } + } +} + + +void phase( InputArray src1, InputArray src2, OutputArray dst, bool angleInDegrees ) +{ + Mat X = src1.getMat(), Y = src2.getMat(); + int type = X.type(), depth = X.depth(), cn = X.channels(); + CV_Assert( X.size == Y.size && type == Y.type() && (depth == CV_32F || depth == CV_64F)); + dst.create( X.dims, X.size, type ); + Mat Angle = dst.getMat(); + + const Mat* arrays[] = {&X, &Y, &Angle, 0}; + uchar* ptrs[3]; + NAryMatIterator it(arrays, ptrs); + cv::AutoBuffer _buf; + float* buf[2] = {0, 0}; + int j, k, total = (int)(it.size*cn), blockSize = total; + size_t esz1 = X.elemSize1(); + + if( depth == CV_64F ) + { + blockSize = std::min(blockSize, ((BLOCK_SIZE+cn-1)/cn)*cn); + _buf.allocate(blockSize*2); + buf[0] = _buf; + buf[1] = buf[0] + blockSize; + } + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( j = 0; j < total; j += blockSize ) + { + int len = std::min(total - j, blockSize); + if( depth == CV_32F ) + { + const float *x = (const float*)ptrs[0], *y = (const float*)ptrs[1]; + float *angle = (float*)ptrs[2]; + FastAtan2_32f( y, x, angle, len, angleInDegrees ); + } + else + { + const double *x = (const double*)ptrs[0], *y = (const double*)ptrs[1]; + double *angle = (double*)ptrs[2]; + for( k = 0; k < len; k++ ) + { + buf[0][k] = (float)x[k]; + buf[1][k] = (float)y[k]; + } + + FastAtan2_32f( buf[1], buf[0], buf[0], len, angleInDegrees ); + for( k = 0; k < len; k++ ) + angle[k] = buf[0][k]; + } + ptrs[0] += len*esz1; + ptrs[1] += len*esz1; + ptrs[2] += len*esz1; + } + } +} + + +void cartToPolar( InputArray src1, InputArray src2, + OutputArray dst1, OutputArray dst2, bool angleInDegrees ) +{ + Mat X = src1.getMat(), Y = src2.getMat(); + int type = X.type(), depth = X.depth(), cn = X.channels(); + CV_Assert( X.size == Y.size && type == Y.type() && (depth == CV_32F || depth == CV_64F)); + dst1.create( X.dims, X.size, type ); + dst2.create( X.dims, X.size, type ); + Mat Mag = dst1.getMat(), Angle = dst2.getMat(); + + const Mat* arrays[] = {&X, &Y, &Mag, &Angle, 0}; + uchar* ptrs[4]; + NAryMatIterator it(arrays, ptrs); + cv::AutoBuffer _buf; + float* buf[2] = {0, 0}; + int j, k, total = (int)(it.size*cn), blockSize = std::min(total, ((BLOCK_SIZE+cn-1)/cn)*cn); + size_t esz1 = X.elemSize1(); + + if( depth == CV_64F ) + { + _buf.allocate(blockSize*2); + buf[0] = _buf; + buf[1] = buf[0] + blockSize; + } + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( j = 0; j < total; j += blockSize ) + { + int len = std::min(total - j, blockSize); + if( depth == CV_32F ) + { + const float *x = (const float*)ptrs[0], *y = (const float*)ptrs[1]; + float *mag = (float*)ptrs[2], *angle = (float*)ptrs[3]; + Magnitude_32f( x, y, mag, len ); + FastAtan2_32f( y, x, angle, len, angleInDegrees ); + } + else + { + const double *x = (const double*)ptrs[0], *y = (const double*)ptrs[1]; + double *angle = (double*)ptrs[3]; + + Magnitude_64f(x, y, (double*)ptrs[2], len); + for( k = 0; k < len; k++ ) + { + buf[0][k] = (float)x[k]; + buf[1][k] = (float)y[k]; + } + + FastAtan2_32f( buf[1], buf[0], buf[0], len, angleInDegrees ); + for( k = 0; k < len; k++ ) + angle[k] = buf[0][k]; + } + ptrs[0] += len*esz1; + ptrs[1] += len*esz1; + ptrs[2] += len*esz1; + ptrs[3] += len*esz1; + } + } +} + + +/****************************************************************************************\ +* Polar -> Cartezian * +\****************************************************************************************/ + +static void SinCos_32f( const float *angle, float *sinval, float* cosval, + int len, int angle_in_degrees ) +{ + const int N = 64; + + static const double sin_table[] = + { + 0.00000000000000000000, 0.09801714032956060400, + 0.19509032201612825000, 0.29028467725446233000, + 0.38268343236508978000, 0.47139673682599764000, + 0.55557023301960218000, 0.63439328416364549000, + 0.70710678118654746000, 0.77301045336273699000, + 0.83146961230254524000, 0.88192126434835494000, + 0.92387953251128674000, 0.95694033573220894000, + 0.98078528040323043000, 0.99518472667219682000, + 1.00000000000000000000, 0.99518472667219693000, + 0.98078528040323043000, 0.95694033573220894000, + 0.92387953251128674000, 0.88192126434835505000, + 0.83146961230254546000, 0.77301045336273710000, + 0.70710678118654757000, 0.63439328416364549000, + 0.55557023301960218000, 0.47139673682599786000, + 0.38268343236508989000, 0.29028467725446239000, + 0.19509032201612861000, 0.09801714032956082600, + 0.00000000000000012246, -0.09801714032956059000, + -0.19509032201612836000, -0.29028467725446211000, + -0.38268343236508967000, -0.47139673682599764000, + -0.55557023301960196000, -0.63439328416364527000, + -0.70710678118654746000, -0.77301045336273666000, + -0.83146961230254524000, -0.88192126434835494000, + -0.92387953251128652000, -0.95694033573220882000, + -0.98078528040323032000, -0.99518472667219693000, + -1.00000000000000000000, -0.99518472667219693000, + -0.98078528040323043000, -0.95694033573220894000, + -0.92387953251128663000, -0.88192126434835505000, + -0.83146961230254546000, -0.77301045336273688000, + -0.70710678118654768000, -0.63439328416364593000, + -0.55557023301960218000, -0.47139673682599792000, + -0.38268343236509039000, -0.29028467725446250000, + -0.19509032201612872000, -0.09801714032956050600, + }; + + static const double k2 = (2*CV_PI)/N; + + static const double sin_a0 = -0.166630293345647*k2*k2*k2; + static const double sin_a2 = k2; + + static const double cos_a0 = -0.499818138450326*k2*k2; + /*static const double cos_a2 = 1;*/ + + double k1; + int i; + + if( !angle_in_degrees ) + k1 = N/(2*CV_PI); + else + k1 = N/360.; + + for( i = 0; i < len; i++ ) + { + double t = angle[i]*k1; + int it = cvRound(t); + t -= it; + int sin_idx = it & (N - 1); + int cos_idx = (N/4 - sin_idx) & (N - 1); + + double sin_b = (sin_a0*t*t + sin_a2)*t; + double cos_b = cos_a0*t*t + 1; + + double sin_a = sin_table[sin_idx]; + double cos_a = sin_table[cos_idx]; + + double sin_val = sin_a*cos_b + cos_a*sin_b; + double cos_val = cos_a*cos_b - sin_a*sin_b; + + sinval[i] = (float)sin_val; + cosval[i] = (float)cos_val; + } +} + + +void polarToCart( InputArray src1, InputArray src2, + OutputArray dst1, OutputArray dst2, bool angleInDegrees ) +{ + Mat Mag = src1.getMat(), Angle = src2.getMat(); + int type = Angle.type(), depth = Angle.depth(), cn = Angle.channels(); + CV_Assert( Mag.empty() || (Angle.size == Mag.size && type == Mag.type() && (depth == CV_32F || depth == CV_64F))); + dst1.create( Angle.dims, Angle.size, type ); + dst2.create( Angle.dims, Angle.size, type ); + Mat X = dst1.getMat(), Y = dst2.getMat(); + + const Mat* arrays[] = {&Mag, &Angle, &X, &Y, 0}; + uchar* ptrs[4]; + NAryMatIterator it(arrays, ptrs); + cv::AutoBuffer _buf; + float* buf[2] = {0, 0}; + int j, k, total = (int)(it.size*cn), blockSize = std::min(total, ((BLOCK_SIZE+cn-1)/cn)*cn); + size_t esz1 = Angle.elemSize1(); + + if( depth == CV_64F ) + { + _buf.allocate(blockSize*2); + buf[0] = _buf; + buf[1] = buf[0] + blockSize; + } + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( j = 0; j < total; j += blockSize ) + { + int len = std::min(total - j, blockSize); + if( depth == CV_32F ) + { + const float *mag = (const float*)ptrs[0], *angle = (const float*)ptrs[1]; + float *x = (float*)ptrs[2], *y = (float*)ptrs[3]; + + SinCos_32f( angle, y, x, len, angleInDegrees ); + if( mag ) + for( k = 0; k < len; k++ ) + { + float m = mag[k]; + x[k] *= m; y[k] *= m; + } + } + else + { + const double *mag = (const double*)ptrs[0], *angle = (const double*)ptrs[1]; + double *x = (double*)ptrs[2], *y = (double*)ptrs[3]; + + for( k = 0; k < len; k++ ) + buf[0][k] = (float)angle[k]; + + SinCos_32f( buf[0], buf[1], buf[0], len, angleInDegrees ); + if( mag ) + for( k = 0; k < len; k++ ) + { + double m = mag[k]; + x[k] = buf[0][k]*m; y[k] = buf[1][k]*m; + } + else + for( k = 0; k < len; k++ ) + { + x[k] = buf[0][k]; y[k] = buf[1][k]; + } + } + + if( ptrs[0] ) + ptrs[0] += len*esz1; + ptrs[1] += len*esz1; + ptrs[2] += len*esz1; + ptrs[3] += len*esz1; + } + } +} + +/****************************************************************************************\ +* E X P * +\****************************************************************************************/ + +typedef union +{ + struct { +#if ( defined( WORDS_BIGENDIAN ) && !defined( OPENCV_UNIVERSAL_BUILD ) ) || defined( __BIG_ENDIAN__ ) + int hi; + int lo; +#else + int lo; + int hi; +#endif + } i; + double d; +} +DBLINT; + +#ifndef HAVE_IPP + +#define EXPTAB_SCALE 6 +#define EXPTAB_MASK ((1 << EXPTAB_SCALE) - 1) + +#define EXPPOLY_32F_A0 .9670371139572337719125840413672004409288e-2 + +static const double expTab[] = { + 1.0 * EXPPOLY_32F_A0, + 1.0108892860517004600204097905619 * EXPPOLY_32F_A0, + 1.0218971486541166782344801347833 * EXPPOLY_32F_A0, + 1.0330248790212284225001082839705 * EXPPOLY_32F_A0, + 1.0442737824274138403219664787399 * EXPPOLY_32F_A0, + 1.0556451783605571588083413251529 * EXPPOLY_32F_A0, + 1.0671404006768236181695211209928 * EXPPOLY_32F_A0, + 1.0787607977571197937406800374385 * EXPPOLY_32F_A0, + 1.0905077326652576592070106557607 * EXPPOLY_32F_A0, + 1.1023825833078409435564142094256 * EXPPOLY_32F_A0, + 1.1143867425958925363088129569196 * EXPPOLY_32F_A0, + 1.126521618608241899794798643787 * EXPPOLY_32F_A0, + 1.1387886347566916537038302838415 * EXPPOLY_32F_A0, + 1.151189229952982705817759635202 * EXPPOLY_32F_A0, + 1.1637248587775775138135735990922 * EXPPOLY_32F_A0, + 1.1763969916502812762846457284838 * EXPPOLY_32F_A0, + 1.1892071150027210667174999705605 * EXPPOLY_32F_A0, + 1.2021567314527031420963969574978 * EXPPOLY_32F_A0, + 1.2152473599804688781165202513388 * EXPPOLY_32F_A0, + 1.2284805361068700056940089577928 * EXPPOLY_32F_A0, + 1.2418578120734840485936774687266 * EXPPOLY_32F_A0, + 1.2553807570246910895793906574423 * EXPPOLY_32F_A0, + 1.2690509571917332225544190810323 * EXPPOLY_32F_A0, + 1.2828700160787782807266697810215 * EXPPOLY_32F_A0, + 1.2968395546510096659337541177925 * EXPPOLY_32F_A0, + 1.3109612115247643419229917863308 * EXPPOLY_32F_A0, + 1.3252366431597412946295370954987 * EXPPOLY_32F_A0, + 1.3396675240533030053600306697244 * EXPPOLY_32F_A0, + 1.3542555469368927282980147401407 * EXPPOLY_32F_A0, + 1.3690024229745906119296011329822 * EXPPOLY_32F_A0, + 1.3839098819638319548726595272652 * EXPPOLY_32F_A0, + 1.3989796725383111402095281367152 * EXPPOLY_32F_A0, + 1.4142135623730950488016887242097 * EXPPOLY_32F_A0, + 1.4296133383919700112350657782751 * EXPPOLY_32F_A0, + 1.4451808069770466200370062414717 * EXPPOLY_32F_A0, + 1.4609177941806469886513028903106 * EXPPOLY_32F_A0, + 1.476826145939499311386907480374 * EXPPOLY_32F_A0, + 1.4929077282912648492006435314867 * EXPPOLY_32F_A0, + 1.5091644275934227397660195510332 * EXPPOLY_32F_A0, + 1.5255981507445383068512536895169 * EXPPOLY_32F_A0, + 1.5422108254079408236122918620907 * EXPPOLY_32F_A0, + 1.5590044002378369670337280894749 * EXPPOLY_32F_A0, + 1.5759808451078864864552701601819 * EXPPOLY_32F_A0, + 1.5931421513422668979372486431191 * EXPPOLY_32F_A0, + 1.6104903319492543081795206673574 * EXPPOLY_32F_A0, + 1.628027421857347766848218522014 * EXPPOLY_32F_A0, + 1.6457554781539648445187567247258 * EXPPOLY_32F_A0, + 1.6636765803267364350463364569764 * EXPPOLY_32F_A0, + 1.6817928305074290860622509524664 * EXPPOLY_32F_A0, + 1.7001063537185234695013625734975 * EXPPOLY_32F_A0, + 1.7186192981224779156293443764563 * EXPPOLY_32F_A0, + 1.7373338352737062489942020818722 * EXPPOLY_32F_A0, + 1.7562521603732994831121606193753 * EXPPOLY_32F_A0, + 1.7753764925265212525505592001993 * EXPPOLY_32F_A0, + 1.7947090750031071864277032421278 * EXPPOLY_32F_A0, + 1.8142521755003987562498346003623 * EXPPOLY_32F_A0, + 1.8340080864093424634870831895883 * EXPPOLY_32F_A0, + 1.8539791250833855683924530703377 * EXPPOLY_32F_A0, + 1.8741676341102999013299989499544 * EXPPOLY_32F_A0, + 1.8945759815869656413402186534269 * EXPPOLY_32F_A0, + 1.9152065613971472938726112702958 * EXPPOLY_32F_A0, + 1.9360617934922944505980559045667 * EXPPOLY_32F_A0, + 1.9571441241754002690183222516269 * EXPPOLY_32F_A0, + 1.9784560263879509682582499181312 * EXPPOLY_32F_A0, +}; + + +// the code below uses _mm_cast* intrinsics, which are not avialable on VS2005 +#if (defined _MSC_VER && _MSC_VER < 1500) || \ + (!defined __APPLE__ && defined __GNUC__ && __GNUC__*100 + __GNUC_MINOR__ < 402) +#undef CV_SSE2 +#define CV_SSE2 0 +#endif + +static const double exp_prescale = 1.4426950408889634073599246810019 * (1 << EXPTAB_SCALE); +static const double exp_postscale = 1./(1 << EXPTAB_SCALE); +static const double exp_max_val = 3000.*(1 << EXPTAB_SCALE); // log10(DBL_MAX) < 3000 + +static void Exp_32f( const float *_x, float *y, int n ) +{ + static const float + A4 = (float)(1.000000000000002438532970795181890933776 / EXPPOLY_32F_A0), + A3 = (float)(.6931471805521448196800669615864773144641 / EXPPOLY_32F_A0), + A2 = (float)(.2402265109513301490103372422686535526573 / EXPPOLY_32F_A0), + A1 = (float)(.5550339366753125211915322047004666939128e-1 / EXPPOLY_32F_A0); + +#undef EXPPOLY +#define EXPPOLY(x) \ + (((((x) + A1)*(x) + A2)*(x) + A3)*(x) + A4) + + int i = 0; + const Cv32suf* x = (const Cv32suf*)_x; + Cv32suf buf[4]; + +#if CV_SSE2 + if( n >= 8 && USE_SSE2 ) + { + static const __m128d prescale2 = _mm_set1_pd(exp_prescale); + static const __m128 postscale4 = _mm_set1_ps((float)exp_postscale); + static const __m128 maxval4 = _mm_set1_ps((float)(exp_max_val/exp_prescale)); + static const __m128 minval4 = _mm_set1_ps((float)(-exp_max_val/exp_prescale)); + + static const __m128 mA1 = _mm_set1_ps(A1); + static const __m128 mA2 = _mm_set1_ps(A2); + static const __m128 mA3 = _mm_set1_ps(A3); + static const __m128 mA4 = _mm_set1_ps(A4); + bool y_aligned = (size_t)(void*)y % 16 == 0; + + ushort CV_DECL_ALIGNED(16) tab_idx[8]; + + for( ; i <= n - 8; i += 8 ) + { + __m128 xf0, xf1; + xf0 = _mm_loadu_ps(&x[i].f); + xf1 = _mm_loadu_ps(&x[i+4].f); + __m128i xi0, xi1, xi2, xi3; + + xf0 = _mm_min_ps(_mm_max_ps(xf0, minval4), maxval4); + xf1 = _mm_min_ps(_mm_max_ps(xf1, minval4), maxval4); + + __m128d xd0 = _mm_cvtps_pd(xf0); + __m128d xd2 = _mm_cvtps_pd(_mm_movehl_ps(xf0, xf0)); + __m128d xd1 = _mm_cvtps_pd(xf1); + __m128d xd3 = _mm_cvtps_pd(_mm_movehl_ps(xf1, xf1)); + + xd0 = _mm_mul_pd(xd0, prescale2); + xd2 = _mm_mul_pd(xd2, prescale2); + xd1 = _mm_mul_pd(xd1, prescale2); + xd3 = _mm_mul_pd(xd3, prescale2); + + xi0 = _mm_cvtpd_epi32(xd0); + xi2 = _mm_cvtpd_epi32(xd2); + + xi1 = _mm_cvtpd_epi32(xd1); + xi3 = _mm_cvtpd_epi32(xd3); + + xd0 = _mm_sub_pd(xd0, _mm_cvtepi32_pd(xi0)); + xd2 = _mm_sub_pd(xd2, _mm_cvtepi32_pd(xi2)); + xd1 = _mm_sub_pd(xd1, _mm_cvtepi32_pd(xi1)); + xd3 = _mm_sub_pd(xd3, _mm_cvtepi32_pd(xi3)); + + xf0 = _mm_movelh_ps(_mm_cvtpd_ps(xd0), _mm_cvtpd_ps(xd2)); + xf1 = _mm_movelh_ps(_mm_cvtpd_ps(xd1), _mm_cvtpd_ps(xd3)); + + xf0 = _mm_mul_ps(xf0, postscale4); + xf1 = _mm_mul_ps(xf1, postscale4); + + xi0 = _mm_unpacklo_epi64(xi0, xi2); + xi1 = _mm_unpacklo_epi64(xi1, xi3); + xi0 = _mm_packs_epi32(xi0, xi1); + + _mm_store_si128((__m128i*)tab_idx, _mm_and_si128(xi0, _mm_set1_epi16(EXPTAB_MASK))); + + xi0 = _mm_add_epi16(_mm_srai_epi16(xi0, EXPTAB_SCALE), _mm_set1_epi16(127)); + xi0 = _mm_max_epi16(xi0, _mm_setzero_si128()); + xi0 = _mm_min_epi16(xi0, _mm_set1_epi16(255)); + xi1 = _mm_unpackhi_epi16(xi0, _mm_setzero_si128()); + xi0 = _mm_unpacklo_epi16(xi0, _mm_setzero_si128()); + + __m128d yd0 = _mm_unpacklo_pd(_mm_load_sd(expTab + tab_idx[0]), _mm_load_sd(expTab + tab_idx[1])); + __m128d yd1 = _mm_unpacklo_pd(_mm_load_sd(expTab + tab_idx[2]), _mm_load_sd(expTab + tab_idx[3])); + __m128d yd2 = _mm_unpacklo_pd(_mm_load_sd(expTab + tab_idx[4]), _mm_load_sd(expTab + tab_idx[5])); + __m128d yd3 = _mm_unpacklo_pd(_mm_load_sd(expTab + tab_idx[6]), _mm_load_sd(expTab + tab_idx[7])); + + __m128 yf0 = _mm_movelh_ps(_mm_cvtpd_ps(yd0), _mm_cvtpd_ps(yd1)); + __m128 yf1 = _mm_movelh_ps(_mm_cvtpd_ps(yd2), _mm_cvtpd_ps(yd3)); + + yf0 = _mm_mul_ps(yf0, _mm_castsi128_ps(_mm_slli_epi32(xi0, 23))); + yf1 = _mm_mul_ps(yf1, _mm_castsi128_ps(_mm_slli_epi32(xi1, 23))); + + __m128 zf0 = _mm_add_ps(xf0, mA1); + __m128 zf1 = _mm_add_ps(xf1, mA1); + + zf0 = _mm_add_ps(_mm_mul_ps(zf0, xf0), mA2); + zf1 = _mm_add_ps(_mm_mul_ps(zf1, xf1), mA2); + + zf0 = _mm_add_ps(_mm_mul_ps(zf0, xf0), mA3); + zf1 = _mm_add_ps(_mm_mul_ps(zf1, xf1), mA3); + + zf0 = _mm_add_ps(_mm_mul_ps(zf0, xf0), mA4); + zf1 = _mm_add_ps(_mm_mul_ps(zf1, xf1), mA4); + + zf0 = _mm_mul_ps(zf0, yf0); + zf1 = _mm_mul_ps(zf1, yf1); + + if( y_aligned ) + { + _mm_store_ps(y + i, zf0); + _mm_store_ps(y + i + 4, zf1); + } + else + { + _mm_storeu_ps(y + i, zf0); + _mm_storeu_ps(y + i + 4, zf1); + } + } + } + else +#endif + for( ; i <= n - 4; i += 4 ) + { + double x0 = x[i].f * exp_prescale; + double x1 = x[i + 1].f * exp_prescale; + double x2 = x[i + 2].f * exp_prescale; + double x3 = x[i + 3].f * exp_prescale; + int val0, val1, val2, val3, t; + + if( ((x[i].i >> 23) & 255) > 127 + 10 ) + x0 = x[i].i < 0 ? -exp_max_val : exp_max_val; + + if( ((x[i+1].i >> 23) & 255) > 127 + 10 ) + x1 = x[i+1].i < 0 ? -exp_max_val : exp_max_val; + + if( ((x[i+2].i >> 23) & 255) > 127 + 10 ) + x2 = x[i+2].i < 0 ? -exp_max_val : exp_max_val; + + if( ((x[i+3].i >> 23) & 255) > 127 + 10 ) + x3 = x[i+3].i < 0 ? -exp_max_val : exp_max_val; + + val0 = cvRound(x0); + val1 = cvRound(x1); + val2 = cvRound(x2); + val3 = cvRound(x3); + + x0 = (x0 - val0)*exp_postscale; + x1 = (x1 - val1)*exp_postscale; + x2 = (x2 - val2)*exp_postscale; + x3 = (x3 - val3)*exp_postscale; + + t = (val0 >> EXPTAB_SCALE) + 127; + t = !(t & ~255) ? t : t < 0 ? 0 : 255; + buf[0].i = t << 23; + + t = (val1 >> EXPTAB_SCALE) + 127; + t = !(t & ~255) ? t : t < 0 ? 0 : 255; + buf[1].i = t << 23; + + t = (val2 >> EXPTAB_SCALE) + 127; + t = !(t & ~255) ? t : t < 0 ? 0 : 255; + buf[2].i = t << 23; + + t = (val3 >> EXPTAB_SCALE) + 127; + t = !(t & ~255) ? t : t < 0 ? 0 : 255; + buf[3].i = t << 23; + + x0 = buf[0].f * expTab[val0 & EXPTAB_MASK] * EXPPOLY( x0 ); + x1 = buf[1].f * expTab[val1 & EXPTAB_MASK] * EXPPOLY( x1 ); + + y[i] = (float)x0; + y[i + 1] = (float)x1; + + x2 = buf[2].f * expTab[val2 & EXPTAB_MASK] * EXPPOLY( x2 ); + x3 = buf[3].f * expTab[val3 & EXPTAB_MASK] * EXPPOLY( x3 ); + + y[i + 2] = (float)x2; + y[i + 3] = (float)x3; + } + + for( ; i < n; i++ ) + { + double x0 = x[i].f * exp_prescale; + int val0, t; + + if( ((x[i].i >> 23) & 255) > 127 + 10 ) + x0 = x[i].i < 0 ? -exp_max_val : exp_max_val; + + val0 = cvRound(x0); + t = (val0 >> EXPTAB_SCALE) + 127; + t = !(t & ~255) ? t : t < 0 ? 0 : 255; + + buf[0].i = t << 23; + x0 = (x0 - val0)*exp_postscale; + + y[i] = (float)(buf[0].f * expTab[val0 & EXPTAB_MASK] * EXPPOLY(x0)); + } +} + + +static void Exp_64f( const double *_x, double *y, int n ) +{ + static const double + A5 = .99999999999999999998285227504999 / EXPPOLY_32F_A0, + A4 = .69314718055994546743029643825322 / EXPPOLY_32F_A0, + A3 = .24022650695886477918181338054308 / EXPPOLY_32F_A0, + A2 = .55504108793649567998466049042729e-1 / EXPPOLY_32F_A0, + A1 = .96180973140732918010002372686186e-2 / EXPPOLY_32F_A0, + A0 = .13369713757180123244806654839424e-2 / EXPPOLY_32F_A0; + +#undef EXPPOLY +#define EXPPOLY(x) (((((A0*(x) + A1)*(x) + A2)*(x) + A3)*(x) + A4)*(x) + A5) + + int i = 0; + Cv64suf buf[4]; + const Cv64suf* x = (const Cv64suf*)_x; + +#if CV_SSE2 + if( USE_SSE2 ) + { + static const __m128d prescale2 = _mm_set1_pd(exp_prescale); + static const __m128d postscale2 = _mm_set1_pd(exp_postscale); + static const __m128d maxval2 = _mm_set1_pd(exp_max_val); + static const __m128d minval2 = _mm_set1_pd(-exp_max_val); + + static const __m128d mA0 = _mm_set1_pd(A0); + static const __m128d mA1 = _mm_set1_pd(A1); + static const __m128d mA2 = _mm_set1_pd(A2); + static const __m128d mA3 = _mm_set1_pd(A3); + static const __m128d mA4 = _mm_set1_pd(A4); + static const __m128d mA5 = _mm_set1_pd(A5); + + int CV_DECL_ALIGNED(16) tab_idx[4]; + + for( ; i <= n - 4; i += 4 ) + { + __m128d xf0 = _mm_loadu_pd(&x[i].f), xf1 = _mm_loadu_pd(&x[i+2].f); + __m128i xi0, xi1; + xf0 = _mm_min_pd(_mm_max_pd(xf0, minval2), maxval2); + xf1 = _mm_min_pd(_mm_max_pd(xf1, minval2), maxval2); + xf0 = _mm_mul_pd(xf0, prescale2); + xf1 = _mm_mul_pd(xf1, prescale2); + + xi0 = _mm_cvtpd_epi32(xf0); + xi1 = _mm_cvtpd_epi32(xf1); + xf0 = _mm_mul_pd(_mm_sub_pd(xf0, _mm_cvtepi32_pd(xi0)), postscale2); + xf1 = _mm_mul_pd(_mm_sub_pd(xf1, _mm_cvtepi32_pd(xi1)), postscale2); + + xi0 = _mm_unpacklo_epi64(xi0, xi1); + _mm_store_si128((__m128i*)tab_idx, _mm_and_si128(xi0, _mm_set1_epi32(EXPTAB_MASK))); + + xi0 = _mm_add_epi32(_mm_srai_epi32(xi0, EXPTAB_SCALE), _mm_set1_epi32(1023)); + xi0 = _mm_packs_epi32(xi0, xi0); + xi0 = _mm_max_epi16(xi0, _mm_setzero_si128()); + xi0 = _mm_min_epi16(xi0, _mm_set1_epi16(2047)); + xi0 = _mm_unpacklo_epi16(xi0, _mm_setzero_si128()); + xi1 = _mm_unpackhi_epi32(xi0, _mm_setzero_si128()); + xi0 = _mm_unpacklo_epi32(xi0, _mm_setzero_si128()); + + __m128d yf0 = _mm_unpacklo_pd(_mm_load_sd(expTab + tab_idx[0]), _mm_load_sd(expTab + tab_idx[1])); + __m128d yf1 = _mm_unpacklo_pd(_mm_load_sd(expTab + tab_idx[2]), _mm_load_sd(expTab + tab_idx[3])); + yf0 = _mm_mul_pd(yf0, _mm_castsi128_pd(_mm_slli_epi64(xi0, 52))); + yf1 = _mm_mul_pd(yf1, _mm_castsi128_pd(_mm_slli_epi64(xi1, 52))); + + __m128d zf0 = _mm_add_pd(_mm_mul_pd(mA0, xf0), mA1); + __m128d zf1 = _mm_add_pd(_mm_mul_pd(mA0, xf1), mA1); + + zf0 = _mm_add_pd(_mm_mul_pd(zf0, xf0), mA2); + zf1 = _mm_add_pd(_mm_mul_pd(zf1, xf1), mA2); + + zf0 = _mm_add_pd(_mm_mul_pd(zf0, xf0), mA3); + zf1 = _mm_add_pd(_mm_mul_pd(zf1, xf1), mA3); + + zf0 = _mm_add_pd(_mm_mul_pd(zf0, xf0), mA4); + zf1 = _mm_add_pd(_mm_mul_pd(zf1, xf1), mA4); + + zf0 = _mm_add_pd(_mm_mul_pd(zf0, xf0), mA5); + zf1 = _mm_add_pd(_mm_mul_pd(zf1, xf1), mA5); + + zf0 = _mm_mul_pd(zf0, yf0); + zf1 = _mm_mul_pd(zf1, yf1); + + _mm_storeu_pd(y + i, zf0); + _mm_storeu_pd(y + i + 2, zf1); + } + } + else +#endif + for( ; i <= n - 4; i += 4 ) + { + double x0 = x[i].f * exp_prescale; + double x1 = x[i + 1].f * exp_prescale; + double x2 = x[i + 2].f * exp_prescale; + double x3 = x[i + 3].f * exp_prescale; + + double y0, y1, y2, y3; + int val0, val1, val2, val3, t; + + t = (int)(x[i].i >> 52); + if( (t & 2047) > 1023 + 10 ) + x0 = t < 0 ? -exp_max_val : exp_max_val; + + t = (int)(x[i+1].i >> 52); + if( (t & 2047) > 1023 + 10 ) + x1 = t < 0 ? -exp_max_val : exp_max_val; + + t = (int)(x[i+2].i >> 52); + if( (t & 2047) > 1023 + 10 ) + x2 = t < 0 ? -exp_max_val : exp_max_val; + + t = (int)(x[i+3].i >> 52); + if( (t & 2047) > 1023 + 10 ) + x3 = t < 0 ? -exp_max_val : exp_max_val; + + val0 = cvRound(x0); + val1 = cvRound(x1); + val2 = cvRound(x2); + val3 = cvRound(x3); + + x0 = (x0 - val0)*exp_postscale; + x1 = (x1 - val1)*exp_postscale; + x2 = (x2 - val2)*exp_postscale; + x3 = (x3 - val3)*exp_postscale; + + t = (val0 >> EXPTAB_SCALE) + 1023; + t = !(t & ~2047) ? t : t < 0 ? 0 : 2047; + buf[0].i = (int64)t << 52; + + t = (val1 >> EXPTAB_SCALE) + 1023; + t = !(t & ~2047) ? t : t < 0 ? 0 : 2047; + buf[1].i = (int64)t << 52; + + t = (val2 >> EXPTAB_SCALE) + 1023; + t = !(t & ~2047) ? t : t < 0 ? 0 : 2047; + buf[2].i = (int64)t << 52; + + t = (val3 >> EXPTAB_SCALE) + 1023; + t = !(t & ~2047) ? t : t < 0 ? 0 : 2047; + buf[3].i = (int64)t << 52; + + y0 = buf[0].f * expTab[val0 & EXPTAB_MASK] * EXPPOLY( x0 ); + y1 = buf[1].f * expTab[val1 & EXPTAB_MASK] * EXPPOLY( x1 ); + + y[i] = y0; + y[i + 1] = y1; + + y2 = buf[2].f * expTab[val2 & EXPTAB_MASK] * EXPPOLY( x2 ); + y3 = buf[3].f * expTab[val3 & EXPTAB_MASK] * EXPPOLY( x3 ); + + y[i + 2] = y2; + y[i + 3] = y3; + } + + for( ; i < n; i++ ) + { + double x0 = x[i].f * exp_prescale; + int val0, t; + + t = (int)(x[i].i >> 52); + if( (t & 2047) > 1023 + 10 ) + x0 = t < 0 ? -exp_max_val : exp_max_val; + + val0 = cvRound(x0); + t = (val0 >> EXPTAB_SCALE) + 1023; + t = !(t & ~2047) ? t : t < 0 ? 0 : 2047; + + buf[0].i = (int64)t << 52; + x0 = (x0 - val0)*exp_postscale; + + y[i] = buf[0].f * expTab[val0 & EXPTAB_MASK] * EXPPOLY( x0 ); + } +} + +#undef EXPTAB_SCALE +#undef EXPTAB_MASK +#undef EXPPOLY_32F_A0 + +#else + +#define Exp_32f ippsExp_32f_A21 +#define Exp_64f ippsExp_64f_A50 + +#endif + +void exp( InputArray _src, OutputArray _dst ) +{ + Mat src = _src.getMat(); + int type = src.type(), depth = src.depth(), cn = src.channels(); + + _dst.create( src.dims, src.size, type ); + Mat dst = _dst.getMat(); + + CV_Assert( depth == CV_32F || depth == CV_64F ); + + const Mat* arrays[] = {&src, &dst, 0}; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs); + int len = (int)(it.size*cn); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + if( depth == CV_32F ) + Exp_32f( (const float*)ptrs[0], (float*)ptrs[1], len ); + else + Exp_64f( (const double*)ptrs[0], (double*)ptrs[1], len ); + } +} + + +/****************************************************************************************\ +* L O G * +\****************************************************************************************/ + +#ifndef HAVE_IPP + +#define LOGTAB_SCALE 8 +#define LOGTAB_MASK ((1 << LOGTAB_SCALE) - 1) +#define LOGTAB_MASK2 ((1 << (20 - LOGTAB_SCALE)) - 1) +#define LOGTAB_MASK2_32F ((1 << (23 - LOGTAB_SCALE)) - 1) + +static const double CV_DECL_ALIGNED(16) icvLogTab[] = { +0.0000000000000000000000000000000000000000, 1.000000000000000000000000000000000000000, +.00389864041565732288852075271279318258166, .9961089494163424124513618677042801556420, +.00778214044205494809292034119607706088573, .9922480620155038759689922480620155038760, +.01165061721997527263705585198749759001657, .9884169884169884169884169884169884169884, +.01550418653596525274396267235488267033361, .9846153846153846153846153846153846153846, +.01934296284313093139406447562578250654042, .9808429118773946360153256704980842911877, +.02316705928153437593630670221500622574241, .9770992366412213740458015267175572519084, +.02697658769820207233514075539915211265906, .9733840304182509505703422053231939163498, +.03077165866675368732785500469617545604706, .9696969696969696969696969696969696969697, +.03455238150665972812758397481047722976656, .9660377358490566037735849056603773584906, +.03831886430213659461285757856785494368522, .9624060150375939849624060150375939849624, +.04207121392068705056921373852674150839447, .9588014981273408239700374531835205992509, +.04580953603129420126371940114040626212953, .9552238805970149253731343283582089552239, +.04953393512227662748292900118940451648088, .9516728624535315985130111524163568773234, +.05324451451881227759255210685296333394944, .9481481481481481481481481481481481481481, +.05694137640013842427411105973078520037234, .9446494464944649446494464944649446494465, +.06062462181643483993820353816772694699466, .9411764705882352941176470588235294117647, +.06429435070539725460836422143984236754475, .9377289377289377289377289377289377289377, +.06795066190850773679699159401934593915938, .9343065693430656934306569343065693430657, +.07159365318700880442825962290953611955044, .9309090909090909090909090909090909090909, +.07522342123758751775142172846244648098944, .9275362318840579710144927536231884057971, +.07884006170777602129362549021607264876369, .9241877256317689530685920577617328519856, +.08244366921107458556772229485432035289706, .9208633093525179856115107913669064748201, +.08603433734180314373940490213499288074675, .9175627240143369175627240143369175627240, +.08961215868968712416897659522874164395031, .9142857142857142857142857142857142857143, +.09317722485418328259854092721070628613231, .9110320284697508896797153024911032028470, +.09672962645855109897752299730200320482256, .9078014184397163120567375886524822695035, +.10026945316367513738597949668474029749630, .9045936395759717314487632508833922261484, +.10379679368164355934833764649738441221420, .9014084507042253521126760563380281690141, +.10731173578908805021914218968959175981580, .8982456140350877192982456140350877192982, +.11081436634029011301105782649756292812530, .8951048951048951048951048951048951048951, +.11430477128005862852422325204315711744130, .8919860627177700348432055749128919860627, +.11778303565638344185817487641543266363440, .8888888888888888888888888888888888888889, +.12124924363286967987640707633545389398930, .8858131487889273356401384083044982698962, +.12470347850095722663787967121606925502420, .8827586206896551724137931034482758620690, +.12814582269193003360996385708858724683530, .8797250859106529209621993127147766323024, +.13157635778871926146571524895989568904040, .8767123287671232876712328767123287671233, +.13499516453750481925766280255629681050780, .8737201365187713310580204778156996587031, +.13840232285911913123754857224412262439730, .8707482993197278911564625850340136054422, +.14179791186025733629172407290752744302150, .8677966101694915254237288135593220338983, +.14518200984449788903951628071808954700830, .8648648648648648648648648648648648648649, +.14855469432313711530824207329715136438610, .8619528619528619528619528619528619528620, +.15191604202584196858794030049466527998450, .8590604026845637583892617449664429530201, +.15526612891112392955683674244937719777230, .8561872909698996655518394648829431438127, +.15860503017663857283636730244325008243330, .8533333333333333333333333333333333333333, +.16193282026931324346641360989451641216880, .8504983388704318936877076411960132890365, +.16524957289530714521497145597095368430010, .8476821192052980132450331125827814569536, +.16855536102980664403538924034364754334090, .8448844884488448844884488448844884488449, +.17185025692665920060697715143760433420540, .8421052631578947368421052631578947368421, +.17513433212784912385018287750426679849630, .8393442622950819672131147540983606557377, +.17840765747281828179637841458315961062910, .8366013071895424836601307189542483660131, +.18167030310763465639212199675966985523700, .8338762214983713355048859934853420195440, +.18492233849401198964024217730184318497780, .8311688311688311688311688311688311688312, +.18816383241818296356839823602058459073300, .8284789644012944983818770226537216828479, +.19139485299962943898322009772527962923050, .8258064516129032258064516129032258064516, +.19461546769967164038916962454095482826240, .8231511254019292604501607717041800643087, +.19782574332991986754137769821682013571260, .8205128205128205128205128205128205128205, +.20102574606059073203390141770796617493040, .8178913738019169329073482428115015974441, +.20421554142869088876999228432396193966280, .8152866242038216560509554140127388535032, +.20739519434607056602715147164417430758480, .8126984126984126984126984126984126984127, +.21056476910734961416338251183333341032260, .8101265822784810126582278481012658227848, +.21372432939771812687723695489694364368910, .8075709779179810725552050473186119873817, +.21687393830061435506806333251006435602900, .8050314465408805031446540880503144654088, +.22001365830528207823135744547471404075630, .8025078369905956112852664576802507836991, +.22314355131420973710199007200571941211830, .8000000000000000000000000000000000000000, +.22626367865045338145790765338460914790630, .7975077881619937694704049844236760124611, +.22937410106484582006380890106811420992010, .7950310559006211180124223602484472049689, +.23247487874309405442296849741978803649550, .7925696594427244582043343653250773993808, +.23556607131276688371634975283086532726890, .7901234567901234567901234567901234567901, +.23864773785017498464178231643018079921600, .7876923076923076923076923076923076923077, +.24171993688714515924331749374687206000090, .7852760736196319018404907975460122699387, +.24478272641769091566565919038112042471760, .7828746177370030581039755351681957186544, +.24783616390458124145723672882013488560910, .7804878048780487804878048780487804878049, +.25088030628580937353433455427875742316250, .7781155015197568389057750759878419452888, +.25391520998096339667426946107298135757450, .7757575757575757575757575757575757575758, +.25694093089750041913887912414793390780680, .7734138972809667673716012084592145015106, +.25995752443692604627401010475296061486000, .7710843373493975903614457831325301204819, +.26296504550088134477547896494797896593800, .7687687687687687687687687687687687687688, +.26596354849713793599974565040611196309330, .7664670658682634730538922155688622754491, +.26895308734550393836570947314612567424780, .7641791044776119402985074626865671641791, +.27193371548364175804834985683555714786050, .7619047619047619047619047619047619047619, +.27490548587279922676529508862586226314300, .7596439169139465875370919881305637982196, +.27786845100345625159121709657483734190480, .7573964497041420118343195266272189349112, +.28082266290088775395616949026589281857030, .7551622418879056047197640117994100294985, +.28376817313064456316240580235898960381750, .7529411764705882352941176470588235294118, +.28670503280395426282112225635501090437180, .7507331378299120234604105571847507331378, +.28963329258304265634293983566749375313530, .7485380116959064327485380116959064327485, +.29255300268637740579436012922087684273730, .7463556851311953352769679300291545189504, +.29546421289383584252163927885703742504130, .7441860465116279069767441860465116279070, +.29836697255179722709783618483925238251680, .7420289855072463768115942028985507246377, +.30126133057816173455023545102449133992200, .7398843930635838150289017341040462427746, +.30414733546729666446850615102448500692850, .7377521613832853025936599423631123919308, +.30702503529491181888388950937951449304830, .7356321839080459770114942528735632183908, +.30989447772286465854207904158101882785550, .7335243553008595988538681948424068767908, +.31275571000389684739317885942000430077330, .7314285714285714285714285714285714285714, +.31560877898630329552176476681779604405180, .7293447293447293447293447293447293447293, +.31845373111853458869546784626436419785030, .7272727272727272727272727272727272727273, +.32129061245373424782201254856772720813750, .7252124645892351274787535410764872521246, +.32411946865421192853773391107097268104550, .7231638418079096045197740112994350282486, +.32694034499585328257253991068864706903700, .7211267605633802816901408450704225352113, +.32975328637246797969240219572384376078850, .7191011235955056179775280898876404494382, +.33255833730007655635318997155991382896900, .7170868347338935574229691876750700280112, +.33535554192113781191153520921943709254280, .7150837988826815642458100558659217877095, +.33814494400871636381467055798566434532400, .7130919220055710306406685236768802228412, +.34092658697059319283795275623560883104800, .7111111111111111111111111111111111111111, +.34370051385331840121395430287520866841080, .7091412742382271468144044321329639889197, +.34646676734620857063262633346312213689100, .7071823204419889502762430939226519337017, +.34922538978528827602332285096053965389730, .7052341597796143250688705234159779614325, +.35197642315717814209818925519357435405250, .7032967032967032967032967032967032967033, +.35471990910292899856770532096561510115850, .7013698630136986301369863013698630136986, +.35745588892180374385176833129662554711100, .6994535519125683060109289617486338797814, +.36018440357500774995358483465679455548530, .6975476839237057220708446866485013623978, +.36290549368936841911903457003063522279280, .6956521739130434782608695652173913043478, +.36561919956096466943762379742111079394830, .6937669376693766937669376693766937669377, +.36832556115870762614150635272380895912650, .6918918918918918918918918918918918918919, +.37102461812787262962487488948681857436900, .6900269541778975741239892183288409703504, +.37371640979358405898480555151763837784530, .6881720430107526881720430107526881720430, +.37640097516425302659470730759494472295050, .6863270777479892761394101876675603217158, +.37907835293496944251145919224654790014030, .6844919786096256684491978609625668449198, +.38174858149084833769393299007788300514230, .6826666666666666666666666666666666666667, +.38441169891033200034513583887019194662580, .6808510638297872340425531914893617021277, +.38706774296844825844488013899535872042180, .6790450928381962864721485411140583554377, +.38971675114002518602873692543653305619950, .6772486772486772486772486772486772486772, +.39235876060286384303665840889152605086580, .6754617414248021108179419525065963060686, +.39499380824086893770896722344332374632350, .6736842105263157894736842105263157894737, +.39762193064713846624158577469643205404280, .6719160104986876640419947506561679790026, +.40024316412701266276741307592601515352730, .6701570680628272251308900523560209424084, +.40285754470108348090917615991202183067800, .6684073107049608355091383812010443864230, +.40546510810816432934799991016916465014230, .6666666666666666666666666666666666666667, +.40806588980822172674223224930756259709600, .6649350649350649350649350649350649350649, +.41065992498526837639616360320360399782650, .6632124352331606217616580310880829015544, +.41324724855021932601317757871584035456180, .6614987080103359173126614987080103359173, +.41582789514371093497757669865677598863850, .6597938144329896907216494845360824742268, +.41840189913888381489925905043492093682300, .6580976863753213367609254498714652956298, +.42096929464412963239894338585145305842150, .6564102564102564102564102564102564102564, +.42353011550580327293502591601281892508280, .6547314578005115089514066496163682864450, +.42608439531090003260516141381231136620050, .6530612244897959183673469387755102040816, +.42863216738969872610098832410585600882780, .6513994910941475826972010178117048346056, +.43117346481837132143866142541810404509300, .6497461928934010152284263959390862944162, +.43370832042155937902094819946796633303180, .6481012658227848101265822784810126582278, +.43623676677491801667585491486534010618930, .6464646464646464646464646464646464646465, +.43875883620762790027214350629947148263450, .6448362720403022670025188916876574307305, +.44127456080487520440058801796112675219780, .6432160804020100502512562814070351758794, +.44378397241030093089975139264424797147500, .6416040100250626566416040100250626566416, +.44628710262841947420398014401143882423650, .6400000000000000000000000000000000000000, +.44878398282700665555822183705458883196130, .6384039900249376558603491271820448877805, +.45127464413945855836729492693848442286250, .6368159203980099502487562189054726368159, +.45375911746712049854579618113348260521900, .6352357320099255583126550868486352357320, +.45623743348158757315857769754074979573500, .6336633663366336633663366336633663366337, +.45870962262697662081833982483658473938700, .6320987654320987654320987654320987654321, +.46117571512217014895185229761409573256980, .6305418719211822660098522167487684729064, +.46363574096303250549055974261136725544930, .6289926289926289926289926289926289926290, +.46608972992459918316399125615134835243230, .6274509803921568627450980392156862745098, +.46853771156323925639597405279346276074650, .6259168704156479217603911980440097799511, +.47097971521879100631480241645476780831830, .6243902439024390243902439024390243902439, +.47341577001667212165614273544633761048330, .6228710462287104622871046228710462287105, +.47584590486996386493601107758877333253630, .6213592233009708737864077669902912621359, +.47827014848147025860569669930555392056700, .6198547215496368038740920096852300242131, +.48068852934575190261057286988943815231330, .6183574879227053140096618357487922705314, +.48310107575113581113157579238759353756900, .6168674698795180722891566265060240963855, +.48550781578170076890899053978500887751580, .6153846153846153846153846153846153846154, +.48790877731923892879351001283794175833480, .6139088729016786570743405275779376498801, +.49030398804519381705802061333088204264650, .6124401913875598086124401913875598086124, +.49269347544257524607047571407747454941280, .6109785202863961813842482100238663484487, +.49507726679785146739476431321236304938800, .6095238095238095238095238095238095238095, +.49745538920281889838648226032091770321130, .6080760095011876484560570071258907363420, +.49982786955644931126130359189119189977650, .6066350710900473933649289099526066350711, +.50219473456671548383667413872899487614650, .6052009456264775413711583924349881796690, +.50455601075239520092452494282042607665050, .6037735849056603773584905660377358490566, +.50691172444485432801997148999362252652650, .6023529411764705882352941176470588235294, +.50926190178980790257412536448100581765150, .6009389671361502347417840375586854460094, +.51160656874906207391973111953120678663250, .5995316159250585480093676814988290398126, +.51394575110223428282552049495279788970950, .5981308411214953271028037383177570093458, +.51627947444845445623684554448118433356300, .5967365967365967365967365967365967365967, +.51860776420804555186805373523384332656850, .5953488372093023255813953488372093023256, +.52093064562418522900344441950437612831600, .5939675174013921113689095127610208816705, +.52324814376454775732838697877014055848100, .5925925925925925925925925925925925925926, +.52556028352292727401362526507000438869000, .5912240184757505773672055427251732101617, +.52786708962084227803046587723656557500350, .5898617511520737327188940092165898617512, +.53016858660912158374145519701414741575700, .5885057471264367816091954022988505747126, +.53246479886947173376654518506256863474850, .5871559633027522935779816513761467889908, +.53475575061602764748158733709715306758900, .5858123569794050343249427917620137299771, +.53704146589688361856929077475797384977350, .5844748858447488584474885844748858447489, +.53932196859560876944783558428753167390800, .5831435079726651480637813211845102505695, +.54159728243274429804188230264117009937750, .5818181818181818181818181818181818181818, +.54386743096728351609669971367111429572100, .5804988662131519274376417233560090702948, +.54613243759813556721383065450936555862450, .5791855203619909502262443438914027149321, +.54839232556557315767520321969641372561450, .5778781038374717832957110609480812641084, +.55064711795266219063194057525834068655950, .5765765765765765765765765765765765765766, +.55289683768667763352766542084282264113450, .5752808988764044943820224719101123595506, +.55514150754050151093110798683483153581600, .5739910313901345291479820627802690582960, +.55738115013400635344709144192165695130850, .5727069351230425055928411633109619686801, +.55961578793542265941596269840374588966350, .5714285714285714285714285714285714285714, +.56184544326269181269140062795486301183700, .5701559020044543429844097995545657015590, +.56407013828480290218436721261241473257550, .5688888888888888888888888888888888888889, +.56628989502311577464155334382667206227800, .5676274944567627494456762749445676274945, +.56850473535266865532378233183408156037350, .5663716814159292035398230088495575221239, +.57071468100347144680739575051120482385150, .5651214128035320088300220750551876379691, +.57291975356178548306473885531886480748650, .5638766519823788546255506607929515418502, +.57511997447138785144460371157038025558000, .5626373626373626373626373626373626373626, +.57731536503482350219940144597785547375700, .5614035087719298245614035087719298245614, +.57950594641464214795689713355386629700650, .5601750547045951859956236323851203501094, +.58169173963462239562716149521293118596100, .5589519650655021834061135371179039301310, +.58387276558098266665552955601015128195300, .5577342047930283224400871459694989106754, +.58604904500357812846544902640744112432000, .5565217391304347826086956521739130434783, +.58822059851708596855957011939608491957200, .5553145336225596529284164859002169197397, +.59038744660217634674381770309992134571100, .5541125541125541125541125541125541125541, +.59254960960667157898740242671919986605650, .5529157667386609071274298056155507559395, +.59470710774669277576265358220553025603300, .5517241379310344827586206896551724137931, +.59685996110779382384237123915227130055450, .5505376344086021505376344086021505376344, +.59900818964608337768851242799428291618800, .5493562231759656652360515021459227467811, +.60115181318933474940990890900138765573500, .5481798715203426124197002141327623126338, +.60329085143808425240052883964381180703650, .5470085470085470085470085470085470085470, +.60542532396671688843525771517306566238400, .5458422174840085287846481876332622601279, +.60755525022454170969155029524699784815300, .5446808510638297872340425531914893617021, +.60968064953685519036241657886421307921400, .5435244161358811040339702760084925690021, +.61180154110599282990534675263916142284850, .5423728813559322033898305084745762711864, +.61391794401237043121710712512140162289150, .5412262156448202959830866807610993657505, +.61602987721551394351138242200249806046500, .5400843881856540084388185654008438818565, +.61813735955507864705538167982012964785100, .5389473684210526315789473684210526315789, +.62024040975185745772080281312810257077200, .5378151260504201680672268907563025210084, +.62233904640877868441606324267922900617100, .5366876310272536687631027253668763102725, +.62443328801189346144440150965237990021700, .5355648535564853556485355648535564853556, +.62652315293135274476554741340805776417250, .5344467640918580375782881002087682672234, +.62860865942237409420556559780379757285100, .5333333333333333333333333333333333333333, +.63068982562619868570408243613201193511500, .5322245322245322245322245322245322245322, +.63276666957103777644277897707070223987100, .5311203319502074688796680497925311203320, +.63483920917301017716738442686619237065300, .5300207039337474120082815734989648033126, +.63690746223706917739093569252872839570050, .5289256198347107438016528925619834710744, +.63897144645792069983514238629140891134750, .5278350515463917525773195876288659793814, +.64103117942093124081992527862894348800200, .5267489711934156378600823045267489711934, +.64308667860302726193566513757104985415950, .5256673511293634496919917864476386036961, +.64513796137358470073053240412264131009600, .5245901639344262295081967213114754098361, +.64718504499530948859131740391603671014300, .5235173824130879345603271983640081799591, +.64922794662510974195157587018911726772800, .5224489795918367346938775510204081632653, +.65126668331495807251485530287027359008800, .5213849287169042769857433808553971486762, +.65330127201274557080523663898929953575150, .5203252032520325203252032520325203252033, +.65533172956312757406749369692988693714150, .5192697768762677484787018255578093306288, +.65735807270835999727154330685152672231200, .5182186234817813765182186234817813765182, +.65938031808912778153342060249997302889800, .5171717171717171717171717171717171717172, +.66139848224536490484126716182800009846700, .5161290322580645161290322580645161290323, +.66341258161706617713093692145776003599150, .5150905432595573440643863179074446680080, +.66542263254509037562201001492212526500250, .5140562248995983935742971887550200803213, +.66742865127195616370414654738851822912700, .5130260521042084168336673346693386773547, +.66943065394262923906154583164607174694550, .5120000000000000000000000000000000000000, +.67142865660530226534774556057527661323550, .5109780439121756487025948103792415169661, +.67342267521216669923234121597488410770900, .5099601593625498007968127490039840637450, +.67541272562017662384192817626171745359900, .5089463220675944333996023856858846918489, +.67739882359180603188519853574689477682100, .5079365079365079365079365079365079365079, +.67938098479579733801614338517538271844400, .5069306930693069306930693069306930693069, +.68135922480790300781450241629499942064300, .5059288537549407114624505928853754940711, +.68333355911162063645036823800182901322850, .5049309664694280078895463510848126232742, +.68530400309891936760919861626462079584600, .5039370078740157480314960629921259842520, +.68727057207096020619019327568821609020250, .5029469548133595284872298624754420432220, +.68923328123880889251040571252815425395950, .5019607843137254901960784313725490196078, +.69314718055994530941723212145818, 5.0e-01, +}; + + + +#define LOGTAB_TRANSLATE(x,h) (((x) - 1.)*icvLogTab[(h)+1]) +static const double ln_2 = 0.69314718055994530941723212145818; + +static void Log_32f( const float *_x, float *y, int n ) +{ + static const float shift[] = { 0, -1.f/512 }; + static const float + A0 = 0.3333333333333333333333333f, + A1 = -0.5f, + A2 = 1.f; + + #undef LOGPOLY + #define LOGPOLY(x) (((A0*(x) + A1)*(x) + A2)*(x)) + + int i = 0; + Cv32suf buf[4]; + const int* x = (const int*)_x; + +#if CV_SSE2 + if( USE_SSE2 ) + { + static const __m128d ln2_2 = _mm_set1_pd(ln_2); + static const __m128 _1_4 = _mm_set1_ps(1.f); + static const __m128 shift4 = _mm_set1_ps(-1.f/512); + + static const __m128 mA0 = _mm_set1_ps(A0); + static const __m128 mA1 = _mm_set1_ps(A1); + static const __m128 mA2 = _mm_set1_ps(A2); + + int CV_DECL_ALIGNED(16) idx[4]; + + for( ; i <= n - 4; i += 4 ) + { + __m128i h0 = _mm_loadu_si128((const __m128i*)(x + i)); + __m128i yi0 = _mm_sub_epi32(_mm_and_si128(_mm_srli_epi32(h0, 23), _mm_set1_epi32(255)), _mm_set1_epi32(127)); + __m128d yd0 = _mm_mul_pd(_mm_cvtepi32_pd(yi0), ln2_2); + __m128d yd1 = _mm_mul_pd(_mm_cvtepi32_pd(_mm_unpackhi_epi64(yi0,yi0)), ln2_2); + + __m128i xi0 = _mm_or_si128(_mm_and_si128(h0, _mm_set1_epi32(LOGTAB_MASK2_32F)), _mm_set1_epi32(127 << 23)); + + h0 = _mm_and_si128(_mm_srli_epi32(h0, 23 - LOGTAB_SCALE - 1), _mm_set1_epi32(LOGTAB_MASK*2)); + _mm_store_si128((__m128i*)idx, h0); + h0 = _mm_cmpeq_epi32(h0, _mm_set1_epi32(510)); + + __m128d t0, t1, t2, t3, t4; + t0 = _mm_load_pd(icvLogTab + idx[0]); + t2 = _mm_load_pd(icvLogTab + idx[1]); + t1 = _mm_unpackhi_pd(t0, t2); + t0 = _mm_unpacklo_pd(t0, t2); + t2 = _mm_load_pd(icvLogTab + idx[2]); + t4 = _mm_load_pd(icvLogTab + idx[3]); + t3 = _mm_unpackhi_pd(t2, t4); + t2 = _mm_unpacklo_pd(t2, t4); + + yd0 = _mm_add_pd(yd0, t0); + yd1 = _mm_add_pd(yd1, t2); + + __m128 yf0 = _mm_movelh_ps(_mm_cvtpd_ps(yd0), _mm_cvtpd_ps(yd1)); + + __m128 xf0 = _mm_sub_ps(_mm_castsi128_ps(xi0), _1_4); + xf0 = _mm_mul_ps(xf0, _mm_movelh_ps(_mm_cvtpd_ps(t1), _mm_cvtpd_ps(t3))); + xf0 = _mm_add_ps(xf0, _mm_and_ps(_mm_castsi128_ps(h0), shift4)); + + __m128 zf0 = _mm_mul_ps(xf0, mA0); + zf0 = _mm_mul_ps(_mm_add_ps(zf0, mA1), xf0); + zf0 = _mm_mul_ps(_mm_add_ps(zf0, mA2), xf0); + yf0 = _mm_add_ps(yf0, zf0); + + _mm_storeu_ps(y + i, yf0); + } + } + else +#endif + for( ; i <= n - 4; i += 4 ) + { + double x0, x1, x2, x3; + double y0, y1, y2, y3; + int h0, h1, h2, h3; + + h0 = x[i]; + h1 = x[i+1]; + buf[0].i = (h0 & LOGTAB_MASK2_32F) | (127 << 23); + buf[1].i = (h1 & LOGTAB_MASK2_32F) | (127 << 23); + + y0 = (((h0 >> 23) & 0xff) - 127) * ln_2; + y1 = (((h1 >> 23) & 0xff) - 127) * ln_2; + + h0 = (h0 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2; + h1 = (h1 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2; + + y0 += icvLogTab[h0]; + y1 += icvLogTab[h1]; + + h2 = x[i+2]; + h3 = x[i+3]; + + x0 = LOGTAB_TRANSLATE( buf[0].f, h0 ); + x1 = LOGTAB_TRANSLATE( buf[1].f, h1 ); + + buf[2].i = (h2 & LOGTAB_MASK2_32F) | (127 << 23); + buf[3].i = (h3 & LOGTAB_MASK2_32F) | (127 << 23); + + y2 = (((h2 >> 23) & 0xff) - 127) * ln_2; + y3 = (((h3 >> 23) & 0xff) - 127) * ln_2; + + h2 = (h2 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2; + h3 = (h3 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2; + + y2 += icvLogTab[h2]; + y3 += icvLogTab[h3]; + + x2 = LOGTAB_TRANSLATE( buf[2].f, h2 ); + x3 = LOGTAB_TRANSLATE( buf[3].f, h3 ); + + x0 += shift[h0 == 510]; + x1 += shift[h1 == 510]; + y0 += LOGPOLY( x0 ); + y1 += LOGPOLY( x1 ); + + y[i] = (float) y0; + y[i + 1] = (float) y1; + + x2 += shift[h2 == 510]; + x3 += shift[h3 == 510]; + y2 += LOGPOLY( x2 ); + y3 += LOGPOLY( x3 ); + + y[i + 2] = (float) y2; + y[i + 3] = (float) y3; + } + + for( ; i < n; i++ ) + { + int h0 = x[i]; + double y0; + float x0; + + y0 = (((h0 >> 23) & 0xff) - 127) * ln_2; + + buf[0].i = (h0 & LOGTAB_MASK2_32F) | (127 << 23); + h0 = (h0 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2; + + y0 += icvLogTab[h0]; + x0 = (float)LOGTAB_TRANSLATE( buf[0].f, h0 ); + x0 += shift[h0 == 510]; + y0 += LOGPOLY( x0 ); + + y[i] = (float)y0; + } +} + + +static void Log_64f( const double *x, double *y, int n ) +{ + static const double shift[] = { 0, -1./512 }; + static const double + A7 = 1.0, + A6 = -0.5, + A5 = 0.333333333333333314829616256247390992939472198486328125, + A4 = -0.25, + A3 = 0.2, + A2 = -0.1666666666666666574148081281236954964697360992431640625, + A1 = 0.1428571428571428769682682968777953647077083587646484375, + A0 = -0.125; + + #undef LOGPOLY + #define LOGPOLY(x,k) ((x)+=shift[k], xq = (x)*(x),\ + (((A0*xq + A2)*xq + A4)*xq + A6)*xq + \ + (((A1*xq + A3)*xq + A5)*xq + A7)*(x)) + + int i = 0; + DBLINT buf[4]; + DBLINT *X = (DBLINT *) x; + +#if CV_SSE2 + if( USE_SSE2 ) + { + static const __m128d ln2_2 = _mm_set1_pd(ln_2); + static const __m128d _1_2 = _mm_set1_pd(1.); + static const __m128d shift2 = _mm_set1_pd(-1./512); + + static const __m128i log_and_mask2 = _mm_set_epi32(LOGTAB_MASK2, 0xffffffff, LOGTAB_MASK2, 0xffffffff); + static const __m128i log_or_mask2 = _mm_set_epi32(1023 << 20, 0, 1023 << 20, 0); + + static const __m128d mA0 = _mm_set1_pd(A0); + static const __m128d mA1 = _mm_set1_pd(A1); + static const __m128d mA2 = _mm_set1_pd(A2); + static const __m128d mA3 = _mm_set1_pd(A3); + static const __m128d mA4 = _mm_set1_pd(A4); + static const __m128d mA5 = _mm_set1_pd(A5); + static const __m128d mA6 = _mm_set1_pd(A6); + static const __m128d mA7 = _mm_set1_pd(A7); + + int CV_DECL_ALIGNED(16) idx[4]; + + for( ; i <= n - 4; i += 4 ) + { + __m128i h0 = _mm_loadu_si128((const __m128i*)(x + i)); + __m128i h1 = _mm_loadu_si128((const __m128i*)(x + i + 2)); + + __m128d xd0 = _mm_castsi128_pd(_mm_or_si128(_mm_and_si128(h0, log_and_mask2), log_or_mask2)); + __m128d xd1 = _mm_castsi128_pd(_mm_or_si128(_mm_and_si128(h1, log_and_mask2), log_or_mask2)); + + h0 = _mm_unpackhi_epi32(_mm_unpacklo_epi32(h0, h1), _mm_unpackhi_epi32(h0, h1)); + + __m128i yi0 = _mm_sub_epi32(_mm_and_si128(_mm_srli_epi32(h0, 20), + _mm_set1_epi32(2047)), _mm_set1_epi32(1023)); + __m128d yd0 = _mm_mul_pd(_mm_cvtepi32_pd(yi0), ln2_2); + __m128d yd1 = _mm_mul_pd(_mm_cvtepi32_pd(_mm_unpackhi_epi64(yi0, yi0)), ln2_2); + + h0 = _mm_and_si128(_mm_srli_epi32(h0, 20 - LOGTAB_SCALE - 1), _mm_set1_epi32(LOGTAB_MASK * 2)); + _mm_store_si128((__m128i*)idx, h0); + h0 = _mm_cmpeq_epi32(h0, _mm_set1_epi32(510)); + + __m128d t0, t1, t2, t3, t4; + t0 = _mm_load_pd(icvLogTab + idx[0]); + t2 = _mm_load_pd(icvLogTab + idx[1]); + t1 = _mm_unpackhi_pd(t0, t2); + t0 = _mm_unpacklo_pd(t0, t2); + t2 = _mm_load_pd(icvLogTab + idx[2]); + t4 = _mm_load_pd(icvLogTab + idx[3]); + t3 = _mm_unpackhi_pd(t2, t4); + t2 = _mm_unpacklo_pd(t2, t4); + + yd0 = _mm_add_pd(yd0, t0); + yd1 = _mm_add_pd(yd1, t2); + + xd0 = _mm_mul_pd(_mm_sub_pd(xd0, _1_2), t1); + xd1 = _mm_mul_pd(_mm_sub_pd(xd1, _1_2), t3); + + xd0 = _mm_add_pd(xd0, _mm_and_pd(_mm_castsi128_pd(_mm_unpacklo_epi32(h0, h0)), shift2)); + xd1 = _mm_add_pd(xd1, _mm_and_pd(_mm_castsi128_pd(_mm_unpackhi_epi32(h0, h0)), shift2)); + + __m128d zd0 = _mm_mul_pd(xd0, mA0); + __m128d zd1 = _mm_mul_pd(xd1, mA0); + zd0 = _mm_mul_pd(_mm_add_pd(zd0, mA1), xd0); + zd1 = _mm_mul_pd(_mm_add_pd(zd1, mA1), xd1); + zd0 = _mm_mul_pd(_mm_add_pd(zd0, mA2), xd0); + zd1 = _mm_mul_pd(_mm_add_pd(zd1, mA2), xd1); + zd0 = _mm_mul_pd(_mm_add_pd(zd0, mA3), xd0); + zd1 = _mm_mul_pd(_mm_add_pd(zd1, mA3), xd1); + zd0 = _mm_mul_pd(_mm_add_pd(zd0, mA4), xd0); + zd1 = _mm_mul_pd(_mm_add_pd(zd1, mA4), xd1); + zd0 = _mm_mul_pd(_mm_add_pd(zd0, mA5), xd0); + zd1 = _mm_mul_pd(_mm_add_pd(zd1, mA5), xd1); + zd0 = _mm_mul_pd(_mm_add_pd(zd0, mA6), xd0); + zd1 = _mm_mul_pd(_mm_add_pd(zd1, mA6), xd1); + zd0 = _mm_mul_pd(_mm_add_pd(zd0, mA7), xd0); + zd1 = _mm_mul_pd(_mm_add_pd(zd1, mA7), xd1); + + yd0 = _mm_add_pd(yd0, zd0); + yd1 = _mm_add_pd(yd1, zd1); + + _mm_storeu_pd(y + i, yd0); + _mm_storeu_pd(y + i + 2, yd1); + } + } + else +#endif + for( ; i <= n - 4; i += 4 ) + { + double xq; + double x0, x1, x2, x3; + double y0, y1, y2, y3; + int h0, h1, h2, h3; + + h0 = X[i].i.lo; + h1 = X[i + 1].i.lo; + buf[0].i.lo = h0; + buf[1].i.lo = h1; + + h0 = X[i].i.hi; + h1 = X[i + 1].i.hi; + buf[0].i.hi = (h0 & LOGTAB_MASK2) | (1023 << 20); + buf[1].i.hi = (h1 & LOGTAB_MASK2) | (1023 << 20); + + y0 = (((h0 >> 20) & 0x7ff) - 1023) * ln_2; + y1 = (((h1 >> 20) & 0x7ff) - 1023) * ln_2; + + h2 = X[i + 2].i.lo; + h3 = X[i + 3].i.lo; + buf[2].i.lo = h2; + buf[3].i.lo = h3; + + h0 = (h0 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2; + h1 = (h1 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2; + + y0 += icvLogTab[h0]; + y1 += icvLogTab[h1]; + + h2 = X[i + 2].i.hi; + h3 = X[i + 3].i.hi; + + x0 = LOGTAB_TRANSLATE( buf[0].d, h0 ); + x1 = LOGTAB_TRANSLATE( buf[1].d, h1 ); + + buf[2].i.hi = (h2 & LOGTAB_MASK2) | (1023 << 20); + buf[3].i.hi = (h3 & LOGTAB_MASK2) | (1023 << 20); + + y2 = (((h2 >> 20) & 0x7ff) - 1023) * ln_2; + y3 = (((h3 >> 20) & 0x7ff) - 1023) * ln_2; + + h2 = (h2 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2; + h3 = (h3 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2; + + y2 += icvLogTab[h2]; + y3 += icvLogTab[h3]; + + x2 = LOGTAB_TRANSLATE( buf[2].d, h2 ); + x3 = LOGTAB_TRANSLATE( buf[3].d, h3 ); + + y0 += LOGPOLY( x0, h0 == 510 ); + y1 += LOGPOLY( x1, h1 == 510 ); + + y[i] = y0; + y[i + 1] = y1; + + y2 += LOGPOLY( x2, h2 == 510 ); + y3 += LOGPOLY( x3, h3 == 510 ); + + y[i + 2] = y2; + y[i + 3] = y3; + } + + for( ; i < n; i++ ) + { + int h0 = X[i].i.hi; + double xq; + double x0, y0 = (((h0 >> 20) & 0x7ff) - 1023) * ln_2; + + buf[0].i.hi = (h0 & LOGTAB_MASK2) | (1023 << 20); + buf[0].i.lo = X[i].i.lo; + h0 = (h0 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2; + + y0 += icvLogTab[h0]; + x0 = LOGTAB_TRANSLATE( buf[0].d, h0 ); + y0 += LOGPOLY( x0, h0 == 510 ); + y[i] = y0; + } +} + +#else + +#define Log_32f ippsLn_32f_A21 +#define Log_64f ippsLn_64f_A50 + +#endif + +void log( InputArray _src, OutputArray _dst ) +{ + Mat src = _src.getMat(); + int type = src.type(), depth = src.depth(), cn = src.channels(); + + _dst.create( src.dims, src.size, type ); + Mat dst = _dst.getMat(); + + CV_Assert( depth == CV_32F || depth == CV_64F ); + + const Mat* arrays[] = {&src, &dst, 0}; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs); + int len = (int)(it.size*cn); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + if( depth == CV_32F ) + Log_32f( (const float*)ptrs[0], (float*)ptrs[1], len ); + else + Log_64f( (const double*)ptrs[0], (double*)ptrs[1], len ); + } +} + +/****************************************************************************************\ +* P O W E R * +\****************************************************************************************/ + +template +static void +iPow_( const T* src, T* dst, int len, int power ) +{ + int i; + for( i = 0; i < len; i++ ) + { + WT a = 1, b = src[i]; + int p = power; + while( p > 1 ) + { + if( p & 1 ) + a *= b; + b *= b; + p >>= 1; + } + + a *= b; + dst[i] = saturate_cast(a); + } +} + + +static void iPow8u(const uchar* src, uchar* dst, int len, int power) +{ + iPow_(src, dst, len, power); +} + +static void iPow8s(const schar* src, schar* dst, int len, int power) +{ + iPow_(src, dst, len, power); +} + +static void iPow16u(const ushort* src, ushort* dst, int len, int power) +{ + iPow_(src, dst, len, power); +} + +static void iPow16s(const short* src, short* dst, int len, int power) +{ + iPow_(src, dst, len, power); +} + +static void iPow32s(const int* src, int* dst, int len, int power) +{ + iPow_(src, dst, len, power); +} + +static void iPow32f(const float* src, float* dst, int len, int power) +{ + iPow_(src, dst, len, power); +} + +static void iPow64f(const double* src, double* dst, int len, int power) +{ + iPow_(src, dst, len, power); +} + + +typedef void (*IPowFunc)( const uchar* src, uchar* dst, int len, int power ); + +static IPowFunc ipowTab[] = +{ + (IPowFunc)iPow8u, (IPowFunc)iPow8s, (IPowFunc)iPow16u, (IPowFunc)iPow16s, + (IPowFunc)iPow32s, (IPowFunc)iPow32f, (IPowFunc)iPow64f, 0 +}; + + +void pow( InputArray _src, double power, OutputArray _dst ) +{ + Mat src = _src.getMat(); + int type = src.type(), depth = src.depth(), cn = src.channels(); + + _dst.create( src.dims, src.size, type ); + Mat dst = _dst.getMat(); + + int ipower = cvRound(power); + bool is_ipower = false; + + if( fabs(ipower - power) < DBL_EPSILON ) + { + if( ipower < 0 ) + { + divide( 1., src, dst ); + if( ipower == -1 ) + return; + ipower = -ipower; + src = dst; + } + + switch( ipower ) + { + case 0: + dst = Scalar::all(1); + return; + case 1: + src.copyTo(dst); + return; + case 2: + multiply(src, src, dst); + return; + default: + is_ipower = true; + } + } + else + CV_Assert( depth == CV_32F || depth == CV_64F ); + + const Mat* arrays[] = {&src, &dst, 0}; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs); + int len = (int)(it.size*cn); + + if( is_ipower ) + { + IPowFunc func = ipowTab[depth]; + CV_Assert( func != 0 ); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + func( ptrs[0], ptrs[1], len, ipower ); + } + else if( fabs(fabs(power) - 0.5) < DBL_EPSILON ) + { + MathFunc func = power < 0 ? + (depth == CV_32F ? (MathFunc)InvSqrt_32f : (MathFunc)InvSqrt_64f) : + (depth == CV_32F ? (MathFunc)Sqrt_32f : (MathFunc)Sqrt_64f); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + func( ptrs[0], ptrs[1], len ); + } + else + { + int j, k, blockSize = std::min(len, ((BLOCK_SIZE + cn-1)/cn)*cn); + size_t esz1 = src.elemSize1(); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( j = 0; j < len; j += blockSize ) + { + int bsz = std::min(len - j, blockSize); + if( depth == CV_32F ) + { + const float* x = (const float*)ptrs[0]; + float* y = (float*)ptrs[1]; + + Log_32f(x, y, bsz); + for( k = 0; k < bsz; k++ ) + y[k] = (float)(y[k]*power); + Exp_32f(y, y, bsz); + } + else + { + const double* x = (const double*)ptrs[0]; + double* y = (double*)ptrs[1]; + + Log_64f(x, y, bsz); + for( k = 0; k < bsz; k++ ) + y[k] *= power; + Exp_64f(y, y, bsz); + } + ptrs[0] += bsz*esz1; + ptrs[1] += bsz*esz1; + } + } + } +} + +void sqrt(InputArray a, OutputArray b) +{ + pow(a, 0.5, b); +} + +/************************** CheckArray for NaN's, Inf's *********************************/ + +template struct mat_type_assotiations{}; + +template<> struct mat_type_assotiations +{ + typedef unsigned char type; + static const type min_allowable = 0x0; + static const type max_allowable = 0xFF; +}; + +template<> struct mat_type_assotiations +{ + typedef signed char type; + static const type min_allowable = SCHAR_MIN; + static const type max_allowable = SCHAR_MAX; +}; + +template<> struct mat_type_assotiations +{ + typedef unsigned short type; + static const type min_allowable = 0x0; + static const type max_allowable = USHRT_MAX; +}; +template<> struct mat_type_assotiations +{ + typedef signed short type; + static const type min_allowable = SHRT_MIN; + static const type max_allowable = SHRT_MAX; +}; + +template<> struct mat_type_assotiations +{ + typedef int type; + static const type min_allowable = (-INT_MAX - 1); + static const type max_allowable = INT_MAX; +}; + +// inclusive maxVal !!! +template +bool checkIntegerRange(cv::Mat src, Point& bad_pt, int minVal, int maxVal, double& bad_value) +{ + typedef mat_type_assotiations type_ass; + + if (minVal < type_ass::min_allowable && maxVal > type_ass::max_allowable) + { + return true; + } + else if (minVal > type_ass::max_allowable || maxVal < type_ass::min_allowable || maxVal < minVal) + { + bad_pt = cv::Point(0,0); + return false; + } + cv::Mat as_one_channel = src.reshape(1,0); + + for (int j = 0; j < as_one_channel.rows; ++j) + for (int i = 0; i < as_one_channel.cols; ++i) + { + if (as_one_channel.at(j ,i) < minVal || as_one_channel.at(j ,i) > maxVal) + { + bad_pt.y = j ; + bad_pt.x = i % src.channels(); + bad_value = as_one_channel.at(j ,i); + return false; + } + } + bad_value = 0.0; + + return true; +} + +typedef bool (*check_range_function)(cv::Mat src, Point& bad_pt, int minVal, int maxVal, double& bad_value); + +check_range_function check_range_functions[] = +{ + &checkIntegerRange, + &checkIntegerRange, + &checkIntegerRange, + &checkIntegerRange, + &checkIntegerRange +}; + +bool checkRange(InputArray _src, bool quiet, Point* pt, double minVal, double maxVal) +{ + Mat src = _src.getMat(); + + if ( src.dims > 2 ) + { + const Mat* arrays[] = {&src, 0}; + Mat planes[1]; + NAryMatIterator it(arrays, planes); + + for ( size_t i = 0; i < it.nplanes; i++, ++it ) + { + if (!checkRange( it.planes[0], quiet, pt, minVal, maxVal )) + { + // todo: set index properly + return false; + } + } + return true; + } + + int depth = src.depth(); + Point badPt(-1, -1); + double badValue = 0; + + if (depth < CV_32F) + { + // see "Bug #1784" + int minVali = minVal<(-INT_MAX - 1) ? (-INT_MAX - 1) : cvFloor(minVal); + int maxVali = maxVal>INT_MAX ? INT_MAX : cvCeil(maxVal) - 1; // checkIntegerRang() use inclusive maxVal + + (check_range_functions[depth])(src, badPt, minVali, maxVali, badValue); + } + else + { + int i, loc = 0; + Size size = getContinuousSize( src, src.channels() ); + + if( depth == CV_32F ) + { + Cv32suf a, b; + int ia, ib; + const int* isrc = (const int*)src.data; + size_t step = src.step/sizeof(isrc[0]); + + a.f = (float)std::max(minVal, (double)-FLT_MAX); + b.f = (float)std::min(maxVal, (double)FLT_MAX); + + ia = CV_TOGGLE_FLT(a.i); + ib = CV_TOGGLE_FLT(b.i); + + for( ; badPt.x < 0 && size.height--; loc += size.width, isrc += step ) + { + for( i = 0; i < size.width; i++ ) + { + int val = isrc[i]; + val = CV_TOGGLE_FLT(val); + + if( val < ia || val >= ib ) + { + badPt = Point((loc + i) % src.cols, (loc + i) / src.cols); + badValue = ((const float*)isrc)[i]; + break; + } + } + } + } + else + { + Cv64suf a, b; + int64 ia, ib; + const int64* isrc = (const int64*)src.data; + size_t step = src.step/sizeof(isrc[0]); + + a.f = minVal; + b.f = maxVal; + + ia = CV_TOGGLE_DBL(a.i); + ib = CV_TOGGLE_DBL(b.i); + + for( ; badPt.x < 0 && size.height--; loc += size.width, isrc += step ) + { + for( i = 0; i < size.width; i++ ) + { + int64 val = isrc[i]; + val = CV_TOGGLE_DBL(val); + + if( val < ia || val >= ib ) + { + badPt = Point((loc + i) % src.cols, (loc + i) / src.cols); + badValue = ((const double*)isrc)[i]; + break; + } + } + } + } + } + + if( badPt.x >= 0 ) + { + if( pt ) + *pt = badPt; + if( !quiet ) + CV_Error_( CV_StsOutOfRange, + ("the value at (%d, %d)=%g is out of range", badPt.x, badPt.y, badValue)); + } + return badPt.x < 0; +} + + +void patchNaNs( InputOutputArray _a, double _val ) +{ + Mat a = _a.getMat(); + CV_Assert( a.depth() == CV_32F ); + + const Mat* arrays[] = {&a, 0}; + int* ptrs[1]; + NAryMatIterator it(arrays, (uchar**)ptrs); + size_t len = it.size*a.channels(); + Cv32suf val; + val.f = (float)_val; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + int* tptr = ptrs[0]; + for( size_t j = 0; j < len; j++ ) + if( (tptr[j] & 0x7fffffff) > 0x7f800000 ) + tptr[j] = val.i; + } +} + + +void exp(const float* src, float* dst, int n) +{ + Exp_32f(src, dst, n); +} + +void log(const float* src, float* dst, int n) +{ + Log_32f(src, dst, n); +} + +void fastAtan2(const float* y, const float* x, float* dst, int n, bool angleInDegrees) +{ + FastAtan2_32f(y, x, dst, n, angleInDegrees); +} + +void magnitude(const float* x, const float* y, float* dst, int n) +{ + Magnitude_32f(x, y, dst, n); +} + +} + +CV_IMPL float cvCbrt(float value) { return cv::cubeRoot(value); } +CV_IMPL float cvFastArctan(float y, float x) { return cv::fastAtan2(y, x); } + +CV_IMPL void +cvCartToPolar( const CvArr* xarr, const CvArr* yarr, + CvArr* magarr, CvArr* anglearr, + int angle_in_degrees ) +{ + cv::Mat X = cv::cvarrToMat(xarr), Y = cv::cvarrToMat(yarr), Mag, Angle; + if( magarr ) + { + Mag = cv::cvarrToMat(magarr); + CV_Assert( Mag.size() == X.size() && Mag.type() == X.type() ); + } + if( anglearr ) + { + Angle = cv::cvarrToMat(anglearr); + CV_Assert( Angle.size() == X.size() && Angle.type() == X.type() ); + } + if( magarr ) + { + if( anglearr ) + cv::cartToPolar( X, Y, Mag, Angle, angle_in_degrees != 0 ); + else + cv::magnitude( X, Y, Mag ); + } + else + cv::phase( X, Y, Angle, angle_in_degrees != 0 ); +} + +CV_IMPL void +cvPolarToCart( const CvArr* magarr, const CvArr* anglearr, + CvArr* xarr, CvArr* yarr, int angle_in_degrees ) +{ + cv::Mat X, Y, Angle = cv::cvarrToMat(anglearr), Mag; + if( magarr ) + { + Mag = cv::cvarrToMat(magarr); + CV_Assert( Mag.size() == Angle.size() && Mag.type() == Angle.type() ); + } + if( xarr ) + { + X = cv::cvarrToMat(xarr); + CV_Assert( X.size() == Angle.size() && X.type() == Angle.type() ); + } + if( yarr ) + { + Y = cv::cvarrToMat(yarr); + CV_Assert( Y.size() == Angle.size() && Y.type() == Angle.type() ); + } + + cv::polarToCart( Mag, Angle, X, Y, angle_in_degrees != 0 ); +} + +CV_IMPL void cvExp( const CvArr* srcarr, CvArr* dstarr ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + CV_Assert( src.type() == dst.type() && src.size == dst.size ); + cv::exp( src, dst ); +} + +CV_IMPL void cvLog( const CvArr* srcarr, CvArr* dstarr ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + CV_Assert( src.type() == dst.type() && src.size == dst.size ); + cv::log( src, dst ); +} + +CV_IMPL void cvPow( const CvArr* srcarr, CvArr* dstarr, double power ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + CV_Assert( src.type() == dst.type() && src.size == dst.size ); + cv::pow( src, power, dst ); +} + +CV_IMPL int cvCheckArr( const CvArr* arr, int flags, + double minVal, double maxVal ) +{ + if( (flags & CV_CHECK_RANGE) == 0 ) + minVal = -DBL_MAX, maxVal = DBL_MAX; + return cv::checkRange(cv::cvarrToMat(arr), (flags & CV_CHECK_QUIET) != 0, 0, minVal, maxVal ); +} + + +/* + Finds real roots of cubic, quadratic or linear equation. + The original code has been taken from Ken Turkowski web page + (http://www.worldserver.com/turk/opensource/) and adopted for OpenCV. + Here is the copyright notice. + + ----------------------------------------------------------------------- + Copyright (C) 1978-1999 Ken Turkowski. + + All rights reserved. + + Warranty Information + Even though I have reviewed this software, I make no warranty + or representation, either express or implied, with respect to this + software, its quality, accuracy, merchantability, or fitness for a + particular purpose. As a result, this software is provided "as is," + and you, its user, are assuming the entire risk as to its quality + and accuracy. + + This code may be used and freely distributed as long as it includes + this copyright notice and the above warranty information. + ----------------------------------------------------------------------- +*/ + +int cv::solveCubic( InputArray _coeffs, OutputArray _roots ) +{ + const int n0 = 3; + Mat coeffs = _coeffs.getMat(); + int ctype = coeffs.type(); + + CV_Assert( ctype == CV_32F || ctype == CV_64F ); + CV_Assert( (coeffs.size() == Size(n0, 1) || + coeffs.size() == Size(n0+1, 1) || + coeffs.size() == Size(1, n0) || + coeffs.size() == Size(1, n0+1)) ); + + _roots.create(n0, 1, ctype, -1, true, DEPTH_MASK_FLT); + Mat roots = _roots.getMat(); + + int i = -1, n = 0; + double a0 = 1., a1, a2, a3; + double x0 = 0., x1 = 0., x2 = 0.; + int ncoeffs = coeffs.rows + coeffs.cols - 1; + + if( ctype == CV_32FC1 ) + { + if( ncoeffs == 4 ) + a0 = coeffs.at(++i); + + a1 = coeffs.at(i+1); + a2 = coeffs.at(i+2); + a3 = coeffs.at(i+3); + } + else + { + if( ncoeffs == 4 ) + a0 = coeffs.at(++i); + + a1 = coeffs.at(i+1); + a2 = coeffs.at(i+2); + a3 = coeffs.at(i+3); + } + + if( a0 == 0 ) + { + if( a1 == 0 ) + { + if( a2 == 0 ) + n = a3 == 0 ? -1 : 0; + else + { + // linear equation + x0 = -a3/a2; + n = 1; + } + } + else + { + // quadratic equation + double d = a2*a2 - 4*a1*a3; + if( d >= 0 ) + { + d = sqrt(d); + double q1 = (-a2 + d) * 0.5; + double q2 = (a2 + d) * -0.5; + if( fabs(q1) > fabs(q2) ) + { + x0 = q1 / a1; + x1 = a3 / q1; + } + else + { + x0 = q2 / a1; + x1 = a3 / q2; + } + n = d > 0 ? 2 : 1; + } + } + } + else + { + a0 = 1./a0; + a1 *= a0; + a2 *= a0; + a3 *= a0; + + double Q = (a1 * a1 - 3 * a2) * (1./9); + double R = (2 * a1 * a1 * a1 - 9 * a1 * a2 + 27 * a3) * (1./54); + double Qcubed = Q * Q * Q; + double d = Qcubed - R * R; + + if( d >= 0 ) + { + double theta = acos(R / sqrt(Qcubed)); + double sqrtQ = sqrt(Q); + double t0 = -2 * sqrtQ; + double t1 = theta * (1./3); + double t2 = a1 * (1./3); + x0 = t0 * cos(t1) - t2; + x1 = t0 * cos(t1 + (2.*CV_PI/3)) - t2; + x2 = t0 * cos(t1 + (4.*CV_PI/3)) - t2; + n = 3; + } + else + { + double e; + d = sqrt(-d); + e = pow(d + fabs(R), 0.333333333333); + if( R > 0 ) + e = -e; + x0 = (e + Q / e) - a1 * (1./3); + n = 1; + } + } + + if( roots.type() == CV_32FC1 ) + { + roots.at(0) = (float)x0; + roots.at(1) = (float)x1; + roots.at(2) = (float)x2; + } + else + { + roots.at(0) = x0; + roots.at(1) = x1; + roots.at(2) = x2; + } + + return n; +} + +/* finds complex roots of a polynomial using Durand-Kerner method: + http://en.wikipedia.org/wiki/Durand%E2%80%93Kerner_method */ +double cv::solvePoly( InputArray _coeffs0, OutputArray _roots0, int maxIters ) +{ + typedef Complex C; + + double maxDiff = 0; + int iter, i, j; + Mat coeffs0 = _coeffs0.getMat(); + int ctype = _coeffs0.type(); + int cdepth = CV_MAT_DEPTH(ctype); + + CV_Assert( CV_MAT_DEPTH(ctype) >= CV_32F && CV_MAT_CN(ctype) <= 2 ); + CV_Assert( coeffs0.rows == 1 || coeffs0.cols == 1 ); + + int n = coeffs0.cols + coeffs0.rows - 2; + + _roots0.create(n, 1, CV_MAKETYPE(cdepth, 2), -1, true, DEPTH_MASK_FLT); + Mat roots0 = _roots0.getMat(); + + AutoBuffer buf(n*2+2); + C *coeffs = buf, *roots = coeffs + n + 1; + Mat coeffs1(coeffs0.size(), CV_MAKETYPE(CV_64F, coeffs0.channels()), coeffs0.channels() == 2 ? coeffs : roots); + coeffs0.convertTo(coeffs1, coeffs1.type()); + if( coeffs0.channels() == 1 ) + { + const double* rcoeffs = (const double*)roots; + for( i = 0; i <= n; i++ ) + coeffs[i] = C(rcoeffs[i], 0); + } + + C p(1, 0), r(1, 1); + + for( i = 0; i < n; i++ ) + { + roots[i] = p; + p = p * r; + } + + maxIters = maxIters <= 0 ? 1000 : maxIters; + for( iter = 0; iter < maxIters; iter++ ) + { + maxDiff = 0; + for( i = 0; i < n; i++ ) + { + p = roots[i]; + C num = coeffs[n], denom = coeffs[n]; + for( j = 0; j < n; j++ ) + { + num = num*p + coeffs[n-j-1]; + if( j != i ) denom = denom * (p - roots[j]); + } + num /= denom; + roots[i] = p - num; + maxDiff = max(maxDiff, abs(num)); + } + if( maxDiff <= 0 ) + break; + } + + if( coeffs0.channels() == 1 ) + { + const double verySmallEps = 1e-100; + for( i = 0; i < n; i++ ) + if( fabs(roots[i].im) < verySmallEps ) + roots[i].im = 0; + } + + Mat(roots0.size(), CV_64FC2, roots).convertTo(roots0, roots0.type()); + return maxDiff; +} + + +CV_IMPL int +cvSolveCubic( const CvMat* coeffs, CvMat* roots ) +{ + cv::Mat _coeffs = cv::cvarrToMat(coeffs), _roots = cv::cvarrToMat(roots), _roots0 = _roots; + int nroots = cv::solveCubic(_coeffs, _roots); + CV_Assert( _roots.data == _roots0.data ); // check that the array of roots was not reallocated + return nroots; +} + + +void cvSolvePoly(const CvMat* a, CvMat *r, int maxiter, int) +{ + cv::Mat _a = cv::cvarrToMat(a), _r = cv::cvarrToMat(r), _r0 = r; + cv::solvePoly(_a, _r, maxiter); + CV_Assert( _r.data == _r0.data ); // check that the array of roots was not reallocated +} + + +/* End of file. */ diff --git a/core/src/matmul.cpp b/core/src/matmul.cpp new file mode 100644 index 0000000..fe138f0 --- /dev/null +++ b/core/src/matmul.cpp @@ -0,0 +1,3211 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#ifdef HAVE_IPP +#include "ippversion.h" +#endif + +namespace cv +{ + +/****************************************************************************************\ +* GEMM * +\****************************************************************************************/ + +static void +GEMM_CopyBlock( const uchar* src, size_t src_step, + uchar* dst, size_t dst_step, + Size size, size_t pix_size ) +{ + int j; + size.width *= (int)(pix_size / sizeof(int)); + + for( ; size.height--; src += src_step, dst += dst_step ) + { + j=0; + #if CV_ENABLE_UNROLLED + for( ; j <= size.width - 4; j += 4 ) + { + int t0 = ((const int*)src)[j]; + int t1 = ((const int*)src)[j+1]; + ((int*)dst)[j] = t0; + ((int*)dst)[j+1] = t1; + t0 = ((const int*)src)[j+2]; + t1 = ((const int*)src)[j+3]; + ((int*)dst)[j+2] = t0; + ((int*)dst)[j+3] = t1; + } + #endif + for( ; j < size.width; j++ ) + ((int*)dst)[j] = ((const int*)src)[j]; + } +} + + +static void +GEMM_TransposeBlock( const uchar* src, size_t src_step, + uchar* dst, size_t dst_step, + Size size, size_t pix_size ) +{ + int i, j; + for( i = 0; i < size.width; i++, dst += dst_step, src += pix_size ) + { + const uchar* _src = src; + switch( pix_size ) + { + case sizeof(int): + for( j = 0; j < size.height; j++, _src += src_step ) + ((int*)dst)[j] = ((int*)_src)[0]; + break; + case sizeof(int)*2: + for( j = 0; j < size.height*2; j += 2, _src += src_step ) + { + int t0 = ((int*)_src)[0]; + int t1 = ((int*)_src)[1]; + ((int*)dst)[j] = t0; + ((int*)dst)[j+1] = t1; + } + break; + case sizeof(int)*4: + for( j = 0; j < size.height*4; j += 4, _src += src_step ) + { + int t0 = ((int*)_src)[0]; + int t1 = ((int*)_src)[1]; + ((int*)dst)[j] = t0; + ((int*)dst)[j+1] = t1; + t0 = ((int*)_src)[2]; + t1 = ((int*)_src)[3]; + ((int*)dst)[j+2] = t0; + ((int*)dst)[j+3] = t1; + } + break; + default: + assert(0); + return; + } + } +} + + +template static void +GEMMSingleMul( const T* a_data, size_t a_step, + const T* b_data, size_t b_step, + const T* c_data, size_t c_step, + T* d_data, size_t d_step, + Size a_size, Size d_size, + double alpha, double beta, int flags ) +{ + int i, j, k, n = a_size.width, m = d_size.width, drows = d_size.height; + const T *_a_data = a_data, *_b_data = b_data, *_c_data = c_data; + cv::AutoBuffer _a_buf; + T* a_buf = 0; + size_t a_step0, a_step1, c_step0, c_step1, t_step; + + a_step /= sizeof(a_data[0]); + b_step /= sizeof(b_data[0]); + c_step /= sizeof(c_data[0]); + d_step /= sizeof(d_data[0]); + a_step0 = a_step; + a_step1 = 1; + + if( !c_data ) + c_step0 = c_step1 = 0; + else if( !(flags & GEMM_3_T) ) + c_step0 = c_step, c_step1 = 1; + else + c_step0 = 1, c_step1 = c_step; + + if( flags & GEMM_1_T ) + { + CV_SWAP( a_step0, a_step1, t_step ); + n = a_size.height; + if( a_step > 1 && n > 1 ) + { + _a_buf.allocate(n); + a_buf = _a_buf; + } + } + + if( n == 1 ) /* external product */ + { + cv::AutoBuffer _b_buf; + T* b_buf = 0; + + if( a_step > 1 && a_size.height > 1 ) + { + _a_buf.allocate(drows); + a_buf = _a_buf; + for( k = 0; k < drows; k++ ) + a_buf[k] = a_data[a_step*k]; + a_data = a_buf; + } + + if( b_step > 1 ) + { + _b_buf.allocate(d_size.width); + b_buf = _b_buf; + for( j = 0; j < d_size.width; j++ ) + b_buf[j] = b_data[j*b_step]; + b_data = b_buf; + } + + for( i = 0; i < drows; i++, _c_data += c_step0, d_data += d_step ) + { + WT al = WT(a_data[i])*alpha; + c_data = _c_data; + for( j = 0; j <= d_size.width - 2; j += 2, c_data += 2*c_step1 ) + { + WT s0 = al*WT(b_data[j]); + WT s1 = al*WT(b_data[j+1]); + if( !c_data ) + { + d_data[j] = T(s0); + d_data[j+1] = T(s1); + } + else + { + d_data[j] = T(s0 + WT(c_data[0])*beta); + d_data[j+1] = T(s1 + WT(c_data[c_step1])*beta); + } + } + + for( ; j < d_size.width; j++, c_data += c_step1 ) + { + WT s0 = al*WT(b_data[j]); + if( !c_data ) + d_data[j] = T(s0); + else + d_data[j] = T(s0 + WT(c_data[0])*beta); + } + } + } + else if( flags & GEMM_2_T ) /* A * Bt */ + { + for( i = 0; i < drows; i++, _a_data += a_step0, _c_data += c_step0, d_data += d_step ) + { + a_data = _a_data; + b_data = _b_data; + c_data = _c_data; + + if( a_buf ) + { + for( k = 0; k < n; k++ ) + a_buf[k] = a_data[a_step1*k]; + a_data = a_buf; + } + + for( j = 0; j < d_size.width; j++, b_data += b_step, + c_data += c_step1 ) + { + WT s0(0), s1(0), s2(0), s3(0); + k = 0; + #if CV_ENABLE_UNROLLED + for( ; k <= n - 4; k += 4 ) + { + s0 += WT(a_data[k])*WT(b_data[k]); + s1 += WT(a_data[k+1])*WT(b_data[k+1]); + s2 += WT(a_data[k+2])*WT(b_data[k+2]); + s3 += WT(a_data[k+3])*WT(b_data[k+3]); + } + #endif + for( ; k < n; k++ ) + s0 += WT(a_data[k])*WT(b_data[k]); + s0 = (s0+s1+s2+s3)*alpha; + + if( !c_data ) + d_data[j] = T(s0); + else + d_data[j] = T(s0 + WT(c_data[0])*beta); + } + } + } + else if( d_size.width*sizeof(d_data[0]) <= 1600 ) + { + for( i = 0; i < drows; i++, _a_data += a_step0, + _c_data += c_step0, + d_data += d_step ) + { + a_data = _a_data, c_data = _c_data; + + if( a_buf ) + { + for( k = 0; k < n; k++ ) + a_buf[k] = a_data[a_step1*k]; + a_data = a_buf; + } + + for( j = 0; j <= m - 4; j += 4, c_data += 4*c_step1 ) + { + const T* b = _b_data + j; + WT s0(0), s1(0), s2(0), s3(0); + + for( k = 0; k < n; k++, b += b_step ) + { + WT a(a_data[k]); + s0 += a * WT(b[0]); s1 += a * WT(b[1]); + s2 += a * WT(b[2]); s3 += a * WT(b[3]); + } + + if( !c_data ) + { + d_data[j] = T(s0*alpha); + d_data[j+1] = T(s1*alpha); + d_data[j+2] = T(s2*alpha); + d_data[j+3] = T(s3*alpha); + } + else + { + s0 = s0*alpha; s1 = s1*alpha; + s2 = s2*alpha; s3 = s3*alpha; + d_data[j] = T(s0 + WT(c_data[0])*beta); + d_data[j+1] = T(s1 + WT(c_data[c_step1])*beta); + d_data[j+2] = T(s2 + WT(c_data[c_step1*2])*beta); + d_data[j+3] = T(s3 + WT(c_data[c_step1*3])*beta); + } + } + + for( ; j < m; j++, c_data += c_step1 ) + { + const T* b = _b_data + j; + WT s0(0); + + for( k = 0; k < n; k++, b += b_step ) + s0 += WT(a_data[k]) * WT(b[0]); + + s0 = s0*alpha; + if( !c_data ) + d_data[j] = T(s0); + else + d_data[j] = T(s0 + WT(c_data[0])*beta); + } + } + } + else + { + cv::AutoBuffer _d_buf(m); + WT* d_buf = _d_buf; + + for( i = 0; i < drows; i++, _a_data += a_step0, _c_data += c_step0, d_data += d_step ) + { + a_data = _a_data; + b_data = _b_data; + c_data = _c_data; + + if( a_buf ) + { + for( k = 0; k < n; k++ ) + a_buf[k] = _a_data[a_step1*k]; + a_data = a_buf; + } + + for( j = 0; j < m; j++ ) + d_buf[j] = WT(0); + + for( k = 0; k < n; k++, b_data += b_step ) + { + WT al(a_data[k]); + j=0; + #if CV_ENABLE_UNROLLED + for(; j <= m - 4; j += 4 ) + { + WT t0 = d_buf[j] + WT(b_data[j])*al; + WT t1 = d_buf[j+1] + WT(b_data[j+1])*al; + d_buf[j] = t0; + d_buf[j+1] = t1; + t0 = d_buf[j+2] + WT(b_data[j+2])*al; + t1 = d_buf[j+3] + WT(b_data[j+3])*al; + d_buf[j+2] = t0; + d_buf[j+3] = t1; + } + #endif + for( ; j < m; j++ ) + d_buf[j] += WT(b_data[j])*al; + } + + if( !c_data ) + for( j = 0; j < m; j++ ) + d_data[j] = T(d_buf[j]*alpha); + else + for( j = 0; j < m; j++, c_data += c_step1 ) + { + WT t = d_buf[j]*alpha; + d_data[j] = T(t + WT(c_data[0])*beta); + } + } + } +} + + +template static void +GEMMBlockMul( const T* a_data, size_t a_step, + const T* b_data, size_t b_step, + WT* d_data, size_t d_step, + Size a_size, Size d_size, int flags ) +{ + int i, j, k, n = a_size.width, m = d_size.width; + const T *_a_data = a_data, *_b_data = b_data; + cv::AutoBuffer _a_buf; + T* a_buf = 0; + size_t a_step0, a_step1, t_step; + int do_acc = flags & 16; + + a_step /= sizeof(a_data[0]); + b_step /= sizeof(b_data[0]); + d_step /= sizeof(d_data[0]); + + a_step0 = a_step; + a_step1 = 1; + + if( flags & GEMM_1_T ) + { + CV_SWAP( a_step0, a_step1, t_step ); + n = a_size.height; + _a_buf.allocate(n); + a_buf = _a_buf; + } + + if( flags & GEMM_2_T ) + { + /* second operand is transposed */ + for( i = 0; i < d_size.height; i++, _a_data += a_step0, d_data += d_step ) + { + a_data = _a_data; b_data = _b_data; + + if( a_buf ) + { + for( k = 0; k < n; k++ ) + a_buf[k] = a_data[a_step1*k]; + a_data = a_buf; + } + + for( j = 0; j < d_size.width; j++, b_data += b_step ) + { + WT s0 = do_acc ? d_data[j]:WT(0), s1(0); + for( k = 0; k <= n - 2; k += 2 ) + { + s0 += WT(a_data[k])*WT(b_data[k]); + s1 += WT(a_data[k+1])*WT(b_data[k+1]); + } + + for( ; k < n; k++ ) + s0 += WT(a_data[k])*WT(b_data[k]); + + d_data[j] = s0 + s1; + } + } + } + else + { + for( i = 0; i < d_size.height; i++, _a_data += a_step0, d_data += d_step ) + { + a_data = _a_data, b_data = _b_data; + + if( a_buf ) + { + for( k = 0; k < n; k++ ) + a_buf[k] = a_data[a_step1*k]; + a_data = a_buf; + } + + for( j = 0; j <= m - 4; j += 4 ) + { + WT s0, s1, s2, s3; + const T* b = b_data + j; + + if( do_acc ) + { + s0 = d_data[j]; s1 = d_data[j+1]; + s2 = d_data[j+2]; s3 = d_data[j+3]; + } + else + s0 = s1 = s2 = s3 = WT(0); + + for( k = 0; k < n; k++, b += b_step ) + { + WT a(a_data[k]); + s0 += a * WT(b[0]); s1 += a * WT(b[1]); + s2 += a * WT(b[2]); s3 += a * WT(b[3]); + } + + d_data[j] = s0; d_data[j+1] = s1; + d_data[j+2] = s2; d_data[j+3] = s3; + } + + for( ; j < m; j++ ) + { + const T* b = b_data + j; + WT s0 = do_acc ? d_data[j] : WT(0); + + for( k = 0; k < n; k++, b += b_step ) + s0 += WT(a_data[k]) * WT(b[0]); + + d_data[j] = s0; + } + } + } +} + + +template static void +GEMMStore( const T* c_data, size_t c_step, + const WT* d_buf, size_t d_buf_step, + T* d_data, size_t d_step, Size d_size, + double alpha, double beta, int flags ) +{ + const T* _c_data = c_data; + int j; + size_t c_step0, c_step1; + + c_step /= sizeof(c_data[0]); + d_buf_step /= sizeof(d_buf[0]); + d_step /= sizeof(d_data[0]); + + if( !c_data ) + c_step0 = c_step1 = 0; + else if( !(flags & GEMM_3_T) ) + c_step0 = c_step, c_step1 = 1; + else + c_step0 = 1, c_step1 = c_step; + + for( ; d_size.height--; _c_data += c_step0, d_buf += d_buf_step, d_data += d_step ) + { + if( _c_data ) + { + c_data = _c_data; + j=0; + #if CV_ENABLE_UNROLLED + for(; j <= d_size.width - 4; j += 4, c_data += 4*c_step1 ) + { + WT t0 = alpha*d_buf[j]; + WT t1 = alpha*d_buf[j+1]; + t0 += beta*WT(c_data[0]); + t1 += beta*WT(c_data[c_step1]); + d_data[j] = T(t0); + d_data[j+1] = T(t1); + t0 = alpha*d_buf[j+2]; + t1 = alpha*d_buf[j+3]; + t0 += beta*WT(c_data[c_step1*2]); + t1 += beta*WT(c_data[c_step1*3]); + d_data[j+2] = T(t0); + d_data[j+3] = T(t1); + } + #endif + for( ; j < d_size.width; j++, c_data += c_step1 ) + { + WT t0 = alpha*d_buf[j]; + d_data[j] = T(t0 + WT(c_data[0])*beta); + } + } + else + { + j = 0; + #if CV_ENABLE_UNROLLED + for( ; j <= d_size.width - 4; j += 4 ) + { + WT t0 = alpha*d_buf[j]; + WT t1 = alpha*d_buf[j+1]; + d_data[j] = T(t0); + d_data[j+1] = T(t1); + t0 = alpha*d_buf[j+2]; + t1 = alpha*d_buf[j+3]; + d_data[j+2] = T(t0); + d_data[j+3] = T(t1); + } + #endif + for( ; j < d_size.width; j++ ) + d_data[j] = T(alpha*d_buf[j]); + } + } +} + + +typedef void (*GEMMSingleMulFunc)( const void* src1, size_t step1, + const void* src2, size_t step2, const void* src3, size_t step3, + void* dst, size_t dststep, Size srcsize, Size dstsize, + double alpha, double beta, int flags ); + +typedef void (*GEMMBlockMulFunc)( const void* src1, size_t step1, + const void* src2, size_t step2, void* dst, size_t dststep, + Size srcsize, Size dstsize, int flags ); + +typedef void (*GEMMStoreFunc)( const void* src1, size_t step1, + const void* src2, size_t step2, void* dst, size_t dststep, + Size dstsize, double alpha, double beta, int flags ); + +static void GEMMSingleMul_32f( const float* a_data, size_t a_step, + const float* b_data, size_t b_step, + const float* c_data, size_t c_step, + float* d_data, size_t d_step, + Size a_size, Size d_size, + double alpha, double beta, int flags ) +{ + GEMMSingleMul(a_data, a_step, b_data, b_step, c_data, + c_step, d_data, d_step, a_size, d_size, + alpha, beta, flags); +} + +static void GEMMSingleMul_64f( const double* a_data, size_t a_step, + const double* b_data, size_t b_step, + const double* c_data, size_t c_step, + double* d_data, size_t d_step, + Size a_size, Size d_size, + double alpha, double beta, int flags ) +{ + GEMMSingleMul(a_data, a_step, b_data, b_step, c_data, + c_step, d_data, d_step, a_size, d_size, + alpha, beta, flags); +} + + +static void GEMMSingleMul_32fc( const Complexf* a_data, size_t a_step, + const Complexf* b_data, size_t b_step, + const Complexf* c_data, size_t c_step, + Complexf* d_data, size_t d_step, + Size a_size, Size d_size, + double alpha, double beta, int flags ) +{ + GEMMSingleMul(a_data, a_step, b_data, b_step, c_data, + c_step, d_data, d_step, a_size, d_size, + alpha, beta, flags); +} + +static void GEMMSingleMul_64fc( const Complexd* a_data, size_t a_step, + const Complexd* b_data, size_t b_step, + const Complexd* c_data, size_t c_step, + Complexd* d_data, size_t d_step, + Size a_size, Size d_size, + double alpha, double beta, int flags ) +{ + GEMMSingleMul(a_data, a_step, b_data, b_step, c_data, + c_step, d_data, d_step, a_size, d_size, + alpha, beta, flags); +} + +static void GEMMBlockMul_32f( const float* a_data, size_t a_step, + const float* b_data, size_t b_step, + double* d_data, size_t d_step, + Size a_size, Size d_size, int flags ) +{ + GEMMBlockMul(a_data, a_step, b_data, b_step, d_data, d_step, a_size, d_size, flags); +} + + +static void GEMMBlockMul_64f( const double* a_data, size_t a_step, + const double* b_data, size_t b_step, + double* d_data, size_t d_step, + Size a_size, Size d_size, int flags ) +{ + GEMMBlockMul(a_data, a_step, b_data, b_step, d_data, d_step, a_size, d_size, flags); +} + + +static void GEMMBlockMul_32fc( const Complexf* a_data, size_t a_step, + const Complexf* b_data, size_t b_step, + Complexd* d_data, size_t d_step, + Size a_size, Size d_size, int flags ) +{ + GEMMBlockMul(a_data, a_step, b_data, b_step, d_data, d_step, a_size, d_size, flags); +} + + +static void GEMMBlockMul_64fc( const Complexd* a_data, size_t a_step, + const Complexd* b_data, size_t b_step, + Complexd* d_data, size_t d_step, + Size a_size, Size d_size, int flags ) +{ + GEMMBlockMul(a_data, a_step, b_data, b_step, d_data, d_step, a_size, d_size, flags); +} + + +static void GEMMStore_32f( const float* c_data, size_t c_step, + const double* d_buf, size_t d_buf_step, + float* d_data, size_t d_step, Size d_size, + double alpha, double beta, int flags ) +{ + GEMMStore(c_data, c_step, d_buf, d_buf_step, d_data, d_step, d_size, alpha, beta, flags); +} + + +static void GEMMStore_64f( const double* c_data, size_t c_step, + const double* d_buf, size_t d_buf_step, + double* d_data, size_t d_step, Size d_size, + double alpha, double beta, int flags ) +{ + GEMMStore(c_data, c_step, d_buf, d_buf_step, d_data, d_step, d_size, alpha, beta, flags); +} + + +static void GEMMStore_32fc( const Complexf* c_data, size_t c_step, + const Complexd* d_buf, size_t d_buf_step, + Complexf* d_data, size_t d_step, Size d_size, + double alpha, double beta, int flags ) +{ + GEMMStore(c_data, c_step, d_buf, d_buf_step, d_data, d_step, d_size, alpha, beta, flags); +} + + +static void GEMMStore_64fc( const Complexd* c_data, size_t c_step, + const Complexd* d_buf, size_t d_buf_step, + Complexd* d_data, size_t d_step, Size d_size, + double alpha, double beta, int flags ) +{ + GEMMStore(c_data, c_step, d_buf, d_buf_step, d_data, d_step, d_size, alpha, beta, flags); +} + +} + +void cv::gemm( InputArray matA, InputArray matB, double alpha, + InputArray matC, double beta, OutputArray _matD, int flags ) +{ + const int block_lin_size = 128; + const int block_size = block_lin_size * block_lin_size; + + static double zero[] = {0,0,0,0}; + static float zerof[] = {0,0,0,0}; + + Mat A = matA.getMat(), B = matB.getMat(), C = beta != 0 ? matC.getMat() : Mat(); + Size a_size = A.size(), d_size; + int i, len = 0, type = A.type(); + + CV_Assert( type == B.type() && (type == CV_32FC1 || type == CV_64FC1 || type == CV_32FC2 || type == CV_64FC2) ); + + switch( flags & (GEMM_1_T|GEMM_2_T) ) + { + case 0: + d_size = Size( B.cols, a_size.height ); + len = B.rows; + CV_Assert( a_size.width == len ); + break; + case 1: + d_size = Size( B.cols, a_size.width ); + len = B.rows; + CV_Assert( a_size.height == len ); + break; + case 2: + d_size = Size( B.rows, a_size.height ); + len = B.cols; + CV_Assert( a_size.width == len ); + break; + case 3: + d_size = Size( B.rows, a_size.width ); + len = B.cols; + CV_Assert( a_size.height == len ); + break; + } + + if( C.data ) + { + CV_Assert( C.type() == type && + (((flags&GEMM_3_T) == 0 && C.rows == d_size.height && C.cols == d_size.width) || + ((flags&GEMM_3_T) != 0 && C.rows == d_size.width && C.cols == d_size.height))); + } + + _matD.create( d_size.height, d_size.width, type ); + Mat D = _matD.getMat(); + if( (flags & GEMM_3_T) != 0 && C.data == D.data ) + { + transpose( C, C ); + flags &= ~GEMM_3_T; + } + + if( flags == 0 && 2 <= len && len <= 4 && (len == d_size.width || len == d_size.height) ) + { + if( type == CV_32F ) + { + float* d = (float*)D.data; + const float *a = (const float*)A.data, + *b = (const float*)B.data, + *c = (const float*)C.data; + size_t d_step = D.step/sizeof(d[0]), + a_step = A.step/sizeof(a[0]), + b_step = B.step/sizeof(b[0]), + c_step = C.data ? C.step/sizeof(c[0]) : 0; + + if( !c ) + c = zerof; + + switch( len ) + { + case 2: + if( len == d_size.width && b != d ) + { + for( i = 0; i < d_size.height; i++, d += d_step, a += a_step, c += c_step ) + { + float t0 = a[0]*b[0] + a[1]*b[b_step]; + float t1 = a[0]*b[1] + a[1]*b[b_step+1]; + d[0] = (float)(t0*alpha + c[0]*beta); + d[1] = (float)(t1*alpha + c[1]*beta); + } + } + else if( a != d ) + { + int c_step0 = 1; + if( c == zerof ) + { + c_step0 = 0; + c_step = 1; + } + + for( i = 0; i < d_size.width; i++, d++, b++, c += c_step0 ) + { + float t0 = a[0]*b[0] + a[1]*b[b_step]; + float t1 = a[a_step]*b[0] + a[a_step+1]*b[b_step]; + d[0] = (float)(t0*alpha + c[0]*beta); + d[d_step] = (float)(t1*alpha + c[c_step]*beta); + } + } + else + break; + return; + case 3: + if( len == d_size.width && b != d ) + { + for( i = 0; i < d_size.height; i++, d += d_step, a += a_step, c += c_step ) + { + float t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2]; + float t1 = a[0]*b[1] + a[1]*b[b_step+1] + a[2]*b[b_step*2+1]; + float t2 = a[0]*b[2] + a[1]*b[b_step+2] + a[2]*b[b_step*2+2]; + d[0] = (float)(t0*alpha + c[0]*beta); + d[1] = (float)(t1*alpha + c[1]*beta); + d[2] = (float)(t2*alpha + c[2]*beta); + } + } + else if( a != d ) + { + int c_step0 = 1; + if( c == zerof ) + { + c_step0 = 0; + c_step = 1; + } + + for( i = 0; i < d_size.width; i++, d++, b++, c += c_step0 ) + { + float t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2]; + float t1 = a[a_step]*b[0] + a[a_step+1]*b[b_step] + a[a_step+2]*b[b_step*2]; + float t2 = a[a_step*2]*b[0] + a[a_step*2+1]*b[b_step] + a[a_step*2+2]*b[b_step*2]; + + d[0] = (float)(t0*alpha + c[0]*beta); + d[d_step] = (float)(t1*alpha + c[c_step]*beta); + d[d_step*2] = (float)(t2*alpha + c[c_step*2]*beta); + } + } + else + break; + return; + case 4: + if( len == d_size.width && b != d ) + { + for( i = 0; i < d_size.height; i++, d += d_step, a += a_step, c += c_step ) + { + float t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2] + a[3]*b[b_step*3]; + float t1 = a[0]*b[1] + a[1]*b[b_step+1] + a[2]*b[b_step*2+1] + a[3]*b[b_step*3+1]; + float t2 = a[0]*b[2] + a[1]*b[b_step+2] + a[2]*b[b_step*2+2] + a[3]*b[b_step*3+2]; + float t3 = a[0]*b[3] + a[1]*b[b_step+3] + a[2]*b[b_step*2+3] + a[3]*b[b_step*3+3]; + d[0] = (float)(t0*alpha + c[0]*beta); + d[1] = (float)(t1*alpha + c[1]*beta); + d[2] = (float)(t2*alpha + c[2]*beta); + d[3] = (float)(t3*alpha + c[3]*beta); + } + } + else if( len <= 16 && a != d ) + { + int c_step0 = 1; + if( c == zerof ) + { + c_step0 = 0; + c_step = 1; + } + + for( i = 0; i < d_size.width; i++, d++, b++, c += c_step0 ) + { + float t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2] + a[3]*b[b_step*3]; + float t1 = a[a_step]*b[0] + a[a_step+1]*b[b_step] + + a[a_step+2]*b[b_step*2] + a[a_step+3]*b[b_step*3]; + float t2 = a[a_step*2]*b[0] + a[a_step*2+1]*b[b_step] + + a[a_step*2+2]*b[b_step*2] + a[a_step*2+3]*b[b_step*3]; + float t3 = a[a_step*3]*b[0] + a[a_step*3+1]*b[b_step] + + a[a_step*3+2]*b[b_step*2] + a[a_step*3+3]*b[b_step*3]; + d[0] = (float)(t0*alpha + c[0]*beta); + d[d_step] = (float)(t1*alpha + c[c_step]*beta); + d[d_step*2] = (float)(t2*alpha + c[c_step*2]*beta); + d[d_step*3] = (float)(t3*alpha + c[c_step*3]*beta); + } + } + else + break; + return; + } + } + + if( type == CV_64F ) + { + double* d = (double*)D.data; + const double *a = (const double*)A.data, + *b = (const double*)B.data, + *c = (const double*)C.data; + size_t d_step = D.step/sizeof(d[0]), + a_step = A.step/sizeof(a[0]), + b_step = B.step/sizeof(b[0]), + c_step = C.data ? C.step/sizeof(c[0]) : 0; + if( !c ) + c = zero; + + switch( len ) + { + case 2: + if( len == d_size.width && b != d ) + { + for( i = 0; i < d_size.height; i++, d += d_step, a += a_step, c += c_step ) + { + double t0 = a[0]*b[0] + a[1]*b[b_step]; + double t1 = a[0]*b[1] + a[1]*b[b_step+1]; + d[0] = t0*alpha + c[0]*beta; + d[1] = t1*alpha + c[1]*beta; + } + } + else if( a != d ) + { + int c_step0 = 1; + if( c == zero ) + { + c_step0 = 0; + c_step = 1; + } + + for( i = 0; i < d_size.width; i++, d++, b++, c += c_step0 ) + { + double t0 = a[0]*b[0] + a[1]*b[b_step]; + double t1 = a[a_step]*b[0] + a[a_step+1]*b[b_step]; + d[0] = t0*alpha + c[0]*beta; + d[d_step] = t1*alpha + c[c_step]*beta; + } + } + else + break; + return; + case 3: + if( len == d_size.width && b != d ) + { + for( i = 0; i < d_size.height; i++, d += d_step, a += a_step, c += c_step ) + { + double t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2]; + double t1 = a[0]*b[1] + a[1]*b[b_step+1] + a[2]*b[b_step*2+1]; + double t2 = a[0]*b[2] + a[1]*b[b_step+2] + a[2]*b[b_step*2+2]; + d[0] = t0*alpha + c[0]*beta; + d[1] = t1*alpha + c[1]*beta; + d[2] = t2*alpha + c[2]*beta; + } + } + else if( a != d ) + { + int c_step0 = 1; + if( c == zero ) + { + c_step0 = 0; + c_step = 1; + } + + for( i = 0; i < d_size.width; i++, d++, b++, c += c_step0 ) + { + double t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2]; + double t1 = a[a_step]*b[0] + a[a_step+1]*b[b_step] + a[a_step+2]*b[b_step*2]; + double t2 = a[a_step*2]*b[0] + a[a_step*2+1]*b[b_step] + a[a_step*2+2]*b[b_step*2]; + + d[0] = t0*alpha + c[0]*beta; + d[d_step] = t1*alpha + c[c_step]*beta; + d[d_step*2] = t2*alpha + c[c_step*2]*beta; + } + } + else + break; + return; + case 4: + if( len == d_size.width && b != d ) + { + for( i = 0; i < d_size.height; i++, d += d_step, a += a_step, c += c_step ) + { + double t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2] + a[3]*b[b_step*3]; + double t1 = a[0]*b[1] + a[1]*b[b_step+1] + a[2]*b[b_step*2+1] + a[3]*b[b_step*3+1]; + double t2 = a[0]*b[2] + a[1]*b[b_step+2] + a[2]*b[b_step*2+2] + a[3]*b[b_step*3+2]; + double t3 = a[0]*b[3] + a[1]*b[b_step+3] + a[2]*b[b_step*2+3] + a[3]*b[b_step*3+3]; + d[0] = t0*alpha + c[0]*beta; + d[1] = t1*alpha + c[1]*beta; + d[2] = t2*alpha + c[2]*beta; + d[3] = t3*alpha + c[3]*beta; + } + } + else if( d_size.width <= 16 && a != d ) + { + int c_step0 = 1; + if( c == zero ) + { + c_step0 = 0; + c_step = 1; + } + + for( i = 0; i < d_size.width; i++, d++, b++, c += c_step0 ) + { + double t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2] + a[3]*b[b_step*3]; + double t1 = a[a_step]*b[0] + a[a_step+1]*b[b_step] + + a[a_step+2]*b[b_step*2] + a[a_step+3]*b[b_step*3]; + double t2 = a[a_step*2]*b[0] + a[a_step*2+1]*b[b_step] + + a[a_step*2+2]*b[b_step*2] + a[a_step*2+3]*b[b_step*3]; + double t3 = a[a_step*3]*b[0] + a[a_step*3+1]*b[b_step] + + a[a_step*3+2]*b[b_step*2] + a[a_step*3+3]*b[b_step*3]; + d[0] = t0*alpha + c[0]*beta; + d[d_step] = t1*alpha + c[c_step]*beta; + d[d_step*2] = t2*alpha + c[c_step*2]*beta; + d[d_step*3] = t3*alpha + c[c_step*3]*beta; + } + } + else + break; + return; + } + } + } + + { + size_t b_step = B.step; + GEMMSingleMulFunc singleMulFunc; + GEMMBlockMulFunc blockMulFunc; + GEMMStoreFunc storeFunc; + Mat *matD = &D, tmat; + const uchar* Cdata = C.data; + size_t Cstep = C.data ? (size_t)C.step : 0; + AutoBuffer buf; + + if( type == CV_32FC1 ) + { + singleMulFunc = (GEMMSingleMulFunc)GEMMSingleMul_32f; + blockMulFunc = (GEMMBlockMulFunc)GEMMBlockMul_32f; + storeFunc = (GEMMStoreFunc)GEMMStore_32f; + } + else if( type == CV_64FC1 ) + { + singleMulFunc = (GEMMSingleMulFunc)GEMMSingleMul_64f; + blockMulFunc = (GEMMBlockMulFunc)GEMMBlockMul_64f; + storeFunc = (GEMMStoreFunc)GEMMStore_64f; + } + else if( type == CV_32FC2 ) + { + singleMulFunc = (GEMMSingleMulFunc)GEMMSingleMul_32fc; + blockMulFunc = (GEMMBlockMulFunc)GEMMBlockMul_32fc; + storeFunc = (GEMMStoreFunc)GEMMStore_32fc; + } + else + { + CV_Assert( type == CV_64FC2 ); + singleMulFunc = (GEMMSingleMulFunc)GEMMSingleMul_64fc; + blockMulFunc = (GEMMBlockMulFunc)GEMMBlockMul_64fc; + storeFunc = (GEMMStoreFunc)GEMMStore_64fc; + } + + if( D.data == A.data || D.data == B.data ) + { + buf.allocate(d_size.width*d_size.height*CV_ELEM_SIZE(type)); + tmat = Mat(d_size.height, d_size.width, type, (uchar*)buf ); + matD = &tmat; + } + + if( (d_size.width == 1 || len == 1) && !(flags & GEMM_2_T) && B.isContinuous() ) + { + b_step = d_size.width == 1 ? 0 : CV_ELEM_SIZE(type); + flags |= GEMM_2_T; + } + + /*if( (d_size.width | d_size.height | len) >= 16 && icvBLAS_GEMM_32f_p != 0 ) + { + blas_func = type == CV_32FC1 ? (icvBLAS_GEMM_32f_t)icvBLAS_GEMM_32f_p : + type == CV_64FC1 ? (icvBLAS_GEMM_32f_t)icvBLAS_GEMM_64f_p : + type == CV_32FC2 ? (icvBLAS_GEMM_32f_t)icvBLAS_GEMM_32fc_p : + type == CV_64FC2 ? (icvBLAS_GEMM_32f_t)icvBLAS_GEMM_64fc_p : 0; + } + + if( blas_func ) + { + const char* transa = flags & GEMM_1_T ? "t" : "n"; + const char* transb = flags & GEMM_2_T ? "t" : "n"; + int lda, ldb, ldd; + + if( C->data.ptr ) + { + if( C->data.ptr != D->data.ptr ) + { + if( !(flags & GEMM_3_T) ) + cvCopy( C, D ); + else + cvTranspose( C, D ); + } + } + + if( CV_MAT_DEPTH(type) == CV_32F ) + { + Complex32f _alpha, _beta; + + lda = A->step/sizeof(float); + ldb = b_step/sizeof(float); + ldd = D->step/sizeof(float); + _alpha.re = (float)alpha; + _alpha.im = 0; + _beta.re = C->data.ptr ? (float)beta : 0; + _beta.im = 0; + if( CV_MAT_CN(type) == 2 ) + lda /= 2, ldb /= 2, ldd /= 2; + + blas_func( transb, transa, &d_size.width, &d_size.height, &len, + &_alpha, B->data.ptr, &ldb, A->data.ptr, &lda, + &_beta, D->data.ptr, &ldd ); + } + else + { + CvComplex64f _alpha, _beta; + + lda = A->step/sizeof(double); + ldb = b_step/sizeof(double); + ldd = D->step/sizeof(double); + _alpha.re = alpha; + _alpha.im = 0; + _beta.re = C->data.ptr ? beta : 0; + _beta.im = 0; + if( CV_MAT_CN(type) == 2 ) + lda /= 2, ldb /= 2, ldd /= 2; + + blas_func( transb, transa, &d_size.width, &d_size.height, &len, + &_alpha, B->data.ptr, &ldb, A->data.ptr, &lda, + &_beta, D->data.ptr, &ldd ); + } + } + else*/ if( ((d_size.height <= block_lin_size/2 || d_size.width <= block_lin_size/2) && + len <= 10000) || len <= 10 || + (d_size.width <= block_lin_size && + d_size.height <= block_lin_size && len <= block_lin_size) ) + { + singleMulFunc( A.data, A.step, B.data, b_step, Cdata, Cstep, + matD->data, matD->step, a_size, d_size, alpha, beta, flags ); + } + else + { + int is_a_t = flags & GEMM_1_T; + int is_b_t = flags & GEMM_2_T; + int elem_size = CV_ELEM_SIZE(type); + int dk0_1, dk0_2; + int a_buf_size = 0, b_buf_size, d_buf_size; + uchar* a_buf = 0; + uchar* b_buf = 0; + uchar* d_buf = 0; + int j, k, di = 0, dj = 0, dk = 0; + int dm0, dn0, dk0; + size_t a_step0, a_step1, b_step0, b_step1, c_step0, c_step1; + int work_elem_size = elem_size << (CV_MAT_DEPTH(type) == CV_32F ? 1 : 0); + + if( !is_a_t ) + a_step0 = A.step, a_step1 = elem_size; + else + a_step0 = elem_size, a_step1 = A.step; + + if( !is_b_t ) + b_step0 = b_step, b_step1 = elem_size; + else + b_step0 = elem_size, b_step1 = b_step; + + if( !C.data ) + { + c_step0 = c_step1 = 0; + flags &= ~GEMM_3_T; + } + else if( !(flags & GEMM_3_T) ) + c_step0 = C.step, c_step1 = elem_size; + else + c_step0 = elem_size, c_step1 = C.step; + + dm0 = std::min( block_lin_size, d_size.height ); + dn0 = std::min( block_lin_size, d_size.width ); + dk0_1 = block_size / dm0; + dk0_2 = block_size / dn0; + dk0 = std::min( dk0_1, dk0_2 ); + dk0 = std::min( dk0, len ); + if( dk0*dm0 > block_size ) + dm0 = block_size / dk0; + if( dk0*dn0 > block_size ) + dn0 = block_size / dk0; + + dk0_1 = (dn0+dn0/8+2) & -2; + b_buf_size = (dk0+dk0/8+1)*dk0_1*elem_size; + d_buf_size = (dk0+dk0/8+1)*dk0_1*work_elem_size; + + if( is_a_t ) + { + a_buf_size = (dm0+dm0/8+1)*((dk0+dk0/8+2)&-2)*elem_size; + flags &= ~GEMM_1_T; + } + + buf.allocate(a_buf_size + b_buf_size + d_buf_size); + d_buf = (uchar*)buf; + b_buf = d_buf + d_buf_size; + + if( is_a_t ) + a_buf = b_buf + b_buf_size; + + for( i = 0; i < d_size.height; i += di ) + { + di = dm0; + if( i + di >= d_size.height || 8*(i + di) + di > 8*d_size.height ) + di = d_size.height - i; + + for( j = 0; j < d_size.width; j += dj ) + { + uchar* _d = matD->data + i*matD->step + j*elem_size; + const uchar* _c = Cdata + i*c_step0 + j*c_step1; + size_t _d_step = matD->step; + dj = dn0; + + if( j + dj >= d_size.width || 8*(j + dj) + dj > 8*d_size.width ) + dj = d_size.width - j; + + flags &= 15; + if( dk0 < len ) + { + _d = d_buf; + _d_step = dj*work_elem_size; + } + + for( k = 0; k < len; k += dk ) + { + const uchar* _a = A.data + i*a_step0 + k*a_step1; + size_t _a_step = A.step; + const uchar* _b = B.data + k*b_step0 + j*b_step1; + size_t _b_step = b_step; + Size a_bl_size; + + dk = dk0; + if( k + dk >= len || 8*(k + dk) + dk > 8*len ) + dk = len - k; + + if( !is_a_t ) + a_bl_size.width = dk, a_bl_size.height = di; + else + a_bl_size.width = di, a_bl_size.height = dk; + + if( a_buf && is_a_t ) + { + _a_step = dk*elem_size; + GEMM_TransposeBlock( _a, A.step, a_buf, _a_step, a_bl_size, elem_size ); + std::swap( a_bl_size.width, a_bl_size.height ); + _a = a_buf; + } + + if( dj < d_size.width ) + { + Size b_size; + if( !is_b_t ) + b_size.width = dj, b_size.height = dk; + else + b_size.width = dk, b_size.height = dj; + + _b_step = b_size.width*elem_size; + GEMM_CopyBlock( _b, b_step, b_buf, _b_step, b_size, elem_size ); + _b = b_buf; + } + + if( dk0 < len ) + blockMulFunc( _a, _a_step, _b, _b_step, _d, _d_step, + a_bl_size, Size(dj,di), flags ); + else + singleMulFunc( _a, _a_step, _b, _b_step, _c, Cstep, + _d, _d_step, a_bl_size, Size(dj,di), alpha, beta, flags ); + flags |= 16; + } + + if( dk0 < len ) + storeFunc( _c, Cstep, _d, _d_step, + matD->data + i*matD->step + j*elem_size, + matD->step, Size(dj,di), alpha, beta, flags ); + } + } + } + + if( matD != &D ) + matD->copyTo(D); + } +} + +/****************************************************************************************\ +* Transform * +\****************************************************************************************/ + +namespace cv +{ + +template static void +transform_( const T* src, T* dst, const WT* m, int len, int scn, int dcn ) +{ + int x; + + if( scn == 2 && dcn == 2 ) + { + for( x = 0; x < len*2; x += 2 ) + { + WT v0 = src[x], v1 = src[x+1]; + T t0 = saturate_cast(m[0]*v0 + m[1]*v1 + m[2]); + T t1 = saturate_cast(m[3]*v0 + m[4]*v1 + m[5]); + dst[x] = t0; dst[x+1] = t1; + } + } + else if( scn == 3 && dcn == 3 ) + { + for( x = 0; x < len*3; x += 3 ) + { + WT v0 = src[x], v1 = src[x+1], v2 = src[x+2]; + T t0 = saturate_cast(m[0]*v0 + m[1]*v1 + m[2]*v2 + m[3]); + T t1 = saturate_cast(m[4]*v0 + m[5]*v1 + m[6]*v2 + m[7]); + T t2 = saturate_cast(m[8]*v0 + m[9]*v1 + m[10]*v2 + m[11]); + dst[x] = t0; dst[x+1] = t1; dst[x+2] = t2; + } + } + else if( scn == 3 && dcn == 1 ) + { + for( x = 0; x < len; x++, src += 3 ) + dst[x] = saturate_cast(m[0]*src[0] + m[1]*src[1] + m[2]*src[2] + m[3]); + } + else if( scn == 4 && dcn == 4 ) + { + for( x = 0; x < len*4; x += 4 ) + { + WT v0 = src[x], v1 = src[x+1], v2 = src[x+2], v3 = src[x+3]; + T t0 = saturate_cast(m[0]*v0 + m[1]*v1 + m[2]*v2 + m[3]*v3 + m[4]); + T t1 = saturate_cast(m[5]*v0 + m[6]*v1 + m[7]*v2 + m[8]*v3 + m[9]); + dst[x] = t0; dst[x+1] = t1; + t0 = saturate_cast(m[10]*v0 + m[11]*v1 + m[12]*v2 + m[13]*v3 + m[14]); + t1 = saturate_cast(m[15]*v0 + m[16]*v1 + m[17]*v2 + m[18]*v3 + m[19]); + dst[x+2] = t0; dst[x+3] = t1; + } + } + else + { + for( x = 0; x < len; x++, src += scn, dst += dcn ) + { + const WT* _m = m; + int j, k; + for( j = 0; j < dcn; j++, _m += scn + 1 ) + { + WT s = _m[scn]; + for( k = 0; k < scn; k++ ) + s += _m[k]*src[k]; + dst[j] = saturate_cast(s); + } + } + } +} + +#if CV_SSE2 + +static inline void +load3x3Matrix( const float* m, __m128& m0, __m128& m1, __m128& m2, __m128& m3 ) +{ + m0 = _mm_setr_ps(m[0], m[4], m[8], 0); + m1 = _mm_setr_ps(m[1], m[5], m[9], 0); + m2 = _mm_setr_ps(m[2], m[6], m[10], 0); + m3 = _mm_setr_ps(m[3], m[7], m[11], 0); +} + +static inline void +load4x4Matrix( const float* m, __m128& m0, __m128& m1, __m128& m2, __m128& m3, __m128& m4 ) +{ + m0 = _mm_setr_ps(m[0], m[5], m[10], m[15]); + m1 = _mm_setr_ps(m[1], m[6], m[11], m[16]); + m2 = _mm_setr_ps(m[2], m[7], m[12], m[17]); + m3 = _mm_setr_ps(m[3], m[8], m[13], m[18]); + m4 = _mm_setr_ps(m[4], m[9], m[14], m[19]); +} + +#endif + +static void +transform_8u( const uchar* src, uchar* dst, const float* m, int len, int scn, int dcn ) +{ +#if CV_SSE2 + const int BITS = 10, SCALE = 1 << BITS; + const float MAX_M = (float)(1 << (15 - BITS)); + + if( USE_SSE2 && scn == 3 && dcn == 3 && + std::abs(m[0]) < MAX_M && std::abs(m[1]) < MAX_M && std::abs(m[2]) < MAX_M && std::abs(m[3]) < MAX_M*256 && + std::abs(m[4]) < MAX_M && std::abs(m[5]) < MAX_M && std::abs(m[6]) < MAX_M && std::abs(m[7]) < MAX_M*256 && + std::abs(m[8]) < MAX_M && std::abs(m[9]) < MAX_M && std::abs(m[10]) < MAX_M && std::abs(m[11]) < MAX_M*256 ) + { + // faster fixed-point transformation + short m00 = saturate_cast(m[0]*SCALE), m01 = saturate_cast(m[1]*SCALE), + m02 = saturate_cast(m[2]*SCALE), m10 = saturate_cast(m[4]*SCALE), + m11 = saturate_cast(m[5]*SCALE), m12 = saturate_cast(m[6]*SCALE), + m20 = saturate_cast(m[8]*SCALE), m21 = saturate_cast(m[9]*SCALE), + m22 = saturate_cast(m[10]*SCALE); + int m03 = saturate_cast((m[3]+0.5f)*SCALE), m13 = saturate_cast((m[7]+0.5f)*SCALE ), + m23 = saturate_cast((m[11]+0.5f)*SCALE); + + __m128i m0 = _mm_setr_epi16(0, m00, m01, m02, m00, m01, m02, 0); + __m128i m1 = _mm_setr_epi16(0, m10, m11, m12, m10, m11, m12, 0); + __m128i m2 = _mm_setr_epi16(0, m20, m21, m22, m20, m21, m22, 0); + __m128i m3 = _mm_setr_epi32(m03, m13, m23, 0); + int x = 0; + + for( ; x <= (len - 8)*3; x += 8*3 ) + { + __m128i z = _mm_setzero_si128(), t0, t1, t2, r0, r1; + __m128i v0 = _mm_loadl_epi64((const __m128i*)(src + x)); + __m128i v1 = _mm_loadl_epi64((const __m128i*)(src + x + 8)); + __m128i v2 = _mm_loadl_epi64((const __m128i*)(src + x + 16)), v3; + v0 = _mm_unpacklo_epi8(v0, z); // b0 g0 r0 b1 g1 r1 b2 g2 + v1 = _mm_unpacklo_epi8(v1, z); // r2 b3 g3 r3 b4 g4 r4 b5 + v2 = _mm_unpacklo_epi8(v2, z); // g5 r5 b6 g6 r6 b7 g7 r7 + + v3 = _mm_srli_si128(v2, 2); // ? b6 g6 r6 b7 g7 r7 0 + v2 = _mm_or_si128(_mm_slli_si128(v2, 10), _mm_srli_si128(v1, 6)); // ? b4 g4 r4 b5 g5 r5 ? + v1 = _mm_or_si128(_mm_slli_si128(v1, 6), _mm_srli_si128(v0, 10)); // ? b2 g2 r2 b3 g3 r3 ? + v0 = _mm_slli_si128(v0, 2); // 0 b0 g0 r0 b1 g1 r1 ? + + // process pixels 0 & 1 + t0 = _mm_madd_epi16(v0, m0); // a0 b0 a1 b1 + t1 = _mm_madd_epi16(v0, m1); // c0 d0 c1 d1 + t2 = _mm_madd_epi16(v0, m2); // e0 f0 e1 f1 + v0 = _mm_unpacklo_epi32(t0, t1); // a0 c0 b0 d0 + t0 = _mm_unpackhi_epi32(t0, t1); // a1 b1 c1 d1 + t1 = _mm_unpacklo_epi32(t2, z); // e0 0 f0 0 + t2 = _mm_unpackhi_epi32(t2, z); // e1 0 f1 0 + r0 = _mm_add_epi32(_mm_add_epi32(_mm_unpacklo_epi64(v0, t1), _mm_unpackhi_epi64(v0,t1)), m3); // B0 G0 R0 0 + r1 = _mm_add_epi32(_mm_add_epi32(_mm_unpacklo_epi64(t0, t2), _mm_unpackhi_epi64(t0,t2)), m3); // B1 G1 R1 0 + r0 = _mm_srai_epi32(r0, BITS); + r1 = _mm_srai_epi32(r1, BITS); + v0 = _mm_packus_epi16(_mm_packs_epi32(_mm_slli_si128(r0, 4), r1), z); // 0 B0 G0 R0 B1 G1 R1 0 + + // process pixels 2 & 3 + t0 = _mm_madd_epi16(v1, m0); // a0 b0 a1 b1 + t1 = _mm_madd_epi16(v1, m1); // c0 d0 c1 d1 + t2 = _mm_madd_epi16(v1, m2); // e0 f0 e1 f1 + v1 = _mm_unpacklo_epi32(t0, t1); // a0 c0 b0 d0 + t0 = _mm_unpackhi_epi32(t0, t1); // a1 b1 c1 d1 + t1 = _mm_unpacklo_epi32(t2, z); // e0 0 f0 0 + t2 = _mm_unpackhi_epi32(t2, z); // e1 0 f1 0 + r0 = _mm_add_epi32(_mm_add_epi32(_mm_unpacklo_epi64(v1, t1), _mm_unpackhi_epi64(v1,t1)), m3); // B2 G2 R2 0 + r1 = _mm_add_epi32(_mm_add_epi32(_mm_unpacklo_epi64(t0, t2), _mm_unpackhi_epi64(t0,t2)), m3); // B3 G3 R3 0 + r0 = _mm_srai_epi32(r0, BITS); + r1 = _mm_srai_epi32(r1, BITS); + v1 = _mm_packus_epi16(_mm_packs_epi32(_mm_slli_si128(r0, 4), r1), z); // 0 B2 G2 R2 B3 G3 R3 0 + + // process pixels 4 & 5 + t0 = _mm_madd_epi16(v2, m0); // a0 b0 a1 b1 + t1 = _mm_madd_epi16(v2, m1); // c0 d0 c1 d1 + t2 = _mm_madd_epi16(v2, m2); // e0 f0 e1 f1 + v2 = _mm_unpacklo_epi32(t0, t1); // a0 c0 b0 d0 + t0 = _mm_unpackhi_epi32(t0, t1); // a1 b1 c1 d1 + t1 = _mm_unpacklo_epi32(t2, z); // e0 0 f0 0 + t2 = _mm_unpackhi_epi32(t2, z); // e1 0 f1 0 + r0 = _mm_add_epi32(_mm_add_epi32(_mm_unpacklo_epi64(v2, t1), _mm_unpackhi_epi64(v2,t1)), m3); // B4 G4 R4 0 + r1 = _mm_add_epi32(_mm_add_epi32(_mm_unpacklo_epi64(t0, t2), _mm_unpackhi_epi64(t0,t2)), m3); // B5 G5 R5 0 + r0 = _mm_srai_epi32(r0, BITS); + r1 = _mm_srai_epi32(r1, BITS); + v2 = _mm_packus_epi16(_mm_packs_epi32(_mm_slli_si128(r0, 4), r1), z); // 0 B4 G4 R4 B5 G5 R5 0 + + // process pixels 6 & 7 + t0 = _mm_madd_epi16(v3, m0); // a0 b0 a1 b1 + t1 = _mm_madd_epi16(v3, m1); // c0 d0 c1 d1 + t2 = _mm_madd_epi16(v3, m2); // e0 f0 e1 f1 + v3 = _mm_unpacklo_epi32(t0, t1); // a0 c0 b0 d0 + t0 = _mm_unpackhi_epi32(t0, t1); // a1 b1 c1 d1 + t1 = _mm_unpacklo_epi32(t2, z); // e0 0 f0 0 + t2 = _mm_unpackhi_epi32(t2, z); // e1 0 f1 0 + r0 = _mm_add_epi32(_mm_add_epi32(_mm_unpacklo_epi64(v3, t1), _mm_unpackhi_epi64(v3,t1)), m3); // B6 G6 R6 0 + r1 = _mm_add_epi32(_mm_add_epi32(_mm_unpacklo_epi64(t0, t2), _mm_unpackhi_epi64(t0,t2)), m3); // B7 G7 R7 0 + r0 = _mm_srai_epi32(r0, BITS); + r1 = _mm_srai_epi32(r1, BITS); + v3 = _mm_packus_epi16(_mm_packs_epi32(_mm_slli_si128(r0, 4), r1), z); // 0 B6 G6 R6 B7 G7 R7 0 + + v0 = _mm_or_si128(_mm_srli_si128(v0, 1), _mm_slli_si128(v1, 5)); + v1 = _mm_or_si128(_mm_srli_si128(v1, 3), _mm_slli_si128(v2, 3)); + v2 = _mm_or_si128(_mm_srli_si128(v2, 5), _mm_slli_si128(v3, 1)); + _mm_storel_epi64((__m128i*)(dst + x), v0); + _mm_storel_epi64((__m128i*)(dst + x + 8), v1); + _mm_storel_epi64((__m128i*)(dst + x + 16), v2); + } + + for( ; x < len*3; x += 3 ) + { + int v0 = src[x], v1 = src[x+1], v2 = src[x+2]; + uchar t0 = saturate_cast((m00*v0 + m01*v1 + m02*v2 + m03)>>BITS); + uchar t1 = saturate_cast((m10*v0 + m11*v1 + m12*v2 + m13)>>BITS); + uchar t2 = saturate_cast((m20*v0 + m21*v1 + m22*v2 + m23)>>BITS); + dst[x] = t0; dst[x+1] = t1; dst[x+2] = t2; + } + return; + } +#endif + + transform_(src, dst, m, len, scn, dcn); +} + +static void +transform_16u( const ushort* src, ushort* dst, const float* m, int len, int scn, int dcn ) +{ +#if CV_SSE2 + if( USE_SSE2 && scn == 3 && dcn == 3 ) + { + __m128 m0, m1, m2, m3; + __m128i delta = _mm_setr_epi16(0,-32768,-32768,-32768,-32768,-32768,-32768,0); + load3x3Matrix(m, m0, m1, m2, m3); + m3 = _mm_sub_ps(m3, _mm_setr_ps(32768.f, 32768.f, 32768.f, 0.f)); + + int x = 0; + for( ; x <= (len - 4)*3; x += 4*3 ) + { + __m128i z = _mm_setzero_si128(); + __m128i v0 = _mm_loadu_si128((const __m128i*)(src + x)), v1; + __m128i v2 = _mm_loadl_epi64((const __m128i*)(src + x + 8)), v3; + v1 = _mm_unpacklo_epi16(_mm_srli_si128(v0, 6), z); // b1 g1 r1 + v3 = _mm_unpacklo_epi16(_mm_srli_si128(v2, 2), z); // b3 g3 r3 + v2 = _mm_or_si128(_mm_srli_si128(v0, 12), _mm_slli_si128(v2, 4)); + v0 = _mm_unpacklo_epi16(v0, z); // b0 g0 r0 + v2 = _mm_unpacklo_epi16(v2, z); // b2 g2 r2 + __m128 x0 = _mm_cvtepi32_ps(v0), x1 = _mm_cvtepi32_ps(v1); + __m128 x2 = _mm_cvtepi32_ps(v2), x3 = _mm_cvtepi32_ps(v3); + __m128 y0 = _mm_add_ps(_mm_add_ps(_mm_add_ps( + _mm_mul_ps(m0, _mm_shuffle_ps(x0,x0,_MM_SHUFFLE(0,0,0,0))), + _mm_mul_ps(m1, _mm_shuffle_ps(x0,x0,_MM_SHUFFLE(1,1,1,1)))), + _mm_mul_ps(m2, _mm_shuffle_ps(x0,x0,_MM_SHUFFLE(2,2,2,2)))), m3); + __m128 y1 = _mm_add_ps(_mm_add_ps(_mm_add_ps( + _mm_mul_ps(m0, _mm_shuffle_ps(x1,x1,_MM_SHUFFLE(0,0,0,0))), + _mm_mul_ps(m1, _mm_shuffle_ps(x1,x1,_MM_SHUFFLE(1,1,1,1)))), + _mm_mul_ps(m2, _mm_shuffle_ps(x1,x1,_MM_SHUFFLE(2,2,2,2)))), m3); + __m128 y2 = _mm_add_ps(_mm_add_ps(_mm_add_ps( + _mm_mul_ps(m0, _mm_shuffle_ps(x2,x2,_MM_SHUFFLE(0,0,0,0))), + _mm_mul_ps(m1, _mm_shuffle_ps(x2,x2,_MM_SHUFFLE(1,1,1,1)))), + _mm_mul_ps(m2, _mm_shuffle_ps(x2,x2,_MM_SHUFFLE(2,2,2,2)))), m3); + __m128 y3 = _mm_add_ps(_mm_add_ps(_mm_add_ps( + _mm_mul_ps(m0, _mm_shuffle_ps(x3,x3,_MM_SHUFFLE(0,0,0,0))), + _mm_mul_ps(m1, _mm_shuffle_ps(x3,x3,_MM_SHUFFLE(1,1,1,1)))), + _mm_mul_ps(m2, _mm_shuffle_ps(x3,x3,_MM_SHUFFLE(2,2,2,2)))), m3); + v0 = _mm_cvtps_epi32(y0); v1 = _mm_cvtps_epi32(y1); + v2 = _mm_cvtps_epi32(y2); v3 = _mm_cvtps_epi32(y3); + + v0 = _mm_add_epi16(_mm_packs_epi32(_mm_slli_si128(v0,4), v1), delta); // 0 b0 g0 r0 b1 g1 r1 0 + v2 = _mm_add_epi16(_mm_packs_epi32(_mm_slli_si128(v2,4), v3), delta); // 0 b2 g2 r2 b3 g3 r3 0 + v1 = _mm_or_si128(_mm_srli_si128(v0,2), _mm_slli_si128(v2,10)); // b0 g0 r0 b1 g1 r1 b2 g2 + v2 = _mm_srli_si128(v2, 6); // r2 b3 g3 r3 0 0 0 0 + _mm_storeu_si128((__m128i*)(dst + x), v1); + _mm_storel_epi64((__m128i*)(dst + x + 8), v2); + } + + for( ; x < len*3; x += 3 ) + { + float v0 = src[x], v1 = src[x+1], v2 = src[x+2]; + ushort t0 = saturate_cast(m[0]*v0 + m[1]*v1 + m[2]*v2 + m[3]); + ushort t1 = saturate_cast(m[4]*v0 + m[5]*v1 + m[6]*v2 + m[7]); + ushort t2 = saturate_cast(m[8]*v0 + m[9]*v1 + m[10]*v2 + m[11]); + dst[x] = t0; dst[x+1] = t1; dst[x+2] = t2; + } + return; + } +#endif + + transform_(src, dst, m, len, scn, dcn); +} + + +static void +transform_32f( const float* src, float* dst, const float* m, int len, int scn, int dcn ) +{ +#if CV_SSE2 + if( USE_SSE2 ) + { + int x = 0; + if( scn == 3 && dcn == 3 ) + { + __m128 m0, m1, m2, m3; + load3x3Matrix(m, m0, m1, m2, m3); + + for( ; x < (len - 1)*3; x += 3 ) + { + __m128 x0 = _mm_loadu_ps(src + x); + __m128 y0 = _mm_add_ps(_mm_add_ps(_mm_add_ps( + _mm_mul_ps(m0, _mm_shuffle_ps(x0,x0,_MM_SHUFFLE(0,0,0,0))), + _mm_mul_ps(m1, _mm_shuffle_ps(x0,x0,_MM_SHUFFLE(1,1,1,1)))), + _mm_mul_ps(m2, _mm_shuffle_ps(x0,x0,_MM_SHUFFLE(2,2,2,2)))), m3); + _mm_storel_pi((__m64*)(dst + x), y0); + _mm_store_ss(dst + x + 2, _mm_movehl_ps(y0,y0)); + } + + for( ; x < len*3; x += 3 ) + { + float v0 = src[x], v1 = src[x+1], v2 = src[x+2]; + float t0 = saturate_cast(m[0]*v0 + m[1]*v1 + m[2]*v2 + m[3]); + float t1 = saturate_cast(m[4]*v0 + m[5]*v1 + m[6]*v2 + m[7]); + float t2 = saturate_cast(m[8]*v0 + m[9]*v1 + m[10]*v2 + m[11]); + dst[x] = t0; dst[x+1] = t1; dst[x+2] = t2; + } + return; + } + + if( scn == 4 && dcn == 4 ) + { + __m128 m0, m1, m2, m3, m4; + load4x4Matrix(m, m0, m1, m2, m3, m4); + + for( ; x < len*4; x += 4 ) + { + __m128 x0 = _mm_loadu_ps(src + x); + __m128 y0 = _mm_add_ps(_mm_add_ps(_mm_add_ps(_mm_add_ps( + _mm_mul_ps(m0, _mm_shuffle_ps(x0,x0,_MM_SHUFFLE(0,0,0,0))), + _mm_mul_ps(m1, _mm_shuffle_ps(x0,x0,_MM_SHUFFLE(1,1,1,1)))), + _mm_mul_ps(m2, _mm_shuffle_ps(x0,x0,_MM_SHUFFLE(2,2,2,2)))), + _mm_mul_ps(m3, _mm_shuffle_ps(x0,x0,_MM_SHUFFLE(3,3,3,3)))), m4); + _mm_storeu_ps(dst + x, y0); + } + return; + } + } +#endif + + transform_(src, dst, m, len, scn, dcn); +} + + +static void +transform_8s(const schar* src, schar* dst, const float* m, int len, int scn, int dcn) +{ + transform_(src, dst, m, len, scn, dcn); +} + +static void +transform_16s(const short* src, short* dst, const float* m, int len, int scn, int dcn) +{ + transform_(src, dst, m, len, scn, dcn); +} + +static void +transform_32s(const int* src, int* dst, const double* m, int len, int scn, int dcn) +{ + transform_(src, dst, m, len, scn, dcn); +} + +static void +transform_64f(const double* src, double* dst, const double* m, int len, int scn, int dcn) +{ + transform_(src, dst, m, len, scn, dcn); +} + +template static void +diagtransform_( const T* src, T* dst, const WT* m, int len, int cn, int ) +{ + int x; + + if( cn == 2 ) + { + for( x = 0; x < len*2; x += 2 ) + { + T t0 = saturate_cast(m[0]*src[x] + m[2]); + T t1 = saturate_cast(m[4]*src[x+1] + m[5]); + dst[x] = t0; dst[x+1] = t1; + } + } + else if( cn == 3 ) + { + for( x = 0; x < len*3; x += 3 ) + { + T t0 = saturate_cast(m[0]*src[x] + m[3]); + T t1 = saturate_cast(m[5]*src[x+1] + m[7]); + T t2 = saturate_cast(m[10]*src[x+2] + m[11]); + dst[x] = t0; dst[x+1] = t1; dst[x+2] = t2; + } + } + else if( cn == 4 ) + { + for( x = 0; x < len*4; x += 4 ) + { + T t0 = saturate_cast(m[0]*src[x] + m[4]); + T t1 = saturate_cast(m[6]*src[x+1] + m[9]); + dst[x] = t0; dst[x+1] = t1; + t0 = saturate_cast(m[12]*src[x+2] + m[14]); + t1 = saturate_cast(m[18]*src[x+3] + m[19]); + dst[x+2] = t0; dst[x+3] = t1; + } + } + else + { + for( x = 0; x < len; x++, src += cn, dst += cn ) + { + const WT* _m = m; + for( int j = 0; j < cn; j++, _m += cn + 1 ) + dst[j] = saturate_cast(src[j]*_m[j] + _m[cn]); + } + } +} + +static void +diagtransform_8u(const uchar* src, uchar* dst, const float* m, int len, int scn, int dcn) +{ + diagtransform_(src, dst, m, len, scn, dcn); +} + +static void +diagtransform_8s(const schar* src, schar* dst, const float* m, int len, int scn, int dcn) +{ + diagtransform_(src, dst, m, len, scn, dcn); +} + +static void +diagtransform_16u(const ushort* src, ushort* dst, const float* m, int len, int scn, int dcn) +{ + diagtransform_(src, dst, m, len, scn, dcn); +} + +static void +diagtransform_16s(const short* src, short* dst, const float* m, int len, int scn, int dcn) +{ + diagtransform_(src, dst, m, len, scn, dcn); +} + +static void +diagtransform_32s(const int* src, int* dst, const double* m, int len, int scn, int dcn) +{ + diagtransform_(src, dst, m, len, scn, dcn); +} + +static void +diagtransform_32f(const float* src, float* dst, const float* m, int len, int scn, int dcn) +{ + diagtransform_(src, dst, m, len, scn, dcn); +} + +static void +diagtransform_64f(const double* src, double* dst, const double* m, int len, int scn, int dcn) +{ + diagtransform_(src, dst, m, len, scn, dcn); +} + + +typedef void (*TransformFunc)( const uchar* src, uchar* dst, const uchar* m, int, int, int ); + +static TransformFunc transformTab[] = +{ + (TransformFunc)transform_8u, (TransformFunc)transform_8s, (TransformFunc)transform_16u, + (TransformFunc)transform_16s, (TransformFunc)transform_32s, (TransformFunc)transform_32f, + (TransformFunc)transform_64f, 0 +}; + +static TransformFunc diagTransformTab[] = +{ + (TransformFunc)diagtransform_8u, (TransformFunc)diagtransform_8s, (TransformFunc)diagtransform_16u, + (TransformFunc)diagtransform_16s, (TransformFunc)diagtransform_32s, (TransformFunc)diagtransform_32f, + (TransformFunc)diagtransform_64f, 0 +}; + +} + +void cv::transform( InputArray _src, OutputArray _dst, InputArray _mtx ) +{ + Mat src = _src.getMat(), m = _mtx.getMat(); + int depth = src.depth(), scn = src.channels(), dcn = m.rows; + CV_Assert( scn == m.cols || scn + 1 == m.cols ); + bool isDiag = false; + + _dst.create( src.size(), CV_MAKETYPE(depth, dcn) ); + Mat dst = _dst.getMat(); + + int mtype = depth == CV_32S || depth == CV_64F ? CV_64F : CV_32F; + AutoBuffer _mbuf; + double* mbuf; + + if( !m.isContinuous() || m.type() != mtype || m.cols != scn + 1 ) + { + _mbuf.allocate(dcn*(scn+1)); + mbuf = (double*)_mbuf; + Mat tmp(dcn, scn+1, mtype, mbuf); + memset(tmp.data, 0, tmp.total()*tmp.elemSize()); + if( m.cols == scn+1 ) + m.convertTo(tmp, mtype); + else + { + Mat tmppart = tmp.colRange(0, m.cols); + m.convertTo(tmppart, mtype); + } + m = tmp; + } + else + mbuf = (double*)m.data; + + if( scn == dcn ) + { + int i, j; + double eps = mtype == CV_32F ? FLT_EPSILON : DBL_EPSILON; + + if( scn == 1 ) + { + double alpha, beta; + if( mtype == CV_32F ) + alpha = m.at(0), beta = m.at(1); + else + alpha = m.at(0), beta = m.at(1); + src.convertTo(dst, dst.type(), alpha, beta); + return; + } + + for( i = 0, isDiag = true; isDiag && i < scn; i++ ) + { + for( j = 0; isDiag && j < scn; j++ ) + { + double v = mtype == CV_32F ? m.at(i, j) : m.at(i, j); + if( i != j && fabs(v) > eps ) + isDiag = false; + } + } + } + + TransformFunc func = isDiag ? diagTransformTab[depth] : transformTab[depth]; + CV_Assert( func != 0 ); + + const Mat* arrays[] = {&src, &dst, 0}; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs); + size_t i, total = it.size; + + for( i = 0; i < it.nplanes; i++, ++it ) + func( ptrs[0], ptrs[1], (uchar*)mbuf, (int)total, scn, dcn ); +} + +/****************************************************************************************\ +* Perspective Transform * +\****************************************************************************************/ + +namespace cv +{ + +template static void +perspectiveTransform_( const T* src, T* dst, const double* m, int len, int scn, int dcn ) +{ + const double eps = FLT_EPSILON; + int i; + + if( scn == 2 && dcn == 2 ) + { + for( i = 0; i < len*2; i += 2 ) + { + T x = src[i], y = src[i + 1]; + double w = x*m[6] + y*m[7] + m[8]; + + if( fabs(w) > eps ) + { + w = 1./w; + dst[i] = (T)((x*m[0] + y*m[1] + m[2])*w); + dst[i+1] = (T)((x*m[3] + y*m[4] + m[5])*w); + } + else + dst[i] = dst[i+1] = (T)0; + } + } + else if( scn == 3 && dcn == 3 ) + { + for( i = 0; i < len*3; i += 3 ) + { + T x = src[i], y = src[i + 1], z = src[i + 2]; + double w = x*m[12] + y*m[13] + z*m[14] + m[15]; + + if( fabs(w) > eps ) + { + w = 1./w; + dst[i] = (T)((x*m[0] + y*m[1] + z*m[2] + m[3]) * w); + dst[i+1] = (T)((x*m[4] + y*m[5] + z*m[6] + m[7]) * w); + dst[i+2] = (T)((x*m[8] + y*m[9] + z*m[10] + m[11]) * w); + } + else + dst[i] = dst[i+1] = dst[i+2] = (T)0; + } + } + else if( scn == 3 && dcn == 2 ) + { + for( i = 0; i < len; i++, src += 3, dst += 2 ) + { + T x = src[0], y = src[1], z = src[2]; + double w = x*m[8] + y*m[9] + z*m[10] + m[11]; + + if( fabs(w) > eps ) + { + w = 1./w; + dst[0] = (T)((x*m[0] + y*m[1] + z*m[2] + m[3])*w); + dst[1] = (T)((x*m[4] + y*m[5] + z*m[6] + m[7])*w); + } + else + dst[0] = dst[1] = (T)0; + } + } + else + { + for( i = 0; i < len; i++, src += scn, dst += dcn ) + { + const double* _m = m + dcn*(scn + 1); + double w = _m[scn]; + int j, k; + for( k = 0; k < scn; k++ ) + w += _m[k]*src[k]; + if( fabs(w) > eps ) + { + _m = m; + for( j = 0; j < dcn; j++, _m += scn + 1 ) + { + double s = _m[scn]; + for( k = 0; k < scn; k++ ) + s += _m[k]*src[k]; + dst[j] = (T)(s*w); + } + } + else + for( j = 0; j < dcn; j++ ) + dst[j] = 0; + } + } +} + + +static void +perspectiveTransform_32f(const float* src, float* dst, const double* m, int len, int scn, int dcn) +{ + perspectiveTransform_(src, dst, m, len, scn, dcn); +} + +static void +perspectiveTransform_64f(const double* src, double* dst, const double* m, int len, int scn, int dcn) +{ + perspectiveTransform_(src, dst, m, len, scn, dcn); +} + +} + +void cv::perspectiveTransform( InputArray _src, OutputArray _dst, InputArray _mtx ) +{ + Mat src = _src.getMat(), m = _mtx.getMat(); + int depth = src.depth(), scn = src.channels(), dcn = m.rows-1; + CV_Assert( scn + 1 == m.cols && (depth == CV_32F || depth == CV_64F)); + + _dst.create( src.size(), CV_MAKETYPE(depth, dcn) ); + Mat dst = _dst.getMat(); + + const int mtype = CV_64F; + AutoBuffer _mbuf; + double* mbuf = _mbuf; + + if( !m.isContinuous() || m.type() != mtype ) + { + _mbuf.allocate((dcn+1)*(scn+1)); + Mat tmp(dcn+1, scn+1, mtype, (double*)_mbuf); + m.convertTo(tmp, mtype); + m = tmp; + } + else + mbuf = (double*)m.data; + + TransformFunc func = depth == CV_32F ? + (TransformFunc)perspectiveTransform_32f : + (TransformFunc)perspectiveTransform_64f; + CV_Assert( func != 0 ); + + const Mat* arrays[] = {&src, &dst, 0}; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs); + size_t i, total = it.size; + + for( i = 0; i < it.nplanes; i++, ++it ) + func( ptrs[0], ptrs[1], (uchar*)mbuf, (int)total, scn, dcn ); +} + +/****************************************************************************************\ +* ScaleAdd * +\****************************************************************************************/ + +namespace cv +{ + +static void scaleAdd_32f(const float* src1, const float* src2, float* dst, + int len, float* _alpha) +{ + float alpha = *_alpha; + int i = 0; +#if CV_SSE2 + if( USE_SSE2 ) + { + __m128 a4 = _mm_set1_ps(alpha); + if( (((size_t)src1|(size_t)src2|(size_t)dst) & 15) == 0 ) + for( ; i <= len - 8; i += 8 ) + { + __m128 x0, x1, y0, y1, t0, t1; + x0 = _mm_load_ps(src1 + i); x1 = _mm_load_ps(src1 + i + 4); + y0 = _mm_load_ps(src2 + i); y1 = _mm_load_ps(src2 + i + 4); + t0 = _mm_add_ps(_mm_mul_ps(x0, a4), y0); + t1 = _mm_add_ps(_mm_mul_ps(x1, a4), y1); + _mm_store_ps(dst + i, t0); + _mm_store_ps(dst + i + 4, t1); + } + else + for( ; i <= len - 8; i += 8 ) + { + __m128 x0, x1, y0, y1, t0, t1; + x0 = _mm_loadu_ps(src1 + i); x1 = _mm_loadu_ps(src1 + i + 4); + y0 = _mm_loadu_ps(src2 + i); y1 = _mm_loadu_ps(src2 + i + 4); + t0 = _mm_add_ps(_mm_mul_ps(x0, a4), y0); + t1 = _mm_add_ps(_mm_mul_ps(x1, a4), y1); + _mm_storeu_ps(dst + i, t0); + _mm_storeu_ps(dst + i + 4, t1); + } + } + else +#endif + //vz why do we need unroll here? + for( ; i <= len - 4; i += 4 ) + { + float t0, t1; + t0 = src1[i]*alpha + src2[i]; + t1 = src1[i+1]*alpha + src2[i+1]; + dst[i] = t0; dst[i+1] = t1; + t0 = src1[i+2]*alpha + src2[i+2]; + t1 = src1[i+3]*alpha + src2[i+3]; + dst[i+2] = t0; dst[i+3] = t1; + } + for(; i < len; i++ ) + dst[i] = src1[i]*alpha + src2[i]; +} + + +static void scaleAdd_64f(const double* src1, const double* src2, double* dst, + int len, double* _alpha) +{ + double alpha = *_alpha; + int i = 0; +#if CV_SSE2 + if( USE_SSE2 && (((size_t)src1|(size_t)src2|(size_t)dst) & 15) == 0 ) + { + __m128d a2 = _mm_set1_pd(alpha); + for( ; i <= len - 4; i += 4 ) + { + __m128d x0, x1, y0, y1, t0, t1; + x0 = _mm_load_pd(src1 + i); x1 = _mm_load_pd(src1 + i + 2); + y0 = _mm_load_pd(src2 + i); y1 = _mm_load_pd(src2 + i + 2); + t0 = _mm_add_pd(_mm_mul_pd(x0, a2), y0); + t1 = _mm_add_pd(_mm_mul_pd(x1, a2), y1); + _mm_store_pd(dst + i, t0); + _mm_store_pd(dst + i + 2, t1); + } + } + else +#endif + //vz why do we need unroll here? + for( ; i <= len - 4; i += 4 ) + { + double t0, t1; + t0 = src1[i]*alpha + src2[i]; + t1 = src1[i+1]*alpha + src2[i+1]; + dst[i] = t0; dst[i+1] = t1; + t0 = src1[i+2]*alpha + src2[i+2]; + t1 = src1[i+3]*alpha + src2[i+3]; + dst[i+2] = t0; dst[i+3] = t1; + } + for(; i < len; i++ ) + dst[i] = src1[i]*alpha + src2[i]; +} + +typedef void (*ScaleAddFunc)(const uchar* src1, const uchar* src2, uchar* dst, int len, const void* alpha); + +} + +void cv::scaleAdd( InputArray _src1, double alpha, InputArray _src2, OutputArray _dst ) +{ + Mat src1 = _src1.getMat(), src2 = _src2.getMat(); + int depth = src1.depth(), cn = src1.channels(); + + CV_Assert( src1.type() == src2.type() ); + if( depth < CV_32F ) + { + addWeighted(_src1, alpha, _src2, 1, 0, _dst, depth); + return; + } + + _dst.create(src1.dims, src1.size, src1.type()); + Mat dst = _dst.getMat(); + + float falpha = (float)alpha; + void* palpha = depth == CV_32F ? (void*)&falpha : (void*)α + + ScaleAddFunc func = depth == CV_32F ? (ScaleAddFunc)scaleAdd_32f : (ScaleAddFunc)scaleAdd_64f; + + if( src1.isContinuous() && src2.isContinuous() && dst.isContinuous() ) + { + size_t len = src1.total()*cn; + func(src1.data, src2.data, dst.data, (int)len, palpha); + return; + } + + const Mat* arrays[] = {&src1, &src2, &dst, 0}; + uchar* ptrs[3]; + NAryMatIterator it(arrays, ptrs); + size_t i, len = it.size*cn; + + for( i = 0; i < it.nplanes; i++, ++it ) + func( ptrs[0], ptrs[1], ptrs[2], (int)len, palpha ); +} + +/****************************************************************************************\ +* Covariation Matrix * +\****************************************************************************************/ + +void cv::calcCovarMatrix( const Mat* data, int nsamples, Mat& covar, Mat& _mean, int flags, int ctype ) +{ + CV_Assert( data && nsamples > 0 ); + Size size = data[0].size(); + int sz = size.width * size.height, esz = (int)data[0].elemSize(); + int type = data[0].type(); + Mat mean; + ctype = std::max(std::max(CV_MAT_DEPTH(ctype >= 0 ? ctype : type), _mean.depth()), CV_32F); + + if( (flags & CV_COVAR_USE_AVG) != 0 ) + { + CV_Assert( _mean.size() == size ); + if( _mean.isContinuous() && _mean.type() == ctype ) + mean = _mean.reshape(1, 1); + else + { + _mean.convertTo(mean, ctype); + mean = mean.reshape(1, 1); + } + } + + Mat _data(nsamples, sz, type); + + for( int i = 0; i < nsamples; i++ ) + { + CV_Assert( data[i].size() == size && data[i].type() == type ); + if( data[i].isContinuous() ) + memcpy( _data.ptr(i), data[i].data, sz*esz ); + else + { + Mat dataRow(size.height, size.width, type, _data.ptr(i)); + data[i].copyTo(dataRow); + } + } + + calcCovarMatrix( _data, covar, mean, (flags & ~(CV_COVAR_ROWS|CV_COVAR_COLS)) | CV_COVAR_ROWS, ctype ); + if( (flags & CV_COVAR_USE_AVG) == 0 ) + _mean = mean.reshape(1, size.height); +} + +void cv::calcCovarMatrix( InputArray _src, OutputArray _covar, InputOutputArray _mean, int flags, int ctype ) +{ + if(_src.kind() == _InputArray::STD_VECTOR_MAT) + { + std::vector src; + _src.getMatVector(src); + + CV_Assert( src.size() > 0 ); + + Size size = src[0].size(); + int type = src[0].type(); + + ctype = std::max(std::max(CV_MAT_DEPTH(ctype >= 0 ? ctype : type), _mean.depth()), CV_32F); + + Mat _data(static_cast(src.size()), size.area(), type); + + int i = 0; + for(vector::iterator each = src.begin(); each != src.end(); each++, i++ ) + { + CV_Assert( (*each).size() == size && (*each).type() == type ); + Mat dataRow(size.height, size.width, type, _data.ptr(i)); + (*each).copyTo(dataRow); + } + + Mat mean; + if( (flags & CV_COVAR_USE_AVG) != 0 ) + { + CV_Assert( _mean.size() == size ); + + if( mean.type() != ctype ) + { + mean = _mean.getMat(); + _mean.create(mean.size(), ctype); + Mat tmp = _mean.getMat(); + mean.convertTo(tmp, ctype); + mean = tmp; + } + + mean = _mean.getMat().reshape(1, 1); + } + + calcCovarMatrix( _data, _covar, mean, (flags & ~(CV_COVAR_ROWS|CV_COVAR_COLS)) | CV_COVAR_ROWS, ctype ); + + if( (flags & CV_COVAR_USE_AVG) == 0 ) + { + mean = mean.reshape(1, size.height); + mean.copyTo(_mean); + } + return; + } + + Mat data = _src.getMat(), mean; + CV_Assert( ((flags & CV_COVAR_ROWS) != 0) ^ ((flags & CV_COVAR_COLS) != 0) ); + bool takeRows = (flags & CV_COVAR_ROWS) != 0; + int type = data.type(); + int nsamples = takeRows ? data.rows : data.cols; + CV_Assert( nsamples > 0 ); + Size size = takeRows ? Size(data.cols, 1) : Size(1, data.rows); + + if( (flags & CV_COVAR_USE_AVG) != 0 ) + { + mean = _mean.getMat(); + ctype = std::max(std::max(CV_MAT_DEPTH(ctype >= 0 ? ctype : type), mean.depth()), CV_32F); + CV_Assert( mean.size() == size ); + if( mean.type() != ctype ) + { + _mean.create(mean.size(), ctype); + Mat tmp = _mean.getMat(); + mean.convertTo(tmp, ctype); + mean = tmp; + } + } + else + { + ctype = std::max(CV_MAT_DEPTH(ctype >= 0 ? ctype : type), CV_32F); + reduce( _src, _mean, takeRows ? 0 : 1, CV_REDUCE_AVG, ctype ); + mean = _mean.getMat(); + } + + mulTransposed( data, _covar, ((flags & CV_COVAR_NORMAL) == 0) ^ takeRows, + mean, (flags & CV_COVAR_SCALE) != 0 ? 1./nsamples : 1, ctype ); +} + +/****************************************************************************************\ +* Mahalanobis * +\****************************************************************************************/ + +double cv::Mahalanobis( InputArray _v1, InputArray _v2, InputArray _icovar ) +{ + Mat v1 = _v1.getMat(), v2 = _v2.getMat(), icovar = _icovar.getMat(); + int type = v1.type(), depth = v1.depth(); + Size sz = v1.size(); + int i, j, len = sz.width*sz.height*v1.channels(); + AutoBuffer buf(len); + double result = 0; + + CV_Assert( type == v2.type() && type == icovar.type() && + sz == v2.size() && len == icovar.rows && len == icovar.cols ); + + sz.width *= v1.channels(); + if( v1.isContinuous() && v2.isContinuous() ) + { + sz.width *= sz.height; + sz.height = 1; + } + + if( depth == CV_32F ) + { + const float* src1 = (const float*)v1.data; + const float* src2 = (const float*)v2.data; + size_t step1 = v1.step/sizeof(src1[0]); + size_t step2 = v2.step/sizeof(src2[0]); + double* diff = buf; + const float* mat = (const float*)icovar.data; + size_t matstep = icovar.step/sizeof(mat[0]); + + for( ; sz.height--; src1 += step1, src2 += step2, diff += sz.width ) + { + for( i = 0; i < sz.width; i++ ) + diff[i] = src1[i] - src2[i]; + } + + diff = buf; + for( i = 0; i < len; i++, mat += matstep ) + { + double row_sum = 0; + j = 0; + #if CV_ENABLE_UNROLLED + for(; j <= len - 4; j += 4 ) + row_sum += diff[j]*mat[j] + diff[j+1]*mat[j+1] + + diff[j+2]*mat[j+2] + diff[j+3]*mat[j+3]; + #endif + for( ; j < len; j++ ) + row_sum += diff[j]*mat[j]; + result += row_sum * diff[i]; + } + } + else if( depth == CV_64F ) + { + const double* src1 = (const double*)v1.data; + const double* src2 = (const double*)v2.data; + size_t step1 = v1.step/sizeof(src1[0]); + size_t step2 = v2.step/sizeof(src2[0]); + double* diff = buf; + const double* mat = (const double*)icovar.data; + size_t matstep = icovar.step/sizeof(mat[0]); + + for( ; sz.height--; src1 += step1, src2 += step2, diff += sz.width ) + { + for( i = 0; i < sz.width; i++ ) + diff[i] = src1[i] - src2[i]; + } + + diff = buf; + for( i = 0; i < len; i++, mat += matstep ) + { + double row_sum = 0; + j = 0; + #if CV_ENABLE_UNROLLED + for(; j <= len - 4; j += 4 ) + row_sum += diff[j]*mat[j] + diff[j+1]*mat[j+1] + + diff[j+2]*mat[j+2] + diff[j+3]*mat[j+3]; + #endif + for( ; j < len; j++ ) + row_sum += diff[j]*mat[j]; + result += row_sum * diff[i]; + } + } + else + CV_Error( CV_StsUnsupportedFormat, "" ); + + return std::sqrt(result); +} + +double cv::Mahalonobis( InputArray _v1, InputArray _v2, InputArray _icovar ) +{ + return Mahalanobis(_v1, _v2, _icovar); +} + +/****************************************************************************************\ +* MulTransposed * +\****************************************************************************************/ + +namespace cv +{ + +template static void +MulTransposedR( const Mat& srcmat, Mat& dstmat, const Mat& deltamat, double scale ) +{ + int i, j, k; + const sT* src = (const sT*)srcmat.data; + dT* dst = (dT*)dstmat.data; + const dT* delta = (const dT*)deltamat.data; + size_t srcstep = srcmat.step/sizeof(src[0]); + size_t dststep = dstmat.step/sizeof(dst[0]); + size_t deltastep = deltamat.rows > 1 ? deltamat.step/sizeof(delta[0]) : 0; + int delta_cols = deltamat.cols; + Size size = srcmat.size(); + dT* tdst = dst; + dT* col_buf = 0; + dT* delta_buf = 0; + int buf_size = size.height*sizeof(dT); + AutoBuffer buf; + + if( delta && delta_cols < size.width ) + { + assert( delta_cols == 1 ); + buf_size *= 5; + } + buf.allocate(buf_size); + col_buf = (dT*)(uchar*)buf; + + if( delta && delta_cols < size.width ) + { + delta_buf = col_buf + size.height; + for( i = 0; i < size.height; i++ ) + delta_buf[i*4] = delta_buf[i*4+1] = + delta_buf[i*4+2] = delta_buf[i*4+3] = delta[i*deltastep]; + delta = delta_buf; + deltastep = deltastep ? 4 : 0; + } + + if( !delta ) + for( i = 0; i < size.width; i++, tdst += dststep ) + { + for( k = 0; k < size.height; k++ ) + col_buf[k] = src[k*srcstep+i]; + + for( j = i; j <= size.width - 4; j += 4 ) + { + double s0 = 0, s1 = 0, s2 = 0, s3 = 0; + const sT *tsrc = src + j; + + for( k = 0; k < size.height; k++, tsrc += srcstep ) + { + double a = col_buf[k]; + s0 += a * tsrc[0]; + s1 += a * tsrc[1]; + s2 += a * tsrc[2]; + s3 += a * tsrc[3]; + } + + tdst[j] = (dT)(s0*scale); + tdst[j+1] = (dT)(s1*scale); + tdst[j+2] = (dT)(s2*scale); + tdst[j+3] = (dT)(s3*scale); + } + + for( ; j < size.width; j++ ) + { + double s0 = 0; + const sT *tsrc = src + j; + + for( k = 0; k < size.height; k++, tsrc += srcstep ) + s0 += (double)col_buf[k] * tsrc[0]; + + tdst[j] = (dT)(s0*scale); + } + } + else + for( i = 0; i < size.width; i++, tdst += dststep ) + { + if( !delta_buf ) + for( k = 0; k < size.height; k++ ) + col_buf[k] = src[k*srcstep+i] - delta[k*deltastep+i]; + else + for( k = 0; k < size.height; k++ ) + col_buf[k] = src[k*srcstep+i] - delta_buf[k*deltastep]; + + for( j = i; j <= size.width - 4; j += 4 ) + { + double s0 = 0, s1 = 0, s2 = 0, s3 = 0; + const sT *tsrc = src + j; + const dT *d = delta_buf ? delta_buf : delta + j; + + for( k = 0; k < size.height; k++, tsrc+=srcstep, d+=deltastep ) + { + double a = col_buf[k]; + s0 += a * (tsrc[0] - d[0]); + s1 += a * (tsrc[1] - d[1]); + s2 += a * (tsrc[2] - d[2]); + s3 += a * (tsrc[3] - d[3]); + } + + tdst[j] = (dT)(s0*scale); + tdst[j+1] = (dT)(s1*scale); + tdst[j+2] = (dT)(s2*scale); + tdst[j+3] = (dT)(s3*scale); + } + + for( ; j < size.width; j++ ) + { + double s0 = 0; + const sT *tsrc = src + j; + const dT *d = delta_buf ? delta_buf : delta + j; + + for( k = 0; k < size.height; k++, tsrc+=srcstep, d+=deltastep ) + s0 += (double)col_buf[k] * (tsrc[0] - d[0]); + + tdst[j] = (dT)(s0*scale); + } + } +} + + +template static void +MulTransposedL( const Mat& srcmat, Mat& dstmat, const Mat& deltamat, double scale ) +{ + int i, j, k; + const sT* src = (const sT*)srcmat.data; + dT* dst = (dT*)dstmat.data; + const dT* delta = (const dT*)deltamat.data; + size_t srcstep = srcmat.step/sizeof(src[0]); + size_t dststep = dstmat.step/sizeof(dst[0]); + size_t deltastep = deltamat.rows > 1 ? deltamat.step/sizeof(delta[0]) : 0; + int delta_cols = deltamat.cols; + Size size = srcmat.size(); + dT* tdst = dst; + + if( !delta ) + for( i = 0; i < size.height; i++, tdst += dststep ) + for( j = i; j < size.height; j++ ) + { + double s = 0; + const sT *tsrc1 = src + i*srcstep; + const sT *tsrc2 = src + j*srcstep; + + for( k = 0; k <= size.width - 4; k += 4 ) + s += (double)tsrc1[k]*tsrc2[k] + (double)tsrc1[k+1]*tsrc2[k+1] + + (double)tsrc1[k+2]*tsrc2[k+2] + (double)tsrc1[k+3]*tsrc2[k+3]; + for( ; k < size.width; k++ ) + s += (double)tsrc1[k] * tsrc2[k]; + tdst[j] = (dT)(s*scale); + } + else + { + dT delta_buf[4]; + int delta_shift = delta_cols == size.width ? 4 : 0; + AutoBuffer buf(size.width*sizeof(dT)); + dT* row_buf = (dT*)(uchar*)buf; + + for( i = 0; i < size.height; i++, tdst += dststep ) + { + const sT *tsrc1 = src + i*srcstep; + const dT *tdelta1 = delta + i*deltastep; + + if( delta_cols < size.width ) + for( k = 0; k < size.width; k++ ) + row_buf[k] = tsrc1[k] - tdelta1[0]; + else + for( k = 0; k < size.width; k++ ) + row_buf[k] = tsrc1[k] - tdelta1[k]; + + for( j = i; j < size.height; j++ ) + { + double s = 0; + const sT *tsrc2 = src + j*srcstep; + const dT *tdelta2 = delta + j*deltastep; + if( delta_cols < size.width ) + { + delta_buf[0] = delta_buf[1] = + delta_buf[2] = delta_buf[3] = tdelta2[0]; + tdelta2 = delta_buf; + } + for( k = 0; k <= size.width-4; k += 4, tdelta2 += delta_shift ) + s += (double)row_buf[k]*(tsrc2[k] - tdelta2[0]) + + (double)row_buf[k+1]*(tsrc2[k+1] - tdelta2[1]) + + (double)row_buf[k+2]*(tsrc2[k+2] - tdelta2[2]) + + (double)row_buf[k+3]*(tsrc2[k+3] - tdelta2[3]); + for( ; k < size.width; k++, tdelta2++ ) + s += (double)row_buf[k]*(tsrc2[k] - tdelta2[0]); + tdst[j] = (dT)(s*scale); + } + } + } +} + +typedef void (*MulTransposedFunc)(const Mat& src, Mat& dst, const Mat& delta, double scale); + +} + +void cv::mulTransposed( InputArray _src, OutputArray _dst, bool ata, + InputArray _delta, double scale, int dtype ) +{ + Mat src = _src.getMat(), delta = _delta.getMat(); + const int gemm_level = 100; // boundary above which GEMM is faster. + int stype = src.type(); + dtype = std::max(std::max(CV_MAT_DEPTH(dtype >= 0 ? dtype : stype), delta.depth()), CV_32F); + CV_Assert( src.channels() == 1 ); + + if( delta.data ) + { + CV_Assert( delta.channels() == 1 && + (delta.rows == src.rows || delta.rows == 1) && + (delta.cols == src.cols || delta.cols == 1)); + if( delta.type() != dtype ) + delta.convertTo(delta, dtype); + } + + int dsize = ata ? src.cols : src.rows; + _dst.create( dsize, dsize, dtype ); + Mat dst = _dst.getMat(); + + if( src.data == dst.data || (stype == dtype && + (dst.cols >= gemm_level && dst.rows >= gemm_level && + src.cols >= gemm_level && src.rows >= gemm_level))) + { + Mat src2; + const Mat* tsrc = &src; + if( delta.data ) + { + if( delta.size() == src.size() ) + subtract( src, delta, src2 ); + else + { + repeat(delta, src.rows/delta.rows, src.cols/delta.cols, src2); + subtract( src, src2, src2 ); + } + tsrc = &src2; + } + gemm( *tsrc, *tsrc, scale, Mat(), 0, dst, ata ? GEMM_1_T : GEMM_2_T ); + } + else + { + MulTransposedFunc func = 0; + if(stype == CV_8U && dtype == CV_32F) + { + if(ata) + func = MulTransposedR; + else + func = MulTransposedL; + } + else if(stype == CV_8U && dtype == CV_64F) + { + if(ata) + func = MulTransposedR; + else + func = MulTransposedL; + } + else if(stype == CV_16U && dtype == CV_32F) + { + if(ata) + func = MulTransposedR; + else + func = MulTransposedL; + } + else if(stype == CV_16U && dtype == CV_64F) + { + if(ata) + func = MulTransposedR; + else + func = MulTransposedL; + } + else if(stype == CV_16S && dtype == CV_32F) + { + if(ata) + func = MulTransposedR; + else + func = MulTransposedL; + } + else if(stype == CV_16S && dtype == CV_64F) + { + if(ata) + func = MulTransposedR; + else + func = MulTransposedL; + } + else if(stype == CV_32F && dtype == CV_32F) + { + if(ata) + func = MulTransposedR; + else + func = MulTransposedL; + } + else if(stype == CV_32F && dtype == CV_64F) + { + if(ata) + func = MulTransposedR; + else + func = MulTransposedL; + } + else if(stype == CV_64F && dtype == CV_64F) + { + if(ata) + func = MulTransposedR; + else + func = MulTransposedL; + } + if( !func ) + CV_Error( CV_StsUnsupportedFormat, "" ); + + func( src, dst, delta, scale ); + completeSymm( dst, false ); + } +} + +/****************************************************************************************\ +* Dot Product * +\****************************************************************************************/ + +namespace cv +{ + +template double +dotProd_(const T* src1, const T* src2, int len) +{ + int i = 0; + double result = 0; + #if CV_ENABLE_UNROLLED + for( ; i <= len - 4; i += 4 ) + result += (double)src1[i]*src2[i] + (double)src1[i+1]*src2[i+1] + + (double)src1[i+2]*src2[i+2] + (double)src1[i+3]*src2[i+3]; + #endif + for( ; i < len; i++ ) + result += (double)src1[i]*src2[i]; + + return result; +} + + +static double dotProd_8u(const uchar* src1, const uchar* src2, int len) +{ + double r = 0; +#if ARITHM_USE_IPP + ippiDotProd_8u64f_C1R(src1, (int)(len*sizeof(src1[0])), + src2, (int)(len*sizeof(src2[0])), + ippiSize(len, 1), &r); + return r; +#else + int i = 0; + +#if CV_SSE2 + if( USE_SSE2 ) + { + int j, len0 = len & -4, blockSize0 = (1 << 13), blockSize; + __m128i z = _mm_setzero_si128(); + while( i < len0 ) + { + blockSize = std::min(len0 - i, blockSize0); + __m128i s = _mm_setzero_si128(); + j = 0; + for( ; j <= blockSize - 16; j += 16 ) + { + __m128i b0 = _mm_loadu_si128((const __m128i*)(src1 + j)); + __m128i b1 = _mm_loadu_si128((const __m128i*)(src2 + j)); + __m128i s0, s1, s2, s3; + s0 = _mm_unpacklo_epi8(b0, z); + s2 = _mm_unpackhi_epi8(b0, z); + s1 = _mm_unpacklo_epi8(b1, z); + s3 = _mm_unpackhi_epi8(b1, z); + s0 = _mm_madd_epi16(s0, s1); + s2 = _mm_madd_epi16(s2, s3); + s = _mm_add_epi32(s, s0); + s = _mm_add_epi32(s, s2); + } + + for( ; j < blockSize; j += 4 ) + { + __m128i s0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(const int*)(src1 + j)), z); + __m128i s1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(const int*)(src2 + j)), z); + s0 = _mm_madd_epi16(s0, s1); + s = _mm_add_epi32(s, s0); + } + CV_DECL_ALIGNED(16) int buf[4]; + _mm_store_si128((__m128i*)buf, s); + r += buf[0] + buf[1] + buf[2] + buf[3]; + + src1 += blockSize; + src2 += blockSize; + i += blockSize; + } + } +#endif + return r + dotProd_(src1, src2, len - i); +#endif +} + + +static double dotProd_8s(const schar* src1, const schar* src2, int len) +{ + return dotProd_(src1, src2, len); +} + +static double dotProd_16u(const ushort* src1, const ushort* src2, int len) +{ + double r = 0; + IF_IPP(ippiDotProd_16u64f_C1R(src1, (int)(len*sizeof(src1[0])), + src2, (int)(len*sizeof(src2[0])), + ippiSize(len, 1), &r), + r = dotProd_(src1, src2, len)); + return r; +} + +static double dotProd_16s(const short* src1, const short* src2, int len) +{ + double r = 0; + IF_IPP(ippiDotProd_16s64f_C1R(src1, (int)(len*sizeof(src1[0])), + src2, (int)(len*sizeof(src2[0])), + ippiSize(len, 1), &r), + r = dotProd_(src1, src2, len)); + return r; +} + +static double dotProd_32s(const int* src1, const int* src2, int len) +{ + double r = 0; + IF_IPP(ippiDotProd_32s64f_C1R(src1, (int)(len*sizeof(src1[0])), + src2, (int)(len*sizeof(src2[0])), + ippiSize(len, 1), &r), + r = dotProd_(src1, src2, len)); + return r; +} + +static double dotProd_32f(const float* src1, const float* src2, int len) +{ + double r = 0; + IF_IPP(ippsDotProd_32f64f(src1, src2, len, &r), + r = dotProd_(src1, src2, len)); + return r; +} + +static double dotProd_64f(const double* src1, const double* src2, int len) +{ + double r = 0; + IF_IPP(ippsDotProd_64f(src1, src2, len, &r), + r = dotProd_(src1, src2, len)); + return r; +} + + +typedef double (*DotProdFunc)(const uchar* src1, const uchar* src2, int len); + +static DotProdFunc dotProdTab[] = +{ + (DotProdFunc)GET_OPTIMIZED(dotProd_8u), (DotProdFunc)GET_OPTIMIZED(dotProd_8s), + (DotProdFunc)dotProd_16u, (DotProdFunc)dotProd_16s, + (DotProdFunc)dotProd_32s, (DotProdFunc)GET_OPTIMIZED(dotProd_32f), + (DotProdFunc)dotProd_64f, 0 +}; + +double Mat::dot(InputArray _mat) const +{ + Mat mat = _mat.getMat(); + int cn = channels(); + DotProdFunc func = dotProdTab[depth()]; + CV_Assert( mat.type() == type() && mat.size == size && func != 0 ); + + if( isContinuous() && mat.isContinuous() ) + { + size_t len = total()*cn; + if( len == (size_t)(int)len ) + return func(data, mat.data, (int)len); + } + + const Mat* arrays[] = {this, &mat, 0}; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs); + int len = (int)(it.size*cn); + double r = 0; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + r += func( ptrs[0], ptrs[1], len ); + + return r; +} + +/****************************************************************************************\ +* PCA * +\****************************************************************************************/ + +PCA::PCA() {} + +PCA::PCA(InputArray data, InputArray _mean, int flags, int maxComponents) +{ + operator()(data, _mean, flags, maxComponents); +} + +PCA& PCA::operator()(InputArray _data, InputArray __mean, int flags, int maxComponents) +{ + Mat data = _data.getMat(), _mean = __mean.getMat(); + int covar_flags = CV_COVAR_SCALE; + int i, len, in_count; + Size mean_sz; + + CV_Assert( data.channels() == 1 ); + if( flags & CV_PCA_DATA_AS_COL ) + { + len = data.rows; + in_count = data.cols; + covar_flags |= CV_COVAR_COLS; + mean_sz = Size(1, len); + } + else + { + len = data.cols; + in_count = data.rows; + covar_flags |= CV_COVAR_ROWS; + mean_sz = Size(len, 1); + } + + int count = std::min(len, in_count), out_count = count; + if( maxComponents > 0 ) + out_count = std::min(count, maxComponents); + + // "scrambled" way to compute PCA (when cols(A)>rows(A)): + // B = A'A; B*x=b*x; C = AA'; C*y=c*y -> AA'*y=c*y -> A'A*(A'*y)=c*(A'*y) -> c = b, x=A'*y + if( len <= in_count ) + covar_flags |= CV_COVAR_NORMAL; + + int ctype = std::max(CV_32F, data.depth()); + mean.create( mean_sz, ctype ); + + Mat covar( count, count, ctype ); + + if( _mean.data ) + { + CV_Assert( _mean.size() == mean_sz ); + _mean.convertTo(mean, ctype); + } + + calcCovarMatrix( data, covar, mean, covar_flags, ctype ); + eigen( covar, eigenvalues, eigenvectors ); + + if( !(covar_flags & CV_COVAR_NORMAL) ) + { + // CV_PCA_DATA_AS_ROW: cols(A)>rows(A). x=A'*y -> x'=y'*A + // CV_PCA_DATA_AS_COL: rows(A)>cols(A). x=A''*y -> x'=y'*A' + Mat tmp_data, tmp_mean = repeat(mean, data.rows/mean.rows, data.cols/mean.cols); + if( data.type() != ctype || tmp_mean.data == mean.data ) + { + data.convertTo( tmp_data, ctype ); + subtract( tmp_data, tmp_mean, tmp_data ); + } + else + { + subtract( data, tmp_mean, tmp_mean ); + tmp_data = tmp_mean; + } + + Mat evects1(count, len, ctype); + gemm( eigenvectors, tmp_data, 1, Mat(), 0, evects1, + (flags & CV_PCA_DATA_AS_COL) ? CV_GEMM_B_T : 0); + eigenvectors = evects1; + + // normalize eigenvectors + for( i = 0; i < out_count; i++ ) + { + Mat vec = eigenvectors.row(i); + normalize(vec, vec); + } + } + + if( count > out_count ) + { + // use clone() to physically copy the data and thus deallocate the original matrices + eigenvalues = eigenvalues.rowRange(0,out_count).clone(); + eigenvectors = eigenvectors.rowRange(0,out_count).clone(); + } + return *this; +} + + +void PCA::project(InputArray _data, OutputArray result) const +{ + Mat data = _data.getMat(); + CV_Assert( mean.data && eigenvectors.data && + ((mean.rows == 1 && mean.cols == data.cols) || (mean.cols == 1 && mean.rows == data.rows))); + Mat tmp_data, tmp_mean = repeat(mean, data.rows/mean.rows, data.cols/mean.cols); + int ctype = mean.type(); + if( data.type() != ctype || tmp_mean.data == mean.data ) + { + data.convertTo( tmp_data, ctype ); + subtract( tmp_data, tmp_mean, tmp_data ); + } + else + { + subtract( data, tmp_mean, tmp_mean ); + tmp_data = tmp_mean; + } + if( mean.rows == 1 ) + gemm( tmp_data, eigenvectors, 1, Mat(), 0, result, GEMM_2_T ); + else + gemm( eigenvectors, tmp_data, 1, Mat(), 0, result, 0 ); +} + +Mat PCA::project(InputArray data) const +{ + Mat result; + project(data, result); + return result; +} + +void PCA::backProject(InputArray _data, OutputArray result) const +{ + Mat data = _data.getMat(); + CV_Assert( mean.data && eigenvectors.data && + ((mean.rows == 1 && eigenvectors.rows == data.cols) || + (mean.cols == 1 && eigenvectors.rows == data.rows))); + + Mat tmp_data, tmp_mean; + data.convertTo(tmp_data, mean.type()); + if( mean.rows == 1 ) + { + tmp_mean = repeat(mean, data.rows, 1); + gemm( tmp_data, eigenvectors, 1, tmp_mean, 1, result, 0 ); + } + else + { + tmp_mean = repeat(mean, 1, data.cols); + gemm( eigenvectors, tmp_data, 1, tmp_mean, 1, result, GEMM_1_T ); + } +} + +Mat PCA::backProject(InputArray data) const +{ + Mat result; + backProject(data, result); + return result; +} + +} + +void cv::PCACompute(InputArray data, InputOutputArray mean, + OutputArray eigenvectors, int maxComponents) +{ + PCA pca; + pca(data, mean, 0, maxComponents); + pca.mean.copyTo(mean); + pca.eigenvectors.copyTo(eigenvectors); +} + +void cv::PCAProject(InputArray data, InputArray mean, + InputArray eigenvectors, OutputArray result) +{ + PCA pca; + pca.mean = mean.getMat(); + pca.eigenvectors = eigenvectors.getMat(); + pca.project(data, result); +} + +void cv::PCABackProject(InputArray data, InputArray mean, + InputArray eigenvectors, OutputArray result) +{ + PCA pca; + pca.mean = mean.getMat(); + pca.eigenvectors = eigenvectors.getMat(); + pca.backProject(data, result); +} + + +/****************************************************************************************\ +* Earlier API * +\****************************************************************************************/ + +CV_IMPL void cvGEMM( const CvArr* Aarr, const CvArr* Barr, double alpha, + const CvArr* Carr, double beta, CvArr* Darr, int flags ) +{ + cv::Mat A = cv::cvarrToMat(Aarr), B = cv::cvarrToMat(Barr); + cv::Mat C, D = cv::cvarrToMat(Darr); + + if( Carr ) + C = cv::cvarrToMat(Carr); + + CV_Assert( (D.rows == ((flags & CV_GEMM_A_T) == 0 ? A.rows : A.cols)) && + (D.cols == ((flags & CV_GEMM_B_T) == 0 ? B.cols : B.rows)) && + D.type() == A.type() ); + + gemm( A, B, alpha, C, beta, D, flags ); +} + + +CV_IMPL void +cvTransform( const CvArr* srcarr, CvArr* dstarr, + const CvMat* transmat, const CvMat* shiftvec ) +{ + cv::Mat m = cv::cvarrToMat(transmat), src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + if( shiftvec ) + { + cv::Mat v = cv::cvarrToMat(shiftvec).reshape(1,m.rows), + _m(m.rows, m.cols + 1, m.type()), m1 = _m.colRange(0,m.cols), v1 = _m.col(m.cols); + m.convertTo(m1, m1.type()); + v.convertTo(v1, v1.type()); + m = _m; + } + + CV_Assert( dst.depth() == src.depth() && dst.channels() == m.rows ); + cv::transform( src, dst, m ); +} + + +CV_IMPL void +cvPerspectiveTransform( const CvArr* srcarr, CvArr* dstarr, const CvMat* mat ) +{ + cv::Mat m = cv::cvarrToMat(mat), src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + CV_Assert( dst.type() == src.type() && dst.channels() == m.rows-1 ); + cv::perspectiveTransform( src, dst, m ); +} + + +CV_IMPL void cvScaleAdd( const CvArr* srcarr1, CvScalar scale, + const CvArr* srcarr2, CvArr* dstarr ) +{ + cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr); + + CV_Assert( src1.size == dst.size && src1.type() == dst.type() ); + cv::scaleAdd( src1, scale.val[0], cv::cvarrToMat(srcarr2), dst ); +} + + +CV_IMPL void +cvCalcCovarMatrix( const CvArr** vecarr, int count, + CvArr* covarr, CvArr* avgarr, int flags ) +{ + cv::Mat cov0 = cv::cvarrToMat(covarr), cov = cov0, mean0, mean; + CV_Assert( vecarr != 0 && count >= 1 ); + + if( avgarr ) + mean = mean0 = cv::cvarrToMat(avgarr); + + if( (flags & CV_COVAR_COLS) != 0 || (flags & CV_COVAR_ROWS) != 0 ) + { + + cv::Mat data = cv::cvarrToMat(vecarr[0]); + cv::calcCovarMatrix( data, cov, mean, flags, cov.type() ); + } + else + { + std::vector data(count); + for( int i = 0; i < count; i++ ) + data[i] = cv::cvarrToMat(vecarr[i]); + cv::calcCovarMatrix( &data[0], count, cov, mean, flags, cov.type() ); + } + + if( mean.data != mean0.data && mean0.data ) + mean.convertTo(mean0, mean0.type()); + + if( cov.data != cov0.data ) + cov.convertTo(cov0, cov0.type()); +} + + +CV_IMPL double +cvMahalanobis( const CvArr* srcAarr, const CvArr* srcBarr, const CvArr* matarr ) +{ + return cv::Mahalanobis(cv::cvarrToMat(srcAarr), + cv::cvarrToMat(srcBarr), cv::cvarrToMat(matarr)); +} + +CV_IMPL void +cvMulTransposed( const CvArr* srcarr, CvArr* dstarr, + int order, const CvArr* deltaarr, double scale ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst0 = cv::cvarrToMat(dstarr), dst = dst0, delta; + if( deltaarr ) + delta = cv::cvarrToMat(deltaarr); + cv::mulTransposed( src, dst, order != 0, delta, scale, dst.type()); + if( dst.data != dst0.data ) + dst.convertTo(dst0, dst0.type()); +} + +CV_IMPL double cvDotProduct( const CvArr* srcAarr, const CvArr* srcBarr ) +{ + return cv::cvarrToMat(srcAarr).dot(cv::cvarrToMat(srcBarr)); +} + + +CV_IMPL void +cvCalcPCA( const CvArr* data_arr, CvArr* avg_arr, CvArr* eigenvals, CvArr* eigenvects, int flags ) +{ + cv::Mat data = cv::cvarrToMat(data_arr), mean0 = cv::cvarrToMat(avg_arr); + cv::Mat evals0 = cv::cvarrToMat(eigenvals), evects0 = cv::cvarrToMat(eigenvects); + cv::Mat mean = mean0, evals = evals0, evects = evects0; + + cv::PCA pca; + pca.mean = mean; + pca.eigenvalues = evals; + pca.eigenvectors = evects; + + pca(data, (flags & CV_PCA_USE_AVG) ? mean : cv::Mat(), + flags, evals.data ? evals.rows + evals.cols - 1 : 0); + + if( pca.mean.size() == mean.size() ) + pca.mean.convertTo( mean, mean.type() ); + else + { + cv::Mat temp; pca.mean.convertTo( temp, mean.type() ); + transpose( temp, mean ); + } + + evals = pca.eigenvalues; + evects = pca.eigenvectors; + int ecount0 = evals0.cols + evals0.rows - 1; + int ecount = evals.cols + evals.rows - 1; + + CV_Assert( (evals0.cols == 1 || evals0.rows == 1) && + ecount0 <= ecount && + evects0.cols == evects.cols && + evects0.rows == ecount0 ); + + cv::Mat temp = evals0; + if( evals.rows == 1 ) + evals.colRange(0, ecount0).convertTo(temp, evals0.type()); + else + evals.rowRange(0, ecount0).convertTo(temp, evals0.type()); + if( temp.data != evals0.data ) + transpose(temp, evals0); + evects.rowRange(0, ecount0).convertTo( evects0, evects0.type() ); + + // otherwise some datatype's or size's were incorrect, so the output arrays have been reallocated + CV_Assert( mean0.data == mean.data ); +} + + +CV_IMPL void +cvProjectPCA( const CvArr* data_arr, const CvArr* avg_arr, + const CvArr* eigenvects, CvArr* result_arr ) +{ + cv::Mat data = cv::cvarrToMat(data_arr), mean = cv::cvarrToMat(avg_arr); + cv::Mat evects = cv::cvarrToMat(eigenvects), dst0 = cv::cvarrToMat(result_arr), dst = dst0; + + cv::PCA pca; + pca.mean = mean; + int n; + if( mean.rows == 1 ) + { + CV_Assert(dst.cols <= evects.rows && dst.rows == data.rows); + n = dst.cols; + } + else + { + CV_Assert(dst.rows <= evects.rows && dst.cols == data.cols); + n = dst.rows; + } + pca.eigenvectors = evects.rowRange(0, n); + + cv::Mat result = pca.project(data); + if( result.cols != dst.cols ) + result = result.reshape(1, 1); + result.convertTo(dst, dst.type()); + + CV_Assert(dst0.data == dst.data); +} + + +CV_IMPL void +cvBackProjectPCA( const CvArr* proj_arr, const CvArr* avg_arr, + const CvArr* eigenvects, CvArr* result_arr ) +{ + cv::Mat data = cv::cvarrToMat(proj_arr), mean = cv::cvarrToMat(avg_arr); + cv::Mat evects = cv::cvarrToMat(eigenvects), dst0 = cv::cvarrToMat(result_arr), dst = dst0; + + cv::PCA pca; + pca.mean = mean; + int n; + if( mean.rows == 1 ) + { + CV_Assert(data.cols <= evects.rows && dst.rows == data.rows); + n = data.cols; + } + else + { + CV_Assert(data.rows <= evects.rows && dst.cols == data.cols); + n = data.rows; + } + pca.eigenvectors = evects.rowRange(0, n); + + cv::Mat result = pca.backProject(data); + result.convertTo(dst, dst.type()); + + CV_Assert(dst0.data == dst.data); +} + +/* End of file. */ diff --git a/core/src/matop.cpp b/core/src/matop.cpp new file mode 100644 index 0000000..736984e --- /dev/null +++ b/core/src/matop.cpp @@ -0,0 +1,1651 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2010, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +/* //////////////////////////////////////////////////////////////////// +// +// Mat basic operations: Copy, Set +// +// */ + +#include "precomp.hpp" + +namespace cv +{ + +class MatOp_Identity : public MatOp +{ +public: + MatOp_Identity() {} + virtual ~MatOp_Identity() {} + + bool elementWise(const MatExpr& /*expr*/) const { return true; } + void assign(const MatExpr& expr, Mat& m, int type=-1) const; + + static void makeExpr(MatExpr& res, const Mat& m); +}; + +static MatOp_Identity g_MatOp_Identity; + +class MatOp_AddEx : public MatOp +{ +public: + MatOp_AddEx() {} + virtual ~MatOp_AddEx() {} + + bool elementWise(const MatExpr& /*expr*/) const { return true; } + void assign(const MatExpr& expr, Mat& m, int type=-1) const; + + void add(const MatExpr& e1, const Scalar& s, MatExpr& res) const; + void subtract(const Scalar& s, const MatExpr& expr, MatExpr& res) const; + void multiply(const MatExpr& e1, double s, MatExpr& res) const; + void divide(double s, const MatExpr& e, MatExpr& res) const; + + void transpose(const MatExpr& e1, MatExpr& res) const; + void abs(const MatExpr& expr, MatExpr& res) const; + + static void makeExpr(MatExpr& res, const Mat& a, const Mat& b, double alpha, double beta, const Scalar& s=Scalar()); +}; + +static MatOp_AddEx g_MatOp_AddEx; + +class MatOp_Bin : public MatOp +{ +public: + MatOp_Bin() {} + virtual ~MatOp_Bin() {} + + bool elementWise(const MatExpr& /*expr*/) const { return true; } + void assign(const MatExpr& expr, Mat& m, int type=-1) const; + + void multiply(const MatExpr& e1, double s, MatExpr& res) const; + void divide(double s, const MatExpr& e, MatExpr& res) const; + + static void makeExpr(MatExpr& res, char op, const Mat& a, const Mat& b, double scale=1); + static void makeExpr(MatExpr& res, char op, const Mat& a, const Scalar& s); +}; + +static MatOp_Bin g_MatOp_Bin; + +class MatOp_Cmp : public MatOp +{ +public: + MatOp_Cmp() {} + virtual ~MatOp_Cmp() {} + + bool elementWise(const MatExpr& /*expr*/) const { return true; } + void assign(const MatExpr& expr, Mat& m, int type=-1) const; + + static void makeExpr(MatExpr& res, int cmpop, const Mat& a, const Mat& b); + static void makeExpr(MatExpr& res, int cmpop, const Mat& a, double alpha); +}; + +static MatOp_Cmp g_MatOp_Cmp; + +class MatOp_GEMM : public MatOp +{ +public: + MatOp_GEMM() {} + virtual ~MatOp_GEMM() {} + + bool elementWise(const MatExpr& /*expr*/) const { return false; } + void assign(const MatExpr& expr, Mat& m, int type=-1) const; + + void add(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const; + void subtract(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const; + void multiply(const MatExpr& e, double s, MatExpr& res) const; + + void transpose(const MatExpr& expr, MatExpr& res) const; + + static void makeExpr(MatExpr& res, int flags, const Mat& a, const Mat& b, + double alpha=1, const Mat& c=Mat(), double beta=1); +}; + +static MatOp_GEMM g_MatOp_GEMM; + +class MatOp_Invert : public MatOp +{ +public: + MatOp_Invert() {} + virtual ~MatOp_Invert() {} + + bool elementWise(const MatExpr& /*expr*/) const { return false; } + void assign(const MatExpr& expr, Mat& m, int type=-1) const; + + void matmul(const MatExpr& expr1, const MatExpr& expr2, MatExpr& res) const; + + static void makeExpr(MatExpr& res, int method, const Mat& m); +}; + +static MatOp_Invert g_MatOp_Invert; + +class MatOp_T : public MatOp +{ +public: + MatOp_T() {} + virtual ~MatOp_T() {} + + bool elementWise(const MatExpr& /*expr*/) const { return false; } + void assign(const MatExpr& expr, Mat& m, int type=-1) const; + + void multiply(const MatExpr& e1, double s, MatExpr& res) const; + void transpose(const MatExpr& expr, MatExpr& res) const; + + static void makeExpr(MatExpr& res, const Mat& a, double alpha=1); +}; + +static MatOp_T g_MatOp_T; + +class MatOp_Solve : public MatOp +{ +public: + MatOp_Solve() {} + virtual ~MatOp_Solve() {} + + bool elementWise(const MatExpr& /*expr*/) const { return false; } + void assign(const MatExpr& expr, Mat& m, int type=-1) const; + + static void makeExpr(MatExpr& res, int method, const Mat& a, const Mat& b); +}; + +static MatOp_Solve g_MatOp_Solve; + +class MatOp_Initializer : public MatOp +{ +public: + MatOp_Initializer() {} + virtual ~MatOp_Initializer() {} + + bool elementWise(const MatExpr& /*expr*/) const { return false; } + void assign(const MatExpr& expr, Mat& m, int type=-1) const; + + void multiply(const MatExpr& e, double s, MatExpr& res) const; + + static void makeExpr(MatExpr& res, int method, Size sz, int type, double alpha=1); +}; + +static MatOp_Initializer g_MatOp_Initializer; + +static inline bool isIdentity(const MatExpr& e) { return e.op == &g_MatOp_Identity; } +static inline bool isAddEx(const MatExpr& e) { return e.op == &g_MatOp_AddEx; } +static inline bool isScaled(const MatExpr& e) { return isAddEx(e) && (!e.b.data || e.beta == 0) && e.s == Scalar(); } +static inline bool isBin(const MatExpr& e, char c) { return e.op == &g_MatOp_Bin && e.flags == c; } +static inline bool isCmp(const MatExpr& e) { return e.op == &g_MatOp_Cmp; } +static inline bool isReciprocal(const MatExpr& e) { return isBin(e,'/') && (!e.b.data || e.beta == 0); } +static inline bool isT(const MatExpr& e) { return e.op == &g_MatOp_T; } +static inline bool isInv(const MatExpr& e) { return e.op == &g_MatOp_Invert; } +static inline bool isSolve(const MatExpr& e) { return e.op == &g_MatOp_Solve; } +static inline bool isGEMM(const MatExpr& e) { return e.op == &g_MatOp_GEMM; } +static inline bool isMatProd(const MatExpr& e) { return e.op == &g_MatOp_GEMM && (!e.c.data || e.beta == 0); } +static inline bool isInitializer(const MatExpr& e) { return e.op == &g_MatOp_Initializer; } + +///////////////////////////////////////////////////////////////////////////////////////////////////// + +bool MatOp::elementWise(const MatExpr& /*expr*/) const +{ + return false; +} + +void MatOp::roi(const MatExpr& expr, const Range& rowRange, const Range& colRange, MatExpr& e) const +{ + if( elementWise(expr) ) + { + e = MatExpr(expr.op, expr.flags, Mat(), Mat(), Mat(), + expr.alpha, expr.beta, expr.s); + if(expr.a.data) + e.a = expr.a(rowRange, colRange); + if(expr.b.data) + e.b = expr.b(rowRange, colRange); + if(expr.c.data) + e.c = expr.c(rowRange, colRange); + } + else + { + Mat m; + expr.op->assign(expr, m); + e = MatExpr(&g_MatOp_Identity, 0, m(rowRange, colRange), Mat(), Mat()); + } +} + +void MatOp::diag(const MatExpr& expr, int d, MatExpr& e) const +{ + if( elementWise(expr) ) + { + e = MatExpr(expr.op, expr.flags, Mat(), Mat(), Mat(), + expr.alpha, expr.beta, expr.s); + if(expr.a.data) + e.a = expr.a.diag(d); + if(expr.b.data) + e.b = expr.b.diag(d); + if(expr.c.data) + e.c = expr.c.diag(d); + } + else + { + Mat m; + expr.op->assign(expr, m); + e = MatExpr(&g_MatOp_Identity, 0, m.diag(d), Mat(), Mat()); + } +} + + +void MatOp::augAssignAdd(const MatExpr& expr, Mat& m) const +{ + Mat temp; + expr.op->assign(expr, temp); + m += temp; +} + + +void MatOp::augAssignSubtract(const MatExpr& expr, Mat& m) const +{ + Mat temp; + expr.op->assign(expr, temp); + m -= temp; +} + + +void MatOp::augAssignMultiply(const MatExpr& expr, Mat& m) const +{ + Mat temp; + expr.op->assign(expr, temp); + m *= temp; +} + + +void MatOp::augAssignDivide(const MatExpr& expr, Mat& m) const +{ + Mat temp; + expr.op->assign(expr, temp); + m /= temp; +} + + +void MatOp::augAssignAnd(const MatExpr& expr, Mat& m) const +{ + Mat temp; + expr.op->assign(expr, temp); + m &= temp; +} + + +void MatOp::augAssignOr(const MatExpr& expr, Mat& m) const +{ + Mat temp; + expr.op->assign(expr, temp); + m |= temp; +} + + +void MatOp::augAssignXor(const MatExpr& expr, Mat& m) const +{ + Mat temp; + expr.op->assign(expr, temp); + m /= temp; +} + + +void MatOp::add(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const +{ + if( this == e2.op ) + { + double alpha = 1, beta = 1; + Scalar s; + Mat m1, m2; + if( isAddEx(e1) && (!e1.b.data || e1.beta == 0) ) + { + m1 = e1.a; + alpha = e1.alpha; + s = e1.s; + } + else + e1.op->assign(e1, m1); + + if( isAddEx(e2) && (!e2.b.data || e2.beta == 0) ) + { + m2 = e2.a; + beta = e2.alpha; + s += e2.s; + } + else + e2.op->assign(e2, m2); + MatOp_AddEx::makeExpr(res, m1, m2, alpha, beta, s); + } + else + e2.op->add(e1, e2, res); +} + + +void MatOp::add(const MatExpr& expr1, const Scalar& s, MatExpr& res) const +{ + Mat m1; + expr1.op->assign(expr1, m1); + MatOp_AddEx::makeExpr(res, m1, Mat(), 1, 0, s); +} + + +void MatOp::subtract(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const +{ + if( this == e2.op ) + { + double alpha = 1, beta = -1; + Scalar s; + Mat m1, m2; + if( isAddEx(e1) && (!e1.b.data || e1.beta == 0) ) + { + m1 = e1.a; + alpha = e1.alpha; + s = e1.s; + } + else + e1.op->assign(e1, m1); + + if( isAddEx(e2) && (!e2.b.data || e2.beta == 0) ) + { + m2 = e2.a; + beta = -e2.alpha; + s -= e2.s; + } + else + e2.op->assign(e2, m2); + MatOp_AddEx::makeExpr(res, m1, m2, alpha, beta, s); + } + else + e2.op->subtract(e1, e2, res); +} + + +void MatOp::subtract(const Scalar& s, const MatExpr& expr, MatExpr& res) const +{ + Mat m; + expr.op->assign(expr, m); + MatOp_AddEx::makeExpr(res, m, Mat(), -1, 0, s); +} + + +void MatOp::multiply(const MatExpr& e1, const MatExpr& e2, MatExpr& res, double scale) const +{ + if( this == e2.op ) + { + Mat m1, m2; + + if( isReciprocal(e1) ) + { + if( isScaled(e2) ) + { + scale *= e2.alpha; + m2 = e2.a; + } + else + e2.op->assign(e2, m2); + + MatOp_Bin::makeExpr(res, '/', m2, e1.a, scale/e1.alpha); + } + else + { + char op = '*'; + if( isScaled(e1) ) + { + m1 = e1.a; + scale *= e1.alpha; + } + else + e1.op->assign(e1, m1); + + if( isScaled(e2) ) + { + m2 = e2.a; + scale *= e2.alpha; + } + else if( isReciprocal(e2) ) + { + op = '/'; + m2 = e2.a; + scale /= e2.alpha; + } + else + e2.op->assign(e2, m2); + + MatOp_Bin::makeExpr(res, op, m1, m2, scale); + } + } + else + e2.op->multiply(e1, e2, res, scale); +} + + +void MatOp::multiply(const MatExpr& expr, double s, MatExpr& res) const +{ + Mat m; + expr.op->assign(expr, m); + MatOp_AddEx::makeExpr(res, m, Mat(), s, 0); +} + + +void MatOp::divide(const MatExpr& e1, const MatExpr& e2, MatExpr& res, double scale) const +{ + if( this == e2.op ) + { + if( isReciprocal(e1) && isReciprocal(e2) ) + MatOp_Bin::makeExpr(res, '/', e2.a, e1.a, e1.alpha/e2.alpha); + else + { + Mat m1, m2; + char op = '/'; + + if( isScaled(e1) ) + { + m1 = e1.a; + scale *= e1.alpha; + } + else + e1.op->assign(e1, m1); + + if( isScaled(e2) ) + { + m2 = e2.a; + scale /= e2.alpha; + } + else if( isReciprocal(e2) ) + { + m2 = e2.a; + scale /= e2.alpha; + op = '*'; + } + else + e2.op->assign(e2, m2); + MatOp_Bin::makeExpr(res, op, m1, m2, scale); + } + } + else + e2.op->divide(e1, e2, res, scale); +} + + +void MatOp::divide(double s, const MatExpr& expr, MatExpr& res) const +{ + Mat m; + expr.op->assign(expr, m); + MatOp_Bin::makeExpr(res, '/', m, Mat(), s); +} + + +void MatOp::abs(const MatExpr& expr, MatExpr& res) const +{ + Mat m; + expr.op->assign(expr, m); + MatOp_Bin::makeExpr(res, 'a', m, Mat()); +} + + +void MatOp::transpose(const MatExpr& expr, MatExpr& res) const +{ + Mat m; + expr.op->assign(expr, m); + MatOp_T::makeExpr(res, m, 1); +} + + +void MatOp::matmul(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const +{ + if( this == e2.op ) + { + double scale = 1; + int flags = 0; + Mat m1, m2; + + if( isT(e1) ) + { + flags = CV_GEMM_A_T; + scale = e1.alpha; + m1 = e1.a; + } + else if( isScaled(e1) ) + { + scale = e1.alpha; + m1 = e1.a; + } + else + e1.op->assign(e1, m1); + + if( isT(e2) ) + { + flags |= CV_GEMM_B_T; + scale *= e2.alpha; + m2 = e2.a; + } + else if( isScaled(e2) ) + { + scale *= e2.alpha; + m2 = e2.a; + } + else + e2.op->assign(e2, m2); + + MatOp_GEMM::makeExpr(res, flags, m1, m2, scale); + } + else + e2.op->matmul(e1, e2, res); +} + + +void MatOp::invert(const MatExpr& expr, int method, MatExpr& res) const +{ + Mat m; + expr.op->assign(expr, m); + MatOp_Invert::makeExpr(res, method, m); +} + + +Size MatOp::size(const MatExpr& expr) const +{ + return !expr.a.empty() ? expr.a.size() : expr.b.empty() ? expr.b.size() : expr.c.size(); +} + +int MatOp::type(const MatExpr& expr) const +{ + return !expr.a.empty() ? expr.a.type() : expr.b.empty() ? expr.b.type() : expr.c.type(); +} + +////////////////////////////////////////////////////////////////////////////////////////////////// + +MatExpr::MatExpr(const Mat& m) : op(&g_MatOp_Identity), flags(0), a(m), b(Mat()), c(Mat()), alpha(1), beta(0), s(Scalar()) +{ +} + +MatExpr MatExpr::row(int y) const +{ + MatExpr e; + op->roi(*this, Range(y, y+1), Range::all(), e); + return e; +} + +MatExpr MatExpr::col(int x) const +{ + MatExpr e; + op->roi(*this, Range::all(), Range(x, x+1), e); + return e; +} + +MatExpr MatExpr::diag(int d) const +{ + MatExpr e; + op->diag(*this, d, e); + return e; +} + +MatExpr MatExpr::operator()( const Range& rowRange, const Range& colRange ) const +{ + MatExpr e; + op->roi(*this, rowRange, colRange, e); + return e; +} + +MatExpr MatExpr::operator()( const Rect& roi ) const +{ + MatExpr e; + op->roi(*this, Range(roi.y, roi.y + roi.height), Range(roi.x, roi.x + roi.width), e); + return e; +} + +Mat MatExpr::cross(const Mat& m) const +{ + return ((Mat)*this).cross(m); +} + +double MatExpr::dot(const Mat& m) const +{ + return ((Mat)*this).dot(m); +} + +MatExpr MatExpr::t() const +{ + MatExpr e; + op->transpose(*this, e); + return e; +} + +MatExpr MatExpr::inv(int method) const +{ + MatExpr e; + op->invert(*this, method, e); + return e; +} + +MatExpr MatExpr::mul(const MatExpr& e, double scale) const +{ + MatExpr en; + op->multiply(*this, e, en, scale); + return en; +} + +MatExpr MatExpr::mul(const Mat& m, double scale) const +{ + MatExpr e; + op->multiply(*this, MatExpr(m), e, scale); + return e; +} + +MatExpr operator + (const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_AddEx::makeExpr(e, a, b, 1, 1); + return e; +} + +MatExpr operator + (const Mat& a, const Scalar& s) +{ + MatExpr e; + MatOp_AddEx::makeExpr(e, a, Mat(), 1, 0, s); + return e; +} + +MatExpr operator + (const Scalar& s, const Mat& a) +{ + MatExpr e; + MatOp_AddEx::makeExpr(e, a, Mat(), 1, 0, s); + return e; +} + +MatExpr operator + (const MatExpr& e, const Mat& m) +{ + MatExpr en; + e.op->add(e, MatExpr(m), en); + return en; +} + +MatExpr operator + (const Mat& m, const MatExpr& e) +{ + MatExpr en; + e.op->add(e, MatExpr(m), en); + return en; +} + +MatExpr operator + (const MatExpr& e, const Scalar& s) +{ + MatExpr en; + e.op->add(e, s, en); + return en; +} + +MatExpr operator + (const Scalar& s, const MatExpr& e) +{ + MatExpr en; + e.op->add(e, s, en); + return en; +} + +MatExpr operator + (const MatExpr& e1, const MatExpr& e2) +{ + MatExpr en; + e1.op->add(e1, e2, en); + return en; +} + +MatExpr operator - (const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_AddEx::makeExpr(e, a, b, 1, -1); + return e; +} + +MatExpr operator - (const Mat& a, const Scalar& s) +{ + MatExpr e; + MatOp_AddEx::makeExpr(e, a, Mat(), 1, 0, -s); + return e; +} + +MatExpr operator - (const Scalar& s, const Mat& a) +{ + MatExpr e; + MatOp_AddEx::makeExpr(e, a, Mat(), -1, 0, s); + return e; +} + +MatExpr operator - (const MatExpr& e, const Mat& m) +{ + MatExpr en; + e.op->subtract(e, MatExpr(m), en); + return en; +} + +MatExpr operator - (const Mat& m, const MatExpr& e) +{ + MatExpr en; + e.op->subtract(MatExpr(m), e, en); + return en; +} + +MatExpr operator - (const MatExpr& e, const Scalar& s) +{ + MatExpr en; + e.op->add(e, -s, en); + return en; +} + +MatExpr operator - (const Scalar& s, const MatExpr& e) +{ + MatExpr en; + e.op->subtract(s, e, en); + return en; +} + +MatExpr operator - (const MatExpr& e1, const MatExpr& e2) +{ + MatExpr en; + e1.op->subtract(e1, e2, en); + return en; +} + +MatExpr operator - (const Mat& m) +{ + MatExpr e; + MatOp_AddEx::makeExpr(e, m, Mat(), -1, 0); + return e; +} + +MatExpr operator - (const MatExpr& e) +{ + MatExpr en; + e.op->subtract(Scalar(0), e, en); + return en; +} + +MatExpr operator * (const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_GEMM::makeExpr(e, 0, a, b); + return e; +} + +MatExpr operator * (const Mat& a, double s) +{ + MatExpr e; + MatOp_AddEx::makeExpr(e, a, Mat(), s, 0); + return e; +} + +MatExpr operator * (double s, const Mat& a) +{ + MatExpr e; + MatOp_AddEx::makeExpr(e, a, Mat(), s, 0); + return e; +} + +MatExpr operator * (const MatExpr& e, const Mat& m) +{ + MatExpr en; + e.op->matmul(e, MatExpr(m), en); + return en; +} + +MatExpr operator * (const Mat& m, const MatExpr& e) +{ + MatExpr en; + e.op->matmul(MatExpr(m), e, en); + return en; +} + +MatExpr operator * (const MatExpr& e, double s) +{ + MatExpr en; + e.op->multiply(e, s, en); + return en; +} + +MatExpr operator * (double s, const MatExpr& e) +{ + MatExpr en; + e.op->multiply(e, s, en); + return en; +} + +MatExpr operator * (const MatExpr& e1, const MatExpr& e2) +{ + MatExpr en; + e1.op->matmul(e1, e2, en); + return en; +} + +MatExpr operator / (const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, '/', a, b); + return e; +} + +MatExpr operator / (const Mat& a, double s) +{ + MatExpr e; + MatOp_AddEx::makeExpr(e, a, Mat(), 1./s, 0); + return e; +} + +MatExpr operator / (double s, const Mat& a) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, '/', a, Mat(), s); + return e; +} + +MatExpr operator / (const MatExpr& e, const Mat& m) +{ + MatExpr en; + e.op->divide(e, MatExpr(m), en); + return en; +} + +MatExpr operator / (const Mat& m, const MatExpr& e) +{ + MatExpr en; + e.op->divide(MatExpr(m), e, en); + return en; +} + +MatExpr operator / (const MatExpr& e, double s) +{ + MatExpr en; + e.op->multiply(e, 1./s, en); + return en; +} + +MatExpr operator / (double s, const MatExpr& e) +{ + MatExpr en; + e.op->divide(s, e, en); + return en; +} + +MatExpr operator / (const MatExpr& e1, const MatExpr& e2) +{ + MatExpr en; + e1.op->divide(e1, e2, en); + return en; +} + +MatExpr operator < (const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_LT, a, b); + return e; +} + +MatExpr operator < (const Mat& a, double s) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_LT, a, s); + return e; +} + +MatExpr operator < (double s, const Mat& a) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_GT, a, s); + return e; +} + +MatExpr operator <= (const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_LE, a, b); + return e; +} + +MatExpr operator <= (const Mat& a, double s) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_LE, a, s); + return e; +} + +MatExpr operator <= (double s, const Mat& a) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_GE, a, s); + return e; +} + +MatExpr operator == (const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_EQ, a, b); + return e; +} + +MatExpr operator == (const Mat& a, double s) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_EQ, a, s); + return e; +} + +MatExpr operator == (double s, const Mat& a) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_EQ, a, s); + return e; +} + +MatExpr operator != (const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_NE, a, b); + return e; +} + +MatExpr operator != (const Mat& a, double s) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_NE, a, s); + return e; +} + +MatExpr operator != (double s, const Mat& a) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_NE, a, s); + return e; +} + +MatExpr operator >= (const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_GE, a, b); + return e; +} + +MatExpr operator >= (const Mat& a, double s) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_GE, a, s); + return e; +} + +MatExpr operator >= (double s, const Mat& a) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_LE, a, s); + return e; +} + +MatExpr operator > (const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_GT, a, b); + return e; +} + +MatExpr operator > (const Mat& a, double s) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_GT, a, s); + return e; +} + +MatExpr operator > (double s, const Mat& a) +{ + MatExpr e; + MatOp_Cmp::makeExpr(e, CV_CMP_LT, a, s); + return e; +} + +MatExpr min(const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, 'm', a, b); + return e; +} + +MatExpr min(const Mat& a, double s) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, 'm', a, s); + return e; +} + +MatExpr min(double s, const Mat& a) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, 'm', a, s); + return e; +} + +MatExpr max(const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, 'M', a, b); + return e; +} + +MatExpr max(const Mat& a, double s) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, 'M', a, s); + return e; +} + +MatExpr max(double s, const Mat& a) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, 'M', a, s); + return e; +} + +MatExpr operator & (const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, '&', a, b); + return e; +} + +MatExpr operator & (const Mat& a, const Scalar& s) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, '&', a, s); + return e; +} + +MatExpr operator & (const Scalar& s, const Mat& a) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, '&', a, s); + return e; +} + +MatExpr operator | (const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, '|', a, b); + return e; +} + +MatExpr operator | (const Mat& a, const Scalar& s) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, '|', a, s); + return e; +} + +MatExpr operator | (const Scalar& s, const Mat& a) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, '|', a, s); + return e; +} + +MatExpr operator ^ (const Mat& a, const Mat& b) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, '^', a, b); + return e; +} + +MatExpr operator ^ (const Mat& a, const Scalar& s) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, '^', a, s); + return e; +} + +MatExpr operator ^ (const Scalar& s, const Mat& a) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, '^', a, s); + return e; +} + +MatExpr operator ~(const Mat& a) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, '~', a, Scalar()); + return e; +} + +MatExpr abs(const Mat& a) +{ + MatExpr e; + MatOp_Bin::makeExpr(e, 'a', a, Scalar()); + return e; +} + +MatExpr abs(const MatExpr& e) +{ + MatExpr en; + e.op->abs(e, en); + return en; +} + + +Size MatExpr::size() const +{ + if( isT(*this) || isInv(*this) ) + return Size(a.rows, a.cols); + if( isGEMM(*this) ) + return Size(b.cols, a.rows); + if( isSolve(*this) ) + return Size(b.cols, a.cols); + if( isInitializer(*this) ) + return a.size(); + return op ? op->size(*this) : Size(); +} + + +int MatExpr::type() const +{ + if( isInitializer(*this) ) + return a.type(); + if( isCmp(*this) ) + return CV_8U; + return op ? op->type(*this) : -1; +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////// + +void MatOp_Identity::assign(const MatExpr& e, Mat& m, int _type) const +{ + if( _type == -1 || _type == e.a.type() ) + m = e.a; + else + { + CV_Assert( CV_MAT_CN(_type) == e.a.channels() ); + e.a.convertTo(m, _type); + } +} + +inline void MatOp_Identity::makeExpr(MatExpr& res, const Mat& m) +{ + res = MatExpr(&g_MatOp_Identity, 0, m, Mat(), Mat(), 1, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// + +void MatOp_AddEx::assign(const MatExpr& e, Mat& m, int _type) const +{ + Mat temp, &dst = _type == -1 || e.a.type() == _type ? m : temp; + if( e.b.data ) + { + if( e.s == Scalar() || !e.s.isReal() ) + { + if( e.alpha == 1 ) + { + if( e.beta == 1 ) + cv::add(e.a, e.b, dst); + else if( e.beta == -1 ) + cv::subtract(e.a, e.b, dst); + else + cv::scaleAdd(e.b, e.beta, e.a, dst); + } + else if( e.beta == 1 ) + { + if( e.alpha == -1 ) + cv::subtract(e.b, e.a, dst); + else + cv::scaleAdd(e.a, e.alpha, e.b, dst); + } + else + cv::addWeighted(e.a, e.alpha, e.b, e.beta, 0, dst); + + if( !e.s.isReal() ) + cv::add(dst, e.s, dst); + } + else + cv::addWeighted(e.a, e.alpha, e.b, e.beta, e.s[0], dst); + } + else if( e.s.isReal() && (dst.data != m.data || fabs(e.alpha) != 1)) + { + e.a.convertTo(m, _type, e.alpha, e.s[0]); + return; + } + else if( e.alpha == 1 ) + cv::add(e.a, e.s, dst); + else if( e.alpha == -1 ) + cv::subtract(e.s, e.a, dst); + else + { + e.a.convertTo(dst, e.a.type(), e.alpha); + cv::add(dst, e.s, dst); + } + + if( dst.data != m.data ) + dst.convertTo(m, m.type()); +} + + +void MatOp_AddEx::add(const MatExpr& e, const Scalar& s, MatExpr& res) const +{ + res = e; + res.s += s; +} + + +void MatOp_AddEx::subtract(const Scalar& s, const MatExpr& e, MatExpr& res) const +{ + res = e; + res.alpha = -res.alpha; + res.beta = -res.beta; + res.s = s - res.s; +} + +void MatOp_AddEx::multiply(const MatExpr& e, double s, MatExpr& res) const +{ + res = e; + res.alpha *= s; + res.beta *= s; + res.s *= s; +} + +void MatOp_AddEx::divide(double s, const MatExpr& e, MatExpr& res) const +{ + if( isScaled(e) ) + MatOp_Bin::makeExpr(res, '/', e.a, Mat(), s/e.alpha); + else + MatOp::divide(s, e, res); +} + + +void MatOp_AddEx::transpose(const MatExpr& e, MatExpr& res) const +{ + if( isScaled(e) ) + MatOp_T::makeExpr(res, e.a, e.alpha); + else + MatOp::transpose(e, res); +} + +void MatOp_AddEx::abs(const MatExpr& e, MatExpr& res) const +{ + if( (!e.b.data || e.beta == 0) && fabs(e.alpha) == 1 ) + MatOp_Bin::makeExpr(res, 'a', e.a, -e.s*e.alpha); + else if( e.b.data && e.alpha + e.beta == 0 && e.alpha*e.beta == -1 ) + MatOp_Bin::makeExpr(res, 'a', e.a, e.b); + else + MatOp::abs(e, res); +} + +inline void MatOp_AddEx::makeExpr(MatExpr& res, const Mat& a, const Mat& b, double alpha, double beta, const Scalar& s) +{ + res = MatExpr(&g_MatOp_AddEx, 0, a, b, Mat(), alpha, beta, s); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void MatOp_Bin::assign(const MatExpr& e, Mat& m, int _type) const +{ + Mat temp, &dst = _type == -1 || e.a.type() == _type ? m : temp; + + if( e.flags == '*' ) + cv::multiply(e.a, e.b, dst, e.alpha); + else if( e.flags == '/' && e.b.data ) + cv::divide(e.a, e.b, dst, e.alpha); + else if( e.flags == '/' && !e.b.data ) + cv::divide(e.alpha, e.a, dst ); + else if( e.flags == '&' && e.b.data ) + bitwise_and(e.a, e.b, dst); + else if( e.flags == '&' && !e.b.data ) + bitwise_and(e.a, e.s, dst); + else if( e.flags == '|' && e.b.data ) + bitwise_or(e.a, e.b, dst); + else if( e.flags == '|' && !e.b.data ) + bitwise_or(e.a, e.s, dst); + else if( e.flags == '^' && e.b.data ) + bitwise_xor(e.a, e.b, dst); + else if( e.flags == '^' && !e.b.data ) + bitwise_xor(e.a, e.s, dst); + else if( e.flags == '~' && !e.b.data ) + bitwise_not(e.a, dst); + else if( e.flags == 'm' && e.b.data ) + cv::min(e.a, e.b, dst); + else if( e.flags == 'm' && !e.b.data ) + cv::min(e.a, e.s[0], dst); + else if( e.flags == 'M' && e.b.data ) + cv::max(e.a, e.b, dst); + else if( e.flags == 'M' && !e.b.data ) + cv::max(e.a, e.s[0], dst); + else if( e.flags == 'a' && e.b.data ) + cv::absdiff(e.a, e.b, dst); + else if( e.flags == 'a' && !e.b.data ) + cv::absdiff(e.a, e.s, dst); + else + CV_Error(CV_StsError, "Unknown operation"); + + if( dst.data != m.data ) + dst.convertTo(m, _type); +} + +void MatOp_Bin::multiply(const MatExpr& e, double s, MatExpr& res) const +{ + if( e.flags == '*' || e.flags == '/' ) + { + res = e; + res.alpha *= s; + } + else + MatOp::multiply(e, s, res); +} + +void MatOp_Bin::divide(double s, const MatExpr& e, MatExpr& res) const +{ + if( e.flags == '/' && (!e.b.data || e.beta == 0) ) + MatOp_AddEx::makeExpr(res, e.a, Mat(), s/e.alpha, 0); + else + MatOp::divide(s, e, res); +} + +inline void MatOp_Bin::makeExpr(MatExpr& res, char op, const Mat& a, const Mat& b, double scale) +{ + res = MatExpr(&g_MatOp_Bin, op, a, b, Mat(), scale, b.data ? 1 : 0); +} + +inline void MatOp_Bin::makeExpr(MatExpr& res, char op, const Mat& a, const Scalar& s) +{ + res = MatExpr(&g_MatOp_Bin, op, a, Mat(), Mat(), 1, 0, s); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////// + +void MatOp_Cmp::assign(const MatExpr& e, Mat& m, int _type) const +{ + Mat temp, &dst = _type == -1 || _type == CV_8U ? m : temp; + + if( e.b.data ) + cv::compare(e.a, e.b, dst, e.flags); + else + cv::compare(e.a, e.alpha, dst, e.flags); + + if( dst.data != m.data ) + dst.convertTo(m, _type); +} + +inline void MatOp_Cmp::makeExpr(MatExpr& res, int cmpop, const Mat& a, const Mat& b) +{ + res = MatExpr(&g_MatOp_Cmp, cmpop, a, b, Mat(), 1, 1); +} + +inline void MatOp_Cmp::makeExpr(MatExpr& res, int cmpop, const Mat& a, double alpha) +{ + res = MatExpr(&g_MatOp_Cmp, cmpop, a, Mat(), Mat(), alpha, 1); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +void MatOp_T::assign(const MatExpr& e, Mat& m, int _type) const +{ + Mat temp, &dst = _type == -1 || _type == e.a.type() ? m : temp; + + cv::transpose(e.a, dst); + + if( dst.data != m.data || e.alpha != 1 ) + dst.convertTo(m, _type, e.alpha); +} + +void MatOp_T::multiply(const MatExpr& e, double s, MatExpr& res) const +{ + res = e; + res.alpha *= s; +} + +void MatOp_T::transpose(const MatExpr& e, MatExpr& res) const +{ + if( e.alpha == 1 ) + MatOp_Identity::makeExpr(res, e.a); + else + MatOp_AddEx::makeExpr(res, e.a, Mat(), e.alpha, 0); +} + +inline void MatOp_T::makeExpr(MatExpr& res, const Mat& a, double alpha) +{ + res = MatExpr(&g_MatOp_T, 0, a, Mat(), Mat(), alpha, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +void MatOp_GEMM::assign(const MatExpr& e, Mat& m, int _type) const +{ + Mat temp, &dst = _type == -1 || _type == e.a.type() ? m : temp; + + cv::gemm(e.a, e.b, e.alpha, e.c, e.beta, dst, e.flags); + if( dst.data != m.data ) + dst.convertTo(m, _type); +} + +void MatOp_GEMM::add(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const +{ + bool i1 = isIdentity(e1), i2 = isIdentity(e2); + double alpha1 = i1 ? 1 : e1.alpha, alpha2 = i2 ? 1 : e2.alpha; + + if( isMatProd(e1) && (i2 || isScaled(e2) || isT(e2)) ) + MatOp_GEMM::makeExpr(res, (e1.flags & ~CV_GEMM_C_T)|(isT(e2) ? CV_GEMM_C_T : 0), + e1.a, e1.b, alpha1, e2.a, alpha2); + else if( isMatProd(e2) && (i1 || isScaled(e1) || isT(e1)) ) + MatOp_GEMM::makeExpr(res, (e2.flags & ~CV_GEMM_C_T)|(isT(e1) ? CV_GEMM_C_T : 0), + e2.a, e2.b, alpha2, e1.a, alpha1); + else if( this == e2.op ) + MatOp::add(e1, e2, res); + else + e2.op->add(e1, e2, res); +} + +void MatOp_GEMM::subtract(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const +{ + bool i1 = isIdentity(e1), i2 = isIdentity(e2); + double alpha1 = i1 ? 1 : e1.alpha, alpha2 = i2 ? 1 : e2.alpha; + + if( isMatProd(e1) && (i2 || isScaled(e2) || isT(e2)) ) + MatOp_GEMM::makeExpr(res, (e1.flags & ~CV_GEMM_C_T)|(isT(e2) ? CV_GEMM_C_T : 0), + e1.a, e1.b, alpha1, e2.a, -alpha2); + else if( isMatProd(e2) && (i1 || isScaled(e1) || isT(e1)) ) + MatOp_GEMM::makeExpr(res, (e2.flags & ~CV_GEMM_C_T)|(isT(e1) ? CV_GEMM_C_T : 0), + e2.a, e2.b, -alpha2, e1.a, alpha1); + else if( this == e2.op ) + MatOp::subtract(e1, e2, res); + else + e2.op->subtract(e1, e2, res); +} + +void MatOp_GEMM::multiply(const MatExpr& e, double s, MatExpr& res) const +{ + res = e; + res.alpha *= s; + res.beta *= s; +} + +void MatOp_GEMM::transpose(const MatExpr& e, MatExpr& res) const +{ + res = e; + res.flags = (!(e.flags & CV_GEMM_A_T) ? CV_GEMM_B_T : 0) | + (!(e.flags & CV_GEMM_B_T) ? CV_GEMM_A_T : 0) | + (!(e.flags & CV_GEMM_C_T) ? CV_GEMM_C_T : 0); + swap(res.a, res.b); +} + +inline void MatOp_GEMM::makeExpr(MatExpr& res, int flags, const Mat& a, const Mat& b, + double alpha, const Mat& c, double beta) +{ + res = MatExpr(&g_MatOp_GEMM, flags, a, b, c, alpha, beta); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////// + +void MatOp_Invert::assign(const MatExpr& e, Mat& m, int _type) const +{ + Mat temp, &dst = _type == -1 || _type == e.a.type() ? m : temp; + + cv::invert(e.a, dst, e.flags); + if( dst.data != m.data ) + dst.convertTo(m, _type); +} + +void MatOp_Invert::matmul(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const +{ + if( isInv(e1) && isIdentity(e2) ) + MatOp_Solve::makeExpr(res, e1.flags, e1.a, e2.a); + else if( this == e2.op ) + MatOp::matmul(e1, e2, res); + else + e2.op->matmul(e1, e2, res); +} + +inline void MatOp_Invert::makeExpr(MatExpr& res, int method, const Mat& m) +{ + res = MatExpr(&g_MatOp_Invert, method, m, Mat(), Mat(), 1, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +void MatOp_Solve::assign(const MatExpr& e, Mat& m, int _type) const +{ + Mat temp, &dst = _type == -1 || _type == e.a.type() ? m : temp; + + cv::solve(e.a, e.b, dst, e.flags); + if( dst.data != m.data ) + dst.convertTo(m, _type); +} + +inline void MatOp_Solve::makeExpr(MatExpr& res, int method, const Mat& a, const Mat& b) +{ + res = MatExpr(&g_MatOp_Solve, method, a, b, Mat(), 1, 1); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void MatOp_Initializer::assign(const MatExpr& e, Mat& m, int _type) const +{ + if( _type == -1 ) + _type = e.a.type(); + m.create(e.a.size(), _type); + if( e.flags == 'I' ) + setIdentity(m, Scalar(e.alpha)); + else if( e.flags == '0' ) + m = Scalar(); + else if( e.flags == '1' ) + m = Scalar(e.alpha); + else + CV_Error(CV_StsError, "Invalid matrix initializer type"); +} + +void MatOp_Initializer::multiply(const MatExpr& e, double s, MatExpr& res) const +{ + res = e; + res.alpha *= s; +} + +inline void MatOp_Initializer::makeExpr(MatExpr& res, int method, Size sz, int type, double alpha) +{ + res = MatExpr(&g_MatOp_Initializer, method, Mat(sz, type, (void*)0), Mat(), Mat(), alpha, 0); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// + +MatExpr Mat::t() const +{ + MatExpr e; + MatOp_T::makeExpr(e, *this); + return e; +} + +MatExpr Mat::inv(int method) const +{ + MatExpr e; + MatOp_Invert::makeExpr(e, method, *this); + return e; +} + + +MatExpr Mat::mul(InputArray m, double scale) const +{ + MatExpr e; + if(m.kind() == _InputArray::EXPR) + { + const MatExpr& me = *(const MatExpr*)m.obj; + me.op->multiply(MatExpr(*this), me, e, scale); + } + else + MatOp_Bin::makeExpr(e, '*', *this, m.getMat(), scale); + return e; +} + +MatExpr Mat::zeros(int rows, int cols, int type) +{ + MatExpr e; + MatOp_Initializer::makeExpr(e, '0', Size(cols, rows), type); + return e; +} + +MatExpr Mat::zeros(Size size, int type) +{ + MatExpr e; + MatOp_Initializer::makeExpr(e, '0', size, type); + return e; +} + +MatExpr Mat::ones(int rows, int cols, int type) +{ + MatExpr e; + MatOp_Initializer::makeExpr(e, '1', Size(cols, rows), type); + return e; +} + +MatExpr Mat::ones(Size size, int type) +{ + MatExpr e; + MatOp_Initializer::makeExpr(e, '1', size, type); + return e; +} + +MatExpr Mat::eye(int rows, int cols, int type) +{ + MatExpr e; + MatOp_Initializer::makeExpr(e, 'I', Size(cols, rows), type); + return e; +} + +MatExpr Mat::eye(Size size, int type) +{ + MatExpr e; + MatOp_Initializer::makeExpr(e, 'I', size, type); + return e; +} + +} + +/* End of file. */ diff --git a/core/src/matrix.cpp b/core/src/matrix.cpp new file mode 100644 index 0000000..aaaac10 --- /dev/null +++ b/core/src/matrix.cpp @@ -0,0 +1,4074 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include "opencv2/core/gpumat.hpp" +#include "opencv2/core/opengl_interop.hpp" + +/****************************************************************************************\ +* [scaled] Identity matrix initialization * +\****************************************************************************************/ + +namespace cv { + +void swap( Mat& a, Mat& b ) +{ + std::swap(a.flags, b.flags); + std::swap(a.dims, b.dims); + std::swap(a.rows, b.rows); + std::swap(a.cols, b.cols); + std::swap(a.data, b.data); + std::swap(a.refcount, b.refcount); + std::swap(a.datastart, b.datastart); + std::swap(a.dataend, b.dataend); + std::swap(a.datalimit, b.datalimit); + std::swap(a.allocator, b.allocator); + + std::swap(a.size.p, b.size.p); + std::swap(a.step.p, b.step.p); + std::swap(a.step.buf[0], b.step.buf[0]); + std::swap(a.step.buf[1], b.step.buf[1]); + + if( a.step.p == b.step.buf ) + { + a.step.p = a.step.buf; + a.size.p = &a.rows; + } + + if( b.step.p == a.step.buf ) + { + b.step.p = b.step.buf; + b.size.p = &b.rows; + } +} + + +static inline void setSize( Mat& m, int _dims, const int* _sz, + const size_t* _steps, bool autoSteps=false ) +{ + CV_Assert( 0 <= _dims && _dims <= CV_MAX_DIM ); + if( m.dims != _dims ) + { + if( m.step.p != m.step.buf ) + { + fastFree(m.step.p); + m.step.p = m.step.buf; + m.size.p = &m.rows; + } + if( _dims > 2 ) + { + m.step.p = (size_t*)fastMalloc(_dims*sizeof(m.step.p[0]) + (_dims+1)*sizeof(m.size.p[0])); + m.size.p = (int*)(m.step.p + _dims) + 1; + m.size.p[-1] = _dims; + m.rows = m.cols = -1; + } + } + + m.dims = _dims; + if( !_sz ) + return; + + size_t esz = CV_ELEM_SIZE(m.flags), total = esz; + int i; + for( i = _dims-1; i >= 0; i-- ) + { + int s = _sz[i]; + CV_Assert( s >= 0 ); + m.size.p[i] = s; + + if( _steps ) + m.step.p[i] = i < _dims-1 ? _steps[i] : esz; + else if( autoSteps ) + { + m.step.p[i] = total; + int64 total1 = (int64)total*s; + if( (uint64)total1 != (size_t)total1 ) + CV_Error( CV_StsOutOfRange, "The total matrix size does not fit to \"size_t\" type" ); + total = (size_t)total1; + } + } + + if( _dims == 1 ) + { + m.dims = 2; + m.cols = 1; + m.step[1] = esz; + } +} + +static void updateContinuityFlag(Mat& m) +{ + int i, j; + for( i = 0; i < m.dims; i++ ) + { + if( m.size[i] > 1 ) + break; + } + + for( j = m.dims-1; j > i; j-- ) + { + if( m.step[j]*m.size[j] < m.step[j-1] ) + break; + } + + uint64 t = (uint64)m.step[0]*m.size[0]; + if( j <= i && t == (size_t)t ) + m.flags |= Mat::CONTINUOUS_FLAG; + else + m.flags &= ~Mat::CONTINUOUS_FLAG; +} + +static void finalizeHdr(Mat& m) +{ + updateContinuityFlag(m); + int d = m.dims; + if( d > 2 ) + m.rows = m.cols = -1; + if( m.data ) + { + m.datalimit = m.datastart + m.size[0]*m.step[0]; + if( m.size[0] > 0 ) + { + m.dataend = m.data + m.size[d-1]*m.step[d-1]; + for( int i = 0; i < d-1; i++ ) + m.dataend += (m.size[i] - 1)*m.step[i]; + } + else + m.dataend = m.datalimit; + } + else + m.dataend = m.datalimit = 0; +} + + +void Mat::create(int d, const int* _sizes, int _type) +{ + int i; + CV_Assert(0 <= d && _sizes && d <= CV_MAX_DIM && _sizes); + _type = CV_MAT_TYPE(_type); + + if( data && (d == dims || (d == 1 && dims <= 2)) && _type == type() ) + { + if( d == 2 && rows == _sizes[0] && cols == _sizes[1] ) + return; + for( i = 0; i < d; i++ ) + if( size[i] != _sizes[i] ) + break; + if( i == d && (d > 1 || size[1] == 1)) + return; + } + + release(); + if( d == 0 ) + return; + flags = (_type & CV_MAT_TYPE_MASK) | MAGIC_VAL; + setSize(*this, d, _sizes, 0, true); + + if( total() > 0 ) + { +#ifdef HAVE_TGPU + if( !allocator || allocator == tegra::getAllocator() ) allocator = tegra::getAllocator(d, _sizes, _type); +#endif + if( !allocator ) + { + size_t totalsize = alignSize(step.p[0]*size.p[0], (int)sizeof(*refcount)); + data = datastart = (uchar*)fastMalloc(totalsize + (int)sizeof(*refcount)); + refcount = (int*)(data + totalsize); + *refcount = 1; + } + else + { +#ifdef HAVE_TGPU + try + { + allocator->allocate(dims, size, _type, refcount, datastart, data, step.p); + CV_Assert( step[dims-1] == (size_t)CV_ELEM_SIZE(flags) ); + }catch(...) + { + allocator = 0; + size_t totalSize = alignSize(step.p[0]*size.p[0], (int)sizeof(*refcount)); + data = datastart = (uchar*)fastMalloc(totalSize + (int)sizeof(*refcount)); + refcount = (int*)(data + totalSize); + *refcount = 1; + } +#else + allocator->allocate(dims, size, _type, refcount, datastart, data, step.p); + CV_Assert( step[dims-1] == (size_t)CV_ELEM_SIZE(flags) ); +#endif + } + } + + finalizeHdr(*this); +} + +void Mat::copySize(const Mat& m) +{ + setSize(*this, m.dims, 0, 0); + for( int i = 0; i < dims; i++ ) + { + size[i] = m.size[i]; + step[i] = m.step[i]; + } +} + +void Mat::deallocate() +{ + if( allocator ) + allocator->deallocate(refcount, datastart, data); + else + { + CV_DbgAssert(refcount != 0); + fastFree(datastart); + } +} + + +Mat::Mat(const Mat& m, const Range& _rowRange, const Range& _colRange) : size(&rows) +{ + initEmpty(); + CV_Assert( m.dims >= 2 ); + if( m.dims > 2 ) + { + AutoBuffer rs(m.dims); + rs[0] = _rowRange; + rs[1] = _colRange; + for( int i = 2; i < m.dims; i++ ) + rs[i] = Range::all(); + *this = m(rs); + return; + } + + *this = m; + if( _rowRange != Range::all() && _rowRange != Range(0,rows) ) + { + CV_Assert( 0 <= _rowRange.start && _rowRange.start <= _rowRange.end && _rowRange.end <= m.rows ); + rows = _rowRange.size(); + data += step*_rowRange.start; + flags |= SUBMATRIX_FLAG; + } + + if( _colRange != Range::all() && _colRange != Range(0,cols) ) + { + CV_Assert( 0 <= _colRange.start && _colRange.start <= _colRange.end && _colRange.end <= m.cols ); + cols = _colRange.size(); + data += _colRange.start*elemSize(); + flags &= cols < m.cols ? ~CONTINUOUS_FLAG : -1; + flags |= SUBMATRIX_FLAG; + } + + if( rows == 1 ) + flags |= CONTINUOUS_FLAG; + + if( rows <= 0 || cols <= 0 ) + { + release(); + rows = cols = 0; + } +} + + +Mat::Mat(const Mat& m, const Rect& roi) + : flags(m.flags), dims(2), rows(roi.height), cols(roi.width), + data(m.data + roi.y*m.step[0]), refcount(m.refcount), + datastart(m.datastart), dataend(m.dataend), datalimit(m.datalimit), + allocator(m.allocator), size(&rows) +{ + CV_Assert( m.dims <= 2 ); + flags &= roi.width < m.cols ? ~CONTINUOUS_FLAG : -1; + flags |= roi.height == 1 ? CONTINUOUS_FLAG : 0; + + size_t esz = CV_ELEM_SIZE(flags); + data += roi.x*esz; + CV_Assert( 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && + 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows ); + if( refcount ) + CV_XADD(refcount, 1); + if( roi.width < m.cols || roi.height < m.rows ) + flags |= SUBMATRIX_FLAG; + + step[0] = m.step[0]; step[1] = esz; + + if( rows <= 0 || cols <= 0 ) + { + release(); + rows = cols = 0; + } +} + + +Mat::Mat(int _dims, const int* _sizes, int _type, void* _data, const size_t* _steps) : size(&rows) +{ + initEmpty(); + flags |= CV_MAT_TYPE(_type); + data = datastart = (uchar*)_data; + setSize(*this, _dims, _sizes, _steps, true); + finalizeHdr(*this); +} + + +Mat::Mat(const Mat& m, const Range* ranges) : size(&rows) +{ + initEmpty(); + int i, d = m.dims; + + CV_Assert(ranges); + for( i = 0; i < d; i++ ) + { + Range r = ranges[i]; + CV_Assert( r == Range::all() || (0 <= r.start && r.start < r.end && r.end <= m.size[i]) ); + } + *this = m; + for( i = 0; i < d; i++ ) + { + Range r = ranges[i]; + if( r != Range::all() && r != Range(0, size.p[i])) + { + size.p[i] = r.end - r.start; + data += r.start*step.p[i]; + flags |= SUBMATRIX_FLAG; + } + } + updateContinuityFlag(*this); +} + + +Mat::Mat(const CvMatND* m, bool copyData) : size(&rows) +{ + initEmpty(); + if( !m ) + return; + data = datastart = m->data.ptr; + flags |= CV_MAT_TYPE(m->type); + int _sizes[CV_MAX_DIM]; + size_t _steps[CV_MAX_DIM]; + + int i, d = m->dims; + for( i = 0; i < d; i++ ) + { + _sizes[i] = m->dim[i].size; + _steps[i] = m->dim[i].step; + } + + setSize(*this, d, _sizes, _steps); + finalizeHdr(*this); + + if( copyData ) + { + Mat temp(*this); + temp.copyTo(*this); + } +} + + +Mat Mat::diag(int d) const +{ + CV_Assert( dims <= 2 ); + Mat m = *this; + size_t esz = elemSize(); + int len; + + if( d >= 0 ) + { + len = std::min(cols - d, rows); + m.data += esz*d; + } + else + { + len = std::min(rows + d, cols); + m.data -= step[0]*d; + } + CV_DbgAssert( len > 0 ); + + m.size[0] = m.rows = len; + m.size[1] = m.cols = 1; + m.step[0] += (len > 1 ? esz : 0); + + if( m.rows > 1 ) + m.flags &= ~CONTINUOUS_FLAG; + else + m.flags |= CONTINUOUS_FLAG; + + if( size() != Size(1,1) ) + m.flags |= SUBMATRIX_FLAG; + + return m; +} + + +Mat::Mat(const CvMat* m, bool copyData) : size(&rows) +{ + initEmpty(); + + if( !m ) + return; + + if( !copyData ) + { + flags = MAGIC_VAL + (m->type & (CV_MAT_TYPE_MASK|CV_MAT_CONT_FLAG)); + dims = 2; + rows = m->rows; + cols = m->cols; + data = datastart = m->data.ptr; + size_t esz = CV_ELEM_SIZE(m->type), minstep = cols*esz, _step = m->step; + if( _step == 0 ) + _step = minstep; + datalimit = datastart + _step*rows; + dataend = datalimit - _step + minstep; + step[0] = _step; step[1] = esz; + } + else + { + data = datastart = dataend = 0; + Mat(m->rows, m->cols, m->type, m->data.ptr, m->step).copyTo(*this); + } +} + + +Mat::Mat(const IplImage* img, bool copyData) : size(&rows) +{ + initEmpty(); + + if( !img ) + return; + + dims = 2; + CV_DbgAssert(CV_IS_IMAGE(img) && img->imageData != 0); + + int imgdepth = IPL2CV_DEPTH(img->depth); + size_t esz; + step[0] = img->widthStep; + + if(!img->roi) + { + CV_Assert(img->dataOrder == IPL_DATA_ORDER_PIXEL); + flags = MAGIC_VAL + CV_MAKETYPE(imgdepth, img->nChannels); + rows = img->height; cols = img->width; + datastart = data = (uchar*)img->imageData; + esz = CV_ELEM_SIZE(flags); + } + else + { + CV_Assert(img->dataOrder == IPL_DATA_ORDER_PIXEL || img->roi->coi != 0); + bool selectedPlane = img->roi->coi && img->dataOrder == IPL_DATA_ORDER_PLANE; + flags = MAGIC_VAL + CV_MAKETYPE(imgdepth, selectedPlane ? 1 : img->nChannels); + rows = img->roi->height; cols = img->roi->width; + esz = CV_ELEM_SIZE(flags); + data = datastart = (uchar*)img->imageData + + (selectedPlane ? (img->roi->coi - 1)*step*img->height : 0) + + img->roi->yOffset*step[0] + img->roi->xOffset*esz; + } + datalimit = datastart + step.p[0]*rows; + dataend = datastart + step.p[0]*(rows-1) + esz*cols; + flags |= (cols*esz == step.p[0] || rows == 1 ? CONTINUOUS_FLAG : 0); + step[1] = esz; + + if( copyData ) + { + Mat m = *this; + release(); + if( !img->roi || !img->roi->coi || + img->dataOrder == IPL_DATA_ORDER_PLANE) + m.copyTo(*this); + else + { + int ch[] = {img->roi->coi - 1, 0}; + create(m.rows, m.cols, m.type()); + mixChannels(&m, 1, this, 1, ch, 1); + } + } +} + + +Mat::operator IplImage() const +{ + CV_Assert( dims <= 2 ); + IplImage img; + cvInitImageHeader(&img, size(), cvIplDepth(flags), channels()); + cvSetData(&img, data, (int)step[0]); + return img; +} + + +void Mat::pop_back(size_t nelems) +{ + CV_Assert( nelems <= (size_t)size.p[0] ); + + if( isSubmatrix() ) + *this = rowRange(0, size.p[0] - (int)nelems); + else + { + size.p[0] -= (int)nelems; + dataend -= nelems*step.p[0]; + /*if( size.p[0] <= 1 ) + { + if( dims <= 2 ) + flags |= CONTINUOUS_FLAG; + else + updateContinuityFlag(*this); + }*/ + } +} + + +void Mat::push_back_(const void* elem) +{ + int r = size.p[0]; + if( isSubmatrix() || dataend + step.p[0] > datalimit ) + reserve( std::max(r + 1, (r*3+1)/2) ); + + size_t esz = elemSize(); + memcpy(data + r*step.p[0], elem, esz); + size.p[0] = r + 1; + dataend += step.p[0]; + if( esz < step.p[0] ) + flags &= ~CONTINUOUS_FLAG; +} + +void Mat::reserve(size_t nelems) +{ + const size_t MIN_SIZE = 64; + + CV_Assert( (int)nelems >= 0 ); + if( !isSubmatrix() && data + step.p[0]*nelems <= datalimit ) + return; + + int r = size.p[0]; + + if( (size_t)r >= nelems ) + return; + + size.p[0] = std::max((int)nelems, 1); + size_t newsize = total()*elemSize(); + + if( newsize < MIN_SIZE ) + size.p[0] = (int)((MIN_SIZE + newsize - 1)*nelems/newsize); + + Mat m(dims, size.p, type()); + size.p[0] = r; + if( r > 0 ) + { + Mat mpart = m.rowRange(0, r); + copyTo(mpart); + } + + *this = m; + size.p[0] = r; + dataend = data + step.p[0]*r; +} + + +void Mat::resize(size_t nelems) +{ + int saveRows = size.p[0]; + if( saveRows == (int)nelems ) + return; + CV_Assert( (int)nelems >= 0 ); + + if( isSubmatrix() || data + step.p[0]*nelems > datalimit ) + reserve(nelems); + + size.p[0] = (int)nelems; + dataend += (size.p[0] - saveRows)*step.p[0]; + + //updateContinuityFlag(*this); +} + + +void Mat::resize(size_t nelems, const Scalar& s) +{ + int saveRows = size.p[0]; + resize(nelems); + + if( size.p[0] > saveRows ) + { + Mat part = rowRange(saveRows, size.p[0]); + part = s; + } +} + +void Mat::push_back(const Mat& elems) +{ + int r = size.p[0], delta = elems.size.p[0]; + if( delta == 0 ) + return; + if( this == &elems ) + { + Mat tmp = elems; + push_back(tmp); + return; + } + if( !data ) + { + *this = elems.clone(); + return; + } + + size.p[0] = elems.size.p[0]; + bool eq = size == elems.size; + size.p[0] = r; + if( !eq ) + CV_Error(CV_StsUnmatchedSizes, ""); + if( type() != elems.type() ) + CV_Error(CV_StsUnmatchedFormats, ""); + + if( isSubmatrix() || dataend + step.p[0]*delta > datalimit ) + reserve( std::max(r + delta, (r*3+1)/2) ); + + size.p[0] += delta; + dataend += step.p[0]*delta; + + //updateContinuityFlag(*this); + + if( isContinuous() && elems.isContinuous() ) + memcpy(data + r*step.p[0], elems.data, elems.total()*elems.elemSize()); + else + { + Mat part = rowRange(r, r + delta); + elems.copyTo(part); + } +} + + +Mat cvarrToMat(const CvArr* arr, bool copyData, + bool /*allowND*/, int coiMode) +{ + if( !arr ) + return Mat(); + if( CV_IS_MAT(arr) ) + return Mat((const CvMat*)arr, copyData ); + if( CV_IS_MATND(arr) ) + return Mat((const CvMatND*)arr, copyData ); + if( CV_IS_IMAGE(arr) ) + { + const IplImage* iplimg = (const IplImage*)arr; + if( coiMode == 0 && iplimg->roi && iplimg->roi->coi > 0 ) + CV_Error(CV_BadCOI, "COI is not supported by the function"); + return Mat(iplimg, copyData); + } + if( CV_IS_SEQ(arr) ) + { + CvSeq* seq = (CvSeq*)arr; + CV_Assert(seq->total > 0 && CV_ELEM_SIZE(seq->flags) == seq->elem_size); + if(!copyData && seq->first->next == seq->first) + return Mat(seq->total, 1, CV_MAT_TYPE(seq->flags), seq->first->data); + Mat buf(seq->total, 1, CV_MAT_TYPE(seq->flags)); + cvCvtSeqToArray(seq, buf.data, CV_WHOLE_SEQ); + return buf; + } + CV_Error(CV_StsBadArg, "Unknown array type"); + return Mat(); +} + +void Mat::locateROI( Size& wholeSize, Point& ofs ) const +{ + CV_Assert( dims <= 2 && step[0] > 0 ); + size_t esz = elemSize(), minstep; + ptrdiff_t delta1 = data - datastart, delta2 = dataend - datastart; + + if( delta1 == 0 ) + ofs.x = ofs.y = 0; + else + { + ofs.y = (int)(delta1/step[0]); + ofs.x = (int)((delta1 - step[0]*ofs.y)/esz); + CV_DbgAssert( data == datastart + ofs.y*step[0] + ofs.x*esz ); + } + minstep = (ofs.x + cols)*esz; + wholeSize.height = (int)((delta2 - minstep)/step[0] + 1); + wholeSize.height = std::max(wholeSize.height, ofs.y + rows); + wholeSize.width = (int)((delta2 - step*(wholeSize.height-1))/esz); + wholeSize.width = std::max(wholeSize.width, ofs.x + cols); +} + +Mat& Mat::adjustROI( int dtop, int dbottom, int dleft, int dright ) +{ + CV_Assert( dims <= 2 && step[0] > 0 ); + Size wholeSize; Point ofs; + size_t esz = elemSize(); + locateROI( wholeSize, ofs ); + int row1 = std::max(ofs.y - dtop, 0), row2 = std::min(ofs.y + rows + dbottom, wholeSize.height); + int col1 = std::max(ofs.x - dleft, 0), col2 = std::min(ofs.x + cols + dright, wholeSize.width); + data += (row1 - ofs.y)*step + (col1 - ofs.x)*esz; + rows = row2 - row1; cols = col2 - col1; + size.p[0] = rows; size.p[1] = cols; + if( esz*cols == step[0] || rows == 1 ) + flags |= CONTINUOUS_FLAG; + else + flags &= ~CONTINUOUS_FLAG; + return *this; +} + +} + +void cv::extractImageCOI(const CvArr* arr, OutputArray _ch, int coi) +{ + Mat mat = cvarrToMat(arr, false, true, 1); + _ch.create(mat.dims, mat.size, mat.depth()); + Mat ch = _ch.getMat(); + if(coi < 0) + { + CV_Assert( CV_IS_IMAGE(arr) ); + coi = cvGetImageCOI((const IplImage*)arr)-1; + } + CV_Assert(0 <= coi && coi < mat.channels()); + int _pairs[] = { coi, 0 }; + mixChannels( &mat, 1, &ch, 1, _pairs, 1 ); +} + +void cv::insertImageCOI(InputArray _ch, CvArr* arr, int coi) +{ + Mat ch = _ch.getMat(), mat = cvarrToMat(arr, false, true, 1); + if(coi < 0) + { + CV_Assert( CV_IS_IMAGE(arr) ); + coi = cvGetImageCOI((const IplImage*)arr)-1; + } + CV_Assert(ch.size == mat.size && ch.depth() == mat.depth() && 0 <= coi && coi < mat.channels()); + int _pairs[] = { 0, coi }; + mixChannels( &ch, 1, &mat, 1, _pairs, 1 ); +} + +namespace cv +{ + +Mat Mat::reshape(int new_cn, int new_rows) const +{ + int cn = channels(); + Mat hdr = *this; + + if( dims > 2 && new_rows == 0 && new_cn != 0 && size[dims-1]*cn % new_cn == 0 ) + { + hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((new_cn-1) << CV_CN_SHIFT); + hdr.step[dims-1] = CV_ELEM_SIZE(hdr.flags); + hdr.size[dims-1] = hdr.size[dims-1]*cn / new_cn; + return hdr; + } + + CV_Assert( dims <= 2 ); + + if( new_cn == 0 ) + new_cn = cn; + + int total_width = cols * cn; + + if( (new_cn > total_width || total_width % new_cn != 0) && new_rows == 0 ) + new_rows = rows * total_width / new_cn; + + if( new_rows != 0 && new_rows != rows ) + { + int total_size = total_width * rows; + if( !isContinuous() ) + CV_Error( CV_BadStep, + "The matrix is not continuous, thus its number of rows can not be changed" ); + + if( (unsigned)new_rows > (unsigned)total_size ) + CV_Error( CV_StsOutOfRange, "Bad new number of rows" ); + + total_width = total_size / new_rows; + + if( total_width * new_rows != total_size ) + CV_Error( CV_StsBadArg, "The total number of matrix elements " + "is not divisible by the new number of rows" ); + + hdr.rows = new_rows; + hdr.step[0] = total_width * elemSize1(); + } + + int new_width = total_width / new_cn; + + if( new_width * new_cn != total_width ) + CV_Error( CV_BadNumChannels, + "The total width is not divisible by the new number of channels" ); + + hdr.cols = new_width; + hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((new_cn-1) << CV_CN_SHIFT); + hdr.step[1] = CV_ELEM_SIZE(hdr.flags); + return hdr; +} + + +int Mat::checkVector(int _elemChannels, int _depth, bool _requireContinuous) const +{ + return (depth() == _depth || _depth <= 0) && + (isContinuous() || !_requireContinuous) && + ((dims == 2 && (((rows == 1 || cols == 1) && channels() == _elemChannels) || (cols == _elemChannels))) || + (dims == 3 && channels() == 1 && size.p[2] == _elemChannels && (size.p[0] == 1 || size.p[1] == 1) && + (isContinuous() || step.p[1] == step.p[2]*size.p[2]))) + ? (int)(total()*channels()/_elemChannels) : -1; +} + + +void scalarToRawData(const Scalar& s, void* _buf, int type, int unroll_to) +{ + int i, depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); + CV_Assert(cn <= 4); + switch(depth) + { + case CV_8U: + { + uchar* buf = (uchar*)_buf; + for(i = 0; i < cn; i++) + buf[i] = saturate_cast(s.val[i]); + for(; i < unroll_to; i++) + buf[i] = buf[i-cn]; + } + break; + case CV_8S: + { + schar* buf = (schar*)_buf; + for(i = 0; i < cn; i++) + buf[i] = saturate_cast(s.val[i]); + for(; i < unroll_to; i++) + buf[i] = buf[i-cn]; + } + break; + case CV_16U: + { + ushort* buf = (ushort*)_buf; + for(i = 0; i < cn; i++) + buf[i] = saturate_cast(s.val[i]); + for(; i < unroll_to; i++) + buf[i] = buf[i-cn]; + } + break; + case CV_16S: + { + short* buf = (short*)_buf; + for(i = 0; i < cn; i++) + buf[i] = saturate_cast(s.val[i]); + for(; i < unroll_to; i++) + buf[i] = buf[i-cn]; + } + break; + case CV_32S: + { + int* buf = (int*)_buf; + for(i = 0; i < cn; i++) + buf[i] = saturate_cast(s.val[i]); + for(; i < unroll_to; i++) + buf[i] = buf[i-cn]; + } + break; + case CV_32F: + { + float* buf = (float*)_buf; + for(i = 0; i < cn; i++) + buf[i] = saturate_cast(s.val[i]); + for(; i < unroll_to; i++) + buf[i] = buf[i-cn]; + } + break; + case CV_64F: + { + double* buf = (double*)_buf; + for(i = 0; i < cn; i++) + buf[i] = saturate_cast(s.val[i]); + for(; i < unroll_to; i++) + buf[i] = buf[i-cn]; + break; + } + default: + CV_Error(CV_StsUnsupportedFormat,""); + } +} + + +/*************************************************************************************************\ + Input/Output Array +\*************************************************************************************************/ + +_InputArray::_InputArray() : flags(0), obj(0) {} +_InputArray::~_InputArray() {} +_InputArray::_InputArray(const Mat& m) : flags(MAT), obj((void*)&m) {} +_InputArray::_InputArray(const vector& vec) : flags(STD_VECTOR_MAT), obj((void*)&vec) {} +_InputArray::_InputArray(const double& val) : flags(FIXED_TYPE + FIXED_SIZE + MATX + CV_64F), obj((void*)&val), sz(Size(1,1)) {} +_InputArray::_InputArray(const MatExpr& expr) : flags(FIXED_TYPE + FIXED_SIZE + EXPR), obj((void*)&expr) {} +_InputArray::_InputArray(const GlBuffer& buf) : flags(FIXED_TYPE + FIXED_SIZE + OPENGL_BUFFER), obj((void*)&buf) {} +_InputArray::_InputArray(const GlTexture& tex) : flags(FIXED_TYPE + FIXED_SIZE + OPENGL_TEXTURE), obj((void*)&tex) {} +_InputArray::_InputArray(const gpu::GpuMat& d_mat) : flags(GPU_MAT), obj((void*)&d_mat) {} + +Mat _InputArray::getMat(int i) const +{ + int k = kind(); + + if( k == MAT ) + { + const Mat* m = (const Mat*)obj; + if( i < 0 ) + return *m; + return m->row(i); + } + + if( k == EXPR ) + { + CV_Assert( i < 0 ); + return (Mat)*((const MatExpr*)obj); + } + + if( k == MATX ) + { + CV_Assert( i < 0 ); + return Mat(sz, flags, obj); + } + + if( k == STD_VECTOR ) + { + CV_Assert( i < 0 ); + int t = CV_MAT_TYPE(flags); + const vector& v = *(const vector*)obj; + + return !v.empty() ? Mat(size(), t, (void*)&v[0]) : Mat(); + } + + if( k == NONE ) + return Mat(); + + if( k == STD_VECTOR_VECTOR ) + { + int t = type(i); + const vector >& vv = *(const vector >*)obj; + CV_Assert( 0 <= i && i < (int)vv.size() ); + const vector& v = vv[i]; + + return !v.empty() ? Mat(size(i), t, (void*)&v[0]) : Mat(); + } + + CV_Assert( k == STD_VECTOR_MAT ); + //if( k == STD_VECTOR_MAT ) + { + const vector& v = *(const vector*)obj; + CV_Assert( 0 <= i && i < (int)v.size() ); + + return v[i]; + } +} + + +void _InputArray::getMatVector(vector& mv) const +{ + int k = kind(); + + if( k == MAT ) + { + const Mat& m = *(const Mat*)obj; + int i, n = (int)m.size[0]; + mv.resize(n); + + for( i = 0; i < n; i++ ) + mv[i] = m.dims == 2 ? Mat(1, m.cols, m.type(), (void*)m.ptr(i)) : + Mat(m.dims-1, &m.size[1], m.type(), (void*)m.ptr(i), &m.step[1]); + return; + } + + if( k == EXPR ) + { + Mat m = *(const MatExpr*)obj; + int i, n = m.size[0]; + mv.resize(n); + + for( i = 0; i < n; i++ ) + mv[i] = m.row(i); + return; + } + + if( k == MATX ) + { + size_t i, n = sz.height, esz = CV_ELEM_SIZE(flags); + mv.resize(n); + + for( i = 0; i < n; i++ ) + mv[i] = Mat(1, sz.width, CV_MAT_TYPE(flags), (uchar*)obj + esz*sz.width*i); + return; + } + + if( k == STD_VECTOR ) + { + const vector& v = *(const vector*)obj; + + size_t i, n = v.size(), esz = CV_ELEM_SIZE(flags); + int t = CV_MAT_DEPTH(flags), cn = CV_MAT_CN(flags); + mv.resize(n); + + for( i = 0; i < n; i++ ) + mv[i] = Mat(1, cn, t, (void*)(&v[0] + esz*i)); + return; + } + + if( k == NONE ) + { + mv.clear(); + return; + } + + if( k == STD_VECTOR_VECTOR ) + { + const vector >& vv = *(const vector >*)obj; + int i, n = (int)vv.size(); + int t = CV_MAT_TYPE(flags); + mv.resize(n); + + for( i = 0; i < n; i++ ) + { + const vector& v = vv[i]; + mv[i] = Mat(size(i), t, (void*)&v[0]); + } + return; + } + + CV_Assert( k == STD_VECTOR_MAT ); + //if( k == STD_VECTOR_MAT ) + { + const vector& v = *(const vector*)obj; + mv.resize(v.size()); + std::copy(v.begin(), v.end(), mv.begin()); + return; + } +} + +GlBuffer _InputArray::getGlBuffer() const +{ + int k = kind(); + + CV_Assert(k == OPENGL_BUFFER); + //if( k == OPENGL_BUFFER ) + { + const GlBuffer* buf = (const GlBuffer*)obj; + return *buf; + } +} + +GlTexture _InputArray::getGlTexture() const +{ + int k = kind(); + + CV_Assert(k == OPENGL_TEXTURE); + //if( k == OPENGL_TEXTURE ) + { + const GlTexture* tex = (const GlTexture*)obj; + return *tex; + } +} + +gpu::GpuMat _InputArray::getGpuMat() const +{ + int k = kind(); + + CV_Assert(k == GPU_MAT); + //if( k == GPU_MAT ) + { + const gpu::GpuMat* d_mat = (const gpu::GpuMat*)obj; + return *d_mat; + } +} + +int _InputArray::kind() const +{ + return flags & KIND_MASK; +} + +Size _InputArray::size(int i) const +{ + int k = kind(); + + if( k == MAT ) + { + CV_Assert( i < 0 ); + return ((const Mat*)obj)->size(); + } + + if( k == EXPR ) + { + CV_Assert( i < 0 ); + return ((const MatExpr*)obj)->size(); + } + + if( k == MATX ) + { + CV_Assert( i < 0 ); + return sz; + } + + if( k == STD_VECTOR ) + { + CV_Assert( i < 0 ); + const vector& v = *(const vector*)obj; + const vector& iv = *(const vector*)obj; + size_t szb = v.size(), szi = iv.size(); + return szb == szi ? Size((int)szb, 1) : Size((int)(szb/CV_ELEM_SIZE(flags)), 1); + } + + if( k == NONE ) + return Size(); + + if( k == STD_VECTOR_VECTOR ) + { + const vector >& vv = *(const vector >*)obj; + if( i < 0 ) + return vv.empty() ? Size() : Size((int)vv.size(), 1); + CV_Assert( i < (int)vv.size() ); + const vector >& ivv = *(const vector >*)obj; + + size_t szb = vv[i].size(), szi = ivv[i].size(); + return szb == szi ? Size((int)szb, 1) : Size((int)(szb/CV_ELEM_SIZE(flags)), 1); + } + + if( k == STD_VECTOR_MAT ) + { + const vector& vv = *(const vector*)obj; + if( i < 0 ) + return vv.empty() ? Size() : Size((int)vv.size(), 1); + CV_Assert( i < (int)vv.size() ); + + return vv[i].size(); + } + + if( k == OPENGL_BUFFER ) + { + CV_Assert( i < 0 ); + const GlBuffer* buf = (const GlBuffer*)obj; + return buf->size(); + } + + if( k == OPENGL_TEXTURE ) + { + CV_Assert( i < 0 ); + const GlTexture* tex = (const GlTexture*)obj; + return tex->size(); + } + + CV_Assert( k == GPU_MAT ); + //if( k == GPU_MAT ) + { + CV_Assert( i < 0 ); + const gpu::GpuMat* d_mat = (const gpu::GpuMat*)obj; + return d_mat->size(); + } +} + +size_t _InputArray::total(int i) const +{ + return size(i).area(); +} + +int _InputArray::type(int i) const +{ + int k = kind(); + + if( k == MAT ) + return ((const Mat*)obj)->type(); + + if( k == EXPR ) + return ((const MatExpr*)obj)->type(); + + if( k == MATX || k == STD_VECTOR || k == STD_VECTOR_VECTOR ) + return CV_MAT_TYPE(flags); + + if( k == NONE ) + return -1; + + if( k == STD_VECTOR_MAT ) + { + const vector& vv = *(const vector*)obj; + CV_Assert( i < (int)vv.size() ); + + return vv[i >= 0 ? i : 0].type(); + } + + if( k == OPENGL_BUFFER ) + return ((const GlBuffer*)obj)->type(); + + if( k == OPENGL_TEXTURE ) + return ((const GlTexture*)obj)->type(); + + CV_Assert( k == GPU_MAT ); + //if( k == GPU_MAT ) + return ((const gpu::GpuMat*)obj)->type(); +} + +int _InputArray::depth(int i) const +{ + return CV_MAT_DEPTH(type(i)); +} + +int _InputArray::channels(int i) const +{ + return CV_MAT_CN(type(i)); +} + +bool _InputArray::empty() const +{ + int k = kind(); + + if( k == MAT ) + return ((const Mat*)obj)->empty(); + + if( k == EXPR ) + return false; + + if( k == MATX ) + return false; + + if( k == STD_VECTOR ) + { + const vector& v = *(const vector*)obj; + return v.empty(); + } + + if( k == NONE ) + return true; + + if( k == STD_VECTOR_VECTOR ) + { + const vector >& vv = *(const vector >*)obj; + return vv.empty(); + } + + if( k == STD_VECTOR_MAT ) + { + const vector& vv = *(const vector*)obj; + return vv.empty(); + } + + if( k == OPENGL_BUFFER ) + return ((const GlBuffer*)obj)->empty(); + + if( k == OPENGL_TEXTURE ) + return ((const GlTexture*)obj)->empty(); + + CV_Assert( k == GPU_MAT ); + //if( k == GPU_MAT ) + return ((const gpu::GpuMat*)obj)->empty(); +} + + +_OutputArray::_OutputArray() {} +_OutputArray::~_OutputArray() {} +_OutputArray::_OutputArray(Mat& m) : _InputArray(m) {} +_OutputArray::_OutputArray(vector& vec) : _InputArray(vec) {} + +_OutputArray::_OutputArray(const Mat& m) : _InputArray(m) {flags |= FIXED_SIZE|FIXED_TYPE;} +_OutputArray::_OutputArray(const vector& vec) : _InputArray(vec) {flags |= FIXED_SIZE;} + + +bool _OutputArray::fixedSize() const +{ + return (flags & FIXED_SIZE) == FIXED_SIZE; +} + +bool _OutputArray::fixedType() const +{ + return (flags & FIXED_TYPE) == FIXED_TYPE; +} + +void _OutputArray::create(Size _sz, int mtype, int i, bool allowTransposed, int fixedDepthMask) const +{ + int k = kind(); + if( k == MAT && i < 0 && !allowTransposed && fixedDepthMask == 0 ) + { + CV_Assert(!fixedSize() || ((Mat*)obj)->size.operator()() == _sz); + CV_Assert(!fixedType() || ((Mat*)obj)->type() == mtype); + ((Mat*)obj)->create(_sz, mtype); + return; + } + int sizes[] = {_sz.height, _sz.width}; + create(2, sizes, mtype, i, allowTransposed, fixedDepthMask); +} + +void _OutputArray::create(int rows, int cols, int mtype, int i, bool allowTransposed, int fixedDepthMask) const +{ + int k = kind(); + if( k == MAT && i < 0 && !allowTransposed && fixedDepthMask == 0 ) + { + CV_Assert(!fixedSize() || ((Mat*)obj)->size.operator()() == Size(cols, rows)); + CV_Assert(!fixedType() || ((Mat*)obj)->type() == mtype); + ((Mat*)obj)->create(rows, cols, mtype); + return; + } + int sizes[] = {rows, cols}; + create(2, sizes, mtype, i, allowTransposed, fixedDepthMask); +} + +void _OutputArray::create(int dims, const int* sizes, int mtype, int i, bool allowTransposed, int fixedDepthMask) const +{ + int k = kind(); + mtype = CV_MAT_TYPE(mtype); + + if( k == MAT ) + { + CV_Assert( i < 0 ); + Mat& m = *(Mat*)obj; + if( allowTransposed ) + { + if( !m.isContinuous() ) + { + CV_Assert(!fixedType() && !fixedSize()); + m.release(); + } + + if( dims == 2 && m.dims == 2 && m.data && + m.type() == mtype && m.rows == sizes[1] && m.cols == sizes[0] ) + return; + } + + if(fixedType()) + { + if(CV_MAT_CN(mtype) == m.channels() && ((1 << CV_MAT_TYPE(flags)) & fixedDepthMask) != 0 ) + mtype = m.type(); + else + CV_Assert(CV_MAT_TYPE(mtype) == m.type()); + } + if(fixedSize()) + { + CV_Assert(m.dims == dims); + for(int j = 0; j < dims; ++j) + CV_Assert(m.size[j] == sizes[j]); + } + m.create(dims, sizes, mtype); + return; + } + + if( k == MATX ) + { + CV_Assert( i < 0 ); + int type0 = CV_MAT_TYPE(flags); + CV_Assert( mtype == type0 || (CV_MAT_CN(mtype) == 1 && ((1 << type0) & fixedDepthMask) != 0) ); + CV_Assert( dims == 2 && ((sizes[0] == sz.height && sizes[1] == sz.width) || + (allowTransposed && sizes[0] == sz.width && sizes[1] == sz.height))); + return; + } + + if( k == STD_VECTOR || k == STD_VECTOR_VECTOR ) + { + CV_Assert( dims == 2 && (sizes[0] == 1 || sizes[1] == 1 || sizes[0]*sizes[1] == 0) ); + size_t len = sizes[0]*sizes[1] > 0 ? sizes[0] + sizes[1] - 1 : 0; + vector* v = (vector*)obj; + + if( k == STD_VECTOR_VECTOR ) + { + vector >& vv = *(vector >*)obj; + if( i < 0 ) + { + CV_Assert(!fixedSize() || len == vv.size()); + vv.resize(len); + return; + } + CV_Assert( i < (int)vv.size() ); + v = &vv[i]; + } + else + CV_Assert( i < 0 ); + + int type0 = CV_MAT_TYPE(flags); + CV_Assert( mtype == type0 || (CV_MAT_CN(mtype) == CV_MAT_CN(type0) && ((1 << type0) & fixedDepthMask) != 0) ); + + int esz = CV_ELEM_SIZE(type0); + CV_Assert(!fixedSize() || len == ((vector*)v)->size() / esz); + switch( esz ) + { + case 1: + ((vector*)v)->resize(len); + break; + case 2: + ((vector*)v)->resize(len); + break; + case 3: + ((vector*)v)->resize(len); + break; + case 4: + ((vector*)v)->resize(len); + break; + case 6: + ((vector*)v)->resize(len); + break; + case 8: + ((vector*)v)->resize(len); + break; + case 12: + ((vector*)v)->resize(len); + break; + case 16: + ((vector*)v)->resize(len); + break; + case 24: + ((vector*)v)->resize(len); + break; + case 32: + ((vector*)v)->resize(len); + break; + case 36: + ((vector >*)v)->resize(len); + break; + case 48: + ((vector >*)v)->resize(len); + break; + case 64: + ((vector >*)v)->resize(len); + break; + case 128: + ((vector >*)v)->resize(len); + break; + case 256: + ((vector >*)v)->resize(len); + break; + case 512: + ((vector >*)v)->resize(len); + break; + default: + CV_Error_(CV_StsBadArg, ("Vectors with element size %d are not supported. Please, modify OutputArray::create()\n", esz)); + } + return; + } + + if( k == NONE ) + { + CV_Error(CV_StsNullPtr, "create() called for the missing output array" ); + return; + } + + CV_Assert( k == STD_VECTOR_MAT ); + //if( k == STD_VECTOR_MAT ) + { + vector& v = *(vector*)obj; + + if( i < 0 ) + { + CV_Assert( dims == 2 && (sizes[0] == 1 || sizes[1] == 1 || sizes[0]*sizes[1] == 0) ); + size_t len = sizes[0]*sizes[1] > 0 ? sizes[0] + sizes[1] - 1 : 0, len0 = v.size(); + + CV_Assert(!fixedSize() || len == len0); + v.resize(len); + if( fixedType() ) + { + int _type = CV_MAT_TYPE(flags); + for( size_t j = len0; j < len; j++ ) + { + if( v[i].type() == _type ) + continue; + CV_Assert( v[i].empty() ); + v[i].flags = (v[i].flags & ~CV_MAT_TYPE_MASK) | _type; + } + } + return; + } + + CV_Assert( i < (int)v.size() ); + Mat& m = v[i]; + + if( allowTransposed ) + { + if( !m.isContinuous() ) + { + CV_Assert(!fixedType() && !fixedSize()); + m.release(); + } + + if( dims == 2 && m.dims == 2 && m.data && + m.type() == mtype && m.rows == sizes[1] && m.cols == sizes[0] ) + return; + } + + if(fixedType()) + { + if(CV_MAT_CN(mtype) == m.channels() && ((1 << CV_MAT_TYPE(flags)) & fixedDepthMask) != 0 ) + mtype = m.type(); + else + CV_Assert(!fixedType() || (CV_MAT_CN(mtype) == m.channels() && ((1 << CV_MAT_TYPE(flags)) & fixedDepthMask) != 0)); + } + if(fixedSize()) + { + CV_Assert(m.dims == dims); + for(int j = 0; j < dims; ++j) + CV_Assert(m.size[j] == sizes[j]); + } + + m.create(dims, sizes, mtype); + } +} + +void _OutputArray::release() const +{ + CV_Assert(!fixedSize()); + + int k = kind(); + + if( k == MAT ) + { + ((Mat*)obj)->release(); + return; + } + + if( k == NONE ) + return; + + if( k == STD_VECTOR ) + { + create(Size(), CV_MAT_TYPE(flags)); + return; + } + + if( k == STD_VECTOR_VECTOR ) + { + ((vector >*)obj)->clear(); + return; + } + + CV_Assert( k == STD_VECTOR_MAT ); + //if( k == STD_VECTOR_MAT ) + { + ((vector*)obj)->clear(); + } +} + +void _OutputArray::clear() const +{ + int k = kind(); + + if( k == MAT ) + { + CV_Assert(!fixedSize()); + ((Mat*)obj)->resize(0); + return; + } + + release(); +} + +bool _OutputArray::needed() const +{ + return kind() != NONE; +} + +Mat& _OutputArray::getMatRef(int i) const +{ + int k = kind(); + if( i < 0 ) + { + CV_Assert( k == MAT ); + return *(Mat*)obj; + } + else + { + CV_Assert( k == STD_VECTOR_MAT ); + vector& v = *(vector*)obj; + CV_Assert( i < (int)v.size() ); + return v[i]; + } +} + +static _OutputArray _none; +OutputArray noArray() { return _none; } + +} + +/*************************************************************************************************\ + Matrix Operations +\*************************************************************************************************/ + +void cv::hconcat(const Mat* src, size_t nsrc, OutputArray _dst) +{ + if( nsrc == 0 || !src ) + { + _dst.release(); + return; + } + + int totalCols = 0, cols = 0; + size_t i; + for( i = 0; i < nsrc; i++ ) + { + CV_Assert( !src[i].empty() && src[i].dims <= 2 && + src[i].rows == src[0].rows && + src[i].type() == src[0].type()); + totalCols += src[i].cols; + } + _dst.create( src[0].rows, totalCols, src[0].type()); + Mat dst = _dst.getMat(); + for( i = 0; i < nsrc; i++ ) + { + Mat dpart = dst(Rect(cols, 0, src[i].cols, src[i].rows)); + src[i].copyTo(dpart); + cols += src[i].cols; + } +} + +void cv::hconcat(InputArray src1, InputArray src2, OutputArray dst) +{ + Mat src[] = {src1.getMat(), src2.getMat()}; + hconcat(src, 2, dst); +} + +void cv::hconcat(InputArray _src, OutputArray dst) +{ + vector src; + _src.getMatVector(src); + hconcat(!src.empty() ? &src[0] : 0, src.size(), dst); +} + +void cv::vconcat(const Mat* src, size_t nsrc, OutputArray _dst) +{ + if( nsrc == 0 || !src ) + { + _dst.release(); + return; + } + + int totalRows = 0, rows = 0; + size_t i; + for( i = 0; i < nsrc; i++ ) + { + CV_Assert( !src[i].empty() && src[i].dims <= 2 && + src[i].cols == src[0].cols && + src[i].type() == src[0].type()); + totalRows += src[i].rows; + } + _dst.create( totalRows, src[0].cols, src[0].type()); + Mat dst = _dst.getMat(); + for( i = 0; i < nsrc; i++ ) + { + Mat dpart(dst, Rect(0, rows, src[i].cols, src[i].rows)); + src[i].copyTo(dpart); + rows += src[i].rows; + } +} + +void cv::vconcat(InputArray src1, InputArray src2, OutputArray dst) +{ + Mat src[] = {src1.getMat(), src2.getMat()}; + vconcat(src, 2, dst); +} + +void cv::vconcat(InputArray _src, OutputArray dst) +{ + vector src; + _src.getMatVector(src); + vconcat(!src.empty() ? &src[0] : 0, src.size(), dst); +} + +//////////////////////////////////////// set identity //////////////////////////////////////////// +void cv::setIdentity( InputOutputArray _m, const Scalar& s ) +{ + Mat m = _m.getMat(); + CV_Assert( m.dims <= 2 ); + int i, j, rows = m.rows, cols = m.cols, type = m.type(); + + if( type == CV_32FC1 ) + { + float* data = (float*)m.data; + float val = (float)s[0]; + size_t step = m.step/sizeof(data[0]); + + for( i = 0; i < rows; i++, data += step ) + { + for( j = 0; j < cols; j++ ) + data[j] = 0; + if( i < cols ) + data[i] = val; + } + } + else if( type == CV_64FC1 ) + { + double* data = (double*)m.data; + double val = s[0]; + size_t step = m.step/sizeof(data[0]); + + for( i = 0; i < rows; i++, data += step ) + { + for( j = 0; j < cols; j++ ) + data[j] = j == i ? val : 0; + } + } + else + { + m = Scalar(0); + m.diag() = s; + } +} + +//////////////////////////////////////////// trace /////////////////////////////////////////// + +cv::Scalar cv::trace( InputArray _m ) +{ + Mat m = _m.getMat(); + CV_Assert( m.dims <= 2 ); + int i, type = m.type(); + int nm = std::min(m.rows, m.cols); + + if( type == CV_32FC1 ) + { + const float* ptr = (const float*)m.data; + size_t step = m.step/sizeof(ptr[0]) + 1; + double _s = 0; + for( i = 0; i < nm; i++ ) + _s += ptr[i*step]; + return _s; + } + + if( type == CV_64FC1 ) + { + const double* ptr = (const double*)m.data; + size_t step = m.step/sizeof(ptr[0]) + 1; + double _s = 0; + for( i = 0; i < nm; i++ ) + _s += ptr[i*step]; + return _s; + } + + return cv::sum(m.diag()); +} + +////////////////////////////////////// transpose ///////////////////////////////////////// + +namespace cv +{ + +template static void +transpose_( const uchar* src, size_t sstep, uchar* dst, size_t dstep, Size sz ) +{ + int i=0, j, m = sz.width, n = sz.height; + + #if CV_ENABLE_UNROLLED + for(; i <= m - 4; i += 4 ) + { + T* d0 = (T*)(dst + dstep*i); + T* d1 = (T*)(dst + dstep*(i+1)); + T* d2 = (T*)(dst + dstep*(i+2)); + T* d3 = (T*)(dst + dstep*(i+3)); + + for( j = 0; j <= n - 4; j += 4 ) + { + const T* s0 = (const T*)(src + i*sizeof(T) + sstep*j); + const T* s1 = (const T*)(src + i*sizeof(T) + sstep*(j+1)); + const T* s2 = (const T*)(src + i*sizeof(T) + sstep*(j+2)); + const T* s3 = (const T*)(src + i*sizeof(T) + sstep*(j+3)); + + d0[j] = s0[0]; d0[j+1] = s1[0]; d0[j+2] = s2[0]; d0[j+3] = s3[0]; + d1[j] = s0[1]; d1[j+1] = s1[1]; d1[j+2] = s2[1]; d1[j+3] = s3[1]; + d2[j] = s0[2]; d2[j+1] = s1[2]; d2[j+2] = s2[2]; d2[j+3] = s3[2]; + d3[j] = s0[3]; d3[j+1] = s1[3]; d3[j+2] = s2[3]; d3[j+3] = s3[3]; + } + + for( ; j < n; j++ ) + { + const T* s0 = (const T*)(src + i*sizeof(T) + j*sstep); + d0[j] = s0[0]; d1[j] = s0[1]; d2[j] = s0[2]; d3[j] = s0[3]; + } + } + #endif + for( ; i < m; i++ ) + { + T* d0 = (T*)(dst + dstep*i); + j = 0; + #if CV_ENABLE_UNROLLED + for(; j <= n - 4; j += 4 ) + { + const T* s0 = (const T*)(src + i*sizeof(T) + sstep*j); + const T* s1 = (const T*)(src + i*sizeof(T) + sstep*(j+1)); + const T* s2 = (const T*)(src + i*sizeof(T) + sstep*(j+2)); + const T* s3 = (const T*)(src + i*sizeof(T) + sstep*(j+3)); + + d0[j] = s0[0]; d0[j+1] = s1[0]; d0[j+2] = s2[0]; d0[j+3] = s3[0]; + } + #endif + for( ; j < n; j++ ) + { + const T* s0 = (const T*)(src + i*sizeof(T) + j*sstep); + d0[j] = s0[0]; + } + } +} + +template static void +transposeI_( uchar* data, size_t step, int n ) +{ + int i, j; + for( i = 0; i < n; i++ ) + { + T* row = (T*)(data + step*i); + uchar* data1 = data + i*sizeof(T); + for( j = i+1; j < n; j++ ) + std::swap( row[j], *(T*)(data1 + step*j) ); + } +} + +typedef void (*TransposeFunc)( const uchar* src, size_t sstep, uchar* dst, size_t dstep, Size sz ); +typedef void (*TransposeInplaceFunc)( uchar* data, size_t step, int n ); + +#define DEF_TRANSPOSE_FUNC(suffix, type) \ +static void transpose_##suffix( const uchar* src, size_t sstep, uchar* dst, size_t dstep, Size sz ) \ +{ transpose_(src, sstep, dst, dstep, sz); } \ +\ +static void transposeI_##suffix( uchar* data, size_t step, int n ) \ +{ transposeI_(data, step, n); } + +DEF_TRANSPOSE_FUNC(8u, uchar) +DEF_TRANSPOSE_FUNC(16u, ushort) +DEF_TRANSPOSE_FUNC(8uC3, Vec3b) +DEF_TRANSPOSE_FUNC(32s, int) +DEF_TRANSPOSE_FUNC(16uC3, Vec3s) +DEF_TRANSPOSE_FUNC(32sC2, Vec2i) +DEF_TRANSPOSE_FUNC(32sC3, Vec3i) +DEF_TRANSPOSE_FUNC(32sC4, Vec4i) +DEF_TRANSPOSE_FUNC(32sC6, Vec6i) +DEF_TRANSPOSE_FUNC(32sC8, Vec8i) + +static TransposeFunc transposeTab[] = +{ + 0, transpose_8u, transpose_16u, transpose_8uC3, transpose_32s, 0, transpose_16uC3, 0, + transpose_32sC2, 0, 0, 0, transpose_32sC3, 0, 0, 0, transpose_32sC4, + 0, 0, 0, 0, 0, 0, 0, transpose_32sC6, 0, 0, 0, 0, 0, 0, 0, transpose_32sC8 +}; + +static TransposeInplaceFunc transposeInplaceTab[] = +{ + 0, transposeI_8u, transposeI_16u, transposeI_8uC3, transposeI_32s, 0, transposeI_16uC3, 0, + transposeI_32sC2, 0, 0, 0, transposeI_32sC3, 0, 0, 0, transposeI_32sC4, + 0, 0, 0, 0, 0, 0, 0, transposeI_32sC6, 0, 0, 0, 0, 0, 0, 0, transposeI_32sC8 +}; + +} + +void cv::transpose( InputArray _src, OutputArray _dst ) +{ + Mat src = _src.getMat(); + size_t esz = src.elemSize(); + CV_Assert( src.dims <= 2 && esz <= (size_t)32 ); + + _dst.create(src.cols, src.rows, src.type()); + Mat dst = _dst.getMat(); + + if( dst.data == src.data ) + { + TransposeInplaceFunc func = transposeInplaceTab[esz]; + CV_Assert( func != 0 ); + func( dst.data, dst.step, dst.rows ); + } + else + { + TransposeFunc func = transposeTab[esz]; + CV_Assert( func != 0 ); + func( src.data, src.step, dst.data, dst.step, src.size() ); + } +} + + +void cv::completeSymm( InputOutputArray _m, bool LtoR ) +{ + Mat m = _m.getMat(); + CV_Assert( m.dims <= 2 ); + + int i, j, nrows = m.rows, type = m.type(); + int j0 = 0, j1 = nrows; + CV_Assert( m.rows == m.cols ); + + if( type == CV_32FC1 || type == CV_32SC1 ) + { + int* data = (int*)m.data; + size_t step = m.step/sizeof(data[0]); + for( i = 0; i < nrows; i++ ) + { + if( !LtoR ) j1 = i; else j0 = i+1; + for( j = j0; j < j1; j++ ) + data[i*step + j] = data[j*step + i]; + } + } + else if( type == CV_64FC1 ) + { + double* data = (double*)m.data; + size_t step = m.step/sizeof(data[0]); + for( i = 0; i < nrows; i++ ) + { + if( !LtoR ) j1 = i; else j0 = i+1; + for( j = j0; j < j1; j++ ) + data[i*step + j] = data[j*step + i]; + } + } + else + CV_Error( CV_StsUnsupportedFormat, "" ); +} + + +cv::Mat cv::Mat::cross(InputArray _m) const +{ + Mat m = _m.getMat(); + int tp = type(), d = CV_MAT_DEPTH(tp); + CV_Assert( dims <= 2 && m.dims <= 2 && size() == m.size() && tp == m.type() && + ((rows == 3 && cols == 1) || (cols*channels() == 3 && rows == 1))); + Mat result(rows, cols, tp); + + if( d == CV_32F ) + { + const float *a = (const float*)data, *b = (const float*)m.data; + float* c = (float*)result.data; + size_t lda = rows > 1 ? step/sizeof(a[0]) : 1; + size_t ldb = rows > 1 ? m.step/sizeof(b[0]) : 1; + + c[0] = a[lda] * b[ldb*2] - a[lda*2] * b[ldb]; + c[1] = a[lda*2] * b[0] - a[0] * b[ldb*2]; + c[2] = a[0] * b[ldb] - a[lda] * b[0]; + } + else if( d == CV_64F ) + { + const double *a = (const double*)data, *b = (const double*)m.data; + double* c = (double*)result.data; + size_t lda = rows > 1 ? step/sizeof(a[0]) : 1; + size_t ldb = rows > 1 ? m.step/sizeof(b[0]) : 1; + + c[0] = a[lda] * b[ldb*2] - a[lda*2] * b[ldb]; + c[1] = a[lda*2] * b[0] - a[0] * b[ldb*2]; + c[2] = a[0] * b[ldb] - a[lda] * b[0]; + } + + return result; +} + + +////////////////////////////////////////// reduce //////////////////////////////////////////// + +namespace cv +{ + +template static void +reduceR_( const Mat& srcmat, Mat& dstmat ) +{ + typedef typename Op::rtype WT; + Size size = srcmat.size(); + size.width *= srcmat.channels(); + AutoBuffer buffer(size.width); + WT* buf = buffer; + ST* dst = (ST*)dstmat.data; + const T* src = (const T*)srcmat.data; + size_t srcstep = srcmat.step/sizeof(src[0]); + int i; + Op op; + + for( i = 0; i < size.width; i++ ) + buf[i] = src[i]; + + for( ; --size.height; ) + { + src += srcstep; + i = 0; + #if CV_ENABLE_UNROLLED + for(; i <= size.width - 4; i += 4 ) + { + WT s0, s1; + s0 = op(buf[i], (WT)src[i]); + s1 = op(buf[i+1], (WT)src[i+1]); + buf[i] = s0; buf[i+1] = s1; + + s0 = op(buf[i+2], (WT)src[i+2]); + s1 = op(buf[i+3], (WT)src[i+3]); + buf[i+2] = s0; buf[i+3] = s1; + } + #endif + for( ; i < size.width; i++ ) + buf[i] = op(buf[i], (WT)src[i]); + } + + for( i = 0; i < size.width; i++ ) + dst[i] = (ST)buf[i]; +} + + +template static void +reduceC_( const Mat& srcmat, Mat& dstmat ) +{ + typedef typename Op::rtype WT; + Size size = srcmat.size(); + int i, k, cn = srcmat.channels(); + size.width *= cn; + Op op; + + for( int y = 0; y < size.height; y++ ) + { + const T* src = (const T*)(srcmat.data + srcmat.step*y); + ST* dst = (ST*)(dstmat.data + dstmat.step*y); + if( size.width == cn ) + for( k = 0; k < cn; k++ ) + dst[k] = src[k]; + else + { + for( k = 0; k < cn; k++ ) + { + WT a0 = src[k], a1 = src[k+cn]; + for( i = 2*cn; i <= size.width - 4*cn; i += 4*cn ) + { + a0 = op(a0, (WT)src[i+k]); + a1 = op(a1, (WT)src[i+k+cn]); + a0 = op(a0, (WT)src[i+k+cn*2]); + a1 = op(a1, (WT)src[i+k+cn*3]); + } + + for( ; i < size.width; i += cn ) + { + a0 = op(a0, (WT)src[i+k]); + } + a0 = op(a0, a1); + dst[k] = (ST)a0; + } + } + } +} + +typedef void (*ReduceFunc)( const Mat& src, Mat& dst ); + +} + +#define reduceSumR8u32s reduceR_ > +#define reduceSumR8u32f reduceR_ > +#define reduceSumR8u64f reduceR_ > +#define reduceSumR16u32f reduceR_ > +#define reduceSumR16u64f reduceR_ > +#define reduceSumR16s32f reduceR_ > +#define reduceSumR16s64f reduceR_ > +#define reduceSumR32f32f reduceR_ > +#define reduceSumR32f64f reduceR_ > +#define reduceSumR64f64f reduceR_ > + +#define reduceMaxR8u reduceR_ > +#define reduceMaxR16u reduceR_ > +#define reduceMaxR16s reduceR_ > +#define reduceMaxR32f reduceR_ > +#define reduceMaxR64f reduceR_ > + +#define reduceMinR8u reduceR_ > +#define reduceMinR16u reduceR_ > +#define reduceMinR16s reduceR_ > +#define reduceMinR32f reduceR_ > +#define reduceMinR64f reduceR_ > + +#define reduceSumC8u32s reduceC_ > +#define reduceSumC8u32f reduceC_ > +#define reduceSumC8u64f reduceC_ > +#define reduceSumC16u32f reduceC_ > +#define reduceSumC16u64f reduceC_ > +#define reduceSumC16s32f reduceC_ > +#define reduceSumC16s64f reduceC_ > +#define reduceSumC32f32f reduceC_ > +#define reduceSumC32f64f reduceC_ > +#define reduceSumC64f64f reduceC_ > + +#define reduceMaxC8u reduceC_ > +#define reduceMaxC16u reduceC_ > +#define reduceMaxC16s reduceC_ > +#define reduceMaxC32f reduceC_ > +#define reduceMaxC64f reduceC_ > + +#define reduceMinC8u reduceC_ > +#define reduceMinC16u reduceC_ > +#define reduceMinC16s reduceC_ > +#define reduceMinC32f reduceC_ > +#define reduceMinC64f reduceC_ > + +void cv::reduce(InputArray _src, OutputArray _dst, int dim, int op, int dtype) +{ + Mat src = _src.getMat(); + CV_Assert( src.dims <= 2 ); + int op0 = op; + int stype = src.type(), sdepth = src.depth(), cn = src.channels(); + if( dtype < 0 ) + dtype = _dst.fixedType() ? _dst.type() : stype; + int ddepth = CV_MAT_DEPTH(dtype); + + _dst.create(dim == 0 ? 1 : src.rows, dim == 0 ? src.cols : 1, + CV_MAKETYPE(dtype >= 0 ? dtype : stype, cn)); + Mat dst = _dst.getMat(), temp = dst; + + CV_Assert( op == CV_REDUCE_SUM || op == CV_REDUCE_MAX || + op == CV_REDUCE_MIN || op == CV_REDUCE_AVG ); + CV_Assert( src.channels() == dst.channels() ); + + if( op == CV_REDUCE_AVG ) + { + op = CV_REDUCE_SUM; + if( sdepth < CV_32S && ddepth < CV_32S ) + { + temp.create(dst.rows, dst.cols, CV_32SC(cn)); + ddepth = CV_32S; + } + } + + ReduceFunc func = 0; + if( dim == 0 ) + { + if( op == CV_REDUCE_SUM ) + { + if(sdepth == CV_8U && ddepth == CV_32S) + func = GET_OPTIMIZED(reduceSumR8u32s); + else if(sdepth == CV_8U && ddepth == CV_32F) + func = reduceSumR8u32f; + else if(sdepth == CV_8U && ddepth == CV_64F) + func = reduceSumR8u64f; + else if(sdepth == CV_16U && ddepth == CV_32F) + func = reduceSumR16u32f; + else if(sdepth == CV_16U && ddepth == CV_64F) + func = reduceSumR16u64f; + else if(sdepth == CV_16S && ddepth == CV_32F) + func = reduceSumR16s32f; + else if(sdepth == CV_16S && ddepth == CV_64F) + func = reduceSumR16s64f; + else if(sdepth == CV_32F && ddepth == CV_32F) + func = GET_OPTIMIZED(reduceSumR32f32f); + else if(sdepth == CV_32F && ddepth == CV_64F) + func = reduceSumR32f64f; + else if(sdepth == CV_64F && ddepth == CV_64F) + func = reduceSumR64f64f; + } + else if(op == CV_REDUCE_MAX) + { + if(sdepth == CV_8U && ddepth == CV_8U) + func = GET_OPTIMIZED(reduceMaxR8u); + else if(sdepth == CV_16U && ddepth == CV_16U) + func = reduceMaxR16u; + else if(sdepth == CV_16S && ddepth == CV_16S) + func = reduceMaxR16s; + else if(sdepth == CV_32F && ddepth == CV_32F) + func = GET_OPTIMIZED(reduceMaxR32f); + else if(sdepth == CV_64F && ddepth == CV_64F) + func = reduceMaxR64f; + } + else if(op == CV_REDUCE_MIN) + { + if(sdepth == CV_8U && ddepth == CV_8U) + func = GET_OPTIMIZED(reduceMinR8u); + else if(sdepth == CV_16U && ddepth == CV_16U) + func = reduceMinR16u; + else if(sdepth == CV_16S && ddepth == CV_16S) + func = reduceMinR16s; + else if(sdepth == CV_32F && ddepth == CV_32F) + func = GET_OPTIMIZED(reduceMinR32f); + else if(sdepth == CV_64F && ddepth == CV_64F) + func = reduceMinR64f; + } + } + else + { + if(op == CV_REDUCE_SUM) + { + if(sdepth == CV_8U && ddepth == CV_32S) + func = GET_OPTIMIZED(reduceSumC8u32s); + else if(sdepth == CV_8U && ddepth == CV_32F) + func = reduceSumC8u32f; + else if(sdepth == CV_8U && ddepth == CV_64F) + func = reduceSumC8u64f; + else if(sdepth == CV_16U && ddepth == CV_32F) + func = reduceSumC16u32f; + else if(sdepth == CV_16U && ddepth == CV_64F) + func = reduceSumC16u64f; + else if(sdepth == CV_16S && ddepth == CV_32F) + func = reduceSumC16s32f; + else if(sdepth == CV_16S && ddepth == CV_64F) + func = reduceSumC16s64f; + else if(sdepth == CV_32F && ddepth == CV_32F) + func = GET_OPTIMIZED(reduceSumC32f32f); + else if(sdepth == CV_32F && ddepth == CV_64F) + func = reduceSumC32f64f; + else if(sdepth == CV_64F && ddepth == CV_64F) + func = reduceSumC64f64f; + } + else if(op == CV_REDUCE_MAX) + { + if(sdepth == CV_8U && ddepth == CV_8U) + func = GET_OPTIMIZED(reduceMaxC8u); + else if(sdepth == CV_16U && ddepth == CV_16U) + func = reduceMaxC16u; + else if(sdepth == CV_16S && ddepth == CV_16S) + func = reduceMaxC16s; + else if(sdepth == CV_32F && ddepth == CV_32F) + func = GET_OPTIMIZED(reduceMaxC32f); + else if(sdepth == CV_64F && ddepth == CV_64F) + func = reduceMaxC64f; + } + else if(op == CV_REDUCE_MIN) + { + if(sdepth == CV_8U && ddepth == CV_8U) + func = GET_OPTIMIZED(reduceMinC8u); + else if(sdepth == CV_16U && ddepth == CV_16U) + func = reduceMinC16u; + else if(sdepth == CV_16S && ddepth == CV_16S) + func = reduceMinC16s; + else if(sdepth == CV_32F && ddepth == CV_32F) + func = GET_OPTIMIZED(reduceMinC32f); + else if(sdepth == CV_64F && ddepth == CV_64F) + func = reduceMinC64f; + } + } + + if( !func ) + CV_Error( CV_StsUnsupportedFormat, + "Unsupported combination of input and output array formats" ); + + func( src, temp ); + + if( op0 == CV_REDUCE_AVG ) + temp.convertTo(dst, dst.type(), 1./(dim == 0 ? src.rows : src.cols)); +} + + +//////////////////////////////////////// sort /////////////////////////////////////////// + +namespace cv +{ + +template static void sort_( const Mat& src, Mat& dst, int flags ) +{ + AutoBuffer buf; + T* bptr; + int i, j, n, len; + bool sortRows = (flags & 1) == CV_SORT_EVERY_ROW; + bool inplace = src.data == dst.data; + bool sortDescending = (flags & CV_SORT_DESCENDING) != 0; + + if( sortRows ) + n = src.rows, len = src.cols; + else + { + n = src.cols, len = src.rows; + buf.allocate(len); + } + bptr = (T*)buf; + + for( i = 0; i < n; i++ ) + { + T* ptr = bptr; + if( sortRows ) + { + T* dptr = (T*)(dst.data + dst.step*i); + if( !inplace ) + { + const T* sptr = (const T*)(src.data + src.step*i); + for( j = 0; j < len; j++ ) + dptr[j] = sptr[j]; + } + ptr = dptr; + } + else + { + for( j = 0; j < len; j++ ) + ptr[j] = ((const T*)(src.data + src.step*j))[i]; + } + std::sort( ptr, ptr + len, LessThan() ); + if( sortDescending ) + for( j = 0; j < len/2; j++ ) + std::swap(ptr[j], ptr[len-1-j]); + if( !sortRows ) + for( j = 0; j < len; j++ ) + ((T*)(dst.data + dst.step*j))[i] = ptr[j]; + } +} + + +template static void sortIdx_( const Mat& src, Mat& dst, int flags ) +{ + AutoBuffer buf; + AutoBuffer ibuf; + T* bptr; + int* _iptr; + int i, j, n, len; + bool sortRows = (flags & 1) == CV_SORT_EVERY_ROW; + bool sortDescending = (flags & CV_SORT_DESCENDING) != 0; + + CV_Assert( src.data != dst.data ); + + if( sortRows ) + n = src.rows, len = src.cols; + else + { + n = src.cols, len = src.rows; + buf.allocate(len); + ibuf.allocate(len); + } + bptr = (T*)buf; + _iptr = (int*)ibuf; + + for( i = 0; i < n; i++ ) + { + T* ptr = bptr; + int* iptr = _iptr; + + if( sortRows ) + { + ptr = (T*)(src.data + src.step*i); + iptr = (int*)(dst.data + dst.step*i); + } + else + { + for( j = 0; j < len; j++ ) + ptr[j] = ((const T*)(src.data + src.step*j))[i]; + } + for( j = 0; j < len; j++ ) + iptr[j] = j; + std::sort( iptr, iptr + len, LessThanIdx(ptr) ); + if( sortDescending ) + for( j = 0; j < len/2; j++ ) + std::swap(iptr[j], iptr[len-1-j]); + if( !sortRows ) + for( j = 0; j < len; j++ ) + ((int*)(dst.data + dst.step*j))[i] = iptr[j]; + } +} + +typedef void (*SortFunc)(const Mat& src, Mat& dst, int flags); + +} + +void cv::sort( InputArray _src, OutputArray _dst, int flags ) +{ + static SortFunc tab[] = + { + sort_, sort_, sort_, sort_, + sort_, sort_, sort_, 0 + }; + Mat src = _src.getMat(); + SortFunc func = tab[src.depth()]; + CV_Assert( src.dims <= 2 && src.channels() == 1 && func != 0 ); + _dst.create( src.size(), src.type() ); + Mat dst = _dst.getMat(); + func( src, dst, flags ); +} + +void cv::sortIdx( InputArray _src, OutputArray _dst, int flags ) +{ + static SortFunc tab[] = + { + sortIdx_, sortIdx_, sortIdx_, sortIdx_, + sortIdx_, sortIdx_, sortIdx_, 0 + }; + Mat src = _src.getMat(); + SortFunc func = tab[src.depth()]; + CV_Assert( src.dims <= 2 && src.channels() == 1 && func != 0 ); + + Mat dst = _dst.getMat(); + if( dst.data == src.data ) + _dst.release(); + _dst.create( src.size(), CV_32S ); + dst = _dst.getMat(); + func( src, dst, flags ); +} + + +////////////////////////////////////////// kmeans //////////////////////////////////////////// + +namespace cv +{ + +static void generateRandomCenter(const vector& box, float* center, RNG& rng) +{ + size_t j, dims = box.size(); + float margin = 1.f/dims; + for( j = 0; j < dims; j++ ) + center[j] = ((float)rng*(1.f+margin*2.f)-margin)*(box[j][1] - box[j][0]) + box[j][0]; +} + + +/* +k-means center initialization using the following algorithm: +Arthur & Vassilvitskii (2007) k-means++: The Advantages of Careful Seeding +*/ +static void generateCentersPP(const Mat& _data, Mat& _out_centers, + int K, RNG& rng, int trials) +{ + int i, j, k, dims = _data.cols, N = _data.rows; + const float* data = _data.ptr(0); + size_t step = _data.step/sizeof(data[0]); + vector _centers(K); + int* centers = &_centers[0]; + vector _dist(N*3); + float* dist = &_dist[0], *tdist = dist + N, *tdist2 = tdist + N; + double sum0 = 0; + + centers[0] = (unsigned)rng % N; + + for( i = 0; i < N; i++ ) + { + dist[i] = normL2Sqr_(data + step*i, data + step*centers[0], dims); + sum0 += dist[i]; + } + + for( k = 1; k < K; k++ ) + { + double bestSum = DBL_MAX; + int bestCenter = -1; + + for( j = 0; j < trials; j++ ) + { + double p = (double)rng*sum0, s = 0; + for( i = 0; i < N-1; i++ ) + if( (p -= dist[i]) <= 0 ) + break; + int ci = i; + for( i = 0; i < N; i++ ) + { + tdist2[i] = std::min(normL2Sqr_(data + step*i, data + step*ci, dims), dist[i]); + s += tdist2[i]; + } + + if( s < bestSum ) + { + bestSum = s; + bestCenter = ci; + std::swap(tdist, tdist2); + } + } + centers[k] = bestCenter; + sum0 = bestSum; + std::swap(dist, tdist); + } + + for( k = 0; k < K; k++ ) + { + const float* src = data + step*centers[k]; + float* dst = _out_centers.ptr(k); + for( j = 0; j < dims; j++ ) + dst[j] = src[j]; + } +} + +} + +double cv::kmeans( InputArray _data, int K, + InputOutputArray _bestLabels, + TermCriteria criteria, int attempts, + int flags, OutputArray _centers ) +{ + const int SPP_TRIALS = 3; + Mat data = _data.getMat(); + bool isrow = data.rows == 1 && data.channels() > 1; + int N = !isrow ? data.rows : data.cols; + int dims = (!isrow ? data.cols : 1)*data.channels(); + int type = data.depth(); + + attempts = std::max(attempts, 1); + CV_Assert( data.dims <= 2 && type == CV_32F && K > 0 ); + CV_Assert( N >= K ); + + _bestLabels.create(N, 1, CV_32S, -1, true); + + Mat _labels, best_labels = _bestLabels.getMat(); + if( flags & CV_KMEANS_USE_INITIAL_LABELS ) + { + CV_Assert( (best_labels.cols == 1 || best_labels.rows == 1) && + best_labels.cols*best_labels.rows == N && + best_labels.type() == CV_32S && + best_labels.isContinuous()); + best_labels.copyTo(_labels); + } + else + { + if( !((best_labels.cols == 1 || best_labels.rows == 1) && + best_labels.cols*best_labels.rows == N && + best_labels.type() == CV_32S && + best_labels.isContinuous())) + best_labels.create(N, 1, CV_32S); + _labels.create(best_labels.size(), best_labels.type()); + } + int* labels = _labels.ptr(); + + Mat centers(K, dims, type), old_centers(K, dims, type), temp(1, dims, type); + vector counters(K); + vector _box(dims); + Vec2f* box = &_box[0]; + + double best_compactness = DBL_MAX, compactness = 0; + RNG& rng = theRNG(); + int a, iter, i, j, k; + + if( criteria.type & TermCriteria::EPS ) + criteria.epsilon = std::max(criteria.epsilon, 0.); + else + criteria.epsilon = FLT_EPSILON; + criteria.epsilon *= criteria.epsilon; + + if( criteria.type & TermCriteria::COUNT ) + criteria.maxCount = std::min(std::max(criteria.maxCount, 2), 100); + else + criteria.maxCount = 100; + + if( K == 1 ) + { + attempts = 1; + criteria.maxCount = 2; + } + + const float* sample = data.ptr(0); + for( j = 0; j < dims; j++ ) + box[j] = Vec2f(sample[j], sample[j]); + + for( i = 1; i < N; i++ ) + { + sample = data.ptr(i); + for( j = 0; j < dims; j++ ) + { + float v = sample[j]; + box[j][0] = std::min(box[j][0], v); + box[j][1] = std::max(box[j][1], v); + } + } + + for( a = 0; a < attempts; a++ ) + { + double max_center_shift = DBL_MAX; + for( iter = 0;; ) + { + swap(centers, old_centers); + + if( iter == 0 && (a > 0 || !(flags & KMEANS_USE_INITIAL_LABELS)) ) + { + if( flags & KMEANS_PP_CENTERS ) + generateCentersPP(data, centers, K, rng, SPP_TRIALS); + else + { + for( k = 0; k < K; k++ ) + generateRandomCenter(_box, centers.ptr(k), rng); + } + } + else + { + if( iter == 0 && a == 0 && (flags & KMEANS_USE_INITIAL_LABELS) ) + { + for( i = 0; i < N; i++ ) + CV_Assert( (unsigned)labels[i] < (unsigned)K ); + } + + // compute centers + centers = Scalar(0); + for( k = 0; k < K; k++ ) + counters[k] = 0; + + for( i = 0; i < N; i++ ) + { + sample = data.ptr(i); + k = labels[i]; + float* center = centers.ptr(k); + j=0; + #if CV_ENABLE_UNROLLED + for(; j <= dims - 4; j += 4 ) + { + float t0 = center[j] + sample[j]; + float t1 = center[j+1] + sample[j+1]; + + center[j] = t0; + center[j+1] = t1; + + t0 = center[j+2] + sample[j+2]; + t1 = center[j+3] + sample[j+3]; + + center[j+2] = t0; + center[j+3] = t1; + } + #endif + for( ; j < dims; j++ ) + center[j] += sample[j]; + counters[k]++; + } + + if( iter > 0 ) + max_center_shift = 0; + + for( k = 0; k < K; k++ ) + { + if( counters[k] != 0 ) + continue; + + // if some cluster appeared to be empty then: + // 1. find the biggest cluster + // 2. find the farthest from the center point in the biggest cluster + // 3. exclude the farthest point from the biggest cluster and form a new 1-point cluster. + int max_k = 0; + for( int k1 = 1; k1 < K; k1++ ) + { + if( counters[max_k] < counters[k1] ) + max_k = k1; + } + + double max_dist = 0; + int farthest_i = -1; + float* new_center = centers.ptr(k); + float* old_center = centers.ptr(max_k); + float* _old_center = temp.ptr(); // normalized + float scale = 1.f/counters[max_k]; + for( j = 0; j < dims; j++ ) + _old_center[j] = old_center[j]*scale; + + for( i = 0; i < N; i++ ) + { + if( labels[i] != max_k ) + continue; + sample = data.ptr(i); + double dist = normL2Sqr_(sample, _old_center, dims); + + if( max_dist <= dist ) + { + max_dist = dist; + farthest_i = i; + } + } + + counters[max_k]--; + counters[k]++; + labels[farthest_i] = k; + sample = data.ptr(farthest_i); + + for( j = 0; j < dims; j++ ) + { + old_center[j] -= sample[j]; + new_center[j] += sample[j]; + } + } + + for( k = 0; k < K; k++ ) + { + float* center = centers.ptr(k); + CV_Assert( counters[k] != 0 ); + + float scale = 1.f/counters[k]; + for( j = 0; j < dims; j++ ) + center[j] *= scale; + + if( iter > 0 ) + { + double dist = 0; + const float* old_center = old_centers.ptr(k); + for( j = 0; j < dims; j++ ) + { + double t = center[j] - old_center[j]; + dist += t*t; + } + max_center_shift = std::max(max_center_shift, dist); + } + } + } + + if( ++iter == MAX(criteria.maxCount, 2) || max_center_shift <= criteria.epsilon ) + break; + + // assign labels + compactness = 0; + for( i = 0; i < N; i++ ) + { + sample = data.ptr(i); + int k_best = 0; + double min_dist = DBL_MAX; + + for( k = 0; k < K; k++ ) + { + const float* center = centers.ptr(k); + double dist = normL2Sqr_(sample, center, dims); + + if( min_dist > dist ) + { + min_dist = dist; + k_best = k; + } + } + + compactness += min_dist; + labels[i] = k_best; + } + } + + if( compactness < best_compactness ) + { + best_compactness = compactness; + if( _centers.needed() ) + centers.copyTo(_centers); + _labels.copyTo(best_labels); + } + } + + return best_compactness; +} + + +CV_IMPL void cvSetIdentity( CvArr* arr, CvScalar value ) +{ + cv::Mat m = cv::cvarrToMat(arr); + cv::setIdentity(m, value); +} + + +CV_IMPL CvScalar cvTrace( const CvArr* arr ) +{ + return cv::trace(cv::cvarrToMat(arr)); +} + + +CV_IMPL void cvTranspose( const CvArr* srcarr, CvArr* dstarr ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + CV_Assert( src.rows == dst.cols && src.cols == dst.rows && src.type() == dst.type() ); + transpose( src, dst ); +} + + +CV_IMPL void cvCompleteSymm( CvMat* matrix, int LtoR ) +{ + cv::Mat m(matrix); + cv::completeSymm( m, LtoR != 0 ); +} + + +CV_IMPL void cvCrossProduct( const CvArr* srcAarr, const CvArr* srcBarr, CvArr* dstarr ) +{ + cv::Mat srcA = cv::cvarrToMat(srcAarr), dst = cv::cvarrToMat(dstarr); + + CV_Assert( srcA.size() == dst.size() && srcA.type() == dst.type() ); + srcA.cross(cv::cvarrToMat(srcBarr)).copyTo(dst); +} + + +CV_IMPL void +cvReduce( const CvArr* srcarr, CvArr* dstarr, int dim, int op ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + if( dim < 0 ) + dim = src.rows > dst.rows ? 0 : src.cols > dst.cols ? 1 : dst.cols == 1; + + if( dim > 1 ) + CV_Error( CV_StsOutOfRange, "The reduced dimensionality index is out of range" ); + + if( (dim == 0 && (dst.cols != src.cols || dst.rows != 1)) || + (dim == 1 && (dst.rows != src.rows || dst.cols != 1)) ) + CV_Error( CV_StsBadSize, "The output array size is incorrect" ); + + if( src.channels() != dst.channels() ) + CV_Error( CV_StsUnmatchedFormats, "Input and output arrays must have the same number of channels" ); + + cv::reduce(src, dst, dim, op, dst.type()); +} + + +CV_IMPL CvArr* +cvRange( CvArr* arr, double start, double end ) +{ + int ok = 0; + + CvMat stub, *mat = (CvMat*)arr; + double delta; + int type, step; + double val = start; + int i, j; + int rows, cols; + + if( !CV_IS_MAT(mat) ) + mat = cvGetMat( mat, &stub); + + rows = mat->rows; + cols = mat->cols; + type = CV_MAT_TYPE(mat->type); + delta = (end-start)/(rows*cols); + + if( CV_IS_MAT_CONT(mat->type) ) + { + cols *= rows; + rows = 1; + step = 1; + } + else + step = mat->step / CV_ELEM_SIZE(type); + + if( type == CV_32SC1 ) + { + int* idata = mat->data.i; + int ival = cvRound(val), idelta = cvRound(delta); + + if( fabs(val - ival) < DBL_EPSILON && + fabs(delta - idelta) < DBL_EPSILON ) + { + for( i = 0; i < rows; i++, idata += step ) + for( j = 0; j < cols; j++, ival += idelta ) + idata[j] = ival; + } + else + { + for( i = 0; i < rows; i++, idata += step ) + for( j = 0; j < cols; j++, val += delta ) + idata[j] = cvRound(val); + } + } + else if( type == CV_32FC1 ) + { + float* fdata = mat->data.fl; + for( i = 0; i < rows; i++, fdata += step ) + for( j = 0; j < cols; j++, val += delta ) + fdata[j] = (float)val; + } + else + CV_Error( CV_StsUnsupportedFormat, "The function only supports 32sC1 and 32fC1 datatypes" ); + + ok = 1; + return ok ? arr : 0; +} + + +CV_IMPL void +cvSort( const CvArr* _src, CvArr* _dst, CvArr* _idx, int flags ) +{ + cv::Mat src = cv::cvarrToMat(_src); + + if( _idx ) + { + cv::Mat idx0 = cv::cvarrToMat(_idx), idx = idx0; + CV_Assert( src.size() == idx.size() && idx.type() == CV_32S && src.data != idx.data ); + cv::sortIdx( src, idx, flags ); + CV_Assert( idx0.data == idx.data ); + } + + if( _dst ) + { + cv::Mat dst0 = cv::cvarrToMat(_dst), dst = dst0; + CV_Assert( src.size() == dst.size() && src.type() == dst.type() ); + cv::sort( src, dst, flags ); + CV_Assert( dst0.data == dst.data ); + } +} + + +CV_IMPL int +cvKMeans2( const CvArr* _samples, int cluster_count, CvArr* _labels, + CvTermCriteria termcrit, int attempts, CvRNG*, + int flags, CvArr* _centers, double* _compactness ) +{ + cv::Mat data = cv::cvarrToMat(_samples), labels = cv::cvarrToMat(_labels), centers; + if( _centers ) + { + centers = cv::cvarrToMat(_centers); + + centers = centers.reshape(1); + data = data.reshape(1); + + CV_Assert( !centers.empty() ); + CV_Assert( centers.rows == cluster_count ); + CV_Assert( centers.cols == data.cols ); + CV_Assert( centers.depth() == data.depth() ); + } + CV_Assert( labels.isContinuous() && labels.type() == CV_32S && + (labels.cols == 1 || labels.rows == 1) && + labels.cols + labels.rows - 1 == data.rows ); + + double compactness = cv::kmeans(data, cluster_count, labels, termcrit, attempts, + flags, _centers ? cv::_OutputArray(centers) : cv::_OutputArray() ); + if( _compactness ) + *_compactness = compactness; + return 1; +} + +///////////////////////////// n-dimensional matrices //////////////////////////// + +namespace cv +{ + +Mat Mat::reshape(int _cn, int _newndims, const int* _newsz) const +{ + if(_newndims == dims) + { + if(_newsz == 0) + return reshape(_cn); + if(_newndims == 2) + return reshape(_cn, _newsz[0]); + } + + CV_Error(CV_StsNotImplemented, ""); + // TBD + return Mat(); +} + +Mat::operator CvMatND() const +{ + CvMatND mat; + cvInitMatNDHeader( &mat, dims, size, type(), data ); + int i, d = dims; + for( i = 0; i < d; i++ ) + mat.dim[i].step = (int)step[i]; + mat.type |= flags & CONTINUOUS_FLAG; + return mat; +} + +NAryMatIterator::NAryMatIterator() + : arrays(0), planes(0), ptrs(0), narrays(0), nplanes(0), size(0), iterdepth(0), idx(0) +{ +} + +NAryMatIterator::NAryMatIterator(const Mat** _arrays, Mat* _planes, int _narrays) +: arrays(0), planes(0), ptrs(0), narrays(0), nplanes(0), size(0), iterdepth(0), idx(0) +{ + init(_arrays, _planes, 0, _narrays); +} + +NAryMatIterator::NAryMatIterator(const Mat** _arrays, uchar** _ptrs, int _narrays) + : arrays(0), planes(0), ptrs(0), narrays(0), nplanes(0), size(0), iterdepth(0), idx(0) +{ + init(_arrays, 0, _ptrs, _narrays); +} + +void NAryMatIterator::init(const Mat** _arrays, Mat* _planes, uchar** _ptrs, int _narrays) +{ + CV_Assert( _arrays && (_ptrs || _planes) ); + int i, j, d1=0, i0 = -1, d = -1; + + arrays = _arrays; + ptrs = _ptrs; + planes = _planes; + narrays = _narrays; + nplanes = 0; + size = 0; + + if( narrays < 0 ) + { + for( i = 0; _arrays[i] != 0; i++ ) + ; + narrays = i; + CV_Assert(narrays <= 1000); + } + + iterdepth = 0; + + for( i = 0; i < narrays; i++ ) + { + CV_Assert(arrays[i] != 0); + const Mat& A = *arrays[i]; + if( ptrs ) + ptrs[i] = A.data; + + if( !A.data ) + continue; + + if( i0 < 0 ) + { + i0 = i; + d = A.dims; + + // find the first dimensionality which is different from 1; + // in any of the arrays the first "d1" step do not affect the continuity + for( d1 = 0; d1 < d; d1++ ) + if( A.size[d1] > 1 ) + break; + } + else + CV_Assert( A.size == arrays[i0]->size ); + + if( !A.isContinuous() ) + { + CV_Assert( A.step[d-1] == A.elemSize() ); + for( j = d-1; j > d1; j-- ) + if( A.step[j]*A.size[j] < A.step[j-1] ) + break; + iterdepth = std::max(iterdepth, j); + } + } + + if( i0 >= 0 ) + { + size = arrays[i0]->size[d-1]; + for( j = d-1; j > iterdepth; j-- ) + { + int64 total1 = (int64)size*arrays[i0]->size[j-1]; + if( total1 != (int)total1 ) + break; + size = (int)total1; + } + + iterdepth = j; + if( iterdepth == d1 ) + iterdepth = 0; + + nplanes = 1; + for( j = iterdepth-1; j >= 0; j-- ) + nplanes *= arrays[i0]->size[j]; + } + else + iterdepth = 0; + + idx = 0; + + if( !planes ) + return; + + for( i = 0; i < narrays; i++ ) + { + CV_Assert(arrays[i] != 0); + const Mat& A = *arrays[i]; + + if( !A.data ) + { + planes[i] = Mat(); + continue; + } + + planes[i] = Mat(1, (int)size, A.type(), A.data); + } +} + + +NAryMatIterator& NAryMatIterator::operator ++() +{ + if( idx >= nplanes-1 ) + return *this; + ++idx; + + if( iterdepth == 1 ) + { + if( ptrs ) + { + for( int i = 0; i < narrays; i++ ) + { + if( !ptrs[i] ) + continue; + ptrs[i] = arrays[i]->data + arrays[i]->step[0]*idx; + } + } + if( planes ) + { + for( int i = 0; i < narrays; i++ ) + { + if( !planes[i].data ) + continue; + planes[i].data = arrays[i]->data + arrays[i]->step[0]*idx; + } + } + } + else + { + for( int i = 0; i < narrays; i++ ) + { + const Mat& A = *arrays[i]; + if( !A.data ) + continue; + int _idx = (int)idx; + uchar* data = A.data; + for( int j = iterdepth-1; j >= 0 && _idx > 0; j-- ) + { + int szi = A.size[j], t = _idx/szi; + data += (_idx - t * szi)*A.step[j]; + _idx = t; + } + if( ptrs ) + ptrs[i] = data; + if( planes ) + planes[i].data = data; + } + } + + return *this; +} + +NAryMatIterator NAryMatIterator::operator ++(int) +{ + NAryMatIterator it = *this; + ++*this; + return it; +} + +/////////////////////////////////////////////////////////////////////////// +// MatConstIterator // +/////////////////////////////////////////////////////////////////////////// + +Point MatConstIterator::pos() const +{ + if( !m ) + return Point(); + CV_DbgAssert(m->dims <= 2); + + ptrdiff_t ofs = ptr - m->data; + int y = (int)(ofs/m->step[0]); + return Point((int)((ofs - y*m->step[0])/elemSize), y); +} + +void MatConstIterator::pos(int* _idx) const +{ + CV_Assert(m != 0 && _idx); + ptrdiff_t ofs = ptr - m->data; + for( int i = 0; i < m->dims; i++ ) + { + size_t s = m->step[i], v = ofs/s; + ofs -= v*s; + _idx[i] = (int)v; + } +} + +ptrdiff_t MatConstIterator::lpos() const +{ + if(!m) + return 0; + if( m->isContinuous() ) + return (ptr - sliceStart)/elemSize; + ptrdiff_t ofs = ptr - m->data; + int i, d = m->dims; + if( d == 2 ) + { + ptrdiff_t y = ofs/m->step[0]; + return y*m->cols + (ofs - y*m->step[0])/elemSize; + } + ptrdiff_t result = 0; + for( i = 0; i < d; i++ ) + { + size_t s = m->step[i], v = ofs/s; + ofs -= v*s; + result = result*m->size[i] + v; + } + return result; +} + +void MatConstIterator::seek(ptrdiff_t ofs, bool relative) +{ + if( m->isContinuous() ) + { + ptr = (relative ? ptr : sliceStart) + ofs*elemSize; + if( ptr < sliceStart ) + ptr = sliceStart; + else if( ptr > sliceEnd ) + ptr = sliceEnd; + return; + } + + int d = m->dims; + if( d == 2 ) + { + ptrdiff_t ofs0, y; + if( relative ) + { + ofs0 = ptr - m->data; + y = ofs0/m->step[0]; + ofs += y*m->cols + (ofs0 - y*m->step[0])/elemSize; + } + y = ofs/m->cols; + int y1 = std::min(std::max((int)y, 0), m->rows-1); + sliceStart = m->data + y1*m->step[0]; + sliceEnd = sliceStart + m->cols*elemSize; + ptr = y < 0 ? sliceStart : y >= m->rows ? sliceEnd : + sliceStart + (ofs - y*m->cols)*elemSize; + return; + } + + if( relative ) + ofs += lpos(); + + if( ofs < 0 ) + ofs = 0; + + int szi = m->size[d-1]; + ptrdiff_t t = ofs/szi; + int v = (int)(ofs - t*szi); + ofs = t; + ptr = m->data + v*elemSize; + sliceStart = m->data; + + for( int i = d-2; i >= 0; i-- ) + { + szi = m->size[i]; + t = ofs/szi; + v = (int)(ofs - t*szi); + ofs = t; + sliceStart += v*m->step[i]; + } + + sliceEnd = sliceStart + m->size[d-1]*elemSize; + if( ofs > 0 ) + ptr = sliceEnd; + else + ptr = sliceStart + (ptr - m->data); +} + +void MatConstIterator::seek(const int* _idx, bool relative) +{ + int i, d = m->dims; + ptrdiff_t ofs = 0; + if( !_idx ) + ; + else if( d == 2 ) + ofs = _idx[0]*m->size[1] + _idx[1]; + else + { + for( i = 0; i < d; i++ ) + ofs = ofs*m->size[i] + _idx[i]; + } + seek(ofs, relative); +} + +ptrdiff_t operator - (const MatConstIterator& b, const MatConstIterator& a) +{ + if( a.m != b.m ) + return INT_MAX; + if( a.sliceEnd == b.sliceEnd ) + return (b.ptr - a.ptr)/b.elemSize; + + return b.lpos() - a.lpos(); +} + +//////////////////////////////// SparseMat //////////////////////////////// + +template void +convertData_(const void* _from, void* _to, int cn) +{ + const T1* from = (const T1*)_from; + T2* to = (T2*)_to; + if( cn == 1 ) + *to = saturate_cast(*from); + else + for( int i = 0; i < cn; i++ ) + to[i] = saturate_cast(from[i]); +} + +template void +convertScaleData_(const void* _from, void* _to, int cn, double alpha, double beta) +{ + const T1* from = (const T1*)_from; + T2* to = (T2*)_to; + if( cn == 1 ) + *to = saturate_cast(*from*alpha + beta); + else + for( int i = 0; i < cn; i++ ) + to[i] = saturate_cast(from[i]*alpha + beta); +} + +ConvertData getConvertElem(int fromType, int toType) +{ + static ConvertData tab[][8] = + {{ convertData_, convertData_, + convertData_, convertData_, + convertData_, convertData_, + convertData_, 0 }, + + { convertData_, convertData_, + convertData_, convertData_, + convertData_, convertData_, + convertData_, 0 }, + + { convertData_, convertData_, + convertData_, convertData_, + convertData_, convertData_, + convertData_, 0 }, + + { convertData_, convertData_, + convertData_, convertData_, + convertData_, convertData_, + convertData_, 0 }, + + { convertData_, convertData_, + convertData_, convertData_, + convertData_, convertData_, + convertData_, 0 }, + + { convertData_, convertData_, + convertData_, convertData_, + convertData_, convertData_, + convertData_, 0 }, + + { convertData_, convertData_, + convertData_, convertData_, + convertData_, convertData_, + convertData_, 0 }, + + { 0, 0, 0, 0, 0, 0, 0, 0 }}; + + ConvertData func = tab[CV_MAT_DEPTH(fromType)][CV_MAT_DEPTH(toType)]; + CV_Assert( func != 0 ); + return func; +} + +ConvertScaleData getConvertScaleElem(int fromType, int toType) +{ + static ConvertScaleData tab[][8] = + {{ convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, 0 }, + + { convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, 0 }, + + { convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, 0 }, + + { convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, 0 }, + + { convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, 0 }, + + { convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, 0 }, + + { convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, convertScaleData_, + convertScaleData_, 0 }, + + { 0, 0, 0, 0, 0, 0, 0, 0 }}; + + ConvertScaleData func = tab[CV_MAT_DEPTH(fromType)][CV_MAT_DEPTH(toType)]; + CV_Assert( func != 0 ); + return func; +} + +enum { HASH_SIZE0 = 8 }; + +static inline void copyElem(const uchar* from, uchar* to, size_t elemSize) +{ + size_t i; + for( i = 0; (int)i <= (int)(elemSize - sizeof(int)); i += sizeof(int) ) + *(int*)(to + i) = *(const int*)(from + i); + for( ; i < elemSize; i++ ) + to[i] = from[i]; +} + +static inline bool isZeroElem(const uchar* data, size_t elemSize) +{ + size_t i; + for( i = 0; i <= elemSize - sizeof(int); i += sizeof(int) ) + if( *(int*)(data + i) != 0 ) + return false; + for( ; i < elemSize; i++ ) + if( data[i] != 0 ) + return false; + return true; +} + +SparseMat::Hdr::Hdr( int _dims, const int* _sizes, int _type ) +{ + refcount = 1; + + dims = _dims; + valueOffset = (int)alignSize(sizeof(SparseMat::Node) + + sizeof(int)*std::max(dims - CV_MAX_DIM, 0), CV_ELEM_SIZE1(_type)); + nodeSize = alignSize(valueOffset + + CV_ELEM_SIZE(_type), (int)sizeof(size_t)); + + int i; + for( i = 0; i < dims; i++ ) + size[i] = _sizes[i]; + for( ; i < CV_MAX_DIM; i++ ) + size[i] = 0; + clear(); +} + +void SparseMat::Hdr::clear() +{ + hashtab.clear(); + hashtab.resize(HASH_SIZE0); + pool.clear(); + pool.resize(nodeSize); + nodeCount = freeList = 0; +} + + +SparseMat::SparseMat(const Mat& m) +: flags(MAGIC_VAL), hdr(0) +{ + create( m.dims, m.size, m.type() ); + + int i, idx[CV_MAX_DIM] = {0}, d = m.dims, lastSize = m.size[d - 1]; + size_t esz = m.elemSize(); + uchar* dptr = m.data; + + for(;;) + { + for( i = 0; i < lastSize; i++, dptr += esz ) + { + if( isZeroElem(dptr, esz) ) + continue; + idx[d-1] = i; + uchar* to = newNode(idx, hash(idx)); + copyElem( dptr, to, esz ); + } + + for( i = d - 2; i >= 0; i-- ) + { + dptr += m.step[i] - m.size[i+1]*m.step[i+1]; + if( ++idx[i] < m.size[i] ) + break; + idx[i] = 0; + } + if( i < 0 ) + break; + } +} + +SparseMat::SparseMat(const CvSparseMat* m) +: flags(MAGIC_VAL), hdr(0) +{ + CV_Assert(m); + create( m->dims, &m->size[0], m->type ); + + CvSparseMatIterator it; + CvSparseNode* n = cvInitSparseMatIterator(m, &it); + size_t esz = elemSize(); + + for( ; n != 0; n = cvGetNextSparseNode(&it) ) + { + const int* idx = CV_NODE_IDX(m, n); + uchar* to = newNode(idx, hash(idx)); + copyElem((const uchar*)CV_NODE_VAL(m, n), to, esz); + } +} + +void SparseMat::create(int d, const int* _sizes, int _type) +{ + int i; + CV_Assert( _sizes && 0 < d && d <= CV_MAX_DIM ); + for( i = 0; i < d; i++ ) + CV_Assert( _sizes[i] > 0 ); + _type = CV_MAT_TYPE(_type); + if( hdr && _type == type() && hdr->dims == d && hdr->refcount == 1 ) + { + for( i = 0; i < d; i++ ) + if( _sizes[i] != hdr->size[i] ) + break; + if( i == d ) + { + clear(); + return; + } + } + release(); + flags = MAGIC_VAL | _type; + hdr = new Hdr(d, _sizes, _type); +} + +void SparseMat::copyTo( SparseMat& m ) const +{ + if( hdr == m.hdr ) + return; + if( !hdr ) + { + m.release(); + return; + } + m.create( hdr->dims, hdr->size, type() ); + SparseMatConstIterator from = begin(); + size_t i, N = nzcount(), esz = elemSize(); + + for( i = 0; i < N; i++, ++from ) + { + const Node* n = from.node(); + uchar* to = m.newNode(n->idx, n->hashval); + copyElem( from.ptr, to, esz ); + } +} + +void SparseMat::copyTo( Mat& m ) const +{ + CV_Assert( hdr ); + m.create( dims(), hdr->size, type() ); + m = Scalar(0); + + SparseMatConstIterator from = begin(); + size_t i, N = nzcount(), esz = elemSize(); + + for( i = 0; i < N; i++, ++from ) + { + const Node* n = from.node(); + copyElem( from.ptr, m.ptr(n->idx), esz); + } +} + + +void SparseMat::convertTo( SparseMat& m, int rtype, double alpha ) const +{ + int cn = channels(); + if( rtype < 0 ) + rtype = type(); + rtype = CV_MAKETYPE(rtype, cn); + if( hdr == m.hdr && rtype != type() ) + { + SparseMat temp; + convertTo(temp, rtype, alpha); + m = temp; + return; + } + + CV_Assert(hdr != 0); + if( hdr != m.hdr ) + m.create( hdr->dims, hdr->size, rtype ); + + SparseMatConstIterator from = begin(); + size_t i, N = nzcount(); + + if( alpha == 1 ) + { + ConvertData cvtfunc = getConvertElem(type(), rtype); + for( i = 0; i < N; i++, ++from ) + { + const Node* n = from.node(); + uchar* to = hdr == m.hdr ? from.ptr : m.newNode(n->idx, n->hashval); + cvtfunc( from.ptr, to, cn ); + } + } + else + { + ConvertScaleData cvtfunc = getConvertScaleElem(type(), rtype); + for( i = 0; i < N; i++, ++from ) + { + const Node* n = from.node(); + uchar* to = hdr == m.hdr ? from.ptr : m.newNode(n->idx, n->hashval); + cvtfunc( from.ptr, to, cn, alpha, 0 ); + } + } +} + + +void SparseMat::convertTo( Mat& m, int rtype, double alpha, double beta ) const +{ + int cn = channels(); + if( rtype < 0 ) + rtype = type(); + rtype = CV_MAKETYPE(rtype, cn); + + CV_Assert( hdr ); + m.create( dims(), hdr->size, rtype ); + m = Scalar(beta); + + SparseMatConstIterator from = begin(); + size_t i, N = nzcount(); + + if( alpha == 1 && beta == 0 ) + { + ConvertData cvtfunc = getConvertElem(type(), rtype); + for( i = 0; i < N; i++, ++from ) + { + const Node* n = from.node(); + uchar* to = m.ptr(n->idx); + cvtfunc( from.ptr, to, cn ); + } + } + else + { + ConvertScaleData cvtfunc = getConvertScaleElem(type(), rtype); + for( i = 0; i < N; i++, ++from ) + { + const Node* n = from.node(); + uchar* to = m.ptr(n->idx); + cvtfunc( from.ptr, to, cn, alpha, beta ); + } + } +} + +void SparseMat::clear() +{ + if( hdr ) + hdr->clear(); +} + +SparseMat::operator CvSparseMat*() const +{ + if( !hdr ) + return 0; + CvSparseMat* m = cvCreateSparseMat(hdr->dims, hdr->size, type()); + + SparseMatConstIterator from = begin(); + size_t i, N = nzcount(), esz = elemSize(); + + for( i = 0; i < N; i++, ++from ) + { + const Node* n = from.node(); + uchar* to = cvPtrND(m, n->idx, 0, -2, 0); + copyElem(from.ptr, to, esz); + } + return m; +} + +uchar* SparseMat::ptr(int i0, bool createMissing, size_t* hashval) +{ + CV_Assert( hdr && hdr->dims == 1 ); + size_t h = hashval ? *hashval : hash(i0); + size_t hidx = h & (hdr->hashtab.size() - 1), nidx = hdr->hashtab[hidx]; + uchar* pool = &hdr->pool[0]; + while( nidx != 0 ) + { + Node* elem = (Node*)(pool + nidx); + if( elem->hashval == h && elem->idx[0] == i0 ) + return &value(elem); + nidx = elem->next; + } + + if( createMissing ) + { + int idx[] = { i0 }; + return newNode( idx, h ); + } + return 0; +} + +uchar* SparseMat::ptr(int i0, int i1, bool createMissing, size_t* hashval) +{ + CV_Assert( hdr && hdr->dims == 2 ); + size_t h = hashval ? *hashval : hash(i0, i1); + size_t hidx = h & (hdr->hashtab.size() - 1), nidx = hdr->hashtab[hidx]; + uchar* pool = &hdr->pool[0]; + while( nidx != 0 ) + { + Node* elem = (Node*)(pool + nidx); + if( elem->hashval == h && elem->idx[0] == i0 && elem->idx[1] == i1 ) + return &value(elem); + nidx = elem->next; + } + + if( createMissing ) + { + int idx[] = { i0, i1 }; + return newNode( idx, h ); + } + return 0; +} + +uchar* SparseMat::ptr(int i0, int i1, int i2, bool createMissing, size_t* hashval) +{ + CV_Assert( hdr && hdr->dims == 3 ); + size_t h = hashval ? *hashval : hash(i0, i1, i2); + size_t hidx = h & (hdr->hashtab.size() - 1), nidx = hdr->hashtab[hidx]; + uchar* pool = &hdr->pool[0]; + while( nidx != 0 ) + { + Node* elem = (Node*)(pool + nidx); + if( elem->hashval == h && elem->idx[0] == i0 && + elem->idx[1] == i1 && elem->idx[2] == i2 ) + return &value(elem); + nidx = elem->next; + } + + if( createMissing ) + { + int idx[] = { i0, i1, i2 }; + return newNode( idx, h ); + } + return 0; +} + +uchar* SparseMat::ptr(const int* idx, bool createMissing, size_t* hashval) +{ + CV_Assert( hdr ); + int i, d = hdr->dims; + size_t h = hashval ? *hashval : hash(idx); + size_t hidx = h & (hdr->hashtab.size() - 1), nidx = hdr->hashtab[hidx]; + uchar* pool = &hdr->pool[0]; + while( nidx != 0 ) + { + Node* elem = (Node*)(pool + nidx); + if( elem->hashval == h ) + { + for( i = 0; i < d; i++ ) + if( elem->idx[i] != idx[i] ) + break; + if( i == d ) + return &value(elem); + } + nidx = elem->next; + } + + return createMissing ? newNode(idx, h) : 0; +} + +void SparseMat::erase(int i0, int i1, size_t* hashval) +{ + CV_Assert( hdr && hdr->dims == 2 ); + size_t h = hashval ? *hashval : hash(i0, i1); + size_t hidx = h & (hdr->hashtab.size() - 1), nidx = hdr->hashtab[hidx], previdx=0; + uchar* pool = &hdr->pool[0]; + while( nidx != 0 ) + { + Node* elem = (Node*)(pool + nidx); + if( elem->hashval == h && elem->idx[0] == i0 && elem->idx[1] == i1 ) + break; + previdx = nidx; + nidx = elem->next; + } + + if( nidx ) + removeNode(hidx, nidx, previdx); +} + +void SparseMat::erase(int i0, int i1, int i2, size_t* hashval) +{ + CV_Assert( hdr && hdr->dims == 3 ); + size_t h = hashval ? *hashval : hash(i0, i1, i2); + size_t hidx = h & (hdr->hashtab.size() - 1), nidx = hdr->hashtab[hidx], previdx=0; + uchar* pool = &hdr->pool[0]; + while( nidx != 0 ) + { + Node* elem = (Node*)(pool + nidx); + if( elem->hashval == h && elem->idx[0] == i0 && + elem->idx[1] == i1 && elem->idx[2] == i2 ) + break; + previdx = nidx; + nidx = elem->next; + } + + if( nidx ) + removeNode(hidx, nidx, previdx); +} + +void SparseMat::erase(const int* idx, size_t* hashval) +{ + CV_Assert( hdr ); + int i, d = hdr->dims; + size_t h = hashval ? *hashval : hash(idx); + size_t hidx = h & (hdr->hashtab.size() - 1), nidx = hdr->hashtab[hidx], previdx=0; + uchar* pool = &hdr->pool[0]; + while( nidx != 0 ) + { + Node* elem = (Node*)(pool + nidx); + if( elem->hashval == h ) + { + for( i = 0; i < d; i++ ) + if( elem->idx[i] != idx[i] ) + break; + if( i == d ) + break; + } + previdx = nidx; + nidx = elem->next; + } + + if( nidx ) + removeNode(hidx, nidx, previdx); +} + +void SparseMat::resizeHashTab(size_t newsize) +{ + newsize = std::max(newsize, (size_t)8); + if((newsize & (newsize-1)) != 0) + newsize = (size_t)1 << cvCeil(std::log((double)newsize)/CV_LOG2); + + size_t i, hsize = hdr->hashtab.size(); + vector _newh(newsize); + size_t* newh = &_newh[0]; + for( i = 0; i < newsize; i++ ) + newh[i] = 0; + uchar* pool = &hdr->pool[0]; + for( i = 0; i < hsize; i++ ) + { + size_t nidx = hdr->hashtab[i]; + while( nidx ) + { + Node* elem = (Node*)(pool + nidx); + size_t next = elem->next; + size_t newhidx = elem->hashval & (newsize - 1); + elem->next = newh[newhidx]; + newh[newhidx] = nidx; + nidx = next; + } + } + hdr->hashtab = _newh; +} + +uchar* SparseMat::newNode(const int* idx, size_t hashval) +{ + const int HASH_MAX_FILL_FACTOR=3; + assert(hdr); + size_t hsize = hdr->hashtab.size(); + if( ++hdr->nodeCount > hsize*HASH_MAX_FILL_FACTOR ) + { + resizeHashTab(std::max(hsize*2, (size_t)8)); + hsize = hdr->hashtab.size(); + } + + if( !hdr->freeList ) + { + size_t i, nsz = hdr->nodeSize, psize = hdr->pool.size(), + newpsize = std::max(psize*2, 8*nsz); + hdr->pool.resize(newpsize); + uchar* pool = &hdr->pool[0]; + hdr->freeList = std::max(psize, nsz); + for( i = hdr->freeList; i < newpsize - nsz; i += nsz ) + ((Node*)(pool + i))->next = i + nsz; + ((Node*)(pool + i))->next = 0; + } + size_t nidx = hdr->freeList; + Node* elem = (Node*)&hdr->pool[nidx]; + hdr->freeList = elem->next; + elem->hashval = hashval; + size_t hidx = hashval & (hsize - 1); + elem->next = hdr->hashtab[hidx]; + hdr->hashtab[hidx] = nidx; + + int i, d = hdr->dims; + for( i = 0; i < d; i++ ) + elem->idx[i] = idx[i]; + size_t esz = elemSize(); + uchar* p = &value(elem); + if( esz == sizeof(float) ) + *((float*)p) = 0.f; + else if( esz == sizeof(double) ) + *((double*)p) = 0.; + else + memset(p, 0, esz); + + return p; +} + + +void SparseMat::removeNode(size_t hidx, size_t nidx, size_t previdx) +{ + Node* n = node(nidx); + if( previdx ) + { + Node* prev = node(previdx); + prev->next = n->next; + } + else + hdr->hashtab[hidx] = n->next; + n->next = hdr->freeList; + hdr->freeList = nidx; + --hdr->nodeCount; +} + + +SparseMatConstIterator::SparseMatConstIterator(const SparseMat* _m) +: m((SparseMat*)_m), hashidx(0), ptr(0) +{ + if(!_m || !_m->hdr) + return; + SparseMat::Hdr& hdr = *m->hdr; + const vector& htab = hdr.hashtab; + size_t i, hsize = htab.size(); + for( i = 0; i < hsize; i++ ) + { + size_t nidx = htab[i]; + if( nidx ) + { + hashidx = i; + ptr = &hdr.pool[nidx] + hdr.valueOffset; + return; + } + } +} + +SparseMatConstIterator& SparseMatConstIterator::operator ++() +{ + if( !ptr || !m || !m->hdr ) + return *this; + SparseMat::Hdr& hdr = *m->hdr; + size_t next = ((const SparseMat::Node*)(ptr - hdr.valueOffset))->next; + if( next ) + { + ptr = &hdr.pool[next] + hdr.valueOffset; + return *this; + } + size_t i = hashidx + 1, sz = hdr.hashtab.size(); + for( ; i < sz; i++ ) + { + size_t nidx = hdr.hashtab[i]; + if( nidx ) + { + hashidx = i; + ptr = &hdr.pool[nidx] + hdr.valueOffset; + return *this; + } + } + hashidx = sz; + ptr = 0; + return *this; +} + + +double norm( const SparseMat& src, int normType ) +{ + SparseMatConstIterator it = src.begin(); + + size_t i, N = src.nzcount(); + normType &= NORM_TYPE_MASK; + int type = src.type(); + double result = 0; + + CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 ); + + if( type == CV_32F ) + { + if( normType == NORM_INF ) + for( i = 0; i < N; i++, ++it ) + result = std::max(result, std::abs((double)*(const float*)it.ptr)); + else if( normType == NORM_L1 ) + for( i = 0; i < N; i++, ++it ) + result += std::abs(*(const float*)it.ptr); + else + for( i = 0; i < N; i++, ++it ) + { + double v = *(const float*)it.ptr; + result += v*v; + } + } + else if( type == CV_64F ) + { + if( normType == NORM_INF ) + for( i = 0; i < N; i++, ++it ) + result = std::max(result, std::abs(*(const double*)it.ptr)); + else if( normType == NORM_L1 ) + for( i = 0; i < N; i++, ++it ) + result += std::abs(*(const double*)it.ptr); + else + for( i = 0; i < N; i++, ++it ) + { + double v = *(const double*)it.ptr; + result += v*v; + } + } + else + CV_Error( CV_StsUnsupportedFormat, "Only 32f and 64f are supported" ); + + if( normType == NORM_L2 ) + result = std::sqrt(result); + return result; +} + +void minMaxLoc( const SparseMat& src, double* _minval, double* _maxval, int* _minidx, int* _maxidx ) +{ + SparseMatConstIterator it = src.begin(); + size_t i, N = src.nzcount(), d = src.hdr ? src.hdr->dims : 0; + int type = src.type(); + const int *minidx = 0, *maxidx = 0; + + if( type == CV_32F ) + { + float minval = FLT_MAX, maxval = -FLT_MAX; + for( i = 0; i < N; i++, ++it ) + { + float v = *(const float*)it.ptr; + if( v < minval ) + { + minval = v; + minidx = it.node()->idx; + } + if( v > maxval ) + { + maxval = v; + maxidx = it.node()->idx; + } + } + if( _minval ) + *_minval = minval; + if( _maxval ) + *_maxval = maxval; + } + else if( type == CV_64F ) + { + double minval = DBL_MAX, maxval = -DBL_MAX; + for( i = 0; i < N; i++, ++it ) + { + double v = *(const double*)it.ptr; + if( v < minval ) + { + minval = v; + minidx = it.node()->idx; + } + if( v > maxval ) + { + maxval = v; + maxidx = it.node()->idx; + } + } + if( _minval ) + *_minval = minval; + if( _maxval ) + *_maxval = maxval; + } + else + CV_Error( CV_StsUnsupportedFormat, "Only 32f and 64f are supported" ); + + if( _minidx ) + for( i = 0; i < d; i++ ) + _minidx[i] = minidx[i]; + if( _maxidx ) + for( i = 0; i < d; i++ ) + _maxidx[i] = maxidx[i]; +} + + +void normalize( const SparseMat& src, SparseMat& dst, double a, int norm_type ) +{ + double scale = 1; + if( norm_type == CV_L2 || norm_type == CV_L1 || norm_type == CV_C ) + { + scale = norm( src, norm_type ); + scale = scale > DBL_EPSILON ? a/scale : 0.; + } + else + CV_Error( CV_StsBadArg, "Unknown/unsupported norm type" ); + + src.convertTo( dst, -1, scale ); +} + +////////////////////// RotatedRect ////////////////////// + +void RotatedRect::points(Point2f pt[]) const +{ + double _angle = angle*CV_PI/180.; + float b = (float)cos(_angle)*0.5f; + float a = (float)sin(_angle)*0.5f; + + pt[0].x = center.x - a*size.height - b*size.width; + pt[0].y = center.y + b*size.height - a*size.width; + pt[1].x = center.x + a*size.height - b*size.width; + pt[1].y = center.y - b*size.height - a*size.width; + pt[2].x = 2*center.x - pt[0].x; + pt[2].y = 2*center.y - pt[0].y; + pt[3].x = 2*center.x - pt[1].x; + pt[3].y = 2*center.y - pt[1].y; +} + +Rect RotatedRect::boundingRect() const +{ + Point2f pt[4]; + points(pt); + Rect r(cvFloor(min(min(min(pt[0].x, pt[1].x), pt[2].x), pt[3].x)), + cvFloor(min(min(min(pt[0].y, pt[1].y), pt[2].y), pt[3].y)), + cvCeil(max(max(max(pt[0].x, pt[1].x), pt[2].x), pt[3].x)), + cvCeil(max(max(max(pt[0].y, pt[1].y), pt[2].y), pt[3].y))); + r.width -= r.x - 1; + r.height -= r.y - 1; + return r; +} + +} + +/* End of file. */ diff --git a/core/src/opengl_interop.cpp b/core/src/opengl_interop.cpp new file mode 100644 index 0000000..5895363 --- /dev/null +++ b/core/src/opengl_interop.cpp @@ -0,0 +1,1589 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include +#include "opencv2/core/opengl_interop.hpp" +#include "opencv2/core/gpumat.hpp" + +#ifdef HAVE_OPENGL + #ifdef __APPLE__ + #include + #include + #else + #include + #include + #endif + + #ifdef HAVE_CUDA + #include + #include + #endif +#endif + +using namespace std; +using namespace cv; +using namespace cv::gpu; + +#ifndef HAVE_OPENGL + #define throw_nogl CV_Error(CV_OpenGlNotSupported, "The library is compiled without OpenGL support") + #define throw_nocuda CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support") +#else + #define throw_nogl CV_Error(CV_OpenGlNotSupported, "OpenGL context doesn't exist") + + #ifndef HAVE_CUDA + #define throw_nocuda CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support") + #else + #if defined(__GNUC__) + #define cudaSafeCall(expr) ___cudaSafeCall(expr, __FILE__, __LINE__, __func__) + #else /* defined(__CUDACC__) || defined(__MSVC__) */ + #define cudaSafeCall(expr) ___cudaSafeCall(expr, __FILE__, __LINE__) + #endif + + namespace + { + inline void ___cudaSafeCall(cudaError_t err, const char *file, const int line, const char *func = "") + { + if (cudaSuccess != err) + cv::gpu::error(cudaGetErrorString(err), file, line, func); + } + } + #endif // HAVE_CUDA +#endif + +namespace +{ + class EmptyGlFuncTab : public CvOpenGlFuncTab + { + public: + void genBuffers(int, unsigned int*) const { throw_nogl; } + void deleteBuffers(int, const unsigned int*) const { throw_nogl; } + + void bufferData(unsigned int, ptrdiff_t, const void*, unsigned int) const { throw_nogl; } + void bufferSubData(unsigned int, ptrdiff_t, ptrdiff_t, const void*) const { throw_nogl; } + + void bindBuffer(unsigned int, unsigned int) const { throw_nogl; } + + void* mapBuffer(unsigned int, unsigned int) const { throw_nogl; return 0; } + void unmapBuffer(unsigned int) const { throw_nogl; } + + void generateBitmapFont(const std::string&, int, int, bool, bool, int, int, int) const { throw_nogl; } + + bool isGlContextInitialized() const { return false; } + }; + + const CvOpenGlFuncTab* g_glFuncTab = 0; + +#if defined HAVE_CUDA || defined HAVE_OPENGL + const CvOpenGlFuncTab* glFuncTab() + { + static EmptyGlFuncTab empty; + return g_glFuncTab ? g_glFuncTab : ∅ + } +#endif +} + +CvOpenGlFuncTab::~CvOpenGlFuncTab() +{ + if (g_glFuncTab == this) + g_glFuncTab = 0; +} + +void icvSetOpenGlFuncTab(const CvOpenGlFuncTab* tab) +{ + g_glFuncTab = tab; +} + +#ifdef HAVE_OPENGL + #ifndef GL_DYNAMIC_DRAW + #define GL_DYNAMIC_DRAW 0x88E8 + #endif + + #ifndef GL_READ_WRITE + #define GL_READ_WRITE 0x88BA + #endif + + #ifndef GL_BGR + #define GL_BGR 0x80E0 + #endif + + #ifndef GL_BGRA + #define GL_BGRA 0x80E1 + #endif + + namespace + { + const GLenum gl_types[] = {GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE}; + + #ifdef HAVE_CUDA + bool g_isCudaGlDeviceInitialized = false; + #endif + } +#endif // HAVE_OPENGL + +void cv::gpu::setGlDevice(int device) +{ +#ifndef HAVE_CUDA + (void)device; + throw_nocuda; +#else + #ifndef HAVE_OPENGL + (void)device; + throw_nogl; + #else + if (!glFuncTab()->isGlContextInitialized()) + throw_nogl; + + cudaSafeCall( cudaGLSetGLDevice(device) ); + + g_isCudaGlDeviceInitialized = true; + #endif +#endif +} + +//////////////////////////////////////////////////////////////////////// +// CudaGlInterop + +#if defined HAVE_CUDA && defined HAVE_OPENGL +namespace +{ + class CudaGlInterop + { + public: + CudaGlInterop(); + ~CudaGlInterop(); + + void registerBuffer(unsigned int buffer); + + void copyFrom(const GpuMat& mat, cudaStream_t stream = 0); + + GpuMat map(int rows, int cols, int type, cudaStream_t stream = 0); + void unmap(cudaStream_t stream = 0); + + private: + cudaGraphicsResource_t resource_; + }; + + inline CudaGlInterop::CudaGlInterop() : resource_(0) + { + } + + CudaGlInterop::~CudaGlInterop() + { + if (resource_) + { + cudaGraphicsUnregisterResource(resource_); + resource_ = 0; + } + } + + void CudaGlInterop::registerBuffer(unsigned int buffer) + { + if (!g_isCudaGlDeviceInitialized) + cvError(CV_GpuApiCallError, "registerBuffer", "cuda GL device wasn't initialized, call setGlDevice", __FILE__, __LINE__); + + cudaGraphicsResource_t resource; + cudaSafeCall( cudaGraphicsGLRegisterBuffer(&resource, buffer, cudaGraphicsMapFlagsNone) ); + + resource_ = resource; + } + + void CudaGlInterop::copyFrom(const GpuMat& mat, cudaStream_t stream) + { + CV_Assert(resource_ != 0); + + cudaSafeCall( cudaGraphicsMapResources(1, &resource_, stream) ); + + void* dst_ptr; + size_t num_bytes; + cudaSafeCall( cudaGraphicsResourceGetMappedPointer(&dst_ptr, &num_bytes, resource_) ); + + const void* src_ptr = mat.ptr(); + size_t widthBytes = mat.cols * mat.elemSize(); + + CV_Assert(widthBytes * mat.rows <= num_bytes); + + if (stream == 0) + cudaSafeCall( cudaMemcpy2D(dst_ptr, widthBytes, src_ptr, mat.step, widthBytes, mat.rows, cudaMemcpyDeviceToDevice) ); + else + cudaSafeCall( cudaMemcpy2DAsync(dst_ptr, widthBytes, src_ptr, mat.step, widthBytes, mat.rows, cudaMemcpyDeviceToDevice, stream) ); + + cudaGraphicsUnmapResources(1, &resource_, stream); + } + + GpuMat CudaGlInterop::map(int rows, int cols, int type, cudaStream_t stream) + { + CV_Assert(resource_ != 0); + + cudaSafeCall( cudaGraphicsMapResources(1, &resource_, stream) ); + + void* ptr; + size_t num_bytes; + cudaSafeCall( cudaGraphicsResourceGetMappedPointer(&ptr, &num_bytes, resource_) ); + + CV_Assert( static_cast(cols) * CV_ELEM_SIZE(type) * rows <= num_bytes ); + + return GpuMat(rows, cols, type, ptr); + } + + inline void CudaGlInterop::unmap(cudaStream_t stream) + { + cudaGraphicsUnmapResources(1, &resource_, stream); + } +} +#endif // HAVE_CUDA && HAVE_OPENGL + +//////////////////////////////////////////////////////////////////////// +// GlBuffer + +#ifndef HAVE_OPENGL + +class cv::GlBuffer::Impl +{ +}; + +#else + +class cv::GlBuffer::Impl +{ +public: + static const Ptr& empty(); + + Impl(int rows, int cols, int type, unsigned int target); + Impl(const Mat& m, unsigned int target); + ~Impl(); + + void copyFrom(const Mat& m, unsigned int target); + +#ifdef HAVE_CUDA + void copyFrom(const GpuMat& mat, cudaStream_t stream = 0); +#endif + + void bind(unsigned int target) const; + void unbind(unsigned int target) const; + + Mat mapHost(int rows, int cols, int type, unsigned int target); + void unmapHost(unsigned int target); + +#ifdef HAVE_CUDA + GpuMat mapDevice(int rows, int cols, int type, cudaStream_t stream = 0); + void unmapDevice(cudaStream_t stream = 0); +#endif + +private: + Impl(); + + unsigned int buffer_; + +#ifdef HAVE_CUDA + CudaGlInterop cudaGlInterop_; +#endif +}; + +inline const Ptr& cv::GlBuffer::Impl::empty() +{ + static Ptr p(new Impl); + return p; +} + +inline cv::GlBuffer::Impl::Impl() : buffer_(0) +{ +} + +cv::GlBuffer::Impl::Impl(int rows, int cols, int type, unsigned int target) : buffer_(0) +{ + if (!glFuncTab()->isGlContextInitialized()) + throw_nogl; + + CV_DbgAssert(rows > 0 && cols > 0); + CV_DbgAssert(CV_MAT_DEPTH(type) >= 0 && CV_MAT_DEPTH(type) <= CV_64F); + + glFuncTab()->genBuffers(1, &buffer_); + CV_CheckGlError(); + CV_Assert(buffer_ != 0); + + size_t size = rows * cols * CV_ELEM_SIZE(type); + + glFuncTab()->bindBuffer(target, buffer_); + CV_CheckGlError(); + + glFuncTab()->bufferData(target, size, 0, GL_DYNAMIC_DRAW); + CV_CheckGlError(); + + glFuncTab()->bindBuffer(target, 0); + +#ifdef HAVE_CUDA + if (g_isCudaGlDeviceInitialized) + cudaGlInterop_.registerBuffer(buffer_); +#endif +} + +cv::GlBuffer::Impl::Impl(const Mat& m, unsigned int target) : buffer_(0) +{ + if (!glFuncTab()->isGlContextInitialized()) + throw_nogl; + + CV_DbgAssert(m.rows > 0 && m.cols > 0); + CV_DbgAssert(m.depth() >= 0 && m.depth() <= CV_64F); + CV_Assert(m.isContinuous()); + + glFuncTab()->genBuffers(1, &buffer_); + CV_CheckGlError(); + CV_Assert(buffer_ != 0); + + size_t size = m.rows * m.cols * m.elemSize(); + + glFuncTab()->bindBuffer(target, buffer_); + CV_CheckGlError(); + + glFuncTab()->bufferData(target, size, m.data, GL_DYNAMIC_DRAW); + CV_CheckGlError(); + + glFuncTab()->bindBuffer(target, 0); + +#ifdef HAVE_CUDA + if (g_isCudaGlDeviceInitialized) + cudaGlInterop_.registerBuffer(buffer_); +#endif +} + +cv::GlBuffer::Impl::~Impl() +{ + try + { + if (buffer_) + glFuncTab()->deleteBuffers(1, &buffer_); + } +#ifdef _DEBUG + catch(const exception& e) + { + cerr << e.what() << endl; + } +#endif + catch(...) + { + } +} + +void cv::GlBuffer::Impl::copyFrom(const Mat& m, unsigned int target) +{ + CV_Assert(buffer_ != 0); + + CV_Assert(m.isContinuous()); + + bind(target); + + size_t size = m.rows * m.cols * m.elemSize(); + + glFuncTab()->bufferSubData(target, 0, size, m.data); + CV_CheckGlError(); + + unbind(target); +} + +#ifdef HAVE_CUDA + +void cv::GlBuffer::Impl::copyFrom(const GpuMat& mat, cudaStream_t stream) +{ + if (!g_isCudaGlDeviceInitialized) + cvError(CV_GpuApiCallError, "copyFrom", "cuda GL device wasn't initialized, call setGlDevice", __FILE__, __LINE__); + + CV_Assert(buffer_ != 0); + + cudaGlInterop_.copyFrom(mat, stream); +} + +#endif // HAVE_CUDA + +inline void cv::GlBuffer::Impl::bind(unsigned int target) const +{ + CV_Assert(buffer_ != 0); + + glFuncTab()->bindBuffer(target, buffer_); + CV_CheckGlError(); +} + +inline void cv::GlBuffer::Impl::unbind(unsigned int target) const +{ + glFuncTab()->bindBuffer(target, 0); +} + +inline Mat cv::GlBuffer::Impl::mapHost(int rows, int cols, int type, unsigned int target) +{ + void* ptr = glFuncTab()->mapBuffer(target, GL_READ_WRITE); + CV_CheckGlError(); + + return Mat(rows, cols, type, ptr); +} + +inline void cv::GlBuffer::Impl::unmapHost(unsigned int target) +{ + glFuncTab()->unmapBuffer(target); +} + +#ifdef HAVE_CUDA + +inline GpuMat cv::GlBuffer::Impl::mapDevice(int rows, int cols, int type, cudaStream_t stream) +{ + if (!g_isCudaGlDeviceInitialized) + cvError(CV_GpuApiCallError, "copyFrom", "cuda GL device wasn't initialized, call setGlDevice", __FILE__, __LINE__); + + CV_Assert(buffer_ != 0); + + return cudaGlInterop_.map(rows, cols, type, stream); +} + +inline void cv::GlBuffer::Impl::unmapDevice(cudaStream_t stream) +{ + if (!g_isCudaGlDeviceInitialized) + cvError(CV_GpuApiCallError, "copyFrom", "cuda GL device wasn't initialized, call setGlDevice", __FILE__, __LINE__); + + cudaGlInterop_.unmap(stream); +} + +#endif // HAVE_CUDA + +#endif // HAVE_OPENGL + +cv::GlBuffer::GlBuffer(Usage _usage) : rows_(0), cols_(0), type_(0), usage_(_usage) +{ +#ifndef HAVE_OPENGL + (void)_usage; + throw_nogl; +#else + impl_ = Impl::empty(); +#endif +} + +cv::GlBuffer::GlBuffer(int _rows, int _cols, int _type, Usage _usage) : rows_(0), cols_(0), type_(0), usage_(_usage) +{ +#ifndef HAVE_OPENGL + (void)_rows; + (void)_cols; + (void)_type; + (void)_usage; + throw_nogl; +#else + impl_ = new Impl(_rows, _cols, _type, _usage); + rows_ = _rows; + cols_ = _cols; + type_ = _type; +#endif +} + +cv::GlBuffer::GlBuffer(Size _size, int _type, Usage _usage) : rows_(0), cols_(0), type_(0), usage_(_usage) +{ +#ifndef HAVE_OPENGL + (void)_size; + (void)_type; + (void)_usage; + throw_nogl; +#else + impl_ = new Impl(_size.height, _size.width, _type, _usage); + rows_ = _size.height; + cols_ = _size.width; + type_ = _type; +#endif +} + +cv::GlBuffer::GlBuffer(InputArray mat_, Usage _usage) : rows_(0), cols_(0), type_(0), usage_(_usage) +{ +#ifndef HAVE_OPENGL + (void)mat_; + (void)_usage; + throw_nogl; +#else + int kind = mat_.kind(); + Size _size = mat_.size(); + int _type = mat_.type(); + + if (kind == _InputArray::GPU_MAT) + { + #ifndef HAVE_CUDA + throw_nocuda; + #else + GpuMat d_mat = mat_.getGpuMat(); + impl_ = new Impl(d_mat.rows, d_mat.cols, d_mat.type(), _usage); + impl_->copyFrom(d_mat); + #endif + } + else + { + Mat mat = mat_.getMat(); + impl_ = new Impl(mat, _usage); + } + + rows_ = _size.height; + cols_ = _size.width; + type_ = _type; +#endif +} + +void cv::GlBuffer::create(int _rows, int _cols, int _type, Usage _usage) +{ +#ifndef HAVE_OPENGL + (void)_rows; + (void)_cols; + (void)_type; + (void)_usage; + throw_nogl; +#else + if (rows_ != _rows || cols_ != _cols || type_ != _type || usage_ != _usage) + { + impl_ = new Impl(_rows, _cols, _type, _usage); + rows_ = _rows; + cols_ = _cols; + type_ = _type; + usage_ = _usage; + } +#endif +} + +void cv::GlBuffer::release() +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + impl_ = Impl::empty(); +#endif +} + +void cv::GlBuffer::copyFrom(InputArray mat_) +{ +#ifndef HAVE_OPENGL + (void)mat_; + throw_nogl; +#else + int kind = mat_.kind(); + Size _size = mat_.size(); + int _type = mat_.type(); + + create(_size, _type); + + switch (kind) + { + case _InputArray::OPENGL_BUFFER: + { + GlBuffer buf = mat_.getGlBuffer(); + *this = buf; + break; + } + case _InputArray::GPU_MAT: + { + #ifndef HAVE_CUDA + throw_nocuda; + #else + GpuMat d_mat = mat_.getGpuMat(); + impl_->copyFrom(d_mat); + #endif + + break; + } + default: + { + Mat mat = mat_.getMat(); + impl_->copyFrom(mat, usage_); + } + } +#endif +} + +void cv::GlBuffer::bind() const +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + impl_->bind(usage_); +#endif +} + +void cv::GlBuffer::unbind() const +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + impl_->unbind(usage_); +#endif +} + +Mat cv::GlBuffer::mapHost() +{ +#ifndef HAVE_OPENGL + throw_nogl; + return Mat(); +#else + return impl_->mapHost(rows_, cols_, type_, usage_); +#endif +} + +void cv::GlBuffer::unmapHost() +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + impl_->unmapHost(usage_); +#endif +} + +GpuMat cv::GlBuffer::mapDevice() +{ +#ifndef HAVE_OPENGL + throw_nogl; + return GpuMat(); +#else + #ifndef HAVE_CUDA + throw_nocuda; + return GpuMat(); + #else + return impl_->mapDevice(rows_, cols_, type_); + #endif +#endif +} + +void cv::GlBuffer::unmapDevice() +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + #ifndef HAVE_CUDA + throw_nocuda; + #else + impl_->unmapDevice(); + #endif +#endif +} + +template <> void cv::Ptr::delete_obj() +{ + if (obj) delete obj; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// GlTexture + +#ifndef HAVE_OPENGL + +class cv::GlTexture::Impl +{ +}; + +#else + +class cv::GlTexture::Impl +{ +public: + static const Ptr empty(); + + Impl(int rows, int cols, int type); + + Impl(const Mat& mat, bool bgra); + Impl(const GlBuffer& buf, bool bgra); + + ~Impl(); + + void copyFrom(const Mat& mat, bool bgra); + void copyFrom(const GlBuffer& buf, bool bgra); + + void bind() const; + void unbind() const; + +private: + Impl(); + + GLuint tex_; +}; + +inline const Ptr cv::GlTexture::Impl::empty() +{ + static Ptr p(new Impl); + return p; +} + +inline cv::GlTexture::Impl::Impl() : tex_(0) +{ +} + +cv::GlTexture::Impl::Impl(int rows, int cols, int type) : tex_(0) +{ + if (!glFuncTab()->isGlContextInitialized()) + throw_nogl; + + int depth = CV_MAT_DEPTH(type); + int cn = CV_MAT_CN(type); + + CV_DbgAssert(rows > 0 && cols > 0); + CV_Assert(cn == 1 || cn == 3 || cn == 4); + CV_Assert(depth >= 0 && depth <= CV_32F); + + glGenTextures(1, &tex_); + CV_CheckGlError(); + CV_Assert(tex_ != 0); + + glBindTexture(GL_TEXTURE_2D, tex_); + CV_CheckGlError(); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + CV_CheckGlError(); + + GLenum format = cn == 1 ? GL_LUMINANCE : cn == 3 ? GL_BGR : GL_BGRA; + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + CV_CheckGlError(); + + glTexImage2D(GL_TEXTURE_2D, 0, cn, cols, rows, 0, format, gl_types[depth], 0); + CV_CheckGlError(); +} + +cv::GlTexture::Impl::Impl(const Mat& mat, bool bgra) : tex_(0) +{ + if (!glFuncTab()->isGlContextInitialized()) + throw_nogl; + + int depth = mat.depth(); + int cn = mat.channels(); + + CV_DbgAssert(mat.rows > 0 && mat.cols > 0); + CV_Assert(cn == 1 || cn == 3 || cn == 4); + CV_Assert(depth >= 0 && depth <= CV_32F); + CV_Assert(mat.isContinuous()); + + glGenTextures(1, &tex_); + CV_CheckGlError(); + CV_Assert(tex_ != 0); + + glBindTexture(GL_TEXTURE_2D, tex_); + CV_CheckGlError(); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + CV_CheckGlError(); + + GLenum format = cn == 1 ? GL_LUMINANCE : (cn == 3 ? (bgra ? GL_BGR : GL_RGB) : (bgra ? GL_BGRA : GL_RGBA)); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + CV_CheckGlError(); + + glTexImage2D(GL_TEXTURE_2D, 0, cn, mat.cols, mat.rows, 0, format, gl_types[depth], mat.data); + CV_CheckGlError(); +} + +cv::GlTexture::Impl::Impl(const GlBuffer& buf, bool bgra) : tex_(0) +{ + if (!glFuncTab()->isGlContextInitialized()) + throw_nogl; + + int depth = buf.depth(); + int cn = buf.channels(); + + CV_DbgAssert(buf.rows() > 0 && buf.cols() > 0); + CV_Assert(cn == 1 || cn == 3 || cn == 4); + CV_Assert(depth >= 0 && depth <= CV_32F); + CV_Assert(buf.usage() == GlBuffer::TEXTURE_BUFFER); + + glGenTextures(1, &tex_); + CV_CheckGlError(); + CV_Assert(tex_ != 0); + + glBindTexture(GL_TEXTURE_2D, tex_); + CV_CheckGlError(); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + CV_CheckGlError(); + + GLenum format = cn == 1 ? GL_LUMINANCE : (cn == 3 ? (bgra ? GL_BGR : GL_RGB) : (bgra ? GL_BGRA : GL_RGBA)); + + buf.bind(); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + CV_CheckGlError(); + + glTexImage2D(GL_TEXTURE_2D, 0, cn, buf.cols(), buf.rows(), 0, format, gl_types[depth], 0); + CV_CheckGlError(); + + buf.unbind(); +} + +inline cv::GlTexture::Impl::~Impl() +{ + if (tex_) + glDeleteTextures(1, &tex_); +} + +void cv::GlTexture::Impl::copyFrom(const Mat& mat, bool bgra) +{ + CV_Assert(tex_ != 0); + + bind(); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + CV_CheckGlError(); + + int cn = mat.channels(); + GLenum format = cn == 1 ? GL_LUMINANCE : (cn == 3 ? (bgra ? GL_BGR : GL_RGB) : (bgra ? GL_BGRA : GL_RGBA)); + + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mat.cols, mat.rows, format, gl_types[mat.depth()], mat.data); + CV_CheckGlError(); + + unbind(); +} + +void cv::GlTexture::Impl::copyFrom(const GlBuffer& buf, bool bgra) +{ + CV_Assert(tex_ != 0); + CV_Assert(buf.usage() == GlBuffer::TEXTURE_BUFFER); + + bind(); + + buf.bind(); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + CV_CheckGlError(); + + int cn = buf.channels(); + GLenum format = cn == 1 ? GL_LUMINANCE : (cn == 3 ? (bgra ? GL_BGR : GL_RGB) : (bgra ? GL_BGRA : GL_RGBA)); + + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, buf.cols(), buf.rows(), format, gl_types[buf.depth()], 0); + CV_CheckGlError(); + + buf.unbind(); + + unbind(); +} + +inline void cv::GlTexture::Impl::bind() const +{ + CV_Assert(tex_ != 0); + + glEnable(GL_TEXTURE_2D); + CV_CheckGlError(); + + glBindTexture(GL_TEXTURE_2D, tex_); + CV_CheckGlError(); +} + +inline void cv::GlTexture::Impl::unbind() const +{ + glBindTexture(GL_TEXTURE_2D, 0); + + glDisable(GL_TEXTURE_2D); +} + +#endif // HAVE_OPENGL + +cv::GlTexture::GlTexture() : rows_(0), cols_(0), type_(0), buf_(GlBuffer::TEXTURE_BUFFER) +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + impl_ = Impl::empty(); +#endif +} + +cv::GlTexture::GlTexture(int _rows, int _cols, int _type) : rows_(0), cols_(0), type_(0), buf_(GlBuffer::TEXTURE_BUFFER) +{ +#ifndef HAVE_OPENGL + (void)_rows; + (void)_cols; + (void)_type; + throw_nogl; +#else + impl_ = new Impl(_rows, _cols, _type); + rows_ = _rows; + cols_ = _cols; + type_ = _type; +#endif +} + +cv::GlTexture::GlTexture(Size _size, int _type) : rows_(0), cols_(0), type_(0), buf_(GlBuffer::TEXTURE_BUFFER) +{ +#ifndef HAVE_OPENGL + (void)_size; + (void)_type; + throw_nogl; +#else + impl_ = new Impl(_size.height, _size.width, _type); + rows_ = _size.height; + cols_ = _size.width; + type_ = _type; +#endif +} + +cv::GlTexture::GlTexture(InputArray mat_, bool bgra) : rows_(0), cols_(0), type_(0), buf_(GlBuffer::TEXTURE_BUFFER) +{ +#ifndef HAVE_OPENGL + (void)mat_; + (void)bgra; + throw_nogl; +#else + int kind = mat_.kind(); + Size _size = mat_.size(); + int _type = mat_.type(); + + switch (kind) + { + case _InputArray::OPENGL_BUFFER: + { + GlBuffer buf = mat_.getGlBuffer(); + impl_ = new Impl(buf, bgra); + break; + } + case _InputArray::GPU_MAT: + { + #ifndef HAVE_CUDA + throw_nocuda; + #else + GpuMat d_mat = mat_.getGpuMat(); + GlBuffer buf(d_mat, GlBuffer::TEXTURE_BUFFER); + impl_ = new Impl(buf, bgra); + #endif + + break; + } + default: + { + Mat mat = mat_.getMat(); + impl_ = new Impl(mat, bgra); + break; + } + } + + rows_ = _size.height; + cols_ = _size.width; + type_ = _type; +#endif +} + +void cv::GlTexture::create(int _rows, int _cols, int _type) +{ +#ifndef HAVE_OPENGL + (void)_rows; + (void)_cols; + (void)_type; + throw_nogl; +#else + if (rows_ != _rows || cols_ != _cols || type_ != _type) + { + impl_ = new Impl(_rows, _cols, _type); + rows_ = _rows; + cols_ = _cols; + type_ = _type; + } +#endif +} + +void cv::GlTexture::release() +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + impl_ = Impl::empty(); +#endif +} + +void cv::GlTexture::copyFrom(InputArray mat_, bool bgra) +{ +#ifndef HAVE_OPENGL + (void)mat_; + (void)bgra; + throw_nogl; +#else + int kind = mat_.kind(); + Size _size = mat_.size(); + int _type = mat_.type(); + + create(_size, _type); + + switch(kind) + { + case _InputArray::OPENGL_TEXTURE: + { + GlTexture tex = mat_.getGlTexture(); + *this = tex; + break; + } + case _InputArray::OPENGL_BUFFER: + { + GlBuffer buf = mat_.getGlBuffer(); + impl_->copyFrom(buf, bgra); + break; + } + case _InputArray::GPU_MAT: + { + #ifndef HAVE_CUDA + throw_nocuda; + #else + GpuMat d_mat = mat_.getGpuMat(); + buf_.copyFrom(d_mat); + impl_->copyFrom(buf_, bgra); + #endif + + break; + } + default: + { + Mat mat = mat_.getMat(); + impl_->copyFrom(mat, bgra); + } + } +#endif +} + +void cv::GlTexture::bind() const +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + impl_->bind(); +#endif +} + +void cv::GlTexture::unbind() const +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + impl_->unbind(); +#endif +} + +template <> void cv::Ptr::delete_obj() +{ + if (obj) delete obj; +} + +//////////////////////////////////////////////////////////////////////// +// GlArrays + +void cv::GlArrays::setVertexArray(InputArray vertex) +{ + int cn = vertex.channels(); + int depth = vertex.depth(); + + CV_Assert(cn == 2 || cn == 3 || cn == 4); + CV_Assert(depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F); + + vertex_.copyFrom(vertex); +} + +void cv::GlArrays::setColorArray(InputArray color, bool bgra) +{ + int cn = color.channels(); + + CV_Assert((cn == 3 && !bgra) || cn == 4); + + color_.copyFrom(color); + bgra_ = bgra; +} + +void cv::GlArrays::setNormalArray(InputArray normal) +{ + int cn = normal.channels(); + int depth = normal.depth(); + + CV_Assert(cn == 3); + CV_Assert(depth == CV_8S || depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F); + + normal_.copyFrom(normal); +} + +void cv::GlArrays::setTexCoordArray(InputArray texCoord) +{ + int cn = texCoord.channels(); + int depth = texCoord.depth(); + + CV_Assert(cn >= 1 && cn <= 4); + CV_Assert(depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F); + + texCoord_.copyFrom(texCoord); +} + +void cv::GlArrays::bind() const +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + CV_DbgAssert(texCoord_.empty() || texCoord_.size().area() == vertex_.size().area()); + CV_DbgAssert(normal_.empty() || normal_.size().area() == vertex_.size().area()); + CV_DbgAssert(color_.empty() || color_.size().area() == vertex_.size().area()); + + if (!texCoord_.empty()) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + CV_CheckGlError(); + + texCoord_.bind(); + + glTexCoordPointer(texCoord_.channels(), gl_types[texCoord_.depth()], 0, 0); + CV_CheckGlError(); + + texCoord_.unbind(); + } + + if (!normal_.empty()) + { + glEnableClientState(GL_NORMAL_ARRAY); + CV_CheckGlError(); + + normal_.bind(); + + glNormalPointer(gl_types[normal_.depth()], 0, 0); + CV_CheckGlError(); + + normal_.unbind(); + } + + if (!color_.empty()) + { + glEnableClientState(GL_COLOR_ARRAY); + CV_CheckGlError(); + + color_.bind(); + + int cn = color_.channels(); + int format = cn == 3 ? cn : (bgra_ ? GL_BGRA : 4); + + glColorPointer(format, gl_types[color_.depth()], 0, 0); + CV_CheckGlError(); + + color_.unbind(); + } + + if (!vertex_.empty()) + { + glEnableClientState(GL_VERTEX_ARRAY); + CV_CheckGlError(); + + vertex_.bind(); + + glVertexPointer(vertex_.channels(), gl_types[vertex_.depth()], 0, 0); + CV_CheckGlError(); + + vertex_.unbind(); + } +#endif +} + +void cv::GlArrays::unbind() const +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + if (!texCoord_.empty()) + { + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + CV_CheckGlError(); + } + + if (!normal_.empty()) + { + glDisableClientState(GL_NORMAL_ARRAY); + CV_CheckGlError(); + } + + if (!color_.empty()) + { + glDisableClientState(GL_COLOR_ARRAY); + CV_CheckGlError(); + } + + if (!vertex_.empty()) + { + glDisableClientState(GL_VERTEX_ARRAY); + CV_CheckGlError(); + } +#endif +} + +//////////////////////////////////////////////////////////////////////// +// GlFont + +cv::GlFont::GlFont(const string& _family, int _height, Weight _weight, Style _style) + : family_(_family), height_(_height), weight_(_weight), style_(_style), base_(0) +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + base_ = glGenLists(256); + CV_CheckGlError(); + + glFuncTab()->generateBitmapFont(family_, height_, weight_, (style_ & STYLE_ITALIC) != 0, (style_ & STYLE_UNDERLINE) != 0, 0, 256, base_); +#endif +} + +void cv::GlFont::draw(const char* str, size_t len) const +{ +#ifndef HAVE_OPENGL + (void)str; + (void)len; + throw_nogl; +#else + if (base_ && len > 0) + { + glPushAttrib(GL_LIST_BIT); + glListBase(base_); + + glCallLists(static_cast(len), GL_UNSIGNED_BYTE, str); + + glPopAttrib(); + + CV_CheckGlError(); + } +#endif +} + +namespace +{ + class FontCompare : public unary_function, bool> + { + public: + inline FontCompare(const string& family, int height, GlFont::Weight weight, GlFont::Style style) + : family_(family), height_(height), weight_(weight), style_(style) + { + } + + bool operator ()(const cv::Ptr& font) + { + return font->family() == family_ && font->height() == height_ && font->weight() == weight_ && font->style() == style_; + } + + private: + string family_; + int height_; + GlFont::Weight weight_; + GlFont::Style style_; + }; +} + +Ptr cv::GlFont::get(const std::string& family, int height, Weight weight, Style style) +{ +#ifndef HAVE_OPENGL + (void)family; + (void)height; + (void)weight; + (void)style; + throw_nogl; + return Ptr(); +#else + static vector< Ptr > fonts; + fonts.reserve(10); + + vector< Ptr >::iterator fontIt = find_if(fonts.begin(), fonts.end(), FontCompare(family, height, weight, style)); + + if (fontIt == fonts.end()) + { + fonts.push_back(new GlFont(family, height, weight, style)); + + fontIt = fonts.end() - 1; + } + + return *fontIt; +#endif +} + +//////////////////////////////////////////////////////////////////////// +// Rendering + +void cv::render(const GlTexture& tex, Rect_ wndRect, Rect_ texRect) +{ +#ifndef HAVE_OPENGL + (void)tex; + (void)wndRect; + (void)texRect; + throw_nogl; +#else + if (!tex.empty()) + { + tex.bind(); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glBegin(GL_QUADS); + glTexCoord2d(texRect.x, texRect.y); + glVertex2d(wndRect.x, wndRect.y); + + glTexCoord2d(texRect.x, texRect.y + texRect.height); + glVertex2d(wndRect.x, (wndRect.y + wndRect.height)); + + glTexCoord2d(texRect.x + texRect.width, texRect.y + texRect.height); + glVertex2d(wndRect.x + wndRect.width, (wndRect.y + wndRect.height)); + + glTexCoord2d(texRect.x + texRect.width, texRect.y); + glVertex2d(wndRect.x + wndRect.width, wndRect.y); + glEnd(); + + CV_CheckGlError(); + + tex.unbind(); + } +#endif +} + +void cv::render(const GlArrays& arr, int mode, Scalar color) +{ +#ifndef HAVE_OPENGL + (void)arr; + (void)mode; + (void)color; + throw_nogl; +#else + glColor3d(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0); + + arr.bind(); + + glDrawArrays(mode, 0, arr.size().area()); + + arr.unbind(); +#endif +} + +void cv::render(const string& str, const Ptr& font, Scalar color, Point2d pos) +{ +#ifndef HAVE_OPENGL + (void)str; + (void)font; + (void)color; + (void)pos; + throw_nogl; +#else + glPushAttrib(GL_DEPTH_BUFFER_BIT); + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + + glDisable(GL_DEPTH_TEST); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glColor3d(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0); + + glRasterPos2d(2.0 * (viewport[0] + pos.x) / viewport[2] - 1.0, 1.0 - 2.0 * (viewport[1] + pos.y + font->height()) / viewport[3]); + + font->draw(str.c_str(), str.length()); + + glPopAttrib(); +#endif +} + +//////////////////////////////////////////////////////////////////////// +// GlCamera + +cv::GlCamera::GlCamera() : + eye_(0.0, 0.0, -5.0), center_(0.0, 0.0, 0.0), up_(0.0, 1.0, 0.0), + pos_(0.0, 0.0, -5.0), yaw_(0.0), pitch_(0.0), roll_(0.0), + useLookAtParams_(false), + + scale_(1.0, 1.0, 1.0), + + projectionMatrix_(), + fov_(45.0), aspect_(0.0), + left_(0.0), right_(1.0), bottom_(1.0), top_(0.0), + zNear_(-1.0), zFar_(1.0), + perspectiveProjection_(false) +{ +} + +void cv::GlCamera::lookAt(Point3d eye, Point3d center, Point3d up) +{ + eye_ = eye; + center_ = center; + up_ = up; + useLookAtParams_ = true; +} + +void cv::GlCamera::setCameraPos(Point3d pos, double yaw, double pitch, double roll) +{ + pos_ = pos; + yaw_ = yaw; + pitch_ = pitch; + roll_ = roll; + useLookAtParams_ = false; +} + +void cv::GlCamera::setScale(Point3d scale) +{ + scale_ = scale; +} + +void cv::GlCamera::setProjectionMatrix(const Mat& projectionMatrix, bool transpose) +{ + CV_Assert(projectionMatrix.type() == CV_32F || projectionMatrix.type() == CV_64F); + CV_Assert(projectionMatrix.cols == 4 && projectionMatrix.rows == 4); + + projectionMatrix_ = transpose ? projectionMatrix.t() : projectionMatrix; +} + +void cv::GlCamera::setPerspectiveProjection(double fov, double aspect, double zNear, double zFar) +{ + fov_ = fov; + aspect_ = aspect; + zNear_ = zNear; + zFar_ = zFar; + + projectionMatrix_.release(); + perspectiveProjection_ = true; +} + +void cv::GlCamera::setOrthoProjection(double left, double right, double bottom, double top, double zNear, double zFar) +{ + left_ = left; + right_ = right; + bottom_ = bottom; + top_ = top; + zNear_ = zNear; + zFar_ = zFar; + + projectionMatrix_.release(); + perspectiveProjection_ = false; +} + +void cv::GlCamera::setupProjectionMatrix() const +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + if (projectionMatrix_.empty()) + { + if (perspectiveProjection_) + gluPerspective(fov_, aspect_, zNear_, zFar_); + else + glOrtho(left_, right_, bottom_, top_, zNear_, zFar_); + } + else + { + if (projectionMatrix_.type() == CV_32F) + glLoadMatrixf(projectionMatrix_.ptr()); + else + glLoadMatrixd(projectionMatrix_.ptr()); + } + + CV_CheckGlError(); +#endif +} + +void cv::GlCamera::setupModelViewMatrix() const +{ +#ifndef HAVE_OPENGL + throw_nogl; +#else + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + if (useLookAtParams_) + gluLookAt(eye_.x, eye_.y, eye_.z, center_.x, center_.y, center_.z, up_.x, up_.y, up_.z); + else + { + glRotated(-yaw_, 0.0, 1.0, 0.0); + glRotated(-pitch_, 1.0, 0.0, 0.0); + glRotated(-roll_, 0.0, 0.0, 1.0); + glTranslated(-pos_.x, -pos_.y, -pos_.z); + } + + glScaled(scale_.x, scale_.y, scale_.z); + + CV_CheckGlError(); +#endif +} + +//////////////////////////////////////////////////////////////////////// +// Error handling + +bool icvCheckGlError(const char* file, const int line, const char* func) +{ +#ifndef HAVE_OPENGL + (void)file; + (void)line; + (void)func; + return true; +#else + GLenum err = glGetError(); + + if (err != GL_NO_ERROR) + { + const char* msg; + + switch (err) + { + case GL_INVALID_ENUM: + msg = "An unacceptable value is specified for an enumerated argument"; + break; + case GL_INVALID_VALUE: + msg = "A numeric argument is out of range"; + break; + case GL_INVALID_OPERATION: + msg = "The specified operation is not allowed in the current state"; + break; + case GL_STACK_OVERFLOW: + msg = "This command would cause a stack overflow"; + break; + case GL_STACK_UNDERFLOW: + msg = "This command would cause a stack underflow"; + break; + case GL_OUT_OF_MEMORY: + msg = "There is not enough memory left to execute the command"; + break; + default: + msg = "Unknown error"; + }; + + cvError(CV_OpenGlApiCallError, func, msg, file, line); + + return false; + } + + return true; +#endif +} diff --git a/core/src/out.cpp b/core/src/out.cpp new file mode 100644 index 0000000..6817fca --- /dev/null +++ b/core/src/out.cpp @@ -0,0 +1,307 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2010, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include + +namespace cv +{ + +static inline char getCloseBrace(char c) +{ + return c == '[' ? ']' : c == '(' ? ')' : c == '{' ? '}' : '\0'; +} + + +template static void writeElems(std::ostream& out, const _Tp* data, + int nelems, int cn, char obrace, char cbrace) +{ + typedef typename DataType<_Tp>::work_type _WTp; + nelems *= cn; + for(int i = 0; i < nelems; i += cn) + { + if(cn == 1) + { + out << (_WTp)data[i] << (i+1 < nelems ? ", " : ""); + continue; + } + out << obrace; + for(int j = 0; j < cn; j++) + out << (_WTp)data[i + j] << (j+1 < cn ? ", " : ""); + out << cbrace << (i+cn < nelems ? ", " : ""); + } +} + + +static void writeElems(std::ostream& out, const void* data, int nelems, int type, char brace) +{ + int depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); + char cbrace = ' '; + if(!brace || isspace(brace)) + { + nelems *= cn; + cn = 1; + } + else + cbrace = getCloseBrace(brace); + if(depth == CV_8U) + writeElems(out, (const uchar*)data, nelems, cn, brace, cbrace); + else if(depth == CV_8S) + writeElems(out, (const schar*)data, nelems, cn, brace, cbrace); + else if(depth == CV_16U) + writeElems(out, (const ushort*)data, nelems, cn, brace, cbrace); + else if(depth == CV_16S) + writeElems(out, (const short*)data, nelems, cn, brace, cbrace); + else if(depth == CV_32S) + writeElems(out, (const int*)data, nelems, cn, brace, cbrace); + else if(depth == CV_32F) + { + std::streamsize pp = out.precision(); + out.precision(8); + writeElems(out, (const float*)data, nelems, cn, brace, cbrace); + out.precision(pp); + } + else if(depth == CV_64F) + { + std::streamsize pp = out.precision(); + out.precision(16); + writeElems(out, (const double*)data, nelems, cn, brace, cbrace); + out.precision(pp); + } + else + CV_Error(CV_StsUnsupportedFormat, ""); +} + + +static void writeMat(std::ostream& out, const Mat& m, char rowsep, char elembrace, bool singleLine) +{ + CV_Assert(m.dims <= 2); + int type = m.type(); + + char crowbrace = getCloseBrace(rowsep); + char orowbrace = crowbrace ? rowsep : '\0'; + + if( orowbrace || isspace(rowsep) ) + rowsep = '\0'; + + for( int i = 0; i < m.rows; i++ ) + { + if(orowbrace) + out << orowbrace; + if( m.data ) + writeElems(out, m.ptr(i), m.cols, type, elembrace); + if(orowbrace) + out << crowbrace << (i+1 < m.rows ? ", " : ""); + if(i+1 < m.rows) + { + if(rowsep) + out << rowsep << (singleLine ? " " : ""); + if(!singleLine) + out << "\n "; + } + } +} + +class MatlabFormatter : public Formatter +{ +public: + virtual ~MatlabFormatter() {} + void write(std::ostream& out, const Mat& m, const int*, int) const + { + out << "["; + writeMat(out, m, ';', ' ', m.cols == 1); + out << "]"; + } + + void write(std::ostream& out, const void* data, int nelems, int type, const int*, int) const + { + writeElems(out, data, nelems, type, ' '); + } +}; + +class PythonFormatter : public Formatter +{ +public: + virtual ~PythonFormatter() {} + void write(std::ostream& out, const Mat& m, const int*, int) const + { + out << "["; + writeMat(out, m, m.cols > 1 ? '[' : ' ', '[', m.cols*m.channels() == 1); + out << "]"; + } + + void write(std::ostream& out, const void* data, int nelems, int type, const int*, int) const + { + writeElems(out, data, nelems, type, '['); + } +}; + + +class NumpyFormatter : public Formatter +{ +public: + virtual ~NumpyFormatter() {} + void write(std::ostream& out, const Mat& m, const int*, int) const + { + static const char* numpyTypes[] = + { + "uint8", "int8", "uint16", "int16", "int32", "float32", "float64", "uint64" + }; + out << "array(["; + writeMat(out, m, m.cols > 1 ? '[' : ' ', '[', m.cols*m.channels() == 1); + out << "], type='" << numpyTypes[m.depth()] << "')"; + } + + void write(std::ostream& out, const void* data, int nelems, int type, const int*, int) const + { + writeElems(out, data, nelems, type, '['); + } +}; + + +class CSVFormatter : public Formatter +{ +public: + virtual ~CSVFormatter() {} + void write(std::ostream& out, const Mat& m, const int*, int) const + { + writeMat(out, m, ' ', ' ', m.cols*m.channels() == 1); + if(m.rows > 1) + out << "\n"; + } + + void write(std::ostream& out, const void* data, int nelems, int type, const int*, int) const + { + writeElems(out, data, nelems, type, ' '); + } +}; + + +class CFormatter : public Formatter +{ +public: + virtual ~CFormatter() {} + void write(std::ostream& out, const Mat& m, const int*, int) const + { + out << "{"; + writeMat(out, m, ',', ' ', m.cols==1); + out << "}"; + } + + void write(std::ostream& out, const void* data, int nelems, int type, const int*, int) const + { + writeElems(out, data, nelems, type, ' '); + } +}; + + +static MatlabFormatter matlabFormatter; +static PythonFormatter pythonFormatter; +static NumpyFormatter numpyFormatter; +static CSVFormatter csvFormatter; +static CFormatter cFormatter; + +static const Formatter* g_defaultFormatter0 = &matlabFormatter; +static const Formatter* g_defaultFormatter = &matlabFormatter; + +static bool my_streq(const char* a, const char* b) +{ + size_t i, alen = strlen(a), blen = strlen(b); + if( alen != blen ) + return false; + for( i = 0; i < alen; i++ ) + if( a[i] != b[i] && a[i] - 32 != b[i] ) + return false; + return true; +} + +const Formatter* Formatter::get(const char* fmt) +{ + if(!fmt || my_streq(fmt, "")) + return g_defaultFormatter; + if( my_streq(fmt, "MATLAB")) + return &matlabFormatter; + if( my_streq(fmt, "CSV")) + return &csvFormatter; + if( my_streq(fmt, "PYTHON")) + return &pythonFormatter; + if( my_streq(fmt, "NUMPY")) + return &numpyFormatter; + if( my_streq(fmt, "C")) + return &cFormatter; + CV_Error(CV_StsBadArg, "Unknown formatter"); + return g_defaultFormatter; +} + +const Formatter* Formatter::setDefault(const Formatter* fmt) +{ + const Formatter* prevFmt = g_defaultFormatter; + if(!fmt) + fmt = g_defaultFormatter0; + g_defaultFormatter = fmt; + return prevFmt; +} + +Formatted::Formatted(const Mat& _m, const Formatter* _fmt, + const vector& _params) +{ + mtx = _m; + fmt = _fmt ? _fmt : Formatter::get(); + std::copy(_params.begin(), _params.end(), back_inserter(params)); +} + +Formatted::Formatted(const Mat& _m, const Formatter* _fmt, const int* _params) +{ + mtx = _m; + fmt = _fmt ? _fmt : Formatter::get(); + + if( _params ) + { + int i, maxParams = 100; + for(i = 0; i < maxParams && _params[i] != 0; i+=2) + ; + std::copy(_params, _params + i, back_inserter(params)); + } +} + +} + diff --git a/core/src/parallel.cpp b/core/src/parallel.cpp new file mode 100644 index 0000000..8072a11 --- /dev/null +++ b/core/src/parallel.cpp @@ -0,0 +1,154 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#if !defined HAVE_TBB && !defined HAVE_OPENMP && !defined HAVE_GCD && !defined HAVE_CONCURRENCY + +#ifdef __APPLE__ +#define HAVE_GCD +#elif defined _MSC_VER && _MSC_VER >= 1600 +#define HAVE_CONCURRENCY +#endif + +#endif + +#ifdef HAVE_CONCURRENCY +# include +#elif defined HAVE_OPENMP +# include +#elif defined HAVE_GCD +# include +#elif defined HAVE_TBB +# include "tbb/tbb_stddef.h" +# if TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202 +# include "tbb/tbb.h" +# include "tbb/task.h" +# undef min +# undef max +# else +# undef HAVE_TBB +# endif // end TBB version +#endif // HAVE_CONCURRENCY + +/* + HAVE_TBB - using TBB + HAVE_GCD - using GCD + HAVE_OPENMP - using OpenMP + HAVE_CONCURRENCY - using visual studio 2010 concurrency +*/ + +namespace cv +{ + ParallelLoopBody::~ParallelLoopBody() { } + +#ifdef HAVE_TBB + class TbbProxyLoopBody + { + public: + TbbProxyLoopBody(const ParallelLoopBody& _body) : + body(&_body) + { } + + void operator ()(const tbb::blocked_range& range) const + { + body->operator()(Range(range.begin(), range.end())); + } + + private: + const ParallelLoopBody* body; + }; +#endif // end HAVE_TBB + +#ifdef HAVE_GCD + static + void block_function(void* context, size_t index) + { + ParallelLoopBody* ptr_body = static_cast(context); + ptr_body->operator()(Range(index, index + 1)); + } +#endif // HAVE_GCD + + void parallel_for_(const Range& range, const ParallelLoopBody& body) + { +#ifdef HAVE_TBB + + tbb::parallel_for(tbb::blocked_range(range.start, range.end), TbbProxyLoopBody(body)); + +#elif defined HAVE_CONCURRENCY + + class ConcurrencyProxyLoopBody + { + public: + ConcurrencyProxyLoopBody(const ParallelLoopBody& body) : _body(body) {} + + void operator ()(int i) const + { + _body(Range(i, i + 1)); + } + + private: + const ParallelLoopBody& _body; + ConcurrencyProxyLoopBody& operator=(const ConcurrencyProxyLoopBody&) {return *this;} + } proxy(body); + + Concurrency::parallel_for(range.start, range.end, proxy); + +#elif defined HAVE_OPENMP + +#pragma omp parallel for schedule(dynamic) + for (int i = range.start; i < range.end; ++i) + body(Range(i, i + 1)); + +#elif defined (HAVE_GCD) + + dispatch_queue_t concurrent_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_apply_f(range.end - range.start, concurrent_queue, &const_cast(body), block_function); + +#else + + body(range); + +#endif // end HAVE_TBB + } + +} // namespace cv diff --git a/core/src/persistence.cpp b/core/src/persistence.cpp new file mode 100644 index 0000000..d060ac3 --- /dev/null +++ b/core/src/persistence.cpp @@ -0,0 +1,5557 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#include +#include +#include +#include + +#define USE_ZLIB 1 + +#ifdef __APPLE__ +# include "TargetConditionals.h" +# if (defined TARGET_OS_IPHONE && TARGET_OS_IPHONE) || (defined TARGET_IPHONE_SIMULATOR && TARGET_IPHONE_SIMULATOR) +# undef USE_ZLIB +# define USE_ZLIB 0 + typedef void* gzFile; +# endif +#endif + +#if USE_ZLIB +# undef HAVE_UNISTD_H //to avoid redefinition +# ifndef _LFS64_LARGEFILE +# define _LFS64_LARGEFILE 0 +# endif +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 0 +# endif +# include +#endif + +/****************************************************************************************\ +* Common macros and type definitions * +\****************************************************************************************/ + +#define cv_isprint(c) ((uchar)(c) >= (uchar)' ') +#define cv_isprint_or_tab(c) ((uchar)(c) >= (uchar)' ' || (c) == '\t') + +static inline bool cv_isalnum(char c) +{ + return ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); +} + +static inline bool cv_isalpha(char c) +{ + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); +} + +static inline bool cv_isdigit(char c) +{ + return '0' <= c && c <= '9'; +} + +static inline bool cv_isspace(char c) +{ + return (9 <= c && c <= 13) || c == ' '; +} + +static char* icv_itoa( int _val, char* buffer, int /*radix*/ ) +{ + const int radix = 10; + char* ptr=buffer + 23 /* enough even for 64-bit integers */; + unsigned val = abs(_val); + + *ptr = '\0'; + do + { + unsigned r = val / radix; + *--ptr = (char)(val - (r*radix) + '0'); + val = r; + } + while( val != 0 ); + + if( _val < 0 ) + *--ptr = '-'; + + return ptr; +} + +cv::string cv::FileStorage::getDefaultObjectName(const string& _filename) +{ + static const char* stubname = "unnamed"; + const char* filename = _filename.c_str(); + const char* ptr2 = filename + _filename.size(); + const char* ptr = ptr2 - 1; + cv::AutoBuffer name_buf(_filename.size()+1); + + while( ptr >= filename && *ptr != '\\' && *ptr != '/' && *ptr != ':' ) + { + if( *ptr == '.' && (!*ptr2 || strncmp(ptr2, ".gz", 3) == 0) ) + ptr2 = ptr; + ptr--; + } + ptr++; + if( ptr == ptr2 ) + CV_Error( CV_StsBadArg, "Invalid filename" ); + + char* name = name_buf; + + // name must start with letter or '_' + if( !cv_isalpha(*ptr) && *ptr!= '_' ){ + *name++ = '_'; + } + + while( ptr < ptr2 ) + { + char c = *ptr++; + if( !cv_isalnum(c) && c != '-' && c != '_' ) + c = '_'; + *name++ = c; + } + *name = '\0'; + name = name_buf; + if( strcmp( name, "_" ) == 0 ) + strcpy( name, stubname ); + return cv::string(name); +} + +namespace cv +{ +#if !defined(ANDROID) || (defined(_GLIBCXX_USE_WCHAR_T) && _GLIBCXX_USE_WCHAR_T) +string fromUtf16(const WString& str) +{ + cv::AutoBuffer _buf(str.size()*4 + 1); + char* buf = _buf; + + size_t sz = wcstombs(buf, str.c_str(), str.size()); + if( sz == (size_t)-1 ) + return string(); + buf[sz] = '\0'; + return string(buf); +} + +WString toUtf16(const string& str) +{ + cv::AutoBuffer _buf(str.size() + 1); + wchar_t* buf = _buf; + + size_t sz = mbstowcs(buf, str.c_str(), str.size()); + if( sz == (size_t)-1 ) + return WString(); + buf[sz] = '\0'; + return WString(buf); +} +#endif +} + +typedef struct CvGenericHash +{ + CV_SET_FIELDS() + int tab_size; + void** table; +} +CvGenericHash; + +typedef CvGenericHash CvStringHash; + +typedef struct CvFileMapNode +{ + CvFileNode value; + const CvStringHashNode* key; + struct CvFileMapNode* next; +} +CvFileMapNode; + +typedef struct CvXMLStackRecord +{ + CvMemStoragePos pos; + CvString struct_tag; + int struct_indent; + int struct_flags; +} +CvXMLStackRecord; + +#define CV_XML_OPENING_TAG 1 +#define CV_XML_CLOSING_TAG 2 +#define CV_XML_EMPTY_TAG 3 +#define CV_XML_HEADER_TAG 4 +#define CV_XML_DIRECTIVE_TAG 5 + +//typedef void (*CvParse)( struct CvFileStorage* fs ); +typedef void (*CvStartWriteStruct)( struct CvFileStorage* fs, const char* key, + int struct_flags, const char* type_name ); +typedef void (*CvEndWriteStruct)( struct CvFileStorage* fs ); +typedef void (*CvWriteInt)( struct CvFileStorage* fs, const char* key, int value ); +typedef void (*CvWriteReal)( struct CvFileStorage* fs, const char* key, double value ); +typedef void (*CvWriteString)( struct CvFileStorage* fs, const char* key, + const char* value, int quote ); +typedef void (*CvWriteComment)( struct CvFileStorage* fs, const char* comment, int eol_comment ); +typedef void (*CvStartNextStream)( struct CvFileStorage* fs ); + +typedef struct CvFileStorage +{ + int flags; + int fmt; + int write_mode; + int is_first; + CvMemStorage* memstorage; + CvMemStorage* dststorage; + CvMemStorage* strstorage; + CvStringHash* str_hash; + CvSeq* roots; + CvSeq* write_stack; + int struct_indent; + int struct_flags; + CvString struct_tag; + int space; + char* filename; + FILE* file; + gzFile gzfile; + char* buffer; + char* buffer_start; + char* buffer_end; + int wrap_margin; + int lineno; + int dummy_eof; + const char* errmsg; + char errmsgbuf[128]; + + CvStartWriteStruct start_write_struct; + CvEndWriteStruct end_write_struct; + CvWriteInt write_int; + CvWriteReal write_real; + CvWriteString write_string; + CvWriteComment write_comment; + CvStartNextStream start_next_stream; + + const char* strbuf; + size_t strbufsize, strbufpos; + std::deque* outbuf; + + bool is_opened; +} +CvFileStorage; + +static void icvPuts( CvFileStorage* fs, const char* str ) +{ + if( fs->outbuf ) + std::copy(str, str + strlen(str), std::back_inserter(*fs->outbuf)); + else if( fs->file ) + fputs( str, fs->file ); +#if USE_ZLIB + else if( fs->gzfile ) + gzputs( fs->gzfile, str ); +#endif + else + CV_Error( CV_StsError, "The storage is not opened" ); +} + +static char* icvGets( CvFileStorage* fs, char* str, int maxCount ) +{ + if( fs->strbuf ) + { + size_t i = fs->strbufpos, len = fs->strbufsize; + int j = 0; + const char* instr = fs->strbuf; + while( i < len && j < maxCount-1 ) + { + char c = instr[i++]; + if( c == '\0' ) + break; + str[j++] = c; + if( c == '\n' ) + break; + } + str[j++] = '\0'; + fs->strbufpos = i; + return j > 1 ? str : 0; + } + if( fs->file ) + return fgets( str, maxCount, fs->file ); +#if USE_ZLIB + if( fs->gzfile ) + return gzgets( fs->gzfile, str, maxCount ); +#endif + CV_Error( CV_StsError, "The storage is not opened" ); + return 0; +} + +static int icvEof( CvFileStorage* fs ) +{ + if( fs->strbuf ) + return fs->strbufpos >= fs->strbufsize; + if( fs->file ) + return feof(fs->file); +#if USE_ZLIB + if( fs->gzfile ) + return gzeof(fs->gzfile); +#endif + return false; +} + +static void icvCloseFile( CvFileStorage* fs ) +{ + if( fs->file ) + fclose( fs->file ); +#if USE_ZLIB + else if( fs->gzfile ) + gzclose( fs->gzfile ); +#endif + fs->file = 0; + fs->gzfile = 0; + fs->strbuf = 0; + fs->strbufpos = 0; + fs->is_opened = false; +} + +static void icvRewind( CvFileStorage* fs ) +{ + if( fs->file ) + rewind(fs->file); +#if USE_ZLIB + else if( fs->gzfile ) + gzrewind(fs->gzfile); +#endif + fs->strbufpos = 0; +} + +#define CV_YML_INDENT 3 +#define CV_XML_INDENT 2 +#define CV_YML_INDENT_FLOW 1 +#define CV_FS_MAX_LEN 4096 + +#define CV_FILE_STORAGE ('Y' + ('A' << 8) + ('M' << 16) + ('L' << 24)) +#define CV_IS_FILE_STORAGE(fs) ((fs) != 0 && (fs)->flags == CV_FILE_STORAGE) + +#define CV_CHECK_FILE_STORAGE(fs) \ +{ \ + if( !CV_IS_FILE_STORAGE(fs) ) \ + CV_Error( (fs) ? CV_StsBadArg : CV_StsNullPtr, \ + "Invalid pointer to file storage" ); \ +} + +#define CV_CHECK_OUTPUT_FILE_STORAGE(fs) \ +{ \ + CV_CHECK_FILE_STORAGE(fs); \ + if( !fs->write_mode ) \ + CV_Error( CV_StsError, "The file storage is opened for reading" ); \ +} + +CV_IMPL const char* +cvAttrValue( const CvAttrList* attr, const char* attr_name ) +{ + while( attr && attr->attr ) + { + int i; + for( i = 0; attr->attr[i*2] != 0; i++ ) + { + if( strcmp( attr_name, attr->attr[i*2] ) == 0 ) + return attr->attr[i*2+1]; + } + attr = attr->next; + } + + return 0; +} + + +static CvGenericHash* +cvCreateMap( int flags, int header_size, int elem_size, + CvMemStorage* storage, int start_tab_size ) +{ + if( header_size < (int)sizeof(CvGenericHash) ) + CV_Error( CV_StsBadSize, "Too small map header_size" ); + + if( start_tab_size <= 0 ) + start_tab_size = 16; + + CvGenericHash* map = (CvGenericHash*)cvCreateSet( flags, header_size, elem_size, storage ); + + map->tab_size = start_tab_size; + start_tab_size *= sizeof(map->table[0]); + map->table = (void**)cvMemStorageAlloc( storage, start_tab_size ); + memset( map->table, 0, start_tab_size ); + + return map; +} + +#ifdef __GNUC__ +#define CV_PARSE_ERROR( errmsg ) \ + icvParseError( fs, __func__, (errmsg), __FILE__, __LINE__ ) +#else +#define CV_PARSE_ERROR( errmsg ) \ + icvParseError( fs, "", (errmsg), __FILE__, __LINE__ ) +#endif + +static void +icvParseError( CvFileStorage* fs, const char* func_name, + const char* err_msg, const char* source_file, int source_line ) +{ + char buf[1<<10]; + sprintf( buf, "%s(%d): %s", fs->filename, fs->lineno, err_msg ); + cvError( CV_StsParseError, func_name, buf, source_file, source_line ); +} + + +static void +icvFSCreateCollection( CvFileStorage* fs, int tag, CvFileNode* collection ) +{ + if( CV_NODE_IS_MAP(tag) ) + { + if( collection->tag != CV_NODE_NONE ) + { + assert( fs->fmt == CV_STORAGE_FORMAT_XML ); + CV_PARSE_ERROR( "Sequence element should not have name (use <_>)" ); + } + + collection->data.map = cvCreateMap( 0, sizeof(CvFileNodeHash), + sizeof(CvFileMapNode), fs->memstorage, 16 ); + } + else + { + CvSeq* seq; + seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvFileNode), fs->memstorage ); + + // if contains some scalar element, add it to the newly created collection + if( CV_NODE_TYPE(collection->tag) != CV_NODE_NONE ) + cvSeqPush( seq, collection ); + + collection->data.seq = seq; + } + + collection->tag = tag; + cvSetSeqBlockSize( collection->data.seq, 8 ); +} + + +/*static void +icvFSReleaseCollection( CvSeq* seq ) +{ + if( seq ) + { + int is_map = CV_IS_SET(seq); + CvSeqReader reader; + int i, total = seq->total; + cvStartReadSeq( seq, &reader, 0 ); + + for( i = 0; i < total; i++ ) + { + CvFileNode* node = (CvFileNode*)reader.ptr; + + if( (!is_map || CV_IS_SET_ELEM( node )) && CV_NODE_IS_COLLECTION(node->tag) ) + { + if( CV_NODE_IS_USER(node->tag) && node->info && node->data.obj.decoded ) + cvRelease( (void**)&node->data.obj.decoded ); + if( !CV_NODE_SEQ_IS_SIMPLE( node->data.seq )) + icvFSReleaseCollection( node->data.seq ); + } + CV_NEXT_SEQ_ELEM( seq->elem_size, reader ); + } + } +}*/ + + +static char* +icvFSDoResize( CvFileStorage* fs, char* ptr, int len ) +{ + char* new_ptr = 0; + int written_len = (int)(ptr - fs->buffer_start); + int new_size = (int)((fs->buffer_end - fs->buffer_start)*3/2); + new_size = MAX( written_len + len, new_size ); + new_ptr = (char*)cvAlloc( new_size + 256 ); + fs->buffer = new_ptr + (fs->buffer - fs->buffer_start); + if( written_len > 0 ) + memcpy( new_ptr, fs->buffer_start, written_len ); + fs->buffer_start = new_ptr; + fs->buffer_end = fs->buffer_start + new_size; + new_ptr += written_len; + return new_ptr; +} + + +inline char* icvFSResizeWriteBuffer( CvFileStorage* fs, char* ptr, int len ) +{ + return ptr + len < fs->buffer_end ? ptr : icvFSDoResize( fs, ptr, len ); +} + + +static char* +icvFSFlush( CvFileStorage* fs ) +{ + char* ptr = fs->buffer; + int indent; + + if( ptr > fs->buffer_start + fs->space ) + { + ptr[0] = '\n'; + ptr[1] = '\0'; + icvPuts( fs, fs->buffer_start ); + fs->buffer = fs->buffer_start; + } + + indent = fs->struct_indent; + + if( fs->space != indent ) + { + if( fs->space < indent ) + memset( fs->buffer_start + fs->space, ' ', indent - fs->space ); + fs->space = indent; + } + + ptr = fs->buffer = fs->buffer_start + fs->space; + + return ptr; +} + + +static void +icvClose( CvFileStorage* fs, std::string* out ) +{ + if( out ) + out->clear(); + + if( !fs ) + CV_Error( CV_StsNullPtr, "NULL double pointer to file storage" ); + + if( fs->is_opened ) + { + if( fs->write_mode && (fs->file || fs->gzfile || fs->outbuf) ) + { + if( fs->write_stack ) + { + while( fs->write_stack->total > 0 ) + cvEndWriteStruct(fs); + } + icvFSFlush(fs); + if( fs->fmt == CV_STORAGE_FORMAT_XML ) + icvPuts( fs, "\n" ); + } + + icvCloseFile(fs); + } + + if( fs->outbuf && out ) + { + out->resize(fs->outbuf->size()); + std::copy(fs->outbuf->begin(), fs->outbuf->end(), out->begin()); + } +} + + +/* closes file storage and deallocates buffers */ +CV_IMPL void +cvReleaseFileStorage( CvFileStorage** p_fs ) +{ + if( !p_fs ) + CV_Error( CV_StsNullPtr, "NULL double pointer to file storage" ); + + if( *p_fs ) + { + CvFileStorage* fs = *p_fs; + *p_fs = 0; + + icvClose(fs, 0); + + cvReleaseMemStorage( &fs->strstorage ); + cvFree( &fs->buffer_start ); + cvReleaseMemStorage( &fs->memstorage ); + + if( fs->outbuf ) + delete fs->outbuf; + + memset( fs, 0, sizeof(*fs) ); + cvFree( &fs ); + } +} + + +#define CV_HASHVAL_SCALE 33 + +CV_IMPL CvStringHashNode* +cvGetHashedKey( CvFileStorage* fs, const char* str, int len, int create_missing ) +{ + CvStringHashNode* node = 0; + unsigned hashval = 0; + int i, tab_size; + CvStringHash* map = fs->str_hash; + + if( !fs ) + return 0; + + if( len < 0 ) + { + for( i = 0; str[i] != '\0'; i++ ) + hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i]; + len = i; + } + else for( i = 0; i < len; i++ ) + hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i]; + + hashval &= INT_MAX; + tab_size = map->tab_size; + if( (tab_size & (tab_size - 1)) == 0 ) + i = (int)(hashval & (tab_size - 1)); + else + i = (int)(hashval % tab_size); + + for( node = (CvStringHashNode*)(map->table[i]); node != 0; node = node->next ) + { + if( node->hashval == hashval && + node->str.len == len && + memcmp( node->str.ptr, str, len ) == 0 ) + break; + } + + if( !node && create_missing ) + { + node = (CvStringHashNode*)cvSetNew( (CvSet*)map ); + node->hashval = hashval; + node->str = cvMemStorageAllocString( map->storage, str, len ); + node->next = (CvStringHashNode*)(map->table[i]); + map->table[i] = node; + } + + return node; +} + + +CV_IMPL CvFileNode* +cvGetFileNode( CvFileStorage* fs, CvFileNode* _map_node, + const CvStringHashNode* key, + int create_missing ) +{ + CvFileNode* value = 0; + int k = 0, attempts = 1; + + if( !fs ) + return 0; + + CV_CHECK_FILE_STORAGE(fs); + + if( !key ) + CV_Error( CV_StsNullPtr, "Null key element" ); + + if( _map_node ) + { + if( !fs->roots ) + return 0; + attempts = fs->roots->total; + } + + for( k = 0; k < attempts; k++ ) + { + int i, tab_size; + CvFileNode* map_node = _map_node; + CvFileMapNode* another; + CvFileNodeHash* map; + + if( !map_node ) + map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k ); + + if( !CV_NODE_IS_MAP(map_node->tag) ) + { + if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) && + CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE ) + CV_Error( CV_StsError, "The node is neither a map nor an empty collection" ); + return 0; + } + + map = map_node->data.map; + tab_size = map->tab_size; + + if( (tab_size & (tab_size - 1)) == 0 ) + i = (int)(key->hashval & (tab_size - 1)); + else + i = (int)(key->hashval % tab_size); + + for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next ) + if( another->key == key ) + { + if( !create_missing ) + { + value = &another->value; + return value; + } + CV_PARSE_ERROR( "Duplicated key" ); + } + + if( k == attempts - 1 && create_missing ) + { + CvFileMapNode* node = (CvFileMapNode*)cvSetNew( (CvSet*)map ); + node->key = key; + + node->next = (CvFileMapNode*)(map->table[i]); + map->table[i] = node; + value = (CvFileNode*)node; + } + } + + return value; +} + + +CV_IMPL CvFileNode* +cvGetFileNodeByName( const CvFileStorage* fs, const CvFileNode* _map_node, const char* str ) +{ + CvFileNode* value = 0; + int i, len, tab_size; + unsigned hashval = 0; + int k = 0, attempts = 1; + + if( !fs ) + return 0; + + CV_CHECK_FILE_STORAGE(fs); + + if( !str ) + CV_Error( CV_StsNullPtr, "Null element name" ); + + for( i = 0; str[i] != '\0'; i++ ) + hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i]; + hashval &= INT_MAX; + len = i; + + if( !_map_node ) + { + if( !fs->roots ) + return 0; + attempts = fs->roots->total; + } + + for( k = 0; k < attempts; k++ ) + { + CvFileNodeHash* map; + const CvFileNode* map_node = _map_node; + CvFileMapNode* another; + + if( !map_node ) + map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k ); + + if( !CV_NODE_IS_MAP(map_node->tag) ) + { + if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) && + CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE ) + CV_Error( CV_StsError, "The node is neither a map nor an empty collection" ); + return 0; + } + + map = map_node->data.map; + tab_size = map->tab_size; + + if( (tab_size & (tab_size - 1)) == 0 ) + i = (int)(hashval & (tab_size - 1)); + else + i = (int)(hashval % tab_size); + + for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next ) + { + const CvStringHashNode* key = another->key; + + if( key->hashval == hashval && + key->str.len == len && + memcmp( key->str.ptr, str, len ) == 0 ) + { + value = &another->value; + return value; + } + } + } + + return value; +} + + +CV_IMPL CvFileNode* +cvGetRootFileNode( const CvFileStorage* fs, int stream_index ) +{ + CV_CHECK_FILE_STORAGE(fs); + + if( !fs->roots || (unsigned)stream_index >= (unsigned)fs->roots->total ) + return 0; + + return (CvFileNode*)cvGetSeqElem( fs->roots, stream_index ); +} + + +/* returns the sequence element by its index */ +/*CV_IMPL CvFileNode* +cvGetFileNodeFromSeq( CvFileStorage* fs, + CvFileNode* seq_node, int index ) +{ + CvFileNode* value = 0; + CvSeq* seq; + + if( !seq_node ) + seq = fs->roots; + else if( !CV_NODE_IS_SEQ(seq_node->tag) ) + { + if( CV_NODE_IS_MAP(seq_node->tag) ) + CV_Error( CV_StsError, "The node is map. Use cvGetFileNodeFromMap()." ); + if( CV_NODE_TYPE(seq_node->tag) == CV_NODE_NONE ) + CV_Error( CV_StsError, "The node is an empty object (None)." ); + if( index != 0 && index != -1 ) + CV_Error( CV_StsOutOfRange, "" ); + value = seq_node; + EXIT; + } + else + seq = seq_node->data.seq; + + if( !seq ) + CV_Error( CV_StsNullPtr, "The file storage is empty" ); + + value = (CvFileNode*)cvGetSeqElem( seq, index, 0 ); + + + + return value; +}*/ + + +static char* +icvDoubleToString( char* buf, double value ) +{ + Cv64suf val; + unsigned ieee754_hi; + + val.f = value; + ieee754_hi = (unsigned)(val.u >> 32); + + if( (ieee754_hi & 0x7ff00000) != 0x7ff00000 ) + { + int ivalue = cvRound(value); + if( ivalue == value ) + sprintf( buf, "%d.", ivalue ); + else + { + static const char* fmt = "%.16e"; + char* ptr = buf; + sprintf( buf, fmt, value ); + if( *ptr == '+' || *ptr == '-' ) + ptr++; + for( ; cv_isdigit(*ptr); ptr++ ) + ; + if( *ptr == ',' ) + *ptr = '.'; + } + } + else + { + unsigned ieee754_lo = (unsigned)val.u; + if( (ieee754_hi & 0x7fffffff) + (ieee754_lo != 0) > 0x7ff00000 ) + strcpy( buf, ".Nan" ); + else + strcpy( buf, (int)ieee754_hi < 0 ? "-.Inf" : ".Inf" ); + } + + return buf; +} + + +static char* +icvFloatToString( char* buf, float value ) +{ + Cv32suf val; + unsigned ieee754; + val.f = value; + ieee754 = val.u; + + if( (ieee754 & 0x7f800000) != 0x7f800000 ) + { + int ivalue = cvRound(value); + if( ivalue == value ) + sprintf( buf, "%d.", ivalue ); + else + { + static const char* fmt = "%.8e"; + char* ptr = buf; + sprintf( buf, fmt, value ); + if( *ptr == '+' || *ptr == '-' ) + ptr++; + for( ; cv_isdigit(*ptr); ptr++ ) + ; + if( *ptr == ',' ) + *ptr = '.'; + } + } + else + { + if( (ieee754 & 0x7fffffff) != 0x7f800000 ) + strcpy( buf, ".Nan" ); + else + strcpy( buf, (int)ieee754 < 0 ? "-.Inf" : ".Inf" ); + } + + return buf; +} + + +static void +icvProcessSpecialDouble( CvFileStorage* fs, char* buf, double* value, char** endptr ) +{ + char c = buf[0]; + int inf_hi = 0x7ff00000; + + if( c == '-' || c == '+' ) + { + inf_hi = c == '-' ? 0xfff00000 : 0x7ff00000; + c = *++buf; + } + + if( c != '.' ) + CV_PARSE_ERROR( "Bad format of floating-point constant" ); + + union{double d; uint64 i;} v; + v.d = 0.; + if( toupper(buf[1]) == 'I' && toupper(buf[2]) == 'N' && toupper(buf[3]) == 'F' ) + v.i = (uint64)inf_hi << 32; + else if( toupper(buf[1]) == 'N' && toupper(buf[2]) == 'A' && toupper(buf[3]) == 'N' ) + v.i = (uint64)-1; + else + CV_PARSE_ERROR( "Bad format of floating-point constant" ); + *value = v.d; + + *endptr = buf + 4; +} + + +static double icv_strtod( CvFileStorage* fs, char* ptr, char** endptr ) +{ + double fval = strtod( ptr, endptr ); + if( **endptr == '.' ) + { + char* dot_pos = *endptr; + *dot_pos = ','; + double fval2 = strtod( ptr, endptr ); + *dot_pos = '.'; + if( *endptr > dot_pos ) + fval = fval2; + else + *endptr = dot_pos; + } + + if( *endptr == ptr || cv_isalpha(**endptr) ) + icvProcessSpecialDouble( fs, ptr, &fval, endptr ); + + return fval; +} + + +/****************************************************************************************\ +* YAML Parser * +\****************************************************************************************/ + +static char* +icvYMLSkipSpaces( CvFileStorage* fs, char* ptr, int min_indent, int max_comment_indent ) +{ + for(;;) + { + while( *ptr == ' ' ) + ptr++; + if( *ptr == '#' ) + { + if( ptr - fs->buffer_start > max_comment_indent ) + return ptr; + *ptr = '\0'; + } + else if( cv_isprint(*ptr) ) + { + if( ptr - fs->buffer_start < min_indent ) + CV_PARSE_ERROR( "Incorrect indentation" ); + break; + } + else if( *ptr == '\0' || *ptr == '\n' || *ptr == '\r' ) + { + int max_size = (int)(fs->buffer_end - fs->buffer_start); + ptr = icvGets( fs, fs->buffer_start, max_size ); + if( !ptr ) + { + // emulate end of stream + ptr = fs->buffer_start; + ptr[0] = ptr[1] = ptr[2] = '.'; + ptr[3] = '\0'; + fs->dummy_eof = 1; + break; + } + else + { + int l = (int)strlen(ptr); + if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !icvEof(fs) ) + CV_PARSE_ERROR( "Too long string or a last string w/o newline" ); + } + + fs->lineno++; + } + else + CV_PARSE_ERROR( *ptr == '\t' ? "Tabs are prohibited in YAML!" : "Invalid character" ); + } + + return ptr; +} + + +static char* +icvYMLParseKey( CvFileStorage* fs, char* ptr, + CvFileNode* map_node, CvFileNode** value_placeholder ) +{ + char c; + char *endptr = ptr - 1, *saveptr; + CvStringHashNode* str_hash_node; + + if( *ptr == '-' ) + CV_PARSE_ERROR( "Key may not start with \'-\'" ); + + do c = *++endptr; + while( cv_isprint(c) && c != ':' ); + + if( c != ':' ) + CV_PARSE_ERROR( "Missing \':\'" ); + + saveptr = endptr + 1; + do c = *--endptr; + while( c == ' ' ); + + ++endptr; + if( endptr == ptr ) + CV_PARSE_ERROR( "An empty key" ); + + str_hash_node = cvGetHashedKey( fs, ptr, (int)(endptr - ptr), 1 ); + *value_placeholder = cvGetFileNode( fs, map_node, str_hash_node, 1 ); + ptr = saveptr; + + return ptr; +} + + +static char* +icvYMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node, + int parent_flags, int min_indent ) +{ + char buf[CV_FS_MAX_LEN + 1024]; + char* endptr = 0; + char c = ptr[0], d = ptr[1]; + int is_parent_flow = CV_NODE_IS_FLOW(parent_flags); + int value_type = CV_NODE_NONE; + int len; + + memset( node, 0, sizeof(*node) ); + + if( c == '!' ) // handle explicit type specification + { + if( d == '!' || d == '^' ) + { + ptr++; + value_type |= CV_NODE_USER; + } + + endptr = ptr++; + do d = *++endptr; + while( cv_isprint(d) && d != ' ' ); + len = (int)(endptr - ptr); + if( len == 0 ) + CV_PARSE_ERROR( "Empty type name" ); + d = *endptr; + *endptr = '\0'; + + if( len == 3 && !CV_NODE_IS_USER(value_type) ) + { + if( memcmp( ptr, "str", 3 ) == 0 ) + value_type = CV_NODE_STRING; + else if( memcmp( ptr, "int", 3 ) == 0 ) + value_type = CV_NODE_INT; + else if( memcmp( ptr, "seq", 3 ) == 0 ) + value_type = CV_NODE_SEQ; + else if( memcmp( ptr, "map", 3 ) == 0 ) + value_type = CV_NODE_MAP; + } + else if( len == 5 && !CV_NODE_IS_USER(value_type) ) + { + if( memcmp( ptr, "float", 5 ) == 0 ) + value_type = CV_NODE_REAL; + } + else if( CV_NODE_IS_USER(value_type) ) + { + node->info = cvFindType( ptr ); + if( !node->info ) + node->tag &= ~CV_NODE_USER; + } + + *endptr = d; + ptr = icvYMLSkipSpaces( fs, endptr, min_indent, INT_MAX ); + + c = *ptr; + + if( !CV_NODE_IS_USER(value_type) ) + { + if( value_type == CV_NODE_STRING && c != '\'' && c != '\"' ) + goto force_string; + if( value_type == CV_NODE_INT ) + goto force_int; + if( value_type == CV_NODE_REAL ) + goto force_real; + } + } + + if( cv_isdigit(c) || + ((c == '-' || c == '+') && (cv_isdigit(d) || d == '.')) || + (c == '.' && cv_isalnum(d))) // a number + { + double fval; + int ival; + endptr = ptr + (c == '-' || c == '+'); + while( cv_isdigit(*endptr) ) + endptr++; + if( *endptr == '.' || *endptr == 'e' ) + { +force_real: + fval = icv_strtod( fs, ptr, &endptr ); + /*if( endptr == ptr || cv_isalpha(*endptr) ) + icvProcessSpecialDouble( fs, endptr, &fval, &endptr ));*/ + + node->tag = CV_NODE_REAL; + node->data.f = fval; + } + else + { +force_int: + ival = (int)strtol( ptr, &endptr, 0 ); + node->tag = CV_NODE_INT; + node->data.i = ival; + } + + if( !endptr || endptr == ptr ) + CV_PARSE_ERROR( "Invalid numeric value (inconsistent explicit type specification?)" ); + + ptr = endptr; + } + else if( c == '\'' || c == '\"' ) // an explicit string + { + node->tag = CV_NODE_STRING; + if( c == '\'' ) + for( len = 0; len < CV_FS_MAX_LEN; ) + { + c = *++ptr; + if( cv_isalnum(c) || (c != '\'' && cv_isprint(c))) + buf[len++] = c; + else if( c == '\'' ) + { + c = *++ptr; + if( c != '\'' ) + break; + buf[len++] = c; + } + else + CV_PARSE_ERROR( "Invalid character" ); + } + else + for( len = 0; len < CV_FS_MAX_LEN; ) + { + c = *++ptr; + if( cv_isalnum(c) || (c != '\\' && c != '\"' && cv_isprint(c))) + buf[len++] = c; + else if( c == '\"' ) + { + ++ptr; + break; + } + else if( c == '\\' ) + { + d = *++ptr; + if( d == '\'' ) + buf[len++] = d; + else if( d == '\"' || d == '\\' || d == '\'' ) + buf[len++] = d; + else if( d == 'n' ) + buf[len++] = '\n'; + else if( d == 'r' ) + buf[len++] = '\r'; + else if( d == 't' ) + buf[len++] = '\t'; + else if( d == 'x' || (cv_isdigit(d) && d < '8') ) + { + int val, is_hex = d == 'x'; + c = ptr[3]; + ptr[3] = '\0'; + val = strtol( ptr + is_hex, &endptr, is_hex ? 8 : 16 ); + ptr[3] = c; + if( endptr == ptr + is_hex ) + buf[len++] = 'x'; + else + { + buf[len++] = (char)val; + ptr = endptr; + } + } + } + else + CV_PARSE_ERROR( "Invalid character" ); + } + + if( len >= CV_FS_MAX_LEN ) + CV_PARSE_ERROR( "Too long string literal" ); + + node->data.str = cvMemStorageAllocString( fs->memstorage, buf, len ); + } + else if( c == '[' || c == '{' ) // collection as a flow + { + int new_min_indent = min_indent + !is_parent_flow; + int struct_flags = CV_NODE_FLOW + (c == '{' ? CV_NODE_MAP : CV_NODE_SEQ); + int is_simple = 1; + + icvFSCreateCollection( fs, CV_NODE_TYPE(struct_flags) + + (node->info ? CV_NODE_USER : 0), node ); + + d = c == '[' ? ']' : '}'; + + for( ++ptr ;;) + { + CvFileNode* elem = 0; + + ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX ); + if( *ptr == '}' || *ptr == ']' ) + { + if( *ptr != d ) + CV_PARSE_ERROR( "The wrong closing bracket" ); + ptr++; + break; + } + + if( node->data.seq->total != 0 ) + { + if( *ptr != ',' ) + CV_PARSE_ERROR( "Missing , between the elements" ); + ptr = icvYMLSkipSpaces( fs, ptr + 1, new_min_indent, INT_MAX ); + } + + if( CV_NODE_IS_MAP(struct_flags) ) + { + ptr = icvYMLParseKey( fs, ptr, node, &elem ); + ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX ); + } + else + { + if( *ptr == ']' ) + break; + elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 ); + } + ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, new_min_indent ); + if( CV_NODE_IS_MAP(struct_flags) ) + elem->tag |= CV_NODE_NAMED; + is_simple &= !CV_NODE_IS_COLLECTION(elem->tag); + } + node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0; + } + else + { + int indent, struct_flags, is_simple; + + if( is_parent_flow || c != '-' ) + { + // implicit (one-line) string or nested block-style collection + if( !is_parent_flow ) + { + if( c == '?' ) + CV_PARSE_ERROR( "Complex keys are not supported" ); + if( c == '|' || c == '>' ) + CV_PARSE_ERROR( "Multi-line text literals are not supported" ); + } + +force_string: + endptr = ptr - 1; + + do c = *++endptr; + while( cv_isprint(c) && + (!is_parent_flow || (c != ',' && c != '}' && c != ']')) && + (is_parent_flow || c != ':' || value_type == CV_NODE_STRING)); + + if( endptr == ptr ) + CV_PARSE_ERROR( "Invalid character" ); + + if( is_parent_flow || c != ':' ) + { + char* str_end = endptr; + node->tag = CV_NODE_STRING; + // strip spaces in the end of string + do c = *--str_end; + while( str_end > ptr && c == ' ' ); + str_end++; + node->data.str = cvMemStorageAllocString( fs->memstorage, ptr, (int)(str_end - ptr) ); + ptr = endptr; + return ptr; + } + struct_flags = CV_NODE_MAP; + } + else + struct_flags = CV_NODE_SEQ; + + icvFSCreateCollection( fs, struct_flags + + (node->info ? CV_NODE_USER : 0), node ); + + indent = (int)(ptr - fs->buffer_start); + is_simple = 1; + + for(;;) + { + CvFileNode* elem = 0; + + if( CV_NODE_IS_MAP(struct_flags) ) + { + ptr = icvYMLParseKey( fs, ptr, node, &elem ); + } + else + { + c = *ptr++; + if( c != '-' ) + CV_PARSE_ERROR( "Block sequence elements must be preceded with \'-\'" ); + + elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 ); + } + + ptr = icvYMLSkipSpaces( fs, ptr, indent + 1, INT_MAX ); + ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, indent + 1 ); + if( CV_NODE_IS_MAP(struct_flags) ) + elem->tag |= CV_NODE_NAMED; + is_simple &= !CV_NODE_IS_COLLECTION(elem->tag); + + ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ); + if( ptr - fs->buffer_start != indent ) + { + if( ptr - fs->buffer_start < indent ) + break; + else + CV_PARSE_ERROR( "Incorrect indentation" ); + } + if( memcmp( ptr, "...", 3 ) == 0 ) + break; + } + + node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0; + } + + return ptr; +} + + +static void +icvYMLParse( CvFileStorage* fs ) +{ + char* ptr = fs->buffer_start; + int is_first = 1; + + for(;;) + { + // 0. skip leading comments and directives and ... + // 1. reach the first item + for(;;) + { + ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ); + if( !ptr ) + return; + + if( *ptr == '%' ) + { + if( memcmp( ptr, "%YAML:", 6 ) == 0 && + memcmp( ptr, "%YAML:1.", 8 ) != 0 ) + CV_PARSE_ERROR( "Unsupported YAML version (it must be 1.x)" ); + *ptr = '\0'; + } + else if( *ptr == '-' ) + { + if( memcmp(ptr, "---", 3) == 0 ) + { + ptr += 3; + break; + } + else if( is_first ) + break; + } + else if( cv_isalnum(*ptr) || *ptr=='_') + { + if( !is_first ) + CV_PARSE_ERROR( "The YAML streams must start with '---', except the first one" ); + break; + } + else if( fs->dummy_eof ) + break; + else + CV_PARSE_ERROR( "Invalid or unsupported syntax" ); + } + + ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ); + if( memcmp( ptr, "...", 3 ) != 0 ) + { + // 2. parse the collection + CvFileNode* root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 ); + + ptr = icvYMLParseValue( fs, ptr, root_node, CV_NODE_NONE, 0 ); + if( !CV_NODE_IS_COLLECTION(root_node->tag) ) + CV_PARSE_ERROR( "Only collections as YAML streams are supported by this parser" ); + + // 3. parse until the end of file or next collection + ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ); + if( !ptr ) + return; + } + + if( fs->dummy_eof ) + break; + ptr += 3; + is_first = 0; + } +} + + +/****************************************************************************************\ +* YAML Emitter * +\****************************************************************************************/ + +static void +icvYMLWrite( CvFileStorage* fs, const char* key, const char* data ) +{ + int i, keylen = 0; + int datalen = 0; + int struct_flags; + char* ptr; + + struct_flags = fs->struct_flags; + + if( key && key[0] == '\0' ) + key = 0; + + if( CV_NODE_IS_COLLECTION(struct_flags) ) + { + if( (CV_NODE_IS_MAP(struct_flags) ^ (key != 0)) ) + CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, " + "or add element with key to sequence" ); + } + else + { + fs->is_first = 0; + struct_flags = CV_NODE_EMPTY | (key ? CV_NODE_MAP : CV_NODE_SEQ); + } + + if( key ) + { + keylen = (int)strlen(key); + if( keylen == 0 ) + CV_Error( CV_StsBadArg, "The key is an empty" ); + + if( keylen > CV_FS_MAX_LEN ) + CV_Error( CV_StsBadArg, "The key is too long" ); + } + + if( data ) + datalen = (int)strlen(data); + + if( CV_NODE_IS_FLOW(struct_flags) ) + { + int new_offset; + ptr = fs->buffer; + if( !CV_NODE_IS_EMPTY(struct_flags) ) + *ptr++ = ','; + new_offset = (int)(ptr - fs->buffer_start) + keylen + datalen; + if( new_offset > fs->wrap_margin && new_offset - fs->struct_indent > 10 ) + { + fs->buffer = ptr; + ptr = icvFSFlush(fs); + } + else + *ptr++ = ' '; + } + else + { + ptr = icvFSFlush(fs); + if( !CV_NODE_IS_MAP(struct_flags) ) + { + *ptr++ = '-'; + if( data ) + *ptr++ = ' '; + } + } + + if( key ) + { + if( !cv_isalpha(key[0]) && key[0] != '_' ) + CV_Error( CV_StsBadArg, "Key must start with a letter or _" ); + + ptr = icvFSResizeWriteBuffer( fs, ptr, keylen ); + + for( i = 0; i < keylen; i++ ) + { + char c = key[i]; + + ptr[i] = c; + if( !cv_isalnum(c) && c != '-' && c != '_' && c != ' ' ) + CV_Error( CV_StsBadArg, "Key names may only contain alphanumeric characters [a-zA-Z0-9], '-', '_' and ' '" ); + } + + ptr += keylen; + *ptr++ = ':'; + if( !CV_NODE_IS_FLOW(struct_flags) && data ) + *ptr++ = ' '; + } + + if( data ) + { + ptr = icvFSResizeWriteBuffer( fs, ptr, datalen ); + memcpy( ptr, data, datalen ); + ptr += datalen; + } + + fs->buffer = ptr; + fs->struct_flags = struct_flags & ~CV_NODE_EMPTY; +} + + +static void +icvYMLStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags, + const char* type_name CV_DEFAULT(0)) +{ + int parent_flags; + char buf[CV_FS_MAX_LEN + 1024]; + const char* data = 0; + + struct_flags = (struct_flags & (CV_NODE_TYPE_MASK|CV_NODE_FLOW)) | CV_NODE_EMPTY; + if( !CV_NODE_IS_COLLECTION(struct_flags)) + CV_Error( CV_StsBadArg, + "Some collection type - CV_NODE_SEQ or CV_NODE_MAP, must be specified" ); + + if( CV_NODE_IS_FLOW(struct_flags) ) + { + char c = CV_NODE_IS_MAP(struct_flags) ? '{' : '['; + struct_flags |= CV_NODE_FLOW; + + if( type_name ) + sprintf( buf, "!!%s %c", type_name, c ); + else + { + buf[0] = c; + buf[1] = '\0'; + } + data = buf; + } + else if( type_name ) + { + sprintf( buf, "!!%s", type_name ); + data = buf; + } + + icvYMLWrite( fs, key, data ); + + parent_flags = fs->struct_flags; + cvSeqPush( fs->write_stack, &parent_flags ); + fs->struct_flags = struct_flags; + + if( !CV_NODE_IS_FLOW(parent_flags) ) + fs->struct_indent += CV_YML_INDENT + CV_NODE_IS_FLOW(struct_flags); +} + + +static void +icvYMLEndWriteStruct( CvFileStorage* fs ) +{ + int parent_flags = 0, struct_flags; + char* ptr; + + struct_flags = fs->struct_flags; + if( fs->write_stack->total == 0 ) + CV_Error( CV_StsError, "EndWriteStruct w/o matching StartWriteStruct" ); + + cvSeqPop( fs->write_stack, &parent_flags ); + + if( CV_NODE_IS_FLOW(struct_flags) ) + { + ptr = fs->buffer; + if( ptr > fs->buffer_start + fs->struct_indent && !CV_NODE_IS_EMPTY(struct_flags) ) + *ptr++ = ' '; + *ptr++ = CV_NODE_IS_MAP(struct_flags) ? '}' : ']'; + fs->buffer = ptr; + } + else if( CV_NODE_IS_EMPTY(struct_flags) ) + { + ptr = icvFSFlush(fs); + memcpy( ptr, CV_NODE_IS_MAP(struct_flags) ? "{}" : "[]", 2 ); + fs->buffer = ptr + 2; + } + + if( !CV_NODE_IS_FLOW(parent_flags) ) + fs->struct_indent -= CV_YML_INDENT + CV_NODE_IS_FLOW(struct_flags); + assert( fs->struct_indent >= 0 ); + + fs->struct_flags = parent_flags; +} + + +static void +icvYMLStartNextStream( CvFileStorage* fs ) +{ + if( !fs->is_first ) + { + while( fs->write_stack->total > 0 ) + icvYMLEndWriteStruct(fs); + + fs->struct_indent = 0; + icvFSFlush(fs); + icvPuts( fs, "...\n" ); + icvPuts( fs, "---\n" ); + fs->buffer = fs->buffer_start; + } +} + + +static void +icvYMLWriteInt( CvFileStorage* fs, const char* key, int value ) +{ + char buf[128]; + icvYMLWrite( fs, key, icv_itoa( value, buf, 10 )); +} + + +static void +icvYMLWriteReal( CvFileStorage* fs, const char* key, double value ) +{ + char buf[128]; + icvYMLWrite( fs, key, icvDoubleToString( buf, value )); +} + + +static void +icvYMLWriteString( CvFileStorage* fs, const char* key, + const char* str, int quote CV_DEFAULT(0)) +{ + char buf[CV_FS_MAX_LEN*4+16]; + char* data = (char*)str; + int i, len; + + if( !str ) + CV_Error( CV_StsNullPtr, "Null string pointer" ); + + len = (int)strlen(str); + if( len > CV_FS_MAX_LEN ) + CV_Error( CV_StsBadArg, "The written string is too long" ); + + if( quote || len == 0 || str[0] != str[len-1] || (str[0] != '\"' && str[0] != '\'') ) + { + int need_quote = quote || len == 0; + data = buf; + *data++ = '\"'; + for( i = 0; i < len; i++ ) + { + char c = str[i]; + + if( !need_quote && !cv_isalnum(c) && c != '_' && c != ' ' && c != '-' && + c != '(' && c != ')' && c != '/' && c != '+' && c != ';' ) + need_quote = 1; + + if( !cv_isalnum(c) && (!cv_isprint(c) || c == '\\' || c == '\'' || c == '\"') ) + { + *data++ = '\\'; + if( cv_isprint(c) ) + *data++ = c; + else if( c == '\n' ) + *data++ = 'n'; + else if( c == '\r' ) + *data++ = 'r'; + else if( c == '\t' ) + *data++ = 't'; + else + { + sprintf( data, "x%02x", c ); + data += 3; + } + } + else + *data++ = c; + } + if( !need_quote && (cv_isdigit(str[0]) || + str[0] == '+' || str[0] == '-' || str[0] == '.' )) + need_quote = 1; + + if( need_quote ) + *data++ = '\"'; + *data++ = '\0'; + data = buf + !need_quote; + } + + icvYMLWrite( fs, key, data ); +} + + +static void +icvYMLWriteComment( CvFileStorage* fs, const char* comment, int eol_comment ) +{ + int len; //, indent; + int multiline; + const char* eol; + char* ptr; + + if( !comment ) + CV_Error( CV_StsNullPtr, "Null comment" ); + + len = (int)strlen(comment); + eol = strchr(comment, '\n'); + multiline = eol != 0; + ptr = fs->buffer; + + if( !eol_comment || multiline || + fs->buffer_end - ptr < len || ptr == fs->buffer_start ) + ptr = icvFSFlush( fs ); + else + *ptr++ = ' '; + + while( comment ) + { + *ptr++ = '#'; + *ptr++ = ' '; + if( eol ) + { + ptr = icvFSResizeWriteBuffer( fs, ptr, (int)(eol - comment) + 1 ); + memcpy( ptr, comment, eol - comment + 1 ); + fs->buffer = ptr + (eol - comment); + comment = eol + 1; + eol = strchr( comment, '\n' ); + } + else + { + len = (int)strlen(comment); + ptr = icvFSResizeWriteBuffer( fs, ptr, len ); + memcpy( ptr, comment, len ); + fs->buffer = ptr + len; + comment = 0; + } + ptr = icvFSFlush( fs ); + } +} + + +/****************************************************************************************\ +* XML Parser * +\****************************************************************************************/ + +#define CV_XML_INSIDE_COMMENT 1 +#define CV_XML_INSIDE_TAG 2 +#define CV_XML_INSIDE_DIRECTIVE 3 + +static char* +icvXMLSkipSpaces( CvFileStorage* fs, char* ptr, int mode ) +{ + int level = 0; + + for(;;) + { + char c; + ptr--; + + if( mode == CV_XML_INSIDE_COMMENT ) + { + do c = *++ptr; + while( cv_isprint_or_tab(c) && (c != '-' || ptr[1] != '-' || ptr[2] != '>') ); + + if( c == '-' ) + { + assert( ptr[1] == '-' && ptr[2] == '>' ); + mode = 0; + ptr += 3; + } + } + else if( mode == CV_XML_INSIDE_DIRECTIVE ) + { + // !!!NOTE!!! This is not quite correct, but should work in most cases + do + { + c = *++ptr; + level += c == '<'; + level -= c == '>'; + if( level < 0 ) + return ptr; + } while( cv_isprint_or_tab(c) ); + } + else + { + do c = *++ptr; + while( c == ' ' || c == '\t' ); + + if( c == '<' && ptr[1] == '!' && ptr[2] == '-' && ptr[3] == '-' ) + { + if( mode != 0 ) + CV_PARSE_ERROR( "Comments are not allowed here" ); + mode = CV_XML_INSIDE_COMMENT; + ptr += 4; + } + else if( cv_isprint(c) ) + break; + } + + if( !cv_isprint(*ptr) ) + { + int max_size = (int)(fs->buffer_end - fs->buffer_start); + if( *ptr != '\0' && *ptr != '\n' && *ptr != '\r' ) + CV_PARSE_ERROR( "Invalid character in the stream" ); + ptr = icvGets( fs, fs->buffer_start, max_size ); + if( !ptr ) + { + ptr = fs->buffer_start; + *ptr = '\0'; + fs->dummy_eof = 1; + break; + } + else + { + int l = (int)strlen(ptr); + if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !icvEof(fs) ) + CV_PARSE_ERROR( "Too long string or a last string w/o newline" ); + } + fs->lineno++; + } + } + return ptr; +} + + +static char* +icvXMLParseTag( CvFileStorage* fs, char* ptr, CvStringHashNode** _tag, + CvAttrList** _list, int* _tag_type ); + +static char* +icvXMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node, + int value_type CV_DEFAULT(CV_NODE_NONE)) +{ + CvFileNode *elem = node; + int have_space = 1, is_simple = 1; + int is_user_type = CV_NODE_IS_USER(value_type); + memset( node, 0, sizeof(*node) ); + + value_type = CV_NODE_TYPE(value_type); + + for(;;) + { + char c = *ptr, d; + char* endptr; + + if( cv_isspace(c) || c == '\0' || (c == '<' && ptr[1] == '!' && ptr[2] == '-') ) + { + ptr = icvXMLSkipSpaces( fs, ptr, 0 ); + have_space = 1; + c = *ptr; + } + + d = ptr[1]; + + if( c =='<' || c == '\0' ) + { + CvStringHashNode *key = 0, *key2 = 0; + CvAttrList* list = 0; + CvTypeInfo* info = 0; + int tag_type = 0; + int is_noname = 0; + const char* type_name = 0; + int elem_type = CV_NODE_NONE; + + if( d == '/' || c == '\0' ) + break; + + ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type ); + + if( tag_type == CV_XML_DIRECTIVE_TAG ) + CV_PARSE_ERROR( "Directive tags are not allowed here" ); + if( tag_type == CV_XML_EMPTY_TAG ) + CV_PARSE_ERROR( "Empty tags are not supported" ); + + assert( tag_type == CV_XML_OPENING_TAG ); + + type_name = list ? cvAttrValue( list, "type_id" ) : 0; + if( type_name ) + { + if( strcmp( type_name, "str" ) == 0 ) + elem_type = CV_NODE_STRING; + else if( strcmp( type_name, "map" ) == 0 ) + elem_type = CV_NODE_MAP; + else if( strcmp( type_name, "seq" ) == 0 ) + elem_type = CV_NODE_SEQ; + else + { + info = cvFindType( type_name ); + if( info ) + elem_type = CV_NODE_USER; + } + } + + is_noname = key->str.len == 1 && key->str.ptr[0] == '_'; + if( !CV_NODE_IS_COLLECTION(node->tag) ) + { + icvFSCreateCollection( fs, is_noname ? CV_NODE_SEQ : CV_NODE_MAP, node ); + } + else if( is_noname ^ CV_NODE_IS_SEQ(node->tag) ) + CV_PARSE_ERROR( is_noname ? "Map element should have a name" : + "Sequence element should not have name (use <_>)" ); + + if( is_noname ) + elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 ); + else + elem = cvGetFileNode( fs, node, key, 1 ); + + ptr = icvXMLParseValue( fs, ptr, elem, elem_type); + if( !is_noname ) + elem->tag |= CV_NODE_NAMED; + is_simple &= !CV_NODE_IS_COLLECTION(elem->tag); + elem->info = info; + ptr = icvXMLParseTag( fs, ptr, &key2, &list, &tag_type ); + if( tag_type != CV_XML_CLOSING_TAG || key2 != key ) + CV_PARSE_ERROR( "Mismatched closing tag" ); + have_space = 1; + } + else + { + if( !have_space ) + CV_PARSE_ERROR( "There should be space between literals" ); + + elem = node; + if( node->tag != CV_NODE_NONE ) + { + if( !CV_NODE_IS_COLLECTION(node->tag) ) + icvFSCreateCollection( fs, CV_NODE_SEQ, node ); + + elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 ); + elem->info = 0; + } + + if( value_type != CV_NODE_STRING && + (cv_isdigit(c) || ((c == '-' || c == '+') && + (cv_isdigit(d) || d == '.')) || (c == '.' && cv_isalnum(d))) ) // a number + { + double fval; + int ival; + endptr = ptr + (c == '-' || c == '+'); + while( cv_isdigit(*endptr) ) + endptr++; + if( *endptr == '.' || *endptr == 'e' ) + { + fval = icv_strtod( fs, ptr, &endptr ); + /*if( endptr == ptr || cv_isalpha(*endptr) ) + icvProcessSpecialDouble( fs, ptr, &fval, &endptr ));*/ + elem->tag = CV_NODE_REAL; + elem->data.f = fval; + } + else + { + ival = (int)strtol( ptr, &endptr, 0 ); + elem->tag = CV_NODE_INT; + elem->data.i = ival; + } + + if( endptr == ptr ) + CV_PARSE_ERROR( "Invalid numeric value (inconsistent explicit type specification?)" ); + + ptr = endptr; + } + else + { + // string + char buf[CV_FS_MAX_LEN+16]; + int i = 0, len, is_quoted = 0; + elem->tag = CV_NODE_STRING; + if( c == '\"' ) + is_quoted = 1; + else + --ptr; + + for( ;; ) + { + c = *++ptr; + if( !cv_isalnum(c) ) + { + if( c == '\"' ) + { + if( !is_quoted ) + CV_PARSE_ERROR( "Literal \" is not allowed within a string. Use "" ); + ++ptr; + break; + } + else if( !cv_isprint(c) || c == '<' || (!is_quoted && cv_isspace(c))) + { + if( is_quoted ) + CV_PARSE_ERROR( "Closing \" is expected" ); + break; + } + else if( c == '\'' || c == '>' ) + { + CV_PARSE_ERROR( "Literal \' or > are not allowed. Use ' or >" ); + } + else if( c == '&' ) + { + if( *++ptr == '#' ) + { + int val, base = 10; + ptr++; + if( *ptr == 'x' ) + { + base = 16; + ptr++; + } + val = (int)strtol( ptr, &endptr, base ); + if( (unsigned)val > (unsigned)255 || + !endptr || *endptr != ';' ) + CV_PARSE_ERROR( "Invalid numeric value in the string" ); + c = (char)val; + } + else + { + endptr = ptr; + do c = *++endptr; + while( cv_isalnum(c) ); + if( c != ';' ) + CV_PARSE_ERROR( "Invalid character in the symbol entity name" ); + len = (int)(endptr - ptr); + if( len == 2 && memcmp( ptr, "lt", len ) == 0 ) + c = '<'; + else if( len == 2 && memcmp( ptr, "gt", len ) == 0 ) + c = '>'; + else if( len == 3 && memcmp( ptr, "amp", len ) == 0 ) + c = '&'; + else if( len == 4 && memcmp( ptr, "apos", len ) == 0 ) + c = '\''; + else if( len == 4 && memcmp( ptr, "quot", len ) == 0 ) + c = '\"'; + else + { + memcpy( buf + i, ptr-1, len + 2 ); + i += len + 2; + } + } + ptr = endptr; + } + } + buf[i++] = c; + if( i >= CV_FS_MAX_LEN ) + CV_PARSE_ERROR( "Too long string literal" ); + } + elem->data.str = cvMemStorageAllocString( fs->memstorage, buf, i ); + } + + if( !CV_NODE_IS_COLLECTION(value_type) && value_type != CV_NODE_NONE ) + break; + have_space = 0; + } + } + + if( (CV_NODE_TYPE(node->tag) == CV_NODE_NONE || + (CV_NODE_TYPE(node->tag) != value_type && + !CV_NODE_IS_COLLECTION(node->tag))) && + CV_NODE_IS_COLLECTION(value_type) ) + { + icvFSCreateCollection( fs, CV_NODE_IS_MAP(value_type) ? + CV_NODE_MAP : CV_NODE_SEQ, node ); + } + + if( value_type != CV_NODE_NONE && + value_type != CV_NODE_TYPE(node->tag) ) + CV_PARSE_ERROR( "The actual type is different from the specified type" ); + + if( CV_NODE_IS_COLLECTION(node->tag) && is_simple ) + node->data.seq->flags |= CV_NODE_SEQ_SIMPLE; + + node->tag |= is_user_type ? CV_NODE_USER : 0; + return ptr; +} + + +static char* +icvXMLParseTag( CvFileStorage* fs, char* ptr, CvStringHashNode** _tag, + CvAttrList** _list, int* _tag_type ) +{ + int tag_type = 0; + CvStringHashNode* tagname = 0; + CvAttrList *first = 0, *last = 0; + int count = 0, max_count = 4; + int attr_buf_size = (max_count*2 + 1)*sizeof(char*) + sizeof(CvAttrList); + char* endptr; + char c; + int have_space; + + if( *ptr == '\0' ) + CV_PARSE_ERROR( "Preliminary end of the stream" ); + + if( *ptr != '<' ) + CV_PARSE_ERROR( "Tag should start with \'<\'" ); + + ptr++; + if( cv_isalnum(*ptr) || *ptr == '_' ) + tag_type = CV_XML_OPENING_TAG; + else if( *ptr == '/' ) + { + tag_type = CV_XML_CLOSING_TAG; + ptr++; + } + else if( *ptr == '?' ) + { + tag_type = CV_XML_HEADER_TAG; + ptr++; + } + else if( *ptr == '!' ) + { + tag_type = CV_XML_DIRECTIVE_TAG; + assert( ptr[1] != '-' || ptr[2] != '-' ); + ptr++; + } + else + CV_PARSE_ERROR( "Unknown tag type" ); + + for(;;) + { + CvStringHashNode* attrname; + + if( !cv_isalpha(*ptr) && *ptr != '_' ) + CV_PARSE_ERROR( "Name should start with a letter or underscore" ); + + endptr = ptr - 1; + do c = *++endptr; + while( cv_isalnum(c) || c == '_' || c == '-' ); + + attrname = cvGetHashedKey( fs, ptr, (int)(endptr - ptr), 1 ); + ptr = endptr; + + if( !tagname ) + tagname = attrname; + else + { + if( tag_type == CV_XML_CLOSING_TAG ) + CV_PARSE_ERROR( "Closing tag should not contain any attributes" ); + + if( !last || count >= max_count ) + { + CvAttrList* chunk; + + chunk = (CvAttrList*)cvMemStorageAlloc( fs->memstorage, attr_buf_size ); + memset( chunk, 0, attr_buf_size ); + chunk->attr = (const char**)(chunk + 1); + count = 0; + if( !last ) + first = last = chunk; + else + last = last->next = chunk; + } + last->attr[count*2] = attrname->str.ptr; + } + + if( last ) + { + CvFileNode stub; + + if( *ptr != '=' ) + { + ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG ); + if( *ptr != '=' ) + CV_PARSE_ERROR( "Attribute name should be followed by \'=\'" ); + } + + c = *++ptr; + if( c != '\"' && c != '\'' ) + { + ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG ); + if( *ptr != '\"' && *ptr != '\'' ) + CV_PARSE_ERROR( "Attribute value should be put into single or double quotes" ); + } + + ptr = icvXMLParseValue( fs, ptr, &stub, CV_NODE_STRING ); + assert( stub.tag == CV_NODE_STRING ); + last->attr[count*2+1] = stub.data.str.ptr; + count++; + } + + c = *ptr; + have_space = cv_isspace(c) || c == '\0'; + + if( c != '>' ) + { + ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG ); + c = *ptr; + } + + if( c == '>' ) + { + if( tag_type == CV_XML_HEADER_TAG ) + CV_PARSE_ERROR( "Invalid closing tag for ' ) + CV_PARSE_ERROR( "Invalid closing tag for ' && tag_type == CV_XML_OPENING_TAG ) + { + tag_type = CV_XML_EMPTY_TAG; + ptr += 2; + break; + } + + if( !have_space ) + CV_PARSE_ERROR( "There should be space between attributes" ); + } + + *_tag = tagname; + *_tag_type = tag_type; + *_list = first; + + return ptr; +} + + +static void +icvXMLParse( CvFileStorage* fs ) +{ + char* ptr = fs->buffer_start; + CvStringHashNode *key = 0, *key2 = 0; + CvAttrList* list = 0; + int tag_type = 0; + + // CV_XML_INSIDE_TAG is used to prohibit leading comments + ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG ); + + if( memcmp( ptr, "\'" ); + + ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type ); + + /*{ + const char* version = cvAttrValue( list, "version" ); + if( version && strncmp( version, "1.", 2 ) != 0 ) + CV_Error( CV_StsParseError, "Unsupported version of XML" ); + }*/ + // we support any 8-bit encoding, so we do not need to check the actual encoding. + // we do not support utf-16, but in the case of utf-16 we will not get here anyway. + /*{ + const char* encoding = cvAttrValue( list, "encoding" ); + if( encoding && strcmp( encoding, "ASCII" ) != 0 && + strcmp( encoding, "UTF-8" ) != 0 && + strcmp( encoding, "utf-8" ) != 0 ) + CV_PARSE_ERROR( "Unsupported encoding" ); + }*/ + + while( *ptr != '\0' ) + { + ptr = icvXMLSkipSpaces( fs, ptr, 0 ); + + if( *ptr != '\0' ) + { + CvFileNode* root_node; + ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type ); + if( tag_type != CV_XML_OPENING_TAG || + strcmp(key->str.ptr,"opencv_storage") != 0 ) + CV_PARSE_ERROR( " tag is missing" ); + + root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 ); + ptr = icvXMLParseValue( fs, ptr, root_node, CV_NODE_NONE ); + ptr = icvXMLParseTag( fs, ptr, &key2, &list, &tag_type ); + if( tag_type != CV_XML_CLOSING_TAG || key != key2 ) + CV_PARSE_ERROR( " tag is missing" ); + ptr = icvXMLSkipSpaces( fs, ptr, 0 ); + } + } + + assert( fs->dummy_eof != 0 ); +} + + +/****************************************************************************************\ +* XML Emitter * +\****************************************************************************************/ + +#define icvXMLFlush icvFSFlush + +static void +icvXMLWriteTag( CvFileStorage* fs, const char* key, int tag_type, CvAttrList list ) +{ + char* ptr = fs->buffer; + int i, len = 0; + int struct_flags = fs->struct_flags; + + if( key && key[0] == '\0' ) + key = 0; + + if( tag_type == CV_XML_OPENING_TAG || tag_type == CV_XML_EMPTY_TAG ) + { + if( CV_NODE_IS_COLLECTION(struct_flags) ) + { + if( CV_NODE_IS_MAP(struct_flags) ^ (key != 0) ) + CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, " + "or add element with key to sequence" ); + } + else + { + struct_flags = CV_NODE_EMPTY + (key ? CV_NODE_MAP : CV_NODE_SEQ); + fs->is_first = 0; + } + + if( !CV_NODE_IS_EMPTY(struct_flags) ) + ptr = icvXMLFlush(fs); + } + + if( !key ) + key = "_"; + else if( key[0] == '_' && key[1] == '\0' ) + CV_Error( CV_StsBadArg, "A single _ is a reserved tag name" ); + + len = (int)strlen( key ); + *ptr++ = '<'; + if( tag_type == CV_XML_CLOSING_TAG ) + { + if( list.attr ) + CV_Error( CV_StsBadArg, "Closing tag should not include any attributes" ); + *ptr++ = '/'; + } + + if( !cv_isalpha(key[0]) && key[0] != '_' ) + CV_Error( CV_StsBadArg, "Key should start with a letter or _" ); + + ptr = icvFSResizeWriteBuffer( fs, ptr, len ); + for( i = 0; i < len; i++ ) + { + char c = key[i]; + if( !cv_isalnum(c) && c != '_' && c != '-' ) + CV_Error( CV_StsBadArg, "Key name may only contain alphanumeric characters [a-zA-Z0-9], '-' and '_'" ); + ptr[i] = c; + } + ptr += len; + + for(;;) + { + const char** attr = list.attr; + + for( ; attr && attr[0] != 0; attr += 2 ) + { + int len0 = (int)strlen(attr[0]); + int len1 = (int)strlen(attr[1]); + + ptr = icvFSResizeWriteBuffer( fs, ptr, len0 + len1 + 4 ); + *ptr++ = ' '; + memcpy( ptr, attr[0], len0 ); + ptr += len0; + *ptr++ = '='; + *ptr++ = '\"'; + memcpy( ptr, attr[1], len1 ); + ptr += len1; + *ptr++ = '\"'; + } + if( !list.next ) + break; + list = *list.next; + } + + if( tag_type == CV_XML_EMPTY_TAG ) + *ptr++ = '/'; + *ptr++ = '>'; + fs->buffer = ptr; + fs->struct_flags = struct_flags & ~CV_NODE_EMPTY; +} + + +static void +icvXMLStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags, + const char* type_name CV_DEFAULT(0)) +{ + CvXMLStackRecord parent; + const char* attr[10]; + int idx = 0; + + struct_flags = (struct_flags & (CV_NODE_TYPE_MASK|CV_NODE_FLOW)) | CV_NODE_EMPTY; + if( !CV_NODE_IS_COLLECTION(struct_flags)) + CV_Error( CV_StsBadArg, + "Some collection type: CV_NODE_SEQ or CV_NODE_MAP must be specified" ); + + if( type_name ) + { + attr[idx++] = "type_id"; + attr[idx++] = type_name; + } + attr[idx++] = 0; + + icvXMLWriteTag( fs, key, CV_XML_OPENING_TAG, cvAttrList(attr,0) ); + + parent.struct_flags = fs->struct_flags & ~CV_NODE_EMPTY; + parent.struct_indent = fs->struct_indent; + parent.struct_tag = fs->struct_tag; + cvSaveMemStoragePos( fs->strstorage, &parent.pos ); + cvSeqPush( fs->write_stack, &parent ); + + fs->struct_indent += CV_XML_INDENT; + if( !CV_NODE_IS_FLOW(struct_flags) ) + icvXMLFlush( fs ); + + fs->struct_flags = struct_flags; + if( key ) + { + fs->struct_tag = cvMemStorageAllocString( fs->strstorage, (char*)key, -1 ); + } + else + { + fs->struct_tag.ptr = 0; + fs->struct_tag.len = 0; + } +} + + +static void +icvXMLEndWriteStruct( CvFileStorage* fs ) +{ + CvXMLStackRecord parent; + + if( fs->write_stack->total == 0 ) + CV_Error( CV_StsError, "An extra closing tag" ); + + icvXMLWriteTag( fs, fs->struct_tag.ptr, CV_XML_CLOSING_TAG, cvAttrList(0,0) ); + cvSeqPop( fs->write_stack, &parent ); + + fs->struct_indent = parent.struct_indent; + fs->struct_flags = parent.struct_flags; + fs->struct_tag = parent.struct_tag; + cvRestoreMemStoragePos( fs->strstorage, &parent.pos ); +} + + +static void +icvXMLStartNextStream( CvFileStorage* fs ) +{ + if( !fs->is_first ) + { + while( fs->write_stack->total > 0 ) + icvXMLEndWriteStruct(fs); + + fs->struct_indent = 0; + icvXMLFlush(fs); + /* XML does not allow multiple top-level elements, + so we just put a comment and continue + the current (and the only) "stream" */ + icvPuts( fs, "\n\n" ); + /*fputs( "\n", fs->file ); + fputs( "\n", fs->file );*/ + fs->buffer = fs->buffer_start; + } +} + + +static void +icvXMLWriteScalar( CvFileStorage* fs, const char* key, const char* data, int len ) +{ + if( CV_NODE_IS_MAP(fs->struct_flags) || + (!CV_NODE_IS_COLLECTION(fs->struct_flags) && key) ) + { + icvXMLWriteTag( fs, key, CV_XML_OPENING_TAG, cvAttrList(0,0) ); + char* ptr = icvFSResizeWriteBuffer( fs, fs->buffer, len ); + memcpy( ptr, data, len ); + fs->buffer = ptr + len; + icvXMLWriteTag( fs, key, CV_XML_CLOSING_TAG, cvAttrList(0,0) ); + } + else + { + char* ptr = fs->buffer; + int new_offset = (int)(ptr - fs->buffer_start) + len; + + if( key ) + CV_Error( CV_StsBadArg, "elements with keys can not be written to sequence" ); + + fs->struct_flags = CV_NODE_SEQ; + + if( (new_offset > fs->wrap_margin && new_offset - fs->struct_indent > 10) || + (ptr > fs->buffer_start && ptr[-1] == '>' && !CV_NODE_IS_EMPTY(fs->struct_flags)) ) + { + ptr = icvXMLFlush(fs); + } + else if( ptr > fs->buffer_start + fs->struct_indent && ptr[-1] != '>' ) + *ptr++ = ' '; + + memcpy( ptr, data, len ); + fs->buffer = ptr + len; + } +} + + +static void +icvXMLWriteInt( CvFileStorage* fs, const char* key, int value ) +{ + char buf[128], *ptr = icv_itoa( value, buf, 10 ); + int len = (int)strlen(ptr); + icvXMLWriteScalar( fs, key, ptr, len ); +} + + +static void +icvXMLWriteReal( CvFileStorage* fs, const char* key, double value ) +{ + char buf[128]; + int len = (int)strlen( icvDoubleToString( buf, value )); + icvXMLWriteScalar( fs, key, buf, len ); +} + + +static void +icvXMLWriteString( CvFileStorage* fs, const char* key, const char* str, int quote ) +{ + char buf[CV_FS_MAX_LEN*6+16]; + char* data = (char*)str; + int i, len; + + if( !str ) + CV_Error( CV_StsNullPtr, "Null string pointer" ); + + len = (int)strlen(str); + if( len > CV_FS_MAX_LEN ) + CV_Error( CV_StsBadArg, "The written string is too long" ); + + if( quote || len == 0 || str[0] != '\"' || str[0] != str[len-1] ) + { + int need_quote = quote || len == 0; + data = buf; + *data++ = '\"'; + for( i = 0; i < len; i++ ) + { + char c = str[i]; + + if( (uchar)c >= 128 || c == ' ' ) + { + *data++ = c; + need_quote = 1; + } + else if( !cv_isprint(c) || c == '<' || c == '>' || c == '&' || c == '\'' || c == '\"' ) + { + *data++ = '&'; + if( c == '<' ) + { + memcpy(data, "lt", 2); + data += 2; + } + else if( c == '>' ) + { + memcpy(data, "gt", 2); + data += 2; + } + else if( c == '&' ) + { + memcpy(data, "amp", 3); + data += 3; + } + else if( c == '\'' ) + { + memcpy(data, "apos", 4); + data += 4; + } + else if( c == '\"' ) + { + memcpy( data, "quot", 4); + data += 4; + } + else + { + sprintf( data, "#x%02x", (uchar)c ); + data += 4; + } + *data++ = ';'; + need_quote = 1; + } + else + *data++ = c; + } + if( !need_quote && (cv_isdigit(str[0]) || + str[0] == '+' || str[0] == '-' || str[0] == '.' )) + need_quote = 1; + + if( need_quote ) + *data++ = '\"'; + len = (int)(data - buf) - !need_quote; + *data++ = '\0'; + data = buf + !need_quote; + } + + icvXMLWriteScalar( fs, key, data, len ); +} + + +static void +icvXMLWriteComment( CvFileStorage* fs, const char* comment, int eol_comment ) +{ + int len; + int multiline; + const char* eol; + char* ptr; + + if( !comment ) + CV_Error( CV_StsNullPtr, "Null comment" ); + + if( strstr(comment, "--") != 0 ) + CV_Error( CV_StsBadArg, "Double hyphen \'--\' is not allowed in the comments" ); + + len = (int)strlen(comment); + eol = strchr(comment, '\n'); + multiline = eol != 0; + ptr = fs->buffer; + + if( multiline || !eol_comment || fs->buffer_end - ptr < len + 5 ) + ptr = icvXMLFlush( fs ); + else if( ptr > fs->buffer_start + fs->struct_indent ) + *ptr++ = ' '; + + if( !multiline ) + { + ptr = icvFSResizeWriteBuffer( fs, ptr, len + 9 ); + sprintf( ptr, "", comment ); + len = (int)strlen(ptr); + } + else + { + strcpy( ptr, "" ); + fs->buffer = ptr + 3; + icvXMLFlush( fs ); + } +} + + +/****************************************************************************************\ +* Common High-Level Functions * +\****************************************************************************************/ + +CV_IMPL CvFileStorage* +cvOpenFileStorage( const char* filename, CvMemStorage* dststorage, int flags, const char* encoding ) +{ + CvFileStorage* fs = 0; + char* xml_buf = 0; + int default_block_size = 1 << 18; + bool append = (flags & 3) == CV_STORAGE_APPEND; + bool mem = (flags & CV_STORAGE_MEMORY) != 0; + bool write_mode = (flags & 3) != 0; + bool isGZ = false; + size_t fnamelen = 0; + + if( !filename || filename[0] == '\0' ) + { + if( !write_mode ) + CV_Error( CV_StsNullPtr, mem ? "NULL or empty filename" : "NULL or empty buffer" ); + mem = true; + } + else + fnamelen = strlen(filename); + + if( mem && append ) + CV_Error( CV_StsBadFlag, "CV_STORAGE_APPEND and CV_STORAGE_MEMORY are not currently compatible" ); + + fs = (CvFileStorage*)cvAlloc( sizeof(*fs) ); + memset( fs, 0, sizeof(*fs)); + + fs->memstorage = cvCreateMemStorage( default_block_size ); + fs->dststorage = dststorage ? dststorage : fs->memstorage; + + fs->flags = CV_FILE_STORAGE; + fs->write_mode = write_mode; + + if( !mem ) + { + fs->filename = (char*)cvMemStorageAlloc( fs->memstorage, fnamelen+1 ); + strcpy( fs->filename, filename ); + + char* dot_pos = strrchr(fs->filename, '.'); + char compression = '\0'; + + if( dot_pos && dot_pos[1] == 'g' && dot_pos[2] == 'z' && + (dot_pos[3] == '\0' || (cv_isdigit(dot_pos[3]) && dot_pos[4] == '\0')) ) + { + if( append ) + CV_Error(CV_StsNotImplemented, "Appending data to compressed file is not implemented" ); + isGZ = true; + compression = dot_pos[3]; + if( compression ) + dot_pos[3] = '\0', fnamelen--; + } + + if( !isGZ ) + { + fs->file = fopen(fs->filename, !fs->write_mode ? "rt" : !append ? "wt" : "a+t" ); + if( !fs->file ) + goto _exit_; + } + else + { + #if USE_ZLIB + char mode[] = { fs->write_mode ? 'w' : 'r', 'b', compression ? compression : '3', '\0' }; + fs->gzfile = gzopen(fs->filename, mode); + if( !fs->gzfile ) + goto _exit_; + #else + CV_Error(CV_StsNotImplemented, "There is no compressed file storage support in this configuration"); + #endif + } + } + + fs->roots = 0; + fs->struct_indent = 0; + fs->struct_flags = 0; + fs->wrap_margin = 71; + + if( fs->write_mode ) + { + int fmt = flags & CV_STORAGE_FORMAT_MASK; + + if( mem ) + fs->outbuf = new std::deque; + + if( fmt == CV_STORAGE_FORMAT_AUTO && filename ) + { + const char* dot_pos = filename + fnamelen - (isGZ ? 7 : 4); + fs->fmt = (dot_pos >= filename && (memcmp( dot_pos, ".xml", 4) == 0 || + memcmp(dot_pos, ".XML", 4) == 0 || memcmp(dot_pos, ".Xml", 4) == 0)) ? + CV_STORAGE_FORMAT_XML : CV_STORAGE_FORMAT_YAML; + } + else + fs->fmt = fmt != CV_STORAGE_FORMAT_AUTO ? fmt : CV_STORAGE_FORMAT_XML; + + // we use factor=6 for XML (the longest characters (' and ") are encoded with 6 bytes (' and ") + // and factor=4 for YAML ( as we use 4 bytes for non ASCII characters (e.g. \xAB)) + int buf_size = CV_FS_MAX_LEN*(fs->fmt == CV_STORAGE_FORMAT_XML ? 6 : 4) + 1024; + + if( append ) + fseek( fs->file, 0, SEEK_END ); + + fs->write_stack = cvCreateSeq( 0, sizeof(CvSeq), fs->fmt == CV_STORAGE_FORMAT_XML ? + sizeof(CvXMLStackRecord) : sizeof(int), fs->memstorage ); + fs->is_first = 1; + fs->struct_indent = 0; + fs->struct_flags = CV_NODE_EMPTY; + fs->buffer_start = fs->buffer = (char*)cvAlloc( buf_size + 1024 ); + fs->buffer_end = fs->buffer_start + buf_size; + if( fs->fmt == CV_STORAGE_FORMAT_XML ) + { + size_t file_size = fs->file ? (size_t)ftell( fs->file ) : (size_t)0; + fs->strstorage = cvCreateChildMemStorage( fs->memstorage ); + if( !append || file_size == 0 ) + { + if( encoding ) + { + if( strcmp( encoding, "UTF-16" ) == 0 || + strcmp( encoding, "utf-16" ) == 0 || + strcmp( encoding, "Utf-16" ) == 0 ) + CV_Error( CV_StsBadArg, "UTF-16 XML encoding is not supported! Use 8-bit encoding\n"); + + CV_Assert( strlen(encoding) < 1000 ); + char buf[1100]; + sprintf(buf, "\n", encoding); + icvPuts( fs, buf ); + } + else + icvPuts( fs, "\n" ); + icvPuts( fs, "\n" ); + } + else + { + int xml_buf_size = 1 << 10; + char substr[] = ""; + int last_occurence = -1; + xml_buf_size = MIN(xml_buf_size, int(file_size)); + fseek( fs->file, -xml_buf_size, SEEK_END ); + xml_buf = (char*)cvAlloc( xml_buf_size+2 ); + // find the last occurence of + for(;;) + { + int line_offset = ftell( fs->file ); + char* ptr0 = icvGets( fs, xml_buf, xml_buf_size ), *ptr; + if( !ptr0 ) + break; + ptr = ptr0; + for(;;) + { + ptr = strstr( ptr, substr ); + if( !ptr ) + break; + last_occurence = line_offset + (int)(ptr - ptr0); + ptr += strlen(substr); + } + } + if( last_occurence < 0 ) + CV_Error( CV_StsError, "Could not find in the end of file.\n" ); + icvCloseFile( fs ); + fs->file = fopen( fs->filename, "r+t" ); + fseek( fs->file, last_occurence, SEEK_SET ); + // replace the last "" with " ", which has the same length + icvPuts( fs, " " ); + fseek( fs->file, 0, SEEK_END ); + icvPuts( fs, "\n" ); + } + fs->start_write_struct = icvXMLStartWriteStruct; + fs->end_write_struct = icvXMLEndWriteStruct; + fs->write_int = icvXMLWriteInt; + fs->write_real = icvXMLWriteReal; + fs->write_string = icvXMLWriteString; + fs->write_comment = icvXMLWriteComment; + fs->start_next_stream = icvXMLStartNextStream; + } + else + { + if( !append ) + icvPuts( fs, "%YAML:1.0\n" ); + else + icvPuts( fs, "...\n---\n" ); + fs->start_write_struct = icvYMLStartWriteStruct; + fs->end_write_struct = icvYMLEndWriteStruct; + fs->write_int = icvYMLWriteInt; + fs->write_real = icvYMLWriteReal; + fs->write_string = icvYMLWriteString; + fs->write_comment = icvYMLWriteComment; + fs->start_next_stream = icvYMLStartNextStream; + } + } + else + { + if( mem ) + { + fs->strbuf = filename; + fs->strbufsize = fnamelen; + } + + size_t buf_size = 1 << 20; + const char* yaml_signature = "%YAML:"; + char buf[16]; + icvGets( fs, buf, sizeof(buf)-2 ); + fs->fmt = strncmp( buf, yaml_signature, strlen(yaml_signature) ) == 0 ? + CV_STORAGE_FORMAT_YAML : CV_STORAGE_FORMAT_XML; + + if( !isGZ ) + { + if( !mem ) + { + fseek( fs->file, 0, SEEK_END ); + buf_size = ftell( fs->file ); + } + else + buf_size = fs->strbufsize; + buf_size = MIN( buf_size, (size_t)(1 << 20) ); + buf_size = MAX( buf_size, (size_t)(CV_FS_MAX_LEN*2 + 1024) ); + } + icvRewind(fs); + + fs->str_hash = cvCreateMap( 0, sizeof(CvStringHash), + sizeof(CvStringHashNode), fs->memstorage, 256 ); + + fs->roots = cvCreateSeq( 0, sizeof(CvSeq), + sizeof(CvFileNode), fs->memstorage ); + + fs->buffer = fs->buffer_start = (char*)cvAlloc( buf_size + 256 ); + fs->buffer_end = fs->buffer_start + buf_size; + fs->buffer[0] = '\n'; + fs->buffer[1] = '\0'; + + //mode = cvGetErrMode(); + //cvSetErrMode( CV_ErrModeSilent ); + if( fs->fmt == CV_STORAGE_FORMAT_XML ) + icvXMLParse( fs ); + else + icvYMLParse( fs ); + //cvSetErrMode( mode ); + + // release resources that we do not need anymore + cvFree( &fs->buffer_start ); + fs->buffer = fs->buffer_end = 0; + } + fs->is_opened = true; + +_exit_: + if( fs ) + { + if( cvGetErrStatus() < 0 || (!fs->file && !fs->gzfile && !fs->outbuf && !fs->strbuf) ) + { + cvReleaseFileStorage( &fs ); + } + else if( !fs->write_mode ) + { + icvCloseFile(fs); + // we close the file since it's not needed anymore. But icvCloseFile() resets is_opened, + // which may be misleading. Since we restore the value of is_opened. + fs->is_opened = true; + } + } + + cvFree( &xml_buf ); + return fs; +} + + +CV_IMPL void +cvStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags, + const char* type_name, CvAttrList /*attributes*/ ) +{ + CV_CHECK_OUTPUT_FILE_STORAGE(fs); + fs->start_write_struct( fs, key, struct_flags, type_name ); +} + + +CV_IMPL void +cvEndWriteStruct( CvFileStorage* fs ) +{ + CV_CHECK_OUTPUT_FILE_STORAGE(fs); + fs->end_write_struct( fs ); +} + + +CV_IMPL void +cvWriteInt( CvFileStorage* fs, const char* key, int value ) +{ + CV_CHECK_OUTPUT_FILE_STORAGE(fs); + fs->write_int( fs, key, value ); +} + + +CV_IMPL void +cvWriteReal( CvFileStorage* fs, const char* key, double value ) +{ + CV_CHECK_OUTPUT_FILE_STORAGE(fs); + fs->write_real( fs, key, value ); +} + + +CV_IMPL void +cvWriteString( CvFileStorage* fs, const char* key, const char* value, int quote ) +{ + CV_CHECK_OUTPUT_FILE_STORAGE(fs); + fs->write_string( fs, key, value, quote ); +} + + +CV_IMPL void +cvWriteComment( CvFileStorage* fs, const char* comment, int eol_comment ) +{ + CV_CHECK_OUTPUT_FILE_STORAGE(fs); + fs->write_comment( fs, comment, eol_comment ); +} + + +CV_IMPL void +cvStartNextStream( CvFileStorage* fs ) +{ + CV_CHECK_OUTPUT_FILE_STORAGE(fs); + fs->start_next_stream( fs ); +} + + +static const char icvTypeSymbol[] = "ucwsifdr"; +#define CV_FS_MAX_FMT_PAIRS 128 + +static char* +icvEncodeFormat( int elem_type, char* dt ) +{ + sprintf( dt, "%d%c", CV_MAT_CN(elem_type), icvTypeSymbol[CV_MAT_DEPTH(elem_type)] ); + return dt + ( dt[2] == '\0' && dt[0] == '1' ); +} + +static int +icvDecodeFormat( const char* dt, int* fmt_pairs, int max_len ) +{ + int fmt_pair_count = 0; + int i = 0, k = 0, len = dt ? (int)strlen(dt) : 0; + + if( !dt || !len ) + return 0; + + assert( fmt_pairs != 0 && max_len > 0 ); + fmt_pairs[0] = 0; + max_len *= 2; + + for( ; k < len; k++ ) + { + char c = dt[k]; + + if( cv_isdigit(c) ) + { + int count = c - '0'; + if( cv_isdigit(dt[k+1]) ) + { + char* endptr = 0; + count = (int)strtol( dt+k, &endptr, 10 ); + k = (int)(endptr - dt) - 1; + } + + if( count <= 0 ) + CV_Error( CV_StsBadArg, "Invalid data type specification" ); + + fmt_pairs[i] = count; + } + else + { + const char* pos = strchr( icvTypeSymbol, c ); + if( !pos ) + CV_Error( CV_StsBadArg, "Invalid data type specification" ); + if( fmt_pairs[i] == 0 ) + fmt_pairs[i] = 1; + fmt_pairs[i+1] = (int)(pos - icvTypeSymbol); + if( i > 0 && fmt_pairs[i+1] == fmt_pairs[i-1] ) + fmt_pairs[i-2] += fmt_pairs[i]; + else + { + i += 2; + if( i >= max_len ) + CV_Error( CV_StsBadArg, "Too long data type specification" ); + } + fmt_pairs[i] = 0; + } + } + + fmt_pair_count = i/2; + return fmt_pair_count; +} + + +static int +icvCalcElemSize( const char* dt, int initial_size ) +{ + int size = 0; + int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count; + int comp_size; + + fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ); + fmt_pair_count *= 2; + for( i = 0, size = initial_size; i < fmt_pair_count; i += 2 ) + { + comp_size = CV_ELEM_SIZE(fmt_pairs[i+1]); + size = cvAlign( size, comp_size ); + size += comp_size * fmt_pairs[i]; + } + if( initial_size == 0 ) + { + comp_size = CV_ELEM_SIZE(fmt_pairs[1]); + size = cvAlign( size, comp_size ); + } + return size; +} + + +static int +icvDecodeSimpleFormat( const char* dt ) +{ + int elem_type = -1; + int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count; + + fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ); + if( fmt_pair_count != 1 || fmt_pairs[0] > 4 ) + CV_Error( CV_StsError, "Too complex format for the matrix" ); + + elem_type = CV_MAKETYPE( fmt_pairs[1], fmt_pairs[0] ); + + return elem_type; +} + + +CV_IMPL void +cvWriteRawData( CvFileStorage* fs, const void* _data, int len, const char* dt ) +{ + const char* data0 = (const char*)_data; + int offset = 0; + int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k, fmt_pair_count; + char buf[256] = ""; + + CV_CHECK_OUTPUT_FILE_STORAGE( fs ); + + if( len < 0 ) + CV_Error( CV_StsOutOfRange, "Negative number of elements" ); + + fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ); + + if( !len ) + return; + + if( !data0 ) + CV_Error( CV_StsNullPtr, "Null data pointer" ); + + if( fmt_pair_count == 1 ) + { + fmt_pairs[0] *= len; + len = 1; + } + + for(;len--;) + { + for( k = 0; k < fmt_pair_count; k++ ) + { + int i, count = fmt_pairs[k*2]; + int elem_type = fmt_pairs[k*2+1]; + int elem_size = CV_ELEM_SIZE(elem_type); + const char* data, *ptr; + + offset = cvAlign( offset, elem_size ); + data = data0 + offset; + + for( i = 0; i < count; i++ ) + { + switch( elem_type ) + { + case CV_8U: + ptr = icv_itoa( *(uchar*)data, buf, 10 ); + data++; + break; + case CV_8S: + ptr = icv_itoa( *(char*)data, buf, 10 ); + data++; + break; + case CV_16U: + ptr = icv_itoa( *(ushort*)data, buf, 10 ); + data += sizeof(ushort); + break; + case CV_16S: + ptr = icv_itoa( *(short*)data, buf, 10 ); + data += sizeof(short); + break; + case CV_32S: + ptr = icv_itoa( *(int*)data, buf, 10 ); + data += sizeof(int); + break; + case CV_32F: + ptr = icvFloatToString( buf, *(float*)data ); + data += sizeof(float); + break; + case CV_64F: + ptr = icvDoubleToString( buf, *(double*)data ); + data += sizeof(double); + break; + case CV_USRTYPE1: /* reference */ + ptr = icv_itoa( (int)*(size_t*)data, buf, 10 ); + data += sizeof(size_t); + break; + default: + assert(0); + return; + } + + if( fs->fmt == CV_STORAGE_FORMAT_XML ) + { + int buf_len = (int)strlen(ptr); + icvXMLWriteScalar( fs, 0, ptr, buf_len ); + } + else + icvYMLWrite( fs, 0, ptr ); + } + + offset = (int)(data - data0); + } + } +} + + +CV_IMPL void +cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src, CvSeqReader* reader ) +{ + int node_type; + CV_CHECK_FILE_STORAGE( fs ); + + if( !src || !reader ) + CV_Error( CV_StsNullPtr, "Null pointer to source file node or reader" ); + + node_type = CV_NODE_TYPE(src->tag); + if( node_type == CV_NODE_INT || node_type == CV_NODE_REAL ) + { + // emulate reading from 1-element sequence + reader->ptr = (schar*)src; + reader->block_max = reader->ptr + sizeof(*src)*2; + reader->block_min = reader->ptr; + reader->seq = 0; + } + else if( node_type == CV_NODE_SEQ ) + { + cvStartReadSeq( src->data.seq, reader, 0 ); + } + else if( node_type == CV_NODE_NONE ) + { + memset( reader, 0, sizeof(*reader) ); + } + else + CV_Error( CV_StsBadArg, "The file node should be a numerical scalar or a sequence" ); +} + + +CV_IMPL void +cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader, + int len, void* _data, const char* dt ) +{ + char* data0 = (char*)_data; + int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k = 0, fmt_pair_count; + int i = 0, offset = 0, count = 0; + + CV_CHECK_FILE_STORAGE( fs ); + + if( !reader || !data0 ) + CV_Error( CV_StsNullPtr, "Null pointer to reader or destination array" ); + + if( !reader->seq && len != 1 ) + CV_Error( CV_StsBadSize, "The readed sequence is a scalar, thus len must be 1" ); + + fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ); + + for(;;) + { + for( k = 0; k < fmt_pair_count; k++ ) + { + int elem_type = fmt_pairs[k*2+1]; + int elem_size = CV_ELEM_SIZE(elem_type); + char* data; + + count = fmt_pairs[k*2]; + offset = cvAlign( offset, elem_size ); + data = data0 + offset; + + for( i = 0; i < count; i++ ) + { + CvFileNode* node = (CvFileNode*)reader->ptr; + if( CV_NODE_IS_INT(node->tag) ) + { + int ival = node->data.i; + + switch( elem_type ) + { + case CV_8U: + *(uchar*)data = CV_CAST_8U(ival); + data++; + break; + case CV_8S: + *(char*)data = CV_CAST_8S(ival); + data++; + break; + case CV_16U: + *(ushort*)data = CV_CAST_16U(ival); + data += sizeof(ushort); + break; + case CV_16S: + *(short*)data = CV_CAST_16S(ival); + data += sizeof(short); + break; + case CV_32S: + *(int*)data = ival; + data += sizeof(int); + break; + case CV_32F: + *(float*)data = (float)ival; + data += sizeof(float); + break; + case CV_64F: + *(double*)data = (double)ival; + data += sizeof(double); + break; + case CV_USRTYPE1: /* reference */ + *(size_t*)data = ival; + data += sizeof(size_t); + break; + default: + assert(0); + return; + } + } + else if( CV_NODE_IS_REAL(node->tag) ) + { + double fval = node->data.f; + int ival; + + switch( elem_type ) + { + case CV_8U: + ival = cvRound(fval); + *(uchar*)data = CV_CAST_8U(ival); + data++; + break; + case CV_8S: + ival = cvRound(fval); + *(char*)data = CV_CAST_8S(ival); + data++; + break; + case CV_16U: + ival = cvRound(fval); + *(ushort*)data = CV_CAST_16U(ival); + data += sizeof(ushort); + break; + case CV_16S: + ival = cvRound(fval); + *(short*)data = CV_CAST_16S(ival); + data += sizeof(short); + break; + case CV_32S: + ival = cvRound(fval); + *(int*)data = ival; + data += sizeof(int); + break; + case CV_32F: + *(float*)data = (float)fval; + data += sizeof(float); + break; + case CV_64F: + *(double*)data = fval; + data += sizeof(double); + break; + case CV_USRTYPE1: /* reference */ + ival = cvRound(fval); + *(size_t*)data = ival; + data += sizeof(size_t); + break; + default: + assert(0); + return; + } + } + else + CV_Error( CV_StsError, + "The sequence element is not a numerical scalar" ); + + CV_NEXT_SEQ_ELEM( sizeof(CvFileNode), *reader ); + if( !--len ) + goto end_loop; + } + + offset = (int)(data - data0); + } + } + +end_loop: + if( i != count - 1 || k != fmt_pair_count - 1 ) + CV_Error( CV_StsBadSize, + "The sequence slice does not fit an integer number of records" ); + + if( !reader->seq ) + reader->ptr -= sizeof(CvFileNode); +} + + +CV_IMPL void +cvReadRawData( const CvFileStorage* fs, const CvFileNode* src, + void* data, const char* dt ) +{ + CvSeqReader reader; + + if( !src || !data ) + CV_Error( CV_StsNullPtr, "Null pointers to source file node or destination array" ); + + cvStartReadRawData( fs, src, &reader ); + cvReadRawDataSlice( fs, &reader, CV_NODE_IS_SEQ(src->tag) ? + src->data.seq->total : 1, data, dt ); +} + + +static void +icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node ); + +static void +icvWriteCollection( CvFileStorage* fs, const CvFileNode* node ) +{ + int i, total = node->data.seq->total; + int elem_size = node->data.seq->elem_size; + int is_map = CV_NODE_IS_MAP(node->tag); + CvSeqReader reader; + + cvStartReadSeq( node->data.seq, &reader, 0 ); + + for( i = 0; i < total; i++ ) + { + CvFileMapNode* elem = (CvFileMapNode*)reader.ptr; + if( !is_map || CV_IS_SET_ELEM(elem) ) + { + const char* name = is_map ? elem->key->str.ptr : 0; + icvWriteFileNode( fs, name, &elem->value ); + } + CV_NEXT_SEQ_ELEM( elem_size, reader ); + } +} + +static void +icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node ) +{ + switch( CV_NODE_TYPE(node->tag) ) + { + case CV_NODE_INT: + fs->write_int( fs, name, node->data.i ); + break; + case CV_NODE_REAL: + fs->write_real( fs, name, node->data.f ); + break; + case CV_NODE_STR: + fs->write_string( fs, name, node->data.str.ptr, 0 ); + break; + case CV_NODE_SEQ: + case CV_NODE_MAP: + fs->start_write_struct( fs, name, CV_NODE_TYPE(node->tag) + + (CV_NODE_SEQ_IS_SIMPLE(node->data.seq) ? CV_NODE_FLOW : 0), + node->info ? node->info->type_name : 0 ); + icvWriteCollection( fs, node ); + fs->end_write_struct( fs ); + break; + case CV_NODE_NONE: + fs->start_write_struct( fs, name, CV_NODE_SEQ, 0 ); + fs->end_write_struct( fs ); + break; + default: + CV_Error( CV_StsBadFlag, "Unknown type of file node" ); + } +} + + +CV_IMPL void +cvWriteFileNode( CvFileStorage* fs, const char* new_node_name, + const CvFileNode* node, int embed ) +{ + CvFileStorage* dst = 0; + CV_CHECK_OUTPUT_FILE_STORAGE(fs); + + if( !node ) + return; + + if( CV_NODE_IS_COLLECTION(node->tag) && embed ) + { + icvWriteCollection( fs, node ); + } + else + { + icvWriteFileNode( fs, new_node_name, node ); + } + /* + int i, stream_count; + stream_count = fs->roots->total; + for( i = 0; i < stream_count; i++ ) + { + CvFileNode* node = (CvFileNode*)cvGetSeqElem( fs->roots, i, 0 ); + icvDumpCollection( dst, node ); + if( i < stream_count - 1 ) + dst->start_next_stream( dst ); + }*/ + cvReleaseFileStorage( &dst ); +} + + +CV_IMPL const char* +cvGetFileNodeName( const CvFileNode* file_node ) +{ + return file_node && CV_NODE_HAS_NAME(file_node->tag) ? + ((CvFileMapNode*)file_node)->key->str.ptr : 0; +} + +/****************************************************************************************\ +* Reading/Writing etc. for standard types * +\****************************************************************************************/ + +/*#define CV_TYPE_NAME_MAT "opencv-matrix" +#define CV_TYPE_NAME_MATND "opencv-nd-matrix" +#define CV_TYPE_NAME_SPARSE_MAT "opencv-sparse-matrix" +#define CV_TYPE_NAME_IMAGE "opencv-image" +#define CV_TYPE_NAME_SEQ "opencv-sequence" +#define CV_TYPE_NAME_SEQ_TREE "opencv-sequence-tree" +#define CV_TYPE_NAME_GRAPH "opencv-graph"*/ + +/******************************* CvMat ******************************/ + +static int +icvIsMat( const void* ptr ) +{ + return CV_IS_MAT_HDR_Z(ptr); +} + +static void +icvWriteMat( CvFileStorage* fs, const char* name, + const void* struct_ptr, CvAttrList /*attr*/ ) +{ + const CvMat* mat = (const CvMat*)struct_ptr; + char dt[16]; + CvSize size; + int y; + + assert( CV_IS_MAT_HDR_Z(mat) ); + + cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MAT ); + cvWriteInt( fs, "rows", mat->rows ); + cvWriteInt( fs, "cols", mat->cols ); + cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 ); + cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW ); + + size = cvGetSize(mat); + if( size.height > 0 && size.width > 0 && mat->data.ptr ) + { + if( CV_IS_MAT_CONT(mat->type) ) + { + size.width *= size.height; + size.height = 1; + } + + for( y = 0; y < size.height; y++ ) + cvWriteRawData( fs, mat->data.ptr + (size_t)y*mat->step, size.width, dt ); + } + cvEndWriteStruct( fs ); + cvEndWriteStruct( fs ); +} + + +static int +icvFileNodeSeqLen( CvFileNode* node ) +{ + return CV_NODE_IS_COLLECTION(node->tag) ? node->data.seq->total : + CV_NODE_TYPE(node->tag) != CV_NODE_NONE; +} + + +static void* +icvReadMat( CvFileStorage* fs, CvFileNode* node ) +{ + void* ptr = 0; + CvMat* mat; + const char* dt; + CvFileNode* data; + int rows, cols, elem_type; + + rows = cvReadIntByName( fs, node, "rows", -1 ); + cols = cvReadIntByName( fs, node, "cols", -1 ); + dt = cvReadStringByName( fs, node, "dt", 0 ); + + if( rows < 0 || cols < 0 || !dt ) + CV_Error( CV_StsError, "Some of essential matrix attributes are absent" ); + + elem_type = icvDecodeSimpleFormat( dt ); + + data = cvGetFileNodeByName( fs, node, "data" ); + if( !data ) + CV_Error( CV_StsError, "The matrix data is not found in file storage" ); + + int nelems = icvFileNodeSeqLen( data ); + if( nelems > 0 && nelems != rows*cols*CV_MAT_CN(elem_type) ) + CV_Error( CV_StsUnmatchedSizes, + "The matrix size does not match to the number of stored elements" ); + + if( nelems > 0 ) + { + mat = cvCreateMat( rows, cols, elem_type ); + cvReadRawData( fs, data, mat->data.ptr, dt ); + } + else if( rows == 0 && cols == 0 ) + mat = cvCreateMatHeader( 0, 1, elem_type ); + else + mat = cvCreateMatHeader( rows, cols, elem_type ); + + ptr = mat; + return ptr; +} + + +/******************************* CvMatND ******************************/ + +static int +icvIsMatND( const void* ptr ) +{ + return CV_IS_MATND_HDR(ptr); +} + + +static void +icvWriteMatND( CvFileStorage* fs, const char* name, + const void* struct_ptr, CvAttrList /*attr*/ ) +{ + CvMatND* mat = (CvMatND*)struct_ptr; + CvMatND stub; + CvNArrayIterator iterator; + int dims, sizes[CV_MAX_DIM]; + char dt[16]; + + assert( CV_IS_MATND_HDR(mat) ); + + cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MATND ); + dims = cvGetDims( mat, sizes ); + cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW ); + cvWriteRawData( fs, sizes, dims, "i" ); + cvEndWriteStruct( fs ); + cvWriteString( fs, "dt", icvEncodeFormat( cvGetElemType(mat), dt ), 0 ); + cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW ); + + if( mat->dim[0].size > 0 && mat->data.ptr ) + { + cvInitNArrayIterator( 1, (CvArr**)&mat, 0, &stub, &iterator ); + + do + cvWriteRawData( fs, iterator.ptr[0], iterator.size.width, dt ); + while( cvNextNArraySlice( &iterator )); + } + cvEndWriteStruct( fs ); + cvEndWriteStruct( fs ); +} + + +static void* +icvReadMatND( CvFileStorage* fs, CvFileNode* node ) +{ + void* ptr = 0; + CvMatND* mat; + const char* dt; + CvFileNode* data; + CvFileNode* sizes_node; + int sizes[CV_MAX_DIM], dims, elem_type; + int i, total_size; + + sizes_node = cvGetFileNodeByName( fs, node, "sizes" ); + dt = cvReadStringByName( fs, node, "dt", 0 ); + + if( !sizes_node || !dt ) + CV_Error( CV_StsError, "Some of essential matrix attributes are absent" ); + + dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total : + CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1; + + if( dims <= 0 || dims > CV_MAX_DIM ) + CV_Error( CV_StsParseError, "Could not determine the matrix dimensionality" ); + + cvReadRawData( fs, sizes_node, sizes, "i" ); + elem_type = icvDecodeSimpleFormat( dt ); + + data = cvGetFileNodeByName( fs, node, "data" ); + if( !data ) + CV_Error( CV_StsError, "The matrix data is not found in file storage" ); + + + + for( total_size = CV_MAT_CN(elem_type), i = 0; i < dims; i++ ) + total_size *= sizes[i]; + + int nelems = icvFileNodeSeqLen( data ); + + if( nelems > 0 && nelems != total_size ) + CV_Error( CV_StsUnmatchedSizes, + "The matrix size does not match to the number of stored elements" ); + + if( nelems > 0 ) + { + mat = cvCreateMatND( dims, sizes, elem_type ); + cvReadRawData( fs, data, mat->data.ptr, dt ); + } + else + mat = cvCreateMatNDHeader( dims, sizes, elem_type ); + + ptr = mat; + return ptr; +} + + +/******************************* CvSparseMat ******************************/ + +static int +icvIsSparseMat( const void* ptr ) +{ + return CV_IS_SPARSE_MAT(ptr); +} + + +static int +icvSortIdxCmpFunc( const void* _a, const void* _b, void* userdata ) +{ + int i, dims = *(int*)userdata; + const int* a = *(const int**)_a; + const int* b = *(const int**)_b; + + for( i = 0; i < dims; i++ ) + { + int delta = a[i] - b[i]; + if( delta ) + return delta; + } + + return 0; +} + + +static void +icvWriteSparseMat( CvFileStorage* fs, const char* name, + const void* struct_ptr, CvAttrList /*attr*/ ) +{ + CvMemStorage* memstorage = 0; + const CvSparseMat* mat = (const CvSparseMat*)struct_ptr; + CvSparseMatIterator iterator; + CvSparseNode* node; + CvSeq* elements; + CvSeqReader reader; + int i, dims; + int *prev_idx = 0; + char dt[16]; + + assert( CV_IS_SPARSE_MAT(mat) ); + + memstorage = cvCreateMemStorage(); + + cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SPARSE_MAT ); + dims = cvGetDims( mat, 0 ); + + cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW ); + cvWriteRawData( fs, mat->size, dims, "i" ); + cvEndWriteStruct( fs ); + cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 ); + cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW ); + + elements = cvCreateSeq( CV_SEQ_ELTYPE_PTR, sizeof(CvSeq), sizeof(int*), memstorage ); + + node = cvInitSparseMatIterator( mat, &iterator ); + while( node ) + { + int* idx = CV_NODE_IDX( mat, node ); + cvSeqPush( elements, &idx ); + node = cvGetNextSparseNode( &iterator ); + } + + cvSeqSort( elements, icvSortIdxCmpFunc, &dims ); + cvStartReadSeq( elements, &reader, 0 ); + + for( i = 0; i < elements->total; i++ ) + { + int* idx; + void* val; + int k = 0; + + CV_READ_SEQ_ELEM( idx, reader ); + if( i > 0 ) + { + for( ; idx[k] == prev_idx[k]; k++ ) + assert( k < dims ); + if( k < dims - 1 ) + fs->write_int( fs, 0, k - dims + 1 ); + } + for( ; k < dims; k++ ) + fs->write_int( fs, 0, idx[k] ); + prev_idx = idx; + + node = (CvSparseNode*)((uchar*)idx - mat->idxoffset ); + val = CV_NODE_VAL( mat, node ); + + cvWriteRawData( fs, val, 1, dt ); + } + + cvEndWriteStruct( fs ); + cvEndWriteStruct( fs ); + cvReleaseMemStorage( &memstorage ); +} + + +static void* +icvReadSparseMat( CvFileStorage* fs, CvFileNode* node ) +{ + void* ptr = 0; + CvSparseMat* mat; + const char* dt; + CvFileNode* data; + CvFileNode* sizes_node; + CvSeqReader reader; + CvSeq* elements; + int sizes[CV_MAX_DIM_HEAP], dims, elem_type, cn; + int i; + + sizes_node = cvGetFileNodeByName( fs, node, "sizes" ); + dt = cvReadStringByName( fs, node, "dt", 0 ); + + if( !sizes_node || !dt ) + CV_Error( CV_StsError, "Some of essential matrix attributes are absent" ); + + dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total : + CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1; + + if( dims <= 0 || dims > CV_MAX_DIM_HEAP ) + CV_Error( CV_StsParseError, "Could not determine sparse matrix dimensionality" ); + + cvReadRawData( fs, sizes_node, sizes, "i" ); + elem_type = icvDecodeSimpleFormat( dt ); + + data = cvGetFileNodeByName( fs, node, "data" ); + if( !data || !CV_NODE_IS_SEQ(data->tag) ) + CV_Error( CV_StsError, "The matrix data is not found in file storage" ); + + mat = cvCreateSparseMat( dims, sizes, elem_type ); + + cn = CV_MAT_CN(elem_type); + int idx[CV_MAX_DIM_HEAP]; + elements = data->data.seq; + cvStartReadRawData( fs, data, &reader ); + + for( i = 0; i < elements->total; ) + { + CvFileNode* elem = (CvFileNode*)reader.ptr; + uchar* val; + int k; + if( !CV_NODE_IS_INT(elem->tag )) + CV_Error( CV_StsParseError, "Sparse matrix data is corrupted" ); + k = elem->data.i; + if( i > 0 && k >= 0 ) + idx[dims-1] = k; + else + { + if( i > 0 ) + k = dims + k - 1; + else + idx[0] = k, k = 1; + for( ; k < dims; k++ ) + { + CV_NEXT_SEQ_ELEM( elements->elem_size, reader ); + i++; + elem = (CvFileNode*)reader.ptr; + if( !CV_NODE_IS_INT(elem->tag ) || elem->data.i < 0 ) + CV_Error( CV_StsParseError, "Sparse matrix data is corrupted" ); + idx[k] = elem->data.i; + } + } + CV_NEXT_SEQ_ELEM( elements->elem_size, reader ); + i++; + val = cvPtrND( mat, idx, 0, 1, 0 ); + cvReadRawDataSlice( fs, &reader, cn, val, dt ); + i += cn; + } + + ptr = mat; + return ptr; +} + + +/******************************* IplImage ******************************/ + +static int +icvIsImage( const void* ptr ) +{ + return CV_IS_IMAGE_HDR(ptr); +} + +static void +icvWriteImage( CvFileStorage* fs, const char* name, + const void* struct_ptr, CvAttrList /*attr*/ ) +{ + const IplImage* image = (const IplImage*)struct_ptr; + char dt_buf[16], *dt; + CvSize size; + int y, depth; + + assert( CV_IS_IMAGE(image) ); + + if( image->dataOrder == IPL_DATA_ORDER_PLANE ) + CV_Error( CV_StsUnsupportedFormat, + "Images with planar data layout are not supported" ); + + cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_IMAGE ); + cvWriteInt( fs, "width", image->width ); + cvWriteInt( fs, "height", image->height ); + cvWriteString( fs, "origin", image->origin == IPL_ORIGIN_TL + ? "top-left" : "bottom-left", 0 ); + cvWriteString( fs, "layout", image->dataOrder == IPL_DATA_ORDER_PLANE + ? "planar" : "interleaved", 0 ); + if( image->roi ) + { + cvStartWriteStruct( fs, "roi", CV_NODE_MAP + CV_NODE_FLOW ); + cvWriteInt( fs, "x", image->roi->xOffset ); + cvWriteInt( fs, "y", image->roi->yOffset ); + cvWriteInt( fs, "width", image->roi->width ); + cvWriteInt( fs, "height", image->roi->height ); + cvWriteInt( fs, "coi", image->roi->coi ); + cvEndWriteStruct( fs ); + } + + depth = IPL2CV_DEPTH(image->depth); + sprintf( dt_buf, "%d%c", image->nChannels, icvTypeSymbol[depth] ); + dt = dt_buf + (dt_buf[2] == '\0' && dt_buf[0] == '1'); + cvWriteString( fs, "dt", dt, 0 ); + + size = cvSize(image->width, image->height); + if( size.width*image->nChannels*CV_ELEM_SIZE(depth) == image->widthStep ) + { + size.width *= size.height; + size.height = 1; + } + + cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW ); + for( y = 0; y < size.height; y++ ) + cvWriteRawData( fs, image->imageData + y*image->widthStep, size.width, dt ); + cvEndWriteStruct( fs ); + cvEndWriteStruct( fs ); +} + + +static void* +icvReadImage( CvFileStorage* fs, CvFileNode* node ) +{ + void* ptr = 0; + IplImage* image; + const char* dt; + CvFileNode* data; + CvFileNode* roi_node; + CvSeqReader reader; + CvRect roi; + int y, width, height, elem_type, coi, depth; + const char* origin, *data_order; + + width = cvReadIntByName( fs, node, "width", 0 ); + height = cvReadIntByName( fs, node, "height", 0 ); + dt = cvReadStringByName( fs, node, "dt", 0 ); + origin = cvReadStringByName( fs, node, "origin", 0 ); + + if( width == 0 || height == 0 || dt == 0 || origin == 0 ) + CV_Error( CV_StsError, "Some of essential image attributes are absent" ); + + elem_type = icvDecodeSimpleFormat( dt ); + data_order = cvReadStringByName( fs, node, "layout", "interleaved" ); + if( strcmp( data_order, "interleaved" ) != 0 ) + CV_Error( CV_StsError, "Only interleaved images can be read" ); + + data = cvGetFileNodeByName( fs, node, "data" ); + if( !data ) + CV_Error( CV_StsError, "The image data is not found in file storage" ); + + if( icvFileNodeSeqLen( data ) != width*height*CV_MAT_CN(elem_type) ) + CV_Error( CV_StsUnmatchedSizes, + "The matrix size does not match to the number of stored elements" ); + + depth = cvIplDepth(elem_type); + image = cvCreateImage( cvSize(width,height), depth, CV_MAT_CN(elem_type) ); + + roi_node = cvGetFileNodeByName( fs, node, "roi" ); + if( roi_node ) + { + roi.x = cvReadIntByName( fs, roi_node, "x", 0 ); + roi.y = cvReadIntByName( fs, roi_node, "y", 0 ); + roi.width = cvReadIntByName( fs, roi_node, "width", 0 ); + roi.height = cvReadIntByName( fs, roi_node, "height", 0 ); + coi = cvReadIntByName( fs, roi_node, "coi", 0 ); + + cvSetImageROI( image, roi ); + cvSetImageCOI( image, coi ); + } + + if( width*CV_ELEM_SIZE(elem_type) == image->widthStep ) + { + width *= height; + height = 1; + } + + width *= CV_MAT_CN(elem_type); + cvStartReadRawData( fs, data, &reader ); + for( y = 0; y < height; y++ ) + { + cvReadRawDataSlice( fs, &reader, width, + image->imageData + y*image->widthStep, dt ); + } + + ptr = image; + return ptr; +} + + +/******************************* CvSeq ******************************/ + +static int +icvIsSeq( const void* ptr ) +{ + return CV_IS_SEQ(ptr); +} + + +static void +icvReleaseSeq( void** ptr ) +{ + if( !ptr ) + CV_Error( CV_StsNullPtr, "NULL double pointer" ); + *ptr = 0; // it's impossible now to release seq, so just clear the pointer +} + + +static void* +icvCloneSeq( const void* ptr ) +{ + return cvSeqSlice( (CvSeq*)ptr, CV_WHOLE_SEQ, + 0 /* use the same storage as for the original sequence */, 1 ); +} + + +static void +icvWriteHeaderData( CvFileStorage* fs, const CvSeq* seq, + CvAttrList* attr, int initial_header_size ) +{ + char header_dt_buf[128]; + const char* header_dt = cvAttrValue( attr, "header_dt" ); + + if( header_dt ) + { + int dt_header_size; + dt_header_size = icvCalcElemSize( header_dt, initial_header_size ); + if( dt_header_size > seq->header_size ) + CV_Error( CV_StsUnmatchedSizes, + "The size of header calculated from \"header_dt\" is greater than header_size" ); + } + else if( seq->header_size > initial_header_size ) + { + if( CV_IS_SEQ(seq) && CV_IS_SEQ_POINT_SET(seq) && + seq->header_size == sizeof(CvPoint2DSeq) && + seq->elem_size == sizeof(int)*2 ) + { + CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq; + + cvStartWriteStruct( fs, "rect", CV_NODE_MAP + CV_NODE_FLOW ); + cvWriteInt( fs, "x", point_seq->rect.x ); + cvWriteInt( fs, "y", point_seq->rect.y ); + cvWriteInt( fs, "width", point_seq->rect.width ); + cvWriteInt( fs, "height", point_seq->rect.height ); + cvEndWriteStruct( fs ); + cvWriteInt( fs, "color", point_seq->color ); + } + else if( CV_IS_SEQ(seq) && CV_IS_SEQ_CHAIN(seq) && + CV_MAT_TYPE(seq->flags) == CV_8UC1 ) + { + CvChain* chain = (CvChain*)seq; + + cvStartWriteStruct( fs, "origin", CV_NODE_MAP + CV_NODE_FLOW ); + cvWriteInt( fs, "x", chain->origin.x ); + cvWriteInt( fs, "y", chain->origin.y ); + cvEndWriteStruct( fs ); + } + else + { + unsigned extra_size = seq->header_size - initial_header_size; + // a heuristic to provide nice defaults for sequences of int's & float's + if( extra_size % sizeof(int) == 0 ) + sprintf( header_dt_buf, "%ui", (unsigned)(extra_size/sizeof(int)) ); + else + sprintf( header_dt_buf, "%uu", extra_size ); + header_dt = header_dt_buf; + } + } + + if( header_dt ) + { + cvWriteString( fs, "header_dt", header_dt, 0 ); + cvStartWriteStruct( fs, "header_user_data", CV_NODE_SEQ + CV_NODE_FLOW ); + cvWriteRawData( fs, (uchar*)seq + sizeof(CvSeq), 1, header_dt ); + cvEndWriteStruct( fs ); + } +} + + +static char* +icvGetFormat( const CvSeq* seq, const char* dt_key, CvAttrList* attr, + int initial_elem_size, char* dt_buf ) +{ + char* dt = 0; + dt = (char*)cvAttrValue( attr, dt_key ); + + if( dt ) + { + int dt_elem_size; + dt_elem_size = icvCalcElemSize( dt, initial_elem_size ); + if( dt_elem_size != seq->elem_size ) + CV_Error( CV_StsUnmatchedSizes, + "The size of element calculated from \"dt\" and " + "the elem_size do not match" ); + } + else if( CV_MAT_TYPE(seq->flags) != 0 || seq->elem_size == 1 ) + { + if( CV_ELEM_SIZE(seq->flags) != seq->elem_size ) + CV_Error( CV_StsUnmatchedSizes, + "Size of sequence element (elem_size) is inconsistent with seq->flags" ); + dt = icvEncodeFormat( CV_MAT_TYPE(seq->flags), dt_buf ); + } + else if( seq->elem_size > initial_elem_size ) + { + unsigned extra_elem_size = seq->elem_size - initial_elem_size; + // a heuristic to provide nice defaults for sequences of int's & float's + if( extra_elem_size % sizeof(int) == 0 ) + sprintf( dt_buf, "%ui", (unsigned)(extra_elem_size/sizeof(int)) ); + else + sprintf( dt_buf, "%uu", extra_elem_size ); + dt = dt_buf; + } + + return dt; +} + + +static void +icvWriteSeq( CvFileStorage* fs, const char* name, + const void* struct_ptr, + CvAttrList attr, int level ) +{ + const CvSeq* seq = (CvSeq*)struct_ptr; + CvSeqBlock* block; + char buf[128]; + char dt_buf[128], *dt; + + assert( CV_IS_SEQ( seq )); + cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ ); + + if( level >= 0 ) + cvWriteInt( fs, "level", level ); + + dt = icvGetFormat( seq, "dt", &attr, 0, dt_buf ); + + strcpy(buf, ""); + if( CV_IS_SEQ_CLOSED(seq) ) + strcat(buf, " closed"); + if( CV_IS_SEQ_HOLE(seq) ) + strcat(buf, " hole"); + if( CV_IS_SEQ_CURVE(seq) ) + strcat(buf, " curve"); + if( CV_SEQ_ELTYPE(seq) == 0 && seq->elem_size != 1 ) + strcat(buf, " untyped"); + + cvWriteString( fs, "flags", buf + (buf[0] ? 1 : 0), 1 ); + + cvWriteInt( fs, "count", seq->total ); + + cvWriteString( fs, "dt", dt, 0 ); + + icvWriteHeaderData( fs, seq, &attr, sizeof(CvSeq) ); + cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW ); + + for( block = seq->first; block; block = block->next ) + { + cvWriteRawData( fs, block->data, block->count, dt ); + if( block == seq->first->prev ) + break; + } + cvEndWriteStruct( fs ); + cvEndWriteStruct( fs ); +} + + +static void +icvWriteSeqTree( CvFileStorage* fs, const char* name, + const void* struct_ptr, CvAttrList attr ) +{ + const CvSeq* seq = (CvSeq*)struct_ptr; + const char* recursive_value = cvAttrValue( &attr, "recursive" ); + int is_recursive = recursive_value && + strcmp(recursive_value,"0") != 0 && + strcmp(recursive_value,"false") != 0 && + strcmp(recursive_value,"False") != 0 && + strcmp(recursive_value,"FALSE") != 0; + + assert( CV_IS_SEQ( seq )); + + if( !is_recursive ) + { + icvWriteSeq( fs, name, seq, attr, -1 ); + } + else + { + CvTreeNodeIterator tree_iterator; + + cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ_TREE ); + cvStartWriteStruct( fs, "sequences", CV_NODE_SEQ ); + cvInitTreeNodeIterator( &tree_iterator, seq, INT_MAX ); + + for(;;) + { + if( !tree_iterator.node ) + break; + icvWriteSeq( fs, 0, tree_iterator.node, attr, tree_iterator.level ); + cvNextTreeNode( &tree_iterator ); + } + + cvEndWriteStruct( fs ); + cvEndWriteStruct( fs ); + } +} + + +static void* +icvReadSeq( CvFileStorage* fs, CvFileNode* node ) +{ + void* ptr = 0; + CvSeq* seq; + CvSeqBlock* block; + CvFileNode *data, *header_node, *rect_node, *origin_node; + CvSeqReader reader; + int total, flags; + int elem_size, header_size = sizeof(CvSeq); + int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count; + int items_per_elem = 0; + const char* flags_str; + const char* header_dt; + const char* dt; + char* endptr = 0; + + flags_str = cvReadStringByName( fs, node, "flags", 0 ); + total = cvReadIntByName( fs, node, "count", -1 ); + dt = cvReadStringByName( fs, node, "dt", 0 ); + + if( !flags_str || total == -1 || !dt ) + CV_Error( CV_StsError, "Some of essential sequence attributes are absent" ); + + flags = CV_SEQ_MAGIC_VAL; + + if( cv_isdigit(flags_str[0]) ) + { + const int OLD_SEQ_ELTYPE_BITS = 9; + const int OLD_SEQ_ELTYPE_MASK = (1 << OLD_SEQ_ELTYPE_BITS) - 1; + const int OLD_SEQ_KIND_BITS = 3; + const int OLD_SEQ_KIND_MASK = ((1 << OLD_SEQ_KIND_BITS) - 1) << OLD_SEQ_ELTYPE_BITS; + const int OLD_SEQ_KIND_CURVE = 1 << OLD_SEQ_ELTYPE_BITS; + const int OLD_SEQ_FLAG_SHIFT = OLD_SEQ_KIND_BITS + OLD_SEQ_ELTYPE_BITS; + const int OLD_SEQ_FLAG_CLOSED = 1 << OLD_SEQ_FLAG_SHIFT; + const int OLD_SEQ_FLAG_HOLE = 8 << OLD_SEQ_FLAG_SHIFT; + + int flags0 = (int)strtol( flags_str, &endptr, 16 ); + if( endptr == flags_str || (flags0 & CV_MAGIC_MASK) != CV_SEQ_MAGIC_VAL ) + CV_Error( CV_StsError, "The sequence flags are invalid" ); + if( (flags0 & OLD_SEQ_KIND_MASK) == OLD_SEQ_KIND_CURVE ) + flags |= CV_SEQ_KIND_CURVE; + if( flags0 & OLD_SEQ_FLAG_CLOSED ) + flags |= CV_SEQ_FLAG_CLOSED; + if( flags0 & OLD_SEQ_FLAG_HOLE ) + flags |= CV_SEQ_FLAG_HOLE; + flags |= flags0 & OLD_SEQ_ELTYPE_MASK; + } + else + { + if( strstr(flags_str, "curve") ) + flags |= CV_SEQ_KIND_CURVE; + if( strstr(flags_str, "closed") ) + flags |= CV_SEQ_FLAG_CLOSED; + if( strstr(flags_str, "hole") ) + flags |= CV_SEQ_FLAG_HOLE; + if( !strstr(flags_str, "untyped") ) + { + try + { + flags |= icvDecodeSimpleFormat(dt); + } + catch(...) + { + } + } + } + + header_dt = cvReadStringByName( fs, node, "header_dt", 0 ); + header_node = cvGetFileNodeByName( fs, node, "header_user_data" ); + + if( (header_dt != 0) ^ (header_node != 0) ) + CV_Error( CV_StsError, + "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" ); + + rect_node = cvGetFileNodeByName( fs, node, "rect" ); + origin_node = cvGetFileNodeByName( fs, node, "origin" ); + + if( (header_node != 0) + (rect_node != 0) + (origin_node != 0) > 1 ) + CV_Error( CV_StsError, "Only one of \"header_user_data\", \"rect\" and \"origin\" tags may occur" ); + + if( header_dt ) + { + header_size = icvCalcElemSize( header_dt, header_size ); + } + else if( rect_node ) + header_size = sizeof(CvPoint2DSeq); + else if( origin_node ) + header_size = sizeof(CvChain); + + elem_size = icvCalcElemSize( dt, 0 ); + seq = cvCreateSeq( flags, header_size, elem_size, fs->dststorage ); + + if( header_node ) + { + cvReadRawData( fs, header_node, (char*)seq + sizeof(CvSeq), header_dt ); + } + else if( rect_node ) + { + CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq; + point_seq->rect.x = cvReadIntByName( fs, rect_node, "x", 0 ); + point_seq->rect.y = cvReadIntByName( fs, rect_node, "y", 0 ); + point_seq->rect.width = cvReadIntByName( fs, rect_node, "width", 0 ); + point_seq->rect.height = cvReadIntByName( fs, rect_node, "height", 0 ); + point_seq->color = cvReadIntByName( fs, node, "color", 0 ); + } + else if( origin_node ) + { + CvChain* chain = (CvChain*)seq; + chain->origin.x = cvReadIntByName( fs, origin_node, "x", 0 ); + chain->origin.y = cvReadIntByName( fs, origin_node, "y", 0 ); + } + + cvSeqPushMulti( seq, 0, total, 0 ); + fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ); + fmt_pair_count *= 2; + for( i = 0; i < fmt_pair_count; i += 2 ) + items_per_elem += fmt_pairs[i]; + + data = cvGetFileNodeByName( fs, node, "data" ); + if( !data ) + CV_Error( CV_StsError, "The image data is not found in file storage" ); + + if( icvFileNodeSeqLen( data ) != total*items_per_elem ) + CV_Error( CV_StsError, "The number of stored elements does not match to \"count\"" ); + + cvStartReadRawData( fs, data, &reader ); + for( block = seq->first; block; block = block->next ) + { + int delta = block->count*items_per_elem; + cvReadRawDataSlice( fs, &reader, delta, block->data, dt ); + if( block == seq->first->prev ) + break; + } + + ptr = seq; + return ptr; +} + + +static void* +icvReadSeqTree( CvFileStorage* fs, CvFileNode* node ) +{ + void* ptr = 0; + CvFileNode *sequences_node = cvGetFileNodeByName( fs, node, "sequences" ); + CvSeq* sequences; + CvSeq* root = 0; + CvSeq* parent = 0; + CvSeq* prev_seq = 0; + CvSeqReader reader; + int i, total; + int prev_level = 0; + + if( !sequences_node || !CV_NODE_IS_SEQ(sequences_node->tag) ) + CV_Error( CV_StsParseError, + "opencv-sequence-tree instance should contain a field \"sequences\" that should be a sequence" ); + + sequences = sequences_node->data.seq; + total = sequences->total; + + cvStartReadSeq( sequences, &reader, 0 ); + for( i = 0; i < total; i++ ) + { + CvFileNode* elem = (CvFileNode*)reader.ptr; + CvSeq* seq; + int level; + seq = (CvSeq*)cvRead( fs, elem ); + level = cvReadIntByName( fs, elem, "level", -1 ); + if( level < 0 ) + CV_Error( CV_StsParseError, "All the sequence tree nodes should contain \"level\" field" ); + if( !root ) + root = seq; + if( level > prev_level ) + { + assert( level == prev_level + 1 ); + parent = prev_seq; + prev_seq = 0; + if( parent ) + parent->v_next = seq; + } + else if( level < prev_level ) + { + for( ; prev_level > level; prev_level-- ) + prev_seq = prev_seq->v_prev; + parent = prev_seq->v_prev; + } + seq->h_prev = prev_seq; + if( prev_seq ) + prev_seq->h_next = seq; + seq->v_prev = parent; + prev_seq = seq; + prev_level = level; + CV_NEXT_SEQ_ELEM( sequences->elem_size, reader ); + } + + ptr = root; + return ptr; +} + +/******************************* CvGraph ******************************/ + +static int +icvIsGraph( const void* ptr ) +{ + return CV_IS_GRAPH(ptr); +} + + +static void +icvReleaseGraph( void** ptr ) +{ + if( !ptr ) + CV_Error( CV_StsNullPtr, "NULL double pointer" ); + + *ptr = 0; // it's impossible now to release graph, so just clear the pointer +} + + +static void* +icvCloneGraph( const void* ptr ) +{ + return cvCloneGraph( (const CvGraph*)ptr, 0 ); +} + + +static void +icvWriteGraph( CvFileStorage* fs, const char* name, + const void* struct_ptr, CvAttrList attr ) +{ + int* flag_buf = 0; + char* write_buf = 0; + const CvGraph* graph = (const CvGraph*)struct_ptr; + CvSeqReader reader; + char buf[128]; + int i, k, vtx_count, edge_count; + char vtx_dt_buf[128], *vtx_dt; + char edge_dt_buf[128], *edge_dt; + int write_buf_size; + + assert( CV_IS_GRAPH(graph) ); + vtx_count = cvGraphGetVtxCount( graph ); + edge_count = cvGraphGetEdgeCount( graph ); + flag_buf = (int*)cvAlloc( vtx_count*sizeof(flag_buf[0])); + + // count vertices + cvStartReadSeq( (CvSeq*)graph, &reader ); + for( i = 0, k = 0; i < graph->total; i++ ) + { + if( CV_IS_SET_ELEM( reader.ptr )) + { + CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr; + flag_buf[k] = vtx->flags; + vtx->flags = k++; + } + CV_NEXT_SEQ_ELEM( graph->elem_size, reader ); + } + + // write header + cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_GRAPH ); + + cvWriteString(fs, "flags", CV_IS_GRAPH_ORIENTED(graph) ? "oriented" : "", 1); + + cvWriteInt( fs, "vertex_count", vtx_count ); + vtx_dt = icvGetFormat( (CvSeq*)graph, "vertex_dt", + &attr, sizeof(CvGraphVtx), vtx_dt_buf ); + if( vtx_dt ) + cvWriteString( fs, "vertex_dt", vtx_dt, 0 ); + + cvWriteInt( fs, "edge_count", edge_count ); + edge_dt = icvGetFormat( (CvSeq*)graph->edges, "edge_dt", + &attr, sizeof(CvGraphEdge), buf ); + sprintf( edge_dt_buf, "2if%s", edge_dt ? edge_dt : "" ); + edge_dt = edge_dt_buf; + cvWriteString( fs, "edge_dt", edge_dt, 0 ); + + icvWriteHeaderData( fs, (CvSeq*)graph, &attr, sizeof(CvGraph) ); + + write_buf_size = MAX( 3*graph->elem_size, 1 << 16 ); + write_buf_size = MAX( 3*graph->edges->elem_size, write_buf_size ); + write_buf = (char*)cvAlloc( write_buf_size ); + + // as vertices and edges are written in similar way, + // do it as a parametrized 2-iteration loop + for( k = 0; k < 2; k++ ) + { + const char* dt = k == 0 ? vtx_dt : edge_dt; + if( dt ) + { + CvSet* data = k == 0 ? (CvSet*)graph : graph->edges; + int elem_size = data->elem_size; + int write_elem_size = icvCalcElemSize( dt, 0 ); + char* src_ptr = write_buf; + int write_max = write_buf_size / write_elem_size, write_count = 0; + + // alignment of user part of the edge data following 2if + int edge_user_align = sizeof(float); + + if( k == 1 ) + { + int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count; + fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ); + if( fmt_pair_count > 2 && CV_ELEM_SIZE(fmt_pairs[2*2+1]) >= (int)sizeof(double)) + edge_user_align = sizeof(double); + } + + cvStartWriteStruct( fs, k == 0 ? "vertices" : "edges", + CV_NODE_SEQ + CV_NODE_FLOW ); + cvStartReadSeq( (CvSeq*)data, &reader ); + for( i = 0; i < data->total; i++ ) + { + if( CV_IS_SET_ELEM( reader.ptr )) + { + if( k == 0 ) // vertices + memcpy( src_ptr, reader.ptr + sizeof(CvGraphVtx), write_elem_size ); + else + { + CvGraphEdge* edge = (CvGraphEdge*)reader.ptr; + src_ptr = (char*)cvAlignPtr( src_ptr, sizeof(int) ); + ((int*)src_ptr)[0] = edge->vtx[0]->flags; + ((int*)src_ptr)[1] = edge->vtx[1]->flags; + *(float*)(src_ptr + sizeof(int)*2) = edge->weight; + if( elem_size > (int)sizeof(CvGraphEdge) ) + { + char* src_ptr2 = (char*)cvAlignPtr( src_ptr + 2*sizeof(int) + + sizeof(float), edge_user_align ); + memcpy( src_ptr2, edge + 1, elem_size - sizeof(CvGraphEdge) ); + } + } + src_ptr += write_elem_size; + if( ++write_count >= write_max ) + { + cvWriteRawData( fs, write_buf, write_count, dt ); + write_count = 0; + src_ptr = write_buf; + } + } + CV_NEXT_SEQ_ELEM( data->elem_size, reader ); + } + + if( write_count > 0 ) + cvWriteRawData( fs, write_buf, write_count, dt ); + cvEndWriteStruct( fs ); + } + } + + cvEndWriteStruct( fs ); + + // final stage. restore the graph flags + cvStartReadSeq( (CvSeq*)graph, &reader ); + vtx_count = 0; + for( i = 0; i < graph->total; i++ ) + { + if( CV_IS_SET_ELEM( reader.ptr )) + ((CvGraphVtx*)reader.ptr)->flags = flag_buf[vtx_count++]; + CV_NEXT_SEQ_ELEM( graph->elem_size, reader ); + } + + cvFree( &write_buf ); + cvFree( &flag_buf ); +} + + +static void* +icvReadGraph( CvFileStorage* fs, CvFileNode* node ) +{ + void* ptr = 0; + char* read_buf = 0; + CvGraphVtx** vtx_buf = 0; + CvGraph* graph; + CvFileNode *header_node, *vtx_node, *edge_node; + int flags, vtx_count, edge_count; + int vtx_size = sizeof(CvGraphVtx), edge_size, header_size = sizeof(CvGraph); + int src_vtx_size = 0, src_edge_size; + int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count; + int vtx_items_per_elem = 0, edge_items_per_elem = 0; + int edge_user_align = sizeof(float); + int read_buf_size; + int i, k; + const char* flags_str; + const char* header_dt; + const char* vtx_dt; + const char* edge_dt; + char* endptr = 0; + + flags_str = cvReadStringByName( fs, node, "flags", 0 ); + vtx_dt = cvReadStringByName( fs, node, "vertex_dt", 0 ); + edge_dt = cvReadStringByName( fs, node, "edge_dt", 0 ); + vtx_count = cvReadIntByName( fs, node, "vertex_count", -1 ); + edge_count = cvReadIntByName( fs, node, "edge_count", -1 ); + + if( !flags_str || vtx_count == -1 || edge_count == -1 || !edge_dt ) + CV_Error( CV_StsError, "Some of essential graph attributes are absent" ); + + flags = CV_SET_MAGIC_VAL + CV_GRAPH; + + if( isxdigit(flags_str[0]) ) + { + const int OLD_SEQ_ELTYPE_BITS = 9; + const int OLD_SEQ_KIND_BITS = 3; + const int OLD_SEQ_FLAG_SHIFT = OLD_SEQ_KIND_BITS + OLD_SEQ_ELTYPE_BITS; + const int OLD_GRAPH_FLAG_ORIENTED = 1 << OLD_SEQ_FLAG_SHIFT; + + int flags0 = (int)strtol( flags_str, &endptr, 16 ); + if( endptr == flags_str || (flags0 & CV_MAGIC_MASK) != CV_SET_MAGIC_VAL ) + CV_Error( CV_StsError, "The sequence flags are invalid" ); + if( flags0 & OLD_GRAPH_FLAG_ORIENTED ) + flags |= CV_GRAPH_FLAG_ORIENTED; + } + else + { + if( strstr(flags_str, "oriented") ) + flags |= CV_GRAPH_FLAG_ORIENTED; + } + + header_dt = cvReadStringByName( fs, node, "header_dt", 0 ); + header_node = cvGetFileNodeByName( fs, node, "header_user_data" ); + + if( (header_dt != 0) ^ (header_node != 0) ) + CV_Error( CV_StsError, + "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" ); + + if( header_dt ) + header_size = icvCalcElemSize( header_dt, header_size ); + + if( vtx_dt ) + { + src_vtx_size = icvCalcElemSize( vtx_dt, 0 ); + vtx_size = icvCalcElemSize( vtx_dt, vtx_size ); + fmt_pair_count = icvDecodeFormat( edge_dt, + fmt_pairs, CV_FS_MAX_FMT_PAIRS ); + fmt_pair_count *= 2; + for( i = 0; i < fmt_pair_count; i += 2 ) + vtx_items_per_elem += fmt_pairs[i]; + } + + { + char dst_edge_dt_buf[128]; + const char* dst_edge_dt = 0; + + fmt_pair_count = icvDecodeFormat( edge_dt, + fmt_pairs, CV_FS_MAX_FMT_PAIRS ); + if( fmt_pair_count < 2 || + fmt_pairs[0] != 2 || fmt_pairs[1] != CV_32S || + fmt_pairs[2] < 1 || fmt_pairs[3] != CV_32F ) + CV_Error( CV_StsBadArg, + "Graph edges should start with 2 integers and a float" ); + + // alignment of user part of the edge data following 2if + if( fmt_pair_count > 2 && CV_ELEM_SIZE(fmt_pairs[5]) >= (int)sizeof(double)) + edge_user_align = sizeof(double); + + fmt_pair_count *= 2; + for( i = 0; i < fmt_pair_count; i += 2 ) + edge_items_per_elem += fmt_pairs[i]; + + if( edge_dt[2] == 'f' || (edge_dt[2] == '1' && edge_dt[3] == 'f') ) + dst_edge_dt = edge_dt + 3 + cv_isdigit(edge_dt[2]); + else + { + int val = (int)strtol( edge_dt + 2, &endptr, 10 ); + sprintf( dst_edge_dt_buf, "%df%s", val-1, endptr ); + dst_edge_dt = dst_edge_dt_buf; + } + + edge_size = icvCalcElemSize( dst_edge_dt, sizeof(CvGraphEdge) ); + src_edge_size = icvCalcElemSize( edge_dt, 0 ); + } + + graph = cvCreateGraph( flags, header_size, vtx_size, edge_size, fs->dststorage ); + + if( header_node ) + cvReadRawData( fs, header_node, (char*)graph + sizeof(CvGraph), header_dt ); + + read_buf_size = MAX( src_vtx_size*3, 1 << 16 ); + read_buf_size = MAX( src_edge_size*3, read_buf_size ); + read_buf = (char*)cvAlloc( read_buf_size ); + vtx_buf = (CvGraphVtx**)cvAlloc( vtx_count * sizeof(vtx_buf[0]) ); + + vtx_node = cvGetFileNodeByName( fs, node, "vertices" ); + edge_node = cvGetFileNodeByName( fs, node, "edges" ); + if( !edge_node ) + CV_Error( CV_StsBadArg, "No edges data" ); + if( vtx_dt && !vtx_node ) + CV_Error( CV_StsBadArg, "No vertices data" ); + + // as vertices and edges are read in similar way, + // do it as a parametrized 2-iteration loop + for( k = 0; k < 2; k++ ) + { + const char* dt = k == 0 ? vtx_dt : edge_dt; + int elem_size = k == 0 ? vtx_size : edge_size; + int src_elem_size = k == 0 ? src_vtx_size : src_edge_size; + int items_per_elem = k == 0 ? vtx_items_per_elem : edge_items_per_elem; + int elem_count = k == 0 ? vtx_count : edge_count; + char* dst_ptr = read_buf; + int read_max = read_buf_size /MAX(src_elem_size, 1), read_count = 0; + CvSeqReader reader; + if(dt) + cvStartReadRawData( fs, k == 0 ? vtx_node : edge_node, &reader ); + + for( i = 0; i < elem_count; i++ ) + { + if( read_count == 0 && dt ) + { + int count = MIN( elem_count - i, read_max )*items_per_elem; + cvReadRawDataSlice( fs, &reader, count, read_buf, dt ); + read_count = count; + dst_ptr = read_buf; + } + + if( k == 0 ) + { + CvGraphVtx* vtx; + cvGraphAddVtx( graph, 0, &vtx ); + vtx_buf[i] = vtx; + if( dt ) + memcpy( vtx + 1, dst_ptr, src_elem_size ); + } + else + { + CvGraphEdge* edge = 0; + int vtx1 = ((int*)dst_ptr)[0]; + int vtx2 = ((int*)dst_ptr)[1]; + int result; + + if( (unsigned)vtx1 >= (unsigned)vtx_count || + (unsigned)vtx2 >= (unsigned)vtx_count ) + CV_Error( CV_StsOutOfRange, + "Some of stored vertex indices are out of range" ); + + result = cvGraphAddEdgeByPtr( graph, + vtx_buf[vtx1], vtx_buf[vtx2], 0, &edge ); + + if( result == 0 ) + CV_Error( CV_StsBadArg, "Duplicated edge has occured" ); + + edge->weight = *(float*)(dst_ptr + sizeof(int)*2); + if( elem_size > (int)sizeof(CvGraphEdge) ) + { + char* dst_ptr2 = (char*)cvAlignPtr( dst_ptr + sizeof(int)*2 + + sizeof(float), edge_user_align ); + memcpy( edge + 1, dst_ptr2, elem_size - sizeof(CvGraphEdge) ); + } + } + + dst_ptr += src_elem_size; + read_count--; + } + } + + ptr = graph; + cvFree( &read_buf ); + cvFree( &vtx_buf ); + + return ptr; +} + +/****************************************************************************************\ +* RTTI Functions * +\****************************************************************************************/ + +CvTypeInfo *CvType::first = 0, *CvType::last = 0; + +CvType::CvType( const char* type_name, + CvIsInstanceFunc is_instance, CvReleaseFunc release, + CvReadFunc read, CvWriteFunc write, CvCloneFunc clone ) +{ + CvTypeInfo _info; + _info.flags = 0; + _info.header_size = sizeof(_info); + _info.type_name = type_name; + _info.prev = _info.next = 0; + _info.is_instance = is_instance; + _info.release = release; + _info.clone = clone; + _info.read = read; + _info.write = write; + + cvRegisterType( &_info ); + info = first; +} + + +CvType::~CvType() +{ + cvUnregisterType( info->type_name ); +} + + +CvType seq_type( CV_TYPE_NAME_SEQ, icvIsSeq, icvReleaseSeq, icvReadSeq, + icvWriteSeqTree /* this is the entry point for + writing a single sequence too */, icvCloneSeq ); + +CvType seq_tree_type( CV_TYPE_NAME_SEQ_TREE, icvIsSeq, icvReleaseSeq, + icvReadSeqTree, icvWriteSeqTree, icvCloneSeq ); + +CvType seq_graph_type( CV_TYPE_NAME_GRAPH, icvIsGraph, icvReleaseGraph, + icvReadGraph, icvWriteGraph, icvCloneGraph ); + +CvType sparse_mat_type( CV_TYPE_NAME_SPARSE_MAT, icvIsSparseMat, + (CvReleaseFunc)cvReleaseSparseMat, icvReadSparseMat, + icvWriteSparseMat, (CvCloneFunc)cvCloneSparseMat ); + +CvType image_type( CV_TYPE_NAME_IMAGE, icvIsImage, (CvReleaseFunc)cvReleaseImage, + icvReadImage, icvWriteImage, (CvCloneFunc)cvCloneImage ); + +CvType mat_type( CV_TYPE_NAME_MAT, icvIsMat, (CvReleaseFunc)cvReleaseMat, + icvReadMat, icvWriteMat, (CvCloneFunc)cvCloneMat ); + +CvType matnd_type( CV_TYPE_NAME_MATND, icvIsMatND, (CvReleaseFunc)cvReleaseMatND, + icvReadMatND, icvWriteMatND, (CvCloneFunc)cvCloneMatND ); + +CV_IMPL void +cvRegisterType( const CvTypeInfo* _info ) +{ + CvTypeInfo* info = 0; + int i, len; + char c; + + //if( !CvType::first ) + // icvCreateStandardTypes(); + + if( !_info || _info->header_size != sizeof(CvTypeInfo) ) + CV_Error( CV_StsBadSize, "Invalid type info" ); + + if( !_info->is_instance || !_info->release || + !_info->read || !_info->write ) + CV_Error( CV_StsNullPtr, + "Some of required function pointers " + "(is_instance, release, read or write) are NULL"); + + c = _info->type_name[0]; + if( !cv_isalpha(c) && c != '_' ) + CV_Error( CV_StsBadArg, "Type name should start with a letter or _" ); + + len = (int)strlen(_info->type_name); + + for( i = 0; i < len; i++ ) + { + c = _info->type_name[i]; + if( !cv_isalnum(c) && c != '-' && c != '_' ) + CV_Error( CV_StsBadArg, + "Type name should contain only letters, digits, - and _" ); + } + + info = (CvTypeInfo*)malloc( sizeof(*info) + len + 1 ); + + *info = *_info; + info->type_name = (char*)(info + 1); + memcpy( (char*)info->type_name, _info->type_name, len + 1 ); + + info->flags = 0; + info->next = CvType::first; + info->prev = 0; + if( CvType::first ) + CvType::first->prev = info; + else + CvType::last = info; + CvType::first = info; +} + + +CV_IMPL void +cvUnregisterType( const char* type_name ) +{ + CvTypeInfo* info; + + info = cvFindType( type_name ); + if( info ) + { + if( info->prev ) + info->prev->next = info->next; + else + CvType::first = info->next; + + if( info->next ) + info->next->prev = info->prev; + else + CvType::last = info->prev; + + if( !CvType::first || !CvType::last ) + CvType::first = CvType::last = 0; + + free( info ); + } +} + + +CV_IMPL CvTypeInfo* +cvFirstType( void ) +{ + return CvType::first; +} + + +CV_IMPL CvTypeInfo* +cvFindType( const char* type_name ) +{ + CvTypeInfo* info = 0; + + if (type_name) + for( info = CvType::first; info != 0; info = info->next ) + if( strcmp( info->type_name, type_name ) == 0 ) + break; + + return info; +} + + +CV_IMPL CvTypeInfo* +cvTypeOf( const void* struct_ptr ) +{ + CvTypeInfo* info = 0; + + if( struct_ptr ) + { + for( info = CvType::first; info != 0; info = info->next ) + if( info->is_instance( struct_ptr )) + break; + } + + return info; +} + + +/* universal functions */ +CV_IMPL void +cvRelease( void** struct_ptr ) +{ + CvTypeInfo* info; + + if( !struct_ptr ) + CV_Error( CV_StsNullPtr, "NULL double pointer" ); + + if( *struct_ptr ) + { + info = cvTypeOf( *struct_ptr ); + if( !info ) + CV_Error( CV_StsError, "Unknown object type" ); + if( !info->release ) + CV_Error( CV_StsError, "release function pointer is NULL" ); + + info->release( struct_ptr ); + *struct_ptr = 0; + } +} + + +void* cvClone( const void* struct_ptr ) +{ + void* struct_copy = 0; + CvTypeInfo* info; + + if( !struct_ptr ) + CV_Error( CV_StsNullPtr, "NULL structure pointer" ); + + info = cvTypeOf( struct_ptr ); + if( !info ) + CV_Error( CV_StsError, "Unknown object type" ); + if( !info->clone ) + CV_Error( CV_StsError, "clone function pointer is NULL" ); + + struct_copy = info->clone( struct_ptr ); + return struct_copy; +} + + +/* reads matrix, image, sequence, graph etc. */ +CV_IMPL void* +cvRead( CvFileStorage* fs, CvFileNode* node, CvAttrList* list ) +{ + void* obj = 0; + CV_CHECK_FILE_STORAGE( fs ); + + if( !node ) + return 0; + + if( !CV_NODE_IS_USER(node->tag) || !node->info ) + CV_Error( CV_StsError, "The node does not represent a user object (unknown type?)" ); + + obj = node->info->read( fs, node ); + if( list ) + *list = cvAttrList(0,0); + + return obj; +} + + +/* writes matrix, image, sequence, graph etc. */ +CV_IMPL void +cvWrite( CvFileStorage* fs, const char* name, + const void* ptr, CvAttrList attributes ) +{ + CvTypeInfo* info; + + CV_CHECK_OUTPUT_FILE_STORAGE( fs ); + + if( !ptr ) + CV_Error( CV_StsNullPtr, "Null pointer to the written object" ); + + info = cvTypeOf( ptr ); + if( !info ) + CV_Error( CV_StsBadArg, "Unknown object" ); + + if( !info->write ) + CV_Error( CV_StsBadArg, "The object does not have write function" ); + + info->write( fs, name, ptr, attributes ); +} + + +/* simple API for reading/writing data */ +CV_IMPL void +cvSave( const char* filename, const void* struct_ptr, + const char* _name, const char* comment, CvAttrList attributes ) +{ + CvFileStorage* fs = 0; + + if( !struct_ptr ) + CV_Error( CV_StsNullPtr, "NULL object pointer" ); + + fs = cvOpenFileStorage( filename, 0, CV_STORAGE_WRITE ); + if( !fs ) + CV_Error( CV_StsError, "Could not open the file storage. Check the path and permissions" ); + + cv::string name = _name ? cv::string(_name) : cv::FileStorage::getDefaultObjectName(filename); + + if( comment ) + cvWriteComment( fs, comment, 0 ); + cvWrite( fs, name.c_str(), struct_ptr, attributes ); + cvReleaseFileStorage( &fs ); +} + +CV_IMPL void* +cvLoad( const char* filename, CvMemStorage* memstorage, + const char* name, const char** _real_name ) +{ + void* ptr = 0; + const char* real_name = 0; + cv::FileStorage fs(cvOpenFileStorage(filename, memstorage, CV_STORAGE_READ)); + + CvFileNode* node = 0; + + if( !fs.isOpened() ) + return 0; + + if( name ) + { + node = cvGetFileNodeByName( *fs, 0, name ); + } + else + { + int i, k; + for( k = 0; k < (*fs)->roots->total; k++ ) + { + CvSeq* seq; + CvSeqReader reader; + + node = (CvFileNode*)cvGetSeqElem( (*fs)->roots, k ); + if( !CV_NODE_IS_MAP( node->tag )) + return 0; + seq = node->data.seq; + node = 0; + + cvStartReadSeq( seq, &reader, 0 ); + + // find the first element in the map + for( i = 0; i < seq->total; i++ ) + { + if( CV_IS_SET_ELEM( reader.ptr )) + { + node = (CvFileNode*)reader.ptr; + goto stop_search; + } + CV_NEXT_SEQ_ELEM( seq->elem_size, reader ); + } + } + +stop_search: + ; + } + + if( !node ) + CV_Error( CV_StsObjectNotFound, "Could not find the/an object in file storage" ); + + real_name = cvGetFileNodeName( node ); + ptr = cvRead( *fs, node, 0 ); + + // sanity check + if( !memstorage && (CV_IS_SEQ( ptr ) || CV_IS_SET( ptr )) ) + CV_Error( CV_StsNullPtr, + "NULL memory storage is passed - the loaded dynamic structure can not be stored" ); + + if( cvGetErrStatus() < 0 ) + { + cvRelease( (void**)&ptr ); + real_name = 0; + } + + if( _real_name) + { + if (real_name) + { + *_real_name = (const char*)cvAlloc(strlen(real_name)); + memcpy((void*)*_real_name, real_name, strlen(real_name)); + } else { + *_real_name = 0; + } + } + + return ptr; +} + + +///////////////////////// new C++ interface for CvFileStorage /////////////////////////// + +namespace cv +{ + +static void getElemSize( const string& fmt, size_t& elemSize, size_t& cn ) +{ + const char* dt = fmt.c_str(); + cn = 1; + if( cv_isdigit(dt[0]) ) + { + cn = dt[0] - '0'; + dt++; + } + char c = dt[0]; + elemSize = cn*(c == 'u' || c == 'c' ? sizeof(uchar) : c == 'w' || c == 's' ? sizeof(ushort) : + c == 'i' ? sizeof(int) : c == 'f' ? sizeof(float) : c == 'd' ? sizeof(double) : + c == 'r' ? sizeof(void*) : (size_t)0); +} + +FileStorage::FileStorage() +{ + state = UNDEFINED; +} + +FileStorage::FileStorage(const string& filename, int flags, const string& encoding) +{ + state = UNDEFINED; + open( filename, flags, encoding ); +} + +FileStorage::FileStorage(CvFileStorage* _fs) +{ + fs = Ptr(_fs); + state = _fs ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED; +} + +FileStorage::~FileStorage() +{ + while( structs.size() > 0 ) + { + cvEndWriteStruct(fs); + structs.pop_back(); + } +} + +bool FileStorage::open(const string& filename, int flags, const string& encoding) +{ + release(); + fs = Ptr(cvOpenFileStorage( filename.c_str(), 0, flags, + !encoding.empty() ? encoding.c_str() : 0)); + bool ok = isOpened(); + state = ok ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED; + return ok; +} + +bool FileStorage::isOpened() const +{ + return !fs.empty() && fs.obj->is_opened; +} + +void FileStorage::release() +{ + fs.release(); + structs.clear(); + state = UNDEFINED; +} + +string FileStorage::releaseAndGetString() +{ + string buf; + if( fs.obj && fs.obj->outbuf ) + icvClose(fs.obj, &buf); + + release(); + return buf; +} + +FileNode FileStorage::root(int streamidx) const +{ + return isOpened() ? FileNode(fs, cvGetRootFileNode(fs, streamidx)) : FileNode(); +} + +FileStorage& operator << (FileStorage& fs, const string& str) +{ + enum { NAME_EXPECTED = FileStorage::NAME_EXPECTED, + VALUE_EXPECTED = FileStorage::VALUE_EXPECTED, + INSIDE_MAP = FileStorage::INSIDE_MAP }; + const char* _str = str.c_str(); + if( !fs.isOpened() || !_str ) + return fs; + if( *_str == '}' || *_str == ']' ) + { + if( fs.structs.empty() ) + CV_Error_( CV_StsError, ("Extra closing '%c'", *_str) ); + if( (*_str == ']' ? '[' : '{') != fs.structs.back() ) + CV_Error_( CV_StsError, + ("The closing '%c' does not match the opening '%c'", *_str, fs.structs.back())); + fs.structs.pop_back(); + fs.state = fs.structs.empty() || fs.structs.back() == '{' ? + INSIDE_MAP + NAME_EXPECTED : VALUE_EXPECTED; + cvEndWriteStruct( *fs ); + fs.elname = string(); + } + else if( fs.state == NAME_EXPECTED + INSIDE_MAP ) + { + if( !cv_isalpha(*_str) ) + CV_Error_( CV_StsError, ("Incorrect element name %s", _str) ); + fs.elname = str; + fs.state = VALUE_EXPECTED + INSIDE_MAP; + } + else if( (fs.state & 3) == VALUE_EXPECTED ) + { + if( *_str == '{' || *_str == '[' ) + { + fs.structs.push_back(*_str); + int flags = *_str++ == '{' ? CV_NODE_MAP : CV_NODE_SEQ; + fs.state = flags == CV_NODE_MAP ? INSIDE_MAP + + NAME_EXPECTED : VALUE_EXPECTED; + if( *_str == ':' ) + { + flags |= CV_NODE_FLOW; + _str++; + } + cvStartWriteStruct( *fs, fs.elname.size() > 0 ? fs.elname.c_str() : 0, + flags, *_str ? _str : 0 ); + fs.elname = string(); + } + else + { + write( fs, fs.elname, (_str[0] == '\\' && (_str[1] == '{' || _str[1] == '}' || + _str[1] == '[' || _str[1] == ']')) ? string(_str+1) : str ); + if( fs.state == INSIDE_MAP + VALUE_EXPECTED ) + fs.state = INSIDE_MAP + NAME_EXPECTED; + } + } + else + CV_Error( CV_StsError, "Invalid fs.state" ); + return fs; +} + + +void FileStorage::writeRaw( const string& fmt, const uchar* vec, size_t len ) +{ + if( !isOpened() ) + return; + size_t elemSize, cn; + getElemSize( fmt, elemSize, cn ); + CV_Assert( len % elemSize == 0 ); + cvWriteRawData( fs, vec, (int)(len/elemSize), fmt.c_str()); +} + + +void FileStorage::writeObj( const string& name, const void* obj ) +{ + if( !isOpened() ) + return; + cvWrite( fs, name.size() > 0 ? name.c_str() : 0, obj ); +} + + +FileNode FileStorage::operator[](const string& nodename) const +{ + return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename.c_str())); +} + +FileNode FileStorage::operator[](const char* nodename) const +{ + return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename)); +} + +FileNode FileNode::operator[](const string& nodename) const +{ + return FileNode(fs, cvGetFileNodeByName(fs, node, nodename.c_str())); +} + +FileNode FileNode::operator[](const char* nodename) const +{ + return FileNode(fs, cvGetFileNodeByName(fs, node, nodename)); +} + +FileNode FileNode::operator[](int i) const +{ + return isSeq() ? FileNode(fs, (CvFileNode*)cvGetSeqElem(node->data.seq, i)) : + i == 0 ? *this : FileNode(); +} + +string FileNode::name() const +{ + const char* str; + return !node || (str = cvGetFileNodeName(node)) == 0 ? string() : string(str); +} + +void* FileNode::readObj() const +{ + if( !fs || !node ) + return 0; + return cvRead( (CvFileStorage*)fs, (CvFileNode*)node ); +} + +FileNodeIterator::FileNodeIterator() +{ + fs = 0; + container = 0; + reader.ptr = 0; + remaining = 0; +} + +FileNodeIterator::FileNodeIterator(const CvFileStorage* _fs, + const CvFileNode* _node, size_t _ofs) +{ + if( _fs && _node && CV_NODE_TYPE(_node->tag) != CV_NODE_NONE ) + { + int node_type = _node->tag & FileNode::TYPE_MASK; + fs = _fs; + container = _node; + if( !(_node->tag & FileNode::USER) && (node_type == FileNode::SEQ || node_type == FileNode::MAP) ) + { + cvStartReadSeq( _node->data.seq, &reader ); + remaining = FileNode(_fs, _node).size(); + } + else + { + reader.ptr = (schar*)_node; + reader.seq = 0; + remaining = 1; + } + (*this) += (int)_ofs; + } + else + { + fs = 0; + container = 0; + reader.ptr = 0; + remaining = 0; + } +} + +FileNodeIterator::FileNodeIterator(const FileNodeIterator& it) +{ + fs = it.fs; + container = it.container; + reader = it.reader; + remaining = it.remaining; +} + +FileNodeIterator& FileNodeIterator::operator ++() +{ + if( remaining > 0 ) + { + if( reader.seq ) + CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader ); + remaining--; + } + return *this; +} + +FileNodeIterator FileNodeIterator::operator ++(int) +{ + FileNodeIterator it = *this; + ++(*this); + return it; +} + +FileNodeIterator& FileNodeIterator::operator --() +{ + if( remaining < FileNode(fs, container).size() ) + { + if( reader.seq ) + CV_PREV_SEQ_ELEM( reader.seq->elem_size, reader ); + remaining++; + } + return *this; +} + +FileNodeIterator FileNodeIterator::operator --(int) +{ + FileNodeIterator it = *this; + --(*this); + return it; +} + +FileNodeIterator& FileNodeIterator::operator += (int ofs) +{ + if( ofs == 0 ) + return *this; + if( ofs > 0 ) + ofs = std::min(ofs, (int)remaining); + else + { + size_t count = FileNode(fs, container).size(); + ofs = (int)(remaining - std::min(remaining - ofs, count)); + } + remaining -= ofs; + if( reader.seq ) + cvSetSeqReaderPos( &reader, ofs, 1 ); + return *this; +} + +FileNodeIterator& FileNodeIterator::operator -= (int ofs) +{ + return operator += (-ofs); +} + + +FileNodeIterator& FileNodeIterator::readRaw( const string& fmt, uchar* vec, size_t maxCount ) +{ + if( fs && container && remaining > 0 ) + { + size_t elem_size, cn; + getElemSize( fmt, elem_size, cn ); + CV_Assert( elem_size > 0 ); + size_t count = std::min(remaining, maxCount); + + if( reader.seq ) + { + cvReadRawDataSlice( fs, &reader, (int)count, vec, fmt.c_str() ); + remaining -= count*cn; + } + else + { + cvReadRawData( fs, container, vec, fmt.c_str() ); + remaining = 0; + } + } + return *this; +} + + +void write( FileStorage& fs, const string& name, int value ) +{ cvWriteInt( *fs, name.size() ? name.c_str() : 0, value ); } + +void write( FileStorage& fs, const string& name, float value ) +{ cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); } + +void write( FileStorage& fs, const string& name, double value ) +{ cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); } + +void write( FileStorage& fs, const string& name, const string& value ) +{ cvWriteString( *fs, name.size() ? name.c_str() : 0, value.c_str() ); } + +void writeScalar(FileStorage& fs, int value ) +{ cvWriteInt( *fs, 0, value ); } + +void writeScalar(FileStorage& fs, float value ) +{ cvWriteReal( *fs, 0, value ); } + +void writeScalar(FileStorage& fs, double value ) +{ cvWriteReal( *fs, 0, value ); } + +void writeScalar(FileStorage& fs, const string& value ) +{ cvWriteString( *fs, 0, value.c_str() ); } + + +void write( FileStorage& fs, const string& name, const Mat& value ) +{ + if( value.dims <= 2 ) + { + CvMat mat = value; + cvWrite( *fs, name.size() ? name.c_str() : 0, &mat ); + } + else + { + CvMatND mat = value; + cvWrite( *fs, name.size() ? name.c_str() : 0, &mat ); + } +} + +// TODO: the 4 functions below need to be implemented more efficiently +void write( FileStorage& fs, const string& name, const SparseMat& value ) +{ + Ptr mat = (CvSparseMat*)value; + cvWrite( *fs, name.size() ? name.c_str() : 0, mat ); +} + + +WriteStructContext::WriteStructContext(FileStorage& _fs, const string& name, + int flags, const string& typeName) : fs(&_fs) +{ + cvStartWriteStruct(**fs, !name.empty() ? name.c_str() : 0, flags, + !typeName.empty() ? typeName.c_str() : 0); +} + +WriteStructContext::~WriteStructContext() { cvEndWriteStruct(**fs); } + + +void read( const FileNode& node, Mat& mat, const Mat& default_mat ) +{ + if( node.empty() ) + { + default_mat.copyTo(mat); + return; + } + void* obj = cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node); + if(CV_IS_MAT_HDR_Z(obj)) + { + Mat((const CvMat*)obj).copyTo(mat); + cvReleaseMat((CvMat**)&obj); + } + else if(CV_IS_MATND_HDR(obj)) + { + Mat((const CvMatND*)obj).copyTo(mat); + cvReleaseMatND((CvMatND**)&obj); + } + else + { + cvRelease(&obj); + CV_Error(CV_StsBadArg, "Unknown array type"); + } +} + +void read( const FileNode& node, SparseMat& mat, const SparseMat& default_mat ) +{ + if( node.empty() ) + { + default_mat.copyTo(mat); + return; + } + Ptr m = (CvSparseMat*)cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node); + CV_Assert(CV_IS_SPARSE_MAT(m)); + SparseMat(m).copyTo(mat); +} + +} + +/* End of file. */ diff --git a/core/src/precomp.cpp b/core/src/precomp.cpp new file mode 100644 index 0000000..e540cc5 --- /dev/null +++ b/core/src/precomp.cpp @@ -0,0 +1,45 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +/* End of file. */ diff --git a/core/src/precomp.hpp b/core/src/precomp.hpp new file mode 100644 index 0000000..81b9d6e --- /dev/null +++ b/core/src/precomp.hpp @@ -0,0 +1,206 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_PRECOMP_H__ +#define __OPENCV_PRECOMP_H__ + +#ifdef HAVE_CVCONFIG_H +#include "cvconfig.h" +#endif + +#include "opencv2/core/core.hpp" +#include "opencv2/core/core_c.h" +#include "opencv2/core/internal.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_TEGRA_OPTIMIZATION +#include "opencv2/core/core_tegra.hpp" +#else +#define GET_OPTIMIZED(func) (func) +#endif + +namespace cv +{ + +// -128.f ... 255.f +extern const float g_8x32fTab[]; +#define CV_8TO32F(x) cv::g_8x32fTab[(x)+128] + +extern const ushort g_8x16uSqrTab[]; +#define CV_SQR_8U(x) cv::g_8x16uSqrTab[(x)+255] + +extern const char* g_HersheyGlyphs[]; + +extern const uchar g_Saturate8u[]; +#define CV_FAST_CAST_8U(t) (assert(-256 <= (t) && (t) <= 512), cv::g_Saturate8u[(t)+256]) +#define CV_MIN_8U(a,b) ((a) - CV_FAST_CAST_8U((a) - (b))) +#define CV_MAX_8U(a,b) ((a) + CV_FAST_CAST_8U((b) - (a))) + + +#if defined WIN32 || defined _WIN32 +void deleteThreadAllocData(); +void deleteThreadRNGData(); +#endif + +template struct OpAdd +{ + typedef T1 type1; + typedef T2 type2; + typedef T3 rtype; + T3 operator ()(T1 a, T2 b) const { return saturate_cast(a + b); } +}; + +template struct OpSub +{ + typedef T1 type1; + typedef T2 type2; + typedef T3 rtype; + T3 operator ()(T1 a, T2 b) const { return saturate_cast(a - b); } +}; + +template struct OpRSub +{ + typedef T1 type1; + typedef T2 type2; + typedef T3 rtype; + T3 operator ()(T1 a, T2 b) const { return saturate_cast(b - a); } +}; + +template struct OpMin +{ + typedef T type1; + typedef T type2; + typedef T rtype; + T operator ()(T a, T b) const { return std::min(a, b); } +}; + +template struct OpMax +{ + typedef T type1; + typedef T type2; + typedef T rtype; + T operator ()(T a, T b) const { return std::max(a, b); } +}; + +inline Size getContinuousSize( const Mat& m1, int widthScale=1 ) +{ + return m1.isContinuous() ? Size(m1.cols*m1.rows*widthScale, 1) : + Size(m1.cols*widthScale, m1.rows); +} + +inline Size getContinuousSize( const Mat& m1, const Mat& m2, int widthScale=1 ) +{ + return (m1.flags & m2.flags & Mat::CONTINUOUS_FLAG) != 0 ? + Size(m1.cols*m1.rows*widthScale, 1) : Size(m1.cols*widthScale, m1.rows); +} + +inline Size getContinuousSize( const Mat& m1, const Mat& m2, + const Mat& m3, int widthScale=1 ) +{ + return (m1.flags & m2.flags & m3.flags & Mat::CONTINUOUS_FLAG) != 0 ? + Size(m1.cols*m1.rows*widthScale, 1) : Size(m1.cols*widthScale, m1.rows); +} + +inline Size getContinuousSize( const Mat& m1, const Mat& m2, + const Mat& m3, const Mat& m4, + int widthScale=1 ) +{ + return (m1.flags & m2.flags & m3.flags & m4.flags & Mat::CONTINUOUS_FLAG) != 0 ? + Size(m1.cols*m1.rows*widthScale, 1) : Size(m1.cols*widthScale, m1.rows); +} + +inline Size getContinuousSize( const Mat& m1, const Mat& m2, + const Mat& m3, const Mat& m4, + const Mat& m5, int widthScale=1 ) +{ + return (m1.flags & m2.flags & m3.flags & m4.flags & m5.flags & Mat::CONTINUOUS_FLAG) != 0 ? + Size(m1.cols*m1.rows*widthScale, 1) : Size(m1.cols*widthScale, m1.rows); +} + +struct NoVec +{ + size_t operator()(const void*, const void*, void*, size_t) const { return 0; } +}; + +extern volatile bool USE_SSE2; +extern volatile bool USE_SSE4_2; +extern volatile bool USE_AVX; + +enum { BLOCK_SIZE = 1024 }; + +#ifdef HAVE_IPP +static inline IppiSize ippiSize(int width, int height) { IppiSize sz = { width, height}; return sz; } +static inline IppiSize ippiSize(Size _sz) { IppiSize sz = { _sz.width, _sz.height}; return sz; } +#endif + +#if defined HAVE_IPP && (IPP_VERSION_MAJOR >= 7) +#define ARITHM_USE_IPP 1 +#define IF_IPP(then_call, else_call) then_call +#else +#define ARITHM_USE_IPP 0 +#define IF_IPP(then_call, else_call) else_call +#endif + +inline bool checkScalar(const Mat& sc, int atype, int sckind, int akind) +{ + if( sc.dims > 2 || (sc.cols != 1 && sc.rows != 1) || !sc.isContinuous() ) + return false; + int cn = CV_MAT_CN(atype); + if( akind == _InputArray::MATX && sckind != _InputArray::MATX ) + return false; + return sc.size() == Size(1, 1) || sc.size() == Size(1, cn) || sc.size() == Size(cn, 1) || + (sc.size() == Size(1, 4) && sc.type() == CV_64F && cn <= 4); +} + +void convertAndUnrollScalar( const Mat& sc, int buftype, uchar* scbuf, size_t blocksize ); + +} + +#endif /*_CXCORE_INTERNAL_H_*/ diff --git a/core/src/rand.cpp b/core/src/rand.cpp new file mode 100644 index 0000000..04f0e14 --- /dev/null +++ b/core/src/rand.cpp @@ -0,0 +1,878 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +/* //////////////////////////////////////////////////////////////////// +// +// Filling CvMat/IplImage instances with random numbers +// +// */ + +#include "precomp.hpp" + +#if defined __SSE2__ || (defined _M_IX86_FP && 2 == _M_IX86_FP) +#include "emmintrin.h" +#endif + +namespace cv +{ + +///////////////////////////// Functions Declaration ////////////////////////////////////// + +/* + Multiply-with-carry generator is used here: + temp = ( A*X(n) + carry ) + X(n+1) = temp mod (2^32) + carry = temp / (2^32) +*/ + +#define RNG_NEXT(x) ((uint64)(unsigned)(x)*CV_RNG_COEFF + ((x) >> 32)) + +/***************************************************************************************\ +* Pseudo-Random Number Generators (PRNGs) * +\***************************************************************************************/ + +template static void +randBits_( T* arr, int len, uint64* state, const Vec2i* p, bool small_flag ) +{ + uint64 temp = *state; + int i; + + if( !small_flag ) + { + for( i = 0; i <= len - 4; i += 4 ) + { + int t0, t1; + + temp = RNG_NEXT(temp); + t0 = ((int)temp & p[i][0]) + p[i][1]; + temp = RNG_NEXT(temp); + t1 = ((int)temp & p[i+1][0]) + p[i+1][1]; + arr[i] = saturate_cast(t0); + arr[i+1] = saturate_cast(t1); + + temp = RNG_NEXT(temp); + t0 = ((int)temp & p[i+2][0]) + p[i+2][1]; + temp = RNG_NEXT(temp); + t1 = ((int)temp & p[i+3][0]) + p[i+3][1]; + arr[i+2] = saturate_cast(t0); + arr[i+3] = saturate_cast(t1); + } + } + else + { + for( i = 0; i <= len - 4; i += 4 ) + { + int t0, t1, t; + temp = RNG_NEXT(temp); + t = (int)temp; + t0 = (t & p[i][0]) + p[i][1]; + t1 = ((t >> 8) & p[i+1][0]) + p[i+1][1]; + arr[i] = saturate_cast(t0); + arr[i+1] = saturate_cast(t1); + + t0 = ((t >> 16) & p[i+2][0]) + p[i+2][1]; + t1 = ((t >> 24) & p[i+3][0]) + p[i+3][1]; + arr[i+2] = saturate_cast(t0); + arr[i+3] = saturate_cast(t1); + } + } + + for( ; i < len; i++ ) + { + int t0; + temp = RNG_NEXT(temp); + + t0 = ((int)temp & p[i][0]) + p[i][1]; + arr[i] = saturate_cast(t0); + } + + *state = temp; +} + +struct DivStruct +{ + unsigned d; + unsigned M; + int sh1, sh2; + int delta; +}; + +template static void +randi_( T* arr, int len, uint64* state, const DivStruct* p ) +{ + uint64 temp = *state; + int i = 0; + unsigned t0, t1, v0, v1; + + for( i = 0; i <= len - 4; i += 4 ) + { + temp = RNG_NEXT(temp); + t0 = (unsigned)temp; + temp = RNG_NEXT(temp); + t1 = (unsigned)temp; + v0 = (unsigned)(((uint64)t0 * p[i].M) >> 32); + v1 = (unsigned)(((uint64)t1 * p[i+1].M) >> 32); + v0 = (v0 + ((t0 - v0) >> p[i].sh1)) >> p[i].sh2; + v1 = (v1 + ((t1 - v1) >> p[i+1].sh1)) >> p[i+1].sh2; + v0 = t0 - v0*p[i].d + p[i].delta; + v1 = t1 - v1*p[i+1].d + p[i+1].delta; + arr[i] = saturate_cast((int)v0); + arr[i+1] = saturate_cast((int)v1); + + temp = RNG_NEXT(temp); + t0 = (unsigned)temp; + temp = RNG_NEXT(temp); + t1 = (unsigned)temp; + v0 = (unsigned)(((uint64)t0 * p[i+2].M) >> 32); + v1 = (unsigned)(((uint64)t1 * p[i+3].M) >> 32); + v0 = (v0 + ((t0 - v0) >> p[i+2].sh1)) >> p[i+2].sh2; + v1 = (v1 + ((t1 - v1) >> p[i+3].sh1)) >> p[i+3].sh2; + v0 = t0 - v0*p[i+2].d + p[i+2].delta; + v1 = t1 - v1*p[i+3].d + p[i+3].delta; + arr[i+2] = saturate_cast((int)v0); + arr[i+3] = saturate_cast((int)v1); + } + + for( ; i < len; i++ ) + { + temp = RNG_NEXT(temp); + t0 = (unsigned)temp; + v0 = (unsigned)(((uint64)t0 * p[i].M) >> 32); + v0 = (v0 + ((t0 - v0) >> p[i].sh1)) >> p[i].sh2; + v0 = t0 - v0*p[i].d + p[i].delta; + arr[i] = saturate_cast((int)v0); + } + + *state = temp; +} + + +#define DEF_RANDI_FUNC(suffix, type) \ +static void randBits_##suffix(type* arr, int len, uint64* state, \ + const Vec2i* p, bool small_flag) \ +{ randBits_(arr, len, state, p, small_flag); } \ +\ +static void randi_##suffix(type* arr, int len, uint64* state, \ + const DivStruct* p, bool ) \ +{ randi_(arr, len, state, p); } + +DEF_RANDI_FUNC(8u, uchar) +DEF_RANDI_FUNC(8s, schar) +DEF_RANDI_FUNC(16u, ushort) +DEF_RANDI_FUNC(16s, short) +DEF_RANDI_FUNC(32s, int) + +static void randf_32f( float* arr, int len, uint64* state, const Vec2f* p, bool ) +{ + uint64 temp = *state; + int i = 0; + + for( ; i <= len - 4; i += 4 ) + { + float f[4]; + f[0] = (float)(int)(temp = RNG_NEXT(temp)); + f[1] = (float)(int)(temp = RNG_NEXT(temp)); + f[2] = (float)(int)(temp = RNG_NEXT(temp)); + f[3] = (float)(int)(temp = RNG_NEXT(temp)); + + // handwritten SSE is required not for performance but for numerical stability! + // both 32-bit gcc and MSVC compilers trend to generate double precision SSE + // while 64-bit compilers generate single precision SIMD instructions + // so manual vectorisation forces all compilers to the single precision +#if defined __SSE2__ || (defined _M_IX86_FP && 2 == _M_IX86_FP) + __m128 q0 = _mm_loadu_ps((const float*)(p + i)); + __m128 q1 = _mm_loadu_ps((const float*)(p + i + 2)); + + __m128 q01l = _mm_unpacklo_ps(q0, q1); + __m128 q01h = _mm_unpackhi_ps(q0, q1); + + __m128 p0 = _mm_unpacklo_ps(q01l, q01h); + __m128 p1 = _mm_unpackhi_ps(q01l, q01h); + + _mm_storeu_ps(arr + i, _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(f), p0), p1)); +#else + arr[i+0] = f[0]*p[i+0][0] + p[i+0][1]; + arr[i+1] = f[1]*p[i+1][0] + p[i+1][1]; + arr[i+2] = f[2]*p[i+2][0] + p[i+2][1]; + arr[i+3] = f[3]*p[i+3][0] + p[i+3][1]; +#endif + } + + for( ; i < len; i++ ) + { + temp = RNG_NEXT(temp); +#if defined __SSE2__ || (defined _M_IX86_FP && 2 == _M_IX86_FP) + _mm_store_ss(arr + i, _mm_add_ss( + _mm_mul_ss(_mm_set_ss((float)(int)temp), _mm_set_ss(p[i][0])), + _mm_set_ss(p[i][1])) + ); +#else + arr[i] = (int)temp*p[i][0] + p[i][1]; +#endif + } + + *state = temp; +} + + +static void +randf_64f( double* arr, int len, uint64* state, const Vec2d* p, bool ) +{ + uint64 temp = *state; + int64 v = 0; + int i; + + for( i = 0; i <= len - 4; i += 4 ) + { + double f0, f1; + + temp = RNG_NEXT(temp); + v = (temp >> 32)|(temp << 32); + f0 = v*p[i][0] + p[i][1]; + temp = RNG_NEXT(temp); + v = (temp >> 32)|(temp << 32); + f1 = v*p[i+1][0] + p[i+1][1]; + arr[i] = f0; arr[i+1] = f1; + + temp = RNG_NEXT(temp); + v = (temp >> 32)|(temp << 32); + f0 = v*p[i+2][0] + p[i+2][1]; + temp = RNG_NEXT(temp); + v = (temp >> 32)|(temp << 32); + f1 = v*p[i+3][0] + p[i+3][1]; + arr[i+2] = f0; arr[i+3] = f1; + } + + for( ; i < len; i++ ) + { + temp = RNG_NEXT(temp); + v = (temp >> 32)|(temp << 32); + arr[i] = v*p[i][0] + p[i][1]; + } + + *state = temp; +} + +typedef void (*RandFunc)(uchar* arr, int len, uint64* state, const void* p, bool small_flag); + + +static RandFunc randTab[][8] = +{ + { + (RandFunc)randi_8u, (RandFunc)randi_8s, (RandFunc)randi_16u, (RandFunc)randi_16s, + (RandFunc)randi_32s, (RandFunc)randf_32f, (RandFunc)randf_64f, 0 + }, + { + (RandFunc)randBits_8u, (RandFunc)randBits_8s, (RandFunc)randBits_16u, (RandFunc)randBits_16s, + (RandFunc)randBits_32s, 0, 0, 0 + } +}; + +/* + The code below implements the algorithm described in + "The Ziggurat Method for Generating Random Variables" + by Marsaglia and Tsang, Journal of Statistical Software. +*/ +static void +randn_0_1_32f( float* arr, int len, uint64* state ) +{ + const float r = 3.442620f; // The start of the right tail + const float rng_flt = 2.3283064365386962890625e-10f; // 2^-32 + static unsigned kn[128]; + static float wn[128], fn[128]; + uint64 temp = *state; + static bool initialized=false; + int i; + + if( !initialized ) + { + const double m1 = 2147483648.0; + double dn = 3.442619855899, tn = dn, vn = 9.91256303526217e-3; + + // Set up the tables + double q = vn/std::exp(-.5*dn*dn); + kn[0] = (unsigned)((dn/q)*m1); + kn[1] = 0; + + wn[0] = (float)(q/m1); + wn[127] = (float)(dn/m1); + + fn[0] = 1.f; + fn[127] = (float)std::exp(-.5*dn*dn); + + for(i=126;i>=1;i--) + { + dn = std::sqrt(-2.*std::log(vn/dn+std::exp(-.5*dn*dn))); + kn[i+1] = (unsigned)((dn/tn)*m1); + tn = dn; + fn[i] = (float)std::exp(-.5*dn*dn); + wn[i] = (float)(dn/m1); + } + initialized = true; + } + + for( i = 0; i < len; i++ ) + { + float x, y; + for(;;) + { + int hz = (int)temp; + temp = RNG_NEXT(temp); + int iz = hz & 127; + x = hz*wn[iz]; + if( (unsigned)std::abs(hz) < kn[iz] ) + break; + if( iz == 0) // iz==0, handles the base strip + { + do + { + x = (unsigned)temp*rng_flt; + temp = RNG_NEXT(temp); + y = (unsigned)temp*rng_flt; + temp = RNG_NEXT(temp); + x = (float)(-std::log(x+FLT_MIN)*0.2904764); + y = (float)-std::log(y+FLT_MIN); + } // .2904764 is 1/r + while( y + y < x*x ); + x = hz > 0 ? r + x : -r - x; + break; + } + // iz > 0, handle the wedges of other strips + y = (unsigned)temp*rng_flt; + temp = RNG_NEXT(temp); + if( fn[iz] + y*(fn[iz - 1] - fn[iz]) < std::exp(-.5*x*x) ) + break; + } + arr[i] = x; + } + *state = temp; +} + + +double RNG::gaussian(double sigma) +{ + float temp; + randn_0_1_32f( &temp, 1, &state ); + return temp*sigma; +} + + +template static void +randnScale_( const float* src, T* dst, int len, int cn, const PT* mean, const PT* stddev, bool stdmtx ) +{ + int i, j, k; + if( !stdmtx ) + { + if( cn == 1 ) + { + PT b = mean[0], a = stddev[0]; + for( i = 0; i < len; i++ ) + dst[i] = saturate_cast(src[i]*a + b); + } + else + { + for( i = 0; i < len; i++, src += cn, dst += cn ) + for( k = 0; k < cn; k++ ) + dst[k] = saturate_cast(src[k]*stddev[k] + mean[k]); + } + } + else + { + for( i = 0; i < len; i++, src += cn, dst += cn ) + { + for( j = 0; j < cn; j++ ) + { + PT s = mean[j]; + for( k = 0; k < cn; k++ ) + s += src[k]*stddev[j*cn + k]; + dst[j] = saturate_cast(s); + } + } + } +} + +static void randnScale_8u( const float* src, uchar* dst, int len, int cn, + const float* mean, const float* stddev, bool stdmtx ) +{ randnScale_(src, dst, len, cn, mean, stddev, stdmtx); } + +static void randnScale_8s( const float* src, schar* dst, int len, int cn, + const float* mean, const float* stddev, bool stdmtx ) +{ randnScale_(src, dst, len, cn, mean, stddev, stdmtx); } + +static void randnScale_16u( const float* src, ushort* dst, int len, int cn, + const float* mean, const float* stddev, bool stdmtx ) +{ randnScale_(src, dst, len, cn, mean, stddev, stdmtx); } + +static void randnScale_16s( const float* src, short* dst, int len, int cn, + const float* mean, const float* stddev, bool stdmtx ) +{ randnScale_(src, dst, len, cn, mean, stddev, stdmtx); } + +static void randnScale_32s( const float* src, int* dst, int len, int cn, + const float* mean, const float* stddev, bool stdmtx ) +{ randnScale_(src, dst, len, cn, mean, stddev, stdmtx); } + +static void randnScale_32f( const float* src, float* dst, int len, int cn, + const float* mean, const float* stddev, bool stdmtx ) +{ randnScale_(src, dst, len, cn, mean, stddev, stdmtx); } + +static void randnScale_64f( const float* src, double* dst, int len, int cn, + const double* mean, const double* stddev, bool stdmtx ) +{ randnScale_(src, dst, len, cn, mean, stddev, stdmtx); } + +typedef void (*RandnScaleFunc)(const float* src, uchar* dst, int len, int cn, + const uchar*, const uchar*, bool); + +static RandnScaleFunc randnScaleTab[] = +{ + (RandnScaleFunc)randnScale_8u, (RandnScaleFunc)randnScale_8s, (RandnScaleFunc)randnScale_16u, + (RandnScaleFunc)randnScale_16s, (RandnScaleFunc)randnScale_32s, (RandnScaleFunc)randnScale_32f, + (RandnScaleFunc)randnScale_64f, 0 +}; + +void RNG::fill( InputOutputArray _mat, int disttype, + InputArray _param1arg, InputArray _param2arg, bool saturateRange ) +{ + Mat mat = _mat.getMat(), _param1 = _param1arg.getMat(), _param2 = _param2arg.getMat(); + int depth = mat.depth(), cn = mat.channels(); + AutoBuffer _parambuf; + int j, k, fast_int_mode = 0, smallFlag = 1; + RandFunc func = 0; + RandnScaleFunc scaleFunc = 0; + + CV_Assert(_param1.channels() == 1 && (_param1.rows == 1 || _param1.cols == 1) && + (_param1.rows + _param1.cols - 1 == cn || _param1.rows + _param1.cols - 1 == 1 || + (_param1.size() == Size(1, 4) && _param1.type() == CV_64F && cn <= 4))); + CV_Assert( _param2.channels() == 1 && + (((_param2.rows == 1 || _param2.cols == 1) && + (_param2.rows + _param2.cols - 1 == cn || _param2.rows + _param2.cols - 1 == 1 || + (_param1.size() == Size(1, 4) && _param1.type() == CV_64F && cn <= 4))) || + (_param2.rows == cn && _param2.cols == cn && disttype == NORMAL))); + + Vec2i* ip = 0; + Vec2d* dp = 0; + Vec2f* fp = 0; + DivStruct* ds = 0; + uchar* mean = 0; + uchar* stddev = 0; + bool stdmtx = false; + int n1 = (int)_param1.total(); + int n2 = (int)_param2.total(); + + if( disttype == UNIFORM ) + { + _parambuf.allocate(cn*8 + n1 + n2); + double* parambuf = _parambuf; + double* p1 = (double*)_param1.data; + double* p2 = (double*)_param2.data; + + if( !_param1.isContinuous() || _param1.type() != CV_64F || n1 != cn ) + { + Mat tmp(_param1.size(), CV_64F, parambuf); + _param1.convertTo(tmp, CV_64F); + p1 = parambuf; + if( n1 < cn ) + for( j = n1; j < cn; j++ ) + p1[j] = p1[j-n1]; + } + + if( !_param2.isContinuous() || _param2.type() != CV_64F || n2 != cn ) + { + Mat tmp(_param2.size(), CV_64F, parambuf + cn); + _param2.convertTo(tmp, CV_64F); + p2 = parambuf + cn; + if( n2 < cn ) + for( j = n2; j < cn; j++ ) + p2[j] = p2[j-n2]; + } + + if( depth <= CV_32S ) + { + ip = (Vec2i*)(parambuf + cn*2); + for( j = 0, fast_int_mode = 1; j < cn; j++ ) + { + double a = min(p1[j], p2[j]); + double b = max(p1[j], p2[j]); + if( saturateRange ) + { + a = max(a, depth == CV_8U || depth == CV_16U ? 0. : + depth == CV_8S ? -128. : depth == CV_16S ? -32768. : (double)INT_MIN); + b = min(b, depth == CV_8U ? 256. : depth == CV_16U ? 65536. : + depth == CV_8S ? 128. : depth == CV_16S ? 32768. : (double)INT_MAX); + } + ip[j][1] = cvCeil(a); + int idiff = ip[j][0] = cvFloor(b) - ip[j][1] - 1; + double diff = b - a; + + fast_int_mode &= diff <= 4294967296. && (idiff & (idiff+1)) == 0; + if( fast_int_mode ) + smallFlag &= idiff <= 255; + else + { + if( diff > INT_MAX ) + ip[j][0] = INT_MAX; + if( a < INT_MIN/2 ) + ip[j][1] = INT_MIN/2; + } + } + + if( !fast_int_mode ) + { + ds = (DivStruct*)(ip + cn); + for( j = 0; j < cn; j++ ) + { + ds[j].delta = ip[j][1]; + unsigned d = ds[j].d = (unsigned)(ip[j][0]+1); + int l = 0; + while(((uint64)1 << l) < d) + l++; + ds[j].M = (unsigned)(((uint64)1 << 32)*(((uint64)1 << l) - d)/d) + 1; + ds[j].sh1 = min(l, 1); + ds[j].sh2 = max(l - 1, 0); + } + } + + func = randTab[fast_int_mode][depth]; + } + else + { + double scale = depth == CV_64F ? + 5.4210108624275221700372640043497e-20 : // 2**-64 + 2.3283064365386962890625e-10; // 2**-32 + double maxdiff = saturateRange ? (double)FLT_MAX : DBL_MAX; + + // for each channel i compute such dparam[0][i] & dparam[1][i], + // so that a signed 32/64-bit integer X is transformed to + // the range [param1.val[i], param2.val[i]) using + // dparam[1][i]*X + dparam[0][i] + if( depth == CV_32F ) + { + fp = (Vec2f*)(parambuf + cn*2); + for( j = 0; j < cn; j++ ) + { + fp[j][0] = (float)(std::min(maxdiff, p2[j] - p1[j])*scale); + fp[j][1] = (float)((p2[j] + p1[j])*0.5); + } + } + else + { + dp = (Vec2d*)(parambuf + cn*2); + for( j = 0; j < cn; j++ ) + { + dp[j][0] = std::min(DBL_MAX, p2[j] - p1[j])*scale; + dp[j][1] = ((p2[j] + p1[j])*0.5); + } + } + + func = randTab[0][depth]; + } + CV_Assert( func != 0 ); + } + else if( disttype == CV_RAND_NORMAL ) + { + _parambuf.allocate(MAX(n1, cn) + MAX(n2, cn)); + double* parambuf = _parambuf; + + int ptype = depth == CV_64F ? CV_64F : CV_32F; + int esz = (int)CV_ELEM_SIZE(ptype); + + if( _param1.isContinuous() && _param1.type() == ptype ) + mean = _param1.data; + else + { + Mat tmp(_param1.size(), ptype, parambuf); + _param1.convertTo(tmp, ptype); + mean = (uchar*)parambuf; + } + + if( n1 < cn ) + for( j = n1*esz; j < cn*esz; j++ ) + mean[j] = mean[j - n1*esz]; + + if( _param2.isContinuous() && _param2.type() == ptype ) + stddev = _param2.data; + else + { + Mat tmp(_param2.size(), ptype, parambuf + cn); + _param2.convertTo(tmp, ptype); + stddev = (uchar*)(parambuf + cn); + } + + if( n1 < cn ) + for( j = n1*esz; j < cn*esz; j++ ) + stddev[j] = stddev[j - n1*esz]; + + stdmtx = _param2.rows == cn && _param2.cols == cn; + scaleFunc = randnScaleTab[depth]; + CV_Assert( scaleFunc != 0 ); + } + else + CV_Error( CV_StsBadArg, "Unknown distribution type" ); + + const Mat* arrays[] = {&mat, 0}; + uchar* ptr; + NAryMatIterator it(arrays, &ptr); + int total = (int)it.size, blockSize = std::min((BLOCK_SIZE + cn - 1)/cn, total); + size_t esz = mat.elemSize(); + AutoBuffer buf; + uchar* param = 0; + float* nbuf = 0; + + if( disttype == UNIFORM ) + { + buf.allocate(blockSize*cn*4); + param = (uchar*)(double*)buf; + + if( ip ) + { + if( ds ) + { + DivStruct* p = (DivStruct*)param; + for( j = 0; j < blockSize*cn; j += cn ) + for( k = 0; k < cn; k++ ) + p[j + k] = ds[k]; + } + else + { + Vec2i* p = (Vec2i*)param; + for( j = 0; j < blockSize*cn; j += cn ) + for( k = 0; k < cn; k++ ) + p[j + k] = ip[k]; + } + } + else if( fp ) + { + Vec2f* p = (Vec2f*)param; + for( j = 0; j < blockSize*cn; j += cn ) + for( k = 0; k < cn; k++ ) + p[j + k] = fp[k]; + } + else + { + Vec2d* p = (Vec2d*)param; + for( j = 0; j < blockSize*cn; j += cn ) + for( k = 0; k < cn; k++ ) + p[j + k] = dp[k]; + } + } + else + { + buf.allocate((blockSize*cn+1)/2); + nbuf = (float*)(double*)buf; + } + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( j = 0; j < total; j += blockSize ) + { + int len = std::min(total - j, blockSize); + + if( disttype == CV_RAND_UNI ) + func( ptr, len*cn, &state, param, smallFlag != 0 ); + else + { + randn_0_1_32f(nbuf, len*cn, &state); + scaleFunc(nbuf, ptr, len, cn, mean, stddev, stdmtx); + } + ptr += len*esz; + } + } +} + +#ifdef WIN32 +#ifdef WINCE +# define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF) +#endif +static DWORD tlsRNGKey = TLS_OUT_OF_INDEXES; + +void deleteThreadRNGData() +{ + if( tlsRNGKey != TLS_OUT_OF_INDEXES ) + delete (RNG*)TlsGetValue( tlsRNGKey ); +} + +RNG& theRNG() +{ + if( tlsRNGKey == TLS_OUT_OF_INDEXES ) + { + tlsRNGKey = TlsAlloc(); + CV_Assert(tlsRNGKey != TLS_OUT_OF_INDEXES); + } + RNG* rng = (RNG*)TlsGetValue( tlsRNGKey ); + if( !rng ) + { + rng = new RNG; + TlsSetValue( tlsRNGKey, rng ); + } + return *rng; +} + +#else + +static pthread_key_t tlsRNGKey = 0; +static pthread_once_t tlsRNGKeyOnce = PTHREAD_ONCE_INIT; + +static void deleteRNG(void* data) +{ + delete (RNG*)data; +} + +static void makeRNGKey() +{ + int errcode = pthread_key_create(&tlsRNGKey, deleteRNG); + CV_Assert(errcode == 0); +} + +RNG& theRNG() +{ + pthread_once(&tlsRNGKeyOnce, makeRNGKey); + RNG* rng = (RNG*)pthread_getspecific(tlsRNGKey); + if( !rng ) + { + rng = new RNG; + pthread_setspecific(tlsRNGKey, rng); + } + return *rng; +} + +#endif + +} + +void cv::randu(InputOutputArray dst, InputArray low, InputArray high) +{ + theRNG().fill(dst, RNG::UNIFORM, low, high); +} + +void cv::randn(InputOutputArray dst, InputArray mean, InputArray stddev) +{ + theRNG().fill(dst, RNG::NORMAL, mean, stddev); +} + +namespace cv +{ + +template static void +randShuffle_( Mat& _arr, RNG& rng, double iterFactor ) +{ + int sz = _arr.rows*_arr.cols, iters = cvRound(iterFactor*sz); + if( _arr.isContinuous() ) + { + T* arr = (T*)_arr.data; + for( int i = 0; i < iters; i++ ) + { + int j = (unsigned)rng % sz, k = (unsigned)rng % sz; + std::swap( arr[j], arr[k] ); + } + } + else + { + uchar* data = _arr.data; + size_t step = _arr.step; + int cols = _arr.cols; + for( int i = 0; i < iters; i++ ) + { + int j1 = (unsigned)rng % sz, k1 = (unsigned)rng % sz; + int j0 = j1/cols, k0 = k1/cols; + j1 -= j0*cols; k1 -= k0*cols; + std::swap( ((T*)(data + step*j0))[j1], ((T*)(data + step*k0))[k1] ); + } + } +} + +typedef void (*RandShuffleFunc)( Mat& dst, RNG& rng, double iterFactor ); + +} + +void cv::randShuffle( InputOutputArray _dst, double iterFactor, RNG* _rng ) +{ + RandShuffleFunc tab[] = + { + 0, + randShuffle_, // 1 + randShuffle_, // 2 + randShuffle_ >, // 3 + randShuffle_, // 4 + 0, + randShuffle_ >, // 6 + 0, + randShuffle_ >, // 8 + 0, 0, 0, + randShuffle_ >, // 12 + 0, 0, 0, + randShuffle_ >, // 16 + 0, 0, 0, 0, 0, 0, 0, + randShuffle_ >, // 24 + 0, 0, 0, 0, 0, 0, 0, + randShuffle_ > // 32 + }; + + Mat dst = _dst.getMat(); + RNG& rng = _rng ? *_rng : theRNG(); + CV_Assert( dst.elemSize() <= 32 ); + RandShuffleFunc func = tab[dst.elemSize()]; + CV_Assert( func != 0 ); + func( dst, rng, iterFactor ); +} + +void cv::randShuffle_( InputOutputArray _dst, double iterFactor ) +{ + randShuffle(_dst, iterFactor); +} + +CV_IMPL void +cvRandArr( CvRNG* _rng, CvArr* arr, int disttype, CvScalar param1, CvScalar param2 ) +{ + cv::Mat mat = cv::cvarrToMat(arr); + // !!! this will only work for current 64-bit MWC RNG !!! + cv::RNG& rng = _rng ? (cv::RNG&)*_rng : cv::theRNG(); + rng.fill(mat, disttype == CV_RAND_NORMAL ? + cv::RNG::NORMAL : cv::RNG::UNIFORM, cv::Scalar(param1), cv::Scalar(param2) ); +} + +CV_IMPL void cvRandShuffle( CvArr* arr, CvRNG* _rng, double iter_factor ) +{ + cv::Mat dst = cv::cvarrToMat(arr); + cv::RNG& rng = _rng ? (cv::RNG&)*_rng : cv::theRNG(); + cv::randShuffle( dst, iter_factor, &rng ); +} + +/* End of file. */ diff --git a/core/src/stat.cpp b/core/src/stat.cpp new file mode 100644 index 0000000..6744b17 --- /dev/null +++ b/core/src/stat.cpp @@ -0,0 +1,2018 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include + +namespace cv +{ + +template static inline Scalar rawToScalar(const T& v) +{ + Scalar s; + typedef typename DataType::channel_type T1; + int i, n = DataType::channels; + for( i = 0; i < n; i++ ) + s.val[i] = ((T1*)&v)[i]; + return s; +} + +/****************************************************************************************\ +* sum * +\****************************************************************************************/ + +template +static int sum_(const T* src0, const uchar* mask, ST* dst, int len, int cn ) +{ + const T* src = src0; + if( !mask ) + { + int i=0; + int k = cn % 4; + if( k == 1 ) + { + ST s0 = dst[0]; + + #if CV_ENABLE_UNROLLED + for(; i <= len - 4; i += 4, src += cn*4 ) + s0 += src[0] + src[cn] + src[cn*2] + src[cn*3]; + #endif + for( ; i < len; i++, src += cn ) + s0 += src[0]; + dst[0] = s0; + } + else if( k == 2 ) + { + ST s0 = dst[0], s1 = dst[1]; + for( i = 0; i < len; i++, src += cn ) + { + s0 += src[0]; + s1 += src[1]; + } + dst[0] = s0; + dst[1] = s1; + } + else if( k == 3 ) + { + ST s0 = dst[0], s1 = dst[1], s2 = dst[2]; + for( i = 0; i < len; i++, src += cn ) + { + s0 += src[0]; + s1 += src[1]; + s2 += src[2]; + } + dst[0] = s0; + dst[1] = s1; + dst[2] = s2; + } + + for( ; k < cn; k += 4 ) + { + src = src0 + k; + ST s0 = dst[k], s1 = dst[k+1], s2 = dst[k+2], s3 = dst[k+3]; + for( i = 0; i < len; i++, src += cn ) + { + s0 += src[0]; s1 += src[1]; + s2 += src[2]; s3 += src[3]; + } + dst[k] = s0; + dst[k+1] = s1; + dst[k+2] = s2; + dst[k+3] = s3; + } + return len; + } + + int i, nzm = 0; + if( cn == 1 ) + { + ST s = dst[0]; + for( i = 0; i < len; i++ ) + if( mask[i] ) + { + s += src[i]; + nzm++; + } + dst[0] = s; + } + else if( cn == 3 ) + { + ST s0 = dst[0], s1 = dst[1], s2 = dst[2]; + for( i = 0; i < len; i++, src += 3 ) + if( mask[i] ) + { + s0 += src[0]; + s1 += src[1]; + s2 += src[2]; + nzm++; + } + dst[0] = s0; + dst[1] = s1; + dst[2] = s2; + } + else + { + for( i = 0; i < len; i++, src += cn ) + if( mask[i] ) + { + int k = 0; + #if CV_ENABLE_UNROLLED + for( ; k <= cn - 4; k += 4 ) + { + ST s0, s1; + s0 = dst[k] + src[k]; + s1 = dst[k+1] + src[k+1]; + dst[k] = s0; dst[k+1] = s1; + s0 = dst[k+2] + src[k+2]; + s1 = dst[k+3] + src[k+3]; + dst[k+2] = s0; dst[k+3] = s1; + } + #endif + for( ; k < cn; k++ ) + dst[k] += src[k]; + nzm++; + } + } + return nzm; +} + + +static int sum8u( const uchar* src, const uchar* mask, int* dst, int len, int cn ) +{ return sum_(src, mask, dst, len, cn); } + +static int sum8s( const schar* src, const uchar* mask, int* dst, int len, int cn ) +{ return sum_(src, mask, dst, len, cn); } + +static int sum16u( const ushort* src, const uchar* mask, int* dst, int len, int cn ) +{ return sum_(src, mask, dst, len, cn); } + +static int sum16s( const short* src, const uchar* mask, int* dst, int len, int cn ) +{ return sum_(src, mask, dst, len, cn); } + +static int sum32s( const int* src, const uchar* mask, double* dst, int len, int cn ) +{ return sum_(src, mask, dst, len, cn); } + +static int sum32f( const float* src, const uchar* mask, double* dst, int len, int cn ) +{ return sum_(src, mask, dst, len, cn); } + +static int sum64f( const double* src, const uchar* mask, double* dst, int len, int cn ) +{ return sum_(src, mask, dst, len, cn); } + +typedef int (*SumFunc)(const uchar*, const uchar* mask, uchar*, int, int); + +static SumFunc sumTab[] = +{ + (SumFunc)GET_OPTIMIZED(sum8u), (SumFunc)sum8s, + (SumFunc)sum16u, (SumFunc)sum16s, + (SumFunc)sum32s, + (SumFunc)GET_OPTIMIZED(sum32f), (SumFunc)sum64f, + 0 +}; + +template +static int countNonZero_(const T* src, int len ) +{ + int i=0, nz = 0; + #if CV_ENABLE_UNROLLED + for(; i <= len - 4; i += 4 ) + nz += (src[i] != 0) + (src[i+1] != 0) + (src[i+2] != 0) + (src[i+3] != 0); + #endif + for( ; i < len; i++ ) + nz += src[i] != 0; + return nz; +} + +static int countNonZero8u( const uchar* src, int len ) +{ + int i=0, nz = 0; +#if CV_SSE2 + if(USE_SSE2)//5x-6x + { + __m128i pattern = _mm_setzero_si128 (); + static uchar tab[256]; + static volatile bool initialized = false; + if( !initialized ) + { + // we compute inverse popcount table, + // since we pass (img[x] == 0) mask as index in the table. + for( int j = 0; j < 256; j++ ) + { + int val = 0; + for( int mask = 1; mask < 256; mask += mask ) + val += (j & mask) == 0; + tab[j] = (uchar)val; + } + initialized = true; + } + + for (; i<=len-16; i+=16) + { + __m128i r0 = _mm_loadu_si128((const __m128i*)(src+i)); + int val = _mm_movemask_epi8(_mm_cmpeq_epi8(r0, pattern)); + nz += tab[val & 255] + tab[val >> 8]; + } + } +#endif + for( ; i < len; i++ ) + nz += src[i] != 0; + return nz; +} + +static int countNonZero16u( const ushort* src, int len ) +{ return countNonZero_(src, len); } + +static int countNonZero32s( const int* src, int len ) +{ return countNonZero_(src, len); } + +static int countNonZero32f( const float* src, int len ) +{ return countNonZero_(src, len); } + +static int countNonZero64f( const double* src, int len ) +{ return countNonZero_(src, len); } + +typedef int (*CountNonZeroFunc)(const uchar*, int); + +static CountNonZeroFunc countNonZeroTab[] = +{ + (CountNonZeroFunc)GET_OPTIMIZED(countNonZero8u), (CountNonZeroFunc)GET_OPTIMIZED(countNonZero8u), + (CountNonZeroFunc)GET_OPTIMIZED(countNonZero16u), (CountNonZeroFunc)GET_OPTIMIZED(countNonZero16u), + (CountNonZeroFunc)GET_OPTIMIZED(countNonZero32s), (CountNonZeroFunc)GET_OPTIMIZED(countNonZero32f), + (CountNonZeroFunc)GET_OPTIMIZED(countNonZero64f), 0 +}; + + +template +static int sumsqr_(const T* src0, const uchar* mask, ST* sum, SQT* sqsum, int len, int cn ) +{ + const T* src = src0; + + if( !mask ) + { + int i; + int k = cn % 4; + + if( k == 1 ) + { + ST s0 = sum[0]; + SQT sq0 = sqsum[0]; + for( i = 0; i < len; i++, src += cn ) + { + T v = src[0]; + s0 += v; sq0 += (SQT)v*v; + } + sum[0] = s0; + sqsum[0] = sq0; + } + else if( k == 2 ) + { + ST s0 = sum[0], s1 = sum[1]; + SQT sq0 = sqsum[0], sq1 = sqsum[1]; + for( i = 0; i < len; i++, src += cn ) + { + T v0 = src[0], v1 = src[1]; + s0 += v0; sq0 += (SQT)v0*v0; + s1 += v1; sq1 += (SQT)v1*v1; + } + sum[0] = s0; sum[1] = s1; + sqsum[0] = sq0; sqsum[1] = sq1; + } + else if( k == 3 ) + { + ST s0 = sum[0], s1 = sum[1], s2 = sum[2]; + SQT sq0 = sqsum[0], sq1 = sqsum[1], sq2 = sqsum[2]; + for( i = 0; i < len; i++, src += cn ) + { + T v0 = src[0], v1 = src[1], v2 = src[2]; + s0 += v0; sq0 += (SQT)v0*v0; + s1 += v1; sq1 += (SQT)v1*v1; + s2 += v2; sq2 += (SQT)v2*v2; + } + sum[0] = s0; sum[1] = s1; sum[2] = s2; + sqsum[0] = sq0; sqsum[1] = sq1; sqsum[2] = sq2; + } + + for( ; k < cn; k += 4 ) + { + src = src0 + k; + ST s0 = sum[k], s1 = sum[k+1], s2 = sum[k+2], s3 = sum[k+3]; + SQT sq0 = sqsum[k], sq1 = sqsum[k+1], sq2 = sqsum[k+2], sq3 = sqsum[k+3]; + for( i = 0; i < len; i++, src += cn ) + { + T v0, v1; + v0 = src[0], v1 = src[1]; + s0 += v0; sq0 += (SQT)v0*v0; + s1 += v1; sq1 += (SQT)v1*v1; + v0 = src[2], v1 = src[3]; + s2 += v0; sq2 += (SQT)v0*v0; + s3 += v1; sq3 += (SQT)v1*v1; + } + sum[k] = s0; sum[k+1] = s1; + sum[k+2] = s2; sum[k+3] = s3; + sqsum[k] = sq0; sqsum[k+1] = sq1; + sqsum[k+2] = sq2; sqsum[k+3] = sq3; + } + return len; + } + + int i, nzm = 0; + + if( cn == 1 ) + { + ST s0 = sum[0]; + SQT sq0 = sqsum[0]; + for( i = 0; i < len; i++ ) + if( mask[i] ) + { + T v = src[i]; + s0 += v; sq0 += (SQT)v*v; + nzm++; + } + sum[0] = s0; + sqsum[0] = sq0; + } + else if( cn == 3 ) + { + ST s0 = sum[0], s1 = sum[1], s2 = sum[2]; + SQT sq0 = sqsum[0], sq1 = sqsum[1], sq2 = sqsum[2]; + for( i = 0; i < len; i++, src += 3 ) + if( mask[i] ) + { + T v0 = src[0], v1 = src[1], v2 = src[2]; + s0 += v0; sq0 += (SQT)v0*v0; + s1 += v1; sq1 += (SQT)v1*v1; + s2 += v2; sq2 += (SQT)v2*v2; + nzm++; + } + sum[0] = s0; sum[1] = s1; sum[2] = s2; + sqsum[0] = sq0; sqsum[1] = sq1; sqsum[2] = sq2; + } + else + { + for( i = 0; i < len; i++, src += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + { + T v = src[k]; + ST s = sum[k] + v; + SQT sq = sqsum[k] + (SQT)v*v; + sum[k] = s; sqsum[k] = sq; + } + nzm++; + } + } + return nzm; +} + + +static int sqsum8u( const uchar* src, const uchar* mask, int* sum, int* sqsum, int len, int cn ) +{ return sumsqr_(src, mask, sum, sqsum, len, cn); } + +static int sqsum8s( const schar* src, const uchar* mask, int* sum, int* sqsum, int len, int cn ) +{ return sumsqr_(src, mask, sum, sqsum, len, cn); } + +static int sqsum16u( const ushort* src, const uchar* mask, int* sum, double* sqsum, int len, int cn ) +{ return sumsqr_(src, mask, sum, sqsum, len, cn); } + +static int sqsum16s( const short* src, const uchar* mask, int* sum, double* sqsum, int len, int cn ) +{ return sumsqr_(src, mask, sum, sqsum, len, cn); } + +static int sqsum32s( const int* src, const uchar* mask, double* sum, double* sqsum, int len, int cn ) +{ return sumsqr_(src, mask, sum, sqsum, len, cn); } + +static int sqsum32f( const float* src, const uchar* mask, double* sum, double* sqsum, int len, int cn ) +{ return sumsqr_(src, mask, sum, sqsum, len, cn); } + +static int sqsum64f( const double* src, const uchar* mask, double* sum, double* sqsum, int len, int cn ) +{ return sumsqr_(src, mask, sum, sqsum, len, cn); } + +typedef int (*SumSqrFunc)(const uchar*, const uchar* mask, uchar*, uchar*, int, int); + +static SumSqrFunc sumSqrTab[] = +{ + (SumSqrFunc)GET_OPTIMIZED(sqsum8u), (SumSqrFunc)sqsum8s, (SumSqrFunc)sqsum16u, (SumSqrFunc)sqsum16s, + (SumSqrFunc)sqsum32s, (SumSqrFunc)GET_OPTIMIZED(sqsum32f), (SumSqrFunc)sqsum64f, 0 +}; + +} + +cv::Scalar cv::sum( InputArray _src ) +{ + Mat src = _src.getMat(); + int k, cn = src.channels(), depth = src.depth(); + SumFunc func = sumTab[depth]; + + CV_Assert( cn <= 4 && func != 0 ); + + const Mat* arrays[] = {&src, 0}; + uchar* ptrs[1]; + NAryMatIterator it(arrays, ptrs); + Scalar s; + int total = (int)it.size, blockSize = total, intSumBlockSize = 0; + int j, count = 0; + AutoBuffer _buf; + int* buf = (int*)&s[0]; + size_t esz = 0; + bool blockSum = depth < CV_32S; + + if( blockSum ) + { + intSumBlockSize = depth <= CV_8S ? (1 << 23) : (1 << 15); + blockSize = std::min(blockSize, intSumBlockSize); + _buf.allocate(cn); + buf = _buf; + + for( k = 0; k < cn; k++ ) + buf[k] = 0; + esz = src.elemSize(); + } + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( j = 0; j < total; j += blockSize ) + { + int bsz = std::min(total - j, blockSize); + func( ptrs[0], 0, (uchar*)buf, bsz, cn ); + count += bsz; + if( blockSum && (count + blockSize >= intSumBlockSize || (i+1 >= it.nplanes && j+bsz >= total)) ) + { + for( k = 0; k < cn; k++ ) + { + s[k] += buf[k]; + buf[k] = 0; + } + count = 0; + } + ptrs[0] += bsz*esz; + } + } + return s; +} + +int cv::countNonZero( InputArray _src ) +{ + Mat src = _src.getMat(); + CountNonZeroFunc func = countNonZeroTab[src.depth()]; + + CV_Assert( src.channels() == 1 && func != 0 ); + + const Mat* arrays[] = {&src, 0}; + uchar* ptrs[1]; + NAryMatIterator it(arrays, ptrs); + int total = (int)it.size, nz = 0; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + nz += func( ptrs[0], total ); + + return nz; +} + +cv::Scalar cv::mean( InputArray _src, InputArray _mask ) +{ + Mat src = _src.getMat(), mask = _mask.getMat(); + CV_Assert( mask.empty() || mask.type() == CV_8U ); + + int k, cn = src.channels(), depth = src.depth(); + SumFunc func = sumTab[depth]; + + CV_Assert( cn <= 4 && func != 0 ); + + const Mat* arrays[] = {&src, &mask, 0}; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs); + Scalar s; + int total = (int)it.size, blockSize = total, intSumBlockSize = 0; + int j, count = 0; + AutoBuffer _buf; + int* buf = (int*)&s[0]; + bool blockSum = depth <= CV_16S; + size_t esz = 0, nz0 = 0; + + if( blockSum ) + { + intSumBlockSize = depth <= CV_8S ? (1 << 23) : (1 << 15); + blockSize = std::min(blockSize, intSumBlockSize); + _buf.allocate(cn); + buf = _buf; + + for( k = 0; k < cn; k++ ) + buf[k] = 0; + esz = src.elemSize(); + } + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( j = 0; j < total; j += blockSize ) + { + int bsz = std::min(total - j, blockSize); + int nz = func( ptrs[0], ptrs[1], (uchar*)buf, bsz, cn ); + count += nz; + nz0 += nz; + if( blockSum && (count + blockSize >= intSumBlockSize || (i+1 >= it.nplanes && j+bsz >= total)) ) + { + for( k = 0; k < cn; k++ ) + { + s[k] += buf[k]; + buf[k] = 0; + } + count = 0; + } + ptrs[0] += bsz*esz; + if( ptrs[1] ) + ptrs[1] += bsz; + } + } + return s*(nz0 ? 1./nz0 : 0); +} + + +void cv::meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, InputArray _mask ) +{ + Mat src = _src.getMat(), mask = _mask.getMat(); + CV_Assert( mask.empty() || mask.type() == CV_8U ); + + int k, cn = src.channels(), depth = src.depth(); + SumSqrFunc func = sumSqrTab[depth]; + + CV_Assert( func != 0 ); + + const Mat* arrays[] = {&src, &mask, 0}; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs); + int total = (int)it.size, blockSize = total, intSumBlockSize = 0; + int j, count = 0, nz0 = 0; + AutoBuffer _buf(cn*4); + double *s = (double*)_buf, *sq = s + cn; + int *sbuf = (int*)s, *sqbuf = (int*)sq; + bool blockSum = depth <= CV_16S, blockSqSum = depth <= CV_8S; + size_t esz = 0; + + for( k = 0; k < cn; k++ ) + s[k] = sq[k] = 0; + + if( blockSum ) + { + intSumBlockSize = 1 << 15; + blockSize = std::min(blockSize, intSumBlockSize); + sbuf = (int*)(sq + cn); + if( blockSqSum ) + sqbuf = sbuf + cn; + for( k = 0; k < cn; k++ ) + sbuf[k] = sqbuf[k] = 0; + esz = src.elemSize(); + } + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( j = 0; j < total; j += blockSize ) + { + int bsz = std::min(total - j, blockSize); + int nz = func( ptrs[0], ptrs[1], (uchar*)sbuf, (uchar*)sqbuf, bsz, cn ); + count += nz; + nz0 += nz; + if( blockSum && (count + blockSize >= intSumBlockSize || (i+1 >= it.nplanes && j+bsz >= total)) ) + { + for( k = 0; k < cn; k++ ) + { + s[k] += sbuf[k]; + sbuf[k] = 0; + } + if( blockSqSum ) + { + for( k = 0; k < cn; k++ ) + { + sq[k] += sqbuf[k]; + sqbuf[k] = 0; + } + } + count = 0; + } + ptrs[0] += bsz*esz; + if( ptrs[1] ) + ptrs[1] += bsz; + } + } + + double scale = nz0 ? 1./nz0 : 0.; + for( k = 0; k < cn; k++ ) + { + s[k] *= scale; + sq[k] = std::sqrt(std::max(sq[k]*scale - s[k]*s[k], 0.)); + } + + for( j = 0; j < 2; j++ ) + { + const double* sptr = j == 0 ? s : sq; + _OutputArray _dst = j == 0 ? _mean : _sdv; + if( !_dst.needed() ) + continue; + + if( !_dst.fixedSize() ) + _dst.create(cn, 1, CV_64F, -1, true); + Mat dst = _dst.getMat(); + int dcn = (int)dst.total(); + CV_Assert( dst.type() == CV_64F && dst.isContinuous() && + (dst.cols == 1 || dst.rows == 1) && dcn >= cn ); + double* dptr = dst.ptr(); + for( k = 0; k < cn; k++ ) + dptr[k] = sptr[k]; + for( ; k < dcn; k++ ) + dptr[k] = 0; + } +} + +/****************************************************************************************\ +* minMaxLoc * +\****************************************************************************************/ + +namespace cv +{ + +template static void +minMaxIdx_( const T* src, const uchar* mask, WT* _minVal, WT* _maxVal, + size_t* _minIdx, size_t* _maxIdx, int len, size_t startIdx ) +{ + WT minVal = *_minVal, maxVal = *_maxVal; + size_t minIdx = *_minIdx, maxIdx = *_maxIdx; + + if( !mask ) + { + for( int i = 0; i < len; i++ ) + { + T val = src[i]; + if( val < minVal ) + { + minVal = val; + minIdx = startIdx + i; + } + if( val > maxVal ) + { + maxVal = val; + maxIdx = startIdx + i; + } + } + } + else + { + for( int i = 0; i < len; i++ ) + { + T val = src[i]; + if( mask[i] && val < minVal ) + { + minVal = val; + minIdx = startIdx + i; + } + if( mask[i] && val > maxVal ) + { + maxVal = val; + maxIdx = startIdx + i; + } + } + } + + *_minIdx = minIdx; + *_maxIdx = maxIdx; + *_minVal = minVal; + *_maxVal = maxVal; +} + +static void minMaxIdx_8u(const uchar* src, const uchar* mask, int* minval, int* maxval, + size_t* minidx, size_t* maxidx, int len, size_t startidx ) +{ minMaxIdx_(src, mask, minval, maxval, minidx, maxidx, len, startidx ); } + +static void minMaxIdx_8s(const schar* src, const uchar* mask, int* minval, int* maxval, + size_t* minidx, size_t* maxidx, int len, size_t startidx ) +{ minMaxIdx_(src, mask, minval, maxval, minidx, maxidx, len, startidx ); } + +static void minMaxIdx_16u(const ushort* src, const uchar* mask, int* minval, int* maxval, + size_t* minidx, size_t* maxidx, int len, size_t startidx ) +{ minMaxIdx_(src, mask, minval, maxval, minidx, maxidx, len, startidx ); } + +static void minMaxIdx_16s(const short* src, const uchar* mask, int* minval, int* maxval, + size_t* minidx, size_t* maxidx, int len, size_t startidx ) +{ minMaxIdx_(src, mask, minval, maxval, minidx, maxidx, len, startidx ); } + +static void minMaxIdx_32s(const int* src, const uchar* mask, int* minval, int* maxval, + size_t* minidx, size_t* maxidx, int len, size_t startidx ) +{ minMaxIdx_(src, mask, minval, maxval, minidx, maxidx, len, startidx ); } + +static void minMaxIdx_32f(const float* src, const uchar* mask, float* minval, float* maxval, + size_t* minidx, size_t* maxidx, int len, size_t startidx ) +{ minMaxIdx_(src, mask, minval, maxval, minidx, maxidx, len, startidx ); } + +static void minMaxIdx_64f(const double* src, const uchar* mask, double* minval, double* maxval, + size_t* minidx, size_t* maxidx, int len, size_t startidx ) +{ minMaxIdx_(src, mask, minval, maxval, minidx, maxidx, len, startidx ); } + +typedef void (*MinMaxIdxFunc)(const uchar*, const uchar*, int*, int*, size_t*, size_t*, int, size_t); + +static MinMaxIdxFunc minmaxTab[] = +{ + (MinMaxIdxFunc)GET_OPTIMIZED(minMaxIdx_8u), (MinMaxIdxFunc)GET_OPTIMIZED(minMaxIdx_8s), + (MinMaxIdxFunc)GET_OPTIMIZED(minMaxIdx_16u), (MinMaxIdxFunc)GET_OPTIMIZED(minMaxIdx_16s), + (MinMaxIdxFunc)GET_OPTIMIZED(minMaxIdx_32s), + (MinMaxIdxFunc)GET_OPTIMIZED(minMaxIdx_32f), (MinMaxIdxFunc)GET_OPTIMIZED(minMaxIdx_64f), + 0 +}; + +static void ofs2idx(const Mat& a, size_t ofs, int* idx) +{ + int i, d = a.dims; + if( ofs > 0 ) + { + ofs--; + for( i = d-1; i >= 0; i-- ) + { + int sz = a.size[i]; + idx[i] = (int)(ofs % sz); + ofs /= sz; + } + } + else + { + for( i = d-1; i >= 0; i-- ) + idx[i] = -1; + } +} + +} + +void cv::minMaxIdx(InputArray _src, double* minVal, + double* maxVal, int* minIdx, int* maxIdx, + InputArray _mask) +{ + Mat src = _src.getMat(), mask = _mask.getMat(); + int depth = src.depth(), cn = src.channels(); + + CV_Assert( (cn == 1 && (mask.empty() || mask.type() == CV_8U)) || + (cn >= 1 && mask.empty() && !minIdx && !maxIdx) ); + MinMaxIdxFunc func = minmaxTab[depth]; + CV_Assert( func != 0 ); + + const Mat* arrays[] = {&src, &mask, 0}; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs); + + size_t minidx = 0, maxidx = 0; + int iminval = INT_MAX, imaxval = INT_MIN; + float fminval = FLT_MAX, fmaxval = -FLT_MAX; + double dminval = DBL_MAX, dmaxval = -DBL_MAX; + size_t startidx = 1; + int *minval = &iminval, *maxval = &imaxval; + int planeSize = (int)it.size*cn; + + if( depth == CV_32F ) + minval = (int*)&fminval, maxval = (int*)&fmaxval; + else if( depth == CV_64F ) + minval = (int*)&dminval, maxval = (int*)&dmaxval; + + for( size_t i = 0; i < it.nplanes; i++, ++it, startidx += planeSize ) + func( ptrs[0], ptrs[1], minval, maxval, &minidx, &maxidx, planeSize, startidx ); + + if( minidx == 0 ) + dminval = dmaxval = 0; + else if( depth == CV_32F ) + dminval = fminval, dmaxval = fmaxval; + else if( depth <= CV_32S ) + dminval = iminval, dmaxval = imaxval; + + if( minVal ) + *minVal = dminval; + if( maxVal ) + *maxVal = dmaxval; + + if( minIdx ) + ofs2idx(src, minidx, minIdx); + if( maxIdx ) + ofs2idx(src, maxidx, maxIdx); +} + +void cv::minMaxLoc( InputArray _img, double* minVal, double* maxVal, + Point* minLoc, Point* maxLoc, InputArray mask ) +{ + Mat img = _img.getMat(); + CV_Assert(img.dims <= 2); + + minMaxIdx(_img, minVal, maxVal, (int*)minLoc, (int*)maxLoc, mask); + if( minLoc ) + std::swap(minLoc->x, minLoc->y); + if( maxLoc ) + std::swap(maxLoc->x, maxLoc->y); +} + +/****************************************************************************************\ +* norm * +\****************************************************************************************/ + +namespace cv +{ + +float normL2Sqr_(const float* a, const float* b, int n) +{ + int j = 0; float d = 0.f; +#if CV_SSE + if( USE_SSE2 ) + { + float CV_DECL_ALIGNED(16) buf[4]; + __m128 d0 = _mm_setzero_ps(), d1 = _mm_setzero_ps(); + + for( ; j <= n - 8; j += 8 ) + { + __m128 t0 = _mm_sub_ps(_mm_loadu_ps(a + j), _mm_loadu_ps(b + j)); + __m128 t1 = _mm_sub_ps(_mm_loadu_ps(a + j + 4), _mm_loadu_ps(b + j + 4)); + d0 = _mm_add_ps(d0, _mm_mul_ps(t0, t0)); + d1 = _mm_add_ps(d1, _mm_mul_ps(t1, t1)); + } + _mm_store_ps(buf, _mm_add_ps(d0, d1)); + d = buf[0] + buf[1] + buf[2] + buf[3]; + } + else +#endif + { + for( ; j <= n - 4; j += 4 ) + { + float t0 = a[j] - b[j], t1 = a[j+1] - b[j+1], t2 = a[j+2] - b[j+2], t3 = a[j+3] - b[j+3]; + d += t0*t0 + t1*t1 + t2*t2 + t3*t3; + } + } + + for( ; j < n; j++ ) + { + float t = a[j] - b[j]; + d += t*t; + } + return d; +} + + +float normL1_(const float* a, const float* b, int n) +{ + int j = 0; float d = 0.f; +#if CV_SSE + if( USE_SSE2 ) + { + float CV_DECL_ALIGNED(16) buf[4]; + static const int CV_DECL_ALIGNED(16) absbuf[4] = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff}; + __m128 d0 = _mm_setzero_ps(), d1 = _mm_setzero_ps(); + __m128 absmask = _mm_load_ps((const float*)absbuf); + + for( ; j <= n - 8; j += 8 ) + { + __m128 t0 = _mm_sub_ps(_mm_loadu_ps(a + j), _mm_loadu_ps(b + j)); + __m128 t1 = _mm_sub_ps(_mm_loadu_ps(a + j + 4), _mm_loadu_ps(b + j + 4)); + d0 = _mm_add_ps(d0, _mm_and_ps(t0, absmask)); + d1 = _mm_add_ps(d1, _mm_and_ps(t1, absmask)); + } + _mm_store_ps(buf, _mm_add_ps(d0, d1)); + d = buf[0] + buf[1] + buf[2] + buf[3]; + } + else +#endif + { + for( ; j <= n - 4; j += 4 ) + { + d += std::abs(a[j] - b[j]) + std::abs(a[j+1] - b[j+1]) + + std::abs(a[j+2] - b[j+2]) + std::abs(a[j+3] - b[j+3]); + } + } + + for( ; j < n; j++ ) + d += std::abs(a[j] - b[j]); + return d; +} + +int normL1_(const uchar* a, const uchar* b, int n) +{ + int j = 0, d = 0; +#if CV_SSE + if( USE_SSE2 ) + { + __m128i d0 = _mm_setzero_si128(); + + for( ; j <= n - 16; j += 16 ) + { + __m128i t0 = _mm_loadu_si128((const __m128i*)(a + j)); + __m128i t1 = _mm_loadu_si128((const __m128i*)(b + j)); + + d0 = _mm_add_epi32(d0, _mm_sad_epu8(t0, t1)); + } + + for( ; j <= n - 4; j += 4 ) + { + __m128i t0 = _mm_cvtsi32_si128(*(const int*)(a + j)); + __m128i t1 = _mm_cvtsi32_si128(*(const int*)(b + j)); + + d0 = _mm_add_epi32(d0, _mm_sad_epu8(t0, t1)); + } + d = _mm_cvtsi128_si32(_mm_add_epi32(d0, _mm_unpackhi_epi64(d0, d0))); + } + else +#endif + { + for( ; j <= n - 4; j += 4 ) + { + d += std::abs(a[j] - b[j]) + std::abs(a[j+1] - b[j+1]) + + std::abs(a[j+2] - b[j+2]) + std::abs(a[j+3] - b[j+3]); + } + } + for( ; j < n; j++ ) + d += std::abs(a[j] - b[j]); + return d; +} + +static const uchar popCountTable[] = +{ + 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 +}; + +static const uchar popCountTable2[] = +{ + 0, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, + 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, + 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, + 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, + 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, + 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 2, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4 +}; + +static const uchar popCountTable4[] = +{ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 +}; + +static int normHamming(const uchar* a, int n) +{ + int i = 0, result = 0; +#if CV_NEON + if (CPU_HAS_NEON_FEATURE) + { + uint32x4_t bits = vmovq_n_u32(0); + for (; i <= n - 16; i += 16) { + uint8x16_t A_vec = vld1q_u8 (a + i); + uint8x16_t bitsSet = vcntq_u8 (A_vec); + uint16x8_t bitSet8 = vpaddlq_u8 (bitsSet); + uint32x4_t bitSet4 = vpaddlq_u16 (bitSet8); + bits = vaddq_u32(bits, bitSet4); + } + uint64x2_t bitSet2 = vpaddlq_u32 (bits); + result = vgetq_lane_s32 (vreinterpretq_s32_u64(bitSet2),0); + result += vgetq_lane_s32 (vreinterpretq_s32_u64(bitSet2),2); + } + else +#endif + for( ; i <= n - 4; i += 4 ) + result += popCountTable[a[i]] + popCountTable[a[i+1]] + + popCountTable[a[i+2]] + popCountTable[a[i+3]]; + for( ; i < n; i++ ) + result += popCountTable[a[i]]; + return result; +} + +int normHamming(const uchar* a, const uchar* b, int n) +{ + int i = 0, result = 0; +#if CV_NEON + if (CPU_HAS_NEON_FEATURE) + { + uint32x4_t bits = vmovq_n_u32(0); + for (; i <= n - 16; i += 16) { + uint8x16_t A_vec = vld1q_u8 (a + i); + uint8x16_t B_vec = vld1q_u8 (b + i); + uint8x16_t AxorB = veorq_u8 (A_vec, B_vec); + uint8x16_t bitsSet = vcntq_u8 (AxorB); + uint16x8_t bitSet8 = vpaddlq_u8 (bitsSet); + uint32x4_t bitSet4 = vpaddlq_u16 (bitSet8); + bits = vaddq_u32(bits, bitSet4); + } + uint64x2_t bitSet2 = vpaddlq_u32 (bits); + result = vgetq_lane_s32 (vreinterpretq_s32_u64(bitSet2),0); + result += vgetq_lane_s32 (vreinterpretq_s32_u64(bitSet2),2); + } + else +#endif + for( ; i <= n - 4; i += 4 ) + result += popCountTable[a[i] ^ b[i]] + popCountTable[a[i+1] ^ b[i+1]] + + popCountTable[a[i+2] ^ b[i+2]] + popCountTable[a[i+3] ^ b[i+3]]; + for( ; i < n; i++ ) + result += popCountTable[a[i] ^ b[i]]; + return result; +} + +static int normHamming(const uchar* a, int n, int cellSize) +{ + if( cellSize == 1 ) + return normHamming(a, n); + const uchar* tab = 0; + if( cellSize == 2 ) + tab = popCountTable2; + else if( cellSize == 4 ) + tab = popCountTable4; + else + CV_Error( CV_StsBadSize, "bad cell size (not 1, 2 or 4) in normHamming" ); + int i = 0, result = 0; +#if CV_ENABLE_UNROLLED + for( ; i <= n - 4; i += 4 ) + result += tab[a[i]] + tab[a[i+1]] + tab[a[i+2]] + tab[a[i+3]]; +#endif + for( ; i < n; i++ ) + result += tab[a[i]]; + return result; +} + +int normHamming(const uchar* a, const uchar* b, int n, int cellSize) +{ + if( cellSize == 1 ) + return normHamming(a, b, n); + const uchar* tab = 0; + if( cellSize == 2 ) + tab = popCountTable2; + else if( cellSize == 4 ) + tab = popCountTable4; + else + CV_Error( CV_StsBadSize, "bad cell size (not 1, 2 or 4) in normHamming" ); + int i = 0, result = 0; + #if CV_ENABLE_UNROLLED + for( ; i <= n - 4; i += 4 ) + result += tab[a[i] ^ b[i]] + tab[a[i+1] ^ b[i+1]] + + tab[a[i+2] ^ b[i+2]] + tab[a[i+3] ^ b[i+3]]; + #endif + for( ; i < n; i++ ) + result += tab[a[i] ^ b[i]]; + return result; +} + + +template int +normInf_(const T* src, const uchar* mask, ST* _result, int len, int cn) +{ + ST result = *_result; + if( !mask ) + { + result = std::max(result, normInf(src, len*cn)); + } + else + { + for( int i = 0; i < len; i++, src += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + result = std::max(result, ST(fast_abs(src[k]))); + } + } + *_result = result; + return 0; +} + +template int +normL1_(const T* src, const uchar* mask, ST* _result, int len, int cn) +{ + ST result = *_result; + if( !mask ) + { + result += normL1(src, len*cn); + } + else + { + for( int i = 0; i < len; i++, src += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + result += fast_abs(src[k]); + } + } + *_result = result; + return 0; +} + +template int +normL2_(const T* src, const uchar* mask, ST* _result, int len, int cn) +{ + ST result = *_result; + if( !mask ) + { + result += normL2Sqr(src, len*cn); + } + else + { + for( int i = 0; i < len; i++, src += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + { + T v = src[k]; + result += (ST)v*v; + } + } + } + *_result = result; + return 0; +} + +template int +normDiffInf_(const T* src1, const T* src2, const uchar* mask, ST* _result, int len, int cn) +{ + ST result = *_result; + if( !mask ) + { + result = std::max(result, normInf(src1, src2, len*cn)); + } + else + { + for( int i = 0; i < len; i++, src1 += cn, src2 += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + result = std::max(result, (ST)std::abs(src1[k] - src2[k])); + } + } + *_result = result; + return 0; +} + +template int +normDiffL1_(const T* src1, const T* src2, const uchar* mask, ST* _result, int len, int cn) +{ + ST result = *_result; + if( !mask ) + { + result += normL1(src1, src2, len*cn); + } + else + { + for( int i = 0; i < len; i++, src1 += cn, src2 += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + result += std::abs(src1[k] - src2[k]); + } + } + *_result = result; + return 0; +} + +template int +normDiffL2_(const T* src1, const T* src2, const uchar* mask, ST* _result, int len, int cn) +{ + ST result = *_result; + if( !mask ) + { + result += normL2Sqr(src1, src2, len*cn); + } + else + { + for( int i = 0; i < len; i++, src1 += cn, src2 += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + { + ST v = src1[k] - src2[k]; + result += v*v; + } + } + } + *_result = result; + return 0; +} + + +#define CV_DEF_NORM_FUNC(L, suffix, type, ntype) \ + static int norm##L##_##suffix(const type* src, const uchar* mask, ntype* r, int len, int cn) \ +{ return norm##L##_(src, mask, r, len, cn); } \ + static int normDiff##L##_##suffix(const type* src1, const type* src2, \ + const uchar* mask, ntype* r, int len, int cn) \ +{ return normDiff##L##_(src1, src2, mask, r, (int)len, cn); } + +#define CV_DEF_NORM_ALL(suffix, type, inftype, l1type, l2type) \ + CV_DEF_NORM_FUNC(Inf, suffix, type, inftype) \ + CV_DEF_NORM_FUNC(L1, suffix, type, l1type) \ + CV_DEF_NORM_FUNC(L2, suffix, type, l2type) + +CV_DEF_NORM_ALL(8u, uchar, int, int, int) +CV_DEF_NORM_ALL(8s, schar, int, int, int) +CV_DEF_NORM_ALL(16u, ushort, int, int, double) +CV_DEF_NORM_ALL(16s, short, int, int, double) +CV_DEF_NORM_ALL(32s, int, int, double, double) +CV_DEF_NORM_ALL(32f, float, float, double, double) +CV_DEF_NORM_ALL(64f, double, double, double, double) + + +typedef int (*NormFunc)(const uchar*, const uchar*, uchar*, int, int); +typedef int (*NormDiffFunc)(const uchar*, const uchar*, const uchar*, uchar*, int, int); + +static NormFunc normTab[3][8] = +{ + { + (NormFunc)GET_OPTIMIZED(normInf_8u), (NormFunc)GET_OPTIMIZED(normInf_8s), (NormFunc)GET_OPTIMIZED(normInf_16u), (NormFunc)GET_OPTIMIZED(normInf_16s), + (NormFunc)GET_OPTIMIZED(normInf_32s), (NormFunc)GET_OPTIMIZED(normInf_32f), (NormFunc)normInf_64f, 0 + }, + { + (NormFunc)GET_OPTIMIZED(normL1_8u), (NormFunc)GET_OPTIMIZED(normL1_8s), (NormFunc)GET_OPTIMIZED(normL1_16u), (NormFunc)GET_OPTIMIZED(normL1_16s), + (NormFunc)GET_OPTIMIZED(normL1_32s), (NormFunc)GET_OPTIMIZED(normL1_32f), (NormFunc)normL1_64f, 0 + }, + { + (NormFunc)GET_OPTIMIZED(normL2_8u), (NormFunc)GET_OPTIMIZED(normL2_8s), (NormFunc)GET_OPTIMIZED(normL2_16u), (NormFunc)GET_OPTIMIZED(normL2_16s), + (NormFunc)GET_OPTIMIZED(normL2_32s), (NormFunc)GET_OPTIMIZED(normL2_32f), (NormFunc)normL2_64f, 0 + } +}; + +static NormDiffFunc normDiffTab[3][8] = +{ + { + (NormDiffFunc)GET_OPTIMIZED(normDiffInf_8u), (NormDiffFunc)normDiffInf_8s, + (NormDiffFunc)normDiffInf_16u, (NormDiffFunc)normDiffInf_16s, + (NormDiffFunc)normDiffInf_32s, (NormDiffFunc)GET_OPTIMIZED(normDiffInf_32f), + (NormDiffFunc)normDiffInf_64f, 0 + }, + { + (NormDiffFunc)GET_OPTIMIZED(normDiffL1_8u), (NormDiffFunc)normDiffL1_8s, + (NormDiffFunc)normDiffL1_16u, (NormDiffFunc)normDiffL1_16s, + (NormDiffFunc)normDiffL1_32s, (NormDiffFunc)GET_OPTIMIZED(normDiffL1_32f), + (NormDiffFunc)normDiffL1_64f, 0 + }, + { + (NormDiffFunc)GET_OPTIMIZED(normDiffL2_8u), (NormDiffFunc)normDiffL2_8s, + (NormDiffFunc)normDiffL2_16u, (NormDiffFunc)normDiffL2_16s, + (NormDiffFunc)normDiffL2_32s, (NormDiffFunc)GET_OPTIMIZED(normDiffL2_32f), + (NormDiffFunc)normDiffL2_64f, 0 + } +}; + +} + +double cv::norm( InputArray _src, int normType, InputArray _mask ) +{ + Mat src = _src.getMat(), mask = _mask.getMat(); + int depth = src.depth(), cn = src.channels(); + + normType &= 7; + CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 || normType == NORM_L2SQR || + ((normType == NORM_HAMMING || normType == NORM_HAMMING2) && src.type() == CV_8U) ); + + if( src.isContinuous() && mask.empty() ) + { + size_t len = src.total()*cn; + if( len == (size_t)(int)len ) + { + if( depth == CV_32F ) + { + const float* data = src.ptr(); + + if( normType == NORM_L2 ) + { + double result = 0; + GET_OPTIMIZED(normL2_32f)(data, 0, &result, (int)len, 1); + return std::sqrt(result); + } + if( normType == NORM_L2SQR ) + { + double result = 0; + GET_OPTIMIZED(normL2_32f)(data, 0, &result, (int)len, 1); + return result; + } + if( normType == NORM_L1 ) + { + double result = 0; + GET_OPTIMIZED(normL1_32f)(data, 0, &result, (int)len, 1); + return result; + } + if( normType == NORM_INF ) + { + float result = 0; + GET_OPTIMIZED(normInf_32f)(data, 0, &result, (int)len, 1); + return result; + } + } + if( depth == CV_8U ) + { + const uchar* data = src.ptr(); + + if( normType == NORM_HAMMING ) + return normHamming(data, (int)len); + + if( normType == NORM_HAMMING2 ) + return normHamming(data, (int)len, 2); + } + } + } + + CV_Assert( mask.empty() || mask.type() == CV_8U ); + + if( normType == NORM_HAMMING || normType == NORM_HAMMING2 ) + { + if( !mask.empty() ) + { + Mat temp; + bitwise_and(src, mask, temp); + return norm(temp, normType); + } + int cellSize = normType == NORM_HAMMING ? 1 : 2; + + const Mat* arrays[] = {&src, 0}; + uchar* ptrs[1]; + NAryMatIterator it(arrays, ptrs); + int total = (int)it.size; + int result = 0; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + result += normHamming(ptrs[0], total, cellSize); + + return result; + } + + NormFunc func = normTab[normType >> 1][depth]; + CV_Assert( func != 0 ); + + const Mat* arrays[] = {&src, &mask, 0}; + uchar* ptrs[2]; + union + { + double d; + int i; + float f; + } + result; + result.d = 0; + NAryMatIterator it(arrays, ptrs); + int j, total = (int)it.size, blockSize = total, intSumBlockSize = 0, count = 0; + bool blockSum = (normType == NORM_L1 && depth <= CV_16S) || + ((normType == NORM_L2 || normType == NORM_L2SQR) && depth <= CV_8S); + int isum = 0; + int *ibuf = &result.i; + size_t esz = 0; + + if( blockSum ) + { + intSumBlockSize = (normType == NORM_L1 && depth <= CV_8S ? (1 << 23) : (1 << 15))/cn; + blockSize = std::min(blockSize, intSumBlockSize); + ibuf = &isum; + esz = src.elemSize(); + } + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( j = 0; j < total; j += blockSize ) + { + int bsz = std::min(total - j, blockSize); + func( ptrs[0], ptrs[1], (uchar*)ibuf, bsz, cn ); + count += bsz; + if( blockSum && (count + blockSize >= intSumBlockSize || (i+1 >= it.nplanes && j+bsz >= total)) ) + { + result.d += isum; + isum = 0; + count = 0; + } + ptrs[0] += bsz*esz; + if( ptrs[1] ) + ptrs[1] += bsz; + } + } + + if( normType == NORM_INF ) + { + if( depth == CV_64F ) + ; + else if( depth == CV_32F ) + result.d = result.f; + else + result.d = result.i; + } + else if( normType == NORM_L2 ) + result.d = std::sqrt(result.d); + + return result.d; +} + + +double cv::norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask ) +{ + if( normType & CV_RELATIVE ) + return norm(_src1, _src2, normType & ~CV_RELATIVE, _mask)/(norm(_src2, normType, _mask) + DBL_EPSILON); + + Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat(); + int depth = src1.depth(), cn = src1.channels(); + + CV_Assert( src1.size == src2.size && src1.type() == src2.type() ); + + normType &= 7; + CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 || normType == NORM_L2SQR || + ((normType == NORM_HAMMING || normType == NORM_HAMMING2) && src1.type() == CV_8U) ); + + if( src1.isContinuous() && src2.isContinuous() && mask.empty() ) + { + size_t len = src1.total()*src1.channels(); + if( len == (size_t)(int)len ) + { + if( src1.depth() == CV_32F ) + { + const float* data1 = src1.ptr(); + const float* data2 = src2.ptr(); + + if( normType == NORM_L2 ) + { + double result = 0; + GET_OPTIMIZED(normDiffL2_32f)(data1, data2, 0, &result, (int)len, 1); + return std::sqrt(result); + } + if( normType == NORM_L2SQR ) + { + double result = 0; + GET_OPTIMIZED(normDiffL2_32f)(data1, data2, 0, &result, (int)len, 1); + return result; + } + if( normType == NORM_L1 ) + { + double result = 0; + GET_OPTIMIZED(normDiffL1_32f)(data1, data2, 0, &result, (int)len, 1); + return result; + } + if( normType == NORM_INF ) + { + float result = 0; + GET_OPTIMIZED(normDiffInf_32f)(data1, data2, 0, &result, (int)len, 1); + return result; + } + } + } + } + + CV_Assert( mask.empty() || mask.type() == CV_8U ); + + if( normType == NORM_HAMMING || normType == NORM_HAMMING2 ) + { + if( !mask.empty() ) + { + Mat temp; + bitwise_xor(src1, src2, temp); + bitwise_and(temp, mask, temp); + return norm(temp, normType); + } + int cellSize = normType == NORM_HAMMING ? 1 : 2; + + const Mat* arrays[] = {&src1, &src2, 0}; + uchar* ptrs[2]; + NAryMatIterator it(arrays, ptrs); + int total = (int)it.size; + int result = 0; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + result += normHamming(ptrs[0], ptrs[1], total, cellSize); + + return result; + } + + NormDiffFunc func = normDiffTab[normType >> 1][depth]; + CV_Assert( func != 0 ); + + const Mat* arrays[] = {&src1, &src2, &mask, 0}; + uchar* ptrs[3]; + union + { + double d; + float f; + int i; + unsigned u; + } + result; + result.d = 0; + NAryMatIterator it(arrays, ptrs); + int j, total = (int)it.size, blockSize = total, intSumBlockSize = 0, count = 0; + bool blockSum = (normType == NORM_L1 && depth <= CV_16S) || + ((normType == NORM_L2 || normType == NORM_L2SQR) && depth <= CV_8S); + unsigned isum = 0; + unsigned *ibuf = &result.u; + size_t esz = 0; + + if( blockSum ) + { + intSumBlockSize = normType == NORM_L1 && depth <= CV_8S ? (1 << 23) : (1 << 15); + blockSize = std::min(blockSize, intSumBlockSize); + ibuf = &isum; + esz = src1.elemSize(); + } + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + for( j = 0; j < total; j += blockSize ) + { + int bsz = std::min(total - j, blockSize); + func( ptrs[0], ptrs[1], ptrs[2], (uchar*)ibuf, bsz, cn ); + count += bsz; + if( blockSum && (count + blockSize >= intSumBlockSize || (i+1 >= it.nplanes && j+bsz >= total)) ) + { + result.d += isum; + isum = 0; + count = 0; + } + ptrs[0] += bsz*esz; + ptrs[1] += bsz*esz; + if( ptrs[2] ) + ptrs[2] += bsz; + } + } + + if( normType == NORM_INF ) + { + if( depth == CV_64F ) + ; + else if( depth == CV_32F ) + result.d = result.f; + else + result.d = result.u; + } + else if( normType == NORM_L2 ) + result.d = std::sqrt(result.d); + + return result.d; +} + + +///////////////////////////////////// batch distance /////////////////////////////////////// + +namespace cv +{ + +template +void batchDistL1_(const _Tp* src1, const _Tp* src2, size_t step2, + int nvecs, int len, _Rt* dist, const uchar* mask) +{ + step2 /= sizeof(src2[0]); + if( !mask ) + { + for( int i = 0; i < nvecs; i++ ) + dist[i] = normL1<_Tp, _Rt>(src1, src2 + step2*i, len); + } + else + { + _Rt val0 = std::numeric_limits<_Rt>::max(); + for( int i = 0; i < nvecs; i++ ) + dist[i] = mask[i] ? normL1<_Tp, _Rt>(src1, src2 + step2*i, len) : val0; + } +} + +template +void batchDistL2Sqr_(const _Tp* src1, const _Tp* src2, size_t step2, + int nvecs, int len, _Rt* dist, const uchar* mask) +{ + step2 /= sizeof(src2[0]); + if( !mask ) + { + for( int i = 0; i < nvecs; i++ ) + dist[i] = normL2Sqr<_Tp, _Rt>(src1, src2 + step2*i, len); + } + else + { + _Rt val0 = std::numeric_limits<_Rt>::max(); + for( int i = 0; i < nvecs; i++ ) + dist[i] = mask[i] ? normL2Sqr<_Tp, _Rt>(src1, src2 + step2*i, len) : val0; + } +} + +template +void batchDistL2_(const _Tp* src1, const _Tp* src2, size_t step2, + int nvecs, int len, _Rt* dist, const uchar* mask) +{ + step2 /= sizeof(src2[0]); + if( !mask ) + { + for( int i = 0; i < nvecs; i++ ) + dist[i] = std::sqrt(normL2Sqr<_Tp, _Rt>(src1, src2 + step2*i, len)); + } + else + { + _Rt val0 = std::numeric_limits<_Rt>::max(); + for( int i = 0; i < nvecs; i++ ) + dist[i] = mask[i] ? std::sqrt(normL2Sqr<_Tp, _Rt>(src1, src2 + step2*i, len)) : val0; + } +} + +static void batchDistHamming(const uchar* src1, const uchar* src2, size_t step2, + int nvecs, int len, int* dist, const uchar* mask) +{ + step2 /= sizeof(src2[0]); + if( !mask ) + { + for( int i = 0; i < nvecs; i++ ) + dist[i] = normHamming(src1, src2 + step2*i, len); + } + else + { + int val0 = INT_MAX; + for( int i = 0; i < nvecs; i++ ) + dist[i] = mask[i] ? normHamming(src1, src2 + step2*i, len) : val0; + } +} + +static void batchDistHamming2(const uchar* src1, const uchar* src2, size_t step2, + int nvecs, int len, int* dist, const uchar* mask) +{ + step2 /= sizeof(src2[0]); + if( !mask ) + { + for( int i = 0; i < nvecs; i++ ) + dist[i] = normHamming(src1, src2 + step2*i, len, 2); + } + else + { + int val0 = INT_MAX; + for( int i = 0; i < nvecs; i++ ) + dist[i] = mask[i] ? normHamming(src1, src2 + step2*i, len, 2) : val0; + } +} + +static void batchDistL1_8u32s(const uchar* src1, const uchar* src2, size_t step2, + int nvecs, int len, int* dist, const uchar* mask) +{ + batchDistL1_(src1, src2, step2, nvecs, len, dist, mask); +} + +static void batchDistL1_8u32f(const uchar* src1, const uchar* src2, size_t step2, + int nvecs, int len, float* dist, const uchar* mask) +{ + batchDistL1_(src1, src2, step2, nvecs, len, dist, mask); +} + +static void batchDistL2Sqr_8u32s(const uchar* src1, const uchar* src2, size_t step2, + int nvecs, int len, int* dist, const uchar* mask) +{ + batchDistL2Sqr_(src1, src2, step2, nvecs, len, dist, mask); +} + +static void batchDistL2Sqr_8u32f(const uchar* src1, const uchar* src2, size_t step2, + int nvecs, int len, float* dist, const uchar* mask) +{ + batchDistL2Sqr_(src1, src2, step2, nvecs, len, dist, mask); +} + +static void batchDistL2_8u32f(const uchar* src1, const uchar* src2, size_t step2, + int nvecs, int len, float* dist, const uchar* mask) +{ + batchDistL2_(src1, src2, step2, nvecs, len, dist, mask); +} + +static void batchDistL1_32f(const float* src1, const float* src2, size_t step2, + int nvecs, int len, float* dist, const uchar* mask) +{ + batchDistL1_(src1, src2, step2, nvecs, len, dist, mask); +} + +static void batchDistL2Sqr_32f(const float* src1, const float* src2, size_t step2, + int nvecs, int len, float* dist, const uchar* mask) +{ + batchDistL2Sqr_(src1, src2, step2, nvecs, len, dist, mask); +} + +static void batchDistL2_32f(const float* src1, const float* src2, size_t step2, + int nvecs, int len, float* dist, const uchar* mask) +{ + batchDistL2_(src1, src2, step2, nvecs, len, dist, mask); +} + +typedef void (*BatchDistFunc)(const uchar* src1, const uchar* src2, size_t step2, + int nvecs, int len, uchar* dist, const uchar* mask); + + +struct BatchDistInvoker +{ + BatchDistInvoker( const Mat& _src1, const Mat& _src2, + Mat& _dist, Mat& _nidx, int _K, + const Mat& _mask, int _update, + BatchDistFunc _func) + { + src1 = &_src1; + src2 = &_src2; + dist = &_dist; + nidx = &_nidx; + K = _K; + mask = &_mask; + update = _update; + func = _func; + } + + void operator()(const BlockedRange& range) const + { + AutoBuffer buf(src2->rows); + int* bufptr = buf; + + for( int i = range.begin(); i < range.end(); i++ ) + { + func(src1->ptr(i), src2->ptr(), src2->step, src2->rows, src2->cols, + K > 0 ? (uchar*)bufptr : dist->ptr(i), mask->data ? mask->ptr(i) : 0); + + if( K > 0 ) + { + int* nidxptr = nidx->ptr(i); + // since positive float's can be compared just like int's, + // we handle both CV_32S and CV_32F cases with a single branch + int* distptr = (int*)dist->ptr(i); + + int j, k; + + for( j = 0; j < src2->rows; j++ ) + { + int d = bufptr[j]; + if( d < distptr[K-1] ) + { + for( k = K-2; k >= 0 && distptr[k] > d; k-- ) + { + nidxptr[k+1] = nidxptr[k]; + distptr[k+1] = distptr[k]; + } + nidxptr[k+1] = j + update; + distptr[k+1] = d; + } + } + } + } + } + + const Mat *src1; + const Mat *src2; + Mat *dist; + Mat *nidx; + const Mat *mask; + int K; + int update; + BatchDistFunc func; +}; + +} + +void cv::batchDistance( InputArray _src1, InputArray _src2, + OutputArray _dist, int dtype, OutputArray _nidx, + int normType, int K, InputArray _mask, + int update, bool crosscheck ) +{ + Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat(); + int type = src1.type(); + CV_Assert( type == src2.type() && src1.cols == src2.cols && + (type == CV_32F || type == CV_8U)); + CV_Assert( _nidx.needed() == (K > 0) ); + + if( dtype == -1 ) + { + dtype = normType == NORM_HAMMING || normType == NORM_HAMMING2 ? CV_32S : CV_32F; + } + CV_Assert( (type == CV_8U && dtype == CV_32S) || dtype == CV_32F); + + K = std::min(K, src2.rows); + + _dist.create(src1.rows, (K > 0 ? K : src2.rows), dtype); + Mat dist = _dist.getMat(), nidx; + if( _nidx.needed() ) + { + _nidx.create(dist.size(), CV_32S); + nidx = _nidx.getMat(); + } + + if( update == 0 && K > 0 ) + { + dist = Scalar::all(dtype == CV_32S ? (double)INT_MAX : (double)FLT_MAX); + nidx = Scalar::all(-1); + } + + if( crosscheck ) + { + CV_Assert( K == 1 && update == 0 && mask.empty() ); + Mat tdist, tidx; + batchDistance(src2, src1, tdist, dtype, tidx, normType, K, mask, 0, false); + + // if an idx-th element from src1 appeared to be the nearest to i-th element of src2, + // we update the minimum mutual distance between idx-th element of src1 and the whole src2 set. + // As a result, if nidx[idx] = i*, it means that idx-th element of src1 is the nearest + // to i*-th element of src2 and i*-th element of src2 is the closest to idx-th element of src1. + // If nidx[idx] = -1, it means that there is no such ideal couple for it in src2. + // This O(N) procedure is called cross-check and it helps to eliminate some false matches. + if( dtype == CV_32S ) + { + for( int i = 0; i < tdist.rows; i++ ) + { + int idx = tidx.at(i); + int d = tdist.at(i), d0 = dist.at(idx); + if( d < d0 ) + { + dist.at(idx) = d0; + nidx.at(idx) = i + update; + } + } + } + else + { + for( int i = 0; i < tdist.rows; i++ ) + { + int idx = tidx.at(i); + float d = tdist.at(i), d0 = dist.at(idx); + if( d < d0 ) + { + dist.at(idx) = d0; + nidx.at(idx) = i + update; + } + } + } + return; + } + + BatchDistFunc func = 0; + if( type == CV_8U ) + { + if( normType == NORM_L1 && dtype == CV_32S ) + func = (BatchDistFunc)batchDistL1_8u32s; + else if( normType == NORM_L1 && dtype == CV_32F ) + func = (BatchDistFunc)batchDistL1_8u32f; + else if( normType == NORM_L2SQR && dtype == CV_32S ) + func = (BatchDistFunc)batchDistL2Sqr_8u32s; + else if( normType == NORM_L2SQR && dtype == CV_32F ) + func = (BatchDistFunc)batchDistL2Sqr_8u32f; + else if( normType == NORM_L2 && dtype == CV_32F ) + func = (BatchDistFunc)batchDistL2_8u32f; + else if( normType == NORM_HAMMING && dtype == CV_32S ) + func = (BatchDistFunc)batchDistHamming; + else if( normType == NORM_HAMMING2 && dtype == CV_32S ) + func = (BatchDistFunc)batchDistHamming2; + } + else if( type == CV_32F && dtype == CV_32F ) + { + if( normType == NORM_L1 ) + func = (BatchDistFunc)batchDistL1_32f; + else if( normType == NORM_L2SQR ) + func = (BatchDistFunc)batchDistL2Sqr_32f; + else if( normType == NORM_L2 ) + func = (BatchDistFunc)batchDistL2_32f; + } + + if( func == 0 ) + CV_Error_(CV_StsUnsupportedFormat, + ("The combination of type=%d, dtype=%d and normType=%d is not supported", + type, dtype, normType)); + + parallel_for(BlockedRange(0, src1.rows), + BatchDistInvoker(src1, src2, dist, nidx, K, mask, update, func)); +} + + +CV_IMPL CvScalar cvSum( const CvArr* srcarr ) +{ + cv::Scalar sum = cv::sum(cv::cvarrToMat(srcarr, false, true, 1)); + if( CV_IS_IMAGE(srcarr) ) + { + int coi = cvGetImageCOI((IplImage*)srcarr); + if( coi ) + { + CV_Assert( 0 < coi && coi <= 4 ); + sum = cv::Scalar(sum[coi-1]); + } + } + return sum; +} + +CV_IMPL int cvCountNonZero( const CvArr* imgarr ) +{ + cv::Mat img = cv::cvarrToMat(imgarr, false, true, 1); + if( img.channels() > 1 ) + cv::extractImageCOI(imgarr, img); + return countNonZero(img); +} + + +CV_IMPL CvScalar +cvAvg( const void* imgarr, const void* maskarr ) +{ + cv::Mat img = cv::cvarrToMat(imgarr, false, true, 1); + cv::Scalar mean = !maskarr ? cv::mean(img) : cv::mean(img, cv::cvarrToMat(maskarr)); + if( CV_IS_IMAGE(imgarr) ) + { + int coi = cvGetImageCOI((IplImage*)imgarr); + if( coi ) + { + CV_Assert( 0 < coi && coi <= 4 ); + mean = cv::Scalar(mean[coi-1]); + } + } + return mean; +} + + +CV_IMPL void +cvAvgSdv( const CvArr* imgarr, CvScalar* _mean, CvScalar* _sdv, const void* maskarr ) +{ + cv::Scalar mean, sdv; + + cv::Mat mask; + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + + cv::meanStdDev(cv::cvarrToMat(imgarr, false, true, 1), mean, sdv, mask ); + + if( CV_IS_IMAGE(imgarr) ) + { + int coi = cvGetImageCOI((IplImage*)imgarr); + if( coi ) + { + CV_Assert( 0 < coi && coi <= 4 ); + mean = cv::Scalar(mean[coi-1]); + sdv = cv::Scalar(sdv[coi-1]); + } + } + + if( _mean ) + *(cv::Scalar*)_mean = mean; + if( _sdv ) + *(cv::Scalar*)_sdv = sdv; +} + + +CV_IMPL void +cvMinMaxLoc( const void* imgarr, double* _minVal, double* _maxVal, + CvPoint* _minLoc, CvPoint* _maxLoc, const void* maskarr ) +{ + cv::Mat mask, img = cv::cvarrToMat(imgarr, false, true, 1); + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + if( img.channels() > 1 ) + cv::extractImageCOI(imgarr, img); + + cv::minMaxLoc( img, _minVal, _maxVal, + (cv::Point*)_minLoc, (cv::Point*)_maxLoc, mask ); +} + + +CV_IMPL double +cvNorm( const void* imgA, const void* imgB, int normType, const void* maskarr ) +{ + cv::Mat a, mask; + if( !imgA ) + { + imgA = imgB; + imgB = 0; + } + + a = cv::cvarrToMat(imgA, false, true, 1); + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + + if( a.channels() > 1 && CV_IS_IMAGE(imgA) && cvGetImageCOI((const IplImage*)imgA) > 0 ) + cv::extractImageCOI(imgA, a); + + if( !imgB ) + return !maskarr ? cv::norm(a, normType) : cv::norm(a, normType, mask); + + cv::Mat b = cv::cvarrToMat(imgB, false, true, 1); + if( b.channels() > 1 && CV_IS_IMAGE(imgB) && cvGetImageCOI((const IplImage*)imgB) > 0 ) + cv::extractImageCOI(imgB, b); + + return !maskarr ? cv::norm(a, b, normType) : cv::norm(a, b, normType, mask); +} diff --git a/core/src/system.cpp b/core/src/system.cpp new file mode 100644 index 0000000..3f28527 --- /dev/null +++ b/core/src/system.cpp @@ -0,0 +1,1033 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#if defined WIN32 || defined _WIN32 || defined WINCE +#include +#if defined _MSC_VER + #if _MSC_VER >= 1400 + #include + #elif defined _M_IX86 + static void __cpuid(int* cpuid_data, int) + { + __asm + { + push ebx + push edi + mov edi, cpuid_data + mov eax, 1 + cpuid + mov [edi], eax + mov [edi + 4], ebx + mov [edi + 8], ecx + mov [edi + 12], edx + pop edi + pop ebx + } + } + #endif +#endif +#else +#include +#include +#include + +#if defined __MACH__ && defined __APPLE__ +#include +#include +#endif + +#endif + +#ifdef _OPENMP +#include "omp.h" +#endif + +#include + +#if defined __linux__ || defined __APPLE__ +#include +#include +#include +#if defined ANDROID +#include +#else +#include +#endif +#endif + +#ifdef ANDROID +# include +#endif + +namespace cv +{ + +Exception::Exception() { code = 0; line = 0; } + +Exception::Exception(int _code, const string& _err, const string& _func, const string& _file, int _line) +: code(_code), err(_err), func(_func), file(_file), line(_line) +{ + formatMessage(); +} + +Exception::~Exception() throw() {} + +/*! + \return the error description and the context as a text string. + */ +const char* Exception::what() const throw() { return msg.c_str(); } + +void Exception::formatMessage() +{ + if( func.size() > 0 ) + msg = format("%s:%d: error: (%d) %s in function %s\n", file.c_str(), line, code, err.c_str(), func.c_str()); + else + msg = format("%s:%d: error: (%d) %s\n", file.c_str(), line, code, err.c_str()); +} + +struct HWFeatures +{ + enum { MAX_FEATURE = CV_HARDWARE_MAX_FEATURE }; + + HWFeatures(void) + { + memset( have, 0, sizeof(have) ); + x86_family = 0; + } + + static HWFeatures initialize(void) + { + HWFeatures f; + int cpuid_data[4] = { 0, 0, 0, 0 }; + + #if defined _MSC_VER && (defined _M_IX86 || defined _M_X64) + __cpuid(cpuid_data, 1); + #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__) + #ifdef __x86_64__ + asm __volatile__ + ( + "movl $1, %%eax\n\t" + "cpuid\n\t" + :[eax]"=a"(cpuid_data[0]),[ebx]"=b"(cpuid_data[1]),[ecx]"=c"(cpuid_data[2]),[edx]"=d"(cpuid_data[3]) + : + : "cc" + ); + #else + asm volatile + ( + "pushl %%ebx\n\t" + "movl $1,%%eax\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" + : "=a"(cpuid_data[0]), "=c"(cpuid_data[2]), "=d"(cpuid_data[3]) + : + : "cc" + ); + #endif + #endif + + f.x86_family = (cpuid_data[0] >> 8) & 15; + if( f.x86_family >= 6 ) + { + f.have[CV_CPU_MMX] = (cpuid_data[3] & (1 << 23)) != 0; + f.have[CV_CPU_SSE] = (cpuid_data[3] & (1<<25)) != 0; + f.have[CV_CPU_SSE2] = (cpuid_data[3] & (1<<26)) != 0; + f.have[CV_CPU_SSE3] = (cpuid_data[2] & (1<<0)) != 0; + f.have[CV_CPU_SSSE3] = (cpuid_data[2] & (1<<9)) != 0; + f.have[CV_CPU_SSE4_1] = (cpuid_data[2] & (1<<19)) != 0; + f.have[CV_CPU_SSE4_2] = (cpuid_data[2] & (1<<20)) != 0; + f.have[CV_CPU_POPCNT] = (cpuid_data[2] & (1<<23)) != 0; + f.have[CV_CPU_AVX] = (cpuid_data[2] & (1<<28)) != 0; + } + + return f; + } + + int x86_family; + bool have[MAX_FEATURE+1]; +}; + +static HWFeatures featuresEnabled = HWFeatures::initialize(), featuresDisabled = HWFeatures(); +static HWFeatures* currentFeatures = &featuresEnabled; + +bool checkHardwareSupport(int feature) +{ + CV_DbgAssert( 0 <= feature && feature <= CV_HARDWARE_MAX_FEATURE ); + return currentFeatures->have[feature]; +} + + +volatile bool useOptimizedFlag = true; +#ifdef HAVE_IPP +struct IPPInitializer +{ + IPPInitializer(void) { ippStaticInit(); } +}; + +IPPInitializer ippInitializer; +#endif + +volatile bool USE_SSE2 = featuresEnabled.have[CV_CPU_SSE2]; +volatile bool USE_SSE4_2 = featuresEnabled.have[CV_CPU_SSE4_2]; +volatile bool USE_AVX = featuresEnabled.have[CV_CPU_AVX]; + +void setUseOptimized( bool flag ) +{ + useOptimizedFlag = flag; + currentFeatures = flag ? &featuresEnabled : &featuresDisabled; + USE_SSE2 = currentFeatures->have[CV_CPU_SSE2]; +} + +bool useOptimized(void) +{ + return useOptimizedFlag; +} + +int64 getTickCount(void) +{ +#if defined WIN32 || defined _WIN32 || defined WINCE + LARGE_INTEGER counter; + QueryPerformanceCounter( &counter ); + return (int64)counter.QuadPart; +#elif defined __linux || defined __linux__ + struct timespec tp; + clock_gettime(CLOCK_MONOTONIC, &tp); + return (int64)tp.tv_sec*1000000000 + tp.tv_nsec; +#elif defined __MACH__ && defined __APPLE__ + return (int64)mach_absolute_time(); +#else + struct timeval tv; + struct timezone tz; + gettimeofday( &tv, &tz ); + return (int64)tv.tv_sec*1000000 + tv.tv_usec; +#endif +} + +double getTickFrequency(void) +{ +#if defined WIN32 || defined _WIN32 || defined WINCE + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + return (double)freq.QuadPart; +#elif defined __linux || defined __linux__ + return 1e9; +#elif defined __MACH__ && defined __APPLE__ + static double freq = 0; + if( freq == 0 ) + { + mach_timebase_info_data_t sTimebaseInfo; + mach_timebase_info(&sTimebaseInfo); + freq = sTimebaseInfo.denom*1e9/sTimebaseInfo.numer; + } + return freq; +#else + return 1e6; +#endif +} + +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__ || defined __ppc__) +#if defined(__i386__) + +int64 getCPUTickCount(void) +{ + int64 x; + __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); + return x; +} +#elif defined(__x86_64__) + +int64 getCPUTickCount(void) +{ + unsigned hi, lo; + __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); + return (int64)lo | ((int64)hi << 32); +} + +#elif defined(__ppc__) + +int64 getCPUTickCount(void) +{ + int64 result = 0; + unsigned upper, lower, tmp; + __asm__ volatile( + "0: \n" + "\tmftbu %0 \n" + "\tmftb %1 \n" + "\tmftbu %2 \n" + "\tcmpw %2,%0 \n" + "\tbne 0b \n" + : "=r"(upper),"=r"(lower),"=r"(tmp) + ); + return lower | ((int64)upper << 32); +} + +#else + +#error "RDTSC not defined" + +#endif + +#elif defined _MSC_VER && defined WIN32 && defined _M_IX86 + +int64 getCPUTickCount(void) +{ + __asm _emit 0x0f; + __asm _emit 0x31; +} + +#else + +#ifdef HAVE_IPP +int64 getCPUTickCount(void) +{ + return ippGetCpuClocks(); +} +#else +int64 getCPUTickCount(void) +{ + return getTickCount(); +} +#endif + +#endif + + +static int numThreads = 0; +static int numProcs = 0; + +int getNumThreads(void) +{ + if( !numProcs ) + setNumThreads(0); + return numThreads; +} + +void setNumThreads( int +#ifdef _OPENMP + threads +#endif + ) +{ + if( !numProcs ) + { +#ifdef _OPENMP + numProcs = omp_get_num_procs(); +#else + numProcs = 1; +#endif + } + +#ifdef _OPENMP + if( threads <= 0 ) + threads = numProcs; + else + threads = MIN( threads, numProcs ); + + numThreads = threads; +#else + numThreads = 1; +#endif +} + + +int getThreadNum(void) +{ +#ifdef _OPENMP + return omp_get_thread_num(); +#else + return 0; +#endif +} + +#ifdef ANDROID +static inline int getNumberOfCPUsImpl() +{ + FILE* cpuPossible = fopen("/sys/devices/system/cpu/possible", "r"); + if(!cpuPossible) + return 1; + + char buf[2000]; //big enough for 1000 CPUs in worst possible configuration + char* pbuf = fgets(buf, sizeof(buf), cpuPossible); + fclose(cpuPossible); + if(!pbuf) + return 1; + + //parse string of form "0-1,3,5-7,10,13-15" + int cpusAvailable = 0; + + while(*pbuf) + { + const char* pos = pbuf; + bool range = false; + while(*pbuf && *pbuf != ',') + { + if(*pbuf == '-') range = true; + ++pbuf; + } + if(*pbuf) *pbuf++ = 0; + if(!range) + ++cpusAvailable; + else + { + int rstart = 0, rend = 0; + sscanf(pos, "%d-%d", &rstart, &rend); + cpusAvailable += rend - rstart + 1; + } + + } + return cpusAvailable ? cpusAvailable : 1; +} +#endif + +int getNumberOfCPUs(void) +{ +#if defined WIN32 || defined _WIN32 + SYSTEM_INFO sysinfo; + GetSystemInfo( &sysinfo ); + + return (int)sysinfo.dwNumberOfProcessors; +#elif defined ANDROID + static int ncpus = getNumberOfCPUsImpl(); + printf("CPUS= %d\n", ncpus); + return ncpus; +#elif defined __linux__ + return (int)sysconf( _SC_NPROCESSORS_ONLN ); +#elif defined __APPLE__ + int numCPU=0; + int mib[4]; + size_t len = sizeof(numCPU); + + /* set the mib for hw.ncpu */ + mib[0] = CTL_HW; + mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU; + + /* get the number of CPUs from the system */ + sysctl(mib, 2, &numCPU, &len, NULL, 0); + + if( numCPU < 1 ) + { + mib[1] = HW_NCPU; + sysctl( mib, 2, &numCPU, &len, NULL, 0 ); + + if( numCPU < 1 ) + numCPU = 1; + } + + return (int)numCPU; +#else + return 1; +#endif +} + +const std::string& getBuildInformation() +{ + static std::string build_info = ""; +//#include "version_string.inc" + + return build_info; +} + +string format( const char* fmt, ... ) +{ + char buf[1 << 16]; + va_list args; + va_start( args, fmt ); + vsprintf( buf, fmt, args ); + return string(buf); +} + +string tempfile( const char* suffix ) +{ +#if defined WIN32 || defined _WIN32 + char temp_dir[MAX_PATH + 1] = { 0 }; + char temp_file[MAX_PATH + 1] = { 0 }; + + ::GetTempPathA(sizeof(temp_dir), temp_dir); + if(0 == ::GetTempFileNameA(temp_dir, "ocv", 0, temp_file)) + return string(); + + string name = temp_file; + if(suffix) + { + if (suffix[0] != '.') + return name + "." + suffix; + else + return name + suffix; + } + else + return name; +# else +# ifdef ANDROID + //char defaultTemplate[] = "/mnt/sdcard/__opencv_temp.XXXXXX"; + char defaultTemplate[] = "/data/local/tmp/__opencv_temp.XXXXXX"; +# else + char defaultTemplate[] = "/tmp/__opencv_temp.XXXXXX"; +# endif + + string fname; + const char *temp_dir = getenv("OPENCV_TEMP_PATH"); + if(temp_dir == 0 || temp_dir[0] == 0) + fname = defaultTemplate; + else + { + fname = temp_dir; + char ech = fname[fname.size() - 1]; + if(ech != '/' && ech != '\\') + fname += "/"; + fname += "__opencv_temp.XXXXXX"; + } + + const int fd = mkstemp((char*)fname.c_str()); + if(fd == -1) return ""; + close(fd); + remove(fname.c_str()); + + if(suffix) + { + if (suffix[0] != '.') + fname = fname + "." + suffix; + else + fname += suffix; + } + return fname; +# endif +} + +static CvErrorCallback customErrorCallback = 0; +static void* customErrorCallbackData = 0; +static bool breakOnError = false; + +bool setBreakOnError(bool value) +{ + bool prevVal = breakOnError; + breakOnError = value; + return prevVal; +} + +void error( const Exception& exc ) +{ + if (customErrorCallback != 0) + customErrorCallback(exc.code, exc.func.c_str(), exc.err.c_str(), + exc.file.c_str(), exc.line, customErrorCallbackData); + else + { + const char* errorStr = cvErrorStr(exc.code); + char buf[1 << 16]; + + sprintf( buf, "OpenCV Error: %s (%s) in %s, file %s, line %d", + errorStr, exc.err.c_str(), exc.func.size() > 0 ? + exc.func.c_str() : "unknown function", exc.file.c_str(), exc.line ); + fprintf( stderr, "%s\n", buf ); + fflush( stderr ); +# ifdef ANDROID + __android_log_print(ANDROID_LOG_ERROR, "cv::error()", "%s", buf); +# endif + } + + if(breakOnError) + { + static volatile int* p = 0; + *p = 0; + } + + throw exc; +} + +CvErrorCallback +redirectError( CvErrorCallback errCallback, void* userdata, void** prevUserdata) +{ + if( prevUserdata ) + *prevUserdata = customErrorCallbackData; + + CvErrorCallback prevCallback = customErrorCallback; + + customErrorCallback = errCallback; + customErrorCallbackData = userdata; + + return prevCallback; +} + +} + +/*CV_IMPL int +cvGuiBoxReport( int code, const char *func_name, const char *err_msg, + const char *file, int line, void* ) +{ +#if (!defined WIN32 && !defined _WIN32) || defined WINCE + return cvStdErrReport( code, func_name, err_msg, file, line, 0 ); +#else + if( code != CV_StsBackTrace && code != CV_StsAutoTrace ) + { + size_t msg_len = strlen(err_msg ? err_msg : "") + 1024; + char* message = (char*)alloca(msg_len); + char title[100]; + + wsprintf( message, "%s (%s)\nin function %s, %s(%d)\n\n" + "Press \"Abort\" to terminate application.\n" + "Press \"Retry\" to debug (if the app is running under debugger).\n" + "Press \"Ignore\" to continue (this is not safe).\n", + cvErrorStr(code), err_msg ? err_msg : "no description", + func_name, file, line ); + + wsprintf( title, "OpenCV GUI Error Handler" ); + + int answer = MessageBox( NULL, message, title, MB_ICONERROR|MB_ABORTRETRYIGNORE|MB_SYSTEMMODAL ); + + if( answer == IDRETRY ) + { + CV_DBG_BREAK(); + } + return answer != IDIGNORE; + } + return 0; +#endif +}*/ + +CV_IMPL int cvCheckHardwareSupport(int feature) +{ + CV_DbgAssert( 0 <= feature && feature <= CV_HARDWARE_MAX_FEATURE ); + return cv::currentFeatures->have[feature]; +} + +CV_IMPL int cvUseOptimized( int flag ) +{ + int prevMode = cv::useOptimizedFlag; + cv::setUseOptimized( flag != 0 ); + return prevMode; +} + +CV_IMPL int64 cvGetTickCount(void) +{ + return cv::getTickCount(); +} + +CV_IMPL double cvGetTickFrequency(void) +{ + return cv::getTickFrequency()*1e-6; +} + +CV_IMPL void cvSetNumThreads(int nt) +{ + cv::setNumThreads(nt); +} + +CV_IMPL int cvGetNumThreads() +{ + return cv::getNumThreads(); +} + +CV_IMPL int cvGetThreadNum() +{ + return cv::getThreadNum(); +} + + +CV_IMPL CvErrorCallback +cvRedirectError( CvErrorCallback errCallback, void* userdata, void** prevUserdata) +{ + return cv::redirectError(errCallback, userdata, prevUserdata); +} + +CV_IMPL int cvNulDevReport( int, const char*, const char*, + const char*, int, void* ) +{ + return 0; +} + +CV_IMPL int cvStdErrReport( int, const char*, const char*, + const char*, int, void* ) +{ + return 0; +} + +CV_IMPL int cvGuiBoxReport( int, const char*, const char*, + const char*, int, void* ) +{ + return 0; +} + +CV_IMPL int cvGetErrInfo( const char**, const char**, const char**, int* ) +{ + return 0; +} + + +CV_IMPL const char* cvErrorStr( int status ) +{ + static char buf[256]; + + switch (status) + { + case CV_StsOk : return "No Error"; + case CV_StsBackTrace : return "Backtrace"; + case CV_StsError : return "Unspecified error"; + case CV_StsInternal : return "Internal error"; + case CV_StsNoMem : return "Insufficient memory"; + case CV_StsBadArg : return "Bad argument"; + case CV_StsNoConv : return "Iterations do not converge"; + case CV_StsAutoTrace : return "Autotrace call"; + case CV_StsBadSize : return "Incorrect size of input array"; + case CV_StsNullPtr : return "Null pointer"; + case CV_StsDivByZero : return "Division by zero occured"; + case CV_BadStep : return "Image step is wrong"; + case CV_StsInplaceNotSupported : return "Inplace operation is not supported"; + case CV_StsObjectNotFound : return "Requested object was not found"; + case CV_BadDepth : return "Input image depth is not supported by function"; + case CV_StsUnmatchedFormats : return "Formats of input arguments do not match"; + case CV_StsUnmatchedSizes : return "Sizes of input arguments do not match"; + case CV_StsOutOfRange : return "One of arguments\' values is out of range"; + case CV_StsUnsupportedFormat : return "Unsupported format or combination of formats"; + case CV_BadCOI : return "Input COI is not supported"; + case CV_BadNumChannels : return "Bad number of channels"; + case CV_StsBadFlag : return "Bad flag (parameter or structure field)"; + case CV_StsBadPoint : return "Bad parameter of type CvPoint"; + case CV_StsBadMask : return "Bad type of mask argument"; + case CV_StsParseError : return "Parsing error"; + case CV_StsNotImplemented : return "The function/feature is not implemented"; + case CV_StsBadMemBlock : return "Memory block has been corrupted"; + case CV_StsAssert : return "Assertion failed"; + case CV_GpuNotSupported : return "No GPU support"; + case CV_GpuApiCallError : return "Gpu API call"; + case CV_OpenGlNotSupported : return "No OpenGL support"; + case CV_OpenGlApiCallError : return "OpenGL API call"; + }; + + sprintf(buf, "Unknown %s code %d", status >= 0 ? "status":"error", status); + return buf; +} + +CV_IMPL int cvGetErrMode(void) +{ + return 0; +} + +CV_IMPL int cvSetErrMode(int) +{ + return 0; +} + +CV_IMPL int cvGetErrStatus(void) +{ + return 0; +} + +CV_IMPL void cvSetErrStatus(int) +{ +} + + +CV_IMPL void cvError( int code, const char* func_name, + const char* err_msg, + const char* file_name, int line ) +{ + cv::error(cv::Exception(code, err_msg, func_name, file_name, line)); +} + +/* function, which converts int to int */ +CV_IMPL int +cvErrorFromIppStatus( int status ) +{ + switch (status) + { + case CV_BADSIZE_ERR: return CV_StsBadSize; + case CV_BADMEMBLOCK_ERR: return CV_StsBadMemBlock; + case CV_NULLPTR_ERR: return CV_StsNullPtr; + case CV_DIV_BY_ZERO_ERR: return CV_StsDivByZero; + case CV_BADSTEP_ERR: return CV_BadStep; + case CV_OUTOFMEM_ERR: return CV_StsNoMem; + case CV_BADARG_ERR: return CV_StsBadArg; + case CV_NOTDEFINED_ERR: return CV_StsError; + case CV_INPLACE_NOT_SUPPORTED_ERR: return CV_StsInplaceNotSupported; + case CV_NOTFOUND_ERR: return CV_StsObjectNotFound; + case CV_BADCONVERGENCE_ERR: return CV_StsNoConv; + case CV_BADDEPTH_ERR: return CV_BadDepth; + case CV_UNMATCHED_FORMATS_ERR: return CV_StsUnmatchedFormats; + case CV_UNSUPPORTED_COI_ERR: return CV_BadCOI; + case CV_UNSUPPORTED_CHANNELS_ERR: return CV_BadNumChannels; + case CV_BADFLAG_ERR: return CV_StsBadFlag; + case CV_BADRANGE_ERR: return CV_StsBadArg; + case CV_BADCOEF_ERR: return CV_StsBadArg; + case CV_BADFACTOR_ERR: return CV_StsBadArg; + case CV_BADPOINT_ERR: return CV_StsBadPoint; + + default: + return CV_StsError; + } +} + +static CvModuleInfo cxcore_info = { 0, "cxcore", CV_VERSION, 0 }; + +CvModuleInfo* CvModule::first = 0, *CvModule::last = 0; + +CvModule::CvModule( CvModuleInfo* _info ) +{ + cvRegisterModule( _info ); + info = last; +} + +CvModule::~CvModule(void) +{ + if( info ) + { + CvModuleInfo* p = first; + for( ; p != 0 && p->next != info; p = p->next ) + ; + + if( p ) + p->next = info->next; + + if( first == info ) + first = info->next; + + if( last == info ) + last = p; + + free( info ); + info = 0; + } +} + +CV_IMPL int +cvRegisterModule( const CvModuleInfo* module ) +{ + CV_Assert( module != 0 && module->name != 0 && module->version != 0 ); + + size_t name_len = strlen(module->name); + size_t version_len = strlen(module->version); + + CvModuleInfo* module_copy = (CvModuleInfo*)malloc( sizeof(*module_copy) + + name_len + 1 + version_len + 1 ); + + *module_copy = *module; + module_copy->name = (char*)(module_copy + 1); + module_copy->version = (char*)(module_copy + 1) + name_len + 1; + + memcpy( (void*)module_copy->name, module->name, name_len + 1 ); + memcpy( (void*)module_copy->version, module->version, version_len + 1 ); + module_copy->next = 0; + + if( CvModule::first == 0 ) + CvModule::first = module_copy; + else + CvModule::last->next = module_copy; + + CvModule::last = module_copy; + + return 0; +} + +CvModule cxcore_module( &cxcore_info ); + +CV_IMPL void +cvGetModuleInfo( const char* name, const char **version, const char **plugin_list ) +{ + static char joint_verinfo[1024] = ""; + static char plugin_list_buf[1024] = ""; + + if( version ) + *version = 0; + + if( plugin_list ) + *plugin_list = 0; + + CvModuleInfo* module; + + if( version ) + { + if( name ) + { + size_t i, name_len = strlen(name); + + for( module = CvModule::first; module != 0; module = module->next ) + { + if( strlen(module->name) == name_len ) + { + for( i = 0; i < name_len; i++ ) + { + int c0 = toupper(module->name[i]), c1 = toupper(name[i]); + if( c0 != c1 ) + break; + } + if( i == name_len ) + break; + } + } + if( !module ) + CV_Error( CV_StsObjectNotFound, "The module is not found" ); + + *version = module->version; + } + else + { + char* ptr = joint_verinfo; + + for( module = CvModule::first; module != 0; module = module->next ) + { + sprintf( ptr, "%s: %s%s", module->name, module->version, module->next ? ", " : "" ); + ptr += strlen(ptr); + } + + *version = joint_verinfo; + } + } + + if( plugin_list ) + *plugin_list = plugin_list_buf; +} + +#if defined BUILD_SHARED_LIBS && defined CVAPI_EXPORTS && defined WIN32 && !defined WINCE +BOOL WINAPI DllMain( HINSTANCE, DWORD fdwReason, LPVOID ); + +BOOL WINAPI DllMain( HINSTANCE, DWORD fdwReason, LPVOID ) +{ + if( fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH ) + { + cv::deleteThreadAllocData(); + cv::deleteThreadRNGData(); + } + return TRUE; +} +#endif + +namespace cv +{ + +#if defined WIN32 || defined _WIN32 || defined WINCE + +struct Mutex::Impl +{ + Impl() { InitializeCriticalSection(&cs); refcount = 1; } + ~Impl() { DeleteCriticalSection(&cs); } + + void lock() { EnterCriticalSection(&cs); } + bool trylock() { return TryEnterCriticalSection(&cs) != 0; } + void unlock() { LeaveCriticalSection(&cs); } + + CRITICAL_SECTION cs; + int refcount; +}; + +#elif defined __APPLE__ + +#include + +struct Mutex::Impl +{ + Impl() { sl = OS_SPINLOCK_INIT; refcount = 1; } + ~Impl() {} + + void lock() { OSSpinLockLock(&sl); } + bool trylock() { return OSSpinLockTry(&sl); } + void unlock() { OSSpinLockUnlock(&sl); } + + OSSpinLock sl; + int refcount; +}; + +#elif defined __linux__ && !defined ANDROID + +struct Mutex::Impl +{ + Impl() { pthread_spin_init(&sl, 0); refcount = 1; } + ~Impl() { pthread_spin_destroy(&sl); } + + void lock() { pthread_spin_lock(&sl); } + bool trylock() { return pthread_spin_trylock(&sl) == 0; } + void unlock() { pthread_spin_unlock(&sl); } + + pthread_spinlock_t sl; + int refcount; +}; + +#else + +struct Mutex::Impl +{ + Impl() { pthread_mutex_init(&sl, 0); refcount = 1; } + ~Impl() { pthread_mutex_destroy(&sl); } + + void lock() { pthread_mutex_lock(&sl); } + bool trylock() { return pthread_mutex_trylock(&sl) == 0; } + void unlock() { pthread_mutex_unlock(&sl); } + + pthread_mutex_t sl; + int refcount; +}; + +#endif + +Mutex::Mutex() +{ + impl = new Mutex::Impl; +} + +Mutex::~Mutex() +{ + if( CV_XADD(&impl->refcount, -1) == 1 ) + delete impl; + impl = 0; +} + +Mutex::Mutex(const Mutex& m) +{ + impl = m.impl; + CV_XADD(&impl->refcount, 1); +} + +Mutex& Mutex::operator = (const Mutex& m) +{ + CV_XADD(&m.impl->refcount, 1); + if( CV_XADD(&impl->refcount, -1) == 1 ) + delete impl; + impl = m.impl; + return *this; +} + +void Mutex::lock() { impl->lock(); } +void Mutex::unlock() { impl->unlock(); } +bool Mutex::trylock() { return impl->trylock(); } + +} + +/* End of file. */ \ No newline at end of file diff --git a/core/src/tables.cpp b/core/src/tables.cpp new file mode 100644 index 0000000..bd5e3cf --- /dev/null +++ b/core/src/tables.cpp @@ -0,0 +1,3512 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +/* //////////////////////////////////////////////////////////////////// +// +// CvMat helper tables +// +// */ + +#include "precomp.hpp" + +namespace cv +{ + +const float g_8x32fTab[] = +{ + -128.f, -127.f, -126.f, -125.f, -124.f, -123.f, -122.f, -121.f, + -120.f, -119.f, -118.f, -117.f, -116.f, -115.f, -114.f, -113.f, + -112.f, -111.f, -110.f, -109.f, -108.f, -107.f, -106.f, -105.f, + -104.f, -103.f, -102.f, -101.f, -100.f, -99.f, -98.f, -97.f, + -96.f, -95.f, -94.f, -93.f, -92.f, -91.f, -90.f, -89.f, + -88.f, -87.f, -86.f, -85.f, -84.f, -83.f, -82.f, -81.f, + -80.f, -79.f, -78.f, -77.f, -76.f, -75.f, -74.f, -73.f, + -72.f, -71.f, -70.f, -69.f, -68.f, -67.f, -66.f, -65.f, + -64.f, -63.f, -62.f, -61.f, -60.f, -59.f, -58.f, -57.f, + -56.f, -55.f, -54.f, -53.f, -52.f, -51.f, -50.f, -49.f, + -48.f, -47.f, -46.f, -45.f, -44.f, -43.f, -42.f, -41.f, + -40.f, -39.f, -38.f, -37.f, -36.f, -35.f, -34.f, -33.f, + -32.f, -31.f, -30.f, -29.f, -28.f, -27.f, -26.f, -25.f, + -24.f, -23.f, -22.f, -21.f, -20.f, -19.f, -18.f, -17.f, + -16.f, -15.f, -14.f, -13.f, -12.f, -11.f, -10.f, -9.f, + -8.f, -7.f, -6.f, -5.f, -4.f, -3.f, -2.f, -1.f, + 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, + 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f, + 16.f, 17.f, 18.f, 19.f, 20.f, 21.f, 22.f, 23.f, + 24.f, 25.f, 26.f, 27.f, 28.f, 29.f, 30.f, 31.f, + 32.f, 33.f, 34.f, 35.f, 36.f, 37.f, 38.f, 39.f, + 40.f, 41.f, 42.f, 43.f, 44.f, 45.f, 46.f, 47.f, + 48.f, 49.f, 50.f, 51.f, 52.f, 53.f, 54.f, 55.f, + 56.f, 57.f, 58.f, 59.f, 60.f, 61.f, 62.f, 63.f, + 64.f, 65.f, 66.f, 67.f, 68.f, 69.f, 70.f, 71.f, + 72.f, 73.f, 74.f, 75.f, 76.f, 77.f, 78.f, 79.f, + 80.f, 81.f, 82.f, 83.f, 84.f, 85.f, 86.f, 87.f, + 88.f, 89.f, 90.f, 91.f, 92.f, 93.f, 94.f, 95.f, + 96.f, 97.f, 98.f, 99.f, 100.f, 101.f, 102.f, 103.f, + 104.f, 105.f, 106.f, 107.f, 108.f, 109.f, 110.f, 111.f, + 112.f, 113.f, 114.f, 115.f, 116.f, 117.f, 118.f, 119.f, + 120.f, 121.f, 122.f, 123.f, 124.f, 125.f, 126.f, 127.f, + 128.f, 129.f, 130.f, 131.f, 132.f, 133.f, 134.f, 135.f, + 136.f, 137.f, 138.f, 139.f, 140.f, 141.f, 142.f, 143.f, + 144.f, 145.f, 146.f, 147.f, 148.f, 149.f, 150.f, 151.f, + 152.f, 153.f, 154.f, 155.f, 156.f, 157.f, 158.f, 159.f, + 160.f, 161.f, 162.f, 163.f, 164.f, 165.f, 166.f, 167.f, + 168.f, 169.f, 170.f, 171.f, 172.f, 173.f, 174.f, 175.f, + 176.f, 177.f, 178.f, 179.f, 180.f, 181.f, 182.f, 183.f, + 184.f, 185.f, 186.f, 187.f, 188.f, 189.f, 190.f, 191.f, + 192.f, 193.f, 194.f, 195.f, 196.f, 197.f, 198.f, 199.f, + 200.f, 201.f, 202.f, 203.f, 204.f, 205.f, 206.f, 207.f, + 208.f, 209.f, 210.f, 211.f, 212.f, 213.f, 214.f, 215.f, + 216.f, 217.f, 218.f, 219.f, 220.f, 221.f, 222.f, 223.f, + 224.f, 225.f, 226.f, 227.f, 228.f, 229.f, 230.f, 231.f, + 232.f, 233.f, 234.f, 235.f, 236.f, 237.f, 238.f, 239.f, + 240.f, 241.f, 242.f, 243.f, 244.f, 245.f, 246.f, 247.f, + 248.f, 249.f, 250.f, 251.f, 252.f, 253.f, 254.f, 255.f +}; + +/* [-255..255].^2 */ +const ushort g_8x16uSqrTab[] = +{ + 65025, 64516, 64009, 63504, 63001, 62500, 62001, 61504, 61009, 60516, 60025, 59536, + 59049, 58564, 58081, 57600, 57121, 56644, 56169, 55696, 55225, 54756, 54289, 53824, + 53361, 52900, 52441, 51984, 51529, 51076, 50625, 50176, 49729, 49284, 48841, 48400, + 47961, 47524, 47089, 46656, 46225, 45796, 45369, 44944, 44521, 44100, 43681, 43264, + 42849, 42436, 42025, 41616, 41209, 40804, 40401, 40000, 39601, 39204, 38809, 38416, + 38025, 37636, 37249, 36864, 36481, 36100, 35721, 35344, 34969, 34596, 34225, 33856, + 33489, 33124, 32761, 32400, 32041, 31684, 31329, 30976, 30625, 30276, 29929, 29584, + 29241, 28900, 28561, 28224, 27889, 27556, 27225, 26896, 26569, 26244, 25921, 25600, + 25281, 24964, 24649, 24336, 24025, 23716, 23409, 23104, 22801, 22500, 22201, 21904, + 21609, 21316, 21025, 20736, 20449, 20164, 19881, 19600, 19321, 19044, 18769, 18496, + 18225, 17956, 17689, 17424, 17161, 16900, 16641, 16384, 16129, 15876, 15625, 15376, + 15129, 14884, 14641, 14400, 14161, 13924, 13689, 13456, 13225, 12996, 12769, 12544, + 12321, 12100, 11881, 11664, 11449, 11236, 11025, 10816, 10609, 10404, 10201, 10000, + 9801, 9604, 9409, 9216, 9025, 8836, 8649, 8464, 8281, 8100, 7921, 7744, + 7569, 7396, 7225, 7056, 6889, 6724, 6561, 6400, 6241, 6084, 5929, 5776, + 5625, 5476, 5329, 5184, 5041, 4900, 4761, 4624, 4489, 4356, 4225, 4096, + 3969, 3844, 3721, 3600, 3481, 3364, 3249, 3136, 3025, 2916, 2809, 2704, + 2601, 2500, 2401, 2304, 2209, 2116, 2025, 1936, 1849, 1764, 1681, 1600, + 1521, 1444, 1369, 1296, 1225, 1156, 1089, 1024, 961, 900, 841, 784, + 729, 676, 625, 576, 529, 484, 441, 400, 361, 324, 289, 256, + 225, 196, 169, 144, 121, 100, 81, 64, 49, 36, 25, 16, + 9, 4, 1, 0, 1, 4, 9, 16, 25, 36, 49, 64, + 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, + 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, + 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, + 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, + 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, + 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400, + 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, + 8649, 8836, 9025, 9216, 9409, 9604, 9801, 10000, 10201, 10404, 10609, 10816, + 11025, 11236, 11449, 11664, 11881, 12100, 12321, 12544, 12769, 12996, 13225, 13456, + 13689, 13924, 14161, 14400, 14641, 14884, 15129, 15376, 15625, 15876, 16129, 16384, + 16641, 16900, 17161, 17424, 17689, 17956, 18225, 18496, 18769, 19044, 19321, 19600, + 19881, 20164, 20449, 20736, 21025, 21316, 21609, 21904, 22201, 22500, 22801, 23104, + 23409, 23716, 24025, 24336, 24649, 24964, 25281, 25600, 25921, 26244, 26569, 26896, + 27225, 27556, 27889, 28224, 28561, 28900, 29241, 29584, 29929, 30276, 30625, 30976, + 31329, 31684, 32041, 32400, 32761, 33124, 33489, 33856, 34225, 34596, 34969, 35344, + 35721, 36100, 36481, 36864, 37249, 37636, 38025, 38416, 38809, 39204, 39601, 40000, + 40401, 40804, 41209, 41616, 42025, 42436, 42849, 43264, 43681, 44100, 44521, 44944, + 45369, 45796, 46225, 46656, 47089, 47524, 47961, 48400, 48841, 49284, 49729, 50176, + 50625, 51076, 51529, 51984, 52441, 52900, 53361, 53824, 54289, 54756, 55225, 55696, + 56169, 56644, 57121, 57600, 58081, 58564, 59049, 59536, 60025, 60516, 61009, 61504, + 62001, 62500, 63001, 63504, 64009, 64516, 65025 +}; + +const uchar g_Saturate8u[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255 +}; + +const char* g_HersheyGlyphs[] = { + "", + "MWRMNV RMVV PSTS", + "MWOMOV OMSMUNUPSQ OQSQURUUSVOV", + "MXVNTMRMPNOPOSPURVTVVU", + "MWOMOV OMRMTNUPUSTURVOV", + "MWOMOV OMUM OQSQ OVUV", + "MVOMOV OMUM OQSQ", + "MXVNTMRMPNOPOSPURVTVVUVR SRVR", + "MWOMOV UMUV OQUQ", + "PTRMRV", + "NUSMSTRVPVOTOS", + "MWOMOV UMOS QQUV", + "MVOMOV OVUV", + "LXNMNV NMRV VMRV VMVV", + "MWOMOV OMUV UMUV", + "MXRMPNOPOSPURVSVUUVSVPUNSMRM", + "MWOMOV OMSMUNUQSROR", + "MXRMPNOPOSPURVSVUUVSVPUNSMRM STVW", + "MWOMOV OMSMUNUQSROR RRUV", + "MWUNSMQMONOOPPTRUSUUSVQVOU", + "MWRMRV NMVM", + "MXOMOSPURVSVUUVSVM", + "MWNMRV VMRV", + "LXNMPV RMPV RMTV VMTV", + "MWOMUV UMOV", + "MWNMRQRV VMRQ", + "MWUMOV OMUM OVUV", + "MWRMNV RMVV PSTS", + "MWOMOV OMSMUNUPSQ OQSQURUUSVOV", + "MVOMOV OMUM", + "MWRMNV RMVV NVVV", + "MWOMOV OMUM OQSQ OVUV", + "MWUMOV OMUM OVUV", + "MWOMOV UMUV OQUQ", + "MXRMPNOPOSPURVSVUUVSVPUNSMRM QQTR TQQR", + "PTRMRV", + "MWOMOV UMOS QQUV", + "MWRMNV RMVV", + "LXNMNV NMRV VMRV VMVV", + "MWOMOV OMUV UMUV", + "MWOMUM PQTR TQPR OVUV", + "MXRMPNOPOSPURVSVUUVSVPUNSMRM", + "MWOMOV UMUV OMUM", + "MWOMOV OMSMUNUQSROR", + "MWOMRQOV OMUM OVUV", + "MWRMRV NMVM", + "MWNONNOMPMQNRPRV VOVNUMTMSNRP", + "LXRMRV PONPNSPTTTVSVPTOPO", + "MWOMUV UMOV", + "LXRMRV NOOPOSQTSTUSUPVO", + "MXOVQVOROPPNRMSMUNVPVRTVVV", + "MWSMMV SMUV OSTS", + "MWQMNV QMTMVNVPSQPQ SQURUTTURVNV", + "LXVPUNTMRMPNOONQNSOUPVRVTUUT", + "MXQMNV QMUMVOVQUTTURVNV", + "MVQMNV QMVM PQSQ NVSV", + "MVQMNV QMVM PQSQ", + "LXVPUNTMRMPNOONQNSOUPVRVTUUSRS", + "MXQMNV WMTV PQUQ", + "PUTMQV", + "OVUMSSRUQVPVOUOT", + "MVQMNV VMOS RQTV", + "NVRMOV OVTV", + "LYPMMV PMQV XMQV XMUV", + "MXQMNV QMTV WMTV", + "LXRMPNOONQNSOUPVRVTUUTVRVPUNTMRM", + "MWQMNV QMUMVNVPUQSRPR", + "LXRMPNOONQNSOUPVRVTUUTVRVPUNTMRM QVPUPTQSRSSTTVUWVW", + "MWQMNV QMUMVNVPUQSRPR QRRUSVTVUU", + "MWVNTMRMPNPPQQTRUSUUSVPVNU", + "MVSMPV PMVM", + "LXPMNSNUOVRVTUUSWM", + "MWOMQV WMQV", + "KXNMNV SMNV SMSV XMSV", + "NWQMTV WMNV", + "NWQMSQQV WMSQ", + "MWQMWMNVTV", + "", + "", + "", + "", + "", + "", + "LXNMRV VMRV NMVM", + "MWNLVX", + "LXRONU ROVU", + "MWNVVV", + "PVRMUQ", + "MWMMOKQKTMVMWK", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "NWQPTPUQUV URQSPTPUQVSVUU", + "MWOMOV OSPURVTUUSTQRPPQOS", + "MWUQSPRPPQOSPURVSVUU", + "MWUMUV USTQRPPQOSPURVTUUS", + "MWOSUSTQRPPQOSPURVTV", + "NVUNTMSMRNRV PPTP", + "MWUPUVTXRYPY USTQRPPQOSPURVTUUS", + "MWOMOV OSPQRPTQUSUV", + "PTRLQMRNSMRL RPRV", + "PUSLRMSNTMSL SPSXRYQYPX", + "NWPMPV UPPT RSUV", + "PTRMRV", + "KYMPMV MSNQOPPPQQRSRV RSSQTPUPVQWSWV", + "MWOPOV OSPQRPTQUSUV", + "MWRPPQOSPURVTUUSTQRP", + "MWOPOY OSPURVTUUSTQRPPQOS", + "MWUPUY USTQRPPQOSPURVTUUS", + "NVPPPV PSQQSPTP", + "NWUQTPQPPQPRQSTSUTUUTVQVPU", + "NVRMRUSVTVUU PPTP", + "MWUPUV OPOSPURVTUUS", + "NVOPRV UPRV", + "LXNPPV RPPV RPTV VPTV", + "MWOPUV UPOV", + "MWOPRV UPRVQXPYOY", + "MWOPUPOVUV", + "MXVPUSTURVPUOSPQRPTQUUVV", + "MWOTQVSVTUTSSRPQRQTPUOUNTMRMQNPPOTNY", + "MXNQOPQPRQRSQW VPURSTQWPY", + "MWTNSMRMQNQORPTQUSTURVPUOSPQRP", + "NWUQSPQPPQPRQS SSQSPTPUQVSVUU", + "NWTMSNSOTP UPSPQQPSPUQVSWSXRYQY", + "LXNQOPPPQQQSPV QSRQTPUPVQVSUVTY", + "LXNQOPPPQQQURVSVTUUSVPVNUMTMSNSPTRUSWT", + "OVRPQSQURVSVTU", + "MWQPOV UPTPRQPS PSQUSVTV", + "MWOMPMQNRPUV RPOV", + "LYPPMY UPTSSUQVPVOUOS TSTUUVVVWU", + "MWNPOPOV UPTSRUOV", + "NWTMSNSOTP UPSPQQQRRSTS SSQTPUPVQWSXSYRZQZ", + "MWRPPQOSPURVTUUSTQRP", + "MXOQQPVP QPQRPV TPTRUV", + "MWOSPURVTUUSTQRPPQOSNY", + "MXVPRPPQOSPURVTUUSTQRP", + "MXOQQPVP SPRV", + "KXMQNPOPPQPUQVSVTUUSVP", + "MXPPOQOSPURVSVUUVSVQUPTPSQRSQY", + "MWOPPPQQSXTYUY UPTRPWOY", + "KYTMRY MQNPOPPQPUQVTVUUVSWP", + "LXOPNRNTOVQVRTRR UPVRVTUVSVRT", + "LWTSSQQPOQNSOUQVSUTS UPTSTUUVVV", + "MWQMOSPURVTUUSTQRPPQOS", + "MWUQSPRPPQOSPURVTV", + "LWTSSQQPOQNSOUQVSUTS VMTSTUUVVV", + "MWOSTSURUQSPRPPQOSPURVTV", + "OVVMUMTNSPQVPXOYNY QPUP", + "MXUSTQRPPQOSPURVTUUS VPTVSXRYPYOX", + "MVQMNV OSPQQPSPTQTRSTSUTVUV", + "PUSMSNTNTMSM QPRPSQSRRTRUSVTV", + "OUSMSNTNTMSM QPRPSQSRRVQXPYOYNX", + "NVRMOV UPTPRQPS PSQUSVTV", + "OTSMQSQURVSV", + "JYKPLPMQMSLV MSNQOPQPRQRSQV RSSQTPVPWQWRVTVUWVXV", + "MWNPOPPQPSOV PSQQRPTPUQURTTTUUVVV", + "MWRPPQOSPURVTUUSTQRP", + "MXNPOPPQPSNY PSQUSVUUVSUQSPQQPS", + "MXUSTQRPPQOSPURVTUUS VPSY", + "MVOPPPQQQSPV UQTPSPRQQS", + "NVTQSPQPPQPRQSRSSTSURVPVOU", + "NUSMQSQURVSV PPTP", + "MWNPOPPQPROTOUPVRVSUTS UPTSTUUVVV", + "MWNPOPPQPROTOUPVRVTUURUP", + "KYLPMPNQNRMTMUNVPVQURSSP RSRUSVUVVUWRWP", + "MWOQPPQPRQRUSVTVUU VQUPTPSQQUPVOVNU", + "MWNPOPPQPROTOUPVRVSUTS UPSVRXQYOYNX", + "NVUPOV PQQPSPTQ PUQVSVTU", + "", + "", + "", + "", + "", + "", + "MWUSTQRPPQOSPURVTUUSUPTNRMQM", + "MWUQSPRPPQOSPURVSVUU OSSS", + "MWRMQNPPOSOVPWRWSVTTUQUNTMRM PRTR", + "MWTMQY RPPQOSPURVSVUUVSUQSPRP", + "MWUQSPQPOQOSPTRUSVSWRXQX", + "", + "", + "KYTPTSUTVTWSWQVOUNSMQMONNOMQMSNUOVQWSWUV TQSPQPPQPSQTSTTS", + "MWUNORUV", + "MWONUROV", + "OUTKQKQYTY", + "OUPKSKSYPY", + "OUTKSLRNROSQQRSSRURVSXTY", + "OUPKQLRNROQQSRQSRURVQXPY", + "LYPMQNQOPPOPNONNOMPMSNUNWMNV USTTTUUVVVWUWTVSUS", + "PT", + "NV", + "MWRMPNOPOSPURVTUUSUPTNRM", + "MWPORMRV", + "MWONQMSMUNUPTROVUV", + "MWONQMSMUNUPSQ RQSQURUUSVQVOU", + "MWSMSV SMNSVS", + "MWPMOQQPRPTQUSTURVQVOU PMTM", + "MWTMRMPNOPOSPURVTUUSTQRPPQOS", + "MWUMQV OMUM", + "MWQMONOPQQSQUPUNSMQM QQOROUQVSVUUURSQ", + "MWUPTRRSPROPPNRMTNUPUSTURVPV", + "PURURVSVSURU", + "PUSVRVRUSUSWRY", + "PURPRQSQSPRP RURVSVSURU", + "PURPRQSQSPRP SVRVRUSUSWRY", + "PURMRR SMSR RURVSVSURU", + "NWPNRMSMUNUPRQRRSRSQUP RURVSVSURU", + "PTRMRQ", + "NVPMPQ TMTQ", + "NVQMPNPPQQSQTPTNSMQM", + "MWRKRX UNSMQMONOPQQTRUSUUSVQVOU", + "MWVLNX", + "OUTKRNQQQSRVTY", + "OUPKRNSQSSRVPY", + "PTRKRY", + "LXNRVR", + "LXRNRV NRVR", + "LXNPVP NTVT", + "MWOOUU UOOU", + "MWRORU OPUT UPOT", + "PURQRRSRSQRQ", + "PUSMRORQSQSPRP", + "PUSNRNRMSMSORQ", + "LXSOVRSU NRVR", + "MXQLQY TLTY OQVQ OTVT", + "LXVRURTSSURVOVNUNSORRQSPSNRMPMONOPQSSUUVVV", + "LXNNOQOSNV VNUQUSVV NNQOSOVN NVQUSUVV", + "LYRQQPOPNQNSOTQTRSSQTPVPWQWSVTTTSSRQ", + "", + "H\\NRMQLRMSNR VRWQXRWSVR", + "H\\MPLQLRMSNSOROQNPMP MQMRNRNQMQ WPVQVRWSXSYRYQXPWP WQWRXRXQWQ", + "I[KRYR", + "", + "H\\RUJPRTZPRU", + "", + "", + "", + "", + "", + "F^ISJQLPNPPQTTVUXUZT[Q ISJPLONOPPTSVTXTZS[Q IYJWLVNVPWTZV[X[ZZ[W IYJVLUNUPVTYVZXZZY[W", + "", + "F^ISJQLPNPPQTTVUXUZT[Q ISJPLONOPPTSVTXTZS[Q IW[W I[[[", + "", + "CaGO]OXI L[GU]U", + "", + "D`F^^^^FFFF^", + "", + "KYQVOUNSNQOOQNSNUOVQVSUUSVQV SVVS QVVQ OUUO NSSN NQQN", + "", + "H\\IR[R", + "H\\IR[R IQ[Q", + "", + "LYPFSCSP RDRP OPVP MRXR OVOWNWNVOUQTTTVUWWVYTZQ[O\\N^Na TTUUVWUYTZ N`O_P_S`V`W_ P_SaVaW_W^", + "LYPFSCSP RDRP OPVP MRXR OVOWNWNVOUQTTTVUWWVYTZ TTUUVWUYTZ RZTZV[W]W^V`TaQaO`N_N^O^O_ TZU[V]V^U`Ta", + "LYPFSCSP RDRP OPVP MRXR VVVWWWWVVUTTRTPUOVNYN^O`QaTaV`W^W\\VZTYQYN[ RTPVOYO^P`Qa TaU`V^V\\UZTY", + "LYPFSCSP RDRP OPVP MRXR QTOUNWOYQZTZVYWWVUTTQT QTPUOWPYQZ TZUYVWUUTT QZO[N]N^O`QaTaV`W^W]V[TZ QZP[O]O^P`Qa TaU`V^V]U[TZ", + "LYOEOFNFNEODQCTCVDWFVHTIQJOKNMNP TCUDVFUHTI NOONPNSOVOWN PNSPVPWNWM MRXR OVOWNWNVOUQTTTVUWWVYTZ TTUUVWUYTZ RZTZV[W]W^V`TaQaO`N_N^O^O_ TZU[V]V^U`Ta", + "LYOEOFNFNEODQCTCVDWFVHTI TCUDVFUHTI RITIVJWLWMVOTPQPOONNNMOMON TIUJVLVMUOTP MRXR QTOUNWOYQZTZVYWWVUTTQT QTPUOWPYQZ TZUYVWUUTT QZO[N]N^O`QaTaV`W^W]V[TZ QZP[O]O^P`Qa TaU`V^V]U[TZ", + "LYOCNI OCVC ODSDVC NIOHQGTGVHWJWMVOTPQPOONNNMOMON TGUHVJVMUOTP MRXR QTOUNWOYQZTZVYWWVUTTQT QTPUOWPYQZ TZUYVWUUTT QZO[N]N^O`QaTaV`W^W]V[TZ QZP[O]O^P`Qa TaU`V^V]U[TZ", + "LYNCNG VERLPP WCTIQP NEPCRCUE NEPDRDUEVE MRXR QTOUNWOYQZTZVYWWVUTTQT QTPUOWPYQZ TZUYVWUUTT QZO[N]N^O`QaTaV`W^W]V[TZ QZP[O]O^P`Qa TaU`V^V]U[TZ", + "LYOCNI OCVC ODSDVC NIOHQGTGVHWJWMVOTPQPOONNNMOMON TGUHVJVMUOTP MRXR VVVWWWWVVUTTRTPUOVNYN^O`QaTaV`W^W\\VZTYQYN[ RTPVOYO^P`Qa TaU`V^V\\UZTY", + "LYPFSCSP RDRP OPVP MRXR SVSa TTTa TTM]X] QaVa", + "LYOEOFNFNEODQCTCVDWFVHTI TCUDVFUHTI RITIVJWLWMVOTPQPOONNNMOMON TIUJVLVMUOTP MRXR SVSa TTTa TTM]X] QaVa", + "F^YXWZU[R[PZMXKWIWHXHZI[K[MZOWPURQTKWGYFZF[G\\H[IZH[G[FZFYFWGVHTLRPPVNZMZ OPUP", + "E^P[MZJXHUGRGOHLJIMGPFTFWGYI[L\\O\\R[UYXVZS[P[ NJNW OJOW LJSJVKWMWNVPSQOQ SJUKVMVNUPSQ LWQW SQTRUVVWWWXV SQURVVWW", + "E^P[MZJXHUGRGOHLJIMGPFTFWGYI[L\\O\\R[UYXVZS[P[ UKVJVNUKSJPJNKMLLOLRMUNVPWSWUVVT PJNLMOMRNUPW", + "E_IM[M IR[R IW[W K[YI", + "CaHQGRHSIRHQ RQQRRSSRRQ \\Q[R\\S]R\\Q", + "", + "E_NWLTIRLPNM LPJRLT JRZR VWXT[RXPVM XPZRXT", + "JZWNTLRIPLMN PLRJTL RJRZ WVTXR[PXMV PXRZTX", + "F^ZJSJOKMLKNJQJSKVMXOYSZZZ SFS^", + "F^JJQJUKWLYNZQZSYVWXUYQZJZ QFQ^", + "F^JJQJUKWLYNZQZSYVWXUYQZJZ ORZR", + "", + "H\\LBL[ RBR[ XBX[", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "I[RFJ[ RFZ[ MTWT", + "G\\KFK[ KFTFWGXHYJYLXNWOTP KPTPWQXRYTYWXYWZT[K[", + "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZV", + "G\\KFK[ KFRFUGWIXKYNYSXVWXUZR[K[", + "H[LFL[ LFYF LPTP L[Y[", + "HZLFL[ LFYF LPTP", + "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZVZS USZS", + "G]KFK[ YFY[ KPYP", + "NVRFR[", + "JZVFVVUYTZR[P[NZMYLVLT", + "G\\KFK[ YFKT POY[", + "HYLFL[ L[X[", + "F^JFJ[ JFR[ ZFR[ ZFZ[", + "G]KFK[ KFY[ YFY[", + "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF", + "G\\KFK[ KFTFWGXHYJYMXOWPTQKQ", + "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF SWY]", + "G\\KFK[ KFTFWGXHYJYLXNWOTPKP RPY[", + "H\\YIWGTFPFMGKIKKLMMNOOUQWRXSYUYXWZT[P[MZKX", + "JZRFR[ KFYF", + "G]KFKULXNZQ[S[VZXXYUYF", + "I[JFR[ ZFR[", + "F^HFM[ RFM[ RFW[ \\FW[", + "H\\KFY[ YFK[", + "I[JFRPR[ ZFRP", + "H\\YFK[ KFYF K[Y[", + "I[RFJ[ RFZ[ MTWT", + "G\\KFK[ KFTFWGXHYJYLXNWOTP KPTPWQXRYTYWXYWZT[K[", + "HYLFL[ LFXF", + "I[RFJ[ RFZ[ J[Z[", + "H[LFL[ LFYF LPTP L[Y[", + "H\\YFK[ KFYF K[Y[", + "G]KFK[ YFY[ KPYP", + "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF OPUP", + "NVRFR[", + "G\\KFK[ YFKT POY[", + "I[RFJ[ RFZ[", + "F^JFJ[ JFR[ ZFR[ ZFZ[", + "G]KFK[ KFY[ YFY[", + "I[KFYF OPUP K[Y[", + "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF", + "G]KFK[ YFY[ KFYF", + "G\\KFK[ KFTFWGXHYJYMXOWPTQKQ", + "I[KFRPK[ KFYF K[Y[", + "JZRFR[ KFYF", + "I[KKKILGMFOFPGQIRMR[ YKYIXGWFUFTGSIRM", + "H\\RFR[ PKMLLMKOKRLTMUPVTVWUXTYRYOXMWLTKPK", + "H\\KFY[ K[YF", + "G]RFR[ ILJLKMLQMSNTQUSUVTWSXQYMZL[L", + "H\\K[O[LTKPKLLINGQFSFVGXIYLYPXTU[Y[", + "G[G[IZLWOSSLVFV[UXSUQSNQLQKRKTLVNXQZT[Y[", + "F]SHTITLSPRSQUOXMZK[J[IZIWJRKOLMNJPHRGUFXFZG[I[KZMYNWOTP SPTPWQXRYTYWXYWZU[R[PZOX", + "H\\TLTMUNWNYMZKZIYGWFTFQGOIMLLNKRKVLYMZO[Q[TZVXWV", + "G^TFRGQIPMOSNVMXKZI[G[FZFXGWIWKXMZP[S[VZXXZT[O[KZHYGWFTFRHRJSMUPWRZT\\U", + "H\\VJVKWLYLZKZIYGVFRFOGNINLONPOSPPPMQLRKTKWLYMZP[S[VZXXYV", + "H\\RLPLNKMINGQFTFXG[G]F XGVNTTRXPZN[L[JZIXIVJULUNV QPZP", + "G^G[IZMVPQQNRJRGQFPFOGNINLONQOUOXNYMZKZQYVXXVZS[O[LZJXIVIT", + "F^MMKLJJJIKGMFNFPGQIQKPONULYJ[H[GZGX MRVOXN[L]J^H^G]F\\FZHXLVRUWUZV[W[YZZY\\V", + "IZWVUTSQROQLQIRGSFUFVGWIWLVQTVSXQZO[M[KZJXJVKUMUOV", + "JYT^R[PVOPOJPGRFTFUGVJVMURR[PaOdNfLgKfKdLaN^P\\SZWX", + "F^MMKLJJJIKGMFNFPGQIQKPONULYJ[H[GZGX ^I^G]F\\FZGXIVLTNROPO ROSQSXTZU[V[XZYY[V", + "I\\MRORSQVOXMYKYHXFVFUGTISNRSQVPXNZL[J[IZIXJWLWNXQZT[V[YZ[X", + "@aEMCLBJBICGEFFFHGIIIKHPGTE[ GTJLLHMGOFPFRGSISKRPQTO[ QTTLVHWGYFZF\\G]I]K\\PZWZZ[[\\[^Z_YaV", + "E]JMHLGJGIHGJFKFMGNINKMPLTJ[ LTOLQHRGTFVFXGYIYKXPVWVZW[X[ZZ[Y]V", + "H]TFQGOIMLLNKRKVLYMZO[Q[TZVXXUYSZOZKYHXGVFTFRHRKSNUQWSZU\\V", + "F_SHTITLSPRSQUOXMZK[J[IZIWJRKOLMNJPHRGUFZF\\G]H^J^M]O\\PZQWQUPTO", + "H^ULTNSOQPOPNNNLOIQGTFWFYGZIZMYPWSSWPYNZK[I[HZHXIWKWMXPZS[V[YZ[X", + "F_SHTITLSPRSQUOXMZK[J[IZIWJRKOLMNJPHRGUFYF[G\\H]J]M\\O[PYQVQSPTQUSUXVZX[ZZ[Y]V", + "H\\H[JZLXOTQQSMTJTGSFRFQGPIPKQMSOVQXSYUYWXYWZT[P[MZKXJVJT", + "H[RLPLNKMINGQFTFXG[G]F XGVNTTRXPZN[L[JZIXIVJULUNV", + "E]JMHLGJGIHGJFKFMGNINKMOLRKVKXLZN[P[RZSYUUXMZF XMWQVWVZW[X[ZZ[Y]V", + "F]KMILHJHIIGKFLFNGOIOKNOMRLVLYM[O[QZTWVTXPYMZIZGYFXFWGVIVKWNYP[Q", + "C_HMFLEJEIFGHFIFKGLILLK[ UFK[ UFS[ aF_G\\JYNVTS[", + "F^NLLLKKKILGNFPFRGSISLQUQXRZT[V[XZYXYVXUVU ]I]G\\FZFXGVITLPUNXLZJ[H[GZGX", + "F]KMILHJHIIGKFLFNGOIOKNOMRLVLXMZN[P[RZTXVUWSYM [FYMVWT]RbPfNgMfMdNaP^S[VY[V", + "H]ULTNSOQPOPNNNLOIQGTFWFYGZIZMYPWTTWPZN[K[JZJXKWNWPXQYR[R^QaPcNfLgKfKdLaN^Q[TYZV", + "", + "", + "", + "", + "", + "", + "I[JFR[ ZFR[ JFZF", + "G]IL[b", + "E_RJIZ RJ[Z", + "I[J[Z[", + "I[J[Z[ZZJZJ[", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "I\\XMX[ XPVNTMQMONMPLSLUMXOZQ[T[VZXX", + "H[LFL[ LPNNPMSMUNWPXSXUWXUZS[P[NZLX", + "I[XPVNTMQMONMPLSLUMXOZQ[T[VZXX", + "I\\XFX[ XPVNTMQMONMPLSLUMXOZQ[T[VZXX", + "I[LSXSXQWOVNTMQMONMPLSLUMXOZQ[T[VZXX", + "MYWFUFSGRJR[ OMVM", + "I\\XMX]W`VaTbQbOa XPVNTMQMONMPLSLUMXOZQ[T[VZXX", + "I\\MFM[ MQPNRMUMWNXQX[", + "NVQFRGSFREQF RMR[", + "MWRFSGTFSERF SMS^RaPbNb", + "IZMFM[ WMMW QSX[", + "NVRFR[", + "CaGMG[ GQJNLMOMQNRQR[ RQUNWMZM\\N]Q][", + "I\\MMM[ MQPNRMUMWNXQX[", + "I\\QMONMPLSLUMXOZQ[T[VZXXYUYSXPVNTMQM", + "H[LMLb LPNNPMSMUNWPXSXUWXUZS[P[NZLX", + "I\\XMXb XPVNTMQMONMPLSLUMXOZQ[T[VZXX", + "KXOMO[ OSPPRNTMWM", + "J[XPWNTMQMNNMPNRPSUTWUXWXXWZT[Q[NZMX", + "MYRFRWSZU[W[ OMVM", + "I\\MMMWNZP[S[UZXW XMX[", + "JZLMR[ XMR[", + "G]JMN[ RMN[ RMV[ ZMV[", + "J[MMX[ XMM[", + "JZLMR[ XMR[P_NaLbKb", + "J[XMM[ MMXM M[X[", + "H]QMONMPLRKUKXLZN[P[RZUWWTYPZM QMSMTNUPWXXZY[Z[", + "I\\UFSGQIOMNPMTLZKb UFWFYHYKXMWNUORO ROTPVRWTWWVYUZS[Q[OZNYMV", + "I\\JPLNNMOMQNROSRSVR[ ZMYPXRR[P_Ob", + "I[TMQMONMPLSLVMYNZP[R[TZVXWUWRVOTMRKQIQGRFTFVGXI", + "JZWOVNTMQMONOPPRSS SSOTMVMXNZP[S[UZWX", + "JYTFRGQHQIRJUKXK XKTMQONRMUMWNYP[S]T_TaSbQbP`", + "H\\IQJOLMNMONOPNTL[ NTPPRNTMVMXOXRWWTb", + "G\\HQIOKMMMNNNPMUMXNZO[Q[SZUWVUWRXMXJWGUFSFRHRJSMUPWRZT", + "LWRMPTOXOZP[R[TYUW", + "I[OMK[ YNXMWMUNQROSNS NSPTQUSZT[U[VZ", + "JZKFMFOGPHX[ RML[", + "H]OMIb NQMVMYO[Q[SZUXWT YMWTVXVZW[Y[[Y\\W", + "I[LMOMNSMXL[ YMXPWRUURXOZL[", + "JZTFRGQHQIRJUKXK UKRLPMOOOQQSTTVT TTPUNVMXMZO\\S^T_TaRbPb", + "J[RMPNNPMSMVNYOZQ[S[UZWXXUXRWOVNTMRM", + "G]PML[ UMVSWXX[ IPKNNM[M", + "I[MSMVNYOZQ[S[UZWXXUXRWOVNTMRMPNNPMSIb", + "I][MQMONMPLSLVMYNZP[R[TZVXWUWRVOUNSM", + "H\\SMP[ JPLNOMZM", + "H\\IQJOLMNMONOPMVMYO[Q[TZVXXTYPYM", + "G]ONMOKQJTJWKYLZN[Q[TZWXYUZRZOXMVMTORSPXMb", + "I[KMMMOOU`WbYb ZMYOWRM]K`Jb", + "F]VFNb GQHOJMLMMNMPLULXMZO[Q[TZVXXUZP[M", + "F]NMLNJQITIWJZK[M[OZQW RSQWRZS[U[WZYWZTZQYNXM", + "L\\UUTSRRPRNSMTLVLXMZO[Q[SZTXVRUWUZV[W[YZZY\\V", + "M[MVOSRNSLTITGSFQGPIOMNTNZO[P[RZTXUUURVVWWYW[V", + "MXTTTSSRQROSNTMVMXNZP[S[VYXV", + "L\\UUTSRRPRNSMTLVLXMZO[Q[SZTXZF VRUWUZV[W[YZZY\\V", + "NXOYQXRWSUSSRRQROSNUNXOZQ[S[UZVYXV", + "OWOVSQUNVLWIWGVFTGSIQQNZKaJdJfKgMfNcOZP[R[TZUYWV", + "L[UUTSRRPRNSMTLVLXMZO[Q[SZTY VRTYPdOfMgLfLdMaP^S\\U[XY[V", + "M\\MVOSRNSLTITGSFQGPIOMNSM[ M[NXOVQSSRURVSVUUXUZV[W[YZZY\\V", + "PWSMSNTNTMSM PVRRPXPZQ[R[TZUYWV", + "PWSMSNTNTMSM PVRRLdKfIgHfHdIaL^O\\Q[TYWV", + "M[MVOSRNSLTITGSFQGPIOMNSM[ M[NXOVQSSRURVSVUTVQV QVSWTZU[V[XZYY[V", + "OWOVQSTNULVIVGUFSGRIQMPTPZQ[R[TZUYWV", + "E^EVGSIRJSJTIXH[ IXJVLSNRPRQSQTPXO[ PXQVSSURWRXSXUWXWZX[Y[[Z\\Y^V", + "J\\JVLSNROSOTNXM[ NXOVQSSRURVSVUUXUZV[W[YZZY\\V", + "LZRRPRNSMTLVLXMZO[Q[SZTYUWUUTSRRQSQURWTXWXYWZV", + "KZKVMSNQMUGg MUNSPRRRTSUUUWTYSZQ[ MZO[R[UZWYZV", + "L[UUTSRRPRNSMTLVLXMZO[Q[SZ VRUUSZPaOdOfPgRfScS\\U[XY[V", + "MZMVOSPQPSSSTTTVSYSZT[U[WZXYZV", + "NYNVPSQQQSSVTXTZR[ NZP[T[VZWYYV", + "OXOVQSSO VFPXPZQ[S[UZVYXV PNWN", + "L[LVNRLXLZM[O[QZSXUU VRTXTZU[V[XZYY[V", + "L[LVNRMWMZN[O[RZTXUUUR URVVWWYW[V", + "I^LRJTIWIYJ[L[NZPX RRPXPZQ[S[UZWXXUXR XRYVZW\\W^V", + "JZJVLSNRPRQSQZR[U[XYZV WSVRTRSSOZN[L[KZ", + "L[LVNRLXLZM[O[QZSXUU VRPdOfMgLfLdMaP^S\\U[XY[V", + "LZLVNSPRRRTTTVSXQZN[P\\Q^QaPdOfMgLfLdMaP^S\\WYZV", + "J\\K[NZQXSVUSWOXKXIWGUFSGRHQJPOPTQXRZT[V[XZYY", + "", + "", + "", + "", + "", + "I[WUWRVOUNSMQMONMPLSLVMYNZP[R[TZVXWUXPXKWHVGTFRFPGNI", + "JZWNUMRMPNNPMSMVNYOZQ[T[VZ MTUT", + "J[TFRGPJOLNOMTMXNZO[Q[SZUWVUWRXMXIWGVFTF NPWP", + "H\\VFNb QMNNLPKSKVLXNZQ[S[VZXXYUYRXPVNSMQM", + "I[XOWNTMQMNNMOLQLSMUOWSZT\\T^S_Q_", + "", + "", + "DaWNVLTKQKOLNMMOMRNTOUQVTVVUWS WKWSXUYV[V\\U]S]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYY", + "F^ZIJRZ[", + "F^JIZRJ[", + "KYOBOb OBVB ObVb", + "KYUBUb NBUB NbUb", + "KYTBQEPHPJQMSOSPORSTSUQWPZP\\Q_Tb", + "KYPBSETHTJSMQOQPURQTQUSWTZT\\S_Pb", + "F^[FYGVHSHPGNFLFJGIIIKKMMMOLPJPHNF [FI[ YTWTUUTWTYV[X[ZZ[X[VYT", + "NV", + "JZ", + "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF", + "H\\NJPISFS[", + "H\\LKLJMHNGPFTFVGWHXJXLWNUQK[Y[", + "H\\MFXFRNUNWOXPYSYUXXVZS[P[MZLYKW", + "H\\UFKTZT UFU[", + "H\\WFMFLOMNPMSMVNXPYSYUXXVZS[P[MZLYKW", + "H\\XIWGTFRFOGMJLOLTMXOZR[S[VZXXYUYTXQVOSNRNOOMQLT", + "H\\YFO[ KFYF", + "H\\PFMGLILKMMONSOVPXRYTYWXYWZT[P[MZLYKWKTLRNPQOUNWMXKXIWGTFPF", + "H\\XMWPURRSQSNRLPKMKLLINGQFRFUGWIXMXRWWUZR[P[MZLX", + "MWRYQZR[SZRY", + "MWSZR[QZRYSZS\\R^Q_", + "MWRMQNROSNRM RYQZR[SZRY", + "MWRMQNROSNRM SZR[QZRYSZS\\R^Q_", + "MWRFRT RYQZR[SZRY", + "I[LKLJMHNGPFTFVGWHXJXLWNVORQRT RYQZR[SZRY", + "NVRFRM", + "JZNFNM VFVM", + "KYQFOGNINKOMQNSNUMVKVIUGSFQF", + "H\\PBP_ TBT_ YIWGTFPFMGKIKKLMMNOOUQWRXSYUYXWZT[P[MZKX", + "G][BIb", + "KYVBTDRGPKOPOTPYR]T`Vb", + "KYNBPDRGTKUPUTTYR]P`Nb", + "NVRBRb", + "E_IR[R", + "E_RIR[ IR[R", + "E_IO[O IU[U", + "G]KKYY YKKY", + "JZRLRX MOWU WOMU", + "MWRQQRRSSRRQ", + "MWSFRGQIQKRLSKRJ", + "MWRHQGRFSGSIRKQL", + "E_UMXP[RXTUW IR[R", + "G]OFOb UFUb JQZQ JWZW", + "E_\\O\\N[MZMYNXPVUTXRZP[L[JZIYHWHUISJRQNRMSKSIRGPFNGMIMKNNPQUXWZY[[[\\Z\\Y", + "G]IIJKKOKUJYI[ [IZKYOYUZY[[ IIKJOKUKYJ[I I[KZOYUYYZ[[", + "F_\\Q[OYNWNUOTPQTPUNVLVJUISIQJOLNNNPOQPTTUUWVYV[U\\S\\Q", + "KYOBO[ UBU[", + "F^RBR[ I[[[", + "F^[BI[[[", + "E_RIQJRKSJRI IYHZI[JZIY [YZZ[[\\Z[Y", + "F^RHNLKPJSJUKWMXOXQWRU RHVLYPZSZUYWWXUXSWRU RUQYP\\ RUSYT\\ P\\T\\", + "F^RNQKPINHMHKIJKJOKRLTNWR\\ RNSKTIVHWHYIZKZOYRXTVWR\\", + "F^RGPJLOIR RGTJXO[R IRLUPZR] [RXUTZR]", + "F^RTTWVXXXZW[U[SZQXPVPSQ SQUOVMVKUISHQHOINKNMOOQQ QQNPLPJQISIUJWLXNXPWRT RTQYP\\ RTSYT\\ P\\T\\", + "F^RRR[Q\\ RVQ\\ RIQHOHNINKONRR RISHUHVIVKUNRR RRNOLNJNIOIQJR RRVOXNZN[O[QZR RRNULVJVIUISJR RRVUXVZV[U[SZR", + "F^ISJSLTMVMXLZ ISIRJQLQMRNTNWMYLZ RGPIOLOOQUQXPZR\\ RGTIULUOSUSXTZR\\ [S[RZQXQWRVTVWWYXZ [SZSXTWVWXXZ KVYV", + "", + "", + "", + "PSSRRSQSPRPQQPRPSQSSRUQV QQQRRRRQQQ", + "PTQPPQPSQTSTTSTQSPQP RQQRRSSRRQ", + "NVPOTU TOPU NRVR", + "MWRKQMOPMR RKSMUPWR RMOQ RMUQ ROPQ ROTQ QQSQ MRWR", + "MWMRMQNOONQMSMUNVOWQWR PNTN OOUO NPVP NQVQ MRWR", + "LRLFLRRRLF LIPQ LLOR LOMQ", + "MWRKQMOPMR RKSMUPWR", + "MWWRWQVOUNSMQMONNOMQMR", + "G]]R]P\\MZJWHTGPGMHJJHMGPGR", + "MWMRMSNUOVQWSWUVVUWSWR", + "LXLPNRQSSSVRXP", + "RURUTTURTPRO", + "RVRRUPVNVLUKTK", + "NRRROPNNNLOKPK", + "MWWHVGTFQFOGNHMJMLNNOOUSVTWVWXVZU[S\\P\\N[MZ", + "G]IWHVGTGQHOINKMMMONPOTUUVWWYW[V\\U]S]P\\N[M", + "G]RRTUUVWWYW[V\\U]S]Q\\O[NYMWMUNTOPUOVMWKWIVHUGSGQHOINKMMMONPORR", + "H\\KFK[ HF[FQP[Z ZV[Y\\[ ZVZY WYZY WYZZ\\[", + "KYUARBPCNELHKLKRLUNWQXSXVWXUYR KPLMNKQJSJVKXMYPYVXZV]T_R`Oa", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + ">f>RfR", + "D`D``D", + "RRR>Rf", + "D`DD``", + "D`DR`R", + "F^FY^K", + "KYK^YF", + "", + "KYKFY^", + "F^FK^Y", + "KYKRYR", + "MWMWWM", + "", + "MWMMWW", + "", + "", + "", + "", + "D`DOGQKSPTTTYS]Q`O", + "PUUDSGQKPPPTQYS]U`", + "OTODQGSKTPTTSYQ]O`", + "D`DUGSKQPPTPYQ]S`U", + "KYRJYNKVRZ", + "JZJRNKVYZR", + "KYKVKNYVYN", + "JZLXJPZTXL", + "JZJ]L]O\\Q[TXUVVSVOULTJSIQIPJOLNONSOVPXS[U\\X]Z]", + "I]]Z]X\\U[SXPVOSNONLOJPIQISJTLUOVSVVUXT[Q\\O]L]J", + "JZZGXGUHSIPLONNQNUOXPZQ[S[TZUXVUVQUNTLQIOHLGJG", + "G[GJGLHOIQLTNUQVUVXUZT[S[QZPXOUNQNNOLPISHUGXGZ", + "E[EPFRHTJUMVQVUUXSZP[NZLWLSMQNNPLSKVKYL\\M^", + "EYETHVKWPWSVVTXQYNYLXKVKSLPNNQMTMYN\\P_", + "OUQOOQOSQUSUUSUQSOQO QPPQPSQTSTTSTQSPQP RQQRRSSRRQ", + "", + "D`DRJR ORUR ZR`R", + "D`DUDO`O`U", + "JZRDJR RDZR", + "D`DR`R JYZY P`T`", + "D`DR`R DRRb `RRb", + "", + "", + "", + "", + "", + "KYQKNLLNKQKSLVNXQYSYVXXVYSYQXNVLSKQK", + "LXLLLXXXXLLL", + "KYRJKVYVRJ", + "LXRHLRR\\XRRH", + "JZRIPOJOOSMYRUWYUSZOTORI", + "KYRKRY KRYR", + "MWMMWW WMMW", + "MWRLRX MOWU WOMU", + "", + "", + "NVQNOONQNSOUQVSVUUVSVQUOSNQN OQOS PPPT QOQU RORU SOSU TPTT UQUS", + "NVNNNVVVVNNN OOOU POPU QOQU RORU SOSU TOTU UOUU", + "MWRLMUWURL ROOT ROUT RRQT RRST", + "LULRUWUMLR ORTU ORTO RRTS RRTQ", + "MWRXWOMORX RUUP RUOP RRSP RRQP", + "OXXROMOWXR URPO URPU RRPQ RRPS", + "LXRLNWXPLPVWRL RRRL RRLP RRNW RRVW RRXP", + "", + "", + "", + "MWRLRX OOUO MUOWQXSXUWWU", + "LXRLRX LQMOWOXQ PWTW", + "KYMNWX WNMX OLLOKQ ULXOYQ", + "I[NII[ VI[[ MM[[ WMI[ NIVI MMWM", + "I[RGRV MJWP WJMP IVL\\ [VX\\ IV[V L\\X\\", + "G[MJSV KPSL G\\[\\[RG\\", + "LXPLPPLPLTPTPXTXTTXTXPTPTLPL", + "KYYPXNVLSKQKNLLNKQKSLVNXQYSYVXXVYT YPWNUMSMQNPOOQOSPUQVSWUWWVYT", + "KYRJKVYVRJ RZYNKNRZ", + "G]PIPGQFSFTGTI GZHXJVKTLPLKMJOIUIWJXKXPYTZV\\X]Z GZ]Z QZP[Q\\S\\T[SZ", + "JZRMRS RSQ\\ RSS\\ Q\\S\\ RMQJPHNG QJNG RMSJTHVG SJVG RMNKLKJM PLLLJM RMVKXKZM TLXLZM RMPNOOOR RMPOOR RMTNUOUR RMTOUR", + "JZRIRK RNRP RSRU RYQ\\ RYS\\ Q\\S\\ RGQIPJ RGSITJ PJRITJ RKPNNOMN RKTNVOWN NOPORNTOVO RPPSNTLTKRKSLT RPTSVTXTYRYSXT NTPTRSTTVT RUPXOYMZLZKYJWJYLZ RUTXUYWZXZYYZWZYXZ MZOZRYUZWZ", + "JZRYQ\\ RYS\\ Q\\S\\ RYUZXZZXZUYTWTYRZOYMWLUMVJUHSGQGOHNJOMMLKMJOKRMTKTJUJXLZOZRY", + "JZRYQ\\ RYS\\ Q\\S\\ RYVXVVXUXRZQZLYIXHVHTGPGNHLHKIJLJQLRLUNVNXRY", + "I[IPKR LKNP RGRO XKVP [PYR", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "QSRQQRRSSRRQ", + "PTQPPQPSQTSTTSTQSPQP", + "NVQNOONQNSOUQVSVUUVSVQUOSNQN", + "MWQMONNOMQMSNUOVQWSWUVVUWSWQVOUNSMQM", + "KYQKNLLNKQKSLVNXQYSYVXXVYSYQXNVLSKQK", + "G]PGMHJJHMGPGTHWJZM\\P]T]W\\ZZ\\W]T]P\\MZJWHTGPG", + "AcPALBJCGEEGCJBLAPATBXCZE]G_JaLbPcTcXbZa]__]aZbXcTcPbLaJ_G]EZCXBTAPA", + "fRAPCMDJDGCEA>H@JAMAZB]D_G`M`PaRc RATCWDZD]C_AfHdJcMcZb]`_]`W`TaRc", + "AcRAPCMDJDGCEABGAKAPBTDXG\\L`Rc RATCWDZD]C_AbGcKcPbT`X]\\X`Rc BHbH", + "H[WPVQWRXQXPVNTMQMNNLPKSKULXNZQ[S[VZXX QMONMPLSLUMXOZQ[ LbXF", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "KYRKMX RNVX RKWX OTTT KXPX TXYX", + "JZNKNX OKOX LKSKVLWNVPSQ SKULVNUPSQ OQSQVRWTWUVWSXLX SQURVTVUUWSX", + "KYVLWKWOVLTKQKOLNMMPMSNVOWQXTXVWWU QKOMNPNSOVQX", + "JZNKNX OKOX LKSKVLWMXPXSWVVWSXLX SKULVMWPWSVVUWSX", + "JYNKNX OKOX SOSS LKVKVOUK OQSQ LXVXVTUX", + "JXNKNX OKOX SOSS LKVKVOUK OQSQ LXQX", + "K[VLWKWOVLTKQKOLNMMPMSNVOWQXTXVW QKOMNPNSOVQX TXUWVU VSVX WSWX TSYS", + "J[NKNX OKOX VKVX WKWX LKQK TKYK OQVQ LXQX TXYX", + "NWRKRX SKSX PKUK PXUX", + "LXSKSURWQX TKTUSWQXPXNWMUNTOUNV QKVK", + "JZNKNX OKOX WKOS QQVX RQWX LKQK TKYK LXQX TXYX", + "KXOKOX PKPX MKRK MXWXWTVX", + "I\\MKMX NNRX NKRU WKRX WKWX XKXX KKNK WKZK KXOX UXZX", + "JZNKNX OMVX OKVV VKVX LKOK TKXK LXPX", + "KZQKOLNMMPMSNVOWQXTXVWWVXSXPWMVLTKQK QKOMNPNSOVQX TXVVWSWPVMTK", + "JYNKNX OKOX LKSKVLWNWOVQSROR SKULVNVOUQSR LXQX", + "KZQKOLNMMPMSNVOWQXTXVWWVXSXPWMVLTKQK QKOMNPNSOVQX TXVVWSWPVMTK PWPUQTSTTUUZV[W[XZ TUUXVZW[", + "JZNKNX OKOX LKSKVLWNWOVQSROR SKULVNVOUQSR LXQX SRTSUWVXWXXW SRUSVWWX", + "KZVMWKWOVMULSKQKOLNMNOOPQQTRVSWT NNOOQPTQVRWSWVVWTXRXPWOVNTNXOV", + "KZRKRX SKSX NKMOMKXKXOWK PXUX", + "J[NKNUOWQXTXVWWUWK OKOUPWQX LKQK UKYK", + "KYMKRX NKRU WKRX KKPK TKYK", + "I[LKOX MKOT RKOX RKUX SKUT XKUX JKOK VKZK", + "KZNKVX OKWX WKNX LKQK TKYK LXQX TXYX", + "LYNKRRRX OKSR WKSRSX LKQK TKYK PXUX", + "LYVKNX WKOX OKNONKWK NXWXWTVX", + "KYRKMX RNVX RKWX OTTT KXPX TXYX", + "JZNKNX OKOX LKSKVLWNVPSQ SKULVNUPSQ OQSQVRWTWUVWSXLX SQURVTVUUWSX", + "KXOKOX PKPX MKWKWOVK MXRX", + "KYRKLX RMWX RKXX MWVW LXXX", + "JYNKNX OKOX SOSS LKVKVOUK OQSQ LXVXVTUX", + "LYVKNX WKOX OKNONKWK NXWXWTVX", + "J[NKNX OKOX VKVX WKWX LKQK TKYK OQVQ LXQX TXYX", + "KZQKOLNMMPMSNVOWQXTXVWWVXSXPWMVLTKQK QKOMNPNSOVQX TXVVWSWPVMTK QOQT TOTT QQTQ QRTR", + "NWRKRX SKSX PKUK PXUX", + "JZNKNX OKOX WKOS QQVX RQWX LKQK TKYK LXQX TXYX", + "KYRKMX RNVX RKWX KXPX TXYX", + "I\\MKMX NNRX NKRU WKRX WKWX XKXX KKNK WKZK KXOX UXZX", + "JZNKNX OMVX OKVV VKVX LKOK TKXK LXPX", + "JZMJLM XJWM PPOS UPTS MVLY XVWY MKWK MLWL PQTQ PRTR MWWW MXWX", + "KZQKOLNMMPMSNVOWQXTXVWWVXSXPWMVLTKQK QKOMNPNSOVQX TXVVWSWPVMTK", + "J[NKNX OKOX VKVX WKWX LKYK LXQX TXYX", + "JYNKNX OKOX LKSKVLWNWOVQSROR SKULVNVOUQSR LXQX", + "K[MKRQ NKSQMX MKWKXOVK NWWW MXWXXTVX", + "KZRKRX SKSX NKMOMKXKXOWK PXUX", + "KZMONLOKPKQLRORX XOWLVKUKTLSOSX MONMOLPLQMRO XOWMVLULTMSO PXUX", + "KZRKRX SKSX QNNOMQMRNTQUTUWTXRXQWOTNQN QNOONQNROTQU TUVTWRWQVOTN PKUK PXUX", + "KZNKVX OKWX WKNX LKQK TKYK LXQX TXYX", + "J[RKRX SKSX LPMONOOSQU TUVSWOXOYP MONROTQUTUVTWRXO PKUK PXUX", + "KZMVNXQXMRMONMOLQKTKVLWMXOXRTXWXXV OUNRNOOMQK TKVMWOWRVU NWPW UWWW", + "KYTKKX SMTX TKUX NTTT IXNX RXWX", + "JYPKLX QKMX NKUKWLWNVPSQ UKVLVNUPSQ OQRQTRUSUUTWQXJX RQTSTUSWQX", + "KXVLWLXKWNVLTKRKPLOMNOMRMUNWPXRXTWUU RKPMOONRNVPX", + "JYPKLX QKMX NKTKVLWNWQVTUVTWQXJX TKULVNVQUTTVSWQX", + "JYPKLX QKMX SORS NKXKWNWK OQRQ JXTXUUSX", + "JXPKLX QKMX SORS NKXKWNWK OQRQ JXOX", + "KYVLWLXKWNVLTKRKPLOMNOMRMUNWPXRXTWUVVS RKPMOONRNVPX RXTVUS SSXS", + "J[PKLX QKMX XKTX YKUX NKSK VK[K OQVQ JXOX RXWX", + "NWTKPX UKQX RKWK NXSX", + "LXUKRUQWPX VKSURWPXOXMWLUMTNUMV SKXK", + "JZPKLX QKMX YKOR RPTX SPUX NKSK VK[K JXOX RXWX", + "KXQKMX RKNX OKTK KXUXVUTX", + "I\\OKKX OMPX PKQV YKPX YKUX ZKVX MKPK YK\\K IXMX SXXX", + "JZPKLX PKTX QKTU XKTX NKQK VKZK JXNX", + "KYRKPLOMNOMRMUNWPXRXTWUVVTWQWNVLTKRK RKPMOONRNVPX RXTVUTVQVMTK", + "JYPKLX QKMX NKUKWLXMXOWQTROR UKWMWOVQTR JXOX", + "KYRKPLOMNOMRMUNWPXRXTWUVVTWQWNVLTKRK RKPMOONRNVPX RXTVUTVQVMTK OWOVPUQURVRZS[T[UZ RVSZT[", + "JZPKLX QKMX NKUKWLXMXOWQTROR UKWMWOVQTR SRTWUXVXWW SRTSUWVX JXOX", + "KZWLXLYKXNWLUKRKPLOMOOPPUSVT ONPOURVSVVUWSXPXNWMULXMWNW", + "KZTKPX UKQX PKNNOKZKYNYK NXSX", + "J[PKMUMWOXSXUWVUYK QKNUNWOX NKSK WK[K", + "KYOKPX PKQV YKPX MKRK VK[K", + "I[NKMX OKNV TKMX TKSX UKTV ZKSX LKQK XK\\K", + "KZPKTX QKUX YKLX NKSK VK[K JXOX RXWX", + "LYPKRQPX QKSQ YKSQQX NKSK VK[K NXSX", + "LYXKLX YKMX QKONPKYK LXUXVUTX", + "", + "", + "", + "", + "", + "", + "", + "KZMHX\\", + "JZRMLW RMXW", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "LZQOPPPQOQOPQOTOVQVWWXXX TOUQUWWX URRSPTOUOWPXSXTWUU RSPUPWQX", + "JYNKNX OKOX ORPPROTOVPWRWUVWTXRXPWOU TOUPVRVUUWTX LKOK", + "LXVQUQURVRVQUPSOQOOPNRNUOWQXSXUWVV QOPPOROUPWQX", + "L[VKVX WKWX VRUPSOQOOPNRNUOWQXSXUWVU QOPPOROUPWQX TKWK VXYX", + "LXOSVSVRUPSOQOOPNRNUOWQXSXUWVV USUQSO QOPPOROUPWQX", + "LWTKULUMVMVLTKRKPMPX RKQMQX NOSO NXSX", + "LYQOOQOSQUSUUSUQSOQO QOPQPSQU SUTSTQSO TPUOVO PTOUOXPYTYVZ OWPXTXVYV[T\\P\\N[NYPX", + "J[NKNX OKOX ORPPROTOVPWRWX TOUPVRVX LKOK LXQX TXYX", + "NWRKRLSLSKRK RORX SOSX POSO PXUX", + "NWSKSLTLTKSK SOSZR\\ TOTZR\\P\\O[OZPZP[O[ QOTO", + "JZNKNX OKOX WOOU RSVX SSWX LKOK TOYO LXQX TXYX", + "NWRKRX SKSX PKSK PXUX", + "F_JOJX KOKX KRLPNOPORPSRSX POQPRRRX SRTPVOXOZP[R[X XOYPZRZX HOKO HXMX PXUX XX]X", + "J[NONX OOOX ORPPROTOVPWRWX TOUPVRVX LOOO LXQX TXYX", + "LYQOOPNRNUOWQXTXVWWUWRVPTOQO QOPPOROUPWQX TXUWVUVRUPTO", + "JYNON\\ OOO\\ ORPPROTOVPWRWUVWTXRXPWOU TOUPVRVUUWTX LOOO L\\Q\\", + "KYUOU\\ VOV\\ URTPROPONPMRMUNWPXRXTWUU POOPNRNUOWPX S\\X\\", + "KXOOOX POPX PRQPSOUOVPVQUQUPVP MOPO MXRX", + "LYTOUPUQVQVPTOQOOPORQSTTVU OQQRTSVTVWTXQXOWOVPVPWQX", + "LWPKPVRXTXUWUV QKQVRX NOTO", + "J[NONUOWQXSXUWVU OOOUPWQX VOVX WOWX LOOO TOWO VXYX", + "KYNORX OORV VORX LOQO TOXO", + "I[LOOX MOOU ROOX ROUX SOUU XOUX JOOO VOZO", + "KYNOUX OOVX VONX LOQO TOXO LXPX SXXX", + "KYNORX OORV VORXP[N\\M\\L[LZMZM[L[ LOQO TOXO", + "LXUONX VOOX OONQNOVO NXVXVVUX", + "K[QOOPNQMSMUNWPXQXSWUUWRXO QOOQNSNUOWPX QOSOUPWWXX SOTPVWXXYX", + "KXRKPMOOMUK\\ QLPNNTL\\ RKTKVLVNUPRQ TKULUNTPRQ RQTRUTUVTWRXQXOWNT RQSRTTTVRX", + "KYLQNOPORPSSSXR\\ LQNPPPRQSS WOVRSXQ\\", + "KYSOQOOPNQMSMUNWPXRXTWUVVTVRUPRNQLQKRJTJUKVM QOOQNSNVPX RXTVUTUQSO QLRKTKVM", + "LXVPTOQOOPOQPRRS QOPPPQRS RSOTNUNWPXSXUW RSPTOUOWPX", + "LWRKQLQMSNVNVMSNPOOPNRNTOVPWRXSYS[R\\P\\O[ SNQOPPOROTPVRX", + "IYJRKPLONOOPOQMX MONPNQLX OQPPROTOVPVRS\\ TOUPURR\\", + "IYJSKQLPNPOQOVPX MPNQNUOWPXQXSWTVUTVQVNULTKRKQLQNRPURWS QXSVTTUQUNTK", + "NWROPVPWQXSXUWVU SOQVQWRX", + "KYOOLX POMX UOVPWPVOTORQOR ORPSRWTXVWWU ORQSSWTX", + "LXLKNKPLWX NKOLVX RPMX RPNX", + "KZOOK\\ POL\\ NUNWOXQXSWTV VOTVTWUXWXXWYU WOUVUWVX", + "JYNOMX OONUMX VRVOWOVRTUQWNXMX LOOO", + "MXRKQLQMSNVN TNQOPPPRRSUS TNROQPQRRS SSPTOUOWQXSYTZT[S\\Q\\ SSQTPUPWQX", + "KXQOOPNQMSMUNWPXRXTWUVVTVRUPSOQO QOOQNSNVPX RXTVUTUQSO", + "IZPPMX PPNX TPSX TPTX KQMOXO KQMPXP", + "JXSOQOOPNQMSJ\\ QOOQNSK\\ SOUPVRVTUVTWRXPXNWMU SOUQUTTVRX", + "K[YOQOOPNQMSMUNWPXRXTWUVVTVRUPYP QOOQNSNVPX RXTVUTUQSO", + "KZSPQX SPRX MQOOXO MQOPXP", + "JXKRLPMOOOPPPROUOWPX NOOPORNUNWPXQXSWUUVRVOUOVP", + "KZOPNQMSMUNWPXRXUWWUXRXPWOUOTPSRRUO\\ MUNVPWRWUVWTXR XQWPUPSR RUQXP\\", + "KXMONOPPS[T\\ NOOPR[T\\U\\ VOTRNYL\\", + "I[TKQ\\ UKP\\ JRKPLONOOPOVPWSWUVWT MONPNTOWPXSXUWWTXRYO", + "JZNPPPPONPMQLSLUMWNXPXQWRUSR LUNWPWRU RRRWSXUXWVXTXRWPVOVPWP RUSWUWWV", + "KZVOTVTWUXWXXWYU WOUVUWVX USUQSOQOOPNQMSMUNWPXRXTV QOOQNSNVPX", + "JXOKMR PKNRNVPX NROPQOSOUPVRVTUVTWRXPXNWMUMR SOUQUTTVRX MKPK", + "KXUPUQVQUPSOQOOPNQMSMUNWPXRXTWUV QOOQNSNVPX", + "KZWKTVTWUXWXXWYU XKUVUWVX USUQSOQOOPNQMSMUNWPXRXTV QOOQNSNVPX UKXK", + "KWNURTTSURUPSOQOOPNQMSMUNWPXRXTWUV QOOQNSNVPX", + "MXWKXLXKVKTLSNPYO[N\\ VKULTNQYP[N\\L\\L[M\\ POVO", + "KYVOTVSYR[ WOUVTYR[P\\M\\L[M[N\\ USUQSOQOOPNQMSMUNWPXRXTV QOOQNSNVPX", + "KZPKLX QKMX OQPPROTOVPVRUUUWVX TOUPURTUTWUXWXXWYU NKQK", + "MWSKSLTLTKSK NROPPOROSPSRRURWSX QORPRRQUQWRXTXUWVU", + "MWTKTLULUKTK ORPPQOSOTPTRRYQ[O\\M\\M[N\\ ROSPSRQYP[O\\", + "KXPKLX QKMX VPUQVQVPUOTORQPROR ORPSQWRXTXUWVU ORQSRWSX NKQK", + "NVSKPVPWQXSXTWUU TKQVQWRX QKTK", + "F^GRHPIOKOLPLQJX JOKPKQIX LQMPOOQOSPSQQX QORPRQPX SQTPVOXOZPZRYUYWZX XOYPYRXUXWYX[X\\W]U", + "J[KRLPMOOOPPPQNX NOOPOQMX PQQPSOUOWPWRVUVWWX UOVPVRUUUWVXXXYWZU", + "KXQOOPNQMSMUNWPXRXTWUVVTVRUPSOQO QOOQNSNVPX RXTVUTUQSO", + "JYKRLPMOOOPPPQM\\ NOOPOQL\\ PQROTOVPWRWTVVUWSXQXOVOT TOVQVTUVSX J\\O\\", + "KYVOR\\ WOS\\ USUQSOQOOPNQMSMUNWPXRXTV QOOQNSNVPX P\\U\\", + "LXMRNPOOQORPRQPX POQPQQOX RQSPUOVOWPWQVQWP", + "LYVPVQWQVPTOQOOPORQSTTVU OQQRTSVTVWTXQXOWNVOVOW", + "NWSKPVPWQXSXTWUU TKQVQWRX POUO", + "IZJRKPLONOOPORNUNWOX MONPNRMUMWOXQXSWTV VOTVTWUXWXXWYU WOUVUWVX", + "JXKRLPMOOOPPPROUOWPX NOOPORNUNWPXQXSWUUVRVOUOVP", + "H\\IRJPKOMONPNRMUMWNX LOMPMRLULWNXOXQWRV TORVRWTX UOSVSWTXUXWWYUZRZOYOZP", + "JZMRNPPOROSPSR QORPRRQUPWNXMXLWLVMVLW XPWQXQXPWOVOTPSRRURWSX QUQWRXTXVWWU", + "IYJRKPLONOOPORNUNWOX MONPNRMUMWOXQXSWTV VOTVSYR[ WOUVTYR[P\\M\\L[M[N\\", + "KYWOWPVQNVMWMX NQOOROUQ OPRPUQVQ NVOVRWUW OVRXUXVV", + "H[RKSLSMTMTLRKOKMLLNLX OKNLMNMX XKYLYMZMZLXKVKTMTX VKUMUX JOWO JXOX RXWX", + "J[UKVLWLWKQKOLNNNX QKPLONOX VOVX WOWX LOWO LXQX TXYX", + "J[WKQKOLNNNX QKPLONOX UKVLVX WKWX LOVO LXQX TXYX", + "F_PKQLQMRMRLPKMKKLJNJX MKLLKNKX YKZL[L[KUKSLRNRX UKTLSNSX ZOZX [O[X HO[O HXMX PXUX XX]X", + "F_PKQLQMRMRLPKMKKLJNJX MKLLKNKX [KUKSLRNRX UKTLSNSX YKZLZX [K[X HOZO HXMX PXUX XX]X", + "NWRORX SOSX POSO PXUX", + "", + "LXVPTOROPPOQNSNUOWQXSXUW ROPQOSOVQX OSSS", + "LYSKQLPMOONRNUOWPXRXTWUVVTWQWNVLUKSK SKQMPOOSOVPX RXTVUTVPVMUK OQVQ", + "KZTKQ\\ UKP\\ QONPMRMUNWQXTXWWXUXRWPTOQO QOOPNRNUOWQX TXVWWUWRVPTO", + "LXUPVRVQUPSOQOOPNRNTOVRX QOOQOTPVRXSYS[R\\P\\", + "", + "", + "", + "I[VKWLXLVKSKQLPMOOLYK[J\\ SKQMPOMYL[J\\H\\H[I\\ ZK[L[KYKWLVNSYR[Q\\ YKXLWNTYS[Q\\O\\O[P\\ LOYO", + "IZVKWLXLXKSKQLPMOOLYK[J\\ SKQMPOMYL[J\\H\\H[I\\ VOTVTWUXWXXWYU WOUVUWVX LOWO", + "IZVKWL XKSKQLPMOOLYK[J\\ SKQMPOMYL[J\\H\\H[I\\ WKTVTWUXWXXWYU XKUVUWVX LOVO", + "F^SKTLTM ULSKPKNLMMLOIYH[G\\ PKNMMOJYI[G\\E\\E[F\\ ZK[L\\L\\KWKUL TMSOPYO[N\\ WKUMTOQYP[N\\L\\L[M\\ ZOXVXWYX[X\\W]U [OYVYWZX IO[O", + "F^SKTLTM ULSKPKNLMMLOIYH[G\\ PKNMMOJYI[G\\E\\E[F\\ ZK[L \\KWKUL TMSOPYO[N\\ WKUMTOQYP[N\\L\\L[M\\ [KXVXWYX[X\\W]U \\KYVYWZX IOZO", + "MWNROPPOROSPSRRURWSX QORPRRQUQWRXTXUWVU", + "", + "OU", + "LX", + "LYQKOLNONTOWQXTXVWWTWOVLTKQK QKPLOOOTPWQX TXUWVTVOULTK", + "LYPNSKSX RLRX OXVX", + "LYOMONNNNMOLQKTKVLWNVPTQQROSNUNX TKULVNUPTQ NWOVPVSWVWWV PVSXVXWVWU", + "LYOMONNNNMOLQKTKVLWNVPTQ TKULVNUPTQ RQTQVRWTWUVWTXQXOWNVNUOUOV TQURVTVUUWTX", + "LYSMSX TKTX TKMTXT QXVX", + "LYOKNQ OKVK OLSLVK NQOPQOTOVPWRWUVWTXQXOWNVNUOUOV TOUPVRVUUWTX", + "LYVMVNWNWMVLTKRKPLOMNPNUOWQXTXVWWUWSVQTPQPNR RKPMOPOUPWQX TXUWVUVSUQTP", + "LYNKNO VMRTPX WKTQQX NMPKRKUM NMPLRLUMVM", + "LYQKOLNNOPQQTQVPWNVLTKQK QKPLONPPQQ TQUPVNULTK QQORNTNUOWQXTXVWWUWTVRTQ QQPROTOUPWQX TXUWVUVTURTQ", + "LYOVOUNUNVOWQXSXUWVVWSWNVLTKQKOLNNNPORQSTSWQ SXUVVSVNULTK QKPLONOPPRQS", + "NVRVQWRXSWRV", + "NVSWRXQWRVSWSYQ[", + "NVROQPRQSPRO RVQWRXSWRV", + "NVROQPRQSPRO SWRXQWRVSWSYQ[", + "NVRKQLRSSLRK RLRO RVQWRXSWRV", + "LYNNONOONONNOLQKTKVLWNWOVQSRRSRTST TKVMVPUQSR RWRXSXSWRW", + "OVRKRP SKRP", + "LXOKOP PKOP UKUP VKUP", + "MWQKPLPNQOSOTNTLSKQK", + "MWRJRP OKUO UKOO", + "KZXHM\\", + "MWUHSJQMPPPTQWSZU\\ SJRLQPQTRXSZ", + "MWOHQJSMTPTTSWQZO\\ QJRLSPSTRXQZ", + "MWPHP\\ QHQ\\ PHUH P\\U\\", + "MWSHS\\ THT\\ OHTH O\\T\\", + "LWSHRIQKQMRORPPRRTRUQWQYR[S\\ RIQM QKRO RUQY QWR[", + "MXQHRISKSMRORPTRRTRUSWSYR[Q\\ RISM SKRO RUSY SWR[", + "MWTHPRT\\", + "MWPHTRP\\", + "OURHR\\", + "MWPHP\\ THT\\", + "I[LRXR", + "I[RLRX LRXR", + "JZRMRX MRWR MXWX", + "JZRMRX MMWM MRWR", + "JZMMWW WMMW", + "NVRQQRRSSRRQ", + "I[RLQMRNSMRL LRXR RVQWRXSWRV", + "I[LPXP LTXT", + "I[WLMX LPXP LTXT", + "I[LNXN LRXR LVXV", + "JZWLMRWX", + "JZMLWRMX", + "JZWKMOWS MTWT MXWX", + "JZMKWOMS MTWT MXWX", + "H[YUWUUTTSRPQOONNNLOKQKRLTNUOUQTRSTPUOWNYN", + "JZLTLRMPOPUSWSXR LRMQOQUTWTXRXP", + "JZMSRPWS MSRQWS", + "NVSKPO SKTLPO", + "NVQKTO QKPLTO", + "LXNKOMQNSNUMVK NKONQOSOUNVK", + "NVSLRMQLRKSLSNQP", + "NVSKQMQORPSORNQO", + "NVQLRMSLRKQLQNSP", + "NVQKSMSORPQORNSO", + "", + "JZWMQMONNOMQMSNUOVQWWW", + "JZMMMSNUOVQWSWUVVUWSWM", + "JZMMSMUNVOWQWSVUUVSWMW", + "JZMWMQNOONQMSMUNVOWQWW", + "JZWMQMONNOMQMSNUOVQWWW MRUR", + "I[TOUPXRUTTU UPWRUT LRWR", + "MWRMRX OPPORLTOUP PORMTO", + "I[POOPLROTPU OPMROT MRXR", + "MWRLRW OTPURXTUUT PURWTU", + "KYVSUPSOQOOPNQMSMUNWPXRXTWUVVTWQWNVLTKQKPLQLRK QOOQNSNVPX RXTVUTVQVNULTK", + "JZLKRX MKRV XKRX LKXK NLWL", + "G[IOLORW KORX [FRX", + "I[XIXJYJYIXHVHTJSLROQUPYO[ UITKSORUQXPZN\\L\\K[KZLZL[", + "I[XIXJYJYIXHVHTJSLROQUPYO[ UITKSORUQXPZN\\L\\K[KZLZL[ QNOONQNSOUQVSVUUVSVQUOSNQN", + "H\\ZRYTWUVUTTSSQPPONNMNKOJQJRKTMUNUPTQSSPTOVNWNYOZQZR", + "JZXKLX OKPLPNOOMOLNLLMKOKSLVLXK UTTUTWUXWXXWXUWTUT", + "J[YPXPXQYQYPXOWOVPUTTVSWQXOXMWLVLTMSORRPSNSLRKPKOLONPQUWWXXXYW OXMVMTOR ONPPVWWX", + "J[UPSOQOPQPRQTSTUS UOUSVTXTYRYQXNVLSKRKOLMNLQLRMUOWRXSXVW", + "KZQHQ\\ THT\\ WLVLVMWMWLUKPKNLNNOPVSWT NNOOVRWTWVVWTXQXOWNVNUOUOVNV", + "KYPKP[ TKT[ MQWQ MUWU", + "LXTLSLSMTMTLSKQKPLPNQPTRUS PNQOTQUSUUSW QPOROTPVSXTY OTPUSWTYT[S\\Q\\P[PZQZQ[P[", + "LXRKQLRMSLRK RMRQ RQQSRVSSRQ RVR\\ POONNOOPPOTOUNVOUPTO", + "LXRMSLRKQLRMRQQRSURV RQSRQURVRZQ[R\\S[RZ POONNOOPPOTOUNVOUPTO PXOWNXOYPXTXUWVXUYTX", + "LYVKVX NKVK QQVQ NXVX", + "", + "H\\QKNLLNKQKSLVNXQYSYVXXVYSYQXNVLSKQK RQQRRSSRRQ", + "LYQKPLPMQN TKULUMTN RNPOOQORPTRUSUUTVRVQUOSNRN RURY SUSY OWVW", + "LYRKPLONOOPQRRSRUQVOVNULSKRK RRRX SRSX OUVU", + "H\\QKNLLNKQKSLVNXQYSYVXXVYSYQXNVLSKQK RKRY KRYR", + "JYRRPQOQMRLTLUMWOXPXRWSUSTRR WMRR RMWMWR RMVNWR", + "JZLLMKOKQLRNRPQRPSNT OKPLQNQQPS VKUX WKTX NTXT", + "JYNKNU OKNR NROPQOSOUPVQVTTVTXUYVYWX SOUQUTTV LKOK", + "LYONRKRQ VNSKSQ RQPROTOUPWRXSXUWVUVTURSQ RTRUSUSTRT", + "JZRKRY MKMPNRPSTSVRWPWK LMMKNM QMRKSM VMWKXM OVUV", + "JYNKNX OKOX LKSKVLWNWOVQSROR SKULVNVOUQSR LXVXVUUX", + "LYWKTKQLONNQNSOVQXTYWY WKTLRNQQQSRVTXWY", + "JZRRPQOQMRLTLUMWOXPXRWSUSTRR SLQQ WMRR XQSS", + "KYPMTW TMPW MPWT WPMT", + "J[OUMULVLXMYOYPXPVNTMRMONMOLQKTKVLWMXOXRWTUVUXVYXYYXYVXUVU NMPLULWM", + "J[OOMOLNLLMKOKPLPNNPMRMUNWOXQYTYVXWWXUXRWPUNULVKXKYLYNXOVO NWPXUXWW", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "F^KHK\\ LHL\\ XHX\\ YHY\\ HH\\H H\\O\\ U\\\\\\", + "H]KHRQJ\\ JHQQ JHYHZMXH K[X[ J\\Y\\ZWX\\", + "KYVBTDRGPKOPOTPYR]T`Vb TDRHQKPPPTQYR\\T`", + "KYNBPDRGTKUPUTTYR]P`Nb PDRHSKTPTTSYR\\P`", + "KYOBOb PBPb OBVB ObVb", + "KYTBTb UBUb NBUB NbUb", + "JYTBQEPHPJQMSOSPORSTSUQWPZP\\Q_Tb RDQGQKRN RVQYQ]R`", + "KZPBSETHTJSMQOQPURQTQUSWTZT\\S_Pb RDSGSKRN RVSYS]R`", + "KYU@RCPFOIOLPOSVTYT\\S_Ra RCQEPHPKQNTUUXU[T^RaOd", + "KYO@RCTFUIULTOQVPYP\\Q_Ra RCSETHTKSNPUOXO[P^RaUd", + "AXCRGRR` GSRa FSRb X:Rb", + "F^[CZD[E\\D\\C[BYBWCUETGSJRNPZO^N` VDUFTJRVQZP]O_MaKbIbHaH`I_J`Ia", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "H\\RFK[ RFY[ RIX[ MUVU I[O[ U[[[", + "G]LFL[ MFM[ IFUFXGYHZJZLYNXOUP UFWGXHYJYLXNWOUP MPUPXQYRZTZWYYXZU[I[ UPWQXRYTYWXYWZU[", + "G\\XIYLYFXIVGSFQFNGLIKKJNJSKVLXNZQ[S[VZXXYV QFOGMILKKNKSLVMXOZQ[", + "G]LFL[ MFM[ IFSFVGXIYKZNZSYVXXVZS[I[ SFUGWIXKYNYSXVWXUZS[", + "G\\LFL[ MFM[ SLST IFYFYLXF MPSP I[Y[YUX[", + "G[LFL[ MFM[ SLST IFYFYLXF MPSP I[P[", + "G^XIYLYFXIVGSFQFNGLIKKJNJSKVLXNZQ[S[VZXX QFOGMILKKNKSLVMXOZQ[ XSX[ YSY[ US\\S", + "F^KFK[ LFL[ XFX[ YFY[ HFOF UF\\F LPXP H[O[ U[\\[", + "MXRFR[ SFS[ OFVF O[V[", + "KZUFUWTZR[P[NZMXMVNUOVNW TFTWSZR[ QFXF", + "F\\KFK[ LFL[ YFLS QOY[ POX[ HFOF UF[F H[O[ U[[[", + "I[NFN[ OFO[ KFRF K[Z[ZUY[", + "F_KFK[ LFRX KFR[ YFR[ YFY[ ZFZ[ HFLF YF]F H[N[ V[][", + "G^LFL[ MFYY MHY[ YFY[ IFMF VF\\F I[O[", + "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF QFOGMILKKOKRLVMXOZQ[ S[UZWXXVYRYOXKWIUGSF", + "G]LFL[ MFM[ IFUFXGYHZJZMYOXPUQMQ UFWGXHYJYMXOWPUQ I[P[", + "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF QFOGMILKKOKRLVMXOZQ[ S[UZWXXVYRYOXKWIUGSF NYNXOVQURUTVUXV_W`Y`Z^Z] UXV\\W^X_Y_Z^", + "G]LFL[ MFM[ IFUFXGYHZJZLYNXOUPMP UFWGXHYJYLXNWOUP I[P[ RPTQURXYYZZZ[Y TQUSWZX[Z[[Y[X", + "H\\XIYFYLXIVGSFPFMGKIKKLMMNOOUQWRYT KKMMONUPWQXRYTYXWZT[Q[NZLXKUK[LX", + "I\\RFR[ SFS[ LFKLKFZFZLYF O[V[", + "F^KFKULXNZQ[S[VZXXYUYF LFLUMXOZQ[ HFOF VF\\F", + "H\\KFR[ LFRX YFR[ IFOF UF[F", + "F^JFN[ KFNV RFN[ RFV[ SFVV ZFV[ GFNF WF]F", + "H\\KFX[ LFY[ YFK[ IFOF UF[F I[O[ U[[[", + "H]KFRQR[ LFSQS[ ZFSQ IFOF VF\\F O[V[", + "H\\XFK[ YFL[ LFKLKFYF K[Y[YUX[", + "H\\RFK[ RFY[ RIX[ MUVU I[O[ U[[[", + "G]LFL[ MFM[ IFUFXGYHZJZLYNXOUP UFWGXHYJYLXNWOUP MPUPXQYRZTZWYYXZU[I[ UPWQXRYTYWXYWZU[", + "I[NFN[ OFO[ KFZFZLYF K[R[", + "H\\RFJ[ RFZ[ RIY[ KZYZ J[Z[", + "G\\LFL[ MFM[ SLST IFYFYLXF MPSP I[Y[YUX[", + "H\\XFK[ YFL[ LFKLKFYF K[Y[YUX[", + "F^KFK[ LFL[ XFX[ YFY[ HFOF UF\\F LPXP H[O[ U[\\[", + "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF QFOGMILKKOKRLVMXOZQ[ S[UZWXXVYRYOXKWIUGSF OMOT UMUT OPUP OQUQ", + "MXRFR[ SFS[ OFVF O[V[", + "F\\KFK[ LFL[ YFLS QOY[ POX[ HFOF UF[F H[O[ U[[[", + "H\\RFK[ RFY[ RIX[ I[O[ U[[[", + "F_KFK[ LFRX KFR[ YFR[ YFY[ ZFZ[ HFLF YF]F H[N[ V[][", + "G^LFL[ MFYY MHY[ YFY[ IFMF VF\\F I[O[", + "G]KEJJ ZEYJ ONNS VNUS KWJ\\ ZWY\\ KGYG KHYH OPUP OQUQ KYYY KZYZ", + "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF QFOGMILKKOKRLVMXOZQ[ S[UZWXXVYRYOXKWIUGSF", + "F^KFK[ LFL[ XFX[ YFY[ HF\\F H[O[ U[\\[", + "G]LFL[ MFM[ IFUFXGYHZJZMYOXPUQMQ UFWGXHYJYMXOWPUQ I[P[", + "H]KFRPJ[ JFQP JFYFZLXF KZXZ J[Y[ZUX[", + "I\\RFR[ SFS[ LFKLKFZFZLYF O[V[", + "I\\KKKILGMFOFPGQIRMR[ KIMGOGQI ZKZIYGXFVFUGTISMS[ ZIXGVGTI O[V[", + "H]RFR[ SFS[ PKMLLMKOKRLTMUPVUVXUYTZRZOYMXLUKPK PKNLMMLOLRMTNUPV UVWUXTYRYOXMWLUK OFVF O[V[", + "H\\KFX[ LFY[ YFK[ IFOF UF[F I[O[ U[[[", + "G^RFR[ SFS[ IMJLLMMQNSOTQU JLKMLQMSNTQUTUWTXSYQZM[L TUVTWSXQYM[L\\M OFVF O[V[", + "G]JXK[O[MWKSJPJLKIMGPFTFWGYIZLZPYSWWU[Y[ZX MWLTKPKLLINGPF TFVGXIYLYPXTWW KZNZ VZYZ", + "H\\UFH[ UFV[ THU[ LUUU F[L[ R[X[", + "F^OFI[ PFJ[ LFWFZG[I[KZNYOVP WFYGZIZKYNXOVP MPVPXQYSYUXXVZR[F[ VPWQXSXUWXUZR[", + "H]ZH[H\\F[L[JZHYGWFTFQGOIMLLOKSKVLYMZP[S[UZWXXV TFRGPINLMOLSLVMYNZP[", + "F]OFI[ PFJ[ LFUFXGYHZKZOYSWWUYSZO[F[ UFWGXHYKYOXSVWTYRZO[", + "F]OFI[ PFJ[ TLRT LF[FZLZF MPSP F[U[WVT[", + "F\\OFI[ PFJ[ TLRT LF[FZLZF MPSP F[M[", + "H^ZH[H\\F[L[JZHYGWFTFQGOIMLLOKSKVLYMZP[R[UZWXYT TFRGPINLMOLSLVMYNZP[ R[TZVXXT UT\\T", + "E_NFH[ OFI[ [FU[ \\FV[ KFRF XF_F LPXP E[L[ R[Y[", + "LYUFO[ VFP[ RFYF L[S[", + "I[XFSWRYQZO[M[KZJXJVKULVKW WFRWQYO[ TF[F", + "F]OFI[ PFJ[ ]FLS SOW[ ROV[ LFSF YF_F F[M[ S[Y[", + "H\\QFK[ RFL[ NFUF H[W[YUV[", + "E`NFH[ NFO[ OFPY \\FO[ \\FV[ ]FW[ KFOF \\F`F E[K[ S[Z[", + "F_OFI[ OFVX OIV[ \\FV[ LFOF YF_F F[L[", + "G]SFPGNILLKOJSJVKYLZN[Q[TZVXXUYRZNZKYHXGVFSF SFQGOIMLLOKSKVLYN[ Q[SZUXWUXRYNYKXHVF", + "F]OFI[ PFJ[ LFXF[G\\I\\K[NYPUQMQ XFZG[I[KZNXPUQ F[M[", + "G]SFPGNILLKOJSJVKYLZN[Q[TZVXXUYRZNZKYHXGVFSF SFQGOIMLLOKSKVLYN[ Q[SZUXWUXRYNYKXHVF LYLXMVOUPURVSXS_T`V`W^W] SXT^U_V_W^", + "F^OFI[ PFJ[ LFWFZG[I[KZNYOVPMP WFYGZIZKYNXOVP RPTQURVZW[Y[ZYZX URWYXZYZZY F[M[", + "G^ZH[H\\F[L[JZHYGVFRFOGMIMKNMONVRXT MKOMVQWRXTXWWYVZS[O[LZKYJWJUI[JYKY", + "H]UFO[ VFP[ OFLLNF]F\\L\\F L[S[", + "F_NFKQJUJXKZN[R[UZWXXU\\F OFLQKUKXLZN[ KFRF YF_F", + "H\\NFO[ OFPY \\FO[ LFRF XF^F", + "E_MFK[ NFLY UFK[ UFS[ VFTY ]FS[ JFQF ZF`F", + "G]NFU[ OFV[ \\FH[ LFRF XF^F F[L[ R[X[", + "H]NFRPO[ OFSPP[ ]FSP LFRF YF_F L[S[", + "G][FH[ \\FI[ OFLLNF\\F H[V[XUU[", + "H\\KILKXWYYY[ LLXX KIKKLMXYY[ PPLTKVKXLZK[ KVMZ LTLVMXMZK[ SSXN VIVLWNYNYLWKVI VIWLYN", + "H\\QIK[ SIY[ RIX[ MUVU I[O[ U[[[ QBOCNENGOIQJSJUIVGVEUCSBQB", + "", + "", + "", + "", + "", + "G]IB[b", + "F^RJIZ RJ[Z", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "I]NONPMPMONNPMTMVNWOXQXXYZZ[ WOWXXZZ[[[ WQVRPSMTLVLXMZP[S[UZWX PSNTMVMXNZP[", + "G\\LFL[ MFM[ MPONQMSMVNXPYSYUXXVZS[Q[OZMX SMUNWPXSXUWXUZS[ IFMF", + "H[WPVQWRXQXPVNTMQMNNLPKSKULXNZQ[S[VZXX QMONMPLSLUMXOZQ[", + "H]WFW[ XFX[ WPUNSMQMNNLPKSKULXNZQ[S[UZWX QMONMPLSLUMXOZQ[ TFXF W[[[", + "H[LSXSXQWOVNTMQMNNLPKSKULXNZQ[S[VZXX WSWPVN QMONMPLSLUMXOZQ[", + "KXUGTHUIVHVGUFSFQGPIP[ SFRGQIQ[ MMUM M[T[", + "I\\QMONNOMQMSNUOVQWSWUVVUWSWQVOUNSMQM ONNPNTOV UVVTVPUN VOWNYMYNWN NUMVLXLYM[P\\U\\X]Y^ LYMZP[U[X\\Y^Y_XaUbObLaK_K^L\\O[", + "G]LFL[ MFM[ MPONRMTMWNXPX[ TMVNWPW[ IFMF I[P[ T[[[", + "MXRFQGRHSGRF RMR[ SMS[ OMSM O[V[", + "MXSFRGSHTGSF TMT_SaQbObNaN`O_P`Oa SMS_RaQb PMTM", + "G\\LFL[ MFM[ WMMW RSX[ QSW[ IFMF TMZM I[P[ T[Z[", + "MXRFR[ SFS[ OFSF O[V[", + "BcGMG[ HMH[ HPJNMMOMRNSPS[ OMQNRPR[ SPUNXMZM]N^P^[ ZM\\N]P][ DMHM D[K[ O[V[ Z[a[", + "G]LML[ MMM[ MPONRMTMWNXPX[ TMVNWPW[ IMMM I[P[ T[[[", + "H\\QMNNLPKSKULXNZQ[S[VZXXYUYSXPVNSMQM QMONMPLSLUMXOZQ[ S[UZWXXUXSWPUNSM", + "G\\LMLb MMMb MPONQMSMVNXPYSYUXXVZS[Q[OZMX SMUNWPXSXUWXUZS[ IMMM IbPb", + "H\\WMWb XMXb WPUNSMQMNNLPKSKULXNZQ[S[UZWX QMONMPLSLUMXOZQ[ Tb[b", + "IZNMN[ OMO[ OSPPRNTMWMXNXOWPVOWN KMOM K[R[", + "J[WOXMXQWOVNTMPMNNMOMQNRPSUUWVXW MPNQPRUTWUXVXYWZU[Q[OZNYMWM[NY", + "KZPFPWQZS[U[WZXX QFQWRZS[ MMUM", + "G]LMLXMZP[R[UZWX MMMXNZP[ WMW[ XMX[ IMMM TMXM W[[[", + "I[LMR[ MMRY XMR[ JMPM TMZM", + "F^JMN[ KMNX RMN[ RMV[ SMVX ZMV[ GMNM WM]M", + "H\\LMW[ MMX[ XML[ JMPM TMZM J[P[ T[Z[", + "H[LMR[ MMRY XMR[P_NaLbKbJaK`La JMPM TMZM", + "I[WML[ XMM[ MMLQLMXM L[X[XWW[", + "G^QMNNLPKRJUJXKZN[P[RZUWWTYPZM QMONMPLRKUKXLZN[ QMSMUNVPXXYZZ[ SMTNUPWXXZZ[[[", + "G\\TFQGOIMMLPKTJZIb TFRGPINMMPLTKZJb TFVFXGYHYKXMWNTOPO VFXHXKWMVNTO POTPVRWTWWVYUZR[P[NZMYLV POSPURVTVWUYTZR[", + "H\\IPKNMMOMQNROSRSVRZOb JOLNPNRO ZMYPXRSYP^Nb YMXPWRSY", + "I\\VNTMRMONMQLTLWMYNZP[R[UZWWXTXQWOSJRHRFSEUEWFYH RMPNNQMTMXNZ R[TZVWWTWPVNTKSISGTFVFYH", + "I[XPVNTMPMNNNPPRSS PMONOPQRSS SSNTLVLXMZP[S[UZWX SSOTMVMXNZP[", + "I[TFRGQHQIRJUKZKZJWKSMPOMRLULWMYP[S]T_TaSbQbPa ULQONRMUMWNYP[", + "G]HQIOKMNMONOPNTL[ MMNNNPMTK[ NTPPRNTMVMXNYOYRXWUb VMXOXRWWTb", + "F]GQHOJMMMNNNPMUMXNZO[ LMMNMPLULXMZO[Q[SZUXWUXRYMYIXGVFTFRHRJSMUPWRZT SZUWVUWRXMXIWGVF", + "LXRMPTOXOZP[S[UYVW SMQTPXPZQ[", + "H\\NMJ[ OMK[ XMYNZNYMWMUNQROSMS OSQTSZT[ OSPTRZS[U[WZYW", + "H\\KFMFOGPHQJWXXZY[ MFOHPJVXWZY[Z[ RMJ[ RMK[", + "F]MMGb NMHb MPLVLYN[P[RZTXVU XMUXUZV[Y[[Y\\W YMVXVZW[", + "H\\NML[ OMNSMXL[ YMXQVU ZMYPXRVUTWQYOZL[ KMOM", + "IZTFRGQHQIRJUKXK UKQLOMNONQPSSTVT UKRLPMOOOQQSST STOUMVLXLZN\\S^T_TaRbPb STPUNVMXMZO\\S^", + "I[RMONMQLTLWMYNZP[R[UZWWXTXQWOVNTMRM RMPNNQMTMXNZ R[TZVWWTWPVN", + "G]PNL[ PNM[ VNV[ VNW[ IPKNNM[M IPKONN[N", + "H[LVMYNZP[R[UZWWXTXQWOVNTMRMONMQLTHb R[TZVWWTWPVN RMPNNQMTIb", + "H][MQMNNLQKTKWLYMZO[Q[TZVWWTWQVOUNSM QMONMQLTLXMZ Q[SZUWVTVPUN UN[N", + "H\\SNP[ SNQ[ JPLNOMZM JPLOONZN", + "H\\IQJOLMOMPNPPNVNYP[ NMONOPMVMYNZP[Q[TZVXXUYRYOXMWNXOYR XUYO", + "G]ONMOKQJTJWKYLZN[Q[TZWXYUZRZOXMVMTORSPXMb JWLYNZQZTYWWYU ZOXNVNTPRSPYNb", + "I[KMMMONPPU_VaWb MMNNOPT_UaWbYb ZMYOWRM]K`Jb", + "F]UFOb VFNb GQHOJMMMNNNPMUMXOZRZTYWVYS LMMNMPLULXMZO[R[TZVXXUYS[M", + "F]JQLOONNMLNJQITIWJZK[M[OZQWRT IWJYKZMZOYQW QTQWRZS[U[WZYWZTZQYNXMWNYOZQ QWRYSZUZWYYW", + "H]XMVTUXUZV[Y[[Y\\W YMWTVXVZW[ VTVQUNSMQMNNLQKTKWLYMZO[Q[SZUWVT QMONMQLTLXMZ", + "H[PFLSLVMYNZ QFMS MSNPPNRMTMVNWOXQXTWWUZR[P[NZMWMS VNWPWTVWTZR[ MFQF", + "I[WPWQXQXPWNUMRMONMQLTLWMYNZP[R[UZWW RMPNNQMTMXNZ", + "H]ZFVTUXUZV[Y[[Y\\W [FWTVXVZW[ VTVQUNSMQMNNLQKTKWLYMZO[Q[SZUWVT QMONMQLTLXMZ WF[F", + "I[MVQUTTWRXPWNUMRMONMQLTLWMYNZP[R[UZWX RMPNNQMTMXNZ", + "KZZGYHZI[H[GZFXFVGUHTJSMP[O_Na XFVHUJTNRWQ[P^O`NaLbJbIaI`J_K`Ja OMYM", + "H\\YMU[T^RaObLbJaI`I_J^K_J` XMT[S^QaOb VTVQUNSMQMNNLQKTKWLYMZO[Q[SZUWVT QMONMQLTLXMZ", + "H]PFJ[ QFK[ MTOPQNSMUMWNXOXQVWVZW[ UMWOWQUWUZV[Y[[Y\\W MFQF", + "LYUFTGUHVGUF MQNOPMSMTNTQRWRZS[ RMSNSQQWQZR[U[WYXW", + "LYVFUGVHWGVF NQOOQMTMUNUQR[Q^P`OaMbKbJaJ`K_L`Ka SMTNTQQ[P^O`Mb", + "H\\PFJ[ QFK[ XNWOXPYOYNXMWMUNQROSMS OSQTSZT[ OSPTRZS[U[WZYW MFQF", + "MYUFQTPXPZQ[T[VYWW VFRTQXQZR[ RFVF", + "AbBQCOEMHMINIPHTF[ GMHNHPGTE[ HTJPLNNMPMRNSOSQP[ PMRORQO[ RTTPVNXMZM\\N]O]Q[W[Z\\[ ZM\\O\\QZWZZ[[^[`YaW", + "F]GQHOJMMMNNNPMTK[ LMMNMPLTJ[ MTOPQNSMUMWNXOXQVWVZW[ UMWOWQUWUZV[Y[[Y\\W", + "I[RMONMQLTLWMYNZP[R[UZWWXTXQWOVNTMRM RMPNNQMTMXNZ R[TZVWWTWPVN", + "G\\HQIOKMNMONOPNTJb MMNNNPMTIb NTOQQNSMUMWNXOYQYTXWVZS[Q[OZNWNT WNXPXTWWUZS[ FbMb", + "H\\XMRb YMSb VTVQUNSMQMNNLQKTKWLYMZO[Q[SZUWVT QMONMQLTLXMZ ObVb", + "IZJQKOMMPMQNQPPTN[ OMPNPPOTM[ PTRPTNVMXMYNYOXPWOXN", + "J[XOXPYPYOXNUMRMONNONQORVVWW NPOQVUWVWYVZS[P[MZLYLXMXMY", + "KYTFPTOXOZP[S[UYVW UFQTPXPZQ[ NMWM", + "F]GQHOJMMMNNNQLWLYN[ LMMNMQKWKYLZN[P[RZTXVT XMVTUXUZV[Y[[Y\\W YMWTVXVZW[", + "H\\IQJOLMOMPNPQNWNYP[ NMONOQMWMYNZP[Q[TZVXXUYQYMXMYO", + "C`DQEOGMJMKNKQIWIYK[ IMJNJQHWHYIZK[M[OZQXRV TMRVRYSZU[W[YZ[X\\V]R]M\\M]O UMSVSYU[", + "H\\KQMNOMRMSOSR QMRORRQVPXNZL[K[JZJYKXLYKZ QVQYR[U[WZYW YNXOYPZOZNYMXMVNTPSRRVRYS[", + "G\\HQIOKMNMONOQMWMYO[ MMNNNQLWLYMZO[Q[SZUXWT ZMV[U^SaPbMbKaJ`J_K^L_K` YMU[T^RaPb", + "H\\YMXOVQNWLYK[ LQMOOMRMVO MOONRNVOXO LYNYRZUZWY NYR[U[WYXW", + "G^VGUHVIWHWGUFRFOGMILLL[ RFPGNIMLM[ \\G[H\\I]H]G\\FZFXGWIW[ ZFYGXIX[ IM[M I[P[ T[[[", + "G]WGVHWIXHWGUFRFOGMILLL[ RFPGNIMLM[ WMW[ XMX[ IMXM I[P[ T[[[", + "G]VGUHVIWHWGUF XFRFOGMILLL[ RFPGNIMLM[ WHW[ XFX[ IMWM I[P[ T[[[", + "BcRGQHRISHRGPFMFJGHIGLG[ MFKGIIHLH[ ]G\\H]I^H]G[FXFUGSIRLR[ XFVGTISLS[ ]M][ ^M^[ DM^M D[K[ O[V[ Z[a[", + "BcRGQHRISHRGPFMFJGHIGLG[ MFKGIIHLH[ \\G[H\\I]H]G[F ^FXFUGSIRLR[ XFVGTISLS[ ]H][ ^F^[ DM]M D[K[ O[V[ Z[a[", + "MXRMR[ SMS[ OMSM O[V[", + "", + "IZWNUMRMONMPLSLVMYNZQ[T[VZ RMPNNPMSMVNYOZQ[ MTUT", + "I\\TFQGOJNLMOLTLXMZO[Q[TZVWWUXRYMYIXGVFTF TFRGPJOLNOMTMXNZO[ Q[SZUWVUWRXMXIWGVF NPWP", + "G]UFOb VFNb QMMNKPJSJVKXMZP[S[WZYXZUZRYPWNTMQM QMNNLPKSKVLXNZP[ S[VZXXYUYRXPVNTM", + "I[TMVNXPXOWNTMQMNNMOLQLSMUOWSZ QMONNOMQMSNUSZT\\T^S_Q_", + "", + "", + "G]LMKNJPJRKUOYP[ JRKTOXP[P]O`MbLbKaJ_J\\KXMTOQRNTMVMYNZPZTYXWZU[T[SZSXTWUXTY VMXNYPYTXXWZ", + "E_YGXHYIZHYGWFTFQGOINKMNLRJ[I_Ha TFRGPIOKNNLWK[J^I`HaFbDbCaC`D_E`Da _G^H_I`H`G_F]F[GZHYJXMU[T_Sa ]F[HZJYNWWV[U^T`SaQbObNaN`O_P`Oa IM^M", + "F^[GZH[I\\H[GXFUFRGPIOKNNMRK[J_Ia UFSGQIPKONMWL[K^J`IaGbEbDaD`E_F`Ea YMWTVXVZW[Z[\\Y]W ZMXTWXWZX[ JMZM", + "F^YGXHYIZHZGXF \\FUFRGPIOKNNMRK[J_Ia UFSGQIPKONMWL[K^J`IaGbEbDaD`E_F`Ea [FWTVXVZW[Z[\\Y]W \\FXTWXWZX[ JMYM", + "@cTGSHTIUHTGRFOFLGJIIKHNGRE[D_Ca OFMGKIJKINGWF[E^D`CaAb?b>a>`?_@`?a `G_H`IaH`G]FZFWGUITKSNRRP[O_Na ZFXGVIUKTNRWQ[P^O`NaLbJbIaI`J_K`Ja ^M\\T[X[Z\\[_[aYbW _M]T\\X\\Z][ DM_M", + "@cTGSHTIUHTGRFOFLGJIIKHNGRE[D_Ca OFMGKIJKINGWF[E^D`CaAb?b>a>`?_@`?a ^G]H^I_H_G]F aFZFWGUITKSNRRP[O_Na ZFXGVIUKTNRWQ[P^O`NaLbJbIaI`J_K`Ja `F\\T[X[Z\\[_[aYbW aF]T\\X\\Z][ DM^M", + "LYMQNOPMSMTNTQRWRZS[ RMSNSQQWQZR[U[WYXW", + "", + "NV", + "JZ", + "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF QFOGNHMJLOLRMWNYOZQ[ S[UZVYWWXRXOWJVHUGSF", + "H\\NJPISFS[ RGR[ N[W[", + "H\\LJMKLLKKKJLHMGPFTFWGXHYJYLXNUPPRNSLUKXK[ TFVGWHXJXLWNTPPR KYLXNXSZVZXYYX NXS[W[XZYXYV", + "H\\LJMKLLKKKJLHMGPFTFWGXIXLWNTOQO TFVGWIWLVNTO TOVPXRYTYWXYWZT[P[MZLYKWKVLUMVLW WQXTXWWYVZT[", + "H\\THT[ UFU[ UFJUZU Q[X[", + "H\\MFKP KPMNPMSMVNXPYSYUXXVZS[P[MZLYKWKVLUMVLW SMUNWPXSXUWXUZS[ MFWF MGRGWF", + "H\\WIVJWKXJXIWGUFRFOGMILKKOKULXNZQ[S[VZXXYUYTXQVOSNRNOOMQLT RFPGNIMKLOLUMXOZQ[ S[UZWXXUXTWQUOSN", + "H\\KFKL KJLHNFPFUIWIXHYF LHNGPGUI YFYIXLTQSSRVR[ XLSQRSQVQ[", + "H\\PFMGLILLMNPOTOWNXLXIWGTFPF PFNGMIMLNNPO TOVNWLWIVGTF POMPLQKSKWLYMZP[T[WZXYYWYSXQWPTO PONPMQLSLWMYNZP[ T[VZWYXWXSWQVPTO", + "H\\XMWPURRSQSNRLPKMKLLINGQFSFVGXIYLYRXVWXUZR[O[MZLXLWMVNWMX QSORMPLMLLMIOGQF SFUGWIXLXRWVVXTZR[", + "MWRYQZR[SZRY", + "MWR[QZRYSZS\\R^Q_", + "MWRMQNROSNRM RYQZR[SZRY", + "MWRMQNROSNRM R[QZRYSZS\\R^Q_", + "MWRFQHRTSHRF RHRN RYQZR[SZRY", + "I[MJNKMLLKLJMHNGPFSFVGWHXJXLWNVORQRT SFUGVHWJWLVNTP RYQZR[SZRY", + "NVRFQM SFQM", + "JZNFMM OFMM VFUM WFUM", + "KYQFOGNINKOMQNSNUMVKVIUGSFQF", + "JZRFRR MIWO WIMO", + "G][BIb", + "KYVBTDRGPKOPOTPYR]T`Vb TDRHQKPPPTQYR\\T`", + "KYNBPDRGTKUPUTTYR]P`Nb PDRHSKTPTTSYR\\P`", + "KYOBOb PBPb OBVB ObVb", + "KYTBTb UBUb NBUB NbUb", + "JYTBQEPHPJQMSOSPORSTSUQWPZP\\Q_Tb RDQGQKRN RVQYQ]R`", + "KZPBSETHTJSMQOQPURQTQUSWTZT\\S_Pb RDSGSKRN RVSYS]R`", + "KYUBNRUb", + "KYOBVROb", + "NVRBRb", + "KYOBOb UBUb", + "E_IR[R", + "E_RIR[ IR[R", + "F^RJR[ JRZR J[Z[", + "F^RJR[ JJZJ JRZR", + "G]KKYY YKKY", + "MWQQQSSSSQQQ RQRS QRSR", + "E_RIQJRKSJRI IR[R RYQZR[SZRY", + "E_IO[O IU[U", + "E_YIK[ IO[O IU[U", + "E_IM[M IR[R IW[W", + "F^ZIJRZ[", + "F^JIZRJ[", + "F^ZFJMZT JVZV J[Z[", + "F^JFZMJT JVZV J[Z[", + "F_[WYWWVUTRPQOONMNKOJQJSKUMVOVQURTUPWNYM[M", + "F^IUISJPLONOPPTSVTXTZS[Q ISJQLPNPPQTTVUXUZT[Q[O", + "G]JTROZT JTRPZT", + "LXTFOL TFUGOL", + "LXPFUL PFOGUL", + "H\\KFLHNJQKSKVJXHYF KFLINKQLSLVKXIYF", + "MWRHQGRFSGSIRKQL", + "MWSFRGQIQKRLSKRJ", + "MWRHSGRFQGQIRKSL", + "MWQFRGSISKRLQKRJ", + "E[HMLMRY KMR[ [BR[", + "F^ZJSJOKMLKNJQJSKVMXOYSZZZ", + "F^JJJQKULWNYQZSZVYXWYUZQZJ", + "F^JJQJUKWLYNZQZSYVWXUYQZJZ", + "F^JZJSKOLMNKQJSJVKXMYOZSZZ", + "F^ZJSJOKMLKNJQJSKVMXOYSZZZ JRVR", + "E_XP[RXT UMZRUW IRZR", + "JZPLRITL MORJWO RJR[", + "E_LPIRLT OMJROW JR[R", + "JZPXR[TX MURZWU RIRZ", + "I\\XRWOVNTMRMONMQLTLWMYNZP[R[UZWXXUYPYKXHWGUFRFPGOHOIPIPH RMPNNQMTMXNZ R[TZVXWUXPXKWHUF", + "H\\JFR[ KFRY ZFR[ JFZF KGYG", + "AbDMIMRY HNR[ b:R[", + "F^[CZD[E\\D\\C[BYBWCUETGSJRNPZO^N` VDUFTJRVQZP]O_MaKbIbHaH`I_J`Ia", + "F^[CZD[E\\D\\C[BYBWCUETGSJRNPZO^N` VDUFTJRVQZP]O_MaKbIbHaH`I_J`Ia QKNLLNKQKSLVNXQYSYVXXVYSYQXNVLSKQK", + "F_\\S[UYVWVUUTTQPPONNLNJOIQISJULVNVPUQTTPUOWNYN[O\\Q\\S", + "F^[FI[ NFPHPJOLMMKMIKIIJGLFNFPGSHVHYG[F WTUUTWTYV[X[ZZ[X[VYTWT", + "F_[NZO[P\\O\\N[MZMYNXPVUTXRZP[M[JZIXIUJSPORMSKSIRGPFNGMIMKNNPQUXWZZ[[[\\Z\\Y M[KZJXJUKSMQ MKNMVXXZZ[", + "E`WNVLTKQKOLNMMPMSNUPVSVUUVS QKOMNPNSOUPV WKVSVUXVZV\\T]Q]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYZX XKWSWUXV", + "H\\PBP_ TBT_ XIWJXKYJYIWGTFPFMGKIKKLMMNOOUQWRYT KKMMONUPWQXRYTYXWZT[P[MZKXKWLVMWLX", + "G]OFOb UFUb JQZQ JWZW", + "JZUITJUKVJVIUGSFQFOGNINKOMQOVR OMTPVRWTWVVXTZ PNNPMRMTNVPXU[ NVSYU[V]V_UaSbQbOaN_N^O]P^O_", + "JZRFQHRJSHRF RFRb RQQTRbSTRQ LMNNPMNLLM LMXM TMVNXMVLTM", + "JZRFQHRJSHRF RFRT RPQRSVRXQVSRRP RTRb R^Q`RbS`R^ LMNNPMNLLM LMXM TMVNXMVLTM L[N\\P[NZL[ L[X[ T[V\\X[VZT[", + "I\\XFX[ KFXF PPXP K[X[", + "", + "E`QFNGKIILHOHRIUKXNZQ[T[WZZX\\U]R]O\\LZIWGTFQF ROQPQQRRSRTQTPSORO RPRQSQSPRP", + "J[PFNGOIQJ PFOGOI UFWGVITJ UFVGVI QJOKNLMNMQNSOTQUTUVTWSXQXNWLVKTJQJ RUR[ SUS[ NXWX", + "I\\RFOGMILLLMMPORRSSSVRXPYMYLXIVGSFRF RSR[ SSS[ NWWW", + "D`PFMGJIHLGOGSHVJYM[P\\T\\W[ZY\\V]S]O\\LZIWGTFPF RFR\\ GQ]Q", + "G`PMMNKPJSJTKWMYPZQZTYVWWTWSVPTNQMPM ]GWG[HUN ]G]M\\IVO \\HVN", + "F\\IIJGLFOFQGRIRLQOPQNSKU OFPGQIQMPPNS VFT[ WFS[ KUYU", + "I\\MFMU NFMQ MQNOONQMTMWNXPXRWTUV TMVNWPWRTXTZU[W[YY KFNF", + "I\\RNOOMQLTLUMXOZR[S[VZXXYUYTXQVOSNRN RHNJRFRN SHWJSFSN RSQTQURVSVTUTTSSRS RTRUSUSTRT", + "G^QHRFR[ THSFS[ JHKFKMLPNRQSRS MHLFLNMQ [HZFZMYPWRTSSS XHYFYNXQ NWWW", + "G]LFL[ MFM[ IFUFXGYHZJZMYOXPUQMQ UFWGXHYJYMXOWPUQ I[Y[YVX[", + "H[YGUGQHNJLMKPKSLVNYQ[U\\Y\\ YGVHSJQMPPPSQVSYV[Y\\", + "F_OQMQKRJSIUIWJYKZM[O[QZRYSWSURSQROQ SHPQ ZJRR \\QST", + "H\\OKUY UKOY KOYU YOKU", + "F^NVLUKUIVHXHYI[K\\L\\N[OYOXNVKRJOJMKJMHPGTGWHYJZMZOYRVVUXUYV[X\\Y\\[[\\Y\\X[VYUXUVV JMKKMIPHTHWIYKZM", + "F^NMLNKNIMHKHJIHKGLGNHOJOKNMKQJTJVKYM[P\\T\\W[YYZVZTYQVMUKUJVHXGYG[H\\J\\K[MYNXNVM JVKXMZP[T[WZYXZV", + "I[KYYK QLULYKXOXS ULXLXO", + "I[YKKY LQLUKYOXSX LULXOX", + "I[YYKK SLOLKKLOLS OLLLLO", + "I[KKYY QXUXYYXUXQ UXXXXU", + "", + "F_JMILIJJHLGNGPHQIRKSP IJKHMHOIPJQLRPR[ [M\\L\\J[HYGWGUHTISKRP \\JZHXHVIUJTLSPS[", + "F^IGJKKMMOPPTPWOYMZK[G IGJJKLMNPOTOWNYLZJ[G PONPMQLSLVMXOZQ[S[UZWXXVXSWQVPTO PPNQMSMVNY VYWVWSVQTP", + "F^MJMV NKNU VKVU WJWV IGKIMJPKTKWJYI[G IYKWMVPUTUWVYW[Y", + "F^[ILIJJILINJPLQNQPPQNQLPJ[J IMJOKPMQ QMPKOJMI IXXXZW[U[SZQXPVPTQSSSUTWIW [TZRYQWP STTVUWWX", + "F]OUMTLTJUIWIXJZL[M[OZPXPWOUJPINIKJILHOGSGWHYJZLZOYRVUUWUYV[X[YZZX MSKPJNJKKILH SGVHXJYLYOXRVU", + "G_HKKHMKMV JILLLV MKPHRKRU OIQLQU RKUHWKW[ TIVLV[ WKZH[J\\M\\P[SZUXWUYP[ YIZJ[M[PZSYUWWTYP[", + "F^ISMSLRKOKMLJNHQGSGVHXJYMYOXRWS[S ITOTMRLOLMMJOHQG SGUHWJXMXOWRUT[T KXYX KYYY", + "F_GLJIMLMX IJLMLX MLPISLSX OJRMRX SLVIYLYW[Y UJXMXXZZ]W", + "G]ZIJY ZIWJQJ XKUKQJ ZIYLYR XKXNYR QRJR PSMSJR QRQY PSPVQY", + "F^HOJKOU JMOWRPWPZO[M[KZIXHWHUITKTMUPVRWUWXUZ WHVIUKUMWQXTXWWYUZ", + "F^IOLLPN KMOORLUN QMTOWLYN VMXO[L IULRPT KSOURRUT QSTUWRYT VSXU[R", + "F^JHNJPLQOQRPUNWJY JHMIOJQLRO RRQUOWMXJY ZHWIUJSLRO RRSUUWWXZY ZHVJTLSOSRTUVWZY IP[P IQ[Q", + "", + "", + "", + "", + "NVQQQSSSSQQQ QQSS SQQS", + "JZMPQRTTVVWYW[V]U^ MQST MRPSTUVWWY", + "JZWKVMTOPQMR SPMS UFVGWIWKVNTPQRMT", + "H\\SMONLPKRKTLVNWQWUVXTYRYPXNVMSM XNSM VMQNLP ONKR LVQW NWSVXT UVYR", + "H\\SMONLPKRKTLVNWQWUVXTYRYPXNVMSM XNSM VMQNLP ONKR LVQW NWSVXT UVYR", + "J[SMPNNPMRMTNVPWRWUVWTXRXPWNUMSM OPUM NRVN MTWO NUXP OVWR PWVT", + "JZOGO^ UFU] MNWL MOWM MWWU MXWV", + "JZNFNX VLV^ NNVL NOVM NWVU NXVV", + "JZNBNW NNQLTLVMWOWQVSSUQVNW NNQMTMVN UMVOVQUSSU", + "E_HIHL \\I\\L HI\\I HJ\\J HK\\K HL\\L", + "JZMNMQ WNWQ MNWN MOWO MPWP MQWQ", + "JZMLWX MLONQOTOVNWMWKUKUMTO ONTO QOWM VKVN ULWL WXUVSUPUNVMWMYOYOWPU UVPU SUMW NVNY MXOX", + "JZPOOMOKMKMMNNPOSOUNWL NKNN MLOL MMSO POUN WLWY", + "A^GfHfIeIdHcGcFdFfGhIiKiNhPfQdR`RUQ;Q4R/S-U,V,X-Y/Y3X6W8U;P?JCHEFHEJDNDREVGYJ[N\\R\\V[XZZW[T[PZMYKWITHPHMIKKJNJRKUMW GdGeHeHdGd U;Q?LCIFGIFKENERFVGXJ[ R\\U[WZYWZTZPYMXKVITH", + "EfNSOUQVSVUUVSVQUOSNQNOONPMSMVNYP[S\\V\\Y[[Y\\W]T]P\\MZJXIUHRHOIMJKLIOHSHXI]KaMcPeTfYf]e`cba KLJNIRIXJ\\L`NbQdUeYe]d_cba POTO OPUP NQVQ NRVR NSVS OTUT PUTU aLaNcNcLaL bLbN aMcM aVaXcXcVaV bVbX aWcW", + "D`H@Hd M@Md W@Wd \\@\\d MMWK MNWL MOWM MWWU MXWV MYWW", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "NVQQQSSSSQQQ QQSS SQQS", + "JZMPQRTTVVWYW[V]U^ MQST MRPSTUVWWY", + "JZWKVMTOPQMR SPMS UFVGWIWKVNTPQRMT", + "H\\PMMNLOKQKSLUMVPWTWWVXUYSYQXOWNTMPM MNLPLSMUNVPW WVXTXQWOVNTM", + "H\\SMONLPKRKTLVNWQWUVXTYRYPXNVMSM XNSM VMQNLP ONKR LVQW NWSVXT UVYR", + "J[SMPNNPMRMTNVPWRWUVWTXRXPWNUMSM OPUM NRVN MTWO NUXP OVWR PWVT", + "JZOGO^ UFU] MNWL MOWM MWWU MXWV", + "JZNFNX VLV^ NNVL NOVM NWVU NXVV", + "JZNBNW NNQLTLVMWOWQVSSUQVNW NNQMTMVN UMVOVQUSSU", + "E_HIHL \\I\\L HI\\I HJ\\J HK\\K HL\\L", + "JZMNMQ WNWQ MNWN MOWO MPWP MQWQ", + "JZQCVMRTRU ULQS TITKPRRUUY W\\UYSXQXOYN[N]O_Ra W\\UZSYOYO]P_Ra SXPZN]", + "JZPOOMOKMKMMNNPOSOUNWL NKNN MLOL MMSO POUN WLSY", + "A^GfHfIeIdHcGcFdFfGhIiKiNhPfQdR`RUQ;Q4R/S-U,V,X-Y/Y3X6W8U;P?JCHEFHEJDNDREVGYJ[N\\R\\V[XZZW[T[PZMYKWITHPHMIKKJNJRKUMW GdGeHeHdGd U;Q?LCIFGIFKENERFVGXJ[ R\\U[WZYWZTZPYMXKVITH", + "IjNQOOQNSNUOVQVSUUSVQVOUNTMQMNNKPISHWH[I^K`NaRaW`[_]]`ZcVfQiMk WHZI]K_N`R`W_[^]\\`YcTgQi POTO OPUP NQVQ NRVR NSVS OTUT PUTU eLeNgNgLeL fLfN eMgM eVeXgXgVeV fVfX eWgW", + "D`H>Hf I>If M>Mf QBSBSDQDQAR?T>W>Y?[A\\D\\I[LYNWOUOSNRLQNOQNROSQVRXSVUUWUYV[X\\[\\`[cYeWfTfReQcQ`S`SbQb RBRD QCSC Y?ZA[D[IZLYN RLRNPQNRPSRVRX YVZX[[[`ZcYe R`Rb QaSa", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "AcHBHb IBIb [B[b \\B\\b DB`B DbMb Wb`b", + "BaGBQPFb FBPP EBPQ EB\\B^I[B Ga\\a Fb\\b^[[b", + "I[X+U1R8P=OANFMNMVN^OcPgRlUsXy U1S6QPBTJTLSNROMRRUSVTXTZPbOfOjPoRsVy T.R2Q5P:P>QCRF R^QaPfPjQoRrTv", + "I\\N+R1T5U:U>TBPJPLQNROWRRUQVPXPZTbUfUjToRsNy P.R2S5T:T>SCRF R^SaTfTjSoRrPv", + "I[V.S1Q4O8N=NCOIPMSXT\\UbUgTlSoQs S1Q5P8O=OBPHQLTWU[VaVgUlSpQsNv", + "I[N.Q1S4U8V=VCUITMQXP\\ObOgPlQoSs Q1S5T8U=UBTHSLPWO[NaNgOlQpSsVv", + "7Z:RARRo @RQo ?RRr Z\"VJRr", + "Ca].\\.[/[0\\1]1^0^.],[+Y+W,U.T0S3R:QJQjPsOv \\/\\0]0]/\\/ R:Rj U.T1S:SZRjQqPtOvMxKyIyGxFvFtGsHsItIuHvGv GtGuHuHtGt", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "H\\RFJ[ RIK[J[ RIY[Z[ RFZ[ MUWU LVXV", + "H\\LFL[ MGMZ LFTFWGXHYJYMXOWPTQ MGTGWHXJXMWOTP MPTPWQXRYTYWXYWZT[L[ MQTQWRXTXWWYTZMZ", + "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZV ZKYKXIWHUGQGOHMKLNLSMVOYQZUZWYXXYVZV", + "H]LFL[ MGMZ LFSFVGXIYKZNZSYVXXVZS[L[ MGSGVHWIXKYNYSXVWXVYSZMZ", + "I\\MFM[ NGNZ MFYF NGYGYF NPTPTQ NQTQ NZYZY[ M[Y[", + "I[MFM[ NGN[M[ MFYF NGYGYF NPTPTQ NQTQ", + "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZVZRUR ZKYKXIWHUGQGOHNIMKLNLSMVNXOYQZUZWYXXYVYSUSUR", + "G]KFK[ KFLFL[K[ YFXFX[Y[ YFY[ LPXP LQXQ", + "NWRFR[S[ RFSFS[", + "J[VFVVUYSZQZOYNVMV VFWFWVVYUZS[Q[OZNYMV", + "H]LFL[M[ LFMFM[ ZFYFMR ZFMS POY[Z[ QOZ[", + "IZMFM[ MFNFNZ NZYZY[ M[Y[", + "F^JFJ[ KKK[J[ KKR[ JFRX ZFRX YKR[ YKY[Z[ ZFZ[", + "G]KFK[ LIL[K[ LIY[ KFXX XFXX XFYFY[", + "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF QGNHLKKNKSLVNYQZSZVYXVYSYNXKVHSGQG", + "H\\LFL[ MGM[L[ LFUFWGXHYJYMXOWPUQMQ MGUGWHXJXMWOUPMP", + "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF QGNHLKKNKSLVNYQZSZVYXVYSYNXKVHSGQG SXX]Y] SXTXY]", + "H\\LFL[ MGM[L[ LFTFWGXHYJYMXOWPTQMQ MGTGWHXJXMWOTPMP RQX[Y[ SQY[", + "H\\YIWGTFPFMGKIKKLMMNOOTQVRWSXUXXWYTZPZNYMXKX YIWIVHTGPGMHLILKMMONTPVQXSYUYXWZT[P[MZKX", + "J[RGR[ SGS[R[ LFYFYG LFLGYG", + "G]KFKULXNZQ[S[VZXXYUYF KFLFLUMXNYQZSZVYWXXUXFYF", + "H\\JFR[ JFKFRX ZFYFRX ZFR[", + "E_GFM[ GFHFMX RFMX RIM[ RIW[ RFWX ]F\\FWX ]FW[", + "H\\KFX[Y[ KFLFY[ YFXFK[ YFL[K[", + "I\\KFRPR[S[ KFLFSP ZFYFRP ZFSPS[", + "H\\XFK[ YFL[ KFYF KFKGXG LZYZY[ K[Y[", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "E\\XFVHTKQPOSLWIZG[E[DZDXEWFXEY XFWJUTT[ XFU[ T[TYSVRTPRNQLQKRKTLWOZR[V[XZ", + "F^UGTHSJQOOUNWLZJ[ THSKQSPVOXMZJ[H[GZGXHWIXHY OLNNMOKOJNJLKJMHOGRFXFZG[I[KZMXNTORO XFYGZIZKYMXN TOWPXQYSYVXYWZU[S[RZRXSU TOVPWQXSXVWYU[", + "H]KHJJJLKNNOQOUNWMYKZIZGYFWFTGQJOMMQLULXMZP[R[UZWXXVXTWRURSSRU WFUGRJPMNQMUMXNZP[", + "F]UGTHSJQOOUNWLZJ[ THSKQSPVOXMZJ[H[GZGXHWJWLXNZP[S[UZWXYTZOZLYIWGUFPFMGKIJKJMKNMNNMOK", + "I\\WIVJVLWMYMZKZIYGWFTFRGQHPJPLQNSO TFRHQJQMSO SOQONPLRKTKWLYMZO[R[UZWXXVXTWRURSSRU QOOPMRLTLXMZ", + "G\\WHVJTORUQWOZM[ QLPNNOLOKMKKLINGQF[FXGWHVKTSSVRXPZM[K[IZHYHXIWJXIY SFWGXG OSPRRQVQXPZMXT", + "G]JIIKIMJOLPOPROTNWKXHXGWFVFTGRIQKPNPQQSSTUTWSYQZO WFUGSIRKQNQRST ZOYSWWUYSZO[L[JZIXIWJVKWJX YSWVUXRZO[", + "F^LLKKKILGOFRFOQMWLYKZI[G[FZFXGWHXGY RFOONRLWKYI[ JTKSMRVOXN[L]J^H^G]F\\FZGXJWLURTVTYV[W[YZ[X \\FZHXLVRUVUYV[", + "IYWHUKSPQUPWNZL[ YLWNTOQOONNLNJOHQGUFYFWHVJTPRVQXOZL[J[IZIXJWKXJY", + "IZYFWHUKSPPYN] YMWOTPQPOONMNKOIQGUFYFWIVKSTQXPZN]M^K_J^J\\KZMXOWRVVU", + "F^LLKKKIMGPFRFOQMWLYKZI[G[FZFXGWHXGY RFOONRLWKYI[ ZGWKUMSNPO ]G\\H]I^H^G]F\\FZGWLVMTNPO POSPTRUYV[ PORPSRTYV[W[YZ[X", + "I[MILKLMMOOPRPUOWNZK[H[GZFYFWGVHTKPUOWMZK[ VHTLRSQVPXNZK[I[HZHXIWKWMXPZR[U[WZYX", + "D`RFNOKUIXGZE[C[BZBXCWDXCY RFPMOQNVNZP[ RFQJPOOVOZP[ [FWORXP[ [FYMXQWVWZY[Z[\\Z^X [FZJYOXVXZY[", + "G^RFQJOPMULWJZH[F[EZEXFWGXFY RFRKSVT[ RFSKTVT[ `G_H`IaHaG`F^F\\GZJYLWQUWT[", + "H]SFQGOIMLLNKRKVLYMZO[Q[TZVXXUYSZOZKYHXGWGUHSJQNPSPV QGOJMNLRLVMYO[", + "F]UGTHSJQOOUNWLZJ[ THSKQSPVOXMZJ[H[GZGXHWIXHY OLNNMOKOJNJLKJMHOGRFVFYGZH[J[MZOYPVQTQRP VFXGYHZJZMYOXPVQ", + "H]UJULTNSOQPOPNNNLOIQGTFWFYGZIZMYPWSSWPYNZK[I[HZHXIWKWMXPZS[V[XZZX WFXGYIYMXPVSSVOYK[", + "F^UGTHSJQOOUNWLZJ[ THSKQSPVOXMZJ[H[GZGXHWIXHY OLNNMOKOJNJLKJMHOGRFWFZG[I[KZMYNVORO WFYGZIZKYMXNVO ROUPVRWYX[ ROTPURVYX[Y[[Z]X", + "H\\NIMKMMNOPPSPVOXN[K\\H\\G[FZFXGWHVJUMSTRWPZN[ VJUNTUSXQZN[K[IZHXHWIVJWIX", + "I[YHXJVOTUSWQZO[ SLRNPONOMMMKNIPGSF\\FZGYHXKVSUVTXRZO[M[KZJYJXKWLXKY UFYGZG", + "G]HJJGLFMFOHOKNNKVKYL[ MFNHNKKSJVJYL[N[PZSWUTVR ZFVRUVUYW[X[ZZ\\X [FWRVVVYW[", + "G\\HJJGLFMFOHOKNOLVLYM[ MFNHNKLRKVKYM[N[QZTWVTXPYMZIZGYFXFWGVIVLWNYP[Q]Q", + "F]ILHLGKGIHGJFNFMHLLKUJ[ LLLUK[ VFTHRLOUMYK[ VFUHTLSUR[ TLTUS[ `F^G\\IZLWUUYS[", + "H\\PKOLMLLKLIMGOFQFSGTITLSPQUOXMZJ[H[GZGXHWIXHY QFRGSISLRPPUNXLZJ[ ]G\\H]I^H^G]F[FYGWIULSPRURXSZT[U[WZYX", + "G]JJLGNFOFQGQIOOORPT OFPGPINONRPTRTUSWQYNZL \\FZLWTUX ]F[LYQWUUXSZP[L[JZIXIWJVKWJX", + "G\\ZHYJWOVRUTSWQYOZL[ SLRNPONOMMMKNIPGSF]F[GZHYKXOVUTXQZL[H[GZGXHWJWLXOZQ[T[WZYX VFZG[G", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "H\\WMW[X[ WMXMX[ WPUNSMPMNNLPKSKULXNZP[S[UZWX WPSNPNNOMPLSLUMXNYPZSZWX", + "H\\LFL[M[ LFMFM[ MPONQMTMVNXPYSYUXXVZT[Q[OZMX MPQNTNVOWPXSXUWXVYTZQZMX", + "I[XPVNTMQMONMPLSLUMXOZQ[T[VZXX XPWQVOTNQNOONPMSMUNXOYQZTZVYWWXX", + "H\\WFW[X[ WFXFX[ WPUNSMPMNNLPKSKULXNZP[S[UZWX WPSNPNNOMPLSLUMXNYPZSZWX", + "I[MTXTXQWOVNTMQMONMPLSLUMXOZQ[T[VZXX MSWSWQVOTNQNOONPMSMUNXOYQZTZVYWWXX", + "LZWFUFSGRJR[S[ WFWGUGSH TGSJS[ OMVMVN OMONVN", + "H\\XMWMW\\V_U`SaQaO`N_L_ XMX\\W_UaSbPbNaL_ WPUNSMPMNNLPKSKULXNZP[S[UZWX WPSNPNNOMPLSLUMXNYPZSZWX", + "H\\LFL[M[ LFMFM[ MQPNRMUMWNXQX[ MQPORNTNVOWQW[X[", + "NWRFQGQHRISITHTGSFRF RGRHSHSGRG RMR[S[ RMSMS[", + "NWRFQGQHRISITHTGSFRF RGRHSHSGRG RMRbSb RMSMSb", + "H[LFL[M[ LFMFM[ XMWMMW XMMX PTV[X[ QSX[", + "NWRFR[S[ RFSFS[", + "CbGMG[H[ GMHMH[ HQKNMMPMRNSQS[ HQKOMNONQORQR[S[ SQVNXM[M]N^Q^[ SQVOXNZN\\O]Q][^[", + "H\\LML[M[ LMMMM[ MQPNRMUMWNXQX[ MQPORNTNVOWQW[X[", + "I\\QMONMPLSLUMXOZQ[T[VZXXYUYSXPVNTMQM QNOONPMSMUNXOYQZTZVYWXXUXSWPVOTNQN", + "H\\LMLbMb LMMMMb MPONQMTMVNXPYSYUXXVZT[Q[OZMX MPQNTNVOWPXSXUWXVYTZQZMX", + "H\\WMWbXb WMXMXb WPUNSMPMNNLPKSKULXNZP[S[UZWX WPSNPNNOMPLSLUMXNYPZSZWX", + "KYOMO[P[ OMPMP[ PSQPSNUMXM PSQQSOUNXNXM", + "J[XPWNTMQMNNMPNRPSUUWV VUWWWXVZ WYTZQZNY OZNXMX XPWPVN WOTNQNNO ONNPOR NQPRUTWUXWXXWZT[Q[NZMX", + "MXRFR[S[ RFSFS[ OMVMVN OMONVN", + "H\\LMLWMZO[R[TZWW LMMMMWNYPZRZTYWW WMW[X[ WMXMX[", + "JZLMR[ LMMMRY XMWMRY XMR[", + "F^IMN[ IMJMNX RMNX RPN[ RPV[ RMVX [MZMVX [MV[", + "I[LMW[X[ LMMMX[ XMWML[ XMM[L[", + "JZLMR[ LMMMRY XMWMRYNb XMR[ObNb", + "I[VNL[ XMNZ LMXM LMLNVN NZXZX[ L[X[", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "K[UUTSRRPRNSMTLVLXMZO[Q[SZTX PRNTMVMYO[ VRTXTZV[XZYY[V WRUXUZV[", + "LZLVNSPO SFMXMZO[P[RZTXUUURVVWWXWZV TFNXNZO[", + "LXTSSTTTTSSRQROSNTMVMXNZP[S[VYXV QROTNVNYP[", + "K[UUTSRRPRNSMTLVLXMZO[Q[SZTX PRNTMVMYO[ ZFTXTZV[XZYY[V [FUXUZV[", + "LXOYQXRWSUSSRRQROSNTMVMXNZP[S[VYXV QROTNVNYP[", + "OXRRUOWLXIXGWFUGTIKdKfLgNfOcPZQ[S[UZVYXV TISNRRO[M`Kd", + "K[UUTSRRPRNSMTLVLXMZO[Q[SZTX PRNTMVMYO[ VRPd WRT[R`PdOfMgLfLdMaO_R]V[YY[V", + "L[LVNSPO SFL[ TFM[ OUQSSRTRVSVUUXUZV[ TRUSUUTXTZV[XZYY[V", + "NVSLRMSNTMSL QROXOZQ[SZTYVV RRPXPZQ[", + "NVSLRMSNTMSL QRKd RRO[M`KdJfHgGfGdHaJ_M]Q[TYVV", + "LZLVNSPO SFL[ TFM[ URUSVSURTRRTOU OURVSZT[ OUQVRZT[U[XYZV", + "NVNVPSRO UFOXOZQ[SZTYVV VFPXPZQ[", + "E^EVGSIRKSKUI[ IRJSJUH[ KUMSORPRRSRUP[ PRQSQUO[ RUTSVRWRYSYUXXXZY[ WRXSXUWXWZY[[Z\\Y^V", + "I[IVKSMROSOUM[ MRNSNUL[ OUQSSRTRVSVUUXUZV[ TRUSUUTXTZV[XZYY[V", + "KYRRPRNSMTLVLXMZO[Q[SZTYUWUUTSRRQSQURWTXVXXWYV PRNTMVMYO[", + "L[LVNSPO QLHg RLIg OUQSSRTRVSVUUXUZV[ TRUSUUTXTZV[XZYY[V", + "K[UUTSRRPRNSMTLVLXMZO[Q[SZ PRNTMVMYO[ VRPdPfQgSfTcT[V[YY[V WRT[R`Pd", + "LZLVNSPRRSRUP[ PRQSQUO[ RUTSVRWRVU VRVUWWXWZV", + "NZNVPSQQQSTUUWUYTZR[ QSSUTWTYR[ NZP[U[XYZV", + "NVNVPSRO UFOXOZQ[SZTYVV VFPXPZQ[ PNVN", + "K[NRLXLZN[O[QZSXUU ORMXMZN[ VRTXTZV[XZYY[V WRUXUZV[", + "KZNRMTLWLZN[O[RZTXUUUR ORNTMWMZN[ URVVWWXWZV", + "H]LRJTIWIZK[L[NZPX MRKTJWJZK[ RRPXPZR[S[UZWXXUXR SRQXQZR[ XRYVZW[W]V", + "JZJVLSNRPRQSQUPXOZM[L[KZKYLYKZ WSVTWTWSVRURSSRUQXQZR[U[XYZV QSRU SSQU PXQZ QXOZ", + "K[NRLXLZN[O[QZSXUU ORMXMZN[ VRPd WRT[R`PdOfMgLfLdMaO_R]V[YY[V", + "LYLVNSPRRRTSTVSXPZN[ RRSSSVRXPZ N[P\\Q^QaPdNfLgKfKdLaO^R\\VYYV N[O\\P^PaOdNf", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "NV", + "JZ", + "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF OGMJLOLRMWOZ NYQZSZVY UZWWXRXOWJUG VHSGQGNH", + "H\\NJPISFS[ NJNKPJRHR[S[", + "H\\LKLJMHNGPFTFVGWHXJXLWNUQL[ LKMKMJNHPGTGVHWJWLVNTQK[ LZYZY[ K[Y[", + "H\\MFXFQO MFMGWG WFPO QNSNVOXQYTYUXXVZS[P[MZLYKWLW POSOVPXS TOWQXTXUWXTZ XVVYSZPZMYLW OZLX", + "H\\UIU[V[ VFV[ VFKVZV UILV LUZUZV", + "H\\MFLO NGMN MFWFWG NGWG MNPMSMVNXPYSYUXXVZS[P[MZLYKWLW LOMOONSNVOXR TNWPXSXUWXTZ XVVYSZPZMYLW OZLX", + "H\\VGWIXIWGTFRFOGMJLOLTMXOZR[S[VZXXYUYTXQVOSNRNOOMQ WHTGRGOH PGNJMOMTNXQZ MVOYRZSZVYXV TZWXXUXTWQTO XSVPSOROOPMS QONQMT", + "H\\KFYFO[ KFKGXG XFN[O[", + "H\\PFMGLILKMMNNPOTPVQWRXTXWWYTZPZMYLWLTMRNQPPTOVNWMXKXIWGTFPF NGMIMKNMPNTOVPXRYTYWXYWZT[P[MZLYKWKTLRNPPOTNVMWKWIVG WHTGPGMH LXOZ UZXX", + "H\\WPURRSQSNRLPKMKLLINGQFRFUGWIXMXRWWUZR[P[MZLXMXNZ WMVPSR WNUQRRQRNQLN PRMPLMLLMIPG LKNHQGRGUHWK SGVIWMWRVWTZ UYRZPZMY", + "MXRXQYQZR[S[TZTYSXRX RYRZSZSYRY", + "MXTZS[R[QZQYRXSXTYT\\S^Q_ RYRZSZSYRY S[T\\ TZS^", + "MXRMQNQORPSPTOTNSMRM RNROSOSNRN RXQYQZR[S[TZTYSXRX RYRZSZSYRY", + "MXRMQNQORPSPTOTNSMRM RNROSOSNRN TZS[R[QZQYRXSXTYT\\S^Q_ RYRZSZSYRY S[T\\ TZS^", + "MXRFRTST RFSFST RXQYQZR[S[TZTYSXRX RYRZSZSYRY", + "I\\LKLJMHNGQFTFWGXHYJYLXNWOUPRQ LKMKMJNHQGTGWHXJXLWNUORP MIPG UGXI XMTP RPRTSTSP RXQYQZR[S[TZTYSXRX RYRZSZSYRY", + "MXTFRGQIQLRMSMTLTKSJRJQK RKRLSLSKRK RGQK QIRJ", + "MXTHSIRIQHQGRFSFTGTJSLQM RGRHSHSGRG SITJ THSL", + "F_\\MZMXNWPUVTXSYQZMZKYJWJUKSLRQOSMTKTISGQFPFNGMIMKNNPQUWXZZ[\\[ \\M\\NZNWP ZMXPVVUXSZQ[M[KZJYIWIUJSLQQNRMSKSIRG SHQGPGNH OGNINKONQQVWXYZZ\\Z\\[", + "I\\RBR_S_ RBSBS_ WIYIWGTFQFNGLILKMMNNVRWSXUXWWYTZQZOYNX WIVHTGQGNHMIMKNMVQXSYUYWXYWZT[Q[NZLXNX XXUZ", + "G^[BIbJb [B\\BJb", + "KYUBSDQGOKNPNTOYQ]S`UbVb UBVBTDRGPKOPOTPYR]T`Vb", + "KYNBPDRGTKUPUTTYR]P`NbOb NBOBQDSGUKVPVTUYS]Q`Ob", + "JZRFQGSQRR RFRR RFSGQQRR MINIVOWO MIWO MIMJWNWO WIVINOMO WIMO WIWJMNMO", + "F_JQ[Q[R JQJR[R", + "F_RIRZSZ RISISZ JQ[Q[R JQJR[R", + "F_JM[M[N JMJN[N JU[U[V JUJV[V", + "NWSFRGRM SGRM SFTGRM", + "I[NFMGMM NGMM NFOGMM WFVGVM WGVM WFXGVM", + "KYQFOGNINKOMQNSNUMVKVIUGSFQF QFNIOMSNVKUGQF SFOGNKQNUMVISF", + "F^ZIJRZ[ ZIZJLRZZZ[", + "F^JIZRJ[ JIJJXRJZJ[", + "G^OFObPb OFPFPb UFUbVb UFVFVb JP[P[Q JPJQ[Q JW[W[X JWJX[X", + "F^[FYGVHSHPGNFLFJGIIIKKMMMOLPJPHNF [FH[I[ [F\\FI[ YTWTUUTWTYV[X[ZZ[X[VYT NFJGIKMMPJNF LFIIKMOLPHLF YTUUTYX[[XYT WTTWV[ZZ[VWT", + "E`WMTKQKOLNMMOMRNTOUQVTVWT WMTLQLOMNONROTQUTUWT VKVSWUYVZV\\U]S]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[U[YZ VKWKWSXUZV YV[U\\S\\O[LZJYIWHTGQGNHLIKJJLIOIRJUKWLXNYQZUZYYYZ", + "E_JPLONOPPSTTUVVXVZU[S[QZOXNVNTOSPPTNULUJT ZPXOVOTPQTPUNVLVJUISIQJOLNNNPOQPTTVUXUZT KOJQJSKU YUZSZQYO", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "NV", + "JZ", + "H]TFQGOIMLLOKSKVLYMZO[Q[TZVXXUYRZNZKYHXGVFTF TFRGPINLMOLSLVMYO[ Q[SZUXWUXRYNYKXHVF", + "H]TJO[ VFP[ VFSIPKNL UIQKNL", + "H]OJPKOLNKNJOHPGSFVFYGZIZKYMWOTQPSMUKWI[ VFXGYIYKXMVOPS JYKXMXRZUZWYXW MXR[U[WZXW", + "H]OJPKOLNKNJOHPGSFVFYGZIZKYMVOSP VFXGYIYKXMVO QPSPVQWRXTXWWYVZS[O[LZKYJWJVKULVKW SPUQVRWTWWVYUZS[", + "H]XGR[ YFS[ YFJUZU", + "H]QFLP QF[F QGVG[F LPMOPNSNVOWPXRXUWXUZR[O[LZKYJWJVKULVKW SNUOVPWRWUVXTZR[", + "H]YIXJYKZJZIYGWFTFQGOIMLLOKSKWLYMZO[R[UZWXXVXSWQVPTOQOOPMRLT TFRGPINLMOLSLXMZ R[TZVXWVWRVP", + "H]NFLL [FZIXLSRQUPWO[ XLRRPUOWN[ MIPFRFWI NHPGRGWIYIZH[F", + "H]SFPGOHNJNMOOQPTPXOYNZLZIYGVFSF SFQGPHOJOMPOQP TPWOXNYLYIXGVF QPMQKSJUJXKZN[R[VZWYXWXTWRVQTP QPNQLSKUKXLZN[ R[UZVYWWWSVQ", + "H]YMXOVQTRQROQNPMNMKNIPGSFVFXGYHZJZNYRXUVXTZQ[N[LZKXKWLVMWLX OQNONKOIQGSF XGYIYNXRWUUXSZQ[", + "MXPYOZP[QZPY", + "MXP[OZPYQZQ[P]N_", + "MXSMRNSOTNSM PYOZP[QZ", + "MXSMRNSOTNSM P[OZPYQZQ[P]N_", + "MXUFTGRS UGRS UFVGRS PYOZP[QZPY", + "H]OJPKOLNKNJOHPGSFWFZG[I[KZMYNSPQQQSRTTT WFYGZIZKYMXNVO PYOZP[QZPY", + "MXVFTHSJSKTLUKTJ", + "MXUHTGUFVGVHUJSL", + "E_\\N[O\\P]O]N\\M[MYNWPRXPZN[K[HZGXGVHTISKRPPROTMUKUITGRFPGOIOLPRQUSXUZW[Y[ZYZX K[IZHXHVITJSPP OLPQQTSWUYWZYZZY", + "H]TBL_ YBQ_ ZJYKZL[K[JZHYGVFRFOGMIMKNMONVRXT MKOMVQWRXTXWWYVZS[O[LZKYJWJVKULVKW", + "G]_BEb", + "KZZBVESHQKOONTNXO]P`Qb VESIQMPPOUOZP_Qb", + "JYSBTDUGVLVPUUSYQ\\N_Jb SBTEUJUOTTSWQ[N_", + "J[TFTR OIYO YIOO", + "E_IR[R", + "E_RIR[ IR[R", + "E_IO[O IU[U", + "NWUFSM VFSM", + "I[PFNM QFNM YFWM ZFWM", + "KZSFQGPIPKQMSNUNWMXKXIWGUFSF", + "F^ZIJRZ[", + "F^JIZRJ[", + "H]SFLb YFRb LQZQ KWYW", + "E_^F\\GXHUHQGOFMFKGJIJKLMNMPLQJQHOF ^FF[ XTVTTUSWSYU[W[YZZXZVXT", + "E`WNVLTKQKOLNMMPMSNUPVSVUUVS QKOMNPNSOUPV WKVSVUXVZV\\T]Q]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYZX XKWSWUXV", + "F_\\S[UYVWVUUTTQPPONNLNJOIQISJULVNVPUQTTPUOWNYN[O\\Q\\S", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "H\\RFK[ RFY[ RIX[ MUVU I[O[ U[[[", + "G]LFL[ MFM[ IFYFYLXF MPUPXQYRZTZWYYXZU[I[ UPWQXRYTYWXYWZU[", + "G]LFL[ MFM[ IFUFXGYHZJZLYNXOUP UFWGXHYJYLXNWOUP MPUPXQYRZTZWYYXZU[I[ UPWQXRYTYWXYWZU[", + "I[NFN[ OFO[ KFZFZLYF K[R[", + "F^NFNLMTLXKZJ[ XFX[ YFY[ KF\\F G[\\[ G[Gb H[Gb [[\\b \\[\\b", + "G\\LFL[ MFM[ SLST IFYFYLXF MPSP I[Y[YUX[", + "CbRFR[ SFS[ OFVF GGHHGIFHFGGFHFIGJIKMLONPWPYOZM[I\\G]F^F_G_H^I]H^G NPLQKSJXIZH[ NPMQLSKXJZI[G[FZEX WPYQZS[X\\Z][ WPXQYSZX[Z\\[^[_Z`X O[V[", + "H\\LIKFKLLINGPFTFWGXIXLWNTOQO TFVGWIWLVNTO TOVPXRYTYWXYWZT[O[MZLYKWKVLUMVLW WQXTXWWYVZT[", + "F^KFK[ LFL[ XFX[ YFY[ HFOF UF\\F XHLY H[O[ U[\\[", + "F^KFK[ LFL[ XFX[ YFY[ HFOF UF\\F XHLY H[O[ U[\\[ N@N?M?M@NBPCTCVBW@", + "F^KFK[ LFL[ HFOF LPSPUOVMWIXGYFZF[G[HZIYHZG SPUQVSWXXZY[ SPTQUSVXWZX[Z[[Z\\X H[O[", + "E^MFMLLTKXJZI[H[GZGYHXIYHZ XFX[ YFY[ JF\\F U[\\[", + "F_KFK[ LFRX KFR[ YFR[ YFY[ ZFZ[ HFLF YF]F H[N[ V[][", + "F^KFK[ LFL[ XFX[ YFY[ HFOF UF\\F LPXP H[O[ U[\\[", + "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF QFOGMILKKOKRLVMXOZQ[ S[UZWXXVYRYOXKWIUGSF", + "F^KFK[ LFL[ XFX[ YFY[ HF\\F H[O[ U[\\[", + "G]LFL[ MFM[ IFUFXGYHZJZMYOXPUQMQ UFWGXHYJYMXOWPUQ I[P[", + "G\\XIYLYFXIVGSFQFNGLIKKJNJSKVLXNZQ[S[VZXXYV QFOGMILKKNKSLVMXOZQ[", + "I\\RFR[ SFS[ LFKLKFZFZLYF O[V[", + "H]KFRV LFSV ZFSVQYPZN[M[LZLYMXNYMZ IFOF VF\\F", + "F_RFR[ SFS[ OFVF PILJJLIOIRJULWPXUXYW[U\\R\\O[LYJUIPI PIMJKLJOJRKUMWPX UXXWZU[R[OZLXJUI O[V[", + "H\\KFX[ LFY[ YFK[ IFOF UF[F I[O[ U[[[", + "F^KFK[ LFL[ XFX[ YFY[ HFOF UF\\F H[\\[ [[\\b \\[\\b", + "F]KFKQLSOTRTUSWQ LFLQMSOT WFW[ XFX[ HFOF TF[F T[[[", + "BcGFG[ HFH[ RFR[ SFS[ ]F][ ^F^[ DFKF OFVF ZFaF D[a[", + "BcGFG[ HFH[ RFR[ SFS[ ]F][ ^F^[ DFKF OFVF ZFaF D[a[ `[ab a[ab", + "F`PFP[ QFQ[ IFHLHFTF QPXP[Q\\R]T]W\\Y[ZX[M[ XPZQ[R\\T\\W[YZZX[", + "CaHFH[ IFI[ EFLF IPPPSQTRUTUWTYSZP[E[ PPRQSRTTTWSYRZP[ [F[[ \\F\\[ XF_F X[_[", + "H]MFM[ NFN[ JFQF NPUPXQYRZTZWYYXZU[J[ UPWQXRYTYWXYWZU[", + "H]LIKFKLLINGQFSFVGXIYKZNZSYVXXVZS[P[MZLYKWKVLUMVLW SFUGWIXKYNYSXVWXUZS[ PPYP", + "CbHFH[ IFI[ EFLF E[L[ VFSGQIPKOOORPVQXSZV[X[[Z]X^V_R_O^K]I[GXFVF VFTGRIQKPOPRQVRXTZV[ X[ZZ\\X]V^R^O]K\\IZGXF IPOP", + "G]WFW[ XFX[ [FOFLGKHJJJLKNLOOPWP OFMGLHKJKLLNMOOP RPPQORLYKZJZIY PQOSMZL[J[IYIX T[[[", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "I]NONPMPMONNPMTMVNWOXQXXYZZ[ WOWXXZZ[[[ WQVRPSMTLVLXMZP[S[UZWX PSNTMVMXNZP[", + "H\\XFWGQINKLNKQKULXNZQ[S[VZXXYUYSXPVNSMQMNNLPKS XFWHUIQJNLLN QMONMPLSLUMXOZQ[ S[UZWXXUXSWPUNSM", + "H\\MMM[ NMN[ JMUMXNYPYQXSUT UMWNXPXQWSUT NTUTXUYWYXXZU[J[ UTWUXWXXWZU[", + "HZMMM[ NMN[ JMXMXRWM J[Q[", + "F]NMNQMWLZK[ WMW[ XMX[ KM[M I[H`H[[[[`Z[", + "H[LSXSXQWOVNTMQMNNLPKSKULXNZQ[S[VZXX WSWPVN QMONMPLSLUMXOZQ[", + "E`RMR[ SMS[ OMVM JNIOHNIMJMKNMRNSPTUTWSXRZN[M\\M]N\\O[N PTNUMVKZJ[ PTNVLZK[I[HZGX UTWUXVZZ[[ UTWVYZZ[\\[]Z^X O[V[", + "I[MOLMLQMONNPMTMWNXPXQWSTT TMVNWPWQVSTT QTTTWUXWXXWZT[P[MZLXLWMVNWMX TTVUWWWXVZT[", + "G]LML[ MMM[ WMW[ XMX[ IMPM TM[M I[P[ T[[[ WNMZ", + "G]LML[ MMM[ WMW[ XMX[ IMPM TM[M I[P[ T[[[ WNMZ OGOFNFNGOIQJSJUIVG", + "H\\MMM[ NMN[ JMQM NTPTSSTRVNWMXMYNXOWN PTSUTVVZW[ PTRUSVUZV[X[YZZX J[Q[", + "G]NMNQMWLZK[J[IZJYKZ WMW[ XMX[ KM[M T[[[", + "G^LML[ LMR[ MMRY XMR[ XMX[ YMY[ IMMM XM\\M I[O[ U[\\[", + "G]LML[ MMM[ WMW[ XMX[ IMPM TM[M MTWT I[P[ T[[[", + "H\\QMNNLPKSKULXNZQ[S[VZXXYUYSXPVNSMQM QMONMPLSLUMXOZQ[ S[UZWXXUXSWPUNSM", + "G]LML[ MMM[ WMW[ XMX[ IM[M I[P[ T[[[", + "G\\LMLb MMMb MPONQMSMVNXPYSYUXXVZS[Q[OZMX SMUNWPXSXUWXUZS[ IMMM IbPb", + "H[WPVQWRXQXPVNTMQMNNLPKSKULXNZQ[S[VZXX QMONMPLSLUMXOZQ[", + "I\\RMR[ SMS[ MMLRLMYMYRXM O[V[", + "I[LMR[ MMRY XMR[P_NaLbKbJaK`La JMPM TMZM", + "H]RFRb SFSb OFSF RPQNPMNMLNKQKWLZN[P[QZRX NMMNLQLWMZN[ WMXNYQYWXZW[ SPTNUMWMYNZQZWYZW[U[TZSX ObVb", + "H\\LMW[ MMX[ XML[ JMPM TMZM J[P[ T[Z[", + "G]LML[ MMM[ WMW[ XMX[ IMPM TM[M I[[[[`Z[", + "G]LMLTMVPWRWUVWT MMMTNVPW WMW[ XMX[ IMPM TM[M T[[[", + "CbHMH[ IMI[ RMR[ SMS[ \\M\\[ ]M][ EMLM OMVM YM`M E[`[", + "CbHMH[ IMI[ RMR[ SMS[ \\M\\[ ]M][ EMLM OMVM YM`M E[`[``_[", + "H]QMQ[ RMR[ LMKRKMUM RTVTYUZWZXYZV[N[ VTXUYWYXXZV[", + "E_JMJ[ KMK[ GMNM KTOTRUSWSXRZO[G[ OTQURWRXQZO[ YMY[ ZMZ[ VM]M V[][", + "J[OMO[ PMP[ LMSM PTTTWUXWXXWZT[L[ TTVUWWWXVZT[", + "I\\MOLMLQMONNPMSMVNXPYSYUXXVZS[P[NZLXLWMVNWMX SMUNWPXSXUWXUZS[ RTXT", + "DaIMI[ JMJ[ FMMM F[M[ VMSNQPPSPUQXSZV[X[[Z]X^U^S]P[NXMVM VMTNRPQSQURXTZV[ X[ZZ\\X]U]S\\PZNXM JTPT", + "G\\VMV[ WMW[ ZMOMLNKPKQLSOTVT OMMNLPLQMSOT TTQUPVNZM[ TTRUQVOZN[L[KZJX S[Z[", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "H\\RFKZ QIW[ RIX[ RFY[ MUVU I[O[ T[[[ KZJ[ KZM[ WZU[ WYV[ XYZ[", + "G]LFL[ MGMZ NFN[ IFUFXGYHZJZLYNXOUP XHYJYLXN UFWGXIXMWOUP NPUPXQYRZTZWYYXZU[I[ XRYTYWXY UPWQXSXXWZU[ JFLG KFLH OFNH PFNG LZJ[ LYK[ NYO[ NZP[", + "G\\XIYFYLXIVGTFQFNGLIKKJNJSKVLXNZQ[T[VZXXYV MILKKNKSLVMX QFOGMJLNLSMWOZQ[", + "G]LFL[ MGMZ NFN[ IFSFVGXIYKZNZSYVXXVZS[I[ WIXKYNYSXVWX SFUGWJXNXSWWUZS[ JFLG KFLH OFNH PFNG LZJ[ LYK[ NYO[ NZP[", + "G\\LFL[ MGMZ NFN[ IFYFYL NPTP TLTT I[Y[YU JFLG KFLH OFNH PFNG TFYG VFYH WFYI XFYL TLSPTT TNRPTR TOPPTQ LZJ[ LYK[ NYO[ NZP[ T[YZ V[YY W[YX X[YU", + "G[LFL[ MGMZ NFN[ IFYFYL NPTP TLTT I[Q[ JFLG KFLH OFNH PFNG TFYG VFYH WFYI XFYL TLSPTT TNRPTR TOPPTQ LZJ[ LYK[ NYO[ NZP[", + "G^XIYFYLXIVGTFQFNGLIKKJNJSKVLXNZQ[T[VZXZY[YS MILKKNKSLVMX QFOGMJLNLSMWOZQ[ XTXY WSWYVZ TS\\S USWT VSWU ZSYU [SYT", + "F^KFK[ LGLZ MFM[ WFW[ XGXZ YFY[ HFPF TF\\F MPWP H[P[ T[\\[ IFKG JFKH NFMH OFMG UFWG VFWH ZFYH [FYG KZI[ KYJ[ MYN[ MZO[ WZU[ WYV[ YYZ[ YZ[[", + "LXQFQ[ RGRZ SFS[ NFVF N[V[ OFQG PFQH TFSH UFSG QZO[ QYP[ SYT[ SZU[", + "JZSFSWRZQ[ TGTWSZ UFUWTZQ[O[MZLXLVMUNUOVOWNXMX MVMWNWNVMV PFXF QFSG RFSH VFUH WFUG", + "F\\KFK[ LGLZ MFM[ XGMR PPW[ QPX[ QNY[ HFPF UF[F H[P[ T[[[ IFKG JFKH NFMH OFMG WFXG ZFXG KZI[ KYJ[ MYN[ MZO[ WYU[ WYZ[", + "I[NFN[ OGOZ PFP[ KFSF K[Z[ZU LFNG MFNH QFPH RFPG NZL[ NYM[ PYQ[ PZR[ U[ZZ W[ZY X[ZX Y[ZU", + "E_JFJZ JFQ[ KFQX LFRX XFQ[ XFX[ YGYZ ZFZ[ GFLF XF]F G[M[ U[][ HFJG [FZH \\FZG JZH[ JZL[ XZV[ XYW[ ZY[[ ZZ\\[", + "F^KFKZ KFY[ LFXX MFYX YGY[ HFMF VF\\F H[N[ IFKG WFYG [FYG KZI[ KZM[", + "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF MILKKNKSLVMX WXXVYSYNXKWI QFOGMJLNLSMWOZQ[ S[UZWWXSXNWJUGSF", + "G]LFL[ MGMZ NFN[ IFUFXGYHZJZMYOXPUQNQ XHYJYMXO UFWGXIXNWPUQ I[Q[ JFLG KFLH OFNH PFNG LZJ[ LYK[ NYO[ NZP[", + "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF MILKKNKSLVMX WXXVYSYNXKWI QFOGMJLNLSMWOZQ[ S[UZWWXSXNWJUGSF NXOVQURUTVUXV^W`Y`Z^Z\\ V\\W^X_Y_ UXW]X^Y^Z]", + "G]LFL[ MGMZ NFN[ IFUFXGYHZJZLYNXOUPNP XHYJYLXN UFWGXIXMWOUP RPTQUSWYX[Z[[Y[W WWXYYZZZ TQURXXYYZY[X I[Q[ JFLG KFLH OFNH PFNG LZJ[ LYK[ NYO[ NZP[", + "H\\XIYFYLXIVGSFPFMGKIKLLNOPURWSXUXXWZ LLMNOOUQWRXT MGLILKMMONUPXRYTYWXYWZT[Q[NZLXKUK[LX", + "H\\JFJL QFQ[ RGRZ SFS[ ZFZL JFZF N[V[ KFJL LFJI MFJH OFJG UFZG WFZH XFZI YFZL QZO[ QYP[ SYT[ SZU[", + "F^KFKULXNZQ[S[VZXXYUYG LGLVMX MFMVNYOZQ[ HFPF VF\\F IFKG JFKH NFMH OFMG WFYG [FYG", + "H\\KFR[ LFRXR[ MFSX YGR[ IFPF UF[F JFLH NFMH OFMG WFYG ZFYG", + "F^JFN[ KFNVN[ LFOV RFOVN[ RFV[ SFVVV[ TFWV ZGWVV[ GFOF RFTF WF]F HFKG IFKH MFLH NFLG XFZG \\FZG", + "H\\KFW[ LFX[ MFY[ XGLZ IFPF UF[F I[O[ T[[[ JFMH NFMH OFMG VFXG ZFXG LZJ[ LZN[ WZU[ WYV[ WYZ[", + "G]JFQQQ[ KFRQRZ LFSQS[ YGSQ HFOF VF\\F N[V[ IFKG NFLG WFYG [FYG QZO[ QYP[ SYT[ SZU[", + "H\\YFKFKL WFK[ XFL[ YFM[ K[Y[YU LFKL MFKI NFKH PFKG T[YZ V[YY W[YX X[YU", + "H\\RFKZ QIW[ RIX[ RFY[ MUVU I[O[ T[[[ KZJ[ KZM[ WZU[ WYV[ XYZ[", + "G]LFL[ MGMZ NFN[ IFUFXGYHZJZLYNXOUP XHYJYLXN UFWGXIXMWOUP NPUPXQYRZTZWYYXZU[I[ XRYTYWXY UPWQXSXXWZU[ JFLG KFLH OFNH PFNG LZJ[ LYK[ NYO[ NZP[", + "I[NFN[ OGOZ PFP[ KFZFZL K[S[ LFNG MFNH QFPH RFPG UFZG WFZH XFZI YFZL NYM[ NZL[ PYQ[ PZR[", + "H\\RFJ[ QIX[ RIY[ RFZ[ KYXY KZXZ J[Z[", + "G\\LFL[ MGMZ NFN[ IFYFYL NPTP TLTT I[Y[YU JFLG KFLH OFNH PFNG TFYG VFYH WFYI XFYL TLSPTT TNRPTR TOPPTQ LZJ[ LYK[ NYO[ NZP[ T[YZ V[YY W[YX X[YU", + "H\\YFKFKL WFK[ XFL[ YFM[ K[Y[YU LFKL MFKI NFKH PFKG T[YZ V[YY W[YX X[YU", + "F^KFK[ LGLZ MFM[ WFW[ XGXZ YFY[ HFPF TF\\F MPWP H[P[ T[\\[ IFKG JFKH NFMH OFMG UFWG VFWH ZFYH [FYG KZI[ KYJ[ MYN[ MZO[ WZU[ WYV[ YYZ[ YZ[[", + "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF MILKKNKSLVMX WXXVYSYNXKWI QFOGMJLNLSMWOZQ[ S[UZWWXSXNWJUGSF OMOT UMUT OPUP OQUQ ONPP OOQP UNTP UOSP PQOS QQOR SQUR TQUS", + "LXQFQ[ RGRZ SFS[ NFVF N[V[ OFQG PFQH TFSH UFSG QZO[ QYP[ SYT[ SZU[", + "F\\KFK[ LGLZ MFM[ XGMR PPW[ QPX[ QNY[ HFPF UF[F H[P[ T[[[ IFKG JFKH NFMH OFMG WFXG ZFXG KZI[ KYJ[ MYN[ MZO[ WYU[ WYZ[", + "H\\RFKZ QIW[ RIX[ RFY[ I[O[ T[[[ KZJ[ KZM[ WZU[ WYV[ XYZ[", + "E_JFJZ JFQ[ KFQX LFRX XFQ[ XFX[ YGYZ ZFZ[ GFLF XF]F G[M[ U[][ HFJG [FZH \\FZG JZH[ JZL[ XZV[ XYW[ ZY[[ ZZ\\[", + "F^KFKZ KFY[ LFXX MFYX YGY[ HFMF VF\\F H[N[ IFKG WFYG [FYG KZI[ KZM[", + "G]JEJL ZEZL OMOT UMUT JUJ\\ ZUZ\\ JGZG JHZH JIZI OPUP OQUQ JXZX JYZY JZZZ JFMH ZFWH KIJK LIJJ XIZJ YIZK ONPP OOQP UNTP UOSP PQOS QQOR SQUR TQUS JVKX JWLX ZWXX ZVYX MYJ[ WYZ[", + "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF MILKKNKSLVMX WXXVYSYNXKWI QFOGMJLNLSMWOZQ[ S[UZWWXSXNWJUGSF", + "F^KFK[ LGLZ MFM[ WFW[ XGXZ YFY[ HF\\F H[P[ T[\\[ IFKG JFKH NFMH OFMG UFWG VFWH ZFYH [FYG KZI[ KYJ[ MYN[ MZO[ WZU[ WYV[ YYZ[ YZ[[", + "G]LFL[ MGMZ NFN[ IFUFXGYHZJZMYOXPUQNQ XHYJYMXO UFWGXIXNWPUQ I[Q[ JFLG KFLH OFNH PFNG LZJ[ LYK[ NYO[ NZP[", + "G]IFPPQQ JFQP KFRPI[ IFYFZLYIWF VFYH TFYG KYYY JZYZ I[Y[ZUYXWY", + "H\\JFJL QFQ[ RGRZ SFS[ ZFZL JFZF N[V[ KFJL LFJI MFJH OFJG UFZG WFZH XFZI YFZL QZO[ QYP[ SYT[ SZU[", + "H\\JMKILGMFOFPGQIRM LHMGOGPH JMKJMHOHPIQMQ[ RMR[ ZMYJWHUHTISMS[ XHWGUGTH ZMYIXGWFUFTGSIRM N[V[ QYP[ QZO[ SZU[ SYT[", + "G]QFQ[ RGRZ SFS[ NFVF N[V[ OFQG PFQH TFSH UFSG QZO[ QYP[ SYT[ SZU[ OKLLKMJOJRKTLUOVUVXUYTZRZOYMXLUKOK LMKOKRLT XTYRYOXM OKMLLOLRMUOV UVWUXRXOWLUK", + "H\\KFW[ LFX[ MFY[ XGLZ IFPF UF[F I[O[ T[[[ JFMH NFMH OFMG VFXG ZFXG LZJ[ LZN[ WZU[ WYV[ WYZ[", + "F^QFQ[ RGRZ SFS[ NFVF N[V[ OFQG PFQH TFSH UFSG QZO[ QYP[ SYT[ SZU[ HMIMJNKQLSMTPUTUWTXSYQZN[M\\M LRKNJLILKN HMIKJKKLLPMSNTPU YN[LZLYNXR TUVTWSXPYLZK[K\\M", + "G]NYKYJWK[O[MVKRJOJLKIMGPFTFWGYIZLZOYRWVU[Y[ZWYYVY LSKOKLLI XIYLYOXS O[MULPLKMHNGPF TFVGWHXKXPWUU[ KZNZ VZYZ", + "H\\UFIZ SJT[ THUZ UFUHVYV[ LUTU F[L[ Q[X[ IZG[ IZK[ TZR[ TYS[ VYW[", + "F^OFI[ PFJ[ QFK[ LFWFZG[I[KZNYOVP YGZIZKYNXO WFXGYIYKXNVP NPVPXQYSYUXXVZR[F[ WQXSXUWXUZ VPWRWUVXTZR[ MFPG NFOH RFPH SFPG JZG[ JYH[ KYL[ JZM[", + "H]ZH[H\\F[L[JZHYGWFTFQGOIMLLOKSKVLYMZP[S[UZWXXV QHOJNLMOLSLWMY TFRGPJOLNOMSMXNZP[", + "F]OFI[ PFJ[ QFK[ LFUFXGYHZKZOYSWWUYSZO[F[ WGXHYKYOXSVWTY UFWHXKXOWSUWRZO[ MFPG NFOH RFPH SFPG JZG[ JYH[ KYL[ JZM[", + "F]OFI[ PFJ[ QFK[ ULST LF[FZL NPTP F[U[WV MFPG NFOH RFPH SFPG WFZG XFZH YFZI ZFZL ULSPST TNRPSR TOQPSQ JZG[ JYH[ KYL[ JZM[ P[UZ R[UY UYWV", + "F\\OFI[ PFJ[ QFK[ ULST LF[FZL NPTP F[N[ MFPG NFOH RFPH SFPG WFZG XFZH YFZI ZFZL ULSPST TNRPSR TOQPSQ JZG[ JYH[ KYL[ JZM[", + "H^ZH[H\\F[L[JZHYGWFTFQGOIMLLOKSKVLYMZP[R[UZWXYT QHOJNLMOLSLWMY VXWWXT TFRGPJOLNOMSMXNZP[ R[TZVWWT TT\\T UTWU VTWW ZTXV [TXU", + "E_NFH[ OFI[ PFJ[ ZFT[ [FU[ \\FV[ KFSF WF_F LPXP E[M[ Q[Y[ LFOG MFNH QFOH RFOG XF[G YFZH ]F[H ^F[G IZF[ IYG[ JYK[ IZL[ UZR[ UYS[ VYW[ UZX[", + "KYTFN[ UFO[ VFP[ QFYF K[S[ RFUG SFTH WFUH XFUG OZL[ OYM[ PYQ[ OZR[", + "I\\WFRWQYO[ XFTSSVRX YFUSSXQZO[M[KZJXJVKULUMVMWLXKX KVKWLWLVKV TF\\F UFXG VFWH ZFXH [FXG", + "F]OFI[ PFJ[ QFK[ \\GMR QOU[ ROV[ SNWZ LFTF YF_F F[N[ R[Y[ MFPG NFOH RFPH SFPG ZF\\G ^F\\G JZG[ JYH[ KYL[ JZM[ UZS[ UYT[ VYX[", + "H\\QFK[ RFL[ SFM[ NFVF H[W[YU OFRG PFQH TFRH UFRG LZI[ LYJ[ MYN[ LZO[ R[WZ T[XX V[YU", + "D`MFGZ MGNYN[ NFOY OFPX [FPXN[ [FU[ \\FV[ ]FW[ JFOF [F`F D[J[ R[Z[ KFMG LFMH ^F\\H _F\\G GZE[ GZI[ VZS[ VYT[ WYX[ VZY[", + "F_OFIZ OFV[ PFVX QFWX \\GWXV[ LFQF YF_F F[L[ MFPG NFPH ZF\\G ^F\\G IZG[ IZK[", + "G]SFPGNILLKOJSJVKYLZN[Q[TZVXXUYRZNZKYHXGVFSF OIMLLOKSKWLY UXWUXRYNYJXH SFQGOJNLMOLSLXMZN[ Q[SZUWVUWRXNXIWGVF", + "F]OFI[ PFJ[ QFK[ LFXF[G\\I\\K[NYPUQMQ ZG[I[KZNXP XFYGZIZKYNWPUQ F[N[ MFPG NFOH RFPH SFPG JZG[ JYH[ KYL[ JZM[", + "G]SFPGNILLKOJSJVKYLZN[Q[TZVXXUYRZNZKYHXGVFSF OIMLLOKSKWLY UXWUXRYNYJXH SFQGOJNLMOLSLXMZN[ Q[SZUWVUWRXNXIWGVF LXMVOUPURVSXT]U^V^W] T^U_V_ SXS_T`V`W]W\\", + "F^OFI[ PFJ[ QFK[ LFWFZG[I[KZNYOVPNP YGZIZKYNXO WFXGYIYKXNVP RPTQURWXXYYYZX WYXZYZ URVZW[Y[ZXZW F[N[ MFPG NFOH RFPH SFPG JZG[ JYH[ KYL[ JZM[", + "G^ZH[H\\F[L[JZHYGVFRFOGMIMLNNPPVSWUWXVZ NLONVRWT OGNINKOMUPWRXTXWWYVZS[O[LZKYJWJUI[JYKY", + "G]TFN[ UFO[ VFP[ MFKL ]F\\L MF]F K[S[ NFKL PFLI RFMG YF\\G ZF\\H [F\\I \\F\\L OZL[ OYM[ PYQ[ OZR[", + "F_NFKQJUJXKZN[R[UZWXXU\\G OFLQKUKYLZ PFMQLULYN[ KFSF YF_F LFOG MFNH QFOH RFOG ZF\\G ^F\\G", + "H\\NFNHOYO[ OGPX PFQW [GO[ LFSF XF^F MFNH QFPH RFOG YF[G ]F[G", + "E_MFMHKYK[ NGLX OFMW UFMWK[ UFUHSYS[ VGTX WFUW ]GUWS[ JFRF UFWF ZF`F KFNG LFMH PFNI QFNG [F]G _F]G", + "G]NFT[ OFU[ PFV[ [GIZ LFSF XF^F F[L[ Q[X[ MFOH QFPH RFPG YF[G ]F[G IZG[ IZK[ TZR[ TYS[ UYW[", + "G]MFQPN[ NFRPO[ OFSPP[ \\GSP KFRF YF_F K[S[ LFNG PFOH QFNG ZF\\G ^F\\G OZL[ OYM[ PYQ[ OZR[", + "G]ZFH[ [FI[ \\FJ[ \\FNFLL H[V[XU OFLL PFMI RFNG R[VZ T[WX U[XU", + "", + "", + "", + "", + "", + "", + "H\\JFR[ KFRX LFSX JFZFR[ LGYG LHYH", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "I]NPNOOOOQMQMONNPMTMVNWOXQXXYZZ[ VOWQWXXZ TMUNVPVXWZZ[[[ VRUSPTMULWLXMZP[S[UZVX NUMWMXNZ USQTOUNWNXOZP[", + "G\\LFL[MZOZ MGMY IFNFNZ NPONQMSMVNXPYSYUXXVZS[Q[OZNX WPXRXVWX SMUNVOWRWVVYUZS[ JFLG KFLH", + "H[WQWPVPVRXRXPVNTMQMNNLPKSKULXNZQ[S[VZXX MPLRLVMX QMONNOMRMVNYOZQ[", + "H]VFV[[[ WGWZ SFXFX[ VPUNSMQMNNLPKSKULXNZQ[S[UZVX MPLRLVMX QMONNOMRMVNYOZQ[ TFVG UFVH XYY[ XZZ[", + "H[MSXSXQWOVNSMQMNNLPKSKULXNZQ[S[VZXX WRWQVO MPLRLVMX VSVPUNSM QMONNOMRMVNYOZQ[", + "KYWHWGVGVIXIXGWFTFRGQHPKP[ RHQKQZ TFSGRIR[ MMVM M[U[ PZN[ PYO[ RYS[ RZT[", + "I\\XNYOZNYMXMVNUO QMONNOMQMSNUOVQWSWUVVUWSWQVOUNSMQM OONQNSOU UUVSVQUO QMPNOPOTPVQW SWTVUTUPTNSM NUMVLXLYM[N\\Q]U]X^Y_ N[Q\\U\\X] LYMZP[U[X\\Y^Y_XaUbObLaK_K^L\\O[ ObMaL_L^M\\O[", + "G^LFL[ MGMZ IFNFN[ NQOOPNRMUMWNXOYRY[ WOXRXZ UMVNWQW[ I[Q[ T[\\[ JFLG KFLH LZJ[ LYK[ NYO[ NZP[ WZU[ WYV[ YYZ[ YZ[[", + "LXQFQHSHSFQF RFRH QGSG QMQ[ RNRZ NMSMS[ N[V[ OMQN PMQO QZO[ QYP[ SYT[ SZU[", + "KXRFRHTHTFRF SFSH RGTG RMR^QaPb SNS]R` OMTMT]S`RaPbMbLaL_N_NaMaM` PMRN QMRO", + "G]LFL[ MGMZ IFNFN[ WNNW RSY[ RTX[ QTW[ TM[M I[Q[ T[[[ JFLG KFLH UMWN ZMWN LZJ[ LYK[ NYO[ NZP[ WYU[ VYZ[", + "LXQFQ[ RGRZ NFSFS[ N[V[ OFQG PFQH QZO[ QYP[ SYT[ SZU[", + "AcFMF[ GNGZ CMHMH[ HQIOJNLMOMQNROSRS[ QORRRZ OMPNQQQ[ SQTOUNWMZM\\N]O^R^[ \\O]R]Z ZM[N\\Q\\[ C[K[ N[V[ Y[a[ DMFN EMFO FZD[ FYE[ HYI[ HZJ[ QZO[ QYP[ SYT[ SZU[ \\ZZ[ \\Y[[ ^Y_[ ^Z`[", + "G^LML[ MNMZ IMNMN[ NQOOPNRMUMWNXOYRY[ WOXRXZ UMVNWQW[ I[Q[ T[\\[ JMLN KMLO LZJ[ LYK[ NYO[ NZP[ WZU[ WYV[ YYZ[ YZ[[", + "H\\QMNNLPKSKULXNZQ[S[VZXXYUYSXPVNSMQM MPLRLVMX WXXVXRWP QMONNOMRMVNYOZQ[ S[UZVYWVWRVOUNSM", + "G\\LMLb MNMa IMNMNb NPONQMSMVNXPYSYUXXVZS[Q[OZNX WPXRXVWX SMUNVOWRWVVYUZS[ IbQb JMLN KMLO LaJb L`Kb N`Ob NaPb", + "H\\VNVb WOWa UNWNXMXb VPUNSMQMNNLPKSKULXNZQ[S[UZVX MPLRLVMX QMONNOMRMVNYOZQ[ Sb[b VaTb V`Ub X`Yb XaZb", + "IZNMN[ ONOZ KMPMP[ WOWNVNVPXPXNWMUMSNQPPS K[S[ LMNN MMNO NZL[ NYM[ PYQ[ PZR[", + "J[WOXMXQWOVNTMPMNNMOMQNSPTUUWVXY NNMQ NRPSUTWU XVWZ MONQPRUSWTXVXYWZU[Q[OZNYMWM[NY", + "KZPHPVQYRZT[V[XZYX QHQWRY PHRFRWSZT[ MMVM", + "G^LMLVMYNZP[S[UZVYWW MNMWNY IMNMNWOZP[ WMW[\\[ XNXZ TMYMY[ JMLN KMLO YYZ[ YZ[[", + "I[LMR[ MMRY NMSY XNSYR[ JMQM TMZM KMNO PMNN VMXN YMXN", + "F^JMN[ KMNX LMOX RMOXN[ RMV[ SMVX RMTMWX ZNWXV[ GMOM WM]M HMKN NMLN XMZN \\MZN", + "H\\LMV[ MMW[ NMX[ WNMZ JMQM TMZM J[P[ S[Z[ KMMN PMNN UMWN YMWN MZK[ MZO[ VZT[ WZY[", + "H[LMR[ MMRY NMSY XNSYP_NaLbJbIaI_K_KaJaJ` JMQM TMZM KMNO PMNN VMXN YMXN", + "I[VML[ WMM[ XMN[ XMLMLQ L[X[XW MMLQ NMLP OMLO QMLN S[XZ U[XY V[XX W[XW", + "G^[MZQYTWXUZR[P[MZKXJUJSKPMNPMRMUNVOWQYXZZ[[\\[ ZMYQXTWVUYTZR[ LXKVKRLP P[NZMYLVLRMONNPM RMTNUOVQXXYZ[[", + "G\\QFNGMHLJKNKb NHMJLNLa QFOGNIMNMb QFSFVGWHXJXLWNVOSP PPTPWQXRYTYWXYWZT[Q[OZNYMW VHWJWLVN WRXTXWWY SFUGVIVMUOSP TPVQWSWXVZT[ KbMb", + "F\\HRINKMMMONPOQRRYSb IOKNMNOOPP HRIPKOMOOPPQQTRYRa XMWPVRTUSWR[Qb YMWQ ZMYOWRTVSXR[ XMZM QbSb", + "H\\SMQMNNLPKSKULXNZQ[S[VZXXYUYSXPVNSMPLNKMJMHNGPFSFWH MPLSLUMX WXXUXSWP QMONNOMRMVNYOZQ[ S[UZVYWVWRVOUNOKNJNIOHQGTGWH", + "I[SMUNVOWOVNSMQMMNLOLQMRQS SSQSMTKVKXMZP[S[VZXXWXVZ NNMOMQNR MULVLXMY QMONNONQORQS QSNTMVMXNZP[", + "I[QHRGRFQFPGPIQJTKXKYKYJXJUKSLPNNPMRLULWMYNZP[S\\U]V_VaUbSbRaR`S`Sa POOPNRMUMWNYOZ UKRMQNOQNTNWOYQ[S\\", + "G]JMKNLPL[ KMLNMPMZ HPINJMLMMNNPN[ UMVNWQWb WOXRXa NQOOPNRMUMWNXOYRYb L[N[ WbYb", + "F]IMJNKPKTLWMYNZQ[S[VZWYXWYRYOXJVGTFRFPGOIOKPMSOVP[Q JMKNLPLTMWNY VYWWXRXOWJVHTG GPHNIMKMLNMPMTNXOZQ[ S[UZVXWSWNVJUHSGQGOI", + "KZNMONPPPXQZS[U[WZXX OMPNQPQXRZ LPMNNMPMQNRPRXSZT[", + "G]JMKNLPL[ KMLNMPMZ HPINJMLMMNNPN[ SOUNWNXOXPZPZNXMVMTNQQOTNW XNYOYP PSQSWYYYZX TWWZYZ RTUZV[X[YZZX L[N[", + "H\\JGKFMFOGQIXXYZZ[ OHPIWXXY MFNGOIVXXZZ[[[ RMJZJ[K[RM", + "G]KMKb LNLa MMMb VMVXWZX[Z[[Z\\X WNWXXZY[ XMXXYZZ[ MXNZP[R[TZUYVW KMMM VMXM KbMb", + "G]JMKNLPMTN[ KMLNMPNTOZ HPINJMLMMNNPOTPZ VVWTXQXMYMZNYQXSVVTXQZN[ XRYOYM", + "JZPGSFRFPGOHOIPJSKVLWKVJSKPLNMMOMQNRPSSTVUWTVSSTOUMVLXLZM[O\\S]U^V_VaTbRbOaPaRb OMNONQOR NVMXMZN[ VKSKQLPMOOOQQSST VTSTPUOVNXNZP\\S]", + "H\\QMNNLPKSKULXNZQ[S[VZXXYUYSXPVNSMQM MPLRLVMX WXXVXRWP QMONNOMRMVNYOZQ[ S[UZVYWVWRVOUNSM", + "G]IQJOKNMM[M KOMNZN IQJPLO[O OONZM[LZMWOO UOVZW[XZWWUO [M[O OOMZ UOWZ", + "G\\QMNNLPKTKb MPLTLa QMONNOMSMb MWNYOZQ[S[VZXXYUYSXPVNSMQM WXXVXRWP S[UZVYWVWRVOUNSM KbMb", + "G]PMMNKPJSJUKXMZP[R[UZWXXUXSWPUNRM LPKRKVLX VXWVWRVP PMNNMOLRLVMYNZP[ R[TZUYVVVRUOTNRM RMZO[N[MPM RMZN", + "H\\JQKOLNNMZM LONNYN JQKPMOZO ROQZR[SZRO ZMZO RORZ", + "G\\JMKNLPLUMXOZQ[S[UZWXXVYRYNXMWMXPXSWWUZ KMLNMPMUNX WMXNXO HPINJMLMMNNPNVOYQ[", + "G]RQQNPMNMLNKOJRJUKXMZP[T[WZYXZUZRYOXNVMTMSNRQ LOKRKULX XXYUYRXO NMMNLQLVMYNZP[ T[VZWYXVXQWNVM RQQb RQRa RQSb QbSb", + "H\\LMMNNPT_VaXbZb[a NOOPU_V` INJMLMNNPPV_WaXb VSXPYMZMYOVSN\\K`JbKbL_N\\", + "F]HNINJPJUKXMZP[T[VZXXYVZRZNYMXMYPYSXWVZ JNKPKULX XMYNYO GPHNIMJMKNLPLVMYNZP[ QFSb RGRa SFQb QFSF QbSb", + "F^NMLNJPISIWJYKZM[O[QZRYSWSTRSQTQWRYSZU[W[YZZY[W[SZPXNVM KPJSJWKY RTRX YYZWZSYP NMLOKRKWLZM[ W[XZYWYRXOVM", + "G]WMUTUXVZW[Y[[Y\\W XMVTVZ WMYMWTVX UTUQTNRMPMMNKQJTJVKYLZN[P[RZSYTWUT NNLQKTKWLY PMNOMQLTLWMZN[", + "I\\PFNMMSMWNYOZQ[S[VZXWYTYRXOWNUMSMQNPOOQNT QFOMNQNWOZ VYWWXTXQWO MFRFPMNT S[UYVWWTWQVNUM NFQG OFPH", + "I[WQWPVPVRXRXPWNUMRMONMQLTLVMYNZP[R[UZWW OONQMTMWNY RMPOOQNTNWOZP[", + "G]YFVQUUUXVZW[Y[[Y\\W ZFWQVUVZ VF[FWTVX UTUQTNRMPMMNKQJTJVKYLZN[P[RZSYTWUT MOLQKTKWLY PMNOMQLTLWMZN[ WFZG XFYH", + "I[MVQUTTWRXPWNUMRMONMQLTLVMYNZP[R[UZWX OONQMTMWNY RMPOOQNTNWOZP[", + "JZZHZGYGYI[I[GZFXFVGTISKRNQRO[N^M`Kb TJSMRRP[O^ XFVHUJTMSRQZP]O_MaKbIbHaH_J_JaIaI` NMYM", + "H]XMT[S^QaOb YMU[S_ XMZMV[T_RaObLbJaI`I^K^K`J`J_ VTVQUNSMQMNNLQKTKVLYMZO[Q[SZTYUWVT NOMQLTLWMY QMOONQMTMWNZO[", + "G]OFI[K[ PFJ[ LFQFK[ MTOPQNSMUMWNXPXSVX WNWRVVVZ WPUUUXVZW[Y[[Y\\W MFPG NFOH", + "KXTFTHVHVFTF UFUH TGVG LQMOOMQMRNSPSSQX RNRRQVQZ RPPUPXQZR[T[VYWW", + "KXUFUHWHWFUF VFVH UGWG MQNOPMRMSNTPTSRZQ]P_NaLbJbIaI_K_KaJaJ` SNSSQZP]O_ SPRTP[O^N`Lb", + "G]OFI[K[ PFJ[ LFQFK[ YOYNXNXPZPZNYMWMUNQROS MSOSQTRUTYUZWZ QUSYTZ OSPTRZS[U[WZYW MFPG NFOH", + "LXTFQQPUPXQZR[T[VYWW UFRQQUQZ QFVFRTQX RFUG SFTH", + "@cAQBODMFMGNHPHSF[ GNGSE[ GPFTD[F[ HSJPLNNMPMRNSPSSQ[ RNRSP[ RPQTO[Q[ SSUPWNYM[M]N^P^S\\X ]N]R\\V\\Z ]P[U[X\\Z][_[aYbW", + "F^GQHOJMLMMNNPNSL[ MNMSK[ MPLTJ[L[ NSPPRNTMVMXNYPYSWX XNXRWVWZ XPVUVXWZX[Z[\\Y]W", + "H\\QMNNLQKTKVLYMZP[S[VZXWYTYRXOWNTMQM NOMQLTLWMY VYWWXTXQWO QMOONQMTMWNZP[ S[UYVWWTWQVNTM", + "G]HQIOKMMMNNOPOSNWKb NNNSMWJb NPMTIb OTPQQORNTMVMXNYOZRZTYWWZT[R[PZOWOT XOYQYTXWWY VMWNXQXTWWVYT[ FbNb JaGb J`Hb K`Lb JaMb", + "G\\WMQb XMRb WMYMSb UTUQTNRMPMMNKQJTJVKYLZN[P[RZSYTWUT MOLQKTKWLY PMNOMQLTLWMZN[ NbVb RaOb R`Pb S`Tb RaUb", + "I[JQKOMMOMPNQPQTO[ PNPTN[ PPOTM[O[ YOYNXNXPZPZNYMWMUNSPQT", + "J[XPXOWOWQYQYOXNUMRMONNONQOSQTTUVVWX ONNQ ORQSTTVU WVVZ NOOQQRTSVTWVWXVZS[P[MZLYLWNWNYMYMX", + "KYTFQQPUPXQZR[T[VYWW UFRQQUQZ TFVFRTQX NMXM", + "F^GQHOJMLMMNNPNSLX MNMRLVLZ MPKUKXLZN[P[RZTXVU XMVUVXWZX[Z[\\Y]W YMWUWZ XMZMXTWX", + "H\\IQJOLMNMONPPPSNX ONORNVNZ OPMUMXNZP[R[TZVXXUYQYMXMXNYP", + "CaDQEOGMIMJNKPKSIX JNJRIVIZ JPHUHXIZK[M[OZQXRU TMRURXSZU[W[YZ[X]U^Q^M]M]N^P UMSUSZ TMVMTTSX", + "G]JQLNNMPMRNSPSR PMQNQRPVOXMZK[I[HZHXJXJZIZIY RORRQVQY ZOZNYNYP[P[NZMXMVNTPSRRVRZS[ PVPXQZS[U[WZYW", + "G]HQIOKMMMNNOPOSMX NNNRMVMZ NPLULXMZO[Q[SZUXWT YMU[T^RaPb ZMV[T_ YM[MW[U_SaPbMbKaJ`J^L^L`K`K_", + "H\\YMXOVQNWLYK[ XOOOMPLR VORNONNO VORMOMMOLR LYUYWXXV NYRZUZVY NYR[U[WYXV", + "", + "", + "", + "", + "", + "", + "H\\WQVOUNSMQMNNLPKSKULXNZQ[S[VZWYXWYSYNXJWHVGSFQFNGMHNHOGQF MPLRLVMX VYWWXSXNWJVH QMONNOMRMVNYOZQ[ S[UZVXWTWMVIUGSF", + "I[UMWNXOYOXNUMRMONMPLSLUMXOZR[U[XZYYXYWZU[ NPMSMUNX RMPNOONRNVOYPZR[ NTTUUTTSNT NTTT", + "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF NHMJLNLSMWNY VYWWXSXNWJVH QFOGNIMNMSNXOZQ[ S[UZVXWSWNVIUGSF LPXQ LQXP", + "G]PMMNKPJSJUKXMZP[T[WZYXZUZSYPWNTMPM LPKSKULX XXYUYSXP PMNNMOLRLVMYNZP[T[VZWYXVXRWOVNTM QFSb RGRa SFQb QFSF QbSb", + "H\\TMVNXPYPYOWNTMPMMNLOKQKSLUNWPXRYSZT\\T^S_Q_O^P^Q_ MOLQLSMUOW PMNNMPMSNURY YPXO", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "NV", + "JZ", + "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF NHMJLNLSMWNY VYWWXSXNWJVH QFOGNIMNMSNXOZQ[ S[UZVXWSWNVIUGSF", + "H\\QHQ[ RHRZ SFS[ SFPINJ M[W[ QZO[ QYP[ SYT[ SZU[", + "H\\LJLKMKMJLJ LIMINJNKMLLLKKKJLHMGPFTFWGXHYJYLXNUPPRNSLUKXK[ WHXJXLWN TFVGWJWLVNTPPR KYLXNXSYWYYX NXSZWZXY NXS[W[XZYXYV", + "H\\LJLKMKMJLJ LIMINJNKMLLLKKKJLHMGPFTFWGXIXLWNTO VGWIWLVN SFUGVIVLUNSO QOTOVPXRYTYWXYWZT[P[MZLYKWKVLUMUNVNWMXLX WRXTXWWY SOUPVQWTWWVZT[ LVLWMWMVLV", + "H\\SIS[ THTZ UFU[ UFJUZU P[X[ SZQ[ SYR[ UYV[ UZW[", + "H\\MFKPMNPMSMVNXPYSYUXXVZS[P[MZLYKWKVLUMUNVNWMXLX WPXRXVWX SMUNVOWRWVVYUZS[ LVLWMWMVLV MFWF MGUG MHQHUGWF", + "H\\VIVJWJWIVI WHVHUIUJVKWKXJXIWGUFRFOGMILKKOKULXNZQ[S[VZXXYUYTXQVOSNQNOONPMR NIMKLOLUMXNY WXXVXSWQ RFPGOHNJMNMUNXOZQ[ S[UZVYWVWSVPUOSN", + "H\\KFKL YFYIXLTQSSRWR[ SRRTQWQ[ XLSQQTPWP[R[ KJLHNFPFUIWIXHYF MHNGPGRH KJLINHPHUI", + "H\\PFMGLILLMNPOTOWNXLXIWGTFPF NGMIMLNN VNWLWIVG PFOGNINLONPO TOUNVLVIUGTF POMPLQKSKWLYMZP[T[WZXYYWYSXQWPTO MQLSLWMY WYXWXSWQ PONPMSMWNZP[ T[VZWWWSVPTO", + "H\\MWMXNXNWMW WOVQURSSQSNRLPKMKLLINGQFSFVGXIYLYRXVWXUZR[O[MZLXLWMVNVOWOXNYMY MPLNLKMI VHWIXLXRWVVX QSORNQMNMKNHOGQF SFUGVIWLWSVWUYTZR[", + "MXRXQYQZR[S[TZTYSXRX RYRZSZSYRY", + "MXTZS[R[QZQYRXSXTYT\\S^Q_ RYRZSZSYRY S[T\\ TZS^", + "MXRMQNQORPSPTOTNSMRM RNROSOSNRN RXQYQZR[S[TZTYSXRX RYRZSZSYRY", + "MXRMQNQORPSPTOTNSMRM RNROSOSNRN TZS[R[QZQYRXSXTYT\\S^Q_ RYRZSZSYRY S[T\\ TZS^", + "MXRFQGQIRQ RFRTST RFSFST SFTGTISQ RXQYQZR[S[TZTYSXRX RYRZSZSYRY", + "I\\MKMJNJNLLLLJMHNGPFTFWGXHYJYLXNWOSQ WHXIXMWN TFVGWIWMVOUP RQRTSTSQRQ RXQYQZR[S[TZTYSXRX RYRZSZSYRY", + "MXTFRGQIQLRMSMTLTKSJRJQK RKRLSLSKRK RGQK QIRJ", + "MXTHSIRIQHQGRFSFTGTJSLQM RGRHSHSGRG SITJ THSL", + "E_[O[NZNZP\\P\\N[MZMYNXPVUTXRZP[L[JZIXIUJSPORMSKSIRGPFNGMIMLNOPRTWWZY[[[\\Y\\X KZJXJUKSLR RMSI SKRG NGMK NNPQTVWYYZ N[LZKXKULSPO MINMQQUVXYZZ[Z\\Y", + "H\\PBP_ TBT_ XKXJWJWLYLYJXHWGTFPFMGKIKLLNOPURWSXUXXWZ LLMNOOUQWRXT MGLILKMMONUPXRYTYWXYWZT[P[MZLYKWKUMUMWLWLV", + "G^[BIbJb [B\\BJb", + "KYUBSDQGOKNPNTOYQ]S`Ub QHPKOOOUPYQ\\ SDRFQIPOPUQ[R^S`", + "KYOBQDSGUKVPVTUYS]Q`Ob SHTKUOUUTYS\\ QDRFSITOTUS[R^Q`", + "JZRFQGSQRR RFRR RFSGQQRR MINIVOWO MIWO MIMJWNWO WIVINOMO WIMO WIWJMNMO", + "F_JQ[Q[R JQJR[R", + "F_RIRZSZ RISISZ JQ[Q[R JQJR[R", + "F_JM[M[N JMJN[N JU[U[V JUJV[V", + "NWSFRGRM SGRM SFTGRM", + "I[NFMGMM NGMM NFOGMM WFVGVM WGVM WFXGVM", + "KYQFOGNINKOMQNSNUMVKVIUGSFQF QFNIOMSNVKUGQF SFOGNKQNUMVISF", + "F^ZIJRZ[ ZIZJLRZZZ[", + "F^JIZRJ[ JIJJXRJZJ[", + "G^OFObPb OFPFPb UFUbVb UFVFVb JP[P[Q JPJQ[Q JW[W[X JWJX[X", + "F^[FYGVHSHPGNFLFJGIIIKKMMMOLPJPHNF [FH[ [FI[ [FJ[ YTWTUUTWTYV[X[ZZ[X[VYT OGLFIIJLMMPJOG NFJGIK KMOLPH ZUWTTWUZX[[XZU YTUUTY V[ZZ[V H[J[", + "E`VNULSKQKOLNMMOMRNTOUQVSVUUVS OMNONROT QKPLOOORPUQV VKVSWUYVZV\\U]R]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYXYWZ WLWSXU VKXKXSYUZV", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "NV", + "JZ", + "H]TFQGOIMLLOKSKVLYMZO[Q[TZVXXUYRZNZKYHXGVFTF QHOJNLMOLSLWMY TYVWWUXRYNYJXH TFRGPJOLNOMSMXNZO[ Q[SZUWVUWRXNXIWGVF", + "H]TJO[Q[ WFUJP[ WFQ[ WFTIQKOL TJRKOL", + "H]OKOJPJPLNLNJOHPGSFVFYGZIZKYMWOMUKWI[ XGYIYKXMVOSQ VFWGXIXKWMUOMU JYKXMXRYWYXX MXRZWZ MXR[U[WZXXXW", + "H]OKOJPJPLNLNJOHPGSFVFYGZIZKYMXNVOSP XGYIYKXMWN VFWGXIXKWMUOSP QPSPVQWRXTXWWYUZR[O[LZKYJWJULULWKWKV VRWTWWVY SPUQVSVWUYTZR[", + "H]WJR[T[ ZFXJS[ ZFT[ ZFJUZU", + "H]QFLP QF[F QGYG PHUHYG[F LPMOPNSNVOWPXRXUWXUZQ[N[LZKYJWJULULWKWKV VPWRWUVXTZ SNUOVQVUUXSZQ[", + "H]YJYIXIXKZKZIYGWFTFQGOIMLLOKSKVLYMZO[R[UZWXXVXSWQVPTOQOOPNQMS PINLMOLSLWMY VXWVWSVQ TFRGPJOLNOMSMXNZO[ R[TZUYVVVRUPTO", + "H]NFLL [FZIXLTQRTQWP[ RSPWO[ XLRRPUOWN[P[ MIPFRFWI OGRGWI MIOHRHWIYIZH[F", + "H]SFPGOHNJNMOOQPTPWOYNZLZIYGWFSF UFPG PHOJONPO OORP SPWO XNYLYIXG YGUF SFQHPJPNQP TPVOWNXLXHWF QPMQKSJUJXKZN[R[VZWYXWXTWRVQTP RPMQ NQLSKUKXLZ KZP[VZ VYWWWTVR VQSP QPOQMSLULXMZN[ R[TZUYVWVSUQTP", + "H]XNWPVQTRQROQNPMNMKNIPGSFVFXGYHZKZNYRXUVXTZQ[N[LZKXKVMVMXLXLW OPNNNKOI XHYJYNXRWUUX QRPQOOOKPHQGSF VFWGXIXNWRVUUWSZQ[", + "MXPXOYOZP[Q[RZRYQXPX PYPZQZQYPY", + "MXQ[P[OZOYPXQXRYR[Q]P^N_ PYPZQZQYPY Q[Q\\P^", + "MXSMRNROSPTPUOUNTMSM SNSOTOTNSN PXOYOZP[Q[RZRYQXPX PYPZQZQYPY", + "MXSMRNROSPTPUOUNTMSM SNSOTOTNSN Q[P[OZOYPXQXRYR[Q]P^N_ PYPZQZQYPY Q[Q\\P^", + "MXVFUFTGRT VGUGRT VGVHRT VFWGWHRT PXOYOZP[Q[RZRYQXPX PYPZQZQYPY", + "H]OKOJPJPLNLNJOHPGSFWFZG[I[KZMYNWOSPQQQSSTTT UFZG YGZIZKYMXNVO WFXGYIYKXMWNSPRQRSST PXOYOZP[Q[RZRYQXPX PYPZQZQYPY", + "MXWFUGTHSJSLTMUMVLVKUJTJ UGTITJ TKTLULUKTK", + "MXVIUITHTGUFVFWGWIVKULSM UGUHVHVGUG VIVJUL", + "E_\\O\\N[N[P]P]N\\M[MYNWPRXPZN[K[HZGXGVHTISKRPPROTMUKUITGRFPGOIOLPRQURWTZV[X[YYYX L[HZ IZHXHVITJSLR PPQSTYVZ K[JZIXIVJTKSMRRO OLPOQRSVUYWZXZYY", + "H]TBL_ YBQ_ ZKZJYJYL[L[JZHYGVFRFOGMIMLNNPPVSWUWXVZ NLONVRWT OGNINKOMUPWRXTXWWYVZS[O[LZKYJWJULULWKWKV", + "G^_BEbFb _B`BFb", + "JZZBXCUERHPKNOMSMXN\\O_Qb SHQKOONTN\\ ZBWDTGRJQLPOOSN\\ NTO]P`Qb", + "JZSBUEVHWLWQVUTYR\\O_LaJb VHVPUUSYQ\\ SBTDUGVP VHUQTUSXRZP]M`Jb", + "J[TFSGUQTR TFTR TFUGSQTR OIPIXOYO OIYO OIOJYNYO YIXIPOOO YIOO YIYJONOO", + "F_JQ[Q[R JQJR[R", + "F_RIRZSZ RISISZ JQ[Q[R JQJR[R", + "F_JM[M[N JMJN[N JU[U[V JUJV[V", + "MWUFTGRM UGRM UFVGRM", + "H\\PFOGMM PGMM PFQGMM ZFYGWM ZGWM ZF[GWM", + "KZSFQGPIPKQMSNUNWMXKXIWGUFSF SFPIQMUNXKWGSF UFQGPKSNWMXIUF", + "F^ZIJRZ[ ZIZJLRZZZ[", + "F^JIZRJ[ JIJJXRJZJ[", + "G^SFKbLb SFTFLb YFQbRb YFZFRb KP\\P\\Q KPKQ\\Q IWZWZX IWIXZX", + "E^^F\\GXHUHQGOFMFKGJIJKLMNMPLQJQHOF ^FE[ ^FF[ ^FG[ XTVTTUSWSYU[W[YZZXZVXT PGMFJIKLNMQJPG OFKGJK LMPLQH YUVTSWTZW[ZXYU XTTUSY U[YZZV E[G[", + "E`UQUNTLRKPKNLMMLPLSMUOVQVSUTTUQ OLNMMPMSNU RKPLOMNPNSOUPV VKUQUSVUXVZV\\U]R]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYXYWZ WKVQVSWU VKXKWQWSXUZV", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + 0 }; + +} + +/* End of file. */ diff --git a/core/test/test_arithm.cpp b/core/test/test_arithm.cpp new file mode 100644 index 0000000..875b849 --- /dev/null +++ b/core/test/test_arithm.cpp @@ -0,0 +1,1525 @@ +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +namespace cvtest +{ + +const int ARITHM_NTESTS = 1000; +const int ARITHM_RNG_SEED = -1; +const int ARITHM_MAX_CHANNELS = 4; +const int ARITHM_MAX_NDIMS = 4; +const int ARITHM_MAX_SIZE_LOG = 10; + +struct BaseElemWiseOp +{ + enum { FIX_ALPHA=1, FIX_BETA=2, FIX_GAMMA=4, REAL_GAMMA=8, SUPPORT_MASK=16, SCALAR_OUTPUT=32 }; + BaseElemWiseOp(int _ninputs, int _flags, double _alpha, double _beta, + Scalar _gamma=Scalar::all(0), int _context=1) + : ninputs(_ninputs), flags(_flags), alpha(_alpha), beta(_beta), gamma(_gamma), context(_context) {} + BaseElemWiseOp() { flags = 0; alpha = beta = 0; gamma = Scalar::all(0); } + virtual ~BaseElemWiseOp() {} + virtual void op(const vector&, Mat&, const Mat&) {} + virtual void refop(const vector&, Mat&, const Mat&) {} + virtual void getValueRange(int depth, double& minval, double& maxval) + { + minval = depth < CV_32S ? cvtest::getMinVal(depth) : depth == CV_32S ? -1000000 : -1000.; + maxval = depth < CV_32S ? cvtest::getMaxVal(depth) : depth == CV_32S ? 1000000 : 1000.; + } + + virtual void getRandomSize(RNG& rng, vector& size) + { + cvtest::randomSize(rng, 2, ARITHM_MAX_NDIMS, cvtest::ARITHM_MAX_SIZE_LOG, size); + } + + virtual int getRandomType(RNG& rng) + { + return cvtest::randomType(rng, DEPTH_MASK_ALL_BUT_8S, 1, + ninputs > 1 ? ARITHM_MAX_CHANNELS : 4); + } + + virtual double getMaxErr(int depth) { return depth < CV_32F ? 1 : depth == CV_32F ? 1e-5 : 1e-12; } + virtual void generateScalars(int depth, RNG& rng) + { + const double m = 3.; + + if( !(flags & FIX_ALPHA) ) + { + alpha = exp(rng.uniform(-0.5, 0.1)*m*2*CV_LOG2); + alpha *= rng.uniform(0, 2) ? 1 : -1; + } + if( !(flags & FIX_BETA) ) + { + beta = exp(rng.uniform(-0.5, 0.1)*m*2*CV_LOG2); + beta *= rng.uniform(0, 2) ? 1 : -1; + } + + if( !(flags & FIX_GAMMA) ) + { + for( int i = 0; i < 4; i++ ) + { + gamma[i] = exp(rng.uniform(-1, 6)*m*CV_LOG2); + gamma[i] *= rng.uniform(0, 2) ? 1 : -1; + } + if( flags & REAL_GAMMA ) + gamma = Scalar::all(gamma[0]); + } + + if( depth == CV_32F ) + { + Mat fl, db; + + db = Mat(1, 1, CV_64F, &alpha); + db.convertTo(fl, CV_32F); + fl.convertTo(db, CV_64F); + + db = Mat(1, 1, CV_64F, &beta); + db.convertTo(fl, CV_32F); + fl.convertTo(db, CV_64F); + + db = Mat(1, 4, CV_64F, &gamma[0]); + db.convertTo(fl, CV_32F); + fl.convertTo(db, CV_64F); + } + } + + int ninputs; + int flags; + double alpha; + double beta; + Scalar gamma; + int maxErr; + int context; +}; + + +struct BaseAddOp : public BaseElemWiseOp +{ + BaseAddOp(int _ninputs, int _flags, double _alpha, double _beta, Scalar _gamma=Scalar::all(0)) + : BaseElemWiseOp(_ninputs, _flags, _alpha, _beta, _gamma) {} + + void refop(const vector& src, Mat& dst, const Mat& mask) + { + Mat temp; + if( !mask.empty() ) + { + cvtest::add(src[0], alpha, src.size() > 1 ? src[1] : Mat(), beta, gamma, temp, src[0].type()); + cvtest::copy(temp, dst, mask); + } + else + cvtest::add(src[0], alpha, src.size() > 1 ? src[1] : Mat(), beta, gamma, dst, src[0].type()); + } +}; + + +struct AddOp : public BaseAddOp +{ + AddOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat& mask) + { + if( mask.empty() ) + add(src[0], src[1], dst); + else + add(src[0], src[1], dst, mask); + } +}; + + +struct SubOp : public BaseAddOp +{ + SubOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, -1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat& mask) + { + if( mask.empty() ) + subtract(src[0], src[1], dst); + else + subtract(src[0], src[1], dst, mask); + } +}; + + +struct AddSOp : public BaseAddOp +{ + AddSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, 1, 0, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat& mask) + { + if( mask.empty() ) + add(src[0], gamma, dst); + else + add(src[0], gamma, dst, mask); + } +}; + + +struct SubRSOp : public BaseAddOp +{ + SubRSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, -1, 0, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat& mask) + { + if( mask.empty() ) + subtract(gamma, src[0], dst); + else + subtract(gamma, src[0], dst, mask); + } +}; + + +struct ScaleAddOp : public BaseAddOp +{ + ScaleAddOp() : BaseAddOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat&) + { + scaleAdd(src[0], alpha, src[1], dst); + } + double getMaxErr(int depth) + { + return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-4 : 1e-12; + } +}; + + +struct AddWeightedOp : public BaseAddOp +{ + AddWeightedOp() : BaseAddOp(2, REAL_GAMMA, 1, 1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat&) + { + addWeighted(src[0], alpha, src[1], beta, gamma[0], dst); + } + double getMaxErr(int depth) + { + return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-10; + } +}; + +struct MulOp : public BaseElemWiseOp +{ + MulOp() : BaseElemWiseOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}; + void getValueRange(int depth, double& minval, double& maxval) + { + minval = depth < CV_32S ? cvtest::getMinVal(depth) : depth == CV_32S ? -1000000 : -1000.; + maxval = depth < CV_32S ? cvtest::getMaxVal(depth) : depth == CV_32S ? 1000000 : 1000.; + minval = std::max(minval, -30000.); + maxval = std::min(maxval, 30000.); + } + void op(const vector& src, Mat& dst, const Mat&) + { + cv::multiply(src[0], src[1], dst, alpha); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::multiply(src[0], src[1], dst, alpha); + } + double getMaxErr(int depth) + { + return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12; + } +}; + +struct DivOp : public BaseElemWiseOp +{ + DivOp() : BaseElemWiseOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat&) + { + cv::divide(src[0], src[1], dst, alpha); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::divide(src[0], src[1], dst, alpha); + } + double getMaxErr(int depth) + { + return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12; + } +}; + +struct RecipOp : public BaseElemWiseOp +{ + RecipOp() : BaseElemWiseOp(1, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat&) + { + cv::divide(alpha, src[0], dst); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::divide(Mat(), src[0], dst, alpha); + } + double getMaxErr(int depth) + { + return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12; + } +}; + +struct AbsDiffOp : public BaseAddOp +{ + AbsDiffOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, -1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat&) + { + absdiff(src[0], src[1], dst); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::add(src[0], 1, src[1], -1, Scalar::all(0), dst, src[0].type(), true); + } +}; + +struct AbsDiffSOp : public BaseAddOp +{ + AbsDiffSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA, 1, 0, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat&) + { + absdiff(src[0], gamma, dst); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::add(src[0], 1, Mat(), 0, -gamma, dst, src[0].type(), true); + } +}; + +struct LogicOp : public BaseElemWiseOp +{ + LogicOp(char _opcode) : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)), opcode(_opcode) {}; + void op(const vector& src, Mat& dst, const Mat& mask) + { + if( opcode == '&' ) + bitwise_and(src[0], src[1], dst, mask); + else if( opcode == '|' ) + bitwise_or(src[0], src[1], dst, mask); + else + bitwise_xor(src[0], src[1], dst, mask); + } + void refop(const vector& src, Mat& dst, const Mat& mask) + { + Mat temp; + if( !mask.empty() ) + { + cvtest::logicOp(src[0], src[1], temp, opcode); + cvtest::copy(temp, dst, mask); + } + else + cvtest::logicOp(src[0], src[1], dst, opcode); + } + double getMaxErr(int) + { + return 0; + } + char opcode; +}; + +struct LogicSOp : public BaseElemWiseOp +{ + LogicSOp(char _opcode) + : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+(_opcode != '~' ? SUPPORT_MASK : 0), 1, 1, Scalar::all(0)), opcode(_opcode) {}; + void op(const vector& src, Mat& dst, const Mat& mask) + { + if( opcode == '&' ) + bitwise_and(src[0], gamma, dst, mask); + else if( opcode == '|' ) + bitwise_or(src[0], gamma, dst, mask); + else if( opcode == '^' ) + bitwise_xor(src[0], gamma, dst, mask); + else + bitwise_not(src[0], dst); + } + void refop(const vector& src, Mat& dst, const Mat& mask) + { + Mat temp; + if( !mask.empty() ) + { + cvtest::logicOp(src[0], gamma, temp, opcode); + cvtest::copy(temp, dst, mask); + } + else + cvtest::logicOp(src[0], gamma, dst, opcode); + } + double getMaxErr(int) + { + return 0; + } + char opcode; +}; + +struct MinOp : public BaseElemWiseOp +{ + MinOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat&) + { + cv::min(src[0], src[1], dst); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::min(src[0], src[1], dst); + } + double getMaxErr(int) + { + return 0; + } +}; + +struct MaxOp : public BaseElemWiseOp +{ + MaxOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat&) + { + cv::max(src[0], src[1], dst); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::max(src[0], src[1], dst); + } + double getMaxErr(int) + { + return 0; + } +}; + +struct MinSOp : public BaseElemWiseOp +{ + MinSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat&) + { + cv::min(src[0], gamma[0], dst); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::min(src[0], gamma[0], dst); + } + double getMaxErr(int) + { + return 0; + } +}; + +struct MaxSOp : public BaseElemWiseOp +{ + MaxSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat&) + { + cv::max(src[0], gamma[0], dst); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::max(src[0], gamma[0], dst); + } + double getMaxErr(int) + { + return 0; + } +}; + +struct CmpOp : public BaseElemWiseOp +{ + CmpOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}; + void generateScalars(int depth, RNG& rng) + { + BaseElemWiseOp::generateScalars(depth, rng); + cmpop = rng.uniform(0, 6); + } + void op(const vector& src, Mat& dst, const Mat&) + { + cv::compare(src[0], src[1], dst, cmpop); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::compare(src[0], src[1], dst, cmpop); + } + int getRandomType(RNG& rng) + { + return cvtest::randomType(rng, DEPTH_MASK_ALL_BUT_8S, 1, 1); + } + + double getMaxErr(int) + { + return 0; + } + int cmpop; +}; + +struct CmpSOp : public BaseElemWiseOp +{ + CmpSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {}; + void generateScalars(int depth, RNG& rng) + { + BaseElemWiseOp::generateScalars(depth, rng); + cmpop = rng.uniform(0, 6); + if( depth < CV_32F ) + gamma[0] = cvRound(gamma[0]); + } + void op(const vector& src, Mat& dst, const Mat&) + { + cv::compare(src[0], gamma[0], dst, cmpop); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::compare(src[0], gamma[0], dst, cmpop); + } + int getRandomType(RNG& rng) + { + return cvtest::randomType(rng, DEPTH_MASK_ALL_BUT_8S, 1, 1); + } + double getMaxErr(int) + { + return 0; + } + int cmpop; +}; + + +struct CopyOp : public BaseElemWiseOp +{ + CopyOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat& mask) + { + src[0].copyTo(dst, mask); + } + void refop(const vector& src, Mat& dst, const Mat& mask) + { + cvtest::copy(src[0], dst, mask); + } + int getRandomType(RNG& rng) + { + return cvtest::randomType(rng, DEPTH_MASK_ALL, 1, ARITHM_MAX_CHANNELS); + } + double getMaxErr(int) + { + return 0; + } + int cmpop; +}; + + +struct SetOp : public BaseElemWiseOp +{ + SetOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {}; + void op(const vector&, Mat& dst, const Mat& mask) + { + dst.setTo(gamma, mask); + } + void refop(const vector&, Mat& dst, const Mat& mask) + { + cvtest::set(dst, gamma, mask); + } + int getRandomType(RNG& rng) + { + return cvtest::randomType(rng, DEPTH_MASK_ALL, 1, ARITHM_MAX_CHANNELS); + } + double getMaxErr(int) + { + return 0; + } +}; + +template static void +inRangeS_(const _Tp* src, const _WTp* a, const _WTp* b, uchar* dst, size_t total, int cn) +{ + size_t i; + int c; + for( i = 0; i < total; i++ ) + { + _Tp val = src[i*cn]; + dst[i] = (a[0] <= val && val <= b[0]) ? uchar(255) : 0; + } + for( c = 1; c < cn; c++ ) + { + for( i = 0; i < total; i++ ) + { + _Tp val = src[i*cn + c]; + dst[i] = a[c] <= val && val <= b[c] ? dst[i] : 0; + } + } +} + +template static void inRange_(const _Tp* src, const _Tp* a, const _Tp* b, uchar* dst, size_t total, int cn) +{ + size_t i; + int c; + for( i = 0; i < total; i++ ) + { + _Tp val = src[i*cn]; + dst[i] = a[i*cn] <= val && val <= b[i*cn] ? 255 : 0; + } + for( c = 1; c < cn; c++ ) + { + for( i = 0; i < total; i++ ) + { + _Tp val = src[i*cn + c]; + dst[i] = a[i*cn + c] <= val && val <= b[i*cn + c] ? dst[i] : 0; + } + } +} + + +static void inRange(const Mat& src, const Mat& lb, const Mat& rb, Mat& dst) +{ + CV_Assert( src.type() == lb.type() && src.type() == rb.type() && + src.size == lb.size && src.size == rb.size ); + dst.create( src.dims, &src.size[0], CV_8U ); + const Mat *arrays[]={&src, &lb, &rb, &dst, 0}; + Mat planes[4]; + + NAryMatIterator it(arrays, planes); + size_t total = planes[0].total(); + size_t i, nplanes = it.nplanes; + int depth = src.depth(), cn = src.channels(); + + for( i = 0; i < nplanes; i++, ++it ) + { + const uchar* sptr = planes[0].data; + const uchar* aptr = planes[1].data; + const uchar* bptr = planes[2].data; + uchar* dptr = planes[3].data; + + switch( depth ) + { + case CV_8U: + inRange_((const uchar*)sptr, (const uchar*)aptr, (const uchar*)bptr, dptr, total, cn); + break; + case CV_8S: + inRange_((const schar*)sptr, (const schar*)aptr, (const schar*)bptr, dptr, total, cn); + break; + case CV_16U: + inRange_((const ushort*)sptr, (const ushort*)aptr, (const ushort*)bptr, dptr, total, cn); + break; + case CV_16S: + inRange_((const short*)sptr, (const short*)aptr, (const short*)bptr, dptr, total, cn); + break; + case CV_32S: + inRange_((const int*)sptr, (const int*)aptr, (const int*)bptr, dptr, total, cn); + break; + case CV_32F: + inRange_((const float*)sptr, (const float*)aptr, (const float*)bptr, dptr, total, cn); + break; + case CV_64F: + inRange_((const double*)sptr, (const double*)aptr, (const double*)bptr, dptr, total, cn); + break; + default: + CV_Error(CV_StsUnsupportedFormat, ""); + } + } +} + + +static void inRangeS(const Mat& src, const Scalar& lb, const Scalar& rb, Mat& dst) +{ + dst.create( src.dims, &src.size[0], CV_8U ); + const Mat *arrays[]={&src, &dst, 0}; + Mat planes[2]; + + NAryMatIterator it(arrays, planes); + size_t total = planes[0].total(); + size_t i, nplanes = it.nplanes; + int depth = src.depth(), cn = src.channels(); + union { double d[4]; float f[4]; int i[4];} lbuf, rbuf; + int wtype = CV_MAKETYPE(depth <= CV_32S ? CV_32S : depth, cn); + scalarToRawData(lb, lbuf.d, wtype, cn); + scalarToRawData(rb, rbuf.d, wtype, cn); + + for( i = 0; i < nplanes; i++, ++it ) + { + const uchar* sptr = planes[0].data; + uchar* dptr = planes[1].data; + + switch( depth ) + { + case CV_8U: + inRangeS_((const uchar*)sptr, lbuf.i, rbuf.i, dptr, total, cn); + break; + case CV_8S: + inRangeS_((const schar*)sptr, lbuf.i, rbuf.i, dptr, total, cn); + break; + case CV_16U: + inRangeS_((const ushort*)sptr, lbuf.i, rbuf.i, dptr, total, cn); + break; + case CV_16S: + inRangeS_((const short*)sptr, lbuf.i, rbuf.i, dptr, total, cn); + break; + case CV_32S: + inRangeS_((const int*)sptr, lbuf.i, rbuf.i, dptr, total, cn); + break; + case CV_32F: + inRangeS_((const float*)sptr, lbuf.f, rbuf.f, dptr, total, cn); + break; + case CV_64F: + inRangeS_((const double*)sptr, lbuf.d, rbuf.d, dptr, total, cn); + break; + default: + CV_Error(CV_StsUnsupportedFormat, ""); + } + } +} + + +struct InRangeSOp : public BaseElemWiseOp +{ + InRangeSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA, 1, 1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat&) + { + cv::inRange(src[0], gamma, gamma1, dst); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::inRangeS(src[0], gamma, gamma1, dst); + } + double getMaxErr(int) + { + return 0; + } + void generateScalars(int depth, RNG& rng) + { + BaseElemWiseOp::generateScalars(depth, rng); + Scalar temp = gamma; + BaseElemWiseOp::generateScalars(depth, rng); + for( int i = 0; i < 4; i++ ) + { + gamma1[i] = std::max(gamma[i], temp[i]); + gamma[i] = std::min(gamma[i], temp[i]); + } + } + Scalar gamma1; +}; + + +struct InRangeOp : public BaseElemWiseOp +{ + InRangeOp() : BaseElemWiseOp(3, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat&) + { + Mat lb, rb; + cvtest::min(src[1], src[2], lb); + cvtest::max(src[1], src[2], rb); + + cv::inRange(src[0], lb, rb, dst); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + Mat lb, rb; + cvtest::min(src[1], src[2], lb); + cvtest::max(src[1], src[2], rb); + + cvtest::inRange(src[0], lb, rb, dst); + } + double getMaxErr(int) + { + return 0; + } +}; + + +struct ConvertScaleOp : public BaseElemWiseOp +{ + ConvertScaleOp() : BaseElemWiseOp(1, FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)), ddepth(0) { }; + void op(const vector& src, Mat& dst, const Mat&) + { + src[0].convertTo(dst, ddepth, alpha, gamma[0]); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::convert(src[0], dst, CV_MAKETYPE(ddepth, src[0].channels()), alpha, gamma[0]); + } + int getRandomType(RNG& rng) + { + int srctype = cvtest::randomType(rng, DEPTH_MASK_ALL, 1, ARITHM_MAX_CHANNELS); + ddepth = cvtest::randomType(rng, DEPTH_MASK_ALL, 1, 1); + return srctype; + } + double getMaxErr(int) + { + return ddepth <= CV_32S ? 2 : ddepth < CV_64F ? 1e-3 : 1e-12; + } + void generateScalars(int depth, RNG& rng) + { + if( rng.uniform(0, 2) ) + BaseElemWiseOp::generateScalars(depth, rng); + else + { + alpha = 1; + gamma = Scalar::all(0); + } + } + int ddepth; +}; + + +struct ConvertScaleAbsOp : public BaseElemWiseOp +{ + ConvertScaleAbsOp() : BaseElemWiseOp(1, FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {}; + void op(const vector& src, Mat& dst, const Mat&) + { + cv::convertScaleAbs(src[0], dst, alpha, gamma[0]); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::add(src[0], alpha, Mat(), 0, Scalar::all(gamma[0]), dst, CV_8UC(src[0].channels()), true); + } + double getMaxErr(int) + { + return 1; + } + void generateScalars(int depth, RNG& rng) + { + if( rng.uniform(0, 2) ) + BaseElemWiseOp::generateScalars(depth, rng); + else + { + alpha = 1; + gamma = Scalar::all(0); + } + } +}; + + +static void flip(const Mat& src, Mat& dst, int flipcode) +{ + CV_Assert(src.dims == 2); + dst.create(src.size(), src.type()); + int i, j, k, esz = (int)src.elemSize(), width = src.cols*esz; + + for( i = 0; i < dst.rows; i++ ) + { + const uchar* sptr = src.ptr(flipcode == 1 ? i : dst.rows - i - 1); + uchar* dptr = dst.ptr(i); + if( flipcode == 0 ) + memcpy(dptr, sptr, width); + else + { + for( j = 0; j < width; j += esz ) + for( k = 0; k < esz; k++ ) + dptr[j + k] = sptr[width - j - esz + k]; + } + } +} + + +static void setIdentity(Mat& dst, const Scalar& s) +{ + CV_Assert( dst.dims == 2 && dst.channels() <= 4 ); + double buf[4]; + scalarToRawData(s, buf, dst.type(), 0); + int i, k, esz = (int)dst.elemSize(), width = dst.cols*esz; + + for( i = 0; i < dst.rows; i++ ) + { + uchar* dptr = dst.ptr(i); + memset( dptr, 0, width ); + if( i < dst.cols ) + for( k = 0; k < esz; k++ ) + dptr[i*esz + k] = ((uchar*)buf)[k]; + } +} + + +struct FlipOp : public BaseElemWiseOp +{ + FlipOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}; + void getRandomSize(RNG& rng, vector& size) + { + cvtest::randomSize(rng, 2, 2, cvtest::ARITHM_MAX_SIZE_LOG, size); + } + void op(const vector& src, Mat& dst, const Mat&) + { + cv::flip(src[0], dst, flipcode); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::flip(src[0], dst, flipcode); + } + void generateScalars(int, RNG& rng) + { + flipcode = rng.uniform(0, 3) - 1; + } + double getMaxErr(int) + { + return 0; + } + int flipcode; +}; + +struct TransposeOp : public BaseElemWiseOp +{ + TransposeOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}; + void getRandomSize(RNG& rng, vector& size) + { + cvtest::randomSize(rng, 2, 2, cvtest::ARITHM_MAX_SIZE_LOG, size); + } + void op(const vector& src, Mat& dst, const Mat&) + { + cv::transpose(src[0], dst); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::transpose(src[0], dst); + } + double getMaxErr(int) + { + return 0; + } +}; + +struct SetIdentityOp : public BaseElemWiseOp +{ + SetIdentityOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA, 1, 1, Scalar::all(0)) {}; + void getRandomSize(RNG& rng, vector& size) + { + cvtest::randomSize(rng, 2, 2, cvtest::ARITHM_MAX_SIZE_LOG, size); + } + void op(const vector&, Mat& dst, const Mat&) + { + cv::setIdentity(dst, gamma); + } + void refop(const vector&, Mat& dst, const Mat&) + { + cvtest::setIdentity(dst, gamma); + } + double getMaxErr(int) + { + return 0; + } +}; + +struct SetZeroOp : public BaseElemWiseOp +{ + SetZeroOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}; + void op(const vector&, Mat& dst, const Mat&) + { + dst = Scalar::all(0); + } + void refop(const vector&, Mat& dst, const Mat&) + { + cvtest::set(dst, Scalar::all(0)); + } + double getMaxErr(int) + { + return 0; + } +}; + + +static void exp(const Mat& src, Mat& dst) +{ + dst.create( src.dims, &src.size[0], src.type() ); + const Mat *arrays[]={&src, &dst, 0}; + Mat planes[2]; + + NAryMatIterator it(arrays, planes); + size_t j, total = planes[0].total()*src.channels(); + size_t i, nplanes = it.nplanes; + int depth = src.depth(); + + for( i = 0; i < nplanes; i++, ++it ) + { + const uchar* sptr = planes[0].data; + uchar* dptr = planes[1].data; + + if( depth == CV_32F ) + { + for( j = 0; j < total; j++ ) + ((float*)dptr)[j] = std::exp(((const float*)sptr)[j]); + } + else if( depth == CV_64F ) + { + for( j = 0; j < total; j++ ) + ((double*)dptr)[j] = std::exp(((const double*)sptr)[j]); + } + } +} + +static void log(const Mat& src, Mat& dst) +{ + dst.create( src.dims, &src.size[0], src.type() ); + const Mat *arrays[]={&src, &dst, 0}; + Mat planes[2]; + + NAryMatIterator it(arrays, planes); + size_t j, total = planes[0].total()*src.channels(); + size_t i, nplanes = it.nplanes; + int depth = src.depth(); + + for( i = 0; i < nplanes; i++, ++it ) + { + const uchar* sptr = planes[0].data; + uchar* dptr = planes[1].data; + + if( depth == CV_32F ) + { + for( j = 0; j < total; j++ ) + ((float*)dptr)[j] = (float)std::log(fabs(((const float*)sptr)[j])); + } + else if( depth == CV_64F ) + { + for( j = 0; j < total; j++ ) + ((double*)dptr)[j] = std::log(fabs(((const double*)sptr)[j])); + } + } +} + +struct ExpOp : public BaseElemWiseOp +{ + ExpOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}; + int getRandomType(RNG& rng) + { + return cvtest::randomType(rng, DEPTH_MASK_FLT, 1, ARITHM_MAX_CHANNELS); + } + void getValueRange(int depth, double& minval, double& maxval) + { + maxval = depth == CV_32F ? 50 : 100; + minval = -maxval; + } + void op(const vector& src, Mat& dst, const Mat&) + { + cv::exp(src[0], dst); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + cvtest::exp(src[0], dst); + } + double getMaxErr(int depth) + { + return depth == CV_32F ? 1e-5 : 1e-12; + } +}; + + +struct LogOp : public BaseElemWiseOp +{ + LogOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}; + int getRandomType(RNG& rng) + { + return cvtest::randomType(rng, DEPTH_MASK_FLT, 1, ARITHM_MAX_CHANNELS); + } + void getValueRange(int depth, double& minval, double& maxval) + { + maxval = depth == CV_32F ? 50 : 100; + minval = -maxval; + } + void op(const vector& src, Mat& dst, const Mat&) + { + Mat temp; + cvtest::exp(src[0], temp); + cv::log(temp, dst); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + Mat temp; + cvtest::exp(src[0], temp); + cvtest::log(temp, dst); + } + double getMaxErr(int depth) + { + return depth == CV_32F ? 1e-5 : 1e-12; + } +}; + + +static void cartToPolar(const Mat& mx, const Mat& my, Mat& mmag, Mat& mangle, bool angleInDegrees) +{ + CV_Assert( (mx.type() == CV_32F || mx.type() == CV_64F) && + mx.type() == my.type() && mx.size == my.size ); + mmag.create( mx.dims, &mx.size[0], mx.type() ); + mangle.create( mx.dims, &mx.size[0], mx.type() ); + const Mat *arrays[]={&mx, &my, &mmag, &mangle, 0}; + Mat planes[4]; + + NAryMatIterator it(arrays, planes); + size_t j, total = planes[0].total(); + size_t i, nplanes = it.nplanes; + int depth = mx.depth(); + double scale = angleInDegrees ? 180/CV_PI : 1; + + for( i = 0; i < nplanes; i++, ++it ) + { + if( depth == CV_32F ) + { + const float* xptr = (const float*)planes[0].data; + const float* yptr = (const float*)planes[1].data; + float* mptr = (float*)planes[2].data; + float* aptr = (float*)planes[3].data; + + for( j = 0; j < total; j++ ) + { + mptr[j] = std::sqrt(xptr[j]*xptr[j] + yptr[j]*yptr[j]); + double a = atan2((double)yptr[j], (double)xptr[j]); + if( a < 0 ) a += CV_PI*2; + aptr[j] = (float)(a*scale); + } + } + else + { + const double* xptr = (const double*)planes[0].data; + const double* yptr = (const double*)planes[1].data; + double* mptr = (double*)planes[2].data; + double* aptr = (double*)planes[3].data; + + for( j = 0; j < total; j++ ) + { + mptr[j] = std::sqrt(xptr[j]*xptr[j] + yptr[j]*yptr[j]); + double a = atan2(yptr[j], xptr[j]); + if( a < 0 ) a += CV_PI*2; + aptr[j] = a*scale; + } + } + } +} + + +struct CartToPolarToCartOp : public BaseElemWiseOp +{ + CartToPolarToCartOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) + { + context = 3; + angleInDegrees = true; + } + int getRandomType(RNG& rng) + { + return cvtest::randomType(rng, DEPTH_MASK_FLT, 1, 1); + } + void op(const vector& src, Mat& dst, const Mat&) + { + Mat mag, angle, x, y; + + cv::cartToPolar(src[0], src[1], mag, angle, angleInDegrees); + cv::polarToCart(mag, angle, x, y, angleInDegrees); + + Mat msrc[] = {mag, angle, x, y}; + int pairs[] = {0, 0, 1, 1, 2, 2, 3, 3}; + dst.create(src[0].dims, src[0].size, CV_MAKETYPE(src[0].depth(), 4)); + cv::mixChannels(msrc, 4, &dst, 1, pairs, 4); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + Mat mag, angle; + cvtest::cartToPolar(src[0], src[1], mag, angle, angleInDegrees); + Mat msrc[] = {mag, angle, src[0], src[1]}; + int pairs[] = {0, 0, 1, 1, 2, 2, 3, 3}; + dst.create(src[0].dims, src[0].size, CV_MAKETYPE(src[0].depth(), 4)); + cv::mixChannels(msrc, 4, &dst, 1, pairs, 4); + } + void generateScalars(int, RNG& rng) + { + angleInDegrees = rng.uniform(0, 2) != 0; + } + double getMaxErr(int) + { + return 1e-3; + } + bool angleInDegrees; +}; + + +struct MeanOp : public BaseElemWiseOp +{ + MeanOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0)) + { + context = 3; + }; + void op(const vector& src, Mat& dst, const Mat& mask) + { + dst.create(1, 1, CV_64FC4); + dst.at(0,0) = cv::mean(src[0], mask); + } + void refop(const vector& src, Mat& dst, const Mat& mask) + { + dst.create(1, 1, CV_64FC4); + dst.at(0,0) = cvtest::mean(src[0], mask); + } + double getMaxErr(int) + { + return 1e-6; + } +}; + + +struct SumOp : public BaseElemWiseOp +{ + SumOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SCALAR_OUTPUT, 1, 1, Scalar::all(0)) + { + context = 3; + }; + void op(const vector& src, Mat& dst, const Mat&) + { + dst.create(1, 1, CV_64FC4); + dst.at(0,0) = cv::sum(src[0]); + } + void refop(const vector& src, Mat& dst, const Mat&) + { + dst.create(1, 1, CV_64FC4); + dst.at(0,0) = cvtest::mean(src[0])*(double)src[0].total(); + } + double getMaxErr(int) + { + return 1e-5; + } +}; + + +struct CountNonZeroOp : public BaseElemWiseOp +{ + CountNonZeroOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SCALAR_OUTPUT+SUPPORT_MASK, 1, 1, Scalar::all(0)) + {} + int getRandomType(RNG& rng) + { + return cvtest::randomType(rng, DEPTH_MASK_ALL, 1, 1); + } + void op(const vector& src, Mat& dst, const Mat& mask) + { + Mat temp; + src[0].copyTo(temp); + if( !mask.empty() ) + temp.setTo(Scalar::all(0), mask); + dst.create(1, 1, CV_32S); + dst.at(0,0) = cv::countNonZero(temp); + } + void refop(const vector& src, Mat& dst, const Mat& mask) + { + Mat temp; + cvtest::compare(src[0], 0, temp, CMP_NE); + if( !mask.empty() ) + cvtest::set(temp, Scalar::all(0), mask); + dst.create(1, 1, CV_32S); + dst.at(0,0) = saturate_cast(cvtest::mean(temp)[0]/255*temp.total()); + } + double getMaxErr(int) + { + return 0; + } +}; + + +struct MeanStdDevOp : public BaseElemWiseOp +{ + Scalar sqmeanRef; + int cn; + + MeanStdDevOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0)) + { + cn = 0; + context = 7; + }; + void op(const vector& src, Mat& dst, const Mat& mask) + { + dst.create(1, 2, CV_64FC4); + cv::meanStdDev(src[0], dst.at(0,0), dst.at(0,1), mask); + } + void refop(const vector& src, Mat& dst, const Mat& mask) + { + Mat temp; + cvtest::convert(src[0], temp, CV_64F); + cvtest::multiply(temp, temp, temp); + Scalar mean = cvtest::mean(src[0], mask); + Scalar sqmean = cvtest::mean(temp, mask); + + sqmeanRef = sqmean; + cn = temp.channels(); + + for( int c = 0; c < 4; c++ ) + sqmean[c] = std::sqrt(std::max(sqmean[c] - mean[c]*mean[c], 0.)); + + dst.create(1, 2, CV_64FC4); + dst.at(0,0) = mean; + dst.at(0,1) = sqmean; + } + double getMaxErr(int) + { + CV_Assert(cn > 0); + double err = sqmeanRef[0]; + for(int i = 1; i < cn; ++i) + err = std::max(err, sqmeanRef[i]); + return 3e-7 * err; + } +}; + + +struct NormOp : public BaseElemWiseOp +{ + NormOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0)) + { + context = 1; + normType = 0; + }; + int getRandomType(RNG& rng) + { + int type = cvtest::randomType(rng, DEPTH_MASK_ALL_BUT_8S, 1, 4); + for(;;) + { + normType = rng.uniform(1, 8); + if( normType == NORM_INF || normType == NORM_L1 || + normType == NORM_L2 || normType == NORM_L2SQR || + normType == NORM_HAMMING || normType == NORM_HAMMING2 ) + break; + } + if( normType == NORM_HAMMING || normType == NORM_HAMMING2 ) + { + type = CV_8U; + } + return type; + } + void op(const vector& src, Mat& dst, const Mat& mask) + { + dst.create(1, 2, CV_64FC1); + dst.at(0,0) = cv::norm(src[0], normType, mask); + dst.at(0,1) = cv::norm(src[0], src[1], normType, mask); + } + void refop(const vector& src, Mat& dst, const Mat& mask) + { + dst.create(1, 2, CV_64FC1); + dst.at(0,0) = cvtest::norm(src[0], normType, mask); + dst.at(0,1) = cvtest::norm(src[0], src[1], normType, mask); + } + void generateScalars(int, RNG& /*rng*/) + { + } + double getMaxErr(int) + { + return 1e-6; + } + int normType; +}; + + +struct MinMaxLocOp : public BaseElemWiseOp +{ + MinMaxLocOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0)) + { + context = ARITHM_MAX_NDIMS*2 + 2; + }; + int getRandomType(RNG& rng) + { + return cvtest::randomType(rng, DEPTH_MASK_ALL_BUT_8S, 1, 1); + } + void saveOutput(const vector& minidx, const vector& maxidx, + double minval, double maxval, Mat& dst) + { + int i, ndims = (int)minidx.size(); + dst.create(1, ndims*2 + 2, CV_64FC1); + + for( i = 0; i < ndims; i++ ) + { + dst.at(0,i) = minidx[i]; + dst.at(0,i+ndims) = maxidx[i]; + } + dst.at(0,ndims*2) = minval; + dst.at(0,ndims*2+1) = maxval; + } + void op(const vector& src, Mat& dst, const Mat& mask) + { + int ndims = src[0].dims; + vector minidx(ndims), maxidx(ndims); + double minval=0, maxval=0; + cv::minMaxIdx(src[0], &minval, &maxval, &minidx[0], &maxidx[0], mask); + saveOutput(minidx, maxidx, minval, maxval, dst); + } + void refop(const vector& src, Mat& dst, const Mat& mask) + { + int ndims=src[0].dims; + vector minidx(ndims), maxidx(ndims); + double minval=0, maxval=0; + cvtest::minMaxLoc(src[0], &minval, &maxval, &minidx, &maxidx, mask); + saveOutput(minidx, maxidx, minval, maxval, dst); + } + double getMaxErr(int) + { + return 0; + } +}; + + +} + +typedef Ptr ElemWiseOpPtr; +class ElemWiseTest : public ::testing::TestWithParam {}; + +TEST_P(ElemWiseTest, accuracy) +{ + ElemWiseOpPtr op = GetParam(); + + int testIdx = 0; + RNG rng((uint64)cvtest::ARITHM_RNG_SEED); + for( testIdx = 0; testIdx < cvtest::ARITHM_NTESTS; testIdx++ ) + { + vector size; + op->getRandomSize(rng, size); + int type = op->getRandomType(rng); + int depth = CV_MAT_DEPTH(type); + bool haveMask = (op->flags & cvtest::BaseElemWiseOp::SUPPORT_MASK) != 0 && rng.uniform(0, 4) == 0; + + double minval=0, maxval=0; + op->getValueRange(depth, minval, maxval); + int i, ninputs = op->ninputs; + vector src(ninputs); + for( i = 0; i < ninputs; i++ ) + src[i] = cvtest::randomMat(rng, size, type, minval, maxval, true); + Mat dst0, dst, mask; + if( haveMask ) + mask = cvtest::randomMat(rng, size, CV_8U, 0, 2, true); + + if( (haveMask || ninputs == 0) && !(op->flags & cvtest::BaseElemWiseOp::SCALAR_OUTPUT)) + { + dst0 = cvtest::randomMat(rng, size, type, minval, maxval, false); + dst = cvtest::randomMat(rng, size, type, minval, maxval, true); + cvtest::copy(dst, dst0); + } + op->generateScalars(depth, rng); + + op->refop(src, dst0, mask); + op->op(src, dst, mask); + + double maxErr = op->getMaxErr(depth); + vector pos; + ASSERT_PRED_FORMAT2(cvtest::MatComparator(maxErr, op->context), dst0, dst) << "\nsrc[0] ~ " << cvtest::MatInfo(!src.empty() ? src[0] : Mat()) << "\ntestCase #" << testIdx << "\n"; + } +} + + +INSTANTIATE_TEST_CASE_P(Core_Copy, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CopyOp))); +INSTANTIATE_TEST_CASE_P(Core_Set, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetOp))); +INSTANTIATE_TEST_CASE_P(Core_SetZero, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetZeroOp))); +INSTANTIATE_TEST_CASE_P(Core_ConvertScale, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ConvertScaleOp))); +INSTANTIATE_TEST_CASE_P(Core_ConvertScaleAbs, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ConvertScaleAbsOp))); + +INSTANTIATE_TEST_CASE_P(Core_Add, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AddOp))); +INSTANTIATE_TEST_CASE_P(Core_Sub, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SubOp))); +INSTANTIATE_TEST_CASE_P(Core_AddS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AddSOp))); +INSTANTIATE_TEST_CASE_P(Core_SubRS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SubRSOp))); +INSTANTIATE_TEST_CASE_P(Core_ScaleAdd, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ScaleAddOp))); +INSTANTIATE_TEST_CASE_P(Core_AddWeighted, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AddWeightedOp))); +INSTANTIATE_TEST_CASE_P(Core_AbsDiff, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AbsDiffOp))); + + +INSTANTIATE_TEST_CASE_P(Core_AbsDiffS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AbsDiffSOp))); + +INSTANTIATE_TEST_CASE_P(Core_And, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicOp('&')))); +INSTANTIATE_TEST_CASE_P(Core_AndS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('&')))); +INSTANTIATE_TEST_CASE_P(Core_Or, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicOp('|')))); +INSTANTIATE_TEST_CASE_P(Core_OrS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('|')))); +INSTANTIATE_TEST_CASE_P(Core_Xor, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicOp('^')))); +INSTANTIATE_TEST_CASE_P(Core_XorS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('^')))); +INSTANTIATE_TEST_CASE_P(Core_Not, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('~')))); + +INSTANTIATE_TEST_CASE_P(Core_Max, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MaxOp))); +INSTANTIATE_TEST_CASE_P(Core_MaxS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MaxSOp))); +INSTANTIATE_TEST_CASE_P(Core_Min, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MinOp))); +INSTANTIATE_TEST_CASE_P(Core_MinS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MinSOp))); + +INSTANTIATE_TEST_CASE_P(Core_Mul, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MulOp))); +INSTANTIATE_TEST_CASE_P(Core_Div, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::DivOp))); +INSTANTIATE_TEST_CASE_P(Core_Recip, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::RecipOp))); + +INSTANTIATE_TEST_CASE_P(Core_Cmp, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CmpOp))); +INSTANTIATE_TEST_CASE_P(Core_CmpS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CmpSOp))); + +INSTANTIATE_TEST_CASE_P(Core_InRangeS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::InRangeSOp))); +INSTANTIATE_TEST_CASE_P(Core_InRange, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::InRangeOp))); + +INSTANTIATE_TEST_CASE_P(Core_Flip, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::FlipOp))); +INSTANTIATE_TEST_CASE_P(Core_Transpose, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::TransposeOp))); +INSTANTIATE_TEST_CASE_P(Core_SetIdentity, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetIdentityOp))); + +INSTANTIATE_TEST_CASE_P(Core_Exp, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ExpOp))); +INSTANTIATE_TEST_CASE_P(Core_Log, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogOp))); + +INSTANTIATE_TEST_CASE_P(Core_CountNonZero, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CountNonZeroOp))); +INSTANTIATE_TEST_CASE_P(Core_Mean, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MeanOp))); +INSTANTIATE_TEST_CASE_P(Core_MeanStdDev, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MeanStdDevOp))); +INSTANTIATE_TEST_CASE_P(Core_Sum, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SumOp))); +INSTANTIATE_TEST_CASE_P(Core_Norm, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::NormOp))); +INSTANTIATE_TEST_CASE_P(Core_MinMaxLoc, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MinMaxLocOp))); +INSTANTIATE_TEST_CASE_P(Core_CartToPolarToCart, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CartToPolarToCartOp))); + + +class CV_ArithmMaskTest : public cvtest::BaseTest +{ +public: + CV_ArithmMaskTest() {} + ~CV_ArithmMaskTest() {} +protected: + void run(int) + { + try + { + RNG& rng = theRNG(); + const int MAX_DIM=3; + int sizes[MAX_DIM]; + for( int iter = 0; iter < 100; iter++ ) + { + //ts->printf(cvtest::TS::LOG, "."); + + ts->update_context(this, iter, true); + int k, dims = rng.uniform(1, MAX_DIM+1), p = 1; + int depth = rng.uniform(CV_8U, CV_64F+1); + int cn = rng.uniform(1, 6); + int type = CV_MAKETYPE(depth, cn); + int op = rng.uniform(0, 5); + int depth1 = op <= 1 ? CV_64F : depth; + for( k = 0; k < dims; k++ ) + { + sizes[k] = rng.uniform(1, 30); + p *= sizes[k]; + } + Mat a(dims, sizes, type), a1; + Mat b(dims, sizes, type), b1; + Mat mask(dims, sizes, CV_8U); + Mat mask1; + Mat c, d; + + rng.fill(a, RNG::UNIFORM, 0, 100); + rng.fill(b, RNG::UNIFORM, 0, 100); + + // [-2,2) range means that the each generated random number + // will be one of -2, -1, 0, 1. Saturated to [0,255], it will become + // 0, 0, 0, 1 => the mask will be filled by ~25%. + rng.fill(mask, RNG::UNIFORM, -2, 2); + + a.convertTo(a1, depth1); + b.convertTo(b1, depth1); + // invert the mask + compare(mask, 0, mask1, CMP_EQ); + a1.setTo(0, mask1); + b1.setTo(0, mask1); + + if( op == 0 ) + { + add(a, b, c, mask); + add(a1, b1, d); + } + else if( op == 1 ) + { + subtract(a, b, c, mask); + subtract(a1, b1, d); + } + else if( op == 2 ) + { + bitwise_and(a, b, c, mask); + bitwise_and(a1, b1, d); + } + else if( op == 3 ) + { + bitwise_or(a, b, c, mask); + bitwise_or(a1, b1, d); + } + else if( op == 4 ) + { + bitwise_xor(a, b, c, mask); + bitwise_xor(a1, b1, d); + } + Mat d1; + d.convertTo(d1, depth); + CV_Assert( norm(c, d1, CV_C) <= DBL_EPSILON ); + } + + Mat_ tmpSrc(100,100); + tmpSrc = 124; + Mat_ tmpMask(100,100); + tmpMask = 255; + Mat_ tmpDst(100,100); + tmpDst = 2; + tmpSrc.copyTo(tmpDst,tmpMask); + } + catch(...) + { + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + } + } +}; + +TEST(Core_ArithmMask, uninitialized) { CV_ArithmMaskTest test; test.safe_run(); } + + diff --git a/core/test/test_countnonzero.cpp b/core/test/test_countnonzero.cpp new file mode 100644 index 0000000..6d16044 --- /dev/null +++ b/core/test/test_countnonzero.cpp @@ -0,0 +1,255 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" +#include +#include +using namespace cv; +using namespace std; + +#define CORE_COUNTNONZERO_ERROR_COUNT 1 + +#define MESSAGE_ERROR_COUNT "Count non zero elements returned by OpenCV function is incorrect." + +#define sign(a) a > 0 ? 1 : a == 0 ? 0 : -1 + +const int FLOAT_TYPE [2] = {CV_32F, CV_64F}; +const int INT_TYPE [5] = {CV_8U, CV_8S, CV_16U, CV_16S, CV_32S}; + +#define MAX_WIDTH 100 +#define MAX_HEIGHT 100 + +class CV_CountNonZeroTest: public cvtest::BaseTest +{ +public: + CV_CountNonZeroTest(); + ~CV_CountNonZeroTest(); + +protected: + void run (int); + +private: + float eps_32; + double eps_64; + Mat src; + int current_type; + + void generate_src_data(cv::Size size, int type); + void generate_src_data(cv::Size size, int type, int count_non_zero); + void generate_src_stat_data(cv::Size size, int type, int distribution); + + int get_count_non_zero(); + + void print_information(int right, int result); +}; + +CV_CountNonZeroTest::CV_CountNonZeroTest(): eps_32(std::numeric_limits::min()), eps_64(std::numeric_limits::min()), src(Mat()), current_type(-1) {} +CV_CountNonZeroTest::~CV_CountNonZeroTest() {} + +void CV_CountNonZeroTest::generate_src_data(cv::Size size, int type) +{ + src.create(size, CV_MAKETYPE(type, 1)); + + for (int j = 0; j < size.width; ++j) + for (int i = 0; i < size.height; ++i) + switch (type) + { + case CV_8U: { src.at(i, j) = cv::randu(); break; } + case CV_8S: { src.at(i, j) = cv::randu() - 128; break; } + case CV_16U: { src.at(i, j) = cv::randu(); break; } + case CV_16S: { src.at(i, j) = cv::randu(); break; } + case CV_32S: { src.at(i, j) = cv::randu(); break; } + case CV_32F: { src.at(i, j) = cv::randu(); break; } + case CV_64F: { src.at(i, j) = cv::randu(); break; } + default: break; + } +} + +void CV_CountNonZeroTest::generate_src_data(cv::Size size, int type, int count_non_zero) +{ + src = Mat::zeros(size, CV_MAKETYPE(type, 1)); + + int n = 0; RNG& rng = ts->get_rng(); + + while (n < count_non_zero) + { + int i = rng.next()%size.height, j = rng.next()%size.width; + + switch (type) + { + case CV_8U: { if (!src.at(i, j)) {src.at(i, j) = cv::randu(); n += (src.at(i, j) > 0);} break; } + case CV_8S: { if (!src.at(i, j)) {src.at(i, j) = cv::randu() - 128; n += abs(sign(src.at(i, j)));} break; } + case CV_16U: { if (!src.at(i, j)) {src.at(i, j) = cv::randu(); n += (src.at(i, j) > 0);} break; } + case CV_16S: { if (!src.at(i, j)) {src.at(i, j) = cv::randu(); n += abs(sign(src.at(i, j)));} break; } + case CV_32S: { if (!src.at(i, j)) {src.at(i, j) = cv::randu(); n += abs(sign(src.at(i, j)));} break; } + case CV_32F: { if (fabs(src.at(i, j)) <= eps_32) {src.at(i, j) = cv::randu(); n += (fabs(src.at(i, j)) > eps_32);} break; } + case CV_64F: { if (fabs(src.at(i, j)) <= eps_64) {src.at(i, j) = cv::randu(); n += (fabs(src.at(i, j)) > eps_64);} break; } + + default: break; + } + } + +} + +void CV_CountNonZeroTest::generate_src_stat_data(cv::Size size, int type, int distribution) +{ + src.create(size, CV_MAKETYPE(type, 1)); + + double mean = 0.0, sigma = 1.0; + double left = -1.0, right = 1.0; + + RNG& rng = ts->get_rng(); + + if (distribution == RNG::NORMAL) + rng.fill(src, RNG::NORMAL, Scalar::all(mean), Scalar::all(sigma)); + else if (distribution == RNG::UNIFORM) + rng.fill(src, RNG::UNIFORM, Scalar::all(left), Scalar::all(right)); +} + +int CV_CountNonZeroTest::get_count_non_zero() +{ + int result = 0; + + for (int i = 0; i < src.rows; ++i) + for (int j = 0; j < src.cols; ++j) + { + if (current_type == CV_8U) result += (src.at(i, j) > 0); + else if (current_type == CV_8S) result += abs(sign(src.at(i, j))); + else if (current_type == CV_16U) result += (src.at(i, j) > 0); + else if (current_type == CV_16S) result += abs(sign(src.at(i, j))); + else if (current_type == CV_32S) result += abs(sign(src.at(i, j))); + else if (current_type == CV_32F) result += (fabs(src.at(i, j)) > eps_32); + else result += (fabs(src.at(i, j)) > eps_64); + } + + return result; +} + +void CV_CountNonZeroTest::print_information(int right, int result) +{ + cout << endl; cout << "Checking for the work of countNonZero function..." << endl; cout << endl; + cout << "Type of Mat: "; + switch (current_type) + { + case 0: {cout << "CV_8U"; break;} + case 1: {cout << "CV_8S"; break;} + case 2: {cout << "CV_16U"; break;} + case 3: {cout << "CV_16S"; break;} + case 4: {cout << "CV_32S"; break;} + case 5: {cout << "CV_32F"; break;} + case 6: {cout << "CV_64F"; break;} + default: break; + } + cout << endl; + cout << "Number of rows: " << src.rows << " Number of cols: " << src.cols << endl; + cout << "True count non zero elements: " << right << " Result: " << result << endl; + cout << endl; +} + +void CV_CountNonZeroTest::run(int) +{ + const size_t N = 1500; + + for (int k = 1; k <= 3; ++k) + for (size_t i = 0; i < N; ++i) + { + RNG& rng = ts->get_rng(); + + int w = rng.next()%MAX_WIDTH + 1, h = rng.next()%MAX_HEIGHT + 1; + + current_type = rng.next()%7; + + switch (k) + { + case 1: { + generate_src_data(Size(w, h), current_type); + int right = get_count_non_zero(), result = countNonZero(src); + if (result != right) + { + cout << "Number of experiment: " << i << endl; + cout << "Method of data generation: RANDOM" << endl; + print_information(right, result); + CV_Error(CORE_COUNTNONZERO_ERROR_COUNT, MESSAGE_ERROR_COUNT); + return; + } + + break; + } + + case 2: { + int count_non_zero = rng.next()%(w*h); + generate_src_data(Size(w, h), current_type, count_non_zero); + int result = countNonZero(src); + if (result != count_non_zero) + { + cout << "Number of experiment: " << i << endl; + cout << "Method of data generation: HALF-RANDOM" << endl; + print_information(count_non_zero, result); + CV_Error(CORE_COUNTNONZERO_ERROR_COUNT, MESSAGE_ERROR_COUNT); + return; + } + + break; + } + + case 3: { + int distribution = cv::randu()%2; + generate_src_stat_data(Size(w, h), current_type, distribution); + int right = get_count_non_zero(), result = countNonZero(src); + if (right != result) + { + cout << "Number of experiment: " << i << endl; + cout << "Method of data generation: STATISTIC" << endl; + print_information(right, result); + CV_Error(CORE_COUNTNONZERO_ERROR_COUNT, MESSAGE_ERROR_COUNT); + return; + } + + break; + } + + default: break; + } + } +} + +TEST (Core_CountNonZero, accuracy) { CV_CountNonZeroTest test; test.safe_run(); } diff --git a/core/test/test_ds.cpp b/core/test/test_ds.cpp new file mode 100644 index 0000000..d797860 --- /dev/null +++ b/core/test/test_ds.cpp @@ -0,0 +1,2122 @@ +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +typedef struct CvTsSimpleSeq +{ + schar* array; + int count; + int max_count; + int elem_size; +} CvTsSimpleSeq; + + +static CvTsSimpleSeq* cvTsCreateSimpleSeq( int max_count, int elem_size ) +{ + CvTsSimpleSeq* seq = (CvTsSimpleSeq*)cvAlloc( sizeof(*seq) + max_count * elem_size ); + seq->elem_size = elem_size; + seq->max_count = max_count; + seq->count = 0; + seq->array = (schar*)(seq + 1); + return seq; +} + + +static void cvTsReleaseSimpleSeq( CvTsSimpleSeq** seq ) +{ + cvFree( seq ); +} + + +static schar* cvTsSimpleSeqElem( CvTsSimpleSeq* seq, int index ) +{ + assert( 0 <= index && index < seq->count ); + return seq->array + index * seq->elem_size; +} + + +static void cvTsClearSimpleSeq( CvTsSimpleSeq* seq ) +{ + seq->count = 0; +} + + +static void cvTsSimpleSeqShiftAndCopy( CvTsSimpleSeq* seq, int from_idx, int to_idx, void* elem=0 ) +{ + int elem_size = seq->elem_size; + + if( from_idx == to_idx ) + return; + assert( (from_idx > to_idx && !elem) || (from_idx < to_idx && elem) ); + + if( from_idx < seq->count ) + { + memmove( seq->array + to_idx*elem_size, seq->array + from_idx*elem_size, + (seq->count - from_idx)*elem_size ); + } + seq->count += to_idx - from_idx; + if( elem && to_idx > from_idx ) + memcpy( seq->array + from_idx*elem_size, elem, (to_idx - from_idx)*elem_size ); +} + +static void cvTsSimpleSeqInvert( CvTsSimpleSeq* seq ) +{ + int i, k, len = seq->count, elem_size = seq->elem_size; + schar *data = seq->array, t; + + for( i = 0; i < len/2; i++ ) + { + schar* a = data + i*elem_size; + schar* b = data + (len - i - 1)*elem_size; + for( k = 0; k < elem_size; k++ ) + CV_SWAP( a[k], b[k], t ); + } +} + +/****************************************************************************************\ + * simple cvset implementation * + \****************************************************************************************/ + +typedef struct CvTsSimpleSet +{ + schar* array; + int count, max_count; + int elem_size; + int* free_stack; + int free_count; +} CvTsSimpleSet; + + +static void cvTsClearSimpleSet( CvTsSimpleSet* set_header ) +{ + int i; + int elem_size = set_header->elem_size; + + for( i = 0; i < set_header->max_count; i++ ) + { + set_header->array[i*elem_size] = 0; + set_header->free_stack[i] = set_header->max_count - i - 1; + } + set_header->free_count = set_header->max_count; + set_header->count = 0; +} + + +static CvTsSimpleSet* cvTsCreateSimpleSet( int max_count, int elem_size ) +{ + CvTsSimpleSet* set_header = (CvTsSimpleSet*)cvAlloc( sizeof(*set_header) + max_count * + (elem_size + 1 + sizeof(int))); + set_header->elem_size = elem_size + 1; + set_header->max_count = max_count; + set_header->free_stack = (int*)(set_header + 1); + set_header->array = (schar*)(set_header->free_stack + max_count); + + cvTsClearSimpleSet( set_header ); + return set_header; +} + + +static void cvTsReleaseSimpleSet( CvTsSimpleSet** set_header ) +{ + cvFree( set_header ); +} + + +static schar* cvTsSimpleSetFind( CvTsSimpleSet* set_header, int index ) +{ + int idx = index * set_header->elem_size; + assert( 0 <= index && index < set_header->max_count ); + return set_header->array[idx] ? set_header->array + idx + 1 : 0; +} + + +static int cvTsSimpleSetAdd( CvTsSimpleSet* set_header, void* elem ) +{ + int idx, idx2; + assert( set_header->free_count > 0 ); + + idx = set_header->free_stack[--set_header->free_count]; + idx2 = idx * set_header->elem_size; + assert( set_header->array[idx2] == 0 ); + set_header->array[idx2] = 1; + if( set_header->elem_size > 1 ) + memcpy( set_header->array + idx2 + 1, elem, set_header->elem_size - 1 ); + set_header->count = MAX( set_header->count, idx + 1 ); + + return idx; +} + + +static void cvTsSimpleSetRemove( CvTsSimpleSet* set_header, int index ) +{ + assert( set_header->free_count < set_header->max_count && + 0 <= index && index < set_header->max_count ); + assert( set_header->array[index * set_header->elem_size] == 1 ); + + set_header->free_stack[set_header->free_count++] = index; + set_header->array[index * set_header->elem_size] = 0; +} + + +/****************************************************************************************\ + * simple graph implementation * + \****************************************************************************************/ + +typedef struct CvTsSimpleGraph +{ + char* matrix; + int edge_size; + int oriented; + CvTsSimpleSet* vtx; +} CvTsSimpleGraph; + + +static void cvTsClearSimpleGraph( CvTsSimpleGraph* graph ) +{ + int max_vtx_count = graph->vtx->max_count; + cvTsClearSimpleSet( graph->vtx ); + memset( graph->matrix, 0, max_vtx_count * max_vtx_count * graph->edge_size ); +} + + +static CvTsSimpleGraph* cvTsCreateSimpleGraph( int max_vtx_count, int vtx_size, + int edge_size, int oriented ) +{ + CvTsSimpleGraph* graph; + + assert( max_vtx_count > 1 && vtx_size >= 0 && edge_size >= 0 ); + graph = (CvTsSimpleGraph*)cvAlloc( sizeof(*graph) + + max_vtx_count * max_vtx_count * (edge_size + 1)); + graph->vtx = cvTsCreateSimpleSet( max_vtx_count, vtx_size ); + graph->edge_size = edge_size + 1; + graph->matrix = (char*)(graph + 1); + graph->oriented = oriented; + + cvTsClearSimpleGraph( graph ); + return graph; +} + + +static void cvTsReleaseSimpleGraph( CvTsSimpleGraph** graph ) +{ + if( *graph ) + { + cvTsReleaseSimpleSet( &(graph[0]->vtx) ); + cvFree( graph ); + } +} + + +static int cvTsSimpleGraphAddVertex( CvTsSimpleGraph* graph, void* vertex ) +{ + return cvTsSimpleSetAdd( graph->vtx, vertex ); +} + + +static void cvTsSimpleGraphRemoveVertex( CvTsSimpleGraph* graph, int index ) +{ + int i, max_vtx_count = graph->vtx->max_count; + int edge_size = graph->edge_size; + cvTsSimpleSetRemove( graph->vtx, index ); + + /* remove all the corresponding edges */ + for( i = 0; i < max_vtx_count; i++ ) + { + graph->matrix[(i*max_vtx_count + index)*edge_size] = + graph->matrix[(index*max_vtx_count + i)*edge_size] = 0; + } +} + + +static void cvTsSimpleGraphAddEdge( CvTsSimpleGraph* graph, int idx1, int idx2, void* edge ) +{ + int i, t, n = graph->oriented ? 1 : 2; + + assert( cvTsSimpleSetFind( graph->vtx, idx1 ) && + cvTsSimpleSetFind( graph->vtx, idx2 )); + + for( i = 0; i < n; i++ ) + { + int ofs = (idx1*graph->vtx->max_count + idx2)*graph->edge_size; + assert( graph->matrix[ofs] == 0 ); + graph->matrix[ofs] = 1; + if( graph->edge_size > 1 ) + memcpy( graph->matrix + ofs + 1, edge, graph->edge_size - 1 ); + + CV_SWAP( idx1, idx2, t ); + } +} + + +static void cvTsSimpleGraphRemoveEdge( CvTsSimpleGraph* graph, int idx1, int idx2 ) +{ + int i, t, n = graph->oriented ? 1 : 2; + + assert( cvTsSimpleSetFind( graph->vtx, idx1 ) && + cvTsSimpleSetFind( graph->vtx, idx2 )); + + for( i = 0; i < n; i++ ) + { + int ofs = (idx1*graph->vtx->max_count + idx2)*graph->edge_size; + assert( graph->matrix[ofs] == 1 ); + graph->matrix[ofs] = 0; + CV_SWAP( idx1, idx2, t ); + } +} + + +static schar* cvTsSimpleGraphFindVertex( CvTsSimpleGraph* graph, int index ) +{ + return cvTsSimpleSetFind( graph->vtx, index ); +} + + +static char* cvTsSimpleGraphFindEdge( CvTsSimpleGraph* graph, int idx1, int idx2 ) +{ + if( cvTsSimpleGraphFindVertex( graph, idx1 ) && + cvTsSimpleGraphFindVertex( graph, idx2 )) + { + char* edge = graph->matrix + (idx1 * graph->vtx->max_count + idx2)*graph->edge_size; + if( edge[0] ) return edge + 1; + } + return 0; +} + + +static int cvTsSimpleGraphVertexDegree( CvTsSimpleGraph* graph, int index ) +{ + int i, count = 0; + int edge_size = graph->edge_size; + int max_vtx_count = graph->vtx->max_count; + assert( cvTsSimpleGraphFindVertex( graph, index ) != 0 ); + + for( i = 0; i < max_vtx_count; i++ ) + { + count += graph->matrix[(i*max_vtx_count + index)*edge_size] + + graph->matrix[(index*max_vtx_count + i)*edge_size]; + } + + if( !graph->oriented ) + { + assert( count % 2 == 0 ); + count /= 2; + } + return count; +} + + +///////////////////////////////////// the tests ////////////////////////////////// + +#define CV_TS_SEQ_CHECK_CONDITION( expr, err_msg ) \ +if( !(expr) ) \ +{ \ +set_error_context( #expr, err_msg, __FILE__, __LINE__ ); \ +ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );\ +throw -1; \ +} + +class Core_DynStructBaseTest : public cvtest::BaseTest +{ +public: + Core_DynStructBaseTest(); + virtual ~Core_DynStructBaseTest(); + bool can_do_fast_forward(); + void clear(); + +protected: + int read_params( CvFileStorage* fs ); + void run_func(void); + void set_error_context( const char* condition, + const char* err_msg, + const char* file, int line ); + int test_seq_block_consistence( int _struct_idx, CvSeq* seq, int total ); + void update_progressbar(); + + int struct_count, max_struct_size, iterations, generations; + int min_log_storage_block_size, max_log_storage_block_size; + int min_log_elem_size, max_log_elem_size; + int gen, struct_idx, iter; + int test_progress; + int64 start_time; + double cpu_freq; + vector cxcore_struct; + vector simple_struct; + Ptr storage; +}; + + +Core_DynStructBaseTest::Core_DynStructBaseTest() +{ + struct_count = 2; + max_struct_size = 2000; + min_log_storage_block_size = 7; + max_log_storage_block_size = 12; + min_log_elem_size = 0; + max_log_elem_size = 8; + generations = 10; + iterations = max_struct_size*2; + gen = struct_idx = iter = -1; + test_progress = -1; + + storage = 0; +} + + +Core_DynStructBaseTest::~Core_DynStructBaseTest() +{ + clear(); +} + + +void Core_DynStructBaseTest::run_func() +{ +} + +bool Core_DynStructBaseTest::can_do_fast_forward() +{ + return false; +} + + +void Core_DynStructBaseTest::clear() +{ + cvtest::BaseTest::clear(); +} + + +int Core_DynStructBaseTest::read_params( CvFileStorage* fs ) +{ + int code = cvtest::BaseTest::read_params( fs ); + double sqrt_scale = sqrt(ts->get_test_case_count_scale()); + if( code < 0 ) + return code; + + struct_count = cvReadInt( find_param( fs, "struct_count" ), struct_count ); + max_struct_size = cvReadInt( find_param( fs, "max_struct_size" ), max_struct_size ); + generations = cvReadInt( find_param( fs, "generations" ), generations ); + iterations = cvReadInt( find_param( fs, "iterations" ), iterations ); + generations = cvRound(generations*sqrt_scale); + iterations = cvRound(iterations*sqrt_scale); + + min_log_storage_block_size = cvReadInt( find_param( fs, "min_log_storage_block_size" ), + min_log_storage_block_size ); + max_log_storage_block_size = cvReadInt( find_param( fs, "max_log_storage_block_size" ), + max_log_storage_block_size ); + min_log_elem_size = cvReadInt( find_param( fs, "min_log_elem_size" ), min_log_elem_size ); + max_log_elem_size = cvReadInt( find_param( fs, "max_log_elem_size" ), max_log_elem_size ); + + struct_count = cvtest::clipInt( struct_count, 1, 100 ); + max_struct_size = cvtest::clipInt( max_struct_size, 1, 1<<20 ); + generations = cvtest::clipInt( generations, 1, 100 ); + iterations = cvtest::clipInt( iterations, 100, 1<<20 ); + + min_log_storage_block_size = cvtest::clipInt( min_log_storage_block_size, 7, 20 ); + max_log_storage_block_size = cvtest::clipInt( max_log_storage_block_size, + min_log_storage_block_size, 20 ); + + min_log_elem_size = cvtest::clipInt( min_log_elem_size, 0, 8 ); + max_log_elem_size = cvtest::clipInt( max_log_elem_size, min_log_elem_size, 10 ); + + return 0; +} + + +void Core_DynStructBaseTest::update_progressbar() +{ + int64 t; + + if( test_progress < 0 ) + { + test_progress = 0; + cpu_freq = cv::getTickFrequency(); + start_time = cv::getTickCount(); + } + + t = cv::getTickCount(); + test_progress = update_progress( test_progress, 0, 0, (double)(t - start_time)/cpu_freq ); +} + + +void Core_DynStructBaseTest::set_error_context( const char* condition, + const char* err_msg, + const char* filename, int lineno ) +{ + ts->printf( cvtest::TS::LOG, "file %s, line %d: %s\n(\"%s\" failed).\n" + "generation = %d, struct_idx = %d, iter = %d\n", + filename, lineno, err_msg, condition, gen, struct_idx, iter ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); +} + + +int Core_DynStructBaseTest::test_seq_block_consistence( int _struct_idx, CvSeq* seq, int total ) +{ + int sum = 0; + struct_idx = _struct_idx; + + CV_TS_SEQ_CHECK_CONDITION( seq != 0, "Null sequence pointer" ); + + if( seq->first ) + { + CvSeqBlock* block = seq->first; + CvSeqBlock* prev_block = block->prev; + + int delta_idx = seq->first->start_index; + + for( ;; ) + { + CV_TS_SEQ_CHECK_CONDITION( sum == block->start_index - delta_idx && + block->count > 0 && block->prev == prev_block && + prev_block->next == block, + "sequence blocks are inconsistent" ); + sum += block->count; + prev_block = block; + block = block->next; + if( block == seq->first ) break; + } + + CV_TS_SEQ_CHECK_CONDITION( block->prev->count * seq->elem_size + + block->prev->data <= seq->block_max, + "block->data or block_max pointer are incorrect" ); + } + + CV_TS_SEQ_CHECK_CONDITION( seq->total == sum && sum == total, + "total number of elements is incorrect" ); + + return 0; +} + + +/////////////////////////////////// sequence tests //////////////////////////////////// + +class Core_SeqBaseTest : public Core_DynStructBaseTest +{ +public: + Core_SeqBaseTest(); + void clear(); + void run( int ); + +protected: + int test_multi_create(); + int test_get_seq_elem( int _struct_idx, int iters ); + int test_get_seq_reading( int _struct_idx, int iters ); + int test_seq_ops( int iters ); +}; + + +Core_SeqBaseTest::Core_SeqBaseTest() +{ +} + + +void Core_SeqBaseTest::clear() +{ + for( size_t i = 0; i < simple_struct.size(); i++ ) + cvTsReleaseSimpleSeq( (CvTsSimpleSeq**)&simple_struct[i] ); + Core_DynStructBaseTest::clear(); +} + + +int Core_SeqBaseTest::test_multi_create() +{ + vector writer(struct_count); + vector pos(struct_count); + vector index(struct_count); + int cur_count, elem_size; + RNG& rng = ts->get_rng(); + + for( int i = 0; i < struct_count; i++ ) + { + double t; + CvTsSimpleSeq* sseq; + + pos[i] = -1; + index[i] = i; + + t = cvtest::randReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size; + elem_size = cvRound( exp(t * CV_LOG2) ); + elem_size = MIN( elem_size, (int)(storage->block_size - sizeof(void*) - + sizeof(CvSeqBlock) - sizeof(CvMemBlock)) ); + + cvTsReleaseSimpleSeq( (CvTsSimpleSeq**)&simple_struct[i] ); + simple_struct[i] = sseq = cvTsCreateSimpleSeq( max_struct_size, elem_size ); + cxcore_struct[i] = 0; + sseq->count = cvtest::randInt( rng ) % max_struct_size; + Mat m( 1, MAX(sseq->count,1)*elem_size, CV_8UC1, sseq->array ); + cvtest::randUni( rng, m, Scalar::all(0), Scalar::all(256) ); + } + + for( cur_count = struct_count; cur_count > 0; cur_count-- ) + { + for(;;) + { + int k = cvtest::randInt( rng ) % cur_count; + struct_idx = index[k]; + CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[struct_idx]; + + if( pos[struct_idx] < 0 ) + { + int hdr_size = (cvtest::randInt(rng) % 10)*4 + sizeof(CvSeq); + hdr_size = MIN( hdr_size, (int)(storage->block_size - sizeof(CvMemBlock)) ); + elem_size = sseq->elem_size; + + if( cvtest::randInt(rng) % 2 ) + { + cvStartWriteSeq( 0, hdr_size, elem_size, storage, &writer[struct_idx] ); + } + else + { + CvSeq* s; + s = cvCreateSeq( 0, hdr_size, elem_size, storage ); + cvStartAppendToSeq( s, &writer[struct_idx] ); + } + + cvSetSeqBlockSize( writer[struct_idx].seq, cvtest::randInt( rng ) % 10000 ); + pos[struct_idx] = 0; + } + + update_progressbar(); + if( pos[struct_idx] == sseq->count ) + { + cxcore_struct[struct_idx] = cvEndWriteSeq( &writer[struct_idx] ); + /* del index */ + for( ; k < cur_count-1; k++ ) + index[k] = index[k+1]; + break; + } + + { + schar* el = cvTsSimpleSeqElem( sseq, pos[struct_idx] ); + CV_WRITE_SEQ_ELEM_VAR( el, writer[struct_idx] ); + } + pos[struct_idx]++; + } + } + + return 0; +} + + +int Core_SeqBaseTest::test_get_seq_elem( int _struct_idx, int iters ) +{ + RNG& rng = ts->get_rng(); + + CvSeq* seq = (CvSeq*)cxcore_struct[_struct_idx]; + CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[_struct_idx]; + struct_idx = _struct_idx; + + assert( seq->total == sseq->count ); + + if( sseq->count == 0 ) + return 0; + + for( int i = 0; i < iters; i++ ) + { + int idx = cvtest::randInt(rng) % (sseq->count*3) - sseq->count*3/2; + int idx0 = (unsigned)idx < (unsigned)(sseq->count) ? idx : idx < 0 ? + idx + sseq->count : idx - sseq->count; + int bad_range = (unsigned)idx0 >= (unsigned)(sseq->count); + schar* elem; + elem = cvGetSeqElem( seq, idx ); + + if( bad_range ) + { + CV_TS_SEQ_CHECK_CONDITION( elem == 0, + "cvGetSeqElem doesn't " + "handle \"out of range\" properly" ); + } + else + { + CV_TS_SEQ_CHECK_CONDITION( elem != 0 && + !memcmp( elem, cvTsSimpleSeqElem(sseq, idx0), sseq->elem_size ), + "cvGetSeqElem returns wrong element" ); + + idx = cvSeqElemIdx(seq, elem ); + CV_TS_SEQ_CHECK_CONDITION( idx >= 0 && idx == idx0, + "cvSeqElemIdx is incorrect" ); + } + } + + return 0; +} + + +int Core_SeqBaseTest::test_get_seq_reading( int _struct_idx, int iters ) +{ + const int max_val = 3*5 + 2; + CvSeq* seq = (CvSeq*)cxcore_struct[_struct_idx]; + CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[_struct_idx]; + int total = seq->total; + RNG& rng = ts->get_rng(); + CvSeqReader reader; + vector _elem(sseq->elem_size); + schar* elem = &_elem[0]; + + assert( total == sseq->count ); + this->struct_idx = _struct_idx; + + int pos = cvtest::randInt(rng) % 2; + cvStartReadSeq( seq, &reader, pos ); + + if( total == 0 ) + { + CV_TS_SEQ_CHECK_CONDITION( reader.ptr == 0, "Empty sequence reader pointer is not NULL" ); + return 0; + } + + pos = pos ? seq->total - 1 : 0; + + CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos(&reader), + "initial reader position is wrong" ); + + for( iter = 0; iter < iters; iter++ ) + { + int op = cvtest::randInt(rng) % max_val; + + if( op >= max_val - 2 ) + { + int new_pos, new_pos0; + int bad_range; + int is_relative = op == max_val - 1; + + new_pos = cvtest::randInt(rng) % (total*2) - total; + new_pos0 = new_pos + (is_relative ? pos : 0 ); + + if( new_pos0 < 0 ) new_pos0 += total; + if( new_pos0 >= total ) new_pos0 -= total; + + bad_range = (unsigned)new_pos0 >= (unsigned)total; + cvSetSeqReaderPos( &reader, new_pos, is_relative ); + + if( !bad_range ) + { + CV_TS_SEQ_CHECK_CONDITION( new_pos0 == cvGetSeqReaderPos( &reader ), + "cvset reader position doesn't work" ); + pos = new_pos0; + } + else + { + CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos( &reader ), + "reader doesn't stay at the current position after wrong positioning" ); + } + } + else + { + int direction = (op % 3) - 1; + memcpy( elem, reader.ptr, sseq->elem_size ); + + if( direction > 0 ) + { + CV_NEXT_SEQ_ELEM( sseq->elem_size, reader ); + } + else if( direction < 0 ) + { + CV_PREV_SEQ_ELEM( sseq->elem_size, reader ); + } + + CV_TS_SEQ_CHECK_CONDITION( memcmp(elem, cvTsSimpleSeqElem(sseq, pos), + sseq->elem_size) == 0, "reading is incorrect" ); + pos += direction; + if( -pos > 0 ) pos += total; + if( pos >= total ) pos -= total; + + CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos( &reader ), + "reader doesn't move correctly after reading" ); + } + } + + return 0; +} + + +int Core_SeqBaseTest::test_seq_ops( int iters ) +{ + const int max_op = 14; + int max_elem_size = 0; + schar* elem2 = 0; + RNG& rng = ts->get_rng(); + + for( int i = 0; i < struct_count; i++ ) + max_elem_size = MAX( max_elem_size, ((CvSeq*)cxcore_struct[i])->elem_size ); + + vector elem_buf(max_struct_size*max_elem_size); + schar* elem = (schar*)&elem_buf[0]; + Mat elem_mat; + + for( iter = 0; iter < iters; iter++ ) + { + struct_idx = cvtest::randInt(rng) % struct_count; + int op = cvtest::randInt(rng) % max_op; + CvSeq* seq = (CvSeq*)cxcore_struct[struct_idx]; + CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[struct_idx]; + int elem_size = sseq->elem_size; + int whence = 0, pos = 0, count = 0; + + switch( op ) + { + case 0: + case 1: + case 2: // push/pushfront/insert + if( sseq->count == sseq->max_count ) + break; + + elem_mat = Mat(1, elem_size, CV_8U, elem); + cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) ); + + whence = op - 1; + if( whence < 0 ) + { + pos = 0; + cvSeqPushFront( seq, elem ); + } + else if( whence > 0 ) + { + pos = sseq->count; + cvSeqPush( seq, elem ); + } + else + { + pos = cvtest::randInt(rng) % (sseq->count + 1); + cvSeqInsert( seq, pos, elem ); + } + + cvTsSimpleSeqShiftAndCopy( sseq, pos, pos + 1, elem ); + elem2 = cvGetSeqElem( seq, pos ); + CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "The inserted element could not be retrieved" ); + CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count && + memcmp(elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0, + "The inserted sequence element is wrong" ); + break; + + case 3: + case 4: + case 5: // pop/popfront/remove + if( sseq->count == 0 ) + break; + + whence = op - 4; + if( whence < 0 ) + { + pos = 0; + cvSeqPopFront( seq, elem ); + } + else if( whence > 0 ) + { + pos = sseq->count-1; + cvSeqPop( seq, elem ); + } + else + { + pos = cvtest::randInt(rng) % sseq->count; + cvSeqRemove( seq, pos ); + } + + if( whence != 0 ) + CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count - 1 && + memcmp( elem, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0, + "The popped sequence element isn't correct" ); + + cvTsSimpleSeqShiftAndCopy( sseq, pos + 1, pos ); + + if( sseq->count > 0 ) + { + elem2 = cvGetSeqElem( seq, pos < sseq->count ? pos : -1 ); + CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "GetSeqElem fails after removing the element" ); + + CV_TS_SEQ_CHECK_CONDITION( memcmp( elem2, + cvTsSimpleSeqElem(sseq, pos - (pos == sseq->count)), elem_size) == 0, + "The first shifted element is not correct after removing another element" ); + } + else + { + CV_TS_SEQ_CHECK_CONDITION( seq->first == 0, + "The sequence doesn't become empty after the final remove" ); + } + break; + + case 6: + case 7: + case 8: // push [front] multi/insert slice + if( sseq->count == sseq->max_count ) + break; + + count = cvtest::randInt( rng ) % (sseq->max_count - sseq->count + 1); + elem_mat = Mat(1, MAX(count,1) * elem_size, CV_8U, elem); + cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) ); + + whence = op - 7; + pos = whence < 0 ? 0 : whence > 0 ? sseq->count : (int)(cvtest::randInt(rng) % (sseq->count+1)); + if( whence != 0 ) + { + cvSeqPushMulti( seq, elem, count, whence < 0 ); + } + else + { + CvSeq header; + CvSeqBlock block; + cvMakeSeqHeaderForArray( CV_SEQ_KIND_GENERIC, sizeof(CvSeq), + sseq->elem_size, + elem, count, + &header, &block ); + + cvSeqInsertSlice( seq, pos, &header ); + } + cvTsSimpleSeqShiftAndCopy( sseq, pos, pos + count, elem ); + + if( sseq->count > 0 ) + { + // choose the random element among the added + pos = count > 0 ? (int)(cvtest::randInt(rng) % count + pos) : MAX(pos-1,0); + elem2 = cvGetSeqElem( seq, pos ); + CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "multi push operation doesn't add elements" ); + CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count && + memcmp( elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0, + "One of the added elements is wrong" ); + } + else + { + CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0, + "Adding no elements to empty sequence fails" ); + } + break; + + case 9: + case 10: + case 11: // pop [front] multi + if( sseq->count == 0 ) + break; + + count = cvtest::randInt(rng) % (sseq->count+1); + whence = op - 10; + pos = whence < 0 ? 0 : whence > 0 ? sseq->count - count : + (int)(cvtest::randInt(rng) % (sseq->count - count + 1)); + + if( whence != 0 ) + { + cvSeqPopMulti( seq, elem, count, whence < 0 ); + + if( count > 0 ) + { + CV_TS_SEQ_CHECK_CONDITION( memcmp(elem, + cvTsSimpleSeqElem(sseq,pos), elem_size) == 0, + "The first (in the sequence order) removed element is wrong after popmulti" ); + } + } + else + { + cvSeqRemoveSlice( seq, cvSlice(pos, pos + count) ); + } + + CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count - count, + "The popmulti left a wrong number of elements in the sequence" ); + + cvTsSimpleSeqShiftAndCopy( sseq, pos + count, pos, 0 ); + if( sseq->count > 0 ) + { + pos = whence < 0 ? 0 : MIN( pos, sseq->count - 1 ); + elem2 = cvGetSeqElem( seq, pos ); + CV_TS_SEQ_CHECK_CONDITION( elem2 && + memcmp( elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0, + "The last sequence element is wrong after POP" ); + } + else + { + CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0, + "The sequence doesn't become empty after final POP" ); + } + break; + case 12: // seqslice + { + CvMemStoragePos storage_pos; + cvSaveMemStoragePos( storage, &storage_pos ); + + int copy_data = cvtest::randInt(rng) % 2; + count = cvtest::randInt(rng) % (seq->total + 1); + pos = cvtest::randInt(rng) % (seq->total - count + 1); + CvSeq* seq_slice = cvSeqSlice( seq, cvSlice(pos, pos + count), storage, copy_data ); + + CV_TS_SEQ_CHECK_CONDITION( seq_slice && seq_slice->total == count, + "cvSeqSlice returned incorrect slice" ); + + if( count > 0 ) + { + int test_idx = cvtest::randInt(rng) % count; + elem2 = cvGetSeqElem( seq_slice, test_idx ); + schar* elem3 = cvGetSeqElem( seq, pos + test_idx ); + CV_TS_SEQ_CHECK_CONDITION( elem2 && + memcmp( elem2, cvTsSimpleSeqElem(sseq,pos + test_idx), elem_size) == 0, + "The extracted slice elements are not correct" ); + CV_TS_SEQ_CHECK_CONDITION( (elem2 == elem3) ^ copy_data, + "copy_data flag is handled incorrectly" ); + } + + cvRestoreMemStoragePos( storage, &storage_pos ); + } + break; + case 13: // clear + cvTsClearSimpleSeq( sseq ); + cvClearSeq( seq ); + CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0, + "The sequence doesn't become empty after clear" ); + break; + default: + assert(0); + return -1; + } + + if( test_seq_block_consistence(struct_idx, seq, sseq->count) < 0 ) + return -1; + + if( test_get_seq_elem(struct_idx, 7) < 0 ) + return -1; + + update_progressbar(); + } + + return 0; +} + + +void Core_SeqBaseTest::run( int ) +{ + try + { + RNG& rng = ts->get_rng(); + int i; + double t; + + clear(); + test_progress = -1; + + simple_struct.resize(struct_count, 0); + cxcore_struct.resize(struct_count, 0); + + for( gen = 0; gen < generations; gen++ ) + { + struct_idx = iter = -1; + + if( !storage ) + { + t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + + min_log_storage_block_size; + storage = cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) ); + } + + iter = struct_idx = -1; + test_multi_create(); + + for( i = 0; i < struct_count; i++ ) + { + if( test_seq_block_consistence(i, (CvSeq*)cxcore_struct[i], + ((CvTsSimpleSeq*)simple_struct[i])->count) < 0 ) + return; + + if( test_get_seq_elem( i, MAX(iterations/3,7) ) < 0 ) + return; + + if( test_get_seq_reading( i, MAX(iterations/3,7) ) < 0 ) + return; + update_progressbar(); + } + + if( test_seq_ops( iterations ) < 0 ) + return; + + if( cvtest::randInt(rng) % 2 ) + storage.release(); + else + cvClearMemStorage( storage ); + } + } + catch(int) + { + } +} + + +////////////////////////////// more sequence tests ////////////////////////////////////// + +class Core_SeqSortInvTest : public Core_SeqBaseTest +{ +public: + Core_SeqSortInvTest(); + void run( int ); + +protected: +}; + + +Core_SeqSortInvTest::Core_SeqSortInvTest() +{ +} + + +static int icvCmpSeqElems( const void* a, const void* b, void* userdata ) +{ + return memcmp( a, b, ((CvSeq*)userdata)->elem_size ); +} + +static int icvCmpSeqElems2_elem_size = 0; +static int icvCmpSeqElems2( const void* a, const void* b ) +{ + return memcmp( a, b, icvCmpSeqElems2_elem_size ); +} + + +void Core_SeqSortInvTest::run( int ) +{ + try + { + RNG& rng = ts->get_rng(); + int i, k; + double t; + schar *elem0, *elem, *elem2; + vector buffer; + + clear(); + test_progress = -1; + + simple_struct.resize(struct_count, 0); + cxcore_struct.resize(struct_count, 0); + + for( gen = 0; gen < generations; gen++ ) + { + struct_idx = iter = -1; + + if( storage.empty() ) + { + t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + + min_log_storage_block_size; + storage = cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) ); + } + + for( iter = 0; iter < iterations/10; iter++ ) + { + int max_size = 0; + test_multi_create(); + + for( i = 0; i < struct_count; i++ ) + { + CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[i]; + max_size = MAX( max_size, sseq->count*sseq->elem_size ); + } + + buffer.resize(max_size); + + for( i = 0; i < struct_count; i++ ) + { + CvSeq* seq = (CvSeq*)cxcore_struct[i]; + CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[i]; + CvSlice slice = CV_WHOLE_SEQ; + + //printf("%d. %d. %d-th size = %d\n", gen, iter, i, sseq->count ); + + cvSeqInvert( seq ); + cvTsSimpleSeqInvert( sseq ); + + if( test_seq_block_consistence( i, seq, sseq->count ) < 0 ) + return; + + if( sseq->count > 0 && cvtest::randInt(rng) % 2 == 0 ) + { + slice.end_index = cvtest::randInt(rng) % sseq->count + 1; + slice.start_index = cvtest::randInt(rng) % (sseq->count - slice.end_index + 1); + slice.end_index += slice.start_index; + } + + cvCvtSeqToArray( seq, &buffer[0], slice ); + + slice.end_index = MIN( slice.end_index, sseq->count ); + CV_TS_SEQ_CHECK_CONDITION( sseq->count == 0 || memcmp( &buffer[0], + sseq->array + slice.start_index*sseq->elem_size, + (slice.end_index - slice.start_index)*sseq->elem_size ) == 0, + "cvSeqInvert returned wrong result" ); + + for( k = 0; k < (sseq->count > 0 ? 10 : 0); k++ ) + { + int idx0 = cvtest::randInt(rng) % sseq->count, idx = 0; + elem0 = cvTsSimpleSeqElem( sseq, idx0 ); + elem = cvGetSeqElem( seq, idx0 ); + elem2 = cvSeqSearch( seq, elem0, k % 2 ? icvCmpSeqElems : 0, 0, &idx, seq ); + + CV_TS_SEQ_CHECK_CONDITION( elem != 0 && + memcmp( elem0, elem, seq->elem_size ) == 0, + "cvSeqInvert gives incorrect result" ); + CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 && + memcmp( elem0, elem2, seq->elem_size ) == 0 && + elem2 == cvGetSeqElem( seq, idx ), + "cvSeqSearch failed (linear search)" ); + } + + cvSeqSort( seq, icvCmpSeqElems, seq ); + + if( test_seq_block_consistence( i, seq, sseq->count ) < 0 ) + return; + + if( sseq->count > 0 ) + { + // !!! This is not thread-safe !!! + icvCmpSeqElems2_elem_size = sseq->elem_size; + qsort( sseq->array, sseq->count, sseq->elem_size, icvCmpSeqElems2 ); + + if( cvtest::randInt(rng) % 2 == 0 ) + { + slice.end_index = cvtest::randInt(rng) % sseq->count + 1; + slice.start_index = cvtest::randInt(rng) % (sseq->count - slice.end_index + 1); + slice.end_index += slice.start_index; + } + } + + cvCvtSeqToArray( seq, &buffer[0], slice ); + CV_TS_SEQ_CHECK_CONDITION( sseq->count == 0 || memcmp( &buffer[0], + sseq->array + slice.start_index*sseq->elem_size, + (slice.end_index - slice.start_index)*sseq->elem_size ) == 0, + "cvSeqSort returned wrong result" ); + + for( k = 0; k < (sseq->count > 0 ? 10 : 0); k++ ) + { + int idx0 = cvtest::randInt(rng) % sseq->count, idx = 0; + elem0 = cvTsSimpleSeqElem( sseq, idx0 ); + elem = cvGetSeqElem( seq, idx0 ); + elem2 = cvSeqSearch( seq, elem0, icvCmpSeqElems, 1, &idx, seq ); + + CV_TS_SEQ_CHECK_CONDITION( elem != 0 && + memcmp( elem0, elem, seq->elem_size ) == 0, + "cvSeqSort gives incorrect result" ); + CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 && + memcmp( elem0, elem2, seq->elem_size ) == 0 && + elem2 == cvGetSeqElem( seq, idx ), + "cvSeqSearch failed (binary search)" ); + } + } + + cvClearMemStorage( storage ); + } + + storage.release(); + } + } + catch (int) + { + } +} + + +/////////////////////////////////////// set tests /////////////////////////////////////// + +class Core_SetTest : public Core_DynStructBaseTest +{ +public: + Core_SetTest(); + void clear(); + void run( int ); + +protected: + //int test_seq_block_consistence( int struct_idx ); + int test_set_ops( int iters ); +}; + + +Core_SetTest::Core_SetTest() +{ +} + + +void Core_SetTest::clear() +{ + for( size_t i = 0; i < simple_struct.size(); i++ ) + cvTsReleaseSimpleSet( (CvTsSimpleSet**)&simple_struct[i] ); + Core_DynStructBaseTest::clear(); +} + + +int Core_SetTest::test_set_ops( int iters ) +{ + const int max_op = 4; + int max_elem_size = 0; + int idx, idx0; + CvSetElem *elem = 0, *elem2 = 0, *elem3 = 0; + schar* elem_data = 0; + RNG& rng = ts->get_rng(); + //int max_active_count = 0, mean_active_count = 0; + + for( int i = 0; i < struct_count; i++ ) + max_elem_size = MAX( max_elem_size, ((CvSeq*)cxcore_struct[i])->elem_size ); + + vector elem_buf(max_elem_size); + Mat elem_mat; + + for( iter = 0; iter < iters; iter++ ) + { + struct_idx = cvtest::randInt(rng) % struct_count; + + CvSet* cvset = (CvSet*)cxcore_struct[struct_idx]; + CvTsSimpleSet* sset = (CvTsSimpleSet*)simple_struct[struct_idx]; + int pure_elem_size = sset->elem_size - 1; + int prev_total = cvset->total, prev_count = cvset->active_count; + int op = cvtest::randInt(rng) % (iter <= iters/10 ? 2 : max_op); + int by_ptr = op % 2 == 0; + CvSetElem* first_free = cvset->free_elems; + CvSetElem* next_free = first_free ? first_free->next_free : 0; + int pass_data = 0; + + if( iter > iters/10 && cvtest::randInt(rng)%200 == 0 ) // clear set + { + prev_count = cvset->total; + cvClearSet( cvset ); + cvTsClearSimpleSet( sset ); + + CV_TS_SEQ_CHECK_CONDITION( cvset->active_count == 0 && cvset->total == 0 && + cvset->first == 0 && cvset->free_elems == 0 && + (cvset->free_blocks != 0 || prev_count == 0), + "cvClearSet doesn't remove all the elements" ); + continue; + } + else if( op == 0 || op == 1 ) // add element + { + if( sset->free_count == 0 ) + continue; + + elem_mat = Mat(1, cvset->elem_size, CV_8U, &elem_buf[0]); + cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) ); + elem = (CvSetElem*)&elem_buf[0]; + + if( by_ptr ) + { + elem2 = cvSetNew( cvset ); + CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "cvSetNew returned NULL pointer" ); + } + else + { + pass_data = cvtest::randInt(rng) % 2; + idx = cvSetAdd( cvset, pass_data ? elem : 0, &elem2 ); + CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 && elem2->flags == idx, + "cvSetAdd returned NULL pointer or a wrong index" ); + } + + elem_data = (schar*)elem + sizeof(int); + + if( !pass_data ) + memcpy( (schar*)elem2 + sizeof(int), elem_data, pure_elem_size ); + + idx = elem2->flags; + idx0 = cvTsSimpleSetAdd( sset, elem_data ); + elem3 = cvGetSetElem( cvset, idx ); + + CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(elem3) && + idx == idx0 && elem3 == elem2 && (!pass_data || + memcmp( (char*)elem3 + sizeof(int), elem_data, pure_elem_size) == 0), + "The added element is not correct" ); + + CV_TS_SEQ_CHECK_CONDITION( (!first_free || elem3 == first_free) && + (!next_free || cvset->free_elems == next_free) && + cvset->active_count == prev_count + 1, + "The free node list is modified incorrectly" ); + } + else if( op == 2 || op == 3 ) // remove element + { + idx = cvtest::randInt(rng) % sset->max_count; + + if( sset->free_count == sset->max_count || idx >= sset->count ) + continue; + + elem_data = cvTsSimpleSetFind(sset, idx); + if( elem_data == 0 ) + continue; + + elem = cvGetSetElem( cvset, idx ); + CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(elem) && elem->flags == idx && + memcmp((char*)elem + sizeof(int), elem_data, pure_elem_size) == 0, + "cvGetSetElem returned wrong element" ); + + if( by_ptr ) + { + cvSetRemoveByPtr( cvset, elem ); + } + else + { + cvSetRemove( cvset, idx ); + } + + cvTsSimpleSetRemove( sset, idx ); + + CV_TS_SEQ_CHECK_CONDITION( !CV_IS_SET_ELEM(elem) && !cvGetSetElem(cvset, idx) && + (elem->flags & CV_SET_ELEM_IDX_MASK) == idx, + "cvSetRemove[ByPtr] didn't release the element properly" ); + + CV_TS_SEQ_CHECK_CONDITION( elem->next_free == first_free && + cvset->free_elems == elem && + cvset->active_count == prev_count - 1, + "The free node list has not been updated properly" ); + } + + //max_active_count = MAX( max_active_count, cvset->active_count ); + //mean_active_count += cvset->active_count; + CV_TS_SEQ_CHECK_CONDITION( cvset->active_count == sset->max_count - sset->free_count && + cvset->total >= cvset->active_count && + (cvset->total == 0 || cvset->total >= prev_total), + "The total number of cvset elements is not correct" ); + + // CvSet and simple set do not neccessary have the same "total" (active & free) number, + // so pass "set->total" to skip that check + test_seq_block_consistence( struct_idx, (CvSeq*)cvset, cvset->total ); + update_progressbar(); + } + + return 0; +} + + +void Core_SetTest::run( int ) +{ + try + { + RNG& rng = ts->get_rng(); + double t; + + clear(); + test_progress = -1; + + simple_struct.resize(struct_count, 0); + cxcore_struct.resize(struct_count, 0); + + for( gen = 0; gen < generations; gen++ ) + { + struct_idx = iter = -1; + t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size; + storage = cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) ); + + for( int i = 0; i < struct_count; i++ ) + { + t = cvtest::randReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size; + int pure_elem_size = cvRound( exp(t * CV_LOG2) ); + int elem_size = pure_elem_size + sizeof(int); + elem_size = (elem_size + sizeof(size_t) - 1) & ~(sizeof(size_t)-1); + elem_size = MAX( elem_size, (int)sizeof(CvSetElem) ); + elem_size = MIN( elem_size, (int)(storage->block_size - sizeof(void*) - sizeof(CvMemBlock) - sizeof(CvSeqBlock)) ); + pure_elem_size = MIN( pure_elem_size, elem_size-(int)sizeof(CvSetElem) ); + + cvTsReleaseSimpleSet( (CvTsSimpleSet**)&simple_struct[i] ); + simple_struct[i] = cvTsCreateSimpleSet( max_struct_size, pure_elem_size ); + cxcore_struct[i] = cvCreateSet( 0, sizeof(CvSet), elem_size, storage ); + } + + if( test_set_ops( iterations*100 ) < 0 ) + return; + + storage.release(); + } + } + catch(int) + { + } +} + + +/////////////////////////////////////// graph tests ////////////////////////////////// + +class Core_GraphTest : public Core_DynStructBaseTest +{ +public: + Core_GraphTest(); + void clear(); + void run( int ); + +protected: + //int test_seq_block_consistence( int struct_idx ); + int test_graph_ops( int iters ); +}; + + +Core_GraphTest::Core_GraphTest() +{ +} + + +void Core_GraphTest::clear() +{ + for( size_t i = 0; i < simple_struct.size(); i++ ) + cvTsReleaseSimpleGraph( (CvTsSimpleGraph**)&simple_struct[i] ); + Core_DynStructBaseTest::clear(); +} + + +int Core_GraphTest::test_graph_ops( int iters ) +{ + const int max_op = 4; + int i, k; + int max_elem_size = 0; + int idx, idx0; + CvGraphVtx *vtx = 0, *vtx2 = 0, *vtx3 = 0; + CvGraphEdge* edge = 0, *edge2 = 0; + RNG& rng = ts->get_rng(); + //int max_active_count = 0, mean_active_count = 0; + + for( i = 0; i < struct_count; i++ ) + { + CvGraph* graph = (CvGraph*)cxcore_struct[i]; + max_elem_size = MAX( max_elem_size, graph->elem_size ); + max_elem_size = MAX( max_elem_size, graph->edges->elem_size ); + } + + vector elem_buf(max_elem_size); + Mat elem_mat; + + for( iter = 0; iter < iters; iter++ ) + { + struct_idx = cvtest::randInt(rng) % struct_count; + CvGraph* graph = (CvGraph*)cxcore_struct[struct_idx]; + CvTsSimpleGraph* sgraph = (CvTsSimpleGraph*)simple_struct[struct_idx]; + CvSet* edges = graph->edges; + schar *vtx_data; + char *edge_data; + int pure_vtx_size = sgraph->vtx->elem_size - 1, + pure_edge_size = sgraph->edge_size - 1; + int prev_vtx_total = graph->total, + prev_edge_total = graph->edges->total, + prev_vtx_count = graph->active_count, + prev_edge_count = graph->edges->active_count; + int op = cvtest::randInt(rng) % max_op; + int pass_data = 0, vtx_degree0 = 0, vtx_degree = 0; + CvSetElem *first_free, *next_free; + + if( cvtest::randInt(rng) % 200 == 0 ) // clear graph + { + int prev_vtx_count2 = graph->total, prev_edge_count2 = graph->edges->total; + + cvClearGraph( graph ); + cvTsClearSimpleGraph( sgraph ); + + CV_TS_SEQ_CHECK_CONDITION( graph->active_count == 0 && graph->total == 0 && + graph->first == 0 && graph->free_elems == 0 && + (graph->free_blocks != 0 || prev_vtx_count2 == 0), + "The graph is not empty after clearing" ); + + CV_TS_SEQ_CHECK_CONDITION( edges->active_count == 0 && edges->total == 0 && + edges->first == 0 && edges->free_elems == 0 && + (edges->free_blocks != 0 || prev_edge_count2 == 0), + "The graph is not empty after clearing" ); + } + else if( op == 0 ) // add vertex + { + if( sgraph->vtx->free_count == 0 ) + continue; + + first_free = graph->free_elems; + next_free = first_free ? first_free->next_free : 0; + + if( pure_vtx_size ) + { + elem_mat = Mat(1, graph->elem_size, CV_8U, &elem_buf[0]); + cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) ); + } + + vtx = (CvGraphVtx*)&elem_buf[0]; + idx0 = cvTsSimpleGraphAddVertex( sgraph, vtx + 1 ); + + pass_data = cvtest::randInt(rng) % 2; + idx = cvGraphAddVtx( graph, pass_data ? vtx : 0, &vtx2 ); + + if( !pass_data && pure_vtx_size > 0 ) + memcpy( vtx2 + 1, vtx + 1, pure_vtx_size ); + + vtx3 = cvGetGraphVtx( graph, idx ); + + CV_TS_SEQ_CHECK_CONDITION( (CV_IS_SET_ELEM(vtx3) && vtx3->flags == idx && + vtx3->first == 0) || (idx == idx0 && vtx3 == vtx2 && + (!pass_data || pure_vtx_size == 0 || + memcmp(vtx3 + 1, vtx + 1, pure_vtx_size) == 0)), + "The added element is not correct" ); + + CV_TS_SEQ_CHECK_CONDITION( (!first_free || first_free == (CvSetElem*)vtx3) && + (!next_free || graph->free_elems == next_free) && + graph->active_count == prev_vtx_count + 1, + "The free node list is modified incorrectly" ); + } + else if( op == 1 ) // remove vertex + { + idx = cvtest::randInt(rng) % sgraph->vtx->max_count; + if( sgraph->vtx->free_count == sgraph->vtx->max_count || idx >= sgraph->vtx->count ) + continue; + + vtx_data = cvTsSimpleGraphFindVertex(sgraph, idx); + if( vtx_data == 0 ) + continue; + + vtx_degree0 = cvTsSimpleGraphVertexDegree( sgraph, idx ); + first_free = graph->free_elems; + + vtx = cvGetGraphVtx( graph, idx ); + CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(vtx) && vtx->flags == idx && + (pure_vtx_size == 0 || memcmp( vtx + 1, vtx_data, pure_vtx_size) == 0), + "cvGetGraphVtx returned wrong element" ); + + if( cvtest::randInt(rng) % 2 ) + { + vtx_degree = cvGraphVtxDegreeByPtr( graph, vtx ); + cvGraphRemoveVtxByPtr( graph, vtx ); + } + else + { + vtx_degree = cvGraphVtxDegree( graph, idx ); + cvGraphRemoveVtx( graph, idx ); + } + + cvTsSimpleGraphRemoveVertex( sgraph, idx ); + + CV_TS_SEQ_CHECK_CONDITION( vtx_degree == vtx_degree0, + "Number of incident edges is different in two graph representations" ); + + CV_TS_SEQ_CHECK_CONDITION( !CV_IS_SET_ELEM(vtx) && !cvGetGraphVtx(graph, idx) && + (vtx->flags & CV_SET_ELEM_IDX_MASK) == idx, + "cvGraphRemoveVtx[ByPtr] didn't release the vertex properly" ); + + CV_TS_SEQ_CHECK_CONDITION( graph->edges->active_count == prev_edge_count - vtx_degree, + "cvGraphRemoveVtx[ByPtr] didn't remove all the incident edges " + "(or removed some extra)" ); + + CV_TS_SEQ_CHECK_CONDITION( ((CvSetElem*)vtx)->next_free == first_free && + graph->free_elems == (CvSetElem*)vtx && + graph->active_count == prev_vtx_count - 1, + "The free node list has not been updated properly" ); + } + else if( op == 2 ) // add edge + { + int v_idx[2] = {0,0}, res = 0; + int v_prev_degree[2] = {0,0}, v_degree[2] = {0,0}; + + if( sgraph->vtx->free_count >= sgraph->vtx->max_count-1 ) + continue; + + for( i = 0, k = 0; i < 10; i++ ) + { + int j = cvtest::randInt(rng) % sgraph->vtx->count; + vtx_data = cvTsSimpleGraphFindVertex( sgraph, j ); + if( vtx_data ) + { + v_idx[k] = j; + if( k == 0 ) + k++; + else if( v_idx[0] != v_idx[1] && + cvTsSimpleGraphFindEdge( sgraph, v_idx[0], v_idx[1] ) == 0 ) + { + k++; + break; + } + } + } + + if( k < 2 ) + continue; + + first_free = graph->edges->free_elems; + next_free = first_free ? first_free->next_free : 0; + + edge = cvFindGraphEdge( graph, v_idx[0], v_idx[1] ); + CV_TS_SEQ_CHECK_CONDITION( edge == 0, "Extra edge appeared in the graph" ); + + if( pure_edge_size > 0 ) + { + elem_mat = Mat(1, graph->edges->elem_size, CV_8U, &elem_buf[0]); + cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) ); + } + edge = (CvGraphEdge*)&elem_buf[0]; + + // assign some default weight that is easy to check for + // consistensy, 'cause an edge weight is not stored + // in the simple graph + edge->weight = (float)(v_idx[0] + v_idx[1]); + pass_data = cvtest::randInt(rng) % 2; + + vtx = cvGetGraphVtx( graph, v_idx[0] ); + vtx2 = cvGetGraphVtx( graph, v_idx[1] ); + CV_TS_SEQ_CHECK_CONDITION( vtx != 0 && vtx2 != 0 && vtx->flags == v_idx[0] && + vtx2->flags == v_idx[1], "Some of the vertices are missing" ); + + if( cvtest::randInt(rng) % 2 ) + { + v_prev_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx ); + v_prev_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 ); + res = cvGraphAddEdgeByPtr(graph, vtx, vtx2, pass_data ? edge : 0, &edge2); + v_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx ); + v_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 ); + } + else + { + v_prev_degree[0] = cvGraphVtxDegree( graph, v_idx[0] ); + v_prev_degree[1] = cvGraphVtxDegree( graph, v_idx[1] ); + res = cvGraphAddEdge(graph, v_idx[0], v_idx[1], pass_data ? edge : 0, &edge2); + v_degree[0] = cvGraphVtxDegree( graph, v_idx[0] ); + v_degree[1] = cvGraphVtxDegree( graph, v_idx[1] ); + } + + //edge3 = (CvGraphEdge*)cvGetSetElem( graph->edges, idx ); + CV_TS_SEQ_CHECK_CONDITION( res == 1 && edge2 != 0 && CV_IS_SET_ELEM(edge2) && + ((edge2->vtx[0] == vtx && edge2->vtx[1] == vtx2) || + (!CV_IS_GRAPH_ORIENTED(graph) && edge2->vtx[0] == vtx2 && edge2->vtx[1] == vtx)) && + (!pass_data || pure_edge_size == 0 || memcmp( edge2 + 1, edge + 1, pure_edge_size ) == 0), + "The edge has been added incorrectly" ); + + if( !pass_data ) + { + if( pure_edge_size > 0 ) + memcpy( edge2 + 1, edge + 1, pure_edge_size ); + edge2->weight = edge->weight; + } + + CV_TS_SEQ_CHECK_CONDITION( v_degree[0] == v_prev_degree[0] + 1 && + v_degree[1] == v_prev_degree[1] + 1, + "The vertices lists have not been updated properly" ); + + cvTsSimpleGraphAddEdge( sgraph, v_idx[0], v_idx[1], edge + 1 ); + + CV_TS_SEQ_CHECK_CONDITION( (!first_free || first_free == (CvSetElem*)edge2) && + (!next_free || graph->edges->free_elems == next_free) && + graph->edges->active_count == prev_edge_count + 1, + "The free node list is modified incorrectly" ); + } + else if( op == 3 ) // find & remove edge + { + int v_idx[2] = {0,0}, by_ptr; + int v_prev_degree[2] = {0,0}, v_degree[2] = {0,0}; + + if( sgraph->vtx->free_count >= sgraph->vtx->max_count-1 ) + continue; + + edge_data = 0; + for( i = 0, k = 0; i < 10; i++ ) + { + int j = cvtest::randInt(rng) % sgraph->vtx->count; + vtx_data = cvTsSimpleGraphFindVertex( sgraph, j ); + if( vtx_data ) + { + v_idx[k] = j; + if( k == 0 ) + k++; + else + { + edge_data = cvTsSimpleGraphFindEdge( sgraph, v_idx[0], v_idx[1] ); + if( edge_data ) + { + k++; + break; + } + } + } + } + + if( k < 2 ) + continue; + + by_ptr = cvtest::randInt(rng) % 2; + first_free = graph->edges->free_elems; + + vtx = cvGetGraphVtx( graph, v_idx[0] ); + vtx2 = cvGetGraphVtx( graph, v_idx[1] ); + CV_TS_SEQ_CHECK_CONDITION( vtx != 0 && vtx2 != 0 && vtx->flags == v_idx[0] && + vtx2->flags == v_idx[1], "Some of the vertices are missing" ); + + if( by_ptr ) + { + edge = cvFindGraphEdgeByPtr( graph, vtx, vtx2 ); + v_prev_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx ); + v_prev_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 ); + } + else + { + edge = cvFindGraphEdge( graph, v_idx[0], v_idx[1] ); + v_prev_degree[0] = cvGraphVtxDegree( graph, v_idx[0] ); + v_prev_degree[1] = cvGraphVtxDegree( graph, v_idx[1] ); + } + + idx = edge->flags; + + CV_TS_SEQ_CHECK_CONDITION( edge != 0 && edge->weight == v_idx[0] + v_idx[1] && + ((edge->vtx[0] == vtx && edge->vtx[1] == vtx2) || + (!CV_IS_GRAPH_ORIENTED(graph) && edge->vtx[1] == vtx && edge->vtx[0] == vtx2)) && + (pure_edge_size == 0 || memcmp(edge + 1, edge_data, pure_edge_size) == 0), + "An edge is missing or incorrect" ); + + if( by_ptr ) + { + cvGraphRemoveEdgeByPtr( graph, vtx, vtx2 ); + edge2 = cvFindGraphEdgeByPtr( graph, vtx, vtx2 ); + v_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx ); + v_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 ); + } + else + { + cvGraphRemoveEdge(graph, v_idx[0], v_idx[1] ); + edge2 = cvFindGraphEdge( graph, v_idx[0], v_idx[1] ); + v_degree[0] = cvGraphVtxDegree( graph, v_idx[0] ); + v_degree[1] = cvGraphVtxDegree( graph, v_idx[1] ); + } + + CV_TS_SEQ_CHECK_CONDITION( !edge2 && !CV_IS_SET_ELEM(edge), + "The edge has not been removed from the edge set" ); + + CV_TS_SEQ_CHECK_CONDITION( v_degree[0] == v_prev_degree[0] - 1 && + v_degree[1] == v_prev_degree[1] - 1, + "The vertices lists have not been updated properly" ); + + cvTsSimpleGraphRemoveEdge( sgraph, v_idx[0], v_idx[1] ); + + CV_TS_SEQ_CHECK_CONDITION( graph->edges->free_elems == (CvSetElem*)edge && + graph->edges->free_elems->next_free == first_free && + graph->edges->active_count == prev_edge_count - 1, + "The free edge list has not been modified properly" ); + } + + //max_active_count = MAX( max_active_count, graph->active_count ); + //mean_active_count += graph->active_count; + + CV_TS_SEQ_CHECK_CONDITION( graph->active_count == sgraph->vtx->max_count - sgraph->vtx->free_count && + graph->total >= graph->active_count && + (graph->total == 0 || graph->total >= prev_vtx_total), + "The total number of graph vertices is not correct" ); + + CV_TS_SEQ_CHECK_CONDITION( graph->edges->total >= graph->edges->active_count && + (graph->edges->total == 0 || graph->edges->total >= prev_edge_total), + "The total number of graph vertices is not correct" ); + + // CvGraph and simple graph do not neccessary have the same "total" (active & free) number, + // so pass "graph->total" (or "graph->edges->total") to skip that check + test_seq_block_consistence( struct_idx, (CvSeq*)graph, graph->total ); + test_seq_block_consistence( struct_idx, (CvSeq*)graph->edges, graph->edges->total ); + update_progressbar(); + } + + return 0; +} + + +void Core_GraphTest::run( int ) +{ + try + { + RNG& rng = ts->get_rng(); + int i, k; + double t; + + clear(); + test_progress = -1; + + simple_struct.resize(struct_count, 0); + cxcore_struct.resize(struct_count, 0); + + for( gen = 0; gen < generations; gen++ ) + { + struct_idx = iter = -1; + t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size; + int block_size = cvRound( exp(t * CV_LOG2) ); + block_size = MAX(block_size, (int)(sizeof(CvGraph) + sizeof(CvMemBlock) + sizeof(CvSeqBlock))); + + storage = cvCreateMemStorage(block_size); + + for( i = 0; i < struct_count; i++ ) + { + int pure_elem_size[2], elem_size[2]; + int is_oriented = (gen + i) % 2; + for( k = 0; k < 2; k++ ) + { + t = cvtest::randReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size; + int pe = cvRound( exp(t * CV_LOG2) ) - 1; // pure_elem_size==0 does also make sense + int delta = k == 0 ? sizeof(CvGraphVtx) : sizeof(CvGraphEdge); + int e = pe + delta; + e = (e + sizeof(size_t) - 1) & ~(sizeof(size_t)-1); + e = MIN( e, (int)(storage->block_size - sizeof(CvMemBlock) - + sizeof(CvSeqBlock) - sizeof(void*)) ); + pe = MIN(pe, e - delta); + pure_elem_size[k] = pe; + elem_size[k] = e; + } + + cvTsReleaseSimpleGraph( (CvTsSimpleGraph**)&simple_struct[i] ); + simple_struct[i] = cvTsCreateSimpleGraph( max_struct_size/4, pure_elem_size[0], + pure_elem_size[1], is_oriented ); + cxcore_struct[i] = cvCreateGraph( is_oriented ? CV_ORIENTED_GRAPH : CV_GRAPH, + sizeof(CvGraph), elem_size[0], elem_size[1], + storage ); + } + + if( test_graph_ops( iterations*10 ) < 0 ) + return; + + storage.release(); + } + } + catch(int) + { + } +} + + +//////////// graph scan test ////////////// + +class Core_GraphScanTest : public Core_DynStructBaseTest +{ +public: + Core_GraphScanTest(); + void run( int ); + +protected: + //int test_seq_block_consistence( int struct_idx ); + int create_random_graph( int ); +}; + + +Core_GraphScanTest::Core_GraphScanTest() +{ + iterations = 100; + struct_count = 1; +} + + +int Core_GraphScanTest::create_random_graph( int _struct_idx ) +{ + RNG& rng = ts->get_rng(); + int is_oriented = cvtest::randInt(rng) % 2; + int i, vtx_count = cvtest::randInt(rng) % max_struct_size; + int edge_count = cvtest::randInt(rng) % MAX(vtx_count*20, 1); + CvGraph* graph; + + struct_idx = _struct_idx; + cxcore_struct[_struct_idx] = graph = + cvCreateGraph(is_oriented ? CV_ORIENTED_GRAPH : CV_GRAPH, + sizeof(CvGraph), sizeof(CvGraphVtx), + sizeof(CvGraphEdge), storage ); + + for( i = 0; i < vtx_count; i++ ) + cvGraphAddVtx( graph ); + + assert( graph->active_count == vtx_count ); + + for( i = 0; i < edge_count; i++ ) + { + int j = cvtest::randInt(rng) % vtx_count; + int k = cvtest::randInt(rng) % vtx_count; + + if( j != k ) + cvGraphAddEdge( graph, j, k ); + } + + assert( graph->active_count == vtx_count && graph->edges->active_count <= edge_count ); + + return 0; +} + + +void Core_GraphScanTest::run( int ) +{ + CvGraphScanner* scanner = 0; + try + { + RNG& rng = ts->get_rng(); + vector vtx_mask, edge_mask; + double t; + int i; + + clear(); + test_progress = -1; + + cxcore_struct.resize(struct_count, 0); + + for( gen = 0; gen < generations; gen++ ) + { + struct_idx = iter = -1; + t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size; + int storage_blocksize = cvRound( exp(t * CV_LOG2) ); + storage_blocksize = MAX(storage_blocksize, (int)(sizeof(CvGraph) + sizeof(CvMemBlock) + sizeof(CvSeqBlock))); + storage_blocksize = MAX(storage_blocksize, (int)(sizeof(CvGraphEdge) + sizeof(CvMemBlock) + sizeof(CvSeqBlock))); + storage_blocksize = MAX(storage_blocksize, (int)(sizeof(CvGraphVtx) + sizeof(CvMemBlock) + sizeof(CvSeqBlock))); + storage = cvCreateMemStorage(storage_blocksize); + + if( gen == 0 ) + { + // special regression test for one sample graph. + // !!! ATTENTION !!! The test relies on the particular order of the inserted edges + // (LIFO: the edge inserted last goes first in the list of incident edges). + // if it is changed, the test will have to be modified. + + int vtx_count = -1, edge_count = 0, edges[][3] = + { + {0,4,'f'}, {0,1,'t'}, {1,4,'t'}, {1,2,'t'}, {2,3,'t'}, {4,3,'c'}, {3,1,'b'}, + {5,7,'t'}, {7,5,'b'}, {5,6,'t'}, {6,0,'c'}, {7,6,'c'}, {6,4,'c'}, {-1,-1,0} + }; + + CvGraph* graph = cvCreateGraph( CV_ORIENTED_GRAPH, sizeof(CvGraph), + sizeof(CvGraphVtx), sizeof(CvGraphEdge), storage ); + + for( i = 0; edges[i][0] >= 0; i++ ) + { + vtx_count = MAX( vtx_count, edges[i][0] ); + vtx_count = MAX( vtx_count, edges[i][1] ); + } + vtx_count++; + + for( i = 0; i < vtx_count; i++ ) + cvGraphAddVtx( graph ); + + for( i = 0; edges[i][0] >= 0; i++ ) + { + CvGraphEdge* edge; + cvGraphAddEdge( graph, edges[i][0], edges[i][1], 0, &edge ); + edge->weight = (float)edges[i][2]; + } + + edge_count = i; + scanner = cvCreateGraphScanner( graph, 0, CV_GRAPH_ALL_ITEMS ); + + for(;;) + { + int code, a = -1, b = -1; + const char* event = ""; + code = cvNextGraphItem( scanner ); + + switch( code ) + { + case CV_GRAPH_VERTEX: + event = "Vertex"; + vtx_count--; + a = cvGraphVtxIdx( graph, scanner->vtx ); + break; + case CV_GRAPH_TREE_EDGE: + event = "Tree Edge"; + edge_count--; + CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'t', + "Invalid edge type" ); + a = cvGraphVtxIdx( graph, scanner->vtx ); + b = cvGraphVtxIdx( graph, scanner->dst ); + break; + case CV_GRAPH_BACK_EDGE: + event = "Back Edge"; + edge_count--; + CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'b', + "Invalid edge type" ); + a = cvGraphVtxIdx( graph, scanner->vtx ); + b = cvGraphVtxIdx( graph, scanner->dst ); + break; + case CV_GRAPH_CROSS_EDGE: + event = "Cross Edge"; + edge_count--; + CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'c', + "Invalid edge type" ); + a = cvGraphVtxIdx( graph, scanner->vtx ); + b = cvGraphVtxIdx( graph, scanner->dst ); + break; + case CV_GRAPH_FORWARD_EDGE: + event = "Forward Edge"; + edge_count--; + CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'f', + "Invalid edge type" ); + a = cvGraphVtxIdx( graph, scanner->vtx ); + b = cvGraphVtxIdx( graph, scanner->dst ); + break; + case CV_GRAPH_BACKTRACKING: + event = "Backtracking"; + a = cvGraphVtxIdx( graph, scanner->vtx ); + break; + case CV_GRAPH_NEW_TREE: + event = "New search tree"; + break; + case CV_GRAPH_OVER: + event = "End of procedure"; + break; + default: + CV_TS_SEQ_CHECK_CONDITION( 0, "Invalid code appeared during graph scan" ); + } + + ts->printf( cvtest::TS::LOG, "%s", event ); + if( a >= 0 ) + { + if( b >= 0 ) + ts->printf( cvtest::TS::LOG, ": (%d,%d)", a, b ); + else + ts->printf( cvtest::TS::LOG, ": %d", a ); + } + + ts->printf( cvtest::TS::LOG, "\n" ); + + if( code < 0 ) + break; + } + + CV_TS_SEQ_CHECK_CONDITION( vtx_count == 0 && edge_count == 0, + "Not every vertex/edge has been visited" ); + update_progressbar(); + } + + // for a random graph the test just checks that every graph vertex and + // every edge is vitisted during the scan + for( iter = 0; iter < iterations; iter++ ) + { + create_random_graph(0); + CvGraph* graph = (CvGraph*)cxcore_struct[0]; + + // iterate twice to check that scanner doesn't damage the graph + for( i = 0; i < 2; i++ ) + { + CvGraphVtx* start_vtx = cvtest::randInt(rng) % 2 || graph->active_count == 0 ? 0 : + cvGetGraphVtx( graph, cvtest::randInt(rng) % graph->active_count ); + + scanner = cvCreateGraphScanner( graph, start_vtx, CV_GRAPH_ALL_ITEMS ); + + vtx_mask.resize(0); + vtx_mask.resize(graph->active_count, 0); + edge_mask.resize(0); + edge_mask.resize(graph->edges->active_count, 0); + + for(;;) + { + int code = cvNextGraphItem( scanner ); + + if( code == CV_GRAPH_OVER ) + break; + else if( code & CV_GRAPH_ANY_EDGE ) + { + int edge_idx = scanner->edge->flags & CV_SET_ELEM_IDX_MASK; + + CV_TS_SEQ_CHECK_CONDITION( edge_idx < graph->edges->active_count && + edge_mask[edge_idx] == 0, + "The edge is not found or visited for the second time" ); + edge_mask[edge_idx] = 1; + } + else if( code & CV_GRAPH_VERTEX ) + { + int vtx_idx = scanner->vtx->flags & CV_SET_ELEM_IDX_MASK; + + CV_TS_SEQ_CHECK_CONDITION( vtx_idx < graph->active_count && + vtx_mask[vtx_idx] == 0, + "The vtx is not found or visited for the second time" ); + vtx_mask[vtx_idx] = 1; + } + } + + cvReleaseGraphScanner( &scanner ); + + CV_TS_SEQ_CHECK_CONDITION( cvtest::norm(Mat(vtx_mask),CV_L1) == graph->active_count && + cvtest::norm(Mat(edge_mask),CV_L1) == graph->edges->active_count, + "Some vertices or edges have not been visited" ); + update_progressbar(); + } + cvClearMemStorage( storage ); + } + + storage.release(); + } + } + catch(int) + { + } + + cvReleaseGraphScanner( &scanner ); +} + + +TEST(Core_DS_Seq, basic_operations) { Core_SeqBaseTest test; test.safe_run(); } +TEST(Core_DS_Seq, sort_invert) { Core_SeqSortInvTest test; test.safe_run(); } +TEST(Core_DS_Set, basic_operations) { Core_SetTest test; test.safe_run(); } +TEST(Core_DS_Graph, basic_operations) { Core_GraphTest test; test.safe_run(); } +TEST(Core_DS_Graph, scan) { Core_GraphScanTest test; test.safe_run(); } + + diff --git a/core/test/test_dxt.cpp b/core/test/test_dxt.cpp new file mode 100644 index 0000000..fd3fdd6 --- /dev/null +++ b/core/test/test_dxt.cpp @@ -0,0 +1,830 @@ +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +namespace cvtest +{ + +static Mat initDFTWave( int n, bool inv ) +{ + int i; + double angle = (inv ? 1 : -1)*CV_PI*2/n; + Complexd wi, w1; + Mat wave(1, n, CV_64FC2); + Complexd* w = wave.ptr(); + + w1.re = cos(angle); + w1.im = sin(angle); + w[0].re = wi.re = 1.; + w[0].im = wi.im = 0.; + + for( i = 1; i < n; i++ ) + { + double t = wi.re*w1.re - wi.im*w1.im; + wi.im = wi.re*w1.im + wi.im*w1.re; + wi.re = t; + w[i] = wi; + } + + return wave; +} + + +static void DFT_1D( const Mat& _src, Mat& _dst, int flags, const Mat& _wave=Mat()) +{ + _dst.create(_src.size(), _src.type()); + int i, j, k, n = _dst.cols + _dst.rows - 1; + Mat wave = _wave; + double scale = (flags & DFT_SCALE) ? 1./n : 1.; + size_t esz = _src.elemSize(); + size_t srcstep = esz, dststep = esz; + const uchar* src0 = _src.data; + uchar* dst0 = _dst.data; + + CV_Assert( _src.cols + _src.rows - 1 == n ); + + if( wave.empty() ) + wave = initDFTWave( n, (flags & DFT_INVERSE) != 0 ); + + const Complexd* w = wave.ptr(); + if( !_src.isContinuous() ) + srcstep = _src.step; + if( !_dst.isContinuous() ) + dststep = _dst.step; + + if( _src.type() == CV_32FC2 ) + { + for( i = 0; i < n; i++ ) + { + Complexf* dst = (Complexf*)(dst0 + i*dststep); + Complexd sum(0,0); + int delta = i; + k = 0; + + for( j = 0; j < n; j++ ) + { + const Complexf* src = (const Complexf*)(src0 + j*srcstep); + sum.re += src->re*w[k].re - src->im*w[k].im; + sum.im += src->re*w[k].im + src->im*w[k].re; + k += delta; + k -= (k >= n ? n : 0); + } + + dst->re = (float)(sum.re*scale); + dst->im = (float)(sum.im*scale); + } + } + else if( _src.type() == CV_64FC2 ) + { + for( i = 0; i < n; i++ ) + { + Complexd* dst = (Complexd*)(dst0 + i*dststep); + Complexd sum(0,0); + int delta = i; + k = 0; + + for( j = 0; j < n; j++ ) + { + const Complexd* src = (const Complexd*)(src0 + j*srcstep); + sum.re += src->re*w[k].re - src->im*w[k].im; + sum.im += src->re*w[k].im + src->im*w[k].re; + k += delta; + k -= (k >= n ? n : 0); + } + + dst->re = sum.re*scale; + dst->im = sum.im*scale; + } + } + else + CV_Error(CV_StsUnsupportedFormat, ""); +} + + +static void DFT_2D( const Mat& src, Mat& dst, int flags ) +{ + const int cn = 2; + int i; + dst.create(src.size(), src.type()); + Mat tmp( src.cols, src.rows, src.type()); + Mat wave = initDFTWave( dst.cols, (flags & DFT_INVERSE) != 0 ); + + // 1. row-wise transform + for( i = 0; i < dst.rows; i++ ) + { + Mat srci = src.row(i).reshape(cn, src.cols), dsti = tmp.col(i); + DFT_1D(srci, dsti, flags, wave ); + } + + if( (flags & DFT_ROWS) == 0 ) + { + if( dst.cols != dst.rows ) + wave = initDFTWave( dst.rows, (flags & DFT_INVERSE) != 0 ); + + // 2. column-wise transform + for( i = 0; i < dst.cols; i++ ) + { + Mat srci = tmp.row(i).reshape(cn, tmp.cols), dsti = dst.col(i); + DFT_1D(srci, dsti, flags, wave ); + } + } + else + cvtest::transpose(tmp, dst); +} + + +static Mat initDCTWave( int n, bool inv ) +{ + int i, k; + double angle = CV_PI*0.5/n; + Mat wave(n, n, CV_64F); + + double scale = sqrt(1./n); + for( k = 0; k < n; k++ ) + wave.at(0, k) = scale; + scale *= sqrt(2.); + for( i = 1; i < n; i++ ) + for( k = 0; k < n; k++ ) + wave.at(i, k) = scale*cos( angle*i*(2*k + 1) ); + + if( inv ) + cv::transpose( wave, wave ); + + return wave; +} + + +static void DCT_1D( const Mat& _src, Mat& _dst, int flags, const Mat& _wave=Mat() ) +{ + _dst.create( _src.size(), _src.type() ); + int i, j, n = _dst.cols + _dst.rows - 1; + Mat wave = _wave; + int srcstep = 1, dststep = 1; + double* w; + + CV_Assert( _src.cols + _src.rows - 1 == n); + + if( wave.empty() ) + wave = initDCTWave( n, (flags & DFT_INVERSE) != 0 ); + w = wave.ptr(); + + if( !_src.isContinuous() ) + srcstep = (int)(_src.step/_src.elemSize()); + if( !_dst.isContinuous() ) + dststep = (int)(_dst.step/_dst.elemSize()); + + if( _src.type() == CV_32FC1 ) + { + float *dst = _dst.ptr(); + + for( i = 0; i < n; i++, dst += dststep ) + { + const float* src = _src.ptr(); + double sum = 0; + + for( j = 0; j < n; j++, src += srcstep ) + sum += src[0]*w[j]; + w += n; + dst[0] = (float)sum; + } + } + else if( _src.type() == CV_64FC1 ) + { + double *dst = _dst.ptr(); + + for( i = 0; i < n; i++, dst += dststep ) + { + const double* src = _src.ptr(); + double sum = 0; + + for( j = 0; j < n; j++, src += srcstep ) + sum += src[0]*w[j]; + w += n; + dst[0] = sum; + } + } + else + assert(0); +} + + +static void DCT_2D( const Mat& src, Mat& dst, int flags ) +{ + const int cn = 1; + int i; + dst.create( src.size(), src.type() ); + Mat tmp(dst.cols, dst.rows, dst.type() ); + Mat wave = initDCTWave( dst.cols, (flags & DCT_INVERSE) != 0 ); + + // 1. row-wise transform + for( i = 0; i < dst.rows; i++ ) + { + Mat srci = src.row(i).reshape(cn, src.cols); + Mat dsti = tmp.col(i); + DCT_1D(srci, dsti, flags, wave); + } + + if( (flags & DCT_ROWS) == 0 ) + { + if( dst.cols != dst.rows ) + wave = initDCTWave( dst.rows, (flags & DCT_INVERSE) != 0 ); + + // 2. column-wise transform + for( i = 0; i < dst.cols; i++ ) + { + Mat srci = tmp.row(i).reshape(cn, tmp.cols); + Mat dsti = dst.col(i); + DCT_1D( srci, dsti, flags, wave ); + } + } + else + cvtest::transpose( tmp, dst ); +} + + +static void convertFromCCS( const Mat& _src0, const Mat& _src1, Mat& _dst, int flags ) +{ + if( _dst.rows > 1 && (_dst.cols > 1 || (flags & DFT_ROWS)) ) + { + int i, count = _dst.rows, len = _dst.cols; + bool is2d = (flags & DFT_ROWS) == 0; + Mat src0row, src1row, dstrow; + for( i = 0; i < count; i++ ) + { + int j = !is2d || i == 0 ? i : count - i; + src0row = _src0.row(i); + src1row = _src1.row(j); + dstrow = _dst.row(i); + convertFromCCS( src0row, src1row, dstrow, 0 ); + } + + if( is2d ) + { + src0row = _src0.col(0); + dstrow = _dst.col(0); + convertFromCCS( src0row, src0row, dstrow, 0 ); + if( (len & 1) == 0 ) + { + src0row = _src0.col(_src0.cols - 1); + dstrow = _dst.col(len/2); + convertFromCCS( src0row, src0row, dstrow, 0 ); + } + } + } + else + { + int i, n = _dst.cols + _dst.rows - 1, n2 = (n+1) >> 1; + int cn = _src0.channels(); + int srcstep = cn, dststep = 1; + + if( !_dst.isContinuous() ) + dststep = (int)(_dst.step/_dst.elemSize()); + + if( !_src0.isContinuous() ) + srcstep = (int)(_src0.step/_src0.elemSize1()); + + if( _dst.depth() == CV_32F ) + { + Complexf* dst = _dst.ptr(); + const float* src0 = _src0.ptr(); + const float* src1 = _src1.ptr(); + int delta0, delta1; + + dst->re = src0[0]; + dst->im = 0; + + if( (n & 1) == 0 ) + { + dst[n2*dststep].re = src0[(cn == 1 ? n-1 : n2)*srcstep]; + dst[n2*dststep].im = 0; + } + + delta0 = srcstep; + delta1 = delta0 + (cn == 1 ? srcstep : 1); + if( cn == 1 ) + srcstep *= 2; + + for( i = 1; i < n2; i++, delta0 += srcstep, delta1 += srcstep ) + { + float t0 = src0[delta0]; + float t1 = src0[delta1]; + + dst[i*dststep].re = t0; + dst[i*dststep].im = t1; + + t0 = src1[delta0]; + t1 = -src1[delta1]; + + dst[(n-i)*dststep].re = t0; + dst[(n-i)*dststep].im = t1; + } + } + else + { + Complexd* dst = _dst.ptr(); + const double* src0 = _src0.ptr(); + const double* src1 = _src1.ptr(); + int delta0, delta1; + + dst->re = src0[0]; + dst->im = 0; + + if( (n & 1) == 0 ) + { + dst[n2*dststep].re = src0[(cn == 1 ? n-1 : n2)*srcstep]; + dst[n2*dststep].im = 0; + } + + delta0 = srcstep; + delta1 = delta0 + (cn == 1 ? srcstep : 1); + if( cn == 1 ) + srcstep *= 2; + + for( i = 1; i < n2; i++, delta0 += srcstep, delta1 += srcstep ) + { + double t0 = src0[delta0]; + double t1 = src0[delta1]; + + dst[i*dststep].re = t0; + dst[i*dststep].im = t1; + + t0 = src1[delta0]; + t1 = -src1[delta1]; + + dst[(n-i)*dststep].re = t0; + dst[(n-i)*dststep].im = t1; + } + } + } +} + + +static void fixCCS( Mat& mat, int cols, int flags ) +{ + int i, rows = mat.rows; + int rows2 = (flags & DFT_ROWS) ? rows : rows/2 + 1, cols2 = cols/2 + 1; + + CV_Assert( cols2 == mat.cols ); + + if( mat.type() == CV_32FC2 ) + { + for( i = 0; i < rows2; i++ ) + { + Complexf* row = mat.ptr(i); + if( (flags & DFT_ROWS) || i == 0 || (i == rows2 - 1 && rows % 2 == 0) ) + { + row[0].im = 0; + if( cols % 2 == 0 ) + row[cols2-1].im = 0; + } + else + { + Complexf* row2 = mat.ptr(rows-i); + row2[0].re = row[0].re; + row2[0].im = -row[0].im; + + if( cols % 2 == 0 ) + { + row2[cols2-1].re = row[cols2-1].re; + row2[cols2-1].im = -row[cols2-1].im; + } + } + } + } + else if( mat.type() == CV_64FC2 ) + { + for( i = 0; i < rows2; i++ ) + { + Complexd* row = mat.ptr(i); + if( (flags & DFT_ROWS) || i == 0 || (i == rows2 - 1 && rows % 2 == 0) ) + { + row[0].im = 0; + if( cols % 2 == 0 ) + row[cols2-1].im = 0; + } + else + { + Complexd* row2 = mat.ptr(rows-i); + row2[0].re = row[0].re; + row2[0].im = -row[0].im; + + if( cols % 2 == 0 ) + { + row2[cols2-1].re = row[cols2-1].re; + row2[cols2-1].im = -row[cols2-1].im; + } + } + } + } +} + + +static void mulComplex( const Mat& src1, const Mat& src2, Mat& dst, int flags ) +{ + dst.create(src1.rows, src1.cols, src1.type()); + int i, j, depth = src1.depth(), cols = src1.cols*2; + + CV_Assert( src1.size == src2.size && src1.type() == src2.type() && + (src1.type() == CV_32FC2 || src1.type() == CV_64FC2) ); + + for( i = 0; i < dst.rows; i++ ) + { + if( depth == CV_32F ) + { + const float* a = src1.ptr(i); + const float* b = src2.ptr(i); + float* c = dst.ptr(i); + + if( !(flags & CV_DXT_MUL_CONJ) ) + for( j = 0; j < cols; j += 2 ) + { + double re = (double)a[j]*b[j] - (double)a[j+1]*b[j+1]; + double im = (double)a[j+1]*b[j] + (double)a[j]*b[j+1]; + + c[j] = (float)re; + c[j+1] = (float)im; + } + else + for( j = 0; j < cols; j += 2 ) + { + double re = (double)a[j]*b[j] + (double)a[j+1]*b[j+1]; + double im = (double)a[j+1]*b[j] - (double)a[j]*b[j+1]; + + c[j] = (float)re; + c[j+1] = (float)im; + } + } + else + { + const double* a = src1.ptr(i); + const double* b = src2.ptr(i); + double* c = dst.ptr(i); + + if( !(flags & CV_DXT_MUL_CONJ) ) + for( j = 0; j < cols; j += 2 ) + { + double re = a[j]*b[j] - a[j+1]*b[j+1]; + double im = a[j+1]*b[j] + a[j]*b[j+1]; + + c[j] = re; + c[j+1] = im; + } + else + for( j = 0; j < cols; j += 2 ) + { + double re = a[j]*b[j] + a[j+1]*b[j+1]; + double im = a[j+1]*b[j] - a[j]*b[j+1]; + + c[j] = re; + c[j+1] = im; + } + } + } +} + +} + + +class CxCore_DXTBaseTest : public cvtest::ArrayTest +{ +public: + typedef cvtest::ArrayTest Base; + CxCore_DXTBaseTest( bool _allow_complex=false, bool _allow_odd=false, + bool _spectrum_mode=false ); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + int prepare_test_case( int test_case_idx ); + double get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ); + int flags; // transformation flags + bool allow_complex; // whether input/output may be complex or not: + // true for DFT and MulSpectrums, false for DCT + bool allow_odd; // whether input/output may be have odd (!=1) dimensions: + // true for DFT and MulSpectrums, false for DCT + bool spectrum_mode; // (2 complex/ccs inputs, 1 complex/ccs output): + // true for MulSpectrums, false for DFT and DCT + bool inplace; // inplace operation (set for each individual test case) + bool temp_dst; // use temporary destination (for real->ccs DFT and ccs MulSpectrums) +}; + + +CxCore_DXTBaseTest::CxCore_DXTBaseTest( bool _allow_complex, bool _allow_odd, bool _spectrum_mode ) +: Base(), flags(0), allow_complex(_allow_complex), allow_odd(_allow_odd), +spectrum_mode(_spectrum_mode), inplace(false), temp_dst(false) +{ + test_array[INPUT].push_back(NULL); + if( spectrum_mode ) + test_array[INPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + test_array[TEMP].push_back(NULL); + test_array[TEMP].push_back(NULL); + + max_log_array_size = 9; + element_wise_relative_error = spectrum_mode; +} + + +void CxCore_DXTBaseTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, + vector >& types ) +{ + RNG& rng = ts->get_rng(); + int bits = cvtest::randInt(rng); + int depth = cvtest::randInt(rng)%2 + CV_32F; + int cn = !allow_complex || !(bits & 256) ? 1 : 2; + Size size; + Base::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + flags = bits & (CV_DXT_INVERSE | CV_DXT_SCALE | CV_DXT_ROWS | CV_DXT_MUL_CONJ); + if( spectrum_mode ) + flags &= ~CV_DXT_INVERSE; + types[TEMP][0] = types[TEMP][1] = types[INPUT][0] = + types[OUTPUT][0] = CV_MAKETYPE(depth, cn); + size = sizes[INPUT][0]; + + temp_dst = false; + + if( flags & CV_DXT_ROWS && (bits&1024) ) + { + if( bits&16 ) + size.width = 1; + else + size.height = 1; + flags &= ~CV_DXT_ROWS; + } + + const int P2_MIN_SIZE = 32; + if( ((bits >> 10) & 1) == 0 ) + { + size.width = (size.width / P2_MIN_SIZE)*P2_MIN_SIZE; + size.width = MAX(size.width, 1); + size.height = (size.height / P2_MIN_SIZE)*P2_MIN_SIZE; + size.height = MAX(size.height, 1); + } + + if( !allow_odd ) + { + if( size.width > 1 && (size.width&1) != 0 ) + size.width = (size.width + 1) & -2; + + if( size.height > 1 && (size.height&1) != 0 && !(flags & CV_DXT_ROWS) ) + size.height = (size.height + 1) & -2; + } + + sizes[INPUT][0] = sizes[OUTPUT][0] = size; + sizes[TEMP][0] = sizes[TEMP][1] = cvSize(0,0); + + if( spectrum_mode ) + { + if( cn == 1 ) + { + types[OUTPUT][0] = depth + 8; + sizes[TEMP][0] = size; + } + sizes[INPUT][0] = sizes[INPUT][1] = size; + types[INPUT][1] = types[INPUT][0]; + } + else if( /*(cn == 2 && (bits&32)) ||*/ (cn == 1 && allow_complex) ) + { + types[TEMP][0] = depth + 8; // CV_??FC2 + sizes[TEMP][0] = size; + size = cvSize(size.width/2+1, size.height); + + if( flags & CV_DXT_INVERSE ) + { + if( cn == 2 ) + { + types[OUTPUT][0] = depth; + sizes[INPUT][0] = size; + } + types[TEMP][1] = types[TEMP][0]; + sizes[TEMP][1] = sizes[TEMP][0]; + } + else + { + if( allow_complex ) + types[OUTPUT][0] = depth + 8; + + if( cn == 2 ) + { + types[INPUT][0] = depth; + types[TEMP][1] = types[TEMP][0]; + sizes[TEMP][1] = size; + } + else + { + types[TEMP][1] = depth; + sizes[TEMP][1] = sizes[TEMP][0]; + } + temp_dst = true; + } + } + + inplace = false; + if( spectrum_mode || + (!temp_dst && types[INPUT][0] == types[OUTPUT][0]) || + (temp_dst && types[INPUT][0] == types[TEMP][1]) ) + inplace = (bits & 64) != 0; + + types[REF_OUTPUT][0] = types[OUTPUT][0]; + sizes[REF_OUTPUT][0] = sizes[OUTPUT][0]; +} + + +double CxCore_DXTBaseTest::get_success_error_level( int test_case_idx, int i, int j ) +{ + return Base::get_success_error_level( test_case_idx, i, j ); +} + + +int CxCore_DXTBaseTest::prepare_test_case( int test_case_idx ) +{ + int code = Base::prepare_test_case( test_case_idx ); + if( code > 0 ) + { + int in_type = test_mat[INPUT][0].type(); + int out_type = test_mat[OUTPUT][0].type(); + + if( CV_MAT_CN(in_type) == 2 && CV_MAT_CN(out_type) == 1 ) + cvtest::fixCCS( test_mat[INPUT][0], test_mat[OUTPUT][0].cols, flags ); + + if( inplace ) + cvtest::copy( test_mat[INPUT][test_case_idx & (int)spectrum_mode], + temp_dst ? test_mat[TEMP][1] : + in_type == out_type ? test_mat[OUTPUT][0] : + test_mat[TEMP][0] ); + } + + return code; +} + + +////////////////////// FFT //////////////////////// +class CxCore_DFTTest : public CxCore_DXTBaseTest +{ +public: + CxCore_DFTTest(); +protected: + void run_func(); + void prepare_to_validation( int test_case_idx ); +}; + + +CxCore_DFTTest::CxCore_DFTTest() : CxCore_DXTBaseTest( true, true, false ) +{ +} + + +void CxCore_DFTTest::run_func() +{ + Mat& dst = temp_dst ? test_mat[TEMP][1] : test_mat[OUTPUT][0]; + const Mat& src = inplace ? dst : test_mat[INPUT][0]; + + if(!(flags & CV_DXT_INVERSE)) + cv::dft( src, dst, flags ); + else + cv::idft(src, dst, flags & ~CV_DXT_INVERSE); +} + + +void CxCore_DFTTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat& src = test_mat[INPUT][0]; + Mat& dst = test_mat[REF_OUTPUT][0]; + Mat* tmp_src = &src; + Mat* tmp_dst = &dst; + int src_cn = src.channels(); + int dst_cn = dst.channels(); + + if( src_cn != 2 || dst_cn != 2 ) + { + tmp_src = &test_mat[TEMP][0]; + + if( !(flags & CV_DXT_INVERSE ) ) + { + Mat& cvdft_dst = test_mat[TEMP][1]; + cvtest::convertFromCCS( cvdft_dst, cvdft_dst, + test_mat[OUTPUT][0], flags ); + *tmp_src = Scalar::all(0); + cvtest::insert( src, *tmp_src, 0 ); + } + else + { + cvtest::convertFromCCS( src, src, *tmp_src, flags ); + tmp_dst = &test_mat[TEMP][1]; + } + } + + if( src.rows == 1 || (src.cols == 1 && !(flags & CV_DXT_ROWS)) ) + cvtest::DFT_1D( *tmp_src, *tmp_dst, flags ); + else + cvtest::DFT_2D( *tmp_src, *tmp_dst, flags ); + + if( tmp_dst != &dst ) + cvtest::extract( *tmp_dst, dst, 0 ); +} + +////////////////////// DCT //////////////////////// +class CxCore_DCTTest : public CxCore_DXTBaseTest +{ +public: + CxCore_DCTTest(); +protected: + void run_func(); + void prepare_to_validation( int test_case_idx ); +}; + + +CxCore_DCTTest::CxCore_DCTTest() : CxCore_DXTBaseTest( false, false, false ) +{ +} + + +void CxCore_DCTTest::run_func() +{ + Mat& dst = test_mat[OUTPUT][0]; + const Mat& src = inplace ? dst : test_mat[INPUT][0]; + + if(!(flags & CV_DXT_INVERSE)) + cv::dct( src, dst, flags ); + else + cv::idct( src, dst, flags & ~CV_DXT_INVERSE); +} + + +void CxCore_DCTTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + const Mat& src = test_mat[INPUT][0]; + Mat& dst = test_mat[REF_OUTPUT][0]; + + if( src.rows == 1 || (src.cols == 1 && !(flags & CV_DXT_ROWS)) ) + cvtest::DCT_1D( src, dst, flags ); + else + cvtest::DCT_2D( src, dst, flags ); +} + + +////////////////////// MulSpectrums //////////////////////// +class CxCore_MulSpectrumsTest : public CxCore_DXTBaseTest +{ +public: + CxCore_MulSpectrumsTest(); +protected: + void run_func(); + void prepare_to_validation( int test_case_idx ); +}; + + +CxCore_MulSpectrumsTest::CxCore_MulSpectrumsTest() : CxCore_DXTBaseTest( true, true, true ) +{ +} + + +void CxCore_MulSpectrumsTest::run_func() +{ + Mat& dst = !test_mat[TEMP].empty() && !test_mat[TEMP][0].empty() ? + test_mat[TEMP][0] : test_mat[OUTPUT][0]; + const Mat* src1 = &test_mat[INPUT][0], *src2 = &test_mat[INPUT][1]; + + if( inplace ) + { + if( ts->get_current_test_info()->test_case_idx & 1 ) + src2 = &dst; + else + src1 = &dst; + } + + cv::mulSpectrums( *src1, *src2, dst, flags, (flags & CV_DXT_MUL_CONJ) != 0 ); +} + + +void CxCore_MulSpectrumsTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat* src1 = &test_mat[INPUT][0]; + Mat* src2 = &test_mat[INPUT][1]; + Mat& dst = test_mat[OUTPUT][0]; + Mat& dst0 = test_mat[REF_OUTPUT][0]; + int cn = src1->channels(); + + if( cn == 1 ) + { + cvtest::convertFromCCS( *src1, *src1, dst, flags ); + cvtest::convertFromCCS( *src2, *src2, dst0, flags ); + src1 = &dst; + src2 = &dst0; + } + + cvtest::mulComplex( *src1, *src2, dst0, flags ); + if( cn == 1 ) + { + Mat& temp = test_mat[TEMP][0]; + cvtest::convertFromCCS( temp, temp, dst, flags ); + } +} + +TEST(Core_DCT, accuracy) { CxCore_DCTTest test; test.safe_run(); } +TEST(Core_DFT, accuracy) { CxCore_DFTTest test; test.safe_run(); } +TEST(Core_MulSpectrums, accuracy) { CxCore_MulSpectrumsTest test; test.safe_run(); } + + diff --git a/core/test/test_eigen.cpp b/core/test/test_eigen.cpp new file mode 100644 index 0000000..7f0ba00 --- /dev/null +++ b/core/test/test_eigen.cpp @@ -0,0 +1,411 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" +#include + +using namespace cv; +using namespace std; + +#define sign(a) a > 0 ? 1 : a == 0 ? 0 : -1 + +#define CORE_EIGEN_ERROR_COUNT 1 +#define CORE_EIGEN_ERROR_SIZE 2 +#define CORE_EIGEN_ERROR_DIFF 3 +#define CORE_EIGEN_ERROR_ORTHO 4 +#define CORE_EIGEN_ERROR_ORDER 5 + +#define MESSAGE_ERROR_COUNT "Matrix of eigen values must have the same rows as source matrix and 1 column." +#define MESSAGE_ERROR_SIZE "Source matrix and matrix of eigen vectors must have the same sizes." +#define MESSAGE_ERROR_DIFF_1 "Accurasy of eigen values computing less than required." +#define MESSAGE_ERROR_DIFF_2 "Accuracy of eigen vectors computing less than required." +#define MESSAGE_ERROR_ORTHO "Matrix of eigen vectors is not orthogonal." +#define MESSAGE_ERROR_ORDER "Eigen values are not sorted in ascending order." + +const int COUNT_NORM_TYPES = 3; +const int NORM_TYPE[COUNT_NORM_TYPES] = {cv::NORM_L1, cv::NORM_L2, cv::NORM_INF}; + +enum TASK_TYPE_EIGEN {VALUES, VECTORS}; + +class Core_EigenTest: public cvtest::BaseTest +{ +public: + + Core_EigenTest(); + ~Core_EigenTest(); + +protected: + + bool test_values(const cv::Mat& src); // complex test for eigen without vectors + bool check_full(int type); // compex test for symmetric matrix + virtual void run (int) = 0; // main testing method + +protected: + + float eps_val_32, eps_vec_32; + float eps_val_64, eps_vec_64; + int ntests; + + bool check_pair_count(const cv::Mat& src, const cv::Mat& evalues, int low_index = -1, int high_index = -1); + bool check_pair_count(const cv::Mat& src, const cv::Mat& evalues, const cv::Mat& evectors, int low_index = -1, int high_index = -1); + bool check_pairs_order(const cv::Mat& eigen_values); // checking order of eigen values & vectors (it should be none up) + bool check_orthogonality(const cv::Mat& U); // checking is matrix of eigen vectors orthogonal + bool test_pairs(const cv::Mat& src); // complex test for eigen with vectors + + void print_information(const size_t norm_idx, const cv::Mat& src, double diff, double max_diff); +}; + +class Core_EigenTest_Scalar : public Core_EigenTest +{ +public: + Core_EigenTest_Scalar() : Core_EigenTest() {} + ~Core_EigenTest_Scalar(); + + virtual void run(int) = 0; +}; + +class Core_EigenTest_Scalar_32 : public Core_EigenTest_Scalar +{ +public: + Core_EigenTest_Scalar_32() : Core_EigenTest_Scalar() {} + ~Core_EigenTest_Scalar_32(); + + void run(int); +}; + +class Core_EigenTest_Scalar_64 : public Core_EigenTest_Scalar +{ +public: + Core_EigenTest_Scalar_64() : Core_EigenTest_Scalar() {} + ~Core_EigenTest_Scalar_64(); + void run(int); +}; + +class Core_EigenTest_32 : public Core_EigenTest +{ +public: + Core_EigenTest_32(): Core_EigenTest() {} + ~Core_EigenTest_32() {} + void run(int); +}; + +class Core_EigenTest_64 : public Core_EigenTest +{ +public: + Core_EigenTest_64(): Core_EigenTest() {} + ~Core_EigenTest_64() {} + void run(int); +}; + +Core_EigenTest_Scalar::~Core_EigenTest_Scalar() {} +Core_EigenTest_Scalar_32::~Core_EigenTest_Scalar_32() {} +Core_EigenTest_Scalar_64::~Core_EigenTest_Scalar_64() {} + +void Core_EigenTest_Scalar_32::run(int) +{ + for (int i = 0; i < ntests; ++i) + { + float value = cv::randu(); + cv::Mat src(1, 1, CV_32FC1, Scalar::all((float)value)); + test_values(src); + } +} + +void Core_EigenTest_Scalar_64::run(int) +{ + for (int i = 0; i < ntests; ++i) + { + float value = cv::randu(); + cv::Mat src(1, 1, CV_64FC1, Scalar::all((double)value)); + test_values(src); + } +} + +void Core_EigenTest_32::run(int) { check_full(CV_32FC1); } +void Core_EigenTest_64::run(int) { check_full(CV_64FC1); } + +Core_EigenTest::Core_EigenTest() +: eps_val_32(1e-3f), eps_vec_32(1e-2f), + eps_val_64(1e-4f), eps_vec_64(1e-3f), ntests(100) {} +Core_EigenTest::~Core_EigenTest() {} + +bool Core_EigenTest::check_pair_count(const cv::Mat& src, const cv::Mat& evalues, int low_index, int high_index) +{ + int n = src.rows, s = sign(high_index); + if (!( (evalues.rows == n - max(0, low_index) - ((int)((n/2.0)*(s*s-s)) + (1+s-s*s)*(n - (high_index+1)))) && (evalues.cols == 1))) + { + std::cout << endl; std::cout << "Checking sizes of eigen values matrix " << evalues << "..." << endl; + std::cout << "Number of rows: " << evalues.rows << " Number of cols: " << evalues.cols << endl; + std:: cout << "Size of src symmetric matrix: " << src.rows << " * " << src.cols << endl; std::cout << endl; + CV_Error(CORE_EIGEN_ERROR_COUNT, MESSAGE_ERROR_COUNT); + return false; + } + return true; +} + +bool Core_EigenTest::check_pair_count(const cv::Mat& src, const cv::Mat& evalues, const cv::Mat& evectors, int low_index, int high_index) +{ + int n = src.rows, s = sign(high_index); + int right_eigen_pair_count = n - max(0, low_index) - ((int)((n/2.0)*(s*s-s)) + (1+s-s*s)*(n - (high_index+1))); + + if (!((evectors.rows == right_eigen_pair_count) && (evectors.cols == right_eigen_pair_count))) + { + std::cout << endl; std::cout << "Checking sizes of eigen vectors matrix " << evectors << "..." << endl; + std::cout << "Number of rows: " << evectors.rows << " Number of cols: " << evectors.cols << endl; + std:: cout << "Size of src symmetric matrix: " << src.rows << " * " << src.cols << endl; std::cout << endl; + CV_Error (CORE_EIGEN_ERROR_SIZE, MESSAGE_ERROR_SIZE); + return false; + } + + if (!((evalues.rows == right_eigen_pair_count) && (evalues.cols == 1))) + { + std::cout << endl; std::cout << "Checking sizes of eigen values matrix " << evalues << "..." << endl; + std::cout << "Number of rows: " << evalues.rows << " Number of cols: " << evalues.cols << endl; + std:: cout << "Size of src symmetric matrix: " << src.rows << " * " << src.cols << endl; std::cout << endl; + CV_Error (CORE_EIGEN_ERROR_COUNT, MESSAGE_ERROR_COUNT); + return false; + } + + return true; +} + +void Core_EigenTest::print_information(const size_t norm_idx, const cv::Mat& src, double diff, double max_diff) +{ + switch (NORM_TYPE[norm_idx]) + { + case cv::NORM_L1: {std::cout << "L1"; break;} + case cv::NORM_L2: {std::cout << "L2"; break;} + case cv::NORM_INF: {std::cout << "INF"; break;} + default: break; + } + + cout << "-criteria... " << endl; + cout << "Source size: " << src.rows << " * " << src.cols << endl; + cout << "Difference between original eigen vectors matrix and result: " << diff << endl; + cout << "Maximum allowed difference: " << max_diff << endl; cout << endl; +} + +bool Core_EigenTest::check_orthogonality(const cv::Mat& U) +{ + int type = U.type(); + double eps_vec = type == CV_32FC1 ? eps_vec_32 : eps_vec_64; + cv::Mat UUt; cv::mulTransposed(U, UUt, false); + + cv::Mat E = Mat::eye(U.rows, U.cols, type); + + for (int i = 0; i < COUNT_NORM_TYPES; ++i) + { + double diff = cv::norm(UUt, E, NORM_TYPE[i]); + if (diff > eps_vec) + { + std::cout << endl; std::cout << "Checking orthogonality of matrix " << U << ": "; + print_information(i, U, diff, eps_vec); + CV_Error(CORE_EIGEN_ERROR_ORTHO, MESSAGE_ERROR_ORTHO); + return false; + } + } + + return true; +} + +bool Core_EigenTest::check_pairs_order(const cv::Mat& eigen_values) +{ + switch (eigen_values.type()) + { + case CV_32FC1: + { + for (int i = 0; i < (int)(eigen_values.total() - 1); ++i) + if (!(eigen_values.at(i, 0) > eigen_values.at(i+1, 0))) + { + std::cout << endl; std::cout << "Checking order of eigen values vector " << eigen_values << "..." << endl; + std::cout << "Pair of indexes with non ascending of eigen values: (" << i << ", " << i+1 << ")." << endl; + std::cout << endl; + CV_Error(CORE_EIGEN_ERROR_ORDER, MESSAGE_ERROR_ORDER); + return false; + } + + break; + } + + case CV_64FC1: + { + for (int i = 0; i < (int)(eigen_values.total() - 1); ++i) + if (!(eigen_values.at(i, 0) > eigen_values.at(i+1, 0))) + { + std::cout << endl; std::cout << "Checking order of eigen values vector " << eigen_values << "..." << endl; + std::cout << "Pair of indexes with non ascending of eigen values: (" << i << ", " << i+1 << ")." << endl; + std::cout << endl; + CV_Error(CORE_EIGEN_ERROR_ORDER, "Eigen values are not sorted in ascending order."); + return false; + } + + break; + } + + default:; + } + + return true; +} + +bool Core_EigenTest::test_pairs(const cv::Mat& src) +{ + int type = src.type(); + double eps_vec = type == CV_32FC1 ? eps_vec_32 : eps_vec_64; + + cv::Mat eigen_values, eigen_vectors; + + cv::eigen(src, true, eigen_values, eigen_vectors); + + if (!check_pair_count(src, eigen_values, eigen_vectors)) return false; + + if (!check_orthogonality (eigen_vectors)) return false; + + if (!check_pairs_order(eigen_values)) return false; + + cv::Mat eigen_vectors_t; cv::transpose(eigen_vectors, eigen_vectors_t); + + cv::Mat src_evec(src.rows, src.cols, type); + src_evec = src*eigen_vectors_t; + + cv::Mat eval_evec(src.rows, src.cols, type); + + switch (type) + { + case CV_32FC1: + { + for (int i = 0; i < src.cols; ++i) + { + cv::Mat tmp = eigen_values.at(i, 0) * eigen_vectors_t.col(i); + for (int j = 0; j < src.rows; ++j) eval_evec.at(j, i) = tmp.at(j, 0); + } + + break; + } + + case CV_64FC1: + { + for (int i = 0; i < src.cols; ++i) + { + cv::Mat tmp = eigen_values.at(i, 0) * eigen_vectors_t.col(i); + for (int j = 0; j < src.rows; ++j) eval_evec.at(j, i) = tmp.at(j, 0); + } + + break; + } + + default:; + } + + cv::Mat disparity = src_evec - eval_evec; + + for (int i = 0; i < COUNT_NORM_TYPES; ++i) + { + double diff = cv::norm(disparity, NORM_TYPE[i]); + if (diff > eps_vec) + { + std::cout << endl; std::cout << "Checking accuracy of eigen vectors computing for matrix " << src << ": "; + print_information(i, src, diff, eps_vec); + CV_Error(CORE_EIGEN_ERROR_DIFF, MESSAGE_ERROR_DIFF_2); + return false; + } + } + + return true; +} + +bool Core_EigenTest::test_values(const cv::Mat& src) +{ + int type = src.type(); + double eps_val = type == CV_32FC1 ? eps_val_32 : eps_val_64; + + cv::Mat eigen_values_1, eigen_values_2, eigen_vectors; + + if (!test_pairs(src)) return false; + + cv::eigen(src, true, eigen_values_1, eigen_vectors); + cv::eigen(src, false, eigen_values_2, eigen_vectors); + + if (!check_pair_count(src, eigen_values_2)) return false; + + for (int i = 0; i < COUNT_NORM_TYPES; ++i) + { + double diff = cv::norm(eigen_values_1, eigen_values_2, NORM_TYPE[i]); + if (diff > eps_val) + { + std::cout << endl; std::cout << "Checking accuracy of eigen values computing for matrix " << src << ": "; + print_information(i, src, diff, eps_val); + CV_Error(CORE_EIGEN_ERROR_DIFF, MESSAGE_ERROR_DIFF_1); + return false; + } + } + + return true; +} + +bool Core_EigenTest::check_full(int type) +{ + const int MAX_DEGREE = 7; + + srand((unsigned int)time(0)); + + for (int i = 0; i < ntests; ++i) + { + int src_size = (int)(std::pow(2.0, (rand()%MAX_DEGREE)+1.)); + + cv::Mat src(src_size, src_size, type); + + for (int j = 0; j < src.rows; ++j) + for (int k = j; k < src.cols; ++k) + if (type == CV_32FC1) src.at(k, j) = src.at(j, k) = cv::randu(); + else src.at(k, j) = src.at(j, k) = cv::randu(); + + if (!test_values(src)) return false; + } + + return true; +} + +TEST(Core_Eigen, scalar_32) {Core_EigenTest_Scalar_32 test; test.safe_run(); } +TEST(Core_Eigen, scalar_64) {Core_EigenTest_Scalar_64 test; test.safe_run(); } +TEST(Core_Eigen, vector_32) { Core_EigenTest_32 test; test.safe_run(); } +TEST(Core_Eigen, vector_64) { Core_EigenTest_64 test; test.safe_run(); } diff --git a/core/test/test_io.cpp b/core/test/test_io.cpp new file mode 100644 index 0000000..6b55eb2 --- /dev/null +++ b/core/test/test_io.cpp @@ -0,0 +1,456 @@ +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +static SparseMat cvTsGetRandomSparseMat(int dims, const int* sz, int type, + int nzcount, double a, double b, RNG& rng) +{ + SparseMat m(dims, sz, type); + int i, j; + CV_Assert(CV_MAT_CN(type) == 1); + for( i = 0; i < nzcount; i++ ) + { + int idx[CV_MAX_DIM]; + for( j = 0; j < dims; j++ ) + idx[j] = cvtest::randInt(rng) % sz[j]; + double val = cvtest::randReal(rng)*(b - a) + a; + uchar* ptr = m.ptr(idx, true, 0); + if( type == CV_8U ) + *(uchar*)ptr = saturate_cast(val); + else if( type == CV_8S ) + *(schar*)ptr = saturate_cast(val); + else if( type == CV_16U ) + *(ushort*)ptr = saturate_cast(val); + else if( type == CV_16S ) + *(short*)ptr = saturate_cast(val); + else if( type == CV_32S ) + *(int*)ptr = saturate_cast(val); + else if( type == CV_32F ) + *(float*)ptr = saturate_cast(val); + else + *(double*)ptr = saturate_cast(val); + } + + return m; +} + +static bool cvTsCheckSparse(const CvSparseMat* m1, const CvSparseMat* m2, double eps) +{ + CvSparseMatIterator it1; + CvSparseNode* node1; + int depth = CV_MAT_DEPTH(m1->type); + + if( m1->heap->active_count != m2->heap->active_count || + m1->dims != m2->dims || CV_MAT_TYPE(m1->type) != CV_MAT_TYPE(m2->type) ) + return false; + + for( node1 = cvInitSparseMatIterator( m1, &it1 ); + node1 != 0; node1 = cvGetNextSparseNode( &it1 )) + { + uchar* v1 = (uchar*)CV_NODE_VAL(m1,node1); + uchar* v2 = cvPtrND( m2, CV_NODE_IDX(m1,node1), 0, 0, &node1->hashval ); + if( !v2 ) + return false; + if( depth == CV_8U || depth == CV_8S ) + { + if( *v1 != *v2 ) + return false; + } + else if( depth == CV_16U || depth == CV_16S ) + { + if( *(ushort*)v1 != *(ushort*)v2 ) + return false; + } + else if( depth == CV_32S ) + { + if( *(int*)v1 != *(int*)v2 ) + return false; + } + else if( depth == CV_32F ) + { + if( fabs(*(float*)v1 - *(float*)v2) > eps*(fabs(*(float*)v2) + 1) ) + return false; + } + else if( fabs(*(double*)v1 - *(double*)v2) > eps*(fabs(*(double*)v2) + 1) ) + return false; + } + + return true; +} + + +class Core_IOTest : public cvtest::BaseTest +{ +public: + Core_IOTest() {}; +protected: + void run(int) + { + double ranges[][2] = {{0, 256}, {-128, 128}, {0, 65536}, {-32768, 32768}, + {-1000000, 1000000}, {-10, 10}, {-10, 10}}; + RNG& rng = ts->get_rng(); + RNG rng0; + test_case_count = 4; + int progress = 0; + MemStorage storage(cvCreateMemStorage(0)); + + for( int idx = 0; idx < test_case_count; idx++ ) + { + ts->update_context( this, idx, false ); + progress = update_progress( progress, idx, test_case_count, 0 ); + + cvClearMemStorage(storage); + + bool mem = (idx % 4) >= 2; + string filename = tempfile(idx % 2 ? ".yml" : ".xml"); + + FileStorage fs(filename, FileStorage::WRITE + (mem ? FileStorage::MEMORY : 0)); + + int test_int = (int)cvtest::randInt(rng); + double test_real = (cvtest::randInt(rng)%2?1:-1)*exp(cvtest::randReal(rng)*18-9); + string test_string = "vw wv23424rt\"&<>&'@#$@$%$%&%IJUKYILFD@#$@%$&*&() "; + + int depth = cvtest::randInt(rng) % (CV_64F+1); + int cn = cvtest::randInt(rng) % 4 + 1; + Mat test_mat(cvtest::randInt(rng)%30+1, cvtest::randInt(rng)%30+1, CV_MAKETYPE(depth, cn)); + + rng0.fill(test_mat, CV_RAND_UNI, Scalar::all(ranges[depth][0]), Scalar::all(ranges[depth][1])); + if( depth >= CV_32F ) + { + exp(test_mat, test_mat); + Mat test_mat_scale(test_mat.size(), test_mat.type()); + rng0.fill(test_mat_scale, CV_RAND_UNI, Scalar::all(-1), Scalar::all(1)); + multiply(test_mat, test_mat_scale, test_mat); + } + + CvSeq* seq = cvCreateSeq(test_mat.type(), (int)sizeof(CvSeq), + (int)test_mat.elemSize(), storage); + cvSeqPushMulti(seq, test_mat.data, test_mat.cols*test_mat.rows); + + CvGraph* graph = cvCreateGraph( CV_ORIENTED_GRAPH, + sizeof(CvGraph), sizeof(CvGraphVtx), + sizeof(CvGraphEdge), storage ); + int edges[][2] = {{0,1},{1,2},{2,0},{0,3},{3,4},{4,1}}; + int i, vcount = 5, ecount = 6; + for( i = 0; i < vcount; i++ ) + cvGraphAddVtx(graph); + for( i = 0; i < ecount; i++ ) + { + CvGraphEdge* edge; + cvGraphAddEdge(graph, edges[i][0], edges[i][1], 0, &edge); + edge->weight = (float)(i+1); + } + + depth = cvtest::randInt(rng) % (CV_64F+1); + cn = cvtest::randInt(rng) % 4 + 1; + int sz[] = {cvtest::randInt(rng)%10+1, cvtest::randInt(rng)%10+1, cvtest::randInt(rng)%10+1}; + MatND test_mat_nd(3, sz, CV_MAKETYPE(depth, cn)); + + rng0.fill(test_mat_nd, CV_RAND_UNI, Scalar::all(ranges[depth][0]), Scalar::all(ranges[depth][1])); + if( depth >= CV_32F ) + { + exp(test_mat_nd, test_mat_nd); + MatND test_mat_scale(test_mat_nd.dims, test_mat_nd.size, test_mat_nd.type()); + rng0.fill(test_mat_scale, CV_RAND_UNI, Scalar::all(-1), Scalar::all(1)); + multiply(test_mat_nd, test_mat_scale, test_mat_nd); + } + + int ssz[] = {cvtest::randInt(rng)%10+1, cvtest::randInt(rng)%10+1, + cvtest::randInt(rng)%10+1,cvtest::randInt(rng)%10+1}; + SparseMat test_sparse_mat = cvTsGetRandomSparseMat(4, ssz, cvtest::randInt(rng)%(CV_64F+1), + cvtest::randInt(rng) % 10000, 0, 100, rng); + + fs << "test_int" << test_int << "test_real" << test_real << "test_string" << test_string; + fs << "test_mat" << test_mat; + fs << "test_mat_nd" << test_mat_nd; + fs << "test_sparse_mat" << test_sparse_mat; + + fs << "test_list" << "[" << 0.0000000000001 << 2 << CV_PI << -3435345 << "2-502 2-029 3egegeg" << + "{:" << "month" << 12 << "day" << 31 << "year" << 1969 << "}" << "]"; + fs << "test_map" << "{" << "x" << 1 << "y" << 2 << "width" << 100 << "height" << 200 << "lbp" << "[:"; + + const uchar arr[] = {0, 1, 1, 0, 1, 1, 0, 1}; + fs.writeRaw("u", arr, (int)(sizeof(arr)/sizeof(arr[0]))); + + fs << "]" << "}"; + cvWriteComment(*fs, "test comment", 0); + + fs.writeObj("test_seq", seq); + fs.writeObj("test_graph",graph); + CvGraph* graph2 = (CvGraph*)cvClone(graph); + + string content = fs.releaseAndGetString(); + + if(!fs.open(mem ? content : filename, FileStorage::READ + (mem ? FileStorage::MEMORY : 0))) + { + ts->printf( cvtest::TS::LOG, "filename %s can not be read\n", !mem ? filename.c_str() : content.c_str()); + ts->set_failed_test_info( cvtest::TS::FAIL_MISSING_TEST_DATA ); + return; + } + + int real_int = (int)fs["test_int"]; + double real_real = (double)fs["test_real"]; + string real_string = (string)fs["test_string"]; + + if( real_int != test_int || + fabs(real_real - test_real) > DBL_EPSILON*(fabs(test_real)+1) || + real_string != test_string ) + { + ts->printf( cvtest::TS::LOG, "the read scalars are not correct\n" ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + + CvMat* m = (CvMat*)fs["test_mat"].readObj(); + CvMat _test_mat = test_mat; + double max_diff = 0; + CvMat stub1, _test_stub1; + cvReshape(m, &stub1, 1, 0); + cvReshape(&_test_mat, &_test_stub1, 1, 0); + vector pt; + + if( !m || !CV_IS_MAT(m) || m->rows != test_mat.rows || m->cols != test_mat.cols || + cvtest::cmpEps( Mat(&stub1), Mat(&_test_stub1), &max_diff, 0, &pt, true) < 0 ) + { + ts->printf( cvtest::TS::LOG, "the read matrix is not correct: (%.20g vs %.20g) at (%d,%d)\n", + cvGetReal2D(&stub1, pt[0], pt[1]), cvGetReal2D(&_test_stub1, pt[0], pt[1]), + pt[0], pt[1] ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + if( m && CV_IS_MAT(m)) + cvReleaseMat(&m); + + CvMatND* m_nd = (CvMatND*)fs["test_mat_nd"].readObj(); + CvMatND _test_mat_nd = test_mat_nd; + + if( !m_nd || !CV_IS_MATND(m_nd) ) + { + ts->printf( cvtest::TS::LOG, "the read nd-matrix is not correct\n" ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + + CvMat stub, _test_stub; + cvGetMat(m_nd, &stub, 0, 1); + cvGetMat(&_test_mat_nd, &_test_stub, 0, 1); + cvReshape(&stub, &stub1, 1, 0); + cvReshape(&_test_stub, &_test_stub1, 1, 0); + + if( !CV_ARE_TYPES_EQ(&stub, &_test_stub) || + !CV_ARE_SIZES_EQ(&stub, &_test_stub) || + //cvNorm(&stub, &_test_stub, CV_L2) != 0 ) + cvtest::cmpEps( Mat(&stub1), Mat(&_test_stub1), &max_diff, 0, &pt, true) < 0 ) + { + ts->printf( cvtest::TS::LOG, "readObj method: the read nd matrix is not correct: (%.20g vs %.20g) vs at (%d,%d)\n", + cvGetReal2D(&stub1, pt[0], pt[1]), cvGetReal2D(&_test_stub1, pt[0], pt[1]), + pt[0], pt[1] ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + + MatND mat_nd2; + fs["test_mat_nd"] >> mat_nd2; + CvMatND m_nd2 = mat_nd2; + cvGetMat(&m_nd2, &stub, 0, 1); + cvReshape(&stub, &stub1, 1, 0); + + if( !CV_ARE_TYPES_EQ(&stub, &_test_stub) || + !CV_ARE_SIZES_EQ(&stub, &_test_stub) || + //cvNorm(&stub, &_test_stub, CV_L2) != 0 ) + cvtest::cmpEps( Mat(&stub1), Mat(&_test_stub1), &max_diff, 0, &pt, true) < 0 ) + { + ts->printf( cvtest::TS::LOG, "C++ method: the read nd matrix is not correct: (%.20g vs %.20g) vs at (%d,%d)\n", + cvGetReal2D(&stub1, pt[0], pt[1]), cvGetReal2D(&_test_stub1, pt[1], pt[0]), + pt[0], pt[1] ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + + cvRelease((void**)&m_nd); + + Ptr m_s = (CvSparseMat*)fs["test_sparse_mat"].readObj(); + Ptr _test_sparse_ = (CvSparseMat*)test_sparse_mat; + Ptr _test_sparse = (CvSparseMat*)cvClone(_test_sparse_); + SparseMat m_s2; + fs["test_sparse_mat"] >> m_s2; + Ptr _m_s2 = (CvSparseMat*)m_s2; + + if( !m_s || !CV_IS_SPARSE_MAT(m_s) || + !cvTsCheckSparse(m_s, _test_sparse,0) || + !cvTsCheckSparse(_m_s2, _test_sparse,0)) + { + ts->printf( cvtest::TS::LOG, "the read sparse matrix is not correct\n" ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + + FileNode tl = fs["test_list"]; + if( tl.type() != FileNode::SEQ || tl.size() != 6 || + fabs((double)tl[0] - 0.0000000000001) >= DBL_EPSILON || + (int)tl[1] != 2 || + fabs((double)tl[2] - CV_PI) >= DBL_EPSILON || + (int)tl[3] != -3435345 || + (string)tl[4] != "2-502 2-029 3egegeg" || + tl[5].type() != FileNode::MAP || tl[5].size() != 3 || + (int)tl[5]["month"] != 12 || + (int)tl[5]["day"] != 31 || + (int)tl[5]["year"] != 1969 ) + { + ts->printf( cvtest::TS::LOG, "the test list is incorrect\n" ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + + FileNode tm = fs["test_map"]; + FileNode tm_lbp = tm["lbp"]; + + int real_x = (int)tm["x"]; + int real_y = (int)tm["y"]; + int real_width = (int)tm["width"]; + int real_height = (int)tm["height"]; + + int real_lbp_val = 0; + FileNodeIterator it; + it = tm_lbp.begin(); + real_lbp_val |= (int)*it << 0; + ++it; + real_lbp_val |= (int)*it << 1; + it++; + real_lbp_val |= (int)*it << 2; + it += 1; + real_lbp_val |= (int)*it << 3; + FileNodeIterator it2(it); + it2 += 4; + real_lbp_val |= (int)*it2 << 7; + --it2; + real_lbp_val |= (int)*it2 << 6; + it2--; + real_lbp_val |= (int)*it2 << 5; + it2 -= 1; + real_lbp_val |= (int)*it2 << 4; + it2 += -1; + CV_Assert( it == it2 ); + + if( tm.type() != FileNode::MAP || tm.size() != 5 || + real_x != 1 || + real_y != 2 || + real_width != 100 || + real_height != 200 || + tm_lbp.type() != FileNode::SEQ || + tm_lbp.size() != 8 || + real_lbp_val != 0xb6 ) + { + ts->printf( cvtest::TS::LOG, "the test map is incorrect\n" ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + + CvGraph* graph3 = (CvGraph*)fs["test_graph"].readObj(); + if(graph2->active_count != vcount || graph3->active_count != vcount || + graph2->edges->active_count != ecount || graph3->edges->active_count != ecount) + { + ts->printf( cvtest::TS::LOG, "the cloned or read graph have wrong number of vertices or edges\n" ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + + for( i = 0; i < ecount; i++ ) + { + CvGraphEdge* edge2 = cvFindGraphEdge(graph2, edges[i][0], edges[i][1]); + CvGraphEdge* edge3 = cvFindGraphEdge(graph3, edges[i][0], edges[i][1]); + if( !edge2 || edge2->weight != (float)(i+1) || + !edge3 || edge3->weight != (float)(i+1) ) + { + ts->printf( cvtest::TS::LOG, "the cloned or read graph do not have the edge (%d, %d)\n", edges[i][0], edges[i][1] ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + } + + fs.release(); + if( !mem ) + remove(filename.c_str()); + } + } +}; + +TEST(Core_InputOutput, write_read_consistency) { Core_IOTest test; test.safe_run(); } + + +class CV_MiscIOTest : public cvtest::BaseTest +{ +public: + CV_MiscIOTest() {} + ~CV_MiscIOTest() {} +protected: + void run(int) + { + try + { + string fname = cv::tempfile(".xml"); + FileStorage fs(fname, FileStorage::WRITE); + vector mi, mi2, mi3, mi4; + vector mv, mv2, mv3, mv4; + Mat m(10, 9, CV_32F); + Mat empty; + randu(m, 0, 1); + mi3.push_back(5); + mv3.push_back(m); + fs << "mi" << mi; + fs << "mv" << mv; + fs << "mi3" << mi3; + fs << "mv3" << mv3; + fs << "empty" << empty; + fs.release(); + fs.open(fname, FileStorage::READ); + fs["mi"] >> mi2; + fs["mv"] >> mv2; + fs["mi3"] >> mi4; + fs["mv3"] >> mv4; + fs["empty"] >> empty; + CV_Assert( mi2.empty() ); + CV_Assert( mv2.empty() ); + CV_Assert( norm(mi3, mi4, CV_C) == 0 ); + CV_Assert( mv4.size() == 1 ); + double n = norm(mv3[0], mv4[0], CV_C); + CV_Assert( n == 0 ); + } + catch(...) + { + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + } + } +}; + +TEST(Core_InputOutput, misc) { CV_MiscIOTest test; test.safe_run(); } + +/*class CV_BigMatrixIOTest : public cvtest::BaseTest +{ +public: + CV_BigMatrixIOTest() {} + ~CV_BigMatrixIOTest() {} +protected: + void run(int) + { + try + { + RNG& rng = theRNG(); + int N = 1000, M = 1200000; + Mat mat(M, N, CV_32F); + rng.fill(mat, RNG::UNIFORM, 0, 1); + FileStorage fs(cv::tempfile(".xml"), FileStorage::WRITE); + fs << "mat" << mat; + fs.release(); + } + catch(...) + { + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + } + } +}; + +TEST(Core_InputOutput, huge) { CV_BigMatrixIOTest test; test.safe_run(); } +*/ + diff --git a/core/test/test_main.cpp b/core/test/test_main.cpp new file mode 100644 index 0000000..6b24993 --- /dev/null +++ b/core/test/test_main.cpp @@ -0,0 +1,3 @@ +#include "test_precomp.hpp" + +CV_TEST_MAIN("cv") diff --git a/core/test/test_mat.cpp b/core/test/test_mat.cpp new file mode 100644 index 0000000..6b5d09f --- /dev/null +++ b/core/test/test_mat.cpp @@ -0,0 +1,874 @@ +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + + +class Core_ReduceTest : public cvtest::BaseTest +{ +public: + Core_ReduceTest() {}; +protected: + void run( int); + int checkOp( const Mat& src, int dstType, int opType, const Mat& opRes, int dim ); + int checkCase( int srcType, int dstType, int dim, Size sz ); + int checkDim( int dim, Size sz ); + int checkSize( Size sz ); +}; + +template +void testReduce( const Mat& src, Mat& sum, Mat& avg, Mat& max, Mat& min, int dim ) +{ + assert( src.channels() == 1 ); + if( dim == 0 ) // row + { + sum.create( 1, src.cols, CV_64FC1 ); + max.create( 1, src.cols, CV_64FC1 ); + min.create( 1, src.cols, CV_64FC1 ); + } + else + { + sum.create( src.rows, 1, CV_64FC1 ); + max.create( src.rows, 1, CV_64FC1 ); + min.create( src.rows, 1, CV_64FC1 ); + } + sum.setTo(Scalar(0)); + max.setTo(Scalar(-DBL_MAX)); + min.setTo(Scalar(DBL_MAX)); + + const Mat_& src_ = src; + Mat_& sum_ = (Mat_&)sum; + Mat_& min_ = (Mat_&)min; + Mat_& max_ = (Mat_&)max; + + if( dim == 0 ) + { + for( int ri = 0; ri < src.rows; ri++ ) + { + for( int ci = 0; ci < src.cols; ci++ ) + { + sum_(0, ci) += src_(ri, ci); + max_(0, ci) = std::max( max_(0, ci), (double)src_(ri, ci) ); + min_(0, ci) = std::min( min_(0, ci), (double)src_(ri, ci) ); + } + } + } + else + { + for( int ci = 0; ci < src.cols; ci++ ) + { + for( int ri = 0; ri < src.rows; ri++ ) + { + sum_(ri, 0) += src_(ri, ci); + max_(ri, 0) = std::max( max_(ri, 0), (double)src_(ri, ci) ); + min_(ri, 0) = std::min( min_(ri, 0), (double)src_(ri, ci) ); + } + } + } + sum.convertTo( avg, CV_64FC1 ); + avg = avg * (1.0 / (dim==0 ? (double)src.rows : (double)src.cols)); +} + +void getMatTypeStr( int type, string& str) +{ + str = type == CV_8UC1 ? "CV_8UC1" : + type == CV_8SC1 ? "CV_8SC1" : + type == CV_16UC1 ? "CV_16UC1" : + type == CV_16SC1 ? "CV_16SC1" : + type == CV_32SC1 ? "CV_32SC1" : + type == CV_32FC1 ? "CV_32FC1" : + type == CV_64FC1 ? "CV_64FC1" : "unsupported matrix type"; +} + +int Core_ReduceTest::checkOp( const Mat& src, int dstType, int opType, const Mat& opRes, int dim ) +{ + int srcType = src.type(); + bool support = false; + if( opType == CV_REDUCE_SUM || opType == CV_REDUCE_AVG ) + { + if( srcType == CV_8U && (dstType == CV_32S || dstType == CV_32F || dstType == CV_64F) ) + support = true; + if( srcType == CV_16U && (dstType == CV_32F || dstType == CV_64F) ) + support = true; + if( srcType == CV_16S && (dstType == CV_32F || dstType == CV_64F) ) + support = true; + if( srcType == CV_32F && (dstType == CV_32F || dstType == CV_64F) ) + support = true; + if( srcType == CV_64F && dstType == CV_64F) + support = true; + } + else if( opType == CV_REDUCE_MAX ) + { + if( srcType == CV_8U && dstType == CV_8U ) + support = true; + if( srcType == CV_32F && dstType == CV_32F ) + support = true; + if( srcType == CV_64F && dstType == CV_64F ) + support = true; + } + else if( opType == CV_REDUCE_MIN ) + { + if( srcType == CV_8U && dstType == CV_8U) + support = true; + if( srcType == CV_32F && dstType == CV_32F) + support = true; + if( srcType == CV_64F && dstType == CV_64F) + support = true; + } + if( !support ) + return cvtest::TS::OK; + + double eps = 0.0; + if ( opType == CV_REDUCE_SUM || opType == CV_REDUCE_AVG ) + { + if ( dstType == CV_32F ) + eps = 1.e-5; + else if( dstType == CV_64F ) + eps = 1.e-8; + else if ( dstType == CV_32S ) + eps = 0.6; + } + + assert( opRes.type() == CV_64FC1 ); + Mat _dst, dst, diff; + reduce( src, _dst, dim, opType, dstType ); + _dst.convertTo( dst, CV_64FC1 ); + + absdiff( opRes,dst,diff ); + bool check = false; + if (dstType == CV_32F || dstType == CV_64F) + check = countNonZero(diff>eps*dst) > 0; + else + check = countNonZero(diff>eps) > 0; + if( check ) + { + char msg[100]; + const char* opTypeStr = opType == CV_REDUCE_SUM ? "CV_REDUCE_SUM" : + opType == CV_REDUCE_AVG ? "CV_REDUCE_AVG" : + opType == CV_REDUCE_MAX ? "CV_REDUCE_MAX" : + opType == CV_REDUCE_MIN ? "CV_REDUCE_MIN" : "unknown operation type"; + string srcTypeStr, dstTypeStr; + getMatTypeStr( src.type(), srcTypeStr ); + getMatTypeStr( dstType, dstTypeStr ); + const char* dimStr = dim == 0 ? "ROWS" : "COLS"; + + sprintf( msg, "bad accuracy with srcType = %s, dstType = %s, opType = %s, dim = %s", + srcTypeStr.c_str(), dstTypeStr.c_str(), opTypeStr, dimStr ); + ts->printf( cvtest::TS::LOG, msg ); + return cvtest::TS::FAIL_BAD_ACCURACY; + } + return cvtest::TS::OK; +} + +int Core_ReduceTest::checkCase( int srcType, int dstType, int dim, Size sz ) +{ + int code = cvtest::TS::OK, tempCode; + Mat src, sum, avg, max, min; + + src.create( sz, srcType ); + randu( src, Scalar(0), Scalar(100) ); + + if( srcType == CV_8UC1 ) + testReduce( src, sum, avg, max, min, dim ); + else if( srcType == CV_8SC1 ) + testReduce( src, sum, avg, max, min, dim ); + else if( srcType == CV_16UC1 ) + testReduce( src, sum, avg, max, min, dim ); + else if( srcType == CV_16SC1 ) + testReduce( src, sum, avg, max, min, dim ); + else if( srcType == CV_32SC1 ) + testReduce( src, sum, avg, max, min, dim ); + else if( srcType == CV_32FC1 ) + testReduce( src, sum, avg, max, min, dim ); + else if( srcType == CV_64FC1 ) + testReduce( src, sum, avg, max, min, dim ); + else + assert( 0 ); + + // 1. sum + tempCode = checkOp( src, dstType, CV_REDUCE_SUM, sum, dim ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + // 2. avg + tempCode = checkOp( src, dstType, CV_REDUCE_AVG, avg, dim ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + // 3. max + tempCode = checkOp( src, dstType, CV_REDUCE_MAX, max, dim ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + // 4. min + tempCode = checkOp( src, dstType, CV_REDUCE_MIN, min, dim ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + return code; +} + +int Core_ReduceTest::checkDim( int dim, Size sz ) +{ + int code = cvtest::TS::OK, tempCode; + + // CV_8UC1 + tempCode = checkCase( CV_8UC1, CV_8UC1, dim, sz ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + tempCode = checkCase( CV_8UC1, CV_32SC1, dim, sz ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + tempCode = checkCase( CV_8UC1, CV_32FC1, dim, sz ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + tempCode = checkCase( CV_8UC1, CV_64FC1, dim, sz ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + // CV_16UC1 + tempCode = checkCase( CV_16UC1, CV_32FC1, dim, sz ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + tempCode = checkCase( CV_16UC1, CV_64FC1, dim, sz ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + // CV_16SC1 + tempCode = checkCase( CV_16SC1, CV_32FC1, dim, sz ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + tempCode = checkCase( CV_16SC1, CV_64FC1, dim, sz ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + // CV_32FC1 + tempCode = checkCase( CV_32FC1, CV_32FC1, dim, sz ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + tempCode = checkCase( CV_32FC1, CV_64FC1, dim, sz ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + // CV_64FC1 + tempCode = checkCase( CV_64FC1, CV_64FC1, dim, sz ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + return code; +} + +int Core_ReduceTest::checkSize( Size sz ) +{ + int code = cvtest::TS::OK, tempCode; + + tempCode = checkDim( 0, sz ); // rows + code = tempCode != cvtest::TS::OK ? tempCode : code; + + tempCode = checkDim( 1, sz ); // cols + code = tempCode != cvtest::TS::OK ? tempCode : code; + + return code; +} + +void Core_ReduceTest::run( int ) +{ + int code = cvtest::TS::OK, tempCode; + + tempCode = checkSize( Size(1,1) ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + tempCode = checkSize( Size(1,100) ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + tempCode = checkSize( Size(100,1) ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + tempCode = checkSize( Size(1000,500) ); + code = tempCode != cvtest::TS::OK ? tempCode : code; + + ts->set_failed_test_info( code ); +} + + +#define CHECK_C + +class Core_PCATest : public cvtest::BaseTest +{ +public: + Core_PCATest() {} +protected: + void run(int) + { + const Size sz(200, 500); + + double diffPrjEps, diffBackPrjEps, + prjEps, backPrjEps, + evalEps, evecEps; + int maxComponents = 100; + Mat rPoints(sz, CV_32FC1), rTestPoints(sz, CV_32FC1); + RNG& rng = ts->get_rng(); + + rng.fill( rPoints, RNG::UNIFORM, Scalar::all(0.0), Scalar::all(1.0) ); + rng.fill( rTestPoints, RNG::UNIFORM, Scalar::all(0.0), Scalar::all(1.0) ); + + PCA rPCA( rPoints, Mat(), CV_PCA_DATA_AS_ROW, maxComponents ), cPCA; + + // 1. check C++ PCA & ROW + Mat rPrjTestPoints = rPCA.project( rTestPoints ); + Mat rBackPrjTestPoints = rPCA.backProject( rPrjTestPoints ); + + Mat avg(1, sz.width, CV_32FC1 ); + reduce( rPoints, avg, 0, CV_REDUCE_AVG ); + Mat Q = rPoints - repeat( avg, rPoints.rows, 1 ), Qt = Q.t(), eval, evec; + Q = Qt * Q; + Q = Q /(float)rPoints.rows; + + eigen( Q, eval, evec ); + /*SVD svd(Q); + evec = svd.vt; + eval = svd.w;*/ + + Mat subEval( maxComponents, 1, eval.type(), eval.data ), + subEvec( maxComponents, evec.cols, evec.type(), evec.data ); + + #ifdef CHECK_C + Mat prjTestPoints, backPrjTestPoints, cPoints = rPoints.t(), cTestPoints = rTestPoints.t(); + CvMat _points, _testPoints, _avg, _eval, _evec, _prjTestPoints, _backPrjTestPoints; + #endif + + // check eigen() + double eigenEps = 1e-6; + double err; + for(int i = 0; i < Q.rows; i++ ) + { + Mat v = evec.row(i).t(); + Mat Qv = Q * v; + + Mat lv = eval.at(i,0) * v; + err = norm( Qv, lv ); + if( err > eigenEps ) + { + ts->printf( cvtest::TS::LOG, "bad accuracy of eigen(); err = %f\n", err ); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + } + // check pca eigenvalues + evalEps = 1e-6, evecEps = 1e-3; + err = norm( rPCA.eigenvalues, subEval ); + if( err > evalEps ) + { + ts->printf( cvtest::TS::LOG, "pca.eigenvalues is incorrect (CV_PCA_DATA_AS_ROW); err = %f\n", err ); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + // check pca eigenvectors + for(int i = 0; i < subEvec.rows; i++) + { + Mat r0 = rPCA.eigenvectors.row(i); + Mat r1 = subEvec.row(i); + err = norm( r0, r1, CV_L2 ); + if( err > evecEps ) + { + r1 *= -1; + double err2 = norm(r0, r1, CV_L2); + if( err2 > evecEps ) + { + Mat tmp; + absdiff(rPCA.eigenvectors, subEvec, tmp); + double mval = 0; Point mloc; + minMaxLoc(tmp, 0, &mval, 0, &mloc); + + ts->printf( cvtest::TS::LOG, "pca.eigenvectors is incorrect (CV_PCA_DATA_AS_ROW); err = %f\n", err ); + ts->printf( cvtest::TS::LOG, "max diff is %g at (i=%d, j=%d) (%g vs %g)\n", + mval, mloc.y, mloc.x, rPCA.eigenvectors.at(mloc.y, mloc.x), + subEvec.at(mloc.y, mloc.x)); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + } + } + + prjEps = 1.265, backPrjEps = 1.265; + for( int i = 0; i < rTestPoints.rows; i++ ) + { + // check pca project + Mat subEvec_t = subEvec.t(); + Mat prj = rTestPoints.row(i) - avg; prj *= subEvec_t; + err = norm(rPrjTestPoints.row(i), prj, CV_RELATIVE_L2); + if( err > prjEps ) + { + ts->printf( cvtest::TS::LOG, "bad accuracy of project() (CV_PCA_DATA_AS_ROW); err = %f\n", err ); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + // check pca backProject + Mat backPrj = rPrjTestPoints.row(i) * subEvec + avg; + err = norm( rBackPrjTestPoints.row(i), backPrj, CV_RELATIVE_L2 ); + if( err > backPrjEps ) + { + ts->printf( cvtest::TS::LOG, "bad accuracy of backProject() (CV_PCA_DATA_AS_ROW); err = %f\n", err ); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + } + + // 2. check C++ PCA & COL + cPCA( rPoints.t(), Mat(), CV_PCA_DATA_AS_COL, maxComponents ); + diffPrjEps = 1, diffBackPrjEps = 1; + Mat ocvPrjTestPoints = cPCA.project(rTestPoints.t()); + err = norm(cv::abs(ocvPrjTestPoints), cv::abs(rPrjTestPoints.t()), CV_RELATIVE_L2 ); + if( err > diffPrjEps ) + { + ts->printf( cvtest::TS::LOG, "bad accuracy of project() (CV_PCA_DATA_AS_COL); err = %f\n", err ); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + err = norm(cPCA.backProject(ocvPrjTestPoints), rBackPrjTestPoints.t(), CV_RELATIVE_L2 ); + if( err > diffBackPrjEps ) + { + ts->printf( cvtest::TS::LOG, "bad accuracy of backProject() (CV_PCA_DATA_AS_COL); err = %f\n", err ); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + + #ifdef CHECK_C + // 3. check C PCA & ROW + _points = rPoints; + _testPoints = rTestPoints; + _avg = avg; + _eval = eval; + _evec = evec; + prjTestPoints.create(rTestPoints.rows, maxComponents, rTestPoints.type() ); + backPrjTestPoints.create(rPoints.size(), rPoints.type() ); + _prjTestPoints = prjTestPoints; + _backPrjTestPoints = backPrjTestPoints; + + cvCalcPCA( &_points, &_avg, &_eval, &_evec, CV_PCA_DATA_AS_ROW ); + cvProjectPCA( &_testPoints, &_avg, &_evec, &_prjTestPoints ); + cvBackProjectPCA( &_prjTestPoints, &_avg, &_evec, &_backPrjTestPoints ); + + err = norm(prjTestPoints, rPrjTestPoints, CV_RELATIVE_L2); + if( err > diffPrjEps ) + { + ts->printf( cvtest::TS::LOG, "bad accuracy of cvProjectPCA() (CV_PCA_DATA_AS_ROW); err = %f\n", err ); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + err = norm(backPrjTestPoints, rBackPrjTestPoints, CV_RELATIVE_L2); + if( err > diffBackPrjEps ) + { + ts->printf( cvtest::TS::LOG, "bad accuracy of cvBackProjectPCA() (CV_PCA_DATA_AS_ROW); err = %f\n", err ); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + + // 3. check C PCA & COL + _points = cPoints; + _testPoints = cTestPoints; + avg = avg.t(); _avg = avg; + eval = eval.t(); _eval = eval; + evec = evec.t(); _evec = evec; + prjTestPoints = prjTestPoints.t(); _prjTestPoints = prjTestPoints; + backPrjTestPoints = backPrjTestPoints.t(); _backPrjTestPoints = backPrjTestPoints; + + cvCalcPCA( &_points, &_avg, &_eval, &_evec, CV_PCA_DATA_AS_COL ); + cvProjectPCA( &_testPoints, &_avg, &_evec, &_prjTestPoints ); + cvBackProjectPCA( &_prjTestPoints, &_avg, &_evec, &_backPrjTestPoints ); + + err = norm(cv::abs(prjTestPoints), cv::abs(rPrjTestPoints.t()), CV_RELATIVE_L2 ); + if( err > diffPrjEps ) + { + ts->printf( cvtest::TS::LOG, "bad accuracy of cvProjectPCA() (CV_PCA_DATA_AS_COL); err = %f\n", err ); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + err = norm(backPrjTestPoints, rBackPrjTestPoints.t(), CV_RELATIVE_L2); + if( err > diffBackPrjEps ) + { + ts->printf( cvtest::TS::LOG, "bad accuracy of cvBackProjectPCA() (CV_PCA_DATA_AS_COL); err = %f\n", err ); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + #endif + } +}; + +class Core_ArrayOpTest : public cvtest::BaseTest +{ +public: + Core_ArrayOpTest(); + ~Core_ArrayOpTest(); +protected: + void run(int); +}; + + +Core_ArrayOpTest::Core_ArrayOpTest() +{ +} +Core_ArrayOpTest::~Core_ArrayOpTest() {} + +static string idx2string(const int* idx, int dims) +{ + char buf[256]; + char* ptr = buf; + for( int k = 0; k < dims; k++ ) + { + sprintf(ptr, "%4d ", idx[k]); + ptr += strlen(ptr); + } + ptr[-1] = '\0'; + return string(buf); +} + +static const int* string2idx(const string& s, int* idx, int dims) +{ + const char* ptr = s.c_str(); + for( int k = 0; k < dims; k++ ) + { + int n = 0; + sscanf(ptr, "%d%n", idx + k, &n); + ptr += n; + } + return idx; +} + +static double getValue(SparseMat& M, const int* idx, RNG& rng) +{ + int d = M.dims(); + size_t hv = 0, *phv = 0; + if( (unsigned)rng % 2 ) + { + hv = d == 2 ? M.hash(idx[0], idx[1]) : + d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx); + phv = &hv; + } + + const uchar* ptr = d == 2 ? M.ptr(idx[0], idx[1], false, phv) : + d == 3 ? M.ptr(idx[0], idx[1], idx[2], false, phv) : + M.ptr(idx, false, phv); + return !ptr ? 0 : M.type() == CV_32F ? *(float*)ptr : M.type() == CV_64F ? *(double*)ptr : 0; +} + +static double getValue(const CvSparseMat* M, const int* idx) +{ + int type = 0; + const uchar* ptr = cvPtrND(M, idx, &type, 0); + return !ptr ? 0 : type == CV_32F ? *(float*)ptr : type == CV_64F ? *(double*)ptr : 0; +} + +static void eraseValue(SparseMat& M, const int* idx, RNG& rng) +{ + int d = M.dims(); + size_t hv = 0, *phv = 0; + if( (unsigned)rng % 2 ) + { + hv = d == 2 ? M.hash(idx[0], idx[1]) : + d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx); + phv = &hv; + } + + if( d == 2 ) + M.erase(idx[0], idx[1], phv); + else if( d == 3 ) + M.erase(idx[0], idx[1], idx[2], phv); + else + M.erase(idx, phv); +} + +static void eraseValue(CvSparseMat* M, const int* idx) +{ + cvClearND(M, idx); +} + +static void setValue(SparseMat& M, const int* idx, double value, RNG& rng) +{ + int d = M.dims(); + size_t hv = 0, *phv = 0; + if( (unsigned)rng % 2 ) + { + hv = d == 2 ? M.hash(idx[0], idx[1]) : + d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx); + phv = &hv; + } + + uchar* ptr = d == 2 ? M.ptr(idx[0], idx[1], true, phv) : + d == 3 ? M.ptr(idx[0], idx[1], idx[2], true, phv) : + M.ptr(idx, true, phv); + if( M.type() == CV_32F ) + *(float*)ptr = (float)value; + else if( M.type() == CV_64F ) + *(double*)ptr = value; + else + CV_Error(CV_StsUnsupportedFormat, ""); +} + +void Core_ArrayOpTest::run( int /* start_from */) +{ + int errcount = 0; + + // dense matrix operations + { + int sz3[] = {5, 10, 15}; + MatND A(3, sz3, CV_32F), B(3, sz3, CV_16SC4); + CvMatND matA = A, matB = B; + RNG rng; + rng.fill(A, CV_RAND_UNI, Scalar::all(-10), Scalar::all(10)); + rng.fill(B, CV_RAND_UNI, Scalar::all(-10), Scalar::all(10)); + + int idx0[] = {3,4,5}, idx1[] = {0, 9, 7}; + float val0 = 130; + Scalar val1(-1000, 30, 3, 8); + cvSetRealND(&matA, idx0, val0); + cvSetReal3D(&matA, idx1[0], idx1[1], idx1[2], -val0); + cvSetND(&matB, idx0, val1); + cvSet3D(&matB, idx1[0], idx1[1], idx1[2], -val1); + Ptr matC = cvCloneMatND(&matB); + + if( A.at(idx0[0], idx0[1], idx0[2]) != val0 || + A.at(idx1[0], idx1[1], idx1[2]) != -val0 || + cvGetReal3D(&matA, idx0[0], idx0[1], idx0[2]) != val0 || + cvGetRealND(&matA, idx1) != -val0 || + + Scalar(B.at(idx0[0], idx0[1], idx0[2])) != val1 || + Scalar(B.at(idx1[0], idx1[1], idx1[2])) != -val1 || + Scalar(cvGet3D(matC, idx0[0], idx0[1], idx0[2])) != val1 || + Scalar(cvGetND(matC, idx1)) != -val1 ) + { + ts->printf(cvtest::TS::LOG, "one of cvSetReal3D, cvSetRealND, cvSet3D, cvSetND " + "or the corresponding *Get* functions is not correct\n"); + errcount++; + } + } + + RNG rng; + const int MAX_DIM = 5, MAX_DIM_SZ = 10; + // sparse matrix operations + for( int si = 0; si < 10; si++ ) + { + int depth = (unsigned)rng % 2 == 0 ? CV_32F : CV_64F; + int dims = ((unsigned)rng % MAX_DIM) + 1; + int i, k, size[MAX_DIM]={0}, idx[MAX_DIM]={0}; + vector all_idxs; + vector all_vals; + vector all_vals2; + string sidx, min_sidx, max_sidx; + double min_val=0, max_val=0; + + int p = 1; + for( k = 0; k < dims; k++ ) + { + size[k] = ((unsigned)rng % MAX_DIM_SZ) + 1; + p *= size[k]; + } + SparseMat M( dims, size, depth ); + map M0; + + int nz0 = (unsigned)rng % max(p/5,10); + nz0 = min(max(nz0, 1), p); + all_vals.resize(nz0); + all_vals2.resize(nz0); + Mat_ _all_vals(all_vals), _all_vals2(all_vals2); + rng.fill(_all_vals, CV_RAND_UNI, Scalar(-1000), Scalar(1000)); + if( depth == CV_32F ) + { + Mat _all_vals_f; + _all_vals.convertTo(_all_vals_f, CV_32F); + _all_vals_f.convertTo(_all_vals, CV_64F); + } + _all_vals.convertTo(_all_vals2, _all_vals2.type(), 2); + if( depth == CV_32F ) + { + Mat _all_vals2_f; + _all_vals2.convertTo(_all_vals2_f, CV_32F); + _all_vals2_f.convertTo(_all_vals2, CV_64F); + } + + minMaxLoc(_all_vals, &min_val, &max_val); + double _norm0 = norm(_all_vals, CV_C); + double _norm1 = norm(_all_vals, CV_L1); + double _norm2 = norm(_all_vals, CV_L2); + + for( i = 0; i < nz0; i++ ) + { + for(;;) + { + for( k = 0; k < dims; k++ ) + idx[k] = (unsigned)rng % size[k]; + sidx = idx2string(idx, dims); + if( M0.count(sidx) == 0 ) + break; + } + all_idxs.push_back(sidx); + M0[sidx] = all_vals[i]; + if( all_vals[i] == min_val ) + min_sidx = sidx; + if( all_vals[i] == max_val ) + max_sidx = sidx; + setValue(M, idx, all_vals[i], rng); + double v = getValue(M, idx, rng); + if( v != all_vals[i] ) + { + ts->printf(cvtest::TS::LOG, "%d. immediately after SparseMat[%s]=%.20g the current value is %.20g\n", + i, sidx.c_str(), all_vals[i], v); + errcount++; + break; + } + } + + Ptr M2 = (CvSparseMat*)M; + MatND Md; + M.copyTo(Md); + SparseMat M3; SparseMat(Md).convertTo(M3, Md.type(), 2); + + int nz1 = (int)M.nzcount(), nz2 = (int)M3.nzcount(); + double norm0 = norm(M, CV_C); + double norm1 = norm(M, CV_L1); + double norm2 = norm(M, CV_L2); + double eps = depth == CV_32F ? FLT_EPSILON*100 : DBL_EPSILON*1000; + + if( nz1 != nz0 || nz2 != nz0) + { + errcount++; + ts->printf(cvtest::TS::LOG, "%d: The number of non-zero elements before/after converting to/from dense matrix is not correct: %d/%d (while it should be %d)\n", + si, nz1, nz2, nz0 ); + break; + } + + if( fabs(norm0 - _norm0) > fabs(_norm0)*eps || + fabs(norm1 - _norm1) > fabs(_norm1)*eps || + fabs(norm2 - _norm2) > fabs(_norm2)*eps ) + { + errcount++; + ts->printf(cvtest::TS::LOG, "%d: The norms are different: %.20g/%.20g/%.20g vs %.20g/%.20g/%.20g\n", + si, norm0, norm1, norm2, _norm0, _norm1, _norm2 ); + break; + } + + int n = (unsigned)rng % max(p/5,10); + n = min(max(n, 1), p) + nz0; + + for( i = 0; i < n; i++ ) + { + double val1, val2, val3, val0; + if(i < nz0) + { + sidx = all_idxs[i]; + string2idx(sidx, idx, dims); + val0 = all_vals[i]; + } + else + { + for( k = 0; k < dims; k++ ) + idx[k] = (unsigned)rng % size[k]; + sidx = idx2string(idx, dims); + val0 = M0[sidx]; + } + val1 = getValue(M, idx, rng); + val2 = getValue(M2, idx); + val3 = getValue(M3, idx, rng); + + if( val1 != val0 || val2 != val0 || fabs(val3 - val0*2) > fabs(val0*2)*FLT_EPSILON ) + { + errcount++; + ts->printf(cvtest::TS::LOG, "SparseMat M[%s] = %g/%g/%g (while it should be %g)\n", sidx.c_str(), val1, val2, val3, val0 ); + break; + } + } + + for( i = 0; i < n; i++ ) + { + double val1, val2; + if(i < nz0) + { + sidx = all_idxs[i]; + string2idx(sidx, idx, dims); + } + else + { + for( k = 0; k < dims; k++ ) + idx[k] = (unsigned)rng % size[k]; + sidx = idx2string(idx, dims); + } + eraseValue(M, idx, rng); + eraseValue(M2, idx); + val1 = getValue(M, idx, rng); + val2 = getValue(M2, idx); + if( val1 != 0 || val2 != 0 ) + { + errcount++; + ts->printf(cvtest::TS::LOG, "SparseMat: after deleting M[%s], it is =%g/%g (while it should be 0)\n", sidx.c_str(), val1, val2 ); + break; + } + } + + int nz = (int)M.nzcount(); + if( nz != 0 ) + { + errcount++; + ts->printf(cvtest::TS::LOG, "The number of non-zero elements after removing all the elements = %d (while it should be 0)\n", nz ); + break; + } + + int idx1[MAX_DIM], idx2[MAX_DIM]; + double val1 = 0, val2 = 0; + M3 = SparseMat(Md); + minMaxLoc(M3, &val1, &val2, idx1, idx2); + string s1 = idx2string(idx1, dims), s2 = idx2string(idx2, dims); + if( val1 != min_val || val2 != max_val || s1 != min_sidx || s2 != max_sidx ) + { + errcount++; + ts->printf(cvtest::TS::LOG, "%d. Sparse: The value and positions of minimum/maximum elements are different from the reference values and positions:\n\t" + "(%g, %g, %s, %s) vs (%g, %g, %s, %s)\n", si, val1, val2, s1.c_str(), s2.c_str(), + min_val, max_val, min_sidx.c_str(), max_sidx.c_str()); + break; + } + + minMaxIdx(Md, &val1, &val2, idx1, idx2); + s1 = idx2string(idx1, dims), s2 = idx2string(idx2, dims); + if( (min_val < 0 && (val1 != min_val || s1 != min_sidx)) || + (max_val > 0 && (val2 != max_val || s2 != max_sidx)) ) + { + errcount++; + ts->printf(cvtest::TS::LOG, "%d. Dense: The value and positions of minimum/maximum elements are different from the reference values and positions:\n\t" + "(%g, %g, %s, %s) vs (%g, %g, %s, %s)\n", si, val1, val2, s1.c_str(), s2.c_str(), + min_val, max_val, min_sidx.c_str(), max_sidx.c_str()); + break; + } + } + + ts->set_failed_test_info(errcount == 0 ? cvtest::TS::OK : cvtest::TS::FAIL_INVALID_OUTPUT); +} + +TEST(Core_PCA, accuracy) { Core_PCATest test; test.safe_run(); } +TEST(Core_Reduce, accuracy) { Core_ReduceTest test; test.safe_run(); } +TEST(Core_Array, basic_operations) { Core_ArrayOpTest test; test.safe_run(); } + + +TEST(Core_IOArray, submat_assignment) +{ + Mat1f A = Mat1f::zeros(2,2); + Mat1f B = Mat1f::ones(1,3); + + EXPECT_THROW( B.colRange(0,3).copyTo(A.row(0)), cv::Exception ); + + EXPECT_NO_THROW( B.colRange(0,2).copyTo(A.row(0)) ); + + EXPECT_EQ( 1.0f, A(0,0) ); + EXPECT_EQ( 1.0f, A(0,1) ); +} + +void OutputArray_create1(OutputArray m) { m.create(1, 2, CV_32S); } +void OutputArray_create2(OutputArray m) { m.create(1, 3, CV_32F); } + +TEST(Core_IOArray, submat_create) +{ + Mat1f A = Mat1f::zeros(2,2); + + EXPECT_THROW( OutputArray_create1(A.row(0)), cv::Exception ); + EXPECT_THROW( OutputArray_create2(A.row(0)), cv::Exception ); +} + +TEST(Core_Mat, reshape_1942) +{ + cv::Mat A = (cv::Mat_(2,3) << 3.4884074, 1.4159607, 0.78737736, 2.3456569, -0.88010466, 0.3009364); + int cn = 0; + ASSERT_NO_THROW( + cv::Mat_ M = A.reshape(3); + cn = M.channels(); + ); + ASSERT_EQ(1, cn); +} \ No newline at end of file diff --git a/core/test/test_math.cpp b/core/test/test_math.cpp new file mode 100644 index 0000000..94b07a6 --- /dev/null +++ b/core/test/test_math.cpp @@ -0,0 +1,2602 @@ +////////////////////////////////////////////////////////////////////////////////////////// +/////////////////// tests for matrix operations and math functions /////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// + +#include "test_precomp.hpp" +#include +#include + +using namespace cv; +using namespace std; + +/// !!! NOTE !!! These tests happily avoid overflow cases & out-of-range arguments +/// so that output arrays contain neigher Inf's nor Nan's. +/// Handling such cases would require special modification of check function +/// (validate_test_results) => TBD. +/// Also, need some logarithmic-scale generation of input data. Right now it is done (in some tests) +/// by generating min/max boundaries for random data in logarimithic scale, but +/// within the same test case all the input array elements are of the same order. + +class Core_MathTest : public cvtest::ArrayTest +{ +public: + typedef cvtest::ArrayTest Base; + Core_MathTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, + vector >& types); + double get_success_error_level( int /*test_case_idx*/, int i, int j ); + bool test_nd; +}; + + +Core_MathTest::Core_MathTest() +{ + optional_mask = false; + + test_array[INPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + + test_nd = false; +} + + +double Core_MathTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) +{ + return test_mat[i][j].depth() == CV_32F ? FLT_EPSILON*128 : DBL_EPSILON*1024; +} + + +void Core_MathTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, + vector >& types) +{ + RNG& rng = ts->get_rng(); + int depth = cvtest::randInt(rng)%2 + CV_32F; + int cn = cvtest::randInt(rng) % 4 + 1, type = CV_MAKETYPE(depth, cn); + size_t i, j; + Base::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + for( i = 0; i < test_array.size(); i++ ) + { + size_t count = test_array[i].size(); + for( j = 0; j < count; j++ ) + types[i][j] = type; + } + test_nd = cvtest::randInt(rng)%3 == 0; +} + + +////////// pow ///////////// + +class Core_PowTest : public Core_MathTest +{ +public: + typedef Core_MathTest Base; + Core_PowTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, + vector >& types ); + void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ); + void run_func(); + void prepare_to_validation( int test_case_idx ); + double get_success_error_level( int test_case_idx, int i, int j ); + double power; +}; + + +Core_PowTest::Core_PowTest() +{ + power = 0; +} + + +void Core_PowTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, + vector >& types ) +{ + RNG& rng = ts->get_rng(); + int depth = cvtest::randInt(rng) % (CV_64F+1); + int cn = cvtest::randInt(rng) % 4 + 1; + size_t i, j; + Base::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + depth += depth == CV_8S; + + if( depth < CV_32F || cvtest::randInt(rng)%8 == 0 ) + // integer power + power = (int)(cvtest::randInt(rng)%21 - 10); + else + { + i = cvtest::randInt(rng)%17; + power = i == 16 ? 1./3 : i == 15 ? 0.5 : i == 14 ? -0.5 : cvtest::randReal(rng)*10 - 5; + } + + for( i = 0; i < test_array.size(); i++ ) + { + size_t count = test_array[i].size(); + int type = CV_MAKETYPE(depth, cn); + for( j = 0; j < count; j++ ) + types[i][j] = type; + } + test_nd = cvtest::randInt(rng)%3 == 0; +} + + +double Core_PowTest::get_success_error_level( int test_case_idx, int i, int j ) +{ + int depth = test_mat[i][j].depth(); + if( depth < CV_32F ) + return power == cvRound(power) && power >= 0 ? 0 : 1; + else + return Base::get_success_error_level( test_case_idx, i, j ); +} + + +void Core_PowTest::get_minmax_bounds( int /*i*/, int /*j*/, int type, Scalar& low, Scalar& high ) +{ + double l, u = cvtest::randInt(ts->get_rng())%1000 + 1; + if( power > 0 ) + { + double mval = cvtest::getMaxVal(type); + double u1 = pow(mval,1./power)*2; + u = MIN(u,u1); + } + + l = power == cvRound(power) ? -u : FLT_EPSILON; + low = Scalar::all(l); + high = Scalar::all(u); +} + + +void Core_PowTest::run_func() +{ + if(!test_nd) + { + if( fabs(power-1./3) <= DBL_EPSILON && test_mat[INPUT][0].depth() == CV_32F ) + { + Mat a = test_mat[INPUT][0], b = test_mat[OUTPUT][0]; + + a = a.reshape(1); + b = b.reshape(1); + for( int i = 0; i < a.rows; i++ ) + { + b.at(i,0) = (float)fabs(cvCbrt(a.at(i,0))); + for( int j = 1; j < a.cols; j++ ) + b.at(i,j) = (float)fabs(cv::cubeRoot(a.at(i,j))); + } + } + else + cvPow( test_array[INPUT][0], test_array[OUTPUT][0], power ); + } + else + { + Mat& a = test_mat[INPUT][0]; + Mat& b = test_mat[OUTPUT][0]; + if(power == 0.5) + cv::sqrt(a, b); + else + cv::pow(a, power, b); + } +} + + +inline static int ipow( int a, int power ) +{ + int b = 1; + while( power > 0 ) + { + if( power&1 ) + b *= a, power--; + else + a *= a, power >>= 1; + } + return b; +} + + +inline static double ipow( double a, int power ) +{ + double b = 1.; + while( power > 0 ) + { + if( power&1 ) + b *= a, power--; + else + a *= a, power >>= 1; + } + return b; +} + + +void Core_PowTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + const Mat& a = test_mat[INPUT][0]; + Mat& b = test_mat[REF_OUTPUT][0]; + + int depth = a.depth(); + int ncols = a.cols*a.channels(); + int ipower = cvRound(power), apower = abs(ipower); + int i, j; + + for( i = 0; i < a.rows; i++ ) + { + const uchar* a_data = a.ptr(i); + uchar* b_data = b.ptr(i); + + switch( depth ) + { + case CV_8U: + if( ipower < 0 ) + for( j = 0; j < ncols; j++ ) + { + int val = ((uchar*)a_data)[j]; + ((uchar*)b_data)[j] = (uchar)(val <= 1 ? val : + val == 2 && ipower == -1 ? 1 : 0); + } + else + for( j = 0; j < ncols; j++ ) + { + int val = ((uchar*)a_data)[j]; + val = ipow( val, ipower ); + ((uchar*)b_data)[j] = saturate_cast(val); + } + break; + case CV_8S: + if( ipower < 0 ) + for( j = 0; j < ncols; j++ ) + { + int val = ((char*)a_data)[j]; + ((char*)b_data)[j] = (char)((val&~1)==0 ? val : + val ==-1 ? 1-2*(ipower&1) : + val == 2 && ipower == -1 ? 1 : 0); + } + else + for( j = 0; j < ncols; j++ ) + { + int val = ((char*)a_data)[j]; + val = ipow( val, ipower ); + ((char*)b_data)[j] = saturate_cast(val); + } + break; + case CV_16U: + if( ipower < 0 ) + for( j = 0; j < ncols; j++ ) + { + int val = ((ushort*)a_data)[j]; + ((ushort*)b_data)[j] = (ushort)((val&~1)==0 ? val : + val ==-1 ? 1-2*(ipower&1) : + val == 2 && ipower == -1 ? 1 : 0); + } + else + for( j = 0; j < ncols; j++ ) + { + int val = ((ushort*)a_data)[j]; + val = ipow( val, ipower ); + ((ushort*)b_data)[j] = saturate_cast(val); + } + break; + case CV_16S: + if( ipower < 0 ) + for( j = 0; j < ncols; j++ ) + { + int val = ((short*)a_data)[j]; + ((short*)b_data)[j] = (short)((val&~1)==0 ? val : + val ==-1 ? 1-2*(ipower&1) : + val == 2 && ipower == -1 ? 1 : 0); + } + else + for( j = 0; j < ncols; j++ ) + { + int val = ((short*)a_data)[j]; + val = ipow( val, ipower ); + ((short*)b_data)[j] = saturate_cast(val); + } + break; + case CV_32S: + if( ipower < 0 ) + for( j = 0; j < ncols; j++ ) + { + int val = ((int*)a_data)[j]; + ((int*)b_data)[j] = (val&~1)==0 ? val : + val ==-1 ? 1-2*(ipower&1) : + val == 2 && ipower == -1 ? 1 : 0; + } + else + for( j = 0; j < ncols; j++ ) + { + int val = ((int*)a_data)[j]; + val = ipow( val, ipower ); + ((int*)b_data)[j] = val; + } + break; + case CV_32F: + if( power != ipower ) + for( j = 0; j < ncols; j++ ) + { + double val = ((float*)a_data)[j]; + val = pow( fabs(val), power ); + ((float*)b_data)[j] = (float)val; + } + else + for( j = 0; j < ncols; j++ ) + { + double val = ((float*)a_data)[j]; + if( ipower < 0 ) + val = 1./val; + val = ipow( val, apower ); + ((float*)b_data)[j] = (float)val; + } + break; + case CV_64F: + if( power != ipower ) + for( j = 0; j < ncols; j++ ) + { + double val = ((double*)a_data)[j]; + val = pow( fabs(val), power ); + ((double*)b_data)[j] = (double)val; + } + else + for( j = 0; j < ncols; j++ ) + { + double val = ((double*)a_data)[j]; + if( ipower < 0 ) + val = 1./val; + val = ipow( val, apower ); + ((double*)b_data)[j] = (double)val; + } + break; + } + } +} + + + +///////////////////////////////////////// matrix tests //////////////////////////////////////////// + +class Core_MatrixTest : public cvtest::ArrayTest +{ +public: + typedef cvtest::ArrayTest Base; + Core_MatrixTest( int in_count, int out_count, + bool allow_int, bool scalar_output, int max_cn ); +protected: + void get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, + vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + bool allow_int; + bool scalar_output; + int max_cn; +}; + + +Core_MatrixTest::Core_MatrixTest( int in_count, int out_count, + bool _allow_int, bool _scalar_output, int _max_cn ) +: allow_int(_allow_int), scalar_output(_scalar_output), max_cn(_max_cn) +{ + int i; + for( i = 0; i < in_count; i++ ) + test_array[INPUT].push_back(NULL); + + for( i = 0; i < out_count; i++ ) + { + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + } + + element_wise_relative_error = false; +} + + +void Core_MatrixTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, + vector >& types ) +{ + RNG& rng = ts->get_rng(); + int depth = cvtest::randInt(rng) % (allow_int ? CV_64F+1 : 2); + int cn = cvtest::randInt(rng) % max_cn + 1; + size_t i, j; + + if( allow_int ) + depth += depth == CV_8S; + else + depth += CV_32F; + + Base::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + for( i = 0; i < test_array.size(); i++ ) + { + size_t count = test_array[i].size(); + int flag = (i == OUTPUT || i == REF_OUTPUT) && scalar_output; + int type = !flag ? CV_MAKETYPE(depth, cn) : CV_64FC1; + + for( j = 0; j < count; j++ ) + { + types[i][j] = type; + if( flag ) + sizes[i][j] = Size( 4, 1 ); + } + } +} + + +double Core_MatrixTest::get_success_error_level( int test_case_idx, int i, int j ) +{ + int input_depth = test_mat[INPUT][0].depth(); + double input_precision = input_depth < CV_32F ? 0 : input_depth == CV_32F ? 5e-5 : 5e-10; + double output_precision = Base::get_success_error_level( test_case_idx, i, j ); + return MAX(input_precision, output_precision); +} + + +///////////////// Trace ///////////////////// + +class Core_TraceTest : public Core_MatrixTest +{ +public: + Core_TraceTest(); +protected: + void run_func(); + void prepare_to_validation( int test_case_idx ); +}; + + +Core_TraceTest::Core_TraceTest() : Core_MatrixTest( 1, 1, true, true, 4 ) +{ +} + + +void Core_TraceTest::run_func() +{ + test_mat[OUTPUT][0].at(0,0) = cvTrace(test_array[INPUT][0]); +} + + +void Core_TraceTest::prepare_to_validation( int ) +{ + Mat& mat = test_mat[INPUT][0]; + int count = MIN( mat.rows, mat.cols ); + Mat diag(count, 1, mat.type(), mat.data, mat.step + mat.elemSize()); + Scalar r = cvtest::mean(diag); + r *= (double)count; + + test_mat[REF_OUTPUT][0].at(0,0) = r; +} + + +///////// dotproduct ////////// + +class Core_DotProductTest : public Core_MatrixTest +{ +public: + Core_DotProductTest(); +protected: + void run_func(); + void prepare_to_validation( int test_case_idx ); +}; + + +Core_DotProductTest::Core_DotProductTest() : Core_MatrixTest( 2, 1, true, true, 4 ) +{ +} + + +void Core_DotProductTest::run_func() +{ + test_mat[OUTPUT][0].at(0,0) = Scalar(cvDotProduct( test_array[INPUT][0], test_array[INPUT][1] )); +} + + +void Core_DotProductTest::prepare_to_validation( int ) +{ + test_mat[REF_OUTPUT][0].at(0,0) = Scalar(cvtest::crossCorr( test_mat[INPUT][0], test_mat[INPUT][1] )); +} + + +///////// crossproduct ////////// + +class Core_CrossProductTest : public Core_MatrixTest +{ +public: + Core_CrossProductTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, + vector >& types ); + void run_func(); + void prepare_to_validation( int test_case_idx ); +}; + + +Core_CrossProductTest::Core_CrossProductTest() : Core_MatrixTest( 2, 1, false, false, 1 ) +{ +} + + +void Core_CrossProductTest::get_test_array_types_and_sizes( int, + vector >& sizes, + vector >& types ) +{ + RNG& rng = ts->get_rng(); + int depth = cvtest::randInt(rng) % 2 + CV_32F; + int cn = cvtest::randInt(rng) & 1 ? 3 : 1, type = CV_MAKETYPE(depth, cn); + CvSize sz; + + types[INPUT][0] = types[INPUT][1] = types[OUTPUT][0] = types[REF_OUTPUT][0] = type; + + if( cn == 3 ) + sz = Size(1,1); + else if( cvtest::randInt(rng) & 1 ) + sz = Size(3,1); + else + sz = Size(1,3); + + sizes[INPUT][0] = sizes[INPUT][1] = sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz; +} + + +void Core_CrossProductTest::run_func() +{ + cvCrossProduct( test_array[INPUT][0], test_array[INPUT][1], test_array[OUTPUT][0] ); +} + + +void Core_CrossProductTest::prepare_to_validation( int ) +{ + CvScalar a = {{0,0,0,0}}, b = {{0,0,0,0}}, c = {{0,0,0,0}}; + + if( test_mat[INPUT][0].rows > 1 ) + { + a.val[0] = cvGetReal2D( test_array[INPUT][0], 0, 0 ); + a.val[1] = cvGetReal2D( test_array[INPUT][0], 1, 0 ); + a.val[2] = cvGetReal2D( test_array[INPUT][0], 2, 0 ); + + b.val[0] = cvGetReal2D( test_array[INPUT][1], 0, 0 ); + b.val[1] = cvGetReal2D( test_array[INPUT][1], 1, 0 ); + b.val[2] = cvGetReal2D( test_array[INPUT][1], 2, 0 ); + } + else if( test_mat[INPUT][0].cols > 1 ) + { + a.val[0] = cvGetReal1D( test_array[INPUT][0], 0 ); + a.val[1] = cvGetReal1D( test_array[INPUT][0], 1 ); + a.val[2] = cvGetReal1D( test_array[INPUT][0], 2 ); + + b.val[0] = cvGetReal1D( test_array[INPUT][1], 0 ); + b.val[1] = cvGetReal1D( test_array[INPUT][1], 1 ); + b.val[2] = cvGetReal1D( test_array[INPUT][1], 2 ); + } + else + { + a = cvGet1D( test_array[INPUT][0], 0 ); + b = cvGet1D( test_array[INPUT][1], 0 ); + } + + c.val[2] = a.val[0]*b.val[1] - a.val[1]*b.val[0]; + c.val[1] = -a.val[0]*b.val[2] + a.val[2]*b.val[0]; + c.val[0] = a.val[1]*b.val[2] - a.val[2]*b.val[1]; + + if( test_mat[REF_OUTPUT][0].rows > 1 ) + { + cvSetReal2D( test_array[REF_OUTPUT][0], 0, 0, c.val[0] ); + cvSetReal2D( test_array[REF_OUTPUT][0], 1, 0, c.val[1] ); + cvSetReal2D( test_array[REF_OUTPUT][0], 2, 0, c.val[2] ); + } + else if( test_mat[REF_OUTPUT][0].cols > 1 ) + { + cvSetReal1D( test_array[REF_OUTPUT][0], 0, c.val[0] ); + cvSetReal1D( test_array[REF_OUTPUT][0], 1, c.val[1] ); + cvSetReal1D( test_array[REF_OUTPUT][0], 2, c.val[2] ); + } + else + { + cvSet1D( test_array[REF_OUTPUT][0], 0, c ); + } +} + + +///////////////// gemm ///////////////////// + +class Core_GEMMTest : public Core_MatrixTest +{ +public: + typedef Core_MatrixTest Base; + Core_GEMMTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ); + int prepare_test_case( int test_case_idx ); + void run_func(); + void prepare_to_validation( int test_case_idx ); + int tabc_flag; + double alpha, beta; +}; + +Core_GEMMTest::Core_GEMMTest() : Core_MatrixTest( 5, 1, false, false, 2 ) +{ + test_case_count = 100; + max_log_array_size = 10; + alpha = beta = 0; +} + + +void Core_GEMMTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + Size sizeA; + Base::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + sizeA = sizes[INPUT][0]; + Base::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + sizes[INPUT][0] = sizeA; + sizes[INPUT][2] = sizes[INPUT][3] = Size(1,1); + types[INPUT][2] = types[INPUT][3] &= ~CV_MAT_CN_MASK; + + tabc_flag = cvtest::randInt(rng) & 7; + + switch( tabc_flag & (CV_GEMM_A_T|CV_GEMM_B_T) ) + { + case 0: + sizes[INPUT][1].height = sizes[INPUT][0].width; + sizes[OUTPUT][0].height = sizes[INPUT][0].height; + sizes[OUTPUT][0].width = sizes[INPUT][1].width; + break; + case CV_GEMM_B_T: + sizes[INPUT][1].width = sizes[INPUT][0].width; + sizes[OUTPUT][0].height = sizes[INPUT][0].height; + sizes[OUTPUT][0].width = sizes[INPUT][1].height; + break; + case CV_GEMM_A_T: + sizes[INPUT][1].height = sizes[INPUT][0].height; + sizes[OUTPUT][0].height = sizes[INPUT][0].width; + sizes[OUTPUT][0].width = sizes[INPUT][1].width; + break; + case CV_GEMM_A_T | CV_GEMM_B_T: + sizes[INPUT][1].width = sizes[INPUT][0].height; + sizes[OUTPUT][0].height = sizes[INPUT][0].width; + sizes[OUTPUT][0].width = sizes[INPUT][1].height; + break; + } + + sizes[REF_OUTPUT][0] = sizes[OUTPUT][0]; + + if( cvtest::randInt(rng) & 1 ) + sizes[INPUT][4] = Size(0,0); + else if( !(tabc_flag & CV_GEMM_C_T) ) + sizes[INPUT][4] = sizes[OUTPUT][0]; + else + { + sizes[INPUT][4].width = sizes[OUTPUT][0].height; + sizes[INPUT][4].height = sizes[OUTPUT][0].width; + } +} + + +int Core_GEMMTest::prepare_test_case( int test_case_idx ) +{ + int code = Base::prepare_test_case( test_case_idx ); + if( code > 0 ) + { + alpha = cvGetReal2D( test_array[INPUT][2], 0, 0 ); + beta = cvGetReal2D( test_array[INPUT][3], 0, 0 ); + } + return code; +} + + +void Core_GEMMTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ) +{ + low = Scalar::all(-10.); + high = Scalar::all(10.); +} + + +void Core_GEMMTest::run_func() +{ + cvGEMM( test_array[INPUT][0], test_array[INPUT][1], alpha, + test_array[INPUT][4], beta, test_array[OUTPUT][0], tabc_flag ); +} + + +void Core_GEMMTest::prepare_to_validation( int ) +{ + cvtest::gemm( test_mat[INPUT][0], test_mat[INPUT][1], alpha, + test_array[INPUT][4] ? test_mat[INPUT][4] : Mat(), + beta, test_mat[REF_OUTPUT][0], tabc_flag ); +} + + +///////////////// multransposed ///////////////////// + +class Core_MulTransposedTest : public Core_MatrixTest +{ +public: + Core_MulTransposedTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ); + void run_func(); + void prepare_to_validation( int test_case_idx ); + int order; +}; + + +Core_MulTransposedTest::Core_MulTransposedTest() : Core_MatrixTest( 2, 1, false, false, 1 ) +{ + test_case_count = 100; + order = 0; + test_array[TEMP].push_back(NULL); +} + + +void Core_MulTransposedTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + int bits = cvtest::randInt(rng); + int src_type = cvtest::randInt(rng) % 5; + int dst_type = cvtest::randInt(rng) % 2; + + src_type = src_type == 0 ? CV_8U : src_type == 1 ? CV_16U : src_type == 2 ? CV_16S : + src_type == 3 ? CV_32F : CV_64F; + dst_type = dst_type == 0 ? CV_32F : CV_64F; + dst_type = MAX( dst_type, src_type ); + + Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + if( bits & 1 ) + sizes[INPUT][1] = Size(0,0); + else + { + sizes[INPUT][1] = sizes[INPUT][0]; + if( bits & 2 ) + sizes[INPUT][1].height = 1; + if( bits & 4 ) + sizes[INPUT][1].width = 1; + } + + sizes[TEMP][0] = sizes[INPUT][0]; + types[INPUT][0] = src_type; + types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][1] = types[TEMP][0] = dst_type; + + order = (bits & 8) != 0; + sizes[OUTPUT][0].width = sizes[OUTPUT][0].height = order == 0 ? + sizes[INPUT][0].height : sizes[INPUT][0].width; + sizes[REF_OUTPUT][0] = sizes[OUTPUT][0]; +} + + +void Core_MulTransposedTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ) +{ + low = cvScalarAll(-10.); + high = cvScalarAll(10.); +} + + +void Core_MulTransposedTest::run_func() +{ + cvMulTransposed( test_array[INPUT][0], test_array[OUTPUT][0], + order, test_array[INPUT][1] ); +} + + +void Core_MulTransposedTest::prepare_to_validation( int ) +{ + const Mat& src = test_mat[INPUT][0]; + Mat delta = test_mat[INPUT][1]; + Mat& temp = test_mat[TEMP][0]; + if( !delta.empty() ) + { + if( delta.rows < src.rows || delta.cols < src.cols ) + { + cv::repeat( delta, src.rows/delta.rows, src.cols/delta.cols, temp); + delta = temp; + } + cvtest::add( src, 1, delta, -1, Scalar::all(0), temp, temp.type()); + } + else + src.convertTo(temp, temp.type()); + + cvtest::gemm( temp, temp, 1., Mat(), 0, test_mat[REF_OUTPUT][0], order == 0 ? GEMM_2_T : GEMM_1_T ); +} + + +///////////////// Transform ///////////////////// + +class Core_TransformTest : public Core_MatrixTest +{ +public: + typedef Core_MatrixTest Base; + Core_TransformTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + int prepare_test_case( int test_case_idx ); + void run_func(); + void prepare_to_validation( int test_case_idx ); + + double scale; + bool diagMtx; +}; + + +Core_TransformTest::Core_TransformTest() : Core_MatrixTest( 3, 1, true, false, 4 ) +{ +} + + +void Core_TransformTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + int bits = cvtest::randInt(rng); + int depth, dst_cn, mat_cols, mattype; + Base::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + mat_cols = CV_MAT_CN(types[INPUT][0]); + depth = CV_MAT_DEPTH(types[INPUT][0]); + dst_cn = cvtest::randInt(rng) % 4 + 1; + types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, dst_cn); + + mattype = depth < CV_32S ? CV_32F : depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F; + types[INPUT][1] = mattype; + types[INPUT][2] = CV_MAKETYPE(mattype, dst_cn); + + scale = 1./((cvtest::randInt(rng)%4)*50+1); + + if( bits & 2 ) + { + sizes[INPUT][2] = Size(0,0); + mat_cols += (bits & 4) != 0; + } + else if( bits & 4 ) + sizes[INPUT][2] = Size(1,1); + else + { + if( bits & 8 ) + sizes[INPUT][2] = Size(dst_cn,1); + else + sizes[INPUT][2] = Size(1,dst_cn); + types[INPUT][2] &= ~CV_MAT_CN_MASK; + } + diagMtx = (bits & 16) != 0; + + sizes[INPUT][1] = Size(mat_cols,dst_cn); +} + + +int Core_TransformTest::prepare_test_case( int test_case_idx ) +{ + int code = Base::prepare_test_case( test_case_idx ); + if( code > 0 ) + { + Mat& m = test_mat[INPUT][1]; + cvtest::add(m, scale, m, 0, Scalar::all(0), m, m.type() ); + if(diagMtx) + { + Mat mask = Mat::eye(m.rows, m.cols, CV_8U)*255; + mask = ~mask; + m.setTo(Scalar::all(0), mask); + } + } + return code; +} + + +double Core_TransformTest::get_success_error_level( int test_case_idx, int i, int j ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth <= CV_8S ? 1 : depth <= CV_32S ? 9 : Base::get_success_error_level( test_case_idx, i, j ); +} + +void Core_TransformTest::run_func() +{ + CvMat _m = test_mat[INPUT][1], _shift = test_mat[INPUT][2]; + cvTransform( test_array[INPUT][0], test_array[OUTPUT][0], &_m, _shift.data.ptr ? &_shift : 0); +} + + +void Core_TransformTest::prepare_to_validation( int ) +{ + Mat transmat = test_mat[INPUT][1]; + Mat shift = test_mat[INPUT][2]; + + cvtest::transform( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], transmat, shift ); +} + + +///////////////// PerspectiveTransform ///////////////////// + +class Core_PerspectiveTransformTest : public Core_MatrixTest +{ +public: + Core_PerspectiveTransformTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void run_func(); + void prepare_to_validation( int test_case_idx ); +}; + + +Core_PerspectiveTransformTest::Core_PerspectiveTransformTest() : Core_MatrixTest( 2, 1, false, false, 2 ) +{ +} + + +void Core_PerspectiveTransformTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + int bits = cvtest::randInt(rng); + int depth, cn, mattype; + Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + cn = CV_MAT_CN(types[INPUT][0]) + 1; + depth = CV_MAT_DEPTH(types[INPUT][0]); + types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn); + + mattype = depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F; + types[INPUT][1] = mattype; + sizes[INPUT][1] = Size(cn + 1, cn + 1); +} + + +double Core_PerspectiveTransformTest::get_success_error_level( int test_case_idx, int i, int j ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth == CV_32F ? 1e-4 : depth == CV_64F ? 1e-8 : + Core_MatrixTest::get_success_error_level(test_case_idx, i, j); +} + + +void Core_PerspectiveTransformTest::run_func() +{ + CvMat _m = test_mat[INPUT][1]; + cvPerspectiveTransform( test_array[INPUT][0], test_array[OUTPUT][0], &_m ); +} + + +static void cvTsPerspectiveTransform( const CvArr* _src, CvArr* _dst, const CvMat* transmat ) +{ + int i, j, cols; + int cn, depth, mat_depth; + CvMat astub, bstub, *a, *b; + double mat[16]; + + a = cvGetMat( _src, &astub, 0, 0 ); + b = cvGetMat( _dst, &bstub, 0, 0 ); + + cn = CV_MAT_CN(a->type); + depth = CV_MAT_DEPTH(a->type); + mat_depth = CV_MAT_DEPTH(transmat->type); + cols = transmat->cols; + + // prepare cn x (cn + 1) transform matrix + if( mat_depth == CV_32F ) + { + for( i = 0; i < transmat->rows; i++ ) + for( j = 0; j < cols; j++ ) + mat[i*cols + j] = ((float*)(transmat->data.ptr + transmat->step*i))[j]; + } + else + { + assert( mat_depth == CV_64F ); + for( i = 0; i < transmat->rows; i++ ) + for( j = 0; j < cols; j++ ) + mat[i*cols + j] = ((double*)(transmat->data.ptr + transmat->step*i))[j]; + } + + // transform data + cols = a->cols * cn; + vector buf(cols); + + for( i = 0; i < a->rows; i++ ) + { + uchar* src = a->data.ptr + i*a->step; + uchar* dst = b->data.ptr + i*b->step; + + switch( depth ) + { + case CV_32F: + for( j = 0; j < cols; j++ ) + buf[j] = ((float*)src)[j]; + break; + case CV_64F: + for( j = 0; j < cols; j++ ) + buf[j] = ((double*)src)[j]; + break; + default: + assert(0); + } + + switch( cn ) + { + case 2: + for( j = 0; j < cols; j += 2 ) + { + double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + mat[2]; + double t1 = buf[j]*mat[3] + buf[j+1]*mat[4] + mat[5]; + double w = buf[j]*mat[6] + buf[j+1]*mat[7] + mat[8]; + w = w ? 1./w : 0; + buf[j] = t0*w; + buf[j+1] = t1*w; + } + break; + case 3: + for( j = 0; j < cols; j += 3 ) + { + double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + buf[j+2]*mat[2] + mat[3]; + double t1 = buf[j]*mat[4] + buf[j+1]*mat[5] + buf[j+2]*mat[6] + mat[7]; + double t2 = buf[j]*mat[8] + buf[j+1]*mat[9] + buf[j+2]*mat[10] + mat[11]; + double w = buf[j]*mat[12] + buf[j+1]*mat[13] + buf[j+2]*mat[14] + mat[15]; + w = w ? 1./w : 0; + buf[j] = t0*w; + buf[j+1] = t1*w; + buf[j+2] = t2*w; + } + break; + default: + assert(0); + } + + switch( depth ) + { + case CV_32F: + for( j = 0; j < cols; j++ ) + ((float*)dst)[j] = (float)buf[j]; + break; + case CV_64F: + for( j = 0; j < cols; j++ ) + ((double*)dst)[j] = buf[j]; + break; + default: + assert(0); + } + } +} + + +void Core_PerspectiveTransformTest::prepare_to_validation( int ) +{ + CvMat transmat = test_mat[INPUT][1]; + cvTsPerspectiveTransform( test_array[INPUT][0], test_array[REF_OUTPUT][0], &transmat ); +} + +///////////////// Mahalanobis ///////////////////// + +class Core_MahalanobisTest : public Core_MatrixTest +{ +public: + typedef Core_MatrixTest Base; + Core_MahalanobisTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + int prepare_test_case( int test_case_idx ); + void run_func(); + void prepare_to_validation( int test_case_idx ); +}; + + +Core_MahalanobisTest::Core_MahalanobisTest() : Core_MatrixTest( 3, 1, false, true, 1 ) +{ + test_case_count = 100; + test_array[TEMP].push_back(NULL); + test_array[TEMP].push_back(NULL); + test_array[TEMP].push_back(NULL); +} + + +void Core_MahalanobisTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + if( cvtest::randInt(rng) & 1 ) + sizes[INPUT][0].width = sizes[INPUT][1].width = 1; + else + sizes[INPUT][0].height = sizes[INPUT][1].height = 1; + + sizes[TEMP][0] = sizes[TEMP][1] = sizes[INPUT][0]; + sizes[INPUT][2].width = sizes[INPUT][2].height = sizes[INPUT][0].width + sizes[INPUT][0].height - 1; + sizes[TEMP][2] = sizes[INPUT][2]; + types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0]; +} + +int Core_MahalanobisTest::prepare_test_case( int test_case_idx ) +{ + int code = Base::prepare_test_case( test_case_idx ); + if( code > 0 ) + { + // make sure that the inverted "covariation" matrix is symmetrix and positively defined. + cvtest::gemm( test_mat[INPUT][2], test_mat[INPUT][2], 1., Mat(), 0., test_mat[TEMP][2], GEMM_2_T ); + cvtest::copy( test_mat[TEMP][2], test_mat[INPUT][2] ); + } + + return code; +} + + +void Core_MahalanobisTest::run_func() +{ + test_mat[OUTPUT][0].at(0,0) = + cvRealScalar(cvMahalanobis(test_array[INPUT][0], test_array[INPUT][1], test_array[INPUT][2])); +} + +void Core_MahalanobisTest::prepare_to_validation( int ) +{ + cvtest::add( test_mat[INPUT][0], 1., test_mat[INPUT][1], -1., + Scalar::all(0), test_mat[TEMP][0], test_mat[TEMP][0].type() ); + if( test_mat[INPUT][0].rows == 1 ) + cvtest::gemm( test_mat[TEMP][0], test_mat[INPUT][2], 1., + Mat(), 0., test_mat[TEMP][1], 0 ); + else + cvtest::gemm( test_mat[INPUT][2], test_mat[TEMP][0], 1., + Mat(), 0., test_mat[TEMP][1], 0 ); + + test_mat[REF_OUTPUT][0].at(0,0) = cvRealScalar(sqrt(cvtest::crossCorr(test_mat[TEMP][0], test_mat[TEMP][1]))); +} + + +///////////////// covarmatrix ///////////////////// + +class Core_CovarMatrixTest : public Core_MatrixTest +{ +public: + Core_CovarMatrixTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + int prepare_test_case( int test_case_idx ); + void run_func(); + void prepare_to_validation( int test_case_idx ); + vector temp_hdrs; + vector hdr_data; + int flags, t_flag, len, count; + bool are_images; +}; + + +Core_CovarMatrixTest::Core_CovarMatrixTest() : Core_MatrixTest( 1, 1, true, false, 1 ), +flags(0), t_flag(0), are_images(false) +{ + test_case_count = 100; + test_array[INPUT_OUTPUT].push_back(NULL); + test_array[REF_INPUT_OUTPUT].push_back(NULL); + test_array[TEMP].push_back(NULL); + test_array[TEMP].push_back(NULL); +} + + +void Core_CovarMatrixTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + int bits = cvtest::randInt(rng); + int i, single_matrix; + Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + flags = bits & (CV_COVAR_NORMAL | CV_COVAR_USE_AVG | CV_COVAR_SCALE | CV_COVAR_ROWS ); + single_matrix = flags & CV_COVAR_ROWS; + t_flag = (bits & 256) != 0; + + const int min_count = 2; + + if( !t_flag ) + { + len = sizes[INPUT][0].width; + count = sizes[INPUT][0].height; + count = MAX(count, min_count); + sizes[INPUT][0] = Size(len, count); + } + else + { + len = sizes[INPUT][0].height; + count = sizes[INPUT][0].width; + count = MAX(count, min_count); + sizes[INPUT][0] = Size(count, len); + } + + if( single_matrix && t_flag ) + flags = (flags & ~CV_COVAR_ROWS) | CV_COVAR_COLS; + + if( CV_MAT_DEPTH(types[INPUT][0]) == CV_32S ) + types[INPUT][0] = (types[INPUT][0] & ~CV_MAT_DEPTH_MASK) | CV_32F; + + sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = flags & CV_COVAR_NORMAL ? Size(len,len) : Size(count,count); + sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = !t_flag ? Size(len,1) : Size(1,len); + sizes[TEMP][0] = sizes[INPUT][0]; + + types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = + types[OUTPUT][0] = types[REF_OUTPUT][0] = types[TEMP][0] = + CV_MAT_DEPTH(types[INPUT][0]) == CV_64F || (bits & 512) ? CV_64F : CV_32F; + + are_images = (bits & 1024) != 0; + for( i = 0; i < (single_matrix ? 1 : count); i++ ) + temp_hdrs.push_back(NULL); +} + + +int Core_CovarMatrixTest::prepare_test_case( int test_case_idx ) +{ + int code = Core_MatrixTest::prepare_test_case( test_case_idx ); + if( code > 0 ) + { + int i; + int single_matrix = flags & (CV_COVAR_ROWS|CV_COVAR_COLS); + int hdr_size = are_images ? sizeof(IplImage) : sizeof(CvMat); + + hdr_data.resize(count*hdr_size); + uchar* _hdr_data = &hdr_data[0]; + if( single_matrix ) + { + if( !are_images ) + *((CvMat*)_hdr_data) = test_mat[INPUT][0]; + else + *((IplImage*)_hdr_data) = test_mat[INPUT][0]; + temp_hdrs[0] = _hdr_data; + } + else + for( i = 0; i < count; i++ ) + { + Mat part; + void* ptr = _hdr_data + i*hdr_size; + + if( !t_flag ) + part = test_mat[INPUT][0].row(i); + else + part = test_mat[INPUT][0].col(i); + + if( !are_images ) + *((CvMat*)ptr) = part; + else + *((IplImage*)ptr) = part; + + temp_hdrs[i] = ptr; + } + } + + return code; +} + + +void Core_CovarMatrixTest::run_func() +{ + cvCalcCovarMatrix( (const void**)&temp_hdrs[0], count, + test_array[OUTPUT][0], test_array[INPUT_OUTPUT][0], flags ); +} + + +void Core_CovarMatrixTest::prepare_to_validation( int ) +{ + Mat& avg = test_mat[REF_INPUT_OUTPUT][0]; + double scale = 1.; + + if( !(flags & CV_COVAR_USE_AVG) ) + { + Mat hdrs0 = cvarrToMat(temp_hdrs[0]); + + int i; + avg = Scalar::all(0); + + for( i = 0; i < count; i++ ) + { + Mat vec; + if( flags & CV_COVAR_ROWS ) + vec = hdrs0.row(i); + else if( flags & CV_COVAR_COLS ) + vec = hdrs0.col(i); + else + vec = cvarrToMat(temp_hdrs[i]); + + cvtest::add(avg, 1, vec, 1, Scalar::all(0), avg, avg.type()); + } + + cvtest::add(avg, 1./count, avg, 0., Scalar::all(0), avg, avg.type()); + } + + if( flags & CV_COVAR_SCALE ) + { + scale = 1./count; + } + + Mat& temp0 = test_mat[TEMP][0]; + cv::repeat( avg, temp0.rows/avg.rows, temp0.cols/avg.cols, temp0 ); + cvtest::add( test_mat[INPUT][0], 1, temp0, -1, Scalar::all(0), temp0, temp0.type()); + + cvtest::gemm( temp0, temp0, scale, Mat(), 0., test_mat[REF_OUTPUT][0], + t_flag ^ ((flags & CV_COVAR_NORMAL) != 0) ? CV_GEMM_A_T : CV_GEMM_B_T ); + temp_hdrs.clear(); +} + + +static void cvTsFloodWithZeros( Mat& mat, RNG& rng ) +{ + int k, total = mat.rows*mat.cols, type = mat.type(); + int zero_total = cvtest::randInt(rng) % total; + CV_Assert( type == CV_32FC1 || type == CV_64FC1 ); + + for( k = 0; k < zero_total; k++ ) + { + int i = cvtest::randInt(rng) % mat.rows; + int j = cvtest::randInt(rng) % mat.cols; + + if( type == CV_32FC1 ) + mat.at(i,j) = 0.f; + else + mat.at(i,j) = 0.; + } +} + + +///////////////// determinant ///////////////////// + +class Core_DetTest : public Core_MatrixTest +{ +public: + typedef Core_MatrixTest Base; + Core_DetTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ); + int prepare_test_case( int test_case_idx ); + void run_func(); + void prepare_to_validation( int test_case_idx ); +}; + + +Core_DetTest::Core_DetTest() : Core_MatrixTest( 1, 1, false, true, 1 ) +{ + test_case_count = 100; + max_log_array_size = 7; + test_array[TEMP].push_back(NULL); +} + + +void Core_DetTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + Base::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + sizes[INPUT][0].width = sizes[INPUT][0].height = sizes[INPUT][0].height; + sizes[TEMP][0] = sizes[INPUT][0]; + types[TEMP][0] = CV_64FC1; +} + + +void Core_DetTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ) +{ + low = cvScalarAll(-2.); + high = cvScalarAll(2.); +} + + +double Core_DetTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-2 : 1e-5; +} + + +int Core_DetTest::prepare_test_case( int test_case_idx ) +{ + int code = Core_MatrixTest::prepare_test_case( test_case_idx ); + if( code > 0 ) + cvTsFloodWithZeros( test_mat[INPUT][0], ts->get_rng() ); + + return code; +} + + +void Core_DetTest::run_func() +{ + test_mat[OUTPUT][0].at(0,0) = cvRealScalar(cvDet(test_array[INPUT][0])); +} + + +// LU method that chooses the optimal in a column pivot element +static double cvTsLU( CvMat* a, CvMat* b=NULL, CvMat* x=NULL, int* rank=0 ) +{ + int i, j, k, N = a->rows, N1 = a->cols, Nm = MIN(N, N1), step = a->step/sizeof(double); + int M = b ? b->cols : 0, b_step = b ? b->step/sizeof(double) : 0; + int x_step = x ? x->step/sizeof(double) : 0; + double *a0 = a->data.db, *b0 = b ? b->data.db : 0; + double *x0 = x ? x->data.db : 0; + double t, det = 1.; + assert( CV_MAT_TYPE(a->type) == CV_64FC1 && + (!b || CV_ARE_TYPES_EQ(a,b)) && (!x || CV_ARE_TYPES_EQ(a,x))); + + for( i = 0; i < Nm; i++ ) + { + double max_val = fabs(a0[i*step + i]); + double *a1, *a2, *b1 = 0, *b2 = 0; + k = i; + + for( j = i+1; j < N; j++ ) + { + t = fabs(a0[j*step + i]); + if( max_val < t ) + { + max_val = t; + k = j; + } + } + + if( k != i ) + { + for( j = i; j < N1; j++ ) + CV_SWAP( a0[i*step + j], a0[k*step + j], t ); + + for( j = 0; j < M; j++ ) + CV_SWAP( b0[i*b_step + j], b0[k*b_step + j], t ); + det = -det; + } + + if( max_val == 0 ) + { + if( rank ) + *rank = i; + return 0.; + } + + a1 = a0 + i*step; + a2 = a1 + step; + b1 = b0 + i*b_step; + b2 = b1 + b_step; + + for( j = i+1; j < N; j++, a2 += step, b2 += b_step ) + { + t = a2[i]/a1[i]; + for( k = i+1; k < N1; k++ ) + a2[k] -= t*a1[k]; + + for( k = 0; k < M; k++ ) + b2[k] -= t*b1[k]; + } + + det *= a1[i]; + } + + if( x ) + { + assert( b ); + + for( i = N-1; i >= 0; i-- ) + { + double* a1 = a0 + i*step; + double* b1 = b0 + i*b_step; + for( j = 0; j < M; j++ ) + { + t = b1[j]; + for( k = i+1; k < N1; k++ ) + t -= a1[k]*x0[k*x_step + j]; + x0[i*x_step + j] = t/a1[i]; + } + } + } + + if( rank ) + *rank = i; + return det; +} + + +void Core_DetTest::prepare_to_validation( int ) +{ + test_mat[INPUT][0].convertTo(test_mat[TEMP][0], test_mat[TEMP][0].type()); + CvMat temp0 = test_mat[TEMP][0]; + test_mat[REF_OUTPUT][0].at(0,0) = cvRealScalar(cvTsLU(&temp0, 0, 0)); +} + + +///////////////// invert ///////////////////// + +class Core_InvertTest : public Core_MatrixTest +{ +public: + typedef Core_MatrixTest Base; + Core_InvertTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ); + double get_success_error_level( int test_case_idx, int i, int j ); + int prepare_test_case( int test_case_idx ); + void run_func(); + void prepare_to_validation( int test_case_idx ); + int method, rank; + double result; +}; + + +Core_InvertTest::Core_InvertTest() +: Core_MatrixTest( 1, 1, false, false, 1 ), method(0), rank(0), result(0.) +{ + test_case_count = 100; + max_log_array_size = 7; + test_array[TEMP].push_back(NULL); + test_array[TEMP].push_back(NULL); +} + + +void Core_InvertTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + int bits = cvtest::randInt(rng); + Base::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height ); + + if( (bits & 3) == 0 ) + { + method = CV_SVD; + if( bits & 4 ) + { + sizes[INPUT][0] = Size(min_size, min_size); + if( bits & 16 ) + method = CV_CHOLESKY; + } + } + else + { + method = CV_LU; + sizes[INPUT][0] = Size(min_size, min_size); + } + + sizes[TEMP][0].width = sizes[INPUT][0].height; + sizes[TEMP][0].height = sizes[INPUT][0].width; + sizes[TEMP][1] = sizes[INPUT][0]; + types[TEMP][0] = types[INPUT][0]; + types[TEMP][1] = CV_64FC1; + sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = Size(min_size, min_size); +} + + +double Core_InvertTest::get_success_error_level( int /*test_case_idx*/, int, int ) +{ + return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 1e-2 : 1e-6; +} + +int Core_InvertTest::prepare_test_case( int test_case_idx ) +{ + int code = Core_MatrixTest::prepare_test_case( test_case_idx ); + if( code > 0 ) + { + cvTsFloodWithZeros( test_mat[INPUT][0], ts->get_rng() ); + + if( method == CV_CHOLESKY ) + { + cvtest::gemm( test_mat[INPUT][0], test_mat[INPUT][0], 1., + Mat(), 0., test_mat[TEMP][0], CV_GEMM_B_T ); + cvtest::copy( test_mat[TEMP][0], test_mat[INPUT][0] ); + } + } + + return code; +} + + + +void Core_InvertTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ) +{ + low = cvScalarAll(-1.); + high = cvScalarAll(1.); +} + + +void Core_InvertTest::run_func() +{ + result = cvInvert(test_array[INPUT][0], test_array[TEMP][0], method); +} + + +static double cvTsSVDet( CvMat* mat, double* ratio ) +{ + int type = CV_MAT_TYPE(mat->type); + int i, nm = MIN( mat->rows, mat->cols ); + CvMat* w = cvCreateMat( nm, 1, type ); + double det = 1.; + + cvSVD( mat, w, 0, 0, 0 ); + + if( type == CV_32FC1 ) + { + for( i = 0; i < nm; i++ ) + det *= w->data.fl[i]; + *ratio = w->data.fl[nm-1] < FLT_EPSILON ? 0 : w->data.fl[nm-1]/w->data.fl[0]; + } + else + { + for( i = 0; i < nm; i++ ) + det *= w->data.db[i]; + *ratio = w->data.db[nm-1] < FLT_EPSILON ? 0 : w->data.db[nm-1]/w->data.db[0]; + } + + cvReleaseMat( &w ); + return det; +} + +void Core_InvertTest::prepare_to_validation( int ) +{ + Mat& input = test_mat[INPUT][0]; + Mat& temp0 = test_mat[TEMP][0]; + Mat& temp1 = test_mat[TEMP][1]; + Mat& dst0 = test_mat[REF_OUTPUT][0]; + Mat& dst = test_mat[OUTPUT][0]; + CvMat _input = input; + double ratio = 0, det = cvTsSVDet( &_input, &ratio ); + double threshold = (input.depth() == CV_32F ? FLT_EPSILON : DBL_EPSILON)*1000; + + cvtest::convert( input, temp1, temp1.type() ); + + if( det < threshold || + ((method == CV_LU || method == CV_CHOLESKY) && (result == 0 || ratio < threshold)) || + ((method == CV_SVD || method == CV_SVD_SYM) && result < threshold) ) + { + dst = Scalar::all(0); + dst0 = Scalar::all(0); + return; + } + + if( input.rows >= input.cols ) + cvtest::gemm( temp0, input, 1., Mat(), 0., dst, 0 ); + else + cvtest::gemm( input, temp0, 1., Mat(), 0., dst, 0 ); + + cv::setIdentity( dst0, Scalar::all(1) ); +} + + +///////////////// solve ///////////////////// + +class Core_SolveTest : public Core_MatrixTest +{ +public: + typedef Core_MatrixTest Base; + Core_SolveTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ); + double get_success_error_level( int test_case_idx, int i, int j ); + int prepare_test_case( int test_case_idx ); + void run_func(); + void prepare_to_validation( int test_case_idx ); + int method, rank; + double result; +}; + + +Core_SolveTest::Core_SolveTest() : Core_MatrixTest( 2, 1, false, false, 1 ), method(0), rank(0), result(0.) +{ + test_case_count = 100; + max_log_array_size = 7; + test_array[TEMP].push_back(NULL); + test_array[TEMP].push_back(NULL); +} + + +void Core_SolveTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + int bits = cvtest::randInt(rng); + Base::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + CvSize in_sz = sizes[INPUT][0]; + if( in_sz.width > in_sz.height ) + in_sz = cvSize(in_sz.height, in_sz.width); + Base::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + sizes[INPUT][0] = in_sz; + int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height ); + + if( (bits & 3) == 0 ) + { + method = CV_SVD; + if( bits & 4 ) + { + sizes[INPUT][0] = Size(min_size, min_size); + /*if( bits & 8 ) + method = CV_SVD_SYM;*/ + } + } + else + { + method = CV_LU; + sizes[INPUT][0] = Size(min_size, min_size); + } + + sizes[INPUT][1].height = sizes[INPUT][0].height; + sizes[TEMP][0].width = sizes[INPUT][1].width; + sizes[TEMP][0].height = sizes[INPUT][0].width; + sizes[TEMP][1] = sizes[INPUT][0]; + types[TEMP][0] = types[INPUT][0]; + types[TEMP][1] = CV_64FC1; + sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = Size(sizes[INPUT][1].width, min_size); +} + + +int Core_SolveTest::prepare_test_case( int test_case_idx ) +{ + int code = Core_MatrixTest::prepare_test_case( test_case_idx ); + + /*if( method == CV_SVD_SYM ) + { + cvTsGEMM( test_array[INPUT][0], test_array[INPUT][0], 1., + 0, 0., test_array[TEMP][0], CV_GEMM_B_T ); + cvTsCopy( test_array[TEMP][0], test_array[INPUT][0] ); + }*/ + + return code; +} + + +void Core_SolveTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ) +{ + low = cvScalarAll(-1.); + high = cvScalarAll(1.); +} + + +double Core_SolveTest::get_success_error_level( int /*test_case_idx*/, int, int ) +{ + return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 5e-2 : 1e-8; +} + + +void Core_SolveTest::run_func() +{ + result = cvSolve(test_array[INPUT][0], test_array[INPUT][1], test_array[TEMP][0], method); +} + +void Core_SolveTest::prepare_to_validation( int ) +{ + //int rank = test_mat[REF_OUTPUT][0].rows; + Mat& input = test_mat[INPUT][0]; + Mat& dst = test_mat[OUTPUT][0]; + Mat& dst0 = test_mat[REF_OUTPUT][0]; + + if( method == CV_LU ) + { + if( result == 0 ) + { + Mat& temp1 = test_mat[TEMP][1]; + cvtest::convert(input, temp1, temp1.type()); + dst = Scalar::all(0); + CvMat _temp1 = temp1; + double det = cvTsLU( &_temp1, 0, 0 ); + dst0 = Scalar::all(det != 0); + return; + } + + double threshold = (input.type() == CV_32F ? FLT_EPSILON : DBL_EPSILON)*1000; + CvMat _input = input; + double ratio = 0, det = cvTsSVDet( &_input, &ratio ); + if( det < threshold || ratio < threshold ) + { + dst = Scalar::all(0); + dst0 = Scalar::all(0); + return; + } + } + + Mat* pdst = input.rows <= input.cols ? &test_mat[OUTPUT][0] : &test_mat[INPUT][1]; + + cvtest::gemm( input, test_mat[TEMP][0], 1., test_mat[INPUT][1], -1., *pdst, 0 ); + if( pdst != &dst ) + cvtest::gemm( input, *pdst, 1., Mat(), 0., dst, CV_GEMM_A_T ); + dst0 = Scalar::all(0); +} + + +///////////////// SVD ///////////////////// + +class Core_SVDTest : public Core_MatrixTest +{ +public: + typedef Core_MatrixTest Base; + Core_SVDTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ); + int prepare_test_case( int test_case_idx ); + void run_func(); + void prepare_to_validation( int test_case_idx ); + int flags; + bool have_u, have_v, symmetric, compact, vector_w; +}; + + +Core_SVDTest::Core_SVDTest() : +Core_MatrixTest( 1, 4, false, false, 1 ), +flags(0), have_u(false), have_v(false), symmetric(false), compact(false), vector_w(false) +{ + test_case_count = 100; + max_log_array_size = 8; + test_array[TEMP].push_back(NULL); + test_array[TEMP].push_back(NULL); + test_array[TEMP].push_back(NULL); + test_array[TEMP].push_back(NULL); +} + + +void Core_SVDTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + int bits = cvtest::randInt(rng); + Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int min_size, i, m, n; + + min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height ); + + flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T); + have_u = (bits & 8) != 0; + have_v = (bits & 16) != 0; + symmetric = (bits & 32) != 0; + compact = (bits & 64) != 0; + vector_w = (bits & 128) != 0; + + if( symmetric ) + sizes[INPUT][0] = Size(min_size, min_size); + + m = sizes[INPUT][0].height; + n = sizes[INPUT][0].width; + + if( compact ) + sizes[TEMP][0] = Size(min_size, min_size); + else + sizes[TEMP][0] = sizes[INPUT][0]; + sizes[TEMP][3] = Size(0,0); + + if( vector_w ) + { + sizes[TEMP][3] = sizes[TEMP][0]; + if( bits & 256 ) + sizes[TEMP][0] = Size(1, min_size); + else + sizes[TEMP][0] = Size(min_size, 1); + } + + if( have_u ) + { + sizes[TEMP][1] = compact ? Size(min_size, m) : Size(m, m); + + if( flags & CV_SVD_U_T ) + CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i ); + } + else + sizes[TEMP][1] = Size(0,0); + + if( have_v ) + { + sizes[TEMP][2] = compact ? Size(n, min_size) : Size(n, n); + + if( !(flags & CV_SVD_V_T) ) + CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i ); + } + else + sizes[TEMP][2] = Size(0,0); + + types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[TEMP][3] = types[INPUT][0]; + types[OUTPUT][0] = types[OUTPUT][1] = types[OUTPUT][2] = types[INPUT][0]; + types[OUTPUT][3] = CV_8UC1; + sizes[OUTPUT][0] = !have_u || !have_v ? Size(0,0) : sizes[INPUT][0]; + sizes[OUTPUT][1] = !have_u ? Size(0,0) : compact ? Size(min_size,min_size) : Size(m,m); + sizes[OUTPUT][2] = !have_v ? Size(0,0) : compact ? Size(min_size,min_size) : Size(n,n); + sizes[OUTPUT][3] = Size(min_size,1); + + for( i = 0; i < 4; i++ ) + { + sizes[REF_OUTPUT][i] = sizes[OUTPUT][i]; + types[REF_OUTPUT][i] = types[OUTPUT][i]; + } +} + + +int Core_SVDTest::prepare_test_case( int test_case_idx ) +{ + int code = Core_MatrixTest::prepare_test_case( test_case_idx ); + if( code > 0 ) + { + Mat& input = test_mat[INPUT][0]; + cvTsFloodWithZeros( input, ts->get_rng() ); + + if( symmetric && (have_u || have_v) ) + { + Mat& temp = test_mat[TEMP][have_u ? 1 : 2]; + cvtest::gemm( input, input, 1., Mat(), 0., temp, CV_GEMM_B_T ); + cvtest::copy( temp, input ); + } + + if( (flags & CV_SVD_MODIFY_A) && test_array[OUTPUT][0] ) + cvtest::copy( input, test_mat[OUTPUT][0] ); + } + + return code; +} + + +void Core_SVDTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ) +{ + low = cvScalarAll(-2.); + high = cvScalarAll(2.); +} + +double Core_SVDTest::get_success_error_level( int test_case_idx, int i, int j ) +{ + int input_depth = CV_MAT_DEPTH(cvGetElemType( test_array[INPUT][0] )); + double input_precision = input_depth < CV_32F ? 0 : input_depth == CV_32F ? 1e-5 : 5e-11; + double output_precision = Base::get_success_error_level( test_case_idx, i, j ); + return MAX(input_precision, output_precision); +} + +void Core_SVDTest::run_func() +{ + CvArr* src = test_array[!(flags & CV_SVD_MODIFY_A) ? INPUT : OUTPUT][0]; + if( !src ) + src = test_array[INPUT][0]; + cvSVD( src, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags ); +} + + +void Core_SVDTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat& input = test_mat[INPUT][0]; + int depth = input.depth(); + int i, m = input.rows, n = input.cols, min_size = MIN(m, n); + Mat *src, *dst, *w; + double prev = 0, threshold = depth == CV_32F ? FLT_EPSILON : DBL_EPSILON; + + if( have_u ) + { + src = &test_mat[TEMP][1]; + dst = &test_mat[OUTPUT][1]; + cvtest::gemm( *src, *src, 1., Mat(), 0., *dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T ); + cv::setIdentity( test_mat[REF_OUTPUT][1], Scalar::all(1.) ); + } + + if( have_v ) + { + src = &test_mat[TEMP][2]; + dst = &test_mat[OUTPUT][2]; + cvtest::gemm( *src, *src, 1., Mat(), 0., *dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T ); + cv::setIdentity( test_mat[REF_OUTPUT][2], Scalar::all(1.) ); + } + + w = &test_mat[TEMP][0]; + for( i = 0; i < min_size; i++ ) + { + double normval = 0, aii; + if( w->rows > 1 && w->cols > 1 ) + { + normval = cvtest::norm( w->row(i), NORM_L1 ); + aii = depth == CV_32F ? w->at(i,i) : w->at(i,i); + } + else + { + normval = aii = depth == CV_32F ? w->at(i) : w->at(i); + } + + normval = fabs(normval - aii); + test_mat[OUTPUT][3].at(i) = aii >= 0 && normval < threshold && (i == 0 || aii <= prev); + prev = aii; + } + + test_mat[REF_OUTPUT][3] = Scalar::all(1); + + if( have_u && have_v ) + { + if( vector_w ) + { + test_mat[TEMP][3] = Scalar::all(0); + for( i = 0; i < min_size; i++ ) + { + double val = depth == CV_32F ? w->at(i) : w->at(i); + cvSetReal2D( test_array[TEMP][3], i, i, val ); + } + w = &test_mat[TEMP][3]; + } + + if( m >= n ) + { + cvtest::gemm( test_mat[TEMP][1], *w, 1., Mat(), 0., test_mat[REF_OUTPUT][0], + flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 ); + cvtest::gemm( test_mat[REF_OUTPUT][0], test_mat[TEMP][2], 1., Mat(), 0., + test_mat[OUTPUT][0], flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T ); + } + else + { + cvtest::gemm( *w, test_mat[TEMP][2], 1., Mat(), 0., test_mat[REF_OUTPUT][0], + flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T ); + cvtest::gemm( test_mat[TEMP][1], test_mat[REF_OUTPUT][0], 1., Mat(), 0., + test_mat[OUTPUT][0], flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 ); + } + + cvtest::copy( test_mat[INPUT][0], test_mat[REF_OUTPUT][0] ); + } +} + + + +///////////////// SVBkSb ///////////////////// + +class Core_SVBkSbTest : public Core_MatrixTest +{ +public: + typedef Core_MatrixTest Base; + Core_SVBkSbTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ); + int prepare_test_case( int test_case_idx ); + void run_func(); + void prepare_to_validation( int test_case_idx ); + int flags; + bool have_b, symmetric, compact, vector_w; +}; + + +Core_SVBkSbTest::Core_SVBkSbTest() : Core_MatrixTest( 2, 1, false, false, 1 ), +flags(0), have_b(false), symmetric(false), compact(false), vector_w(false) +{ + test_case_count = 100; + test_array[TEMP].push_back(NULL); + test_array[TEMP].push_back(NULL); + test_array[TEMP].push_back(NULL); +} + + +void Core_SVBkSbTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, + vector >& types ) +{ + RNG& rng = ts->get_rng(); + int bits = cvtest::randInt(rng); + Base::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int min_size, i, m, n; + CvSize b_size; + + min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height ); + + flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T); + have_b = (bits & 16) != 0; + symmetric = (bits & 32) != 0; + compact = (bits & 64) != 0; + vector_w = (bits & 128) != 0; + + if( symmetric ) + sizes[INPUT][0] = Size(min_size, min_size); + + m = sizes[INPUT][0].height; + n = sizes[INPUT][0].width; + + sizes[INPUT][1] = Size(0,0); + b_size = Size(m,m); + if( have_b ) + { + sizes[INPUT][1].height = sizes[INPUT][0].height; + sizes[INPUT][1].width = cvtest::randInt(rng) % 100 + 1; + b_size = sizes[INPUT][1]; + } + + if( compact ) + sizes[TEMP][0] = Size(min_size, min_size); + else + sizes[TEMP][0] = sizes[INPUT][0]; + + if( vector_w ) + { + if( bits & 256 ) + sizes[TEMP][0] = Size(1, min_size); + else + sizes[TEMP][0] = Size(min_size, 1); + } + + sizes[TEMP][1] = compact ? Size(min_size, m) : Size(m, m); + + if( flags & CV_SVD_U_T ) + CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i ); + + sizes[TEMP][2] = compact ? Size(n, min_size) : Size(n, n); + + if( !(flags & CV_SVD_V_T) ) + CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i ); + + types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0]; + types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][0]; + sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = Size( b_size.width, n ); +} + + +int Core_SVBkSbTest::prepare_test_case( int test_case_idx ) +{ + int code = Base::prepare_test_case( test_case_idx ); + if( code > 0 ) + { + Mat& input = test_mat[INPUT][0]; + cvTsFloodWithZeros( input, ts->get_rng() ); + + if( symmetric ) + { + Mat& temp = test_mat[TEMP][1]; + cvtest::gemm( input, input, 1., Mat(), 0., temp, CV_GEMM_B_T ); + cvtest::copy( temp, input ); + } + + CvMat _input = input; + cvSVD( &_input, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags ); + } + + return code; +} + + +void Core_SVBkSbTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high ) +{ + low = cvScalarAll(-2.); + high = cvScalarAll(2.); +} + + +double Core_SVBkSbTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-3 : 1e-7; +} + + +void Core_SVBkSbTest::run_func() +{ + cvSVBkSb( test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], + test_array[INPUT][1], test_array[OUTPUT][0], flags ); +} + + +void Core_SVBkSbTest::prepare_to_validation( int ) +{ + Mat& input = test_mat[INPUT][0]; + int i, m = input.rows, n = input.cols, min_size = MIN(m, n); + bool is_float = input.type() == CV_32F; + Size w_size = compact ? Size(min_size,min_size) : Size(m,n); + Mat& w = test_mat[TEMP][0]; + Mat wdb( w_size.height, w_size.width, CV_64FC1 ); + CvMat _w = w, _wdb = wdb; + // use exactly the same threshold as in icvSVD... , + // so the changes in the library and here should be synchronized. + double threshold = cv::sum(w)[0]*(DBL_EPSILON*2);//(is_float ? FLT_EPSILON*10 : DBL_EPSILON*2); + + wdb = Scalar::all(0); + for( i = 0; i < min_size; i++ ) + { + double wii = vector_w ? cvGetReal1D(&_w,i) : cvGetReal2D(&_w,i,i); + cvSetReal2D( &_wdb, i, i, wii > threshold ? 1./wii : 0. ); + } + + Mat u = test_mat[TEMP][1]; + Mat v = test_mat[TEMP][2]; + Mat b = test_mat[INPUT][1]; + + if( is_float ) + { + test_mat[TEMP][1].convertTo(u, CV_64F); + test_mat[TEMP][2].convertTo(v, CV_64F); + if( !b.empty() ) + test_mat[INPUT][1].convertTo(b, CV_64F); + } + + Mat t0, t1; + + if( !b.empty() ) + cvtest::gemm( u, b, 1., Mat(), 0., t0, !(flags & CV_SVD_U_T) ? CV_GEMM_A_T : 0 ); + else if( flags & CV_SVD_U_T ) + cvtest::copy( u, t0 ); + else + cvtest::transpose( u, t0 ); + + cvtest::gemm( wdb, t0, 1, Mat(), 0, t1, 0 ); + + cvtest::gemm( v, t1, 1, Mat(), 0, t0, flags & CV_SVD_V_T ? CV_GEMM_A_T : 0 ); + Mat& dst0 = test_mat[REF_OUTPUT][0]; + t0.convertTo(dst0, dst0.type() ); +} + + +typedef std::complex complex_type; + +struct pred_complex +{ + bool operator() (const complex_type& lhs, const complex_type& rhs) const + { + return fabs(lhs.real() - rhs.real()) > fabs(rhs.real())*FLT_EPSILON ? lhs.real() < rhs.real() : lhs.imag() < rhs.imag(); + } +}; + +struct pred_double +{ + bool operator() (const double& lhs, const double& rhs) const + { + return lhs < rhs; + } +}; + +class Core_SolvePolyTest : public cvtest::BaseTest +{ +public: + Core_SolvePolyTest(); + ~Core_SolvePolyTest(); +protected: + virtual void run( int start_from ); +}; + +Core_SolvePolyTest::Core_SolvePolyTest() {} + +Core_SolvePolyTest::~Core_SolvePolyTest() {} + +void Core_SolvePolyTest::run( int ) +{ + RNG& rng = ts->get_rng(); + int fig = 100; + double range = 50; + double err_eps = 1e-4; + + for (int idx = 0, max_idx = 1000, progress = 0; idx < max_idx; ++idx) + { + progress = update_progress(progress, idx-1, max_idx, 0); + int n = cvtest::randInt(rng) % 13 + 1; + std::vector r(n), ar(n), c(n + 1, 0); + std::vector a(n + 1), u(n * 2), ar1(n), ar2(n); + + int rr_odds = 3; // odds that we get a real root + for (int j = 0; j < n;) + { + if (cvtest::randInt(rng) % rr_odds == 0 || j == n - 1) + r[j++] = cvtest::randReal(rng) * range; + else + { + r[j] = complex_type(cvtest::randReal(rng) * range, + cvtest::randReal(rng) * range + 1); + r[j + 1] = std::conj(r[j]); + j += 2; + } + } + + for (int j = 0, k = 1 << n, jj, kk; j < k; ++j) + { + int p = 0; + complex_type v(1); + for (jj = 0, kk = 1; jj < n && !(j & kk); ++jj, ++p, kk <<= 1) + ; + for (; jj < n; ++jj, kk <<= 1) + { + if (j & kk) + v *= -r[jj]; + else + ++p; + } + c[p] += v; + } + + bool pass = false; + double div = 0, s = 0; + int cubic_case = idx & 1; + for (int maxiter = 100; !pass && maxiter < 10000; maxiter *= 2, cubic_case = (cubic_case + 1) % 2) + { + for (int j = 0; j < n + 1; ++j) + a[j] = c[j].real(); + + CvMat amat, umat; + cvInitMatHeader(&amat, n + 1, 1, CV_64FC1, &a[0]); + cvInitMatHeader(&umat, n, 1, CV_64FC2, &u[0]); + cvSolvePoly(&amat, &umat, maxiter, fig); + + for (int j = 0; j < n; ++j) + ar[j] = complex_type(u[j * 2], u[j * 2 + 1]); + + std::sort(r.begin(), r.end(), pred_complex()); + std::sort(ar.begin(), ar.end(), pred_complex()); + + pass = true; + if( n == 3 ) + { + ar2.resize(n); + cv::Mat _umat2(3, 1, CV_64F, &ar2[0]), umat2 = _umat2; + cvFlip(&amat, &amat, 0); + int nr2; + if( cubic_case == 0 ) + nr2 = cv::solveCubic(cv::Mat(&amat),umat2); + else + nr2 = cv::solveCubic(cv::Mat_(cv::Mat(&amat)), umat2); + cvFlip(&amat, &amat, 0); + if(nr2 > 0) + std::sort(ar2.begin(), ar2.begin()+nr2, pred_double()); + ar2.resize(nr2); + + int nr1 = 0; + for(int j = 0; j < n; j++) + if( fabs(r[j].imag()) < DBL_EPSILON ) + ar1[nr1++] = r[j].real(); + + pass = pass && nr1 == nr2; + if( nr2 > 0 ) + { + div = s = 0; + for(int j = 0; j < nr1; j++) + { + s += fabs(ar1[j]); + div += fabs(ar1[j] - ar2[j]); + } + div /= s; + pass = pass && div < err_eps; + } + } + + div = s = 0; + for (int j = 0; j < n; ++j) + { + s += fabs(r[j].real()) + fabs(r[j].imag()); + div += sqrt(pow(r[j].real() - ar[j].real(), 2) + pow(r[j].imag() - ar[j].imag(), 2)); + } + div /= s; + pass = pass && div < err_eps; + } + + if (!pass) + { + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); + ts->printf( cvtest::TS::LOG, "too big diff = %g\n", div ); + + for (size_t j=0;jprintf( cvtest::TS::LOG, "ar2[%d]=%g\n", j, ar2[j]); + ts->printf(cvtest::TS::LOG, "\n"); + + for (size_t j=0;jprintf( cvtest::TS::LOG, "r[%d]=(%g, %g)\n", j, r[j].real(), r[j].imag()); + ts->printf( cvtest::TS::LOG, "\n" ); + for (size_t j=0;jprintf( cvtest::TS::LOG, "ar[%d]=(%g, %g)\n", j, ar[j].real(), ar[j].imag()); + break; + } + } +} + +class Core_CheckRange_Empty : public cvtest::BaseTest +{ +public: + Core_CheckRange_Empty(){} + ~Core_CheckRange_Empty(){} +protected: + virtual void run( int start_from ); +}; + +void Core_CheckRange_Empty::run( int ) +{ + cv::Mat m; + ASSERT_TRUE( cv::checkRange(m) ); +} + +TEST(Core_CheckRange_Empty, accuracy) { Core_CheckRange_Empty test; test.safe_run(); } + +class Core_CheckRange_INT_MAX : public cvtest::BaseTest +{ +public: + Core_CheckRange_INT_MAX(){} + ~Core_CheckRange_INT_MAX(){} +protected: + virtual void run( int start_from ); +}; + +void Core_CheckRange_INT_MAX::run( int ) +{ + cv::Mat m(3, 3, CV_32SC1, cv::Scalar(INT_MAX)); + ASSERT_FALSE( cv::checkRange(m, true, 0, 0, INT_MAX) ); + ASSERT_TRUE( cv::checkRange(m) ); +} + +TEST(Core_CheckRange_INT_MAX, accuracy) { Core_CheckRange_INT_MAX test; test.safe_run(); } + +template class Core_CheckRange : public testing::Test {}; + +TYPED_TEST_CASE_P(Core_CheckRange); + +TYPED_TEST_P(Core_CheckRange, Negative) +{ + double min_bound = 4.5; + double max_bound = 16.0; + + TypeParam data[] = {5, 10, 15, 4, 10 ,2, 8, 12, 14}; + cv::Mat src = cv::Mat(3,3, cv::DataDepth::value, data); + + cv::Point* bad_pt = new cv::Point(0, 0); + + ASSERT_FALSE(checkRange(src, true, bad_pt, min_bound, max_bound)); + ASSERT_EQ(bad_pt->x,0); + ASSERT_EQ(bad_pt->y,1); + + delete bad_pt; +} + +TYPED_TEST_P(Core_CheckRange, Positive) +{ + double min_bound = -1; + double max_bound = 16.0; + + TypeParam data[] = {5, 10, 15, 4, 10 ,2, 8, 12, 14}; + cv::Mat src = cv::Mat(3,3, cv::DataDepth::value, data); + + cv::Point* bad_pt = new cv::Point(0, 0); + + ASSERT_TRUE(checkRange(src, true, bad_pt, min_bound, max_bound)); + ASSERT_EQ(bad_pt->x,0); + ASSERT_EQ(bad_pt->y,0); + + delete bad_pt; +} + +TYPED_TEST_P(Core_CheckRange, Bounds) +{ + double min_bound = 24.5; + double max_bound = 1.0; + + TypeParam data[] = {5, 10, 15, 4, 10 ,2, 8, 12, 14}; + cv::Mat src = cv::Mat(3,3, cv::DataDepth::value, data); + + cv::Point* bad_pt = new cv::Point(0, 0); + + ASSERT_FALSE(checkRange(src, true, bad_pt, min_bound, max_bound)); + ASSERT_EQ(bad_pt->x,0); + ASSERT_EQ(bad_pt->y,0); + + delete bad_pt; +} + +TYPED_TEST_P(Core_CheckRange, Zero) +{ + double min_bound = 0.0; + double max_bound = 0.1; + + cv::Mat src = cv::Mat::zeros(3,3, cv::DataDepth::value); + + ASSERT_TRUE( checkRange(src, true, NULL, min_bound, max_bound) ); +} + +REGISTER_TYPED_TEST_CASE_P(Core_CheckRange, Negative, Positive, Bounds, Zero); + +typedef ::testing::Types mat_data_types; +INSTANTIATE_TYPED_TEST_CASE_P(Negative_Test, Core_CheckRange, mat_data_types); + +///////////////////////////////////////////////////////////////////////////////////////////////////// + +TEST(Core_CovarMatrix, accuracy) { Core_CovarMatrixTest test; test.safe_run(); } +TEST(Core_CrossProduct, accuracy) { Core_CrossProductTest test; test.safe_run(); } +TEST(Core_Determinant, accuracy) { Core_DetTest test; test.safe_run(); } +TEST(Core_DotProduct, accuracy) { Core_DotProductTest test; test.safe_run(); } +TEST(Core_GEMM, accuracy) { Core_GEMMTest test; test.safe_run(); } +TEST(Core_Invert, accuracy) { Core_InvertTest test; test.safe_run(); } +TEST(Core_Mahalanobis, accuracy) { Core_MahalanobisTest test; test.safe_run(); } +TEST(Core_MulTransposed, accuracy) { Core_MulTransposedTest test; test.safe_run(); } +TEST(Core_Transform, accuracy) { Core_TransformTest test; test.safe_run(); } +TEST(Core_PerspectiveTransform, accuracy) { Core_PerspectiveTransformTest test; test.safe_run(); } +TEST(Core_Pow, accuracy) { Core_PowTest test; test.safe_run(); } +TEST(Core_SolveLinearSystem, accuracy) { Core_SolveTest test; test.safe_run(); } +TEST(Core_SVD, accuracy) { Core_SVDTest test; test.safe_run(); } +TEST(Core_SVBkSb, accuracy) { Core_SVBkSbTest test; test.safe_run(); } +TEST(Core_Trace, accuracy) { Core_TraceTest test; test.safe_run(); } +TEST(Core_SolvePoly, accuracy) { Core_SolvePolyTest test; test.safe_run(); } + +// TODO: eigenvv, invsqrt, cbrt, fastarctan, (round, floor, ceil(?)), + + +class CV_KMeansSingularTest : public cvtest::BaseTest +{ +public: + CV_KMeansSingularTest() {} + ~CV_KMeansSingularTest() {} +protected: + void run(int) + { + int i, iter = 0, N = 0, N0 = 0, K = 0, dims = 0; + Mat labels; + try + { + RNG& rng = theRNG(); + const int MAX_DIM=5; + int MAX_POINTS = 100, maxIter = 100; + for( iter = 0; iter < maxIter; iter++ ) + { + ts->update_context(this, iter, true); + dims = rng.uniform(1, MAX_DIM+1); + N = rng.uniform(1, MAX_POINTS+1); + N0 = rng.uniform(1, MAX(N/10, 2)); + K = rng.uniform(1, N+1); + + Mat data0(N0, dims, CV_32F); + rng.fill(data0, RNG::UNIFORM, -1, 1); + + Mat data(N, dims, CV_32F); + for( i = 0; i < N; i++ ) + data0.row(rng.uniform(0, N0)).copyTo(data.row(i)); + + kmeans(data, K, labels, TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 0), + 5, KMEANS_PP_CENTERS); + + Mat hist(K, 1, CV_32S, Scalar(0)); + for( i = 0; i < N; i++ ) + { + int l = labels.at(i); + CV_Assert(0 <= l && l < K); + hist.at(l)++; + } + for( i = 0; i < K; i++ ) + CV_Assert( hist.at(i) != 0 ); + } + } + catch(...) + { + ts->printf(cvtest::TS::LOG, + "context: iteration=%d, N=%d, N0=%d, K=%d\n", + iter, N, N0, K); + std::cout << labels << std::endl; + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + } + } +}; + +TEST(Core_KMeans, singular) { CV_KMeansSingularTest test; test.safe_run(); } + +TEST(CovariationMatrixVectorOfMat, accuracy) +{ + unsigned int col_problem_size = 8, row_problem_size = 8, vector_size = 16; + cv::Mat src(vector_size, col_problem_size * row_problem_size, CV_32F); + int singleMatFlags = CV_COVAR_ROWS; + + cv::Mat gold; + cv::Mat goldMean; + cv::randu(src,cv::Scalar(-128), cv::Scalar(128)); + cv::calcCovarMatrix(src,gold,goldMean,singleMatFlags,CV_32F); + std::vector srcVec; + for(size_t i = 0; i < vector_size; i++) + { + srcVec.push_back(src.row(static_cast(i)).reshape(0,col_problem_size)); + } + + cv::Mat actual; + cv::Mat actualMean; + cv::calcCovarMatrix(srcVec, actual, actualMean,singleMatFlags,CV_32F); + + cv::Mat diff; + cv::absdiff(gold, actual, diff); + cv::Scalar s = cv::sum(diff); + ASSERT_EQ(s.dot(s), 0.0); + + cv::Mat meanDiff; + cv::absdiff(goldMean, actualMean.reshape(0,1), meanDiff); + cv::Scalar sDiff = cv::sum(meanDiff); + ASSERT_EQ(sDiff.dot(sDiff), 0.0); +} + +TEST(CovariationMatrixVectorOfMatWithMean, accuracy) +{ + unsigned int col_problem_size = 8, row_problem_size = 8, vector_size = 16; + cv::Mat src(vector_size, col_problem_size * row_problem_size, CV_32F); + int singleMatFlags = CV_COVAR_ROWS | CV_COVAR_USE_AVG; + + cv::Mat gold; + cv::randu(src,cv::Scalar(-128), cv::Scalar(128)); + cv::Mat goldMean; + + cv::reduce(src,goldMean,0 ,CV_REDUCE_AVG, CV_32F); + + cv::calcCovarMatrix(src,gold,goldMean,singleMatFlags,CV_32F); + + std::vector srcVec; + for(size_t i = 0; i < vector_size; i++) + { + srcVec.push_back(src.row(static_cast(i)).reshape(0,col_problem_size)); + } + + cv::Mat actual; + cv::Mat actualMean = goldMean.reshape(0, row_problem_size); + cv::calcCovarMatrix(srcVec, actual, actualMean,singleMatFlags,CV_32F); + + cv::Mat diff; + cv::absdiff(gold, actual, diff); + cv::Scalar s = cv::sum(diff); + ASSERT_EQ(s.dot(s), 0.0); + + cv::Mat meanDiff; + cv::absdiff(goldMean, actualMean.reshape(0,1), meanDiff); + cv::Scalar sDiff = cv::sum(meanDiff); + ASSERT_EQ(sDiff.dot(sDiff), 0.0); +} + +/* End of file. */ + diff --git a/core/test/test_misc.cpp b/core/test/test_misc.cpp new file mode 100644 index 0000000..8f58f55 --- /dev/null +++ b/core/test/test_misc.cpp @@ -0,0 +1,42 @@ +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +TEST(Core_Drawing, _914) +{ + const int rows = 256; + const int cols = 256; + + Mat img(rows, cols, CV_8UC1, Scalar(255)); + + line(img, Point(0, 10), Point(255, 10), Scalar(0), 2, 4); + line(img, Point(-5, 20), Point(260, 20), Scalar(0), 2, 4); + line(img, Point(10, 0), Point(10, 255), Scalar(0), 2, 4); + + double x0 = 0.0/pow(2.0, -2.0); + double x1 = 255.0/pow(2.0, -2.0); + double y = 30.5/pow(2.0, -2.0); + + line(img, Point(int(x0), int(y)), Point(int(x1), int(y)), Scalar(0), 2, 4, 2); + + int pixelsDrawn = rows*cols - countNonZero(img); + ASSERT_EQ( (3*rows + cols)*3 - 3*9, pixelsDrawn); +} + + +TEST(Core_OutputArraySreate, _1997) +{ + struct local { + static void create(OutputArray arr, Size submatSize, int type) + { + int sizes[] = {submatSize.width, submatSize.height}; + arr.create(sizeof(sizes)/sizeof(sizes[0]), sizes, type); + } + }; + + Mat mat(Size(512, 512), CV_8U); + Size submatSize = Size(256, 256); + + ASSERT_NO_THROW(local::create( mat(Rect(Point(), submatSize)), submatSize, mat.type() )); +} \ No newline at end of file diff --git a/core/test/test_operations.cpp b/core/test/test_operations.cpp new file mode 100644 index 0000000..86a90c8 --- /dev/null +++ b/core/test/test_operations.cpp @@ -0,0 +1,1132 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +#include +#include +#include +#include +#include +#include + +using namespace cv; +using namespace std; + + +class CV_OperationsTest : public cvtest::BaseTest +{ +public: + CV_OperationsTest(); + ~CV_OperationsTest(); +protected: + void run(int); + + struct test_excep + { + test_excep(const string& _s=string("")) : s(_s) {}; + string s; + }; + + bool SomeMatFunctions(); + bool TestMat(); + bool TestTemplateMat(); + bool TestMatND(); + bool TestSparseMat(); + bool TestVec(); + bool TestMatxMultiplication(); + bool TestSubMatAccess(); + bool TestSVD(); + bool operations1(); + + void checkDiff(const Mat& m1, const Mat& m2, const string& s) + { + if (norm(m1, m2, NORM_INF) != 0) throw test_excep(s); + } + void checkDiffF(const Mat& m1, const Mat& m2, const string& s) + { + if (norm(m1, m2, NORM_INF) > 1e-5) throw test_excep(s); + } +}; + +CV_OperationsTest::CV_OperationsTest() +{ +} + +CV_OperationsTest::~CV_OperationsTest() {} + +#define STR(a) STR2(a) +#define STR2(a) #a + +#define CHECK_DIFF(a, b) checkDiff(a, b, "(" #a ") != (" #b ") at l." STR(__LINE__)) +#define CHECK_DIFF_FLT(a, b) checkDiffF(a, b, "(" #a ") !=(eps) (" #b ") at l." STR(__LINE__)) + +#if defined _MSC_VER && _MSC_VER < 1400 +#define MSVC_OLD 1 +#else +#define MSVC_OLD 0 +#endif + +bool CV_OperationsTest::TestMat() +{ + try + { + Mat one_3x1(3, 1, CV_32F, Scalar(1.0)); + Mat shi_3x1(3, 1, CV_32F, Scalar(1.2)); + Mat shi_2x1(2, 1, CV_32F, Scalar(-1)); + Scalar shift = Scalar::all(15); + + float data[] = { sqrt(2.f)/2, -sqrt(2.f)/2, 1.f, sqrt(2.f)/2, sqrt(2.f)/2, 10.f }; + Mat rot_2x3(2, 3, CV_32F, data); + + Mat res = one_3x1 + shi_3x1 + shi_3x1 + shi_3x1; + res = Mat(Mat(2 * rot_2x3) * res - shi_2x1) + shift; + + Mat tmp, res2; + add(one_3x1, shi_3x1, tmp); + add(tmp, shi_3x1, tmp); + add(tmp, shi_3x1, tmp); + gemm(rot_2x3, tmp, 2, shi_2x1, -1, res2, 0); + add(res2, Mat(2, 1, CV_32F, shift), res2); + + CHECK_DIFF(res, res2); + + Mat mat4x4(4, 4, CV_32F); + randu(mat4x4, Scalar(0), Scalar(10)); + + Mat roi1 = mat4x4(Rect(Point(1, 1), Size(2, 2))); + Mat roi2 = mat4x4(Range(1, 3), Range(1, 3)); + + CHECK_DIFF(roi1, roi2); + CHECK_DIFF(mat4x4, mat4x4(Rect(Point(0,0), mat4x4.size()))); + + Mat intMat10(3, 3, CV_32S, Scalar(10)); + Mat intMat11(3, 3, CV_32S, Scalar(11)); + Mat resMat(3, 3, CV_8U, Scalar(255)); + + CHECK_DIFF(resMat, intMat10 == intMat10); + CHECK_DIFF(resMat, intMat10 < intMat11); + CHECK_DIFF(resMat, intMat11 > intMat10); + CHECK_DIFF(resMat, intMat10 <= intMat11); + CHECK_DIFF(resMat, intMat11 >= intMat10); + CHECK_DIFF(resMat, intMat11 != intMat10); + + CHECK_DIFF(resMat, intMat10 == 10.0); + CHECK_DIFF(resMat, 10.0 == intMat10); + CHECK_DIFF(resMat, intMat10 < 11.0); + CHECK_DIFF(resMat, 11.0 > intMat10); + CHECK_DIFF(resMat, 10.0 < intMat11); + CHECK_DIFF(resMat, 11.0 >= intMat10); + CHECK_DIFF(resMat, 10.0 <= intMat11); + CHECK_DIFF(resMat, 10.0 != intMat11); + CHECK_DIFF(resMat, intMat11 != 10.0); + + Mat eye = Mat::eye(3, 3, CV_16S); + Mat maskMat4(3, 3, CV_16S, Scalar(4)); + Mat maskMat1(3, 3, CV_16S, Scalar(1)); + Mat maskMat5(3, 3, CV_16S, Scalar(5)); + Mat maskMat0(3, 3, CV_16S, Scalar(0)); + + CHECK_DIFF(maskMat0, maskMat4 & maskMat1); + CHECK_DIFF(maskMat0, Scalar(1) & maskMat4); + CHECK_DIFF(maskMat0, maskMat4 & Scalar(1)); + + Mat m; + m = maskMat4.clone(); m &= maskMat1; CHECK_DIFF(maskMat0, m); + m = maskMat4.clone(); m &= maskMat1 | maskMat1; CHECK_DIFF(maskMat0, m); + m = maskMat4.clone(); m &= (2* maskMat1 - maskMat1); CHECK_DIFF(maskMat0, m); + + m = maskMat4.clone(); m &= Scalar(1); CHECK_DIFF(maskMat0, m); + m = maskMat4.clone(); m |= maskMat1; CHECK_DIFF(maskMat5, m); + m = maskMat5.clone(); m ^= maskMat1; CHECK_DIFF(maskMat4, m); + m = maskMat4.clone(); m |= (2* maskMat1 - maskMat1); CHECK_DIFF(maskMat5, m); + m = maskMat5.clone(); m ^= (2* maskMat1 - maskMat1); CHECK_DIFF(maskMat4, m); + + m = maskMat4.clone(); m |= Scalar(1); CHECK_DIFF(maskMat5, m); + m = maskMat5.clone(); m ^= Scalar(1); CHECK_DIFF(maskMat4, m); + + + + CHECK_DIFF(maskMat0, (maskMat4 | maskMat4) & (maskMat1 | maskMat1)); + CHECK_DIFF(maskMat0, (maskMat4 | maskMat4) & maskMat1); + CHECK_DIFF(maskMat0, maskMat4 & (maskMat1 | maskMat1)); + CHECK_DIFF(maskMat0, (maskMat1 | maskMat1) & Scalar(4)); + CHECK_DIFF(maskMat0, Scalar(4) & (maskMat1 | maskMat1)); + + CHECK_DIFF(maskMat0, maskMat5 ^ (maskMat4 | maskMat1)); + CHECK_DIFF(maskMat0, (maskMat4 | maskMat1) ^ maskMat5); + CHECK_DIFF(maskMat0, (maskMat4 + maskMat1) ^ (maskMat4 + maskMat1)); + CHECK_DIFF(maskMat0, Scalar(5) ^ (maskMat4 | Scalar(1))); + CHECK_DIFF(maskMat1, Scalar(5) ^ maskMat4); + CHECK_DIFF(maskMat0, Scalar(5) ^ (maskMat4 + maskMat1)); + CHECK_DIFF(maskMat5, Scalar(5) | (maskMat4 + maskMat1)); + CHECK_DIFF(maskMat0, (maskMat4 + maskMat1) ^ Scalar(5)); + + CHECK_DIFF(maskMat5, maskMat5 | (maskMat4 ^ maskMat1)); + CHECK_DIFF(maskMat5, (maskMat4 ^ maskMat1) | maskMat5); + CHECK_DIFF(maskMat5, maskMat5 | (maskMat4 ^ Scalar(1))); + CHECK_DIFF(maskMat5, (maskMat4 | maskMat4) | Scalar(1)); + CHECK_DIFF(maskMat5, Scalar(1) | (maskMat4 | maskMat4)); + CHECK_DIFF(maskMat5, Scalar(1) | maskMat4); + CHECK_DIFF(maskMat5, (maskMat5 | maskMat5) | (maskMat4 ^ maskMat1)); + + CHECK_DIFF(maskMat1, min(maskMat1, maskMat5)); + CHECK_DIFF(maskMat1, min(Mat(maskMat1 | maskMat1), maskMat5 | maskMat5)); + CHECK_DIFF(maskMat5, max(maskMat1, maskMat5)); + CHECK_DIFF(maskMat5, max(Mat(maskMat1 | maskMat1), maskMat5 | maskMat5)); + + CHECK_DIFF(maskMat1, min(maskMat1, maskMat5 | maskMat5)); + CHECK_DIFF(maskMat1, min(maskMat1 | maskMat1, maskMat5)); + CHECK_DIFF(maskMat5, max(maskMat1 | maskMat1, maskMat5)); + CHECK_DIFF(maskMat5, max(maskMat1, maskMat5 | maskMat5)); + + CHECK_DIFF(~maskMat1, maskMat1 ^ -1); + CHECK_DIFF(~(maskMat1 | maskMat1), maskMat1 ^ -1); + + CHECK_DIFF(maskMat1, maskMat4/4.0); + + ///////////////////////////// + + CHECK_DIFF(1.0 - (maskMat5 | maskMat5), -maskMat4); + CHECK_DIFF((maskMat4 | maskMat4) * 1.0 + 1.0, maskMat5); + CHECK_DIFF(1.0 + (maskMat4 | maskMat4) * 1.0, maskMat5); + CHECK_DIFF((maskMat5 | maskMat5) * 1.0 - 1.0, maskMat4); + CHECK_DIFF(5.0 - (maskMat4 | maskMat4) * 1.0, maskMat1); + CHECK_DIFF((maskMat4 | maskMat4) * 1.0 + 0.5 + 0.5, maskMat5); + CHECK_DIFF(0.5 + ((maskMat4 | maskMat4) * 1.0 + 0.5), maskMat5); + CHECK_DIFF(((maskMat4 | maskMat4) * 1.0 + 2.0) - 1.0, maskMat5); + CHECK_DIFF(5.0 - ((maskMat1 | maskMat1) * 1.0 + 3.0), maskMat1); + CHECK_DIFF( ( (maskMat1 | maskMat1) * 2.0 + 2.0) * 1.25, maskMat5); + CHECK_DIFF( 1.25 * ( (maskMat1 | maskMat1) * 2.0 + 2.0), maskMat5); + CHECK_DIFF( -( (maskMat1 | maskMat1) * (-2.0) + 1.0), maskMat1); + CHECK_DIFF( maskMat1 * 1.0 + maskMat4 * 0.5 + 2.0, maskMat5); + CHECK_DIFF( 1.0 + (maskMat1 * 1.0 + maskMat4 * 0.5 + 1.0), maskMat5); + CHECK_DIFF( (maskMat1 * 1.0 + maskMat4 * 0.5 + 2.0) - 1.0, maskMat4); + CHECK_DIFF(5.0 - (maskMat1 * 1.0 + maskMat4 * 0.5 + 1.0), maskMat1); + CHECK_DIFF((maskMat1 * 1.0 + maskMat4 * 0.5 + 1.0)*1.25, maskMat5); + CHECK_DIFF(1.25 * (maskMat1 * 1.0 + maskMat4 * 0.5 + 1.0), maskMat5); + CHECK_DIFF(-(maskMat1 * 2.0 + maskMat4 * (-1) + 1.0), maskMat1); + CHECK_DIFF((maskMat1 * 1.0 + maskMat4), maskMat5); + CHECK_DIFF((maskMat4 + maskMat1 * 1.0), maskMat5); + CHECK_DIFF((maskMat1 * 3.0 + 1.0) + maskMat1, maskMat5); + CHECK_DIFF(maskMat1 + (maskMat1 * 3.0 + 1.0), maskMat5); + CHECK_DIFF(maskMat1*4.0 + (maskMat1 | maskMat1), maskMat5); + CHECK_DIFF((maskMat1 | maskMat1) + maskMat1*4.0, maskMat5); + CHECK_DIFF((maskMat1*3.0 + 1.0) + (maskMat1 | maskMat1), maskMat5); + CHECK_DIFF((maskMat1 | maskMat1) + (maskMat1*3.0 + 1.0), maskMat5); + CHECK_DIFF(maskMat1*4.0 + maskMat4*2.0, maskMat1 * 12); + CHECK_DIFF((maskMat1*3.0 + 1.0) + maskMat4*2.0, maskMat1 * 12); + CHECK_DIFF(maskMat4*2.0 + (maskMat1*3.0 + 1.0), maskMat1 * 12); + CHECK_DIFF((maskMat1*3.0 + 1.0) + (maskMat1*2.0 + 2.0), maskMat1 * 8); + + CHECK_DIFF(maskMat5*1.0 - maskMat4, maskMat1); + CHECK_DIFF(maskMat5 - maskMat1 * 4.0, maskMat1); + CHECK_DIFF((maskMat4 * 1.0 + 4.0)- maskMat4, maskMat4); + CHECK_DIFF(maskMat5 - (maskMat1 * 2.0 + 2.0), maskMat1); + CHECK_DIFF(maskMat5*1.0 - (maskMat4 | maskMat4), maskMat1); + CHECK_DIFF((maskMat5 | maskMat5) - maskMat1 * 4.0, maskMat1); + CHECK_DIFF((maskMat4 * 1.0 + 4.0)- (maskMat4 | maskMat4), maskMat4); + CHECK_DIFF((maskMat5 | maskMat5) - (maskMat1 * 2.0 + 2.0), maskMat1); + CHECK_DIFF(maskMat1*5.0 - maskMat4 * 1.0, maskMat1); + CHECK_DIFF((maskMat1*5.0 + 3.0)- maskMat4 * 1.0, maskMat4); + CHECK_DIFF(maskMat4 * 2.0 - (maskMat1*4.0 + 3.0), maskMat1); + CHECK_DIFF((maskMat1 * 2.0 + 3.0) - (maskMat1*3.0 + 1.0), maskMat1); + + CHECK_DIFF((maskMat5 - maskMat4)* 4.0, maskMat4); + CHECK_DIFF(4.0 * (maskMat5 - maskMat4), maskMat4); + + CHECK_DIFF(-((maskMat4 | maskMat4) - (maskMat5 | maskMat5)), maskMat1); + + CHECK_DIFF(4.0 * (maskMat1 | maskMat1), maskMat4); + CHECK_DIFF((maskMat4 | maskMat4)/4.0, maskMat1); + +#if !MSVC_OLD + CHECK_DIFF(2.0 * (maskMat1 * 2.0) , maskMat4); +#endif + CHECK_DIFF((maskMat4 / 2.0) / 2.0 , maskMat1); + CHECK_DIFF(-(maskMat4 - maskMat5) , maskMat1); + CHECK_DIFF(-((maskMat4 - maskMat5) * 1.0), maskMat1); + + + ///////////////////////////// + CHECK_DIFF(maskMat4 / maskMat4, maskMat1); + + ///// Element-wise multiplication + + CHECK_DIFF(maskMat4.mul(maskMat4, 0.25), maskMat4); + CHECK_DIFF(maskMat4.mul(maskMat1 * 4, 0.25), maskMat4); + CHECK_DIFF(maskMat4.mul(maskMat4 / 4), maskMat4); + CHECK_DIFF(maskMat4.mul(maskMat4 / 4), maskMat4); + CHECK_DIFF(maskMat4.mul(maskMat4) * 0.25, maskMat4); + CHECK_DIFF(0.25 * maskMat4.mul(maskMat4), maskMat4); + + ////// Element-wise division + + CHECK_DIFF(maskMat4 / maskMat4, maskMat1); + CHECK_DIFF((maskMat4 & maskMat4) / (maskMat1 * 4), maskMat1); + + CHECK_DIFF((maskMat4 & maskMat4) / maskMat4, maskMat1); + CHECK_DIFF(maskMat4 / (maskMat4 & maskMat4), maskMat1); + CHECK_DIFF((maskMat1 * 4) / maskMat4, maskMat1); + + CHECK_DIFF(maskMat4 / (maskMat1 * 4), maskMat1); + CHECK_DIFF((maskMat4 * 0.5 )/ (maskMat1 * 2), maskMat1); + + CHECK_DIFF(maskMat4 / maskMat4.mul(maskMat1), maskMat1); + CHECK_DIFF((maskMat4 & maskMat4) / maskMat4.mul(maskMat1), maskMat1); + + CHECK_DIFF(4.0 / maskMat4, maskMat1); + CHECK_DIFF(4.0 / (maskMat4 | maskMat4), maskMat1); + CHECK_DIFF(4.0 / (maskMat1 * 4.0), maskMat1); + CHECK_DIFF(4.0 / (maskMat4 / maskMat1), maskMat1); + + m = maskMat4.clone(); m/=4.0; CHECK_DIFF(m, maskMat1); + m = maskMat4.clone(); m/=maskMat4; CHECK_DIFF(m, maskMat1); + m = maskMat4.clone(); m/=(maskMat1 * 4.0); CHECK_DIFF(m, maskMat1); + m = maskMat4.clone(); m/=(maskMat4 / maskMat1); CHECK_DIFF(m, maskMat1); + + ///////////////////////////// + float matrix_data[] = { 3, 1, -4, -5, 1, 0, 0, 1.1f, 1.5f}; + Mat mt(3, 3, CV_32F, matrix_data); + Mat mi = mt.inv(); + Mat d1 = Mat::eye(3, 3, CV_32F); + Mat d2 = d1 * 2; + MatExpr mt_tr = mt.t(); + MatExpr mi_tr = mi.t(); + Mat mi2 = mi * 2; + + + CHECK_DIFF_FLT( mi2 * mt, d2 ); + CHECK_DIFF_FLT( mi * mt, d1 ); + CHECK_DIFF_FLT( mt_tr * mi_tr, d1 ); + + m = mi.clone(); m*=mt; CHECK_DIFF_FLT(m, d1); + m = mi.clone(); m*= (2 * mt - mt) ; CHECK_DIFF_FLT(m, d1); + + m = maskMat4.clone(); m+=(maskMat1 * 1.0); CHECK_DIFF(m, maskMat5); + m = maskMat5.clone(); m-=(maskMat1 * 4.0); CHECK_DIFF(m, maskMat1); + + m = maskMat1.clone(); m+=(maskMat1 * 3.0 + 1.0); CHECK_DIFF(m, maskMat5); + m = maskMat5.clone(); m-=(maskMat1 * 3.0 + 1.0); CHECK_DIFF(m, maskMat1); +#if !MSVC_OLD + m = mi.clone(); m+=(3.0 * mi * mt + d1); CHECK_DIFF_FLT(m, mi + d1 * 4); + m = mi.clone(); m-=(3.0 * mi * mt + d1); CHECK_DIFF_FLT(m, mi - d1 * 4); + m = mi.clone(); m*=(mt * 1.0); CHECK_DIFF_FLT(m, d1); + m = mi.clone(); m*=(mt * 1.0 + Mat::eye(m.size(), m.type())); CHECK_DIFF_FLT(m, d1 + mi); + m = mi.clone(); m*=mt_tr.t(); CHECK_DIFF_FLT(m, d1); + + CHECK_DIFF_FLT( (mi * 2) * mt, d2); + CHECK_DIFF_FLT( mi * (2 * mt), d2); + CHECK_DIFF_FLT( mt.t() * mi_tr, d1 ); + CHECK_DIFF_FLT( mt_tr * mi.t(), d1 ); + CHECK_DIFF_FLT( (mi * 0.4) * (mt * 5), d2); + + CHECK_DIFF_FLT( mt.t() * (mi_tr * 2), d2 ); + CHECK_DIFF_FLT( (mt_tr * 2) * mi.t(), d2 ); + + CHECK_DIFF_FLT(mt.t() * mi.t(), d1); + CHECK_DIFF_FLT( (mi * mt) * 2.0, d2); + CHECK_DIFF_FLT( 2.0 * (mi * mt), d2); + CHECK_DIFF_FLT( -(mi * mt), -d1); + + CHECK_DIFF_FLT( (mi * mt) / 2.0, d1 / 2); + + Mat mt_mul_2_plus_1; + gemm(mt, d1, 2, Mat::ones(3, 3, CV_32F), 1, mt_mul_2_plus_1); + + CHECK_DIFF( (mt * 2.0 + 1.0) * mi, mt_mul_2_plus_1 * mi); // (A*alpha + beta)*B + CHECK_DIFF( mi * (mt * 2.0 + 1.0), mi * mt_mul_2_plus_1); // A*(B*alpha + beta) + CHECK_DIFF( (mt * 2.0 + 1.0) * (mi * 2), mt_mul_2_plus_1 * mi2); // (A*alpha + beta)*(B*gamma) + CHECK_DIFF( (mi *2)* (mt * 2.0 + 1.0), mi2 * mt_mul_2_plus_1); // (A*gamma)*(B*alpha + beta) + CHECK_DIFF_FLT( (mt * 2.0 + 1.0) * mi.t(), mt_mul_2_plus_1 * mi_tr); // (A*alpha + beta)*B^t + CHECK_DIFF_FLT( mi.t() * (mt * 2.0 + 1.0), mi_tr * mt_mul_2_plus_1); // A^t*(B*alpha + beta) + + CHECK_DIFF_FLT( (mi * mt + d2)*5, d1 * 3 * 5); + CHECK_DIFF_FLT( mi * mt + d2, d1 * 3); + CHECK_DIFF_FLT( -(mi * mt) + d2, d1); + CHECK_DIFF_FLT( (mi * mt) + d1, d2); + CHECK_DIFF_FLT( d1 + (mi * mt), d2); + CHECK_DIFF_FLT( (mi * mt) - d2, -d1); + CHECK_DIFF_FLT( d2 - (mi * mt), d1); + + CHECK_DIFF_FLT( (mi * mt) + d2 * 0.5, d2); + CHECK_DIFF_FLT( d2 * 0.5 + (mi * mt), d2); + CHECK_DIFF_FLT( (mi * mt) - d1 * 2, -d1); + CHECK_DIFF_FLT( d1 * 2 - (mi * mt), d1); + + CHECK_DIFF_FLT( (mi * mt) + mi.t(), mi_tr + d1); + CHECK_DIFF_FLT( mi.t() + (mi * mt), mi_tr + d1); + CHECK_DIFF_FLT( (mi * mt) - mi.t(), d1 - mi_tr); + CHECK_DIFF_FLT( mi.t() - (mi * mt), mi_tr - d1); + + CHECK_DIFF_FLT( 2.0 *(mi * mt + d2), d1 * 6); + CHECK_DIFF_FLT( -(mi * mt + d2), d1 * -3); + + CHECK_DIFF_FLT(mt.inv() * mt, d1); + + CHECK_DIFF_FLT(mt.inv() * (2*mt - mt), d1); +#endif + } + catch (const test_excep& e) + { + ts->printf(cvtest::TS::LOG, "%s\n", e.s.c_str()); + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + return false; + } + return true; +} + +bool CV_OperationsTest::SomeMatFunctions() +{ + try + { + Mat rgba( 10, 10, CV_8UC4, Scalar(1,2,3,4) ); + Mat bgr( rgba.rows, rgba.cols, CV_8UC3 ); + Mat alpha( rgba.rows, rgba.cols, CV_8UC1 ); + Mat out[] = { bgr, alpha }; + // rgba[0] -> bgr[2], rgba[1] -> bgr[1], + // rgba[2] -> bgr[0], rgba[3] -> alpha[0] + int from_to[] = { 0,2, 1,1, 2,0, 3,3 }; + mixChannels( &rgba, 1, out, 2, from_to, 4 ); + + Mat bgr_exp( rgba.size(), CV_8UC3, Scalar(3,2,1)); + Mat alpha_exp( rgba.size(), CV_8UC1, Scalar(4)); + + CHECK_DIFF(bgr_exp, bgr); + CHECK_DIFF(alpha_exp, alpha); + } + catch (const test_excep& e) + { + ts->printf(cvtest::TS::LOG, "%s\n", e.s.c_str()); + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + return false; + } + return true; + +} + + +bool CV_OperationsTest::TestSubMatAccess() +{ + try + { + Mat_ T_bs(4,4); + Vec3f cdir(1.f, 1.f, 0.f); + Vec3f ydir(1.f, 0.f, 1.f); + Vec3f fpt(0.1f, 0.7f, 0.2f); + T_bs.setTo(0); + T_bs(Range(0,3),Range(2,3)) = 1.0*Mat(cdir); // wierd OpenCV stuff, need to do multiply + T_bs(Range(0,3),Range(1,2)) = 1.0*Mat(ydir); + T_bs(Range(0,3),Range(0,1)) = 1.0*Mat(cdir.cross(ydir)); + T_bs(Range(0,3),Range(3,4)) = 1.0*Mat(fpt); + T_bs(3,3) = 1.0; + //std::cout << "[Nav Grok] S frame =" << std::endl << T_bs << std::endl; + + // set up display coords, really just the S frame + std::vectorcoords; + + for (int i=0; i<16; i++) + { + coords.push_back(T_bs(i)); + //std::cout << T_bs1(i) << std::endl; + } + CV_Assert( norm(coords, T_bs.reshape(1,1), NORM_INF) == 0 ); + } + catch (const test_excep& e) + { + ts->printf(cvtest::TS::LOG, "%s\n", e.s.c_str()); + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + return false; + } + return true; +} + +bool CV_OperationsTest::TestTemplateMat() +{ + try + { + Mat_ one_3x1(3, 1, 1.0f); + Mat_ shi_3x1(3, 1, 1.2f); + Mat_ shi_2x1(2, 1, -2); + Scalar shift = Scalar::all(15); + + float data[] = { sqrt(2.f)/2, -sqrt(2.f)/2, 1.f, sqrt(2.f)/2, sqrt(2.f)/2, 10.f }; + Mat_ rot_2x3(2, 3, data); + + Mat_ res = Mat(Mat(2 * rot_2x3) * Mat(one_3x1 + shi_3x1 + shi_3x1 + shi_3x1) - shi_2x1) + shift; + Mat_ resS = rot_2x3 * one_3x1; + + Mat_ tmp, res2, resS2; + add(one_3x1, shi_3x1, tmp); + add(tmp, shi_3x1, tmp); + add(tmp, shi_3x1, tmp); + gemm(rot_2x3, tmp, 2, shi_2x1, -1, res2, 0); + add(res2, Mat(2, 1, CV_32F, shift), res2); + + gemm(rot_2x3, one_3x1, 1, shi_2x1, 0, resS2, 0); + CHECK_DIFF(res, res2); + CHECK_DIFF(resS, resS2); + + + Mat_ mat4x4(4, 4); + randu(mat4x4, Scalar(0), Scalar(10)); + + Mat_ roi1 = mat4x4(Rect(Point(1, 1), Size(2, 2))); + Mat_ roi2 = mat4x4(Range(1, 3), Range(1, 3)); + + CHECK_DIFF(roi1, roi2); + CHECK_DIFF(mat4x4, mat4x4(Rect(Point(0,0), mat4x4.size()))); + + Mat_ intMat10(3, 3, 10); + Mat_ intMat11(3, 3, 11); + Mat_ resMat(3, 3, 255); + + CHECK_DIFF(resMat, intMat10 == intMat10); + CHECK_DIFF(resMat, intMat10 < intMat11); + CHECK_DIFF(resMat, intMat11 > intMat10); + CHECK_DIFF(resMat, intMat10 <= intMat11); + CHECK_DIFF(resMat, intMat11 >= intMat10); + + CHECK_DIFF(resMat, intMat10 == 10.0); + CHECK_DIFF(resMat, intMat10 < 11.0); + CHECK_DIFF(resMat, intMat11 > 10.0); + CHECK_DIFF(resMat, intMat10 <= 11.0); + CHECK_DIFF(resMat, intMat11 >= 10.0); + + Mat_ maskMat4(3, 3, 4); + Mat_ maskMat1(3, 3, 1); + Mat_ maskMat5(3, 3, 5); + Mat_ maskMat0(3, 3, (uchar)0); + + CHECK_DIFF(maskMat0, maskMat4 & maskMat1); + CHECK_DIFF(maskMat0, Scalar(1) & maskMat4); + CHECK_DIFF(maskMat0, maskMat4 & Scalar(1)); + + Mat_ m; + m = maskMat4.clone(); m&=maskMat1; CHECK_DIFF(maskMat0, m); + m = maskMat4.clone(); m&=Scalar(1); CHECK_DIFF(maskMat0, m); + + m = maskMat4.clone(); m|=maskMat1; CHECK_DIFF(maskMat5, m); + m = maskMat4.clone(); m^=maskMat1; CHECK_DIFF(maskMat5, m); + + CHECK_DIFF(maskMat0, (maskMat4 | maskMat4) & (maskMat1 | maskMat1)); + CHECK_DIFF(maskMat0, (maskMat4 | maskMat4) & maskMat1); + CHECK_DIFF(maskMat0, maskMat4 & (maskMat1 | maskMat1)); + + CHECK_DIFF(maskMat0, maskMat5 ^ (maskMat4 | maskMat1)); + CHECK_DIFF(maskMat0, Scalar(5) ^ (maskMat4 | Scalar(1))); + + CHECK_DIFF(maskMat5, maskMat5 | (maskMat4 ^ maskMat1)); + CHECK_DIFF(maskMat5, maskMat5 | (maskMat4 ^ Scalar(1))); + + CHECK_DIFF(~maskMat1, maskMat1 ^ 0xFF); + CHECK_DIFF(~(maskMat1 | maskMat1), maskMat1 ^ 0xFF); + + CHECK_DIFF(maskMat1 + maskMat4, maskMat5); + CHECK_DIFF(maskMat1 + Scalar(4), maskMat5); + CHECK_DIFF(Scalar(4) + maskMat1, maskMat5); + CHECK_DIFF(Scalar(4) + (maskMat1 & maskMat1), maskMat5); + + CHECK_DIFF(maskMat1 + 4.0, maskMat5); + CHECK_DIFF((maskMat1 & 0xFF) + 4.0, maskMat5); + CHECK_DIFF(4.0 + maskMat1, maskMat5); + + m = maskMat4.clone(); m+=Scalar(1); CHECK_DIFF(m, maskMat5); + m = maskMat4.clone(); m+=maskMat1; CHECK_DIFF(m, maskMat5); + m = maskMat4.clone(); m+=(maskMat1 | maskMat1); CHECK_DIFF(m, maskMat5); + + CHECK_DIFF(maskMat5 - maskMat1, maskMat4); + CHECK_DIFF(maskMat5 - Scalar(1), maskMat4); + CHECK_DIFF((maskMat5 | maskMat5) - Scalar(1), maskMat4); + CHECK_DIFF(maskMat5 - 1, maskMat4); + CHECK_DIFF((maskMat5 | maskMat5) - 1, maskMat4); + CHECK_DIFF((maskMat5 | maskMat5) - (maskMat1 | maskMat1), maskMat4); + + CHECK_DIFF(maskMat1, min(maskMat1, maskMat5)); + CHECK_DIFF(maskMat5, max(maskMat1, maskMat5)); + + m = maskMat5.clone(); m-=Scalar(1); CHECK_DIFF(m, maskMat4); + m = maskMat5.clone(); m-=maskMat1; CHECK_DIFF(m, maskMat4); + m = maskMat5.clone(); m-=(maskMat1 | maskMat1); CHECK_DIFF(m, maskMat4); + + m = maskMat4.clone(); m |= Scalar(1); CHECK_DIFF(maskMat5, m); + m = maskMat5.clone(); m ^= Scalar(1); CHECK_DIFF(maskMat4, m); + + CHECK_DIFF(maskMat1, maskMat4/4.0); + + Mat_ negf(3, 3, -3.0); + Mat_ posf = -negf; + Mat_ posf2 = posf * 2; + Mat_ negi(3, 3, -3); + + CHECK_DIFF(abs(negf), -negf); + CHECK_DIFF(abs(posf - posf2), -negf); + CHECK_DIFF(abs(negi), -(negi & negi)); + + CHECK_DIFF(5.0 - maskMat4, maskMat1); + + + CHECK_DIFF(maskMat4.mul(maskMat4, 0.25), maskMat4); + CHECK_DIFF(maskMat4.mul(maskMat1 * 4, 0.25), maskMat4); + CHECK_DIFF(maskMat4.mul(maskMat4 / 4), maskMat4); + + + ////// Element-wise division + + CHECK_DIFF(maskMat4 / maskMat4, maskMat1); + CHECK_DIFF(4.0 / maskMat4, maskMat1); + m = maskMat4.clone(); m/=4.0; CHECK_DIFF(m, maskMat1); + + //////////////////////////////// + + typedef Mat_ TestMat_t; + + const TestMat_t cnegi = negi.clone(); + + TestMat_t::iterator beg = negi.begin(); + TestMat_t::iterator end = negi.end(); + + TestMat_t::const_iterator cbeg = cnegi.begin(); + TestMat_t::const_iterator cend = cnegi.end(); + + int sum = 0; + for(; beg!=end; ++beg) + sum+=*beg; + + for(; cbeg!=cend; ++cbeg) + sum-=*cbeg; + + if (sum != 0) throw test_excep(); + + CHECK_DIFF(negi.col(1), negi.col(2)); + CHECK_DIFF(negi.row(1), negi.row(2)); + CHECK_DIFF(negi.col(1), negi.diag()); + + if (Mat_(1, 1).elemSize1() != sizeof(float)) throw test_excep(); + if (Mat_(1, 1).elemSize() != 2 * sizeof(float)) throw test_excep(); + if (Mat_(1, 1).depth() != CV_32F) throw test_excep(); + if (Mat_(1, 1).depth() != CV_32F) throw test_excep(); + if (Mat_(1, 1).depth() != CV_32S) throw test_excep(); + if (Mat_(1, 1).depth() != CV_64F) throw test_excep(); + if (Mat_(1, 1).depth() != CV_64F) throw test_excep(); + if (Mat_(1, 1).depth() != CV_8S) throw test_excep(); + if (Mat_(1, 1).depth() != CV_16U) throw test_excep(); + if (Mat_(1, 1).channels() != 1) throw test_excep(); + if (Mat_(1, 1).channels() != 2) throw test_excep(); + if (Mat_(1, 1).channels() != 3) throw test_excep(); + if (Mat_(1, 1).channels() != 3) throw test_excep(); + + Mat_ eye = Mat_::zeros(2, 2); CHECK_DIFF(Mat_::zeros(Size(2, 2)), eye); + eye.at(Point(0,0)) = 1; eye.at(1, 1) = 1; + + CHECK_DIFF(Mat_::eye(2, 2), eye); + CHECK_DIFF(eye, Mat_::eye(Size(2,2))); + + Mat_ ones(2, 2, (uchar)1); + CHECK_DIFF(ones, Mat_::ones(Size(2,2))); + CHECK_DIFF(Mat_::ones(2, 2), ones); + + Mat_ pntMat(2, 2, Point2f(1, 0)); + if(pntMat.stepT() != 2) throw test_excep(); + + uchar uchar_data[] = {1, 0, 0, 1}; + + Mat_ matFromData(1, 4, uchar_data); + const Mat_ mat2 = matFromData.clone(); + CHECK_DIFF(matFromData, eye.reshape(1, 1)); + if (matFromData(Point(0,0)) != uchar_data[0])throw test_excep(); + if (mat2(Point(0,0)) != uchar_data[0]) throw test_excep(); + + if (matFromData(0,0) != uchar_data[0])throw test_excep(); + if (mat2(0,0) != uchar_data[0]) throw test_excep(); + + Mat_ rect(eye, Rect(0, 0, 1, 1)); + if (rect.cols != 1 || rect.rows != 1 || rect(0,0) != uchar_data[0]) throw test_excep(); + + //cv::Mat_<_Tp>::adjustROI(int,int,int,int) + //cv::Mat_<_Tp>::cross(const Mat_&) const + //cv::Mat_<_Tp>::Mat_(const vector<_Tp>&,bool) + //cv::Mat_<_Tp>::Mat_(int,int,_Tp*,size_t) + //cv::Mat_<_Tp>::Mat_(int,int,const _Tp&) + //cv::Mat_<_Tp>::Mat_(Size,const _Tp&) + //cv::Mat_<_Tp>::mul(const Mat_<_Tp>&,double) const + //cv::Mat_<_Tp>::mul(const MatExpr_,double,Mat_<_Tp>,MatOp_DivRS_ >,Mat_<_Tp> >&,double) const + //cv::Mat_<_Tp>::mul(const MatExpr_,double,Mat_<_Tp>,MatOp_Scale_ >,Mat_<_Tp> >&,double) const + //cv::Mat_<_Tp>::operator Mat_() const + //cv::Mat_<_Tp>::operator MatExpr_,Mat_<_Tp> >() const + //cv::Mat_<_Tp>::operator()(const Range&,const Range&) const + //cv::Mat_<_Tp>::operator()(const Rect&) const + + //cv::Mat_<_Tp>::operator=(const MatExpr_Base&) + //cv::Mat_<_Tp>::operator[](int) const + + + /////////////////////////////// + + float matrix_data[] = { 3, 1, -4, -5, 1, 0, 0, 1.1f, 1.5f}; + Mat_ mt(3, 3, matrix_data); + Mat_ mi = mt.inv(); + Mat_ d1 = Mat_::eye(3, 3); + Mat_ d2 = d1 * 2; + Mat_ mt_tr = mt.t(); + Mat_ mi_tr = mi.t(); + Mat_ mi2 = mi * 2; + + CHECK_DIFF_FLT( mi2 * mt, d2 ); + CHECK_DIFF_FLT( mi * mt, d1 ); + CHECK_DIFF_FLT( mt_tr * mi_tr, d1 ); + + Mat_ mf; + mf = mi.clone(); mf*=mt; CHECK_DIFF_FLT(mf, d1); + + ////// typedefs ////// + + if (Mat1b(1, 1).elemSize() != sizeof(uchar)) throw test_excep(); + if (Mat2b(1, 1).elemSize() != 2 * sizeof(uchar)) throw test_excep(); + if (Mat3b(1, 1).elemSize() != 3 * sizeof(uchar)) throw test_excep(); + if (Mat1f(1, 1).elemSize() != sizeof(float)) throw test_excep(); + if (Mat2f(1, 1).elemSize() != 2 * sizeof(float)) throw test_excep(); + if (Mat3f(1, 1).elemSize() != 3 * sizeof(float)) throw test_excep(); + if (Mat1f(1, 1).depth() != CV_32F) throw test_excep(); + if (Mat3f(1, 1).depth() != CV_32F) throw test_excep(); + if (Mat3f(1, 1).type() != CV_32FC3) throw test_excep(); + if (Mat1i(1, 1).depth() != CV_32S) throw test_excep(); + if (Mat1d(1, 1).depth() != CV_64F) throw test_excep(); + if (Mat1b(1, 1).depth() != CV_8U) throw test_excep(); + if (Mat3b(1, 1).type() != CV_8UC3) throw test_excep(); + if (Mat1w(1, 1).depth() != CV_16U) throw test_excep(); + if (Mat1s(1, 1).depth() != CV_16S) throw test_excep(); + if (Mat1f(1, 1).channels() != 1) throw test_excep(); + if (Mat1b(1, 1).channels() != 1) throw test_excep(); + if (Mat1i(1, 1).channels() != 1) throw test_excep(); + if (Mat1w(1, 1).channels() != 1) throw test_excep(); + if (Mat1s(1, 1).channels() != 1) throw test_excep(); + if (Mat2f(1, 1).channels() != 2) throw test_excep(); + if (Mat2b(1, 1).channels() != 2) throw test_excep(); + if (Mat2i(1, 1).channels() != 2) throw test_excep(); + if (Mat2w(1, 1).channels() != 2) throw test_excep(); + if (Mat2s(1, 1).channels() != 2) throw test_excep(); + if (Mat3f(1, 1).channels() != 3) throw test_excep(); + if (Mat3b(1, 1).channels() != 3) throw test_excep(); + if (Mat3i(1, 1).channels() != 3) throw test_excep(); + if (Mat3w(1, 1).channels() != 3) throw test_excep(); + if (Mat3s(1, 1).channels() != 3) throw test_excep(); + + vector > mvf, mvf2; + Mat_ mf2; + mvf.push_back(Mat_::ones(4, 3)); + mvf.push_back(Mat_::zeros(4, 3)); + merge(mvf, mf2); + split(mf2, mvf2); + CV_Assert( norm(mvf2[0], mvf[0], CV_C) == 0 && + norm(mvf2[1], mvf[1], CV_C) == 0 ); + + { + Mat a(2,2,CV_32F,1.f); + Mat b(1,2,CV_32F,1.f); + Mat c = (a*b.t()).t(); + CV_Assert( norm(c, CV_L1) == 4. ); + } + } + catch (const test_excep& e) + { + ts->printf(cvtest::TS::LOG, "%s\n", e.s.c_str()); + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + return false; + } + return true; +} + +bool CV_OperationsTest::TestMatND() +{ + int sizes[] = { 3, 3, 3}; + cv::MatND nd(3, sizes, CV_32F); + + return true; +} + +bool CV_OperationsTest::TestSparseMat() +{ + try + { + int sizes[] = { 10, 10, 10}; + int dims = sizeof(sizes)/sizeof(sizes[0]); + SparseMat mat(dims, sizes, CV_32FC2); + + if (mat.dims() != dims) throw test_excep(); + if (mat.channels() != 2) throw test_excep(); + if (mat.depth() != CV_32F) throw test_excep(); + + SparseMat mat2 = mat.clone(); + } + catch (const test_excep&) + { + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + return false; + } + return true; +} + + +bool CV_OperationsTest::TestMatxMultiplication() +{ + try + { + Matx33f mat(1, 1, 1, 0, 1, 1, 0, 0, 1); // Identity matrix + Point2f pt(3, 4); + Point3f res = mat * pt; // Correctly assumes homogeneous coordinates + + Vec3f res2 = mat*Vec3f(res.x, res.y, res.z); + + if(res.x != 8.0) throw test_excep(); + if(res.y != 5.0) throw test_excep(); + if(res.z != 1.0) throw test_excep(); + + if(res2[0] != 14.0) throw test_excep(); + if(res2[1] != 6.0) throw test_excep(); + if(res2[2] != 1.0) throw test_excep(); + + Matx44f mat44f(1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1); + Matx44d mat44d(1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1); + Scalar s(4, 3, 2, 1); + Scalar sf = mat44f*s; + Scalar sd = mat44d*s; + + if(sf[0] != 10.0) throw test_excep(); + if(sf[1] != 6.0) throw test_excep(); + if(sf[2] != 3.0) throw test_excep(); + if(sf[3] != 1.0) throw test_excep(); + + if(sd[0] != 10.0) throw test_excep(); + if(sd[1] != 6.0) throw test_excep(); + if(sd[2] != 3.0) throw test_excep(); + if(sd[3] != 1.0) throw test_excep(); + } + catch(const test_excep&) + { + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); + return false; + } + return true; +} + + +bool CV_OperationsTest::TestVec() +{ + try + { + cv::Mat hsvImage_f(5, 5, CV_32FC3), hsvImage_b(5, 5, CV_8UC3); + int i = 0,j = 0; + cv::Vec3f a; + + //these compile + cv::Vec3b b = a; + hsvImage_f.at(i,j) = cv::Vec3f((float)i,0,1); + hsvImage_b.at(i,j) = cv::Vec3b(cv::Vec3f((float)i,0,1)); + + //these don't + b = cv::Vec3f(1,0,0); + cv::Vec3b c; + c = cv::Vec3f(0,0,1); + hsvImage_b.at(i,j) = cv::Vec3f((float)i,0,1); + hsvImage_b.at(i,j) = a; + hsvImage_b.at(i,j) = cv::Vec3f(1,2,3); + } + catch(const test_excep&) + { + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); + return false; + } + return true; +} + +bool CV_OperationsTest::operations1() +{ + try + { + Point3d p1(1, 1, 1), p2(2, 2, 2), p4(4, 4, 4); + p1*=2; + if (!(p1 == p2)) throw test_excep(); + if (!(p2 * 2 == p4)) throw test_excep(); + if (!(p2 * 2.f == p4)) throw test_excep(); + if (!(p2 * 2.f == p4)) throw test_excep(); + + Point2d pi1(1, 1), pi2(2, 2), pi4(4, 4); + pi1*=2; + if (!(pi1 == pi2)) throw test_excep(); + if (!(pi2 * 2 == pi4)) throw test_excep(); + if (!(pi2 * 2.f == pi4)) throw test_excep(); + if (!(pi2 * 2.f == pi4)) throw test_excep(); + + Vec2d v12(1, 1), v22(2, 2); + v12*=2.0; + if (!(v12 == v22)) throw test_excep(); + + Vec3d v13(1, 1, 1), v23(2, 2, 2); + v13*=2.0; + if (!(v13 == v23)) throw test_excep(); + + Vec4d v14(1, 1, 1, 1), v24(2, 2, 2, 2); + v14*=2.0; + if (!(v14 == v24)) throw test_excep(); + + Size sz(10, 20); + if (sz.area() != 200) throw test_excep(); + if (sz.width != 10 || sz.height != 20) throw test_excep(); + if (((CvSize)sz).width != 10 || ((CvSize)sz).height != 20) throw test_excep(); + + Vec v5d(1, 1, 1, 1, 1); + Vec v6d(1, 1, 1, 1, 1, 1); + Vec v7d(1, 1, 1, 1, 1, 1, 1); + Vec v8d(1, 1, 1, 1, 1, 1, 1, 1); + Vec v9d(1, 1, 1, 1, 1, 1, 1, 1, 1); + Vec v10d(1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + Vec v10dzero; + for (int ii = 0; ii < 10; ++ii) { + if (!v10dzero[ii] == 0.0) + throw test_excep(); + } + + Mat A(1, 32, CV_32F), B; + for( int i = 0; i < A.cols; i++ ) + A.at(i) = (float)(i <= 12 ? i : 24 - i); + transpose(A, B); + + int minidx[2] = {0, 0}, maxidx[2] = {0, 0}; + double minval = 0, maxval = 0; + minMaxIdx(A, &minval, &maxval, minidx, maxidx); + + if( !(minidx[0] == 0 && minidx[1] == 31 && maxidx[0] == 0 && maxidx[1] == 12 && + minval == -7 && maxval == 12)) + throw test_excep(); + + minMaxIdx(B, &minval, &maxval, minidx, maxidx); + + if( !(minidx[0] == 31 && minidx[1] == 0 && maxidx[0] == 12 && maxidx[1] == 0 && + minval == -7 && maxval == 12)) + throw test_excep(); + } + catch(const test_excep&) + { + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + return false; + } + return true; +} + + +bool CV_OperationsTest::TestSVD() +{ + try + { + Mat A = (Mat_(3,4) << 1, 2, -1, 4, 2, 4, 3, 5, -1, -2, 6, 7); + Mat x; + SVD::solveZ(A,x); + if( norm(A*x, CV_C) > FLT_EPSILON ) + throw test_excep(); + + SVD svd(A, SVD::FULL_UV); + if( norm(A*svd.vt.row(3).t(), CV_C) > FLT_EPSILON ) + throw test_excep(); + + Mat Dp(3,3,CV_32FC1); + Mat Dc(3,3,CV_32FC1); + Mat Q(3,3,CV_32FC1); + Mat U,Vt,R,T,W; + + Dp.at(0,0)=0.86483884f; Dp.at(0,1)= -0.3077251f; Dp.at(0,2)=-0.55711365f; + Dp.at(1,0)=0.49294353f; Dp.at(1,1)=-0.24209651f; Dp.at(1,2)=-0.25084701f; + Dp.at(2,0)=0; Dp.at(2,1)=0; Dp.at(2,2)=0; + + Dc.at(0,0)=0.75632739f; Dc.at(0,1)= -0.38859656f; Dc.at(0,2)=-0.36773083f; + Dc.at(1,0)=0.9699229f; Dc.at(1,1)=-0.49858192f; Dc.at(1,2)=-0.47134098f; + Dc.at(2,0)=0.10566688f; Dc.at(2,1)=-0.060333252f; Dc.at(2,2)=-0.045333147f; + + Q=Dp*Dc.t(); + SVD decomp; + decomp=SVD(Q); + U=decomp.u; + Vt=decomp.vt; + W=decomp.w; + Mat I = Mat::eye(3, 3, CV_32F); + + if( norm(U*U.t(), I, CV_C) > FLT_EPSILON || + norm(Vt*Vt.t(), I, CV_C) > FLT_EPSILON || + W.at(2) < 0 || W.at(1) < W.at(2) || + W.at(0) < W.at(1) || + norm(U*Mat::diag(W)*Vt, Q, CV_C) > FLT_EPSILON ) + throw test_excep(); + } + catch(const test_excep&) + { + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + return false; + } + return true; +} + +void CV_OperationsTest::run( int /* start_from */) +{ + if (!TestMat()) + return; + + if (!SomeMatFunctions()) + return; + + if (!TestTemplateMat()) + return; + + /* if (!TestMatND()) + return;*/ + + if (!TestSparseMat()) + return; + + if (!TestVec()) + return; + + if (!TestMatxMultiplication()) + return; + + if (!TestSubMatAccess()) + return; + + if (!TestSVD()) + return; + + if (!operations1()) + return; + + ts->set_failed_test_info(cvtest::TS::OK); +} + +TEST(Core_Array, expressions) { CV_OperationsTest test; test.safe_run(); } + +class CV_SparseMatTest : public cvtest::BaseTest +{ +public: + CV_SparseMatTest() {} + ~CV_SparseMatTest() {} +protected: + void run(int) + { + try + { + RNG& rng = theRNG(); + const int MAX_DIM=3; + int sizes[MAX_DIM], idx[MAX_DIM]; + for( int iter = 0; iter < 100; iter++ ) + { + ts->printf(cvtest::TS::LOG, "."); + ts->update_context(this, iter, true); + int k, dims = rng.uniform(1, MAX_DIM+1), p = 1; + for( k = 0; k < dims; k++ ) + { + sizes[k] = rng.uniform(1, 30); + p *= sizes[k]; + } + int j, nz = rng.uniform(0, (p+2)/2), nz0 = 0; + SparseMat_ v(dims,sizes); + + CV_Assert( (int)v.nzcount() == 0 ); + + SparseMatIterator_ it = v.begin(); + SparseMatIterator_ it_end = v.end(); + + for( k = 0; it != it_end; ++it, ++k ) + ; + CV_Assert( k == 0 ); + + int sum0 = 0, sum = 0; + for( j = 0; j < nz; j++ ) + { + int val = rng.uniform(1, 100); + for( k = 0; k < dims; k++ ) + idx[k] = rng.uniform(0, sizes[k]); + if( dims == 1 ) + { + CV_Assert( v.ref(idx[0]) == v(idx[0]) ); + } + else if( dims == 2 ) + { + CV_Assert( v.ref(idx[0], idx[1]) == v(idx[0], idx[1]) ); + } + else if( dims == 3 ) + { + CV_Assert( v.ref(idx[0], idx[1], idx[2]) == v(idx[0], idx[1], idx[2]) ); + } + CV_Assert( v.ref(idx) == v(idx) ); + v.ref(idx) += val; + if( v(idx) == val ) + nz0++; + sum0 += val; + } + + CV_Assert( (int)v.nzcount() == nz0 ); + + it = v.begin(); + it_end = v.end(); + + for( k = 0; it != it_end; ++it, ++k ) + sum += *it; + CV_Assert( k == nz0 && sum == sum0 ); + + v.clear(); + CV_Assert( (int)v.nzcount() == 0 ); + + it = v.begin(); + it_end = v.end(); + + for( k = 0; it != it_end; ++it, ++k ) + ; + CV_Assert( k == 0 ); + } + } + catch(...) + { + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + } + } +}; + +TEST(Core_SparseMat, iterations) { CV_SparseMatTest test; test.safe_run(); } diff --git a/core/test/test_precomp.cpp b/core/test/test_precomp.cpp new file mode 100644 index 0000000..5956e13 --- /dev/null +++ b/core/test/test_precomp.cpp @@ -0,0 +1 @@ +#include "test_precomp.hpp" diff --git a/core/test/test_precomp.hpp b/core/test/test_precomp.hpp new file mode 100644 index 0000000..1326195 --- /dev/null +++ b/core/test/test_precomp.hpp @@ -0,0 +1,13 @@ +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wmissing-declarations" +# pragma GCC diagnostic ignored "-Wmissing-prototypes" //OSX +#endif + +#ifndef __OPENCV_TEST_PRECOMP_HPP__ +#define __OPENCV_TEST_PRECOMP_HPP__ + +#include "opencv2/ts/ts.hpp" +#include "opencv2/core/core_c.h" +#include + +#endif diff --git a/core/test/test_rand.cpp b/core/test/test_rand.cpp new file mode 100644 index 0000000..e93415b --- /dev/null +++ b/core/test/test_rand.cpp @@ -0,0 +1,341 @@ +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +class Core_RandTest : public cvtest::BaseTest +{ +public: + Core_RandTest(); +protected: + void run(int); + bool check_pdf(const Mat& hist, double scale, int dist_type, + double& refval, double& realval); +}; + + +Core_RandTest::Core_RandTest() +{ +} + +static double chi2_p95(int n) +{ + static float chi2_tab95[] = { + 3.841f, 5.991f, 7.815f, 9.488f, 11.07f, 12.59f, 14.07f, 15.51f, + 16.92f, 18.31f, 19.68f, 21.03f, 21.03f, 22.36f, 23.69f, 25.00f, + 26.30f, 27.59f, 28.87f, 30.14f, 31.41f, 32.67f, 33.92f, 35.17f, + 36.42f, 37.65f, 38.89f, 40.11f, 41.34f, 42.56f, 43.77f }; + static const double xp = 1.64; + CV_Assert(n >= 1); + + if( n <= 30 ) + return chi2_tab95[n-1]; + return n + sqrt((double)2*n)*xp + 0.6666666666666*(xp*xp - 1); +} + +bool Core_RandTest::check_pdf(const Mat& hist, double scale, + int dist_type, double& refval, double& realval) +{ + Mat hist0(hist.size(), CV_32F); + const int* H = (const int*)hist.data; + float* H0 = ((float*)hist0.data); + int i, hsz = hist.cols; + + double sum = 0; + for( i = 0; i < hsz; i++ ) + sum += H[i]; + CV_Assert( fabs(1./sum - scale) < FLT_EPSILON ); + + if( dist_type == CV_RAND_UNI ) + { + float scale0 = (float)(1./hsz); + for( i = 0; i < hsz; i++ ) + H0[i] = scale0; + } + else + { + double sum2 = 0, r = (hsz-1.)/2; + double alpha = 2*sqrt(2.)/r, beta = -alpha*r; + for( i = 0; i < hsz; i++ ) + { + double x = i*alpha + beta; + H0[i] = (float)exp(-x*x); + sum2 += H0[i]; + } + sum2 = 1./sum2; + for( i = 0; i < hsz; i++ ) + H0[i] = (float)(H0[i]*sum2); + } + + double chi2 = 0; + for( i = 0; i < hsz; i++ ) + { + double a = H0[i]; + double b = H[i]*scale; + if( a > DBL_EPSILON ) + chi2 += (a - b)*(a - b)/(a + b); + } + realval = chi2; + + double chi2_pval = chi2_p95(hsz - 1 - (dist_type == CV_RAND_NORMAL ? 2 : 0)); + refval = chi2_pval*0.01; + return realval <= refval; +} + +void Core_RandTest::run( int ) +{ + static int _ranges[][2] = + {{ 0, 256 }, { -128, 128 }, { 0, 65536 }, { -32768, 32768 }, + { -1000000, 1000000 }, { -1000, 1000 }, { -1000, 1000 }}; + + const int MAX_SDIM = 10; + const int N = 2000000; + const int maxSlice = 1000; + const int MAX_HIST_SIZE = 1000; + int progress = 0; + + RNG& rng = ts->get_rng(); + RNG tested_rng = theRNG(); + test_case_count = 200; + + for( int idx = 0; idx < test_case_count; idx++ ) + { + progress = update_progress( progress, idx, test_case_count, 0 ); + ts->update_context( this, idx, false ); + + int depth = cvtest::randInt(rng) % (CV_64F+1); + int c, cn = (cvtest::randInt(rng) % 4) + 1; + int type = CV_MAKETYPE(depth, cn); + int dist_type = cvtest::randInt(rng) % (CV_RAND_NORMAL+1); + int i, k, SZ = N/cn; + Scalar A, B; + + double eps = 1.e-4; + if (depth == CV_64F) + eps = 1.e-7; + + bool do_sphere_test = dist_type == CV_RAND_UNI; + Mat arr[2], hist[4]; + int W[] = {0,0,0,0}; + + arr[0].create(1, SZ, type); + arr[1].create(1, SZ, type); + bool fast_algo = dist_type == CV_RAND_UNI && depth < CV_32F; + + for( c = 0; c < cn; c++ ) + { + int a, b, hsz; + if( dist_type == CV_RAND_UNI ) + { + a = (int)(cvtest::randInt(rng) % (_ranges[depth][1] - + _ranges[depth][0])) + _ranges[depth][0]; + do + { + b = (int)(cvtest::randInt(rng) % (_ranges[depth][1] - + _ranges[depth][0])) + _ranges[depth][0]; + } + while( abs(a-b) <= 1 ); + if( a > b ) + std::swap(a, b); + + unsigned r = (unsigned)(b - a); + fast_algo = fast_algo && r <= 256 && (r & (r-1)) == 0; + hsz = min((unsigned)(b - a), (unsigned)MAX_HIST_SIZE); + do_sphere_test = do_sphere_test && b - a >= 100; + } + else + { + int vrange = _ranges[depth][1] - _ranges[depth][0]; + int meanrange = vrange/16; + int mindiv = MAX(vrange/20, 5); + int maxdiv = MIN(vrange/8, 10000); + + a = cvtest::randInt(rng) % meanrange - meanrange/2 + + (_ranges[depth][0] + _ranges[depth][1])/2; + b = cvtest::randInt(rng) % (maxdiv - mindiv) + mindiv; + hsz = min((unsigned)b*9, (unsigned)MAX_HIST_SIZE); + } + A[c] = a; + B[c] = b; + hist[c].create(1, hsz, CV_32S); + } + + cv::RNG saved_rng = tested_rng; + int maxk = fast_algo ? 0 : 1; + for( k = 0; k <= maxk; k++ ) + { + tested_rng = saved_rng; + int sz = 0, dsz = 0, slice; + for( slice = 0; slice < maxSlice; slice++, sz += dsz ) + { + dsz = slice+1 < maxSlice ? (int)(cvtest::randInt(rng) % (SZ - sz + 1)) : SZ - sz; + Mat aslice = arr[k].colRange(sz, sz + dsz); + tested_rng.fill(aslice, dist_type, A, B); + } + } + + if( maxk >= 1 && norm(arr[0], arr[1], NORM_INF) > eps) + { + ts->printf( cvtest::TS::LOG, "RNG output depends on the array lengths (some generated numbers get lost?)" ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + + for( c = 0; c < cn; c++ ) + { + const uchar* data = arr[0].data; + int* H = hist[c].ptr(); + int HSZ = hist[c].cols; + double minVal = dist_type == CV_RAND_UNI ? A[c] : A[c] - B[c]*4; + double maxVal = dist_type == CV_RAND_UNI ? B[c] : A[c] + B[c]*4; + double scale = HSZ/(maxVal - minVal); + double delta = -minVal*scale; + + hist[c] = Scalar::all(0); + + for( i = c; i < SZ*cn; i += cn ) + { + double val = depth == CV_8U ? ((const uchar*)data)[i] : + depth == CV_8S ? ((const schar*)data)[i] : + depth == CV_16U ? ((const ushort*)data)[i] : + depth == CV_16S ? ((const short*)data)[i] : + depth == CV_32S ? ((const int*)data)[i] : + depth == CV_32F ? ((const float*)data)[i] : + ((const double*)data)[i]; + int ival = cvFloor(val*scale + delta); + if( (unsigned)ival < (unsigned)HSZ ) + { + H[ival]++; + W[c]++; + } + else if( dist_type == CV_RAND_UNI ) + { + if( (minVal <= val && val < maxVal) || (depth >= CV_32F && val == maxVal) ) + { + H[ival < 0 ? 0 : HSZ-1]++; + W[c]++; + } + else + { + putchar('^'); + } + } + } + + if( dist_type == CV_RAND_UNI && W[c] != SZ ) + { + ts->printf( cvtest::TS::LOG, "Uniform RNG gave values out of the range [%g,%g) on channel %d/%d\n", + A[c], B[c], c, cn); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + if( dist_type == CV_RAND_NORMAL && W[c] < SZ*.90) + { + ts->printf( cvtest::TS::LOG, "Normal RNG gave too many values out of the range (%g+4*%g,%g+4*%g) on channel %d/%d\n", + A[c], B[c], A[c], B[c], c, cn); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + double refval = 0, realval = 0; + + if( !check_pdf(hist[c], 1./W[c], dist_type, refval, realval) ) + { + ts->printf( cvtest::TS::LOG, "RNG failed Chi-square test " + "(got %g vs probable maximum %g) on channel %d/%d\n", + realval, refval, c, cn); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + } + + // Monte-Carlo test. Compute volume of SDIM-dimensional sphere + // inscribed in [-1,1]^SDIM cube. + if( do_sphere_test ) + { + int SDIM = cvtest::randInt(rng) % (MAX_SDIM-1) + 2; + int N0 = (SZ*cn/SDIM), n = 0; + double r2 = 0; + const uchar* data = arr[0].data; + double scale[4], delta[4]; + for( c = 0; c < cn; c++ ) + { + scale[c] = 2./(B[c] - A[c]); + delta[c] = -A[c]*scale[c] - 1; + } + + for( i = k = c = 0; i <= SZ*cn - SDIM; i++, k++, c++ ) + { + double val = depth == CV_8U ? ((const uchar*)data)[i] : + depth == CV_8S ? ((const schar*)data)[i] : + depth == CV_16U ? ((const ushort*)data)[i] : + depth == CV_16S ? ((const short*)data)[i] : + depth == CV_32S ? ((const int*)data)[i] : + depth == CV_32F ? ((const float*)data)[i] : ((const double*)data)[i]; + c &= c < cn ? -1 : 0; + val = val*scale[c] + delta[c]; + r2 += val*val; + if( k == SDIM-1 ) + { + n += r2 <= 1; + r2 = 0; + k = -1; + } + } + + double V = ((double)n/N0)*(1 << SDIM); + + // the theoretically computed volume + int sdim = SDIM % 2; + double V0 = sdim + 1; + for( sdim += 2; sdim <= SDIM; sdim += 2 ) + V0 *= 2*CV_PI/sdim; + + if( fabs(V - V0) > 0.3*fabs(V0) ) + { + ts->printf( cvtest::TS::LOG, "RNG failed %d-dim sphere volume test (got %g instead of %g)\n", + SDIM, V, V0); + ts->printf( cvtest::TS::LOG, "depth = %d, N0 = %d\n", depth, N0); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return; + } + } + } +} + +TEST(Core_Rand, quality) { Core_RandTest test; test.safe_run(); } + + +class Core_RandRangeTest : public cvtest::BaseTest +{ +public: + Core_RandRangeTest() {} + ~Core_RandRangeTest() {} +protected: + void run(int) + { + Mat a(Size(1280, 720), CV_8U, Scalar(20)); + Mat af(Size(1280, 720), CV_32F, Scalar(20)); + theRNG().fill(a, RNG::UNIFORM, -DBL_MAX, DBL_MAX); + theRNG().fill(af, RNG::UNIFORM, -DBL_MAX, DBL_MAX); + int n0 = 0, n255 = 0, nx = 0; + int nfmin = 0, nfmax = 0, nfx = 0; + + for( int i = 0; i < a.rows; i++ ) + for( int j = 0; j < a.cols; j++ ) + { + int v = a.at(i,j); + double vf = af.at(i,j); + if( v == 0 ) n0++; + else if( v == 255 ) n255++; + else nx++; + if( vf < FLT_MAX*-0.999f ) nfmin++; + else if( vf > FLT_MAX*0.999f ) nfmax++; + else nfx++; + } + CV_Assert( n0 > nx*2 && n255 > nx*2 ); + CV_Assert( nfmin > nfx*2 && nfmax > nfx*2 ); + } +}; + +TEST(Core_Rand, range) { Core_RandRangeTest test; test.safe_run(); } + diff --git a/highgui/.DS_Store b/highgui/.DS_Store new file mode 100644 index 0000000..f013094 Binary files /dev/null and b/highgui/.DS_Store differ diff --git a/highgui/.highgui/CMakeFiles/CMakeDirectoryInformation.cmake b/highgui/.highgui/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000..18abf29 --- /dev/null +++ b/highgui/.highgui/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Relative path conversion top directories. +SET(CMAKE_RELATIVE_PATH_TOP_SOURCE "/Users/beau/Documents/workspace/OpenCV/opencv") +SET(CMAKE_RELATIVE_PATH_TOP_BINARY "/Users/beau/Documents/workspace/OpenCV/opencv") + +# Force unix paths in dependencies. +SET(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +SET(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +SET(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +SET(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +SET(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/highgui/.highgui/CMakeFiles/progress.marks b/highgui/.highgui/CMakeFiles/progress.marks new file mode 100644 index 0000000..573541a --- /dev/null +++ b/highgui/.highgui/CMakeFiles/progress.marks @@ -0,0 +1 @@ +0 diff --git a/highgui/.highgui/Makefile b/highgui/.highgui/Makefile new file mode 100644 index 0000000..edbfadb --- /dev/null +++ b/highgui/.highgui/Makefile @@ -0,0 +1,167 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." + /opt/local/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /opt/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: install/local +.PHONY : install/local/fast + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /opt/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: install/strip +.PHONY : install/strip/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\" \"main\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /opt/local/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_progress_start /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/.highgui/CMakeFiles/progress.marks + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/highgui/.highgui/all + $(CMAKE_COMMAND) -E cmake_progress_start /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/highgui/.highgui/clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/highgui/.highgui/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/highgui/.highgui/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... rebuild_cache" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/highgui/.highgui/cmake_install.cmake b/highgui/.highgui/cmake_install.cmake new file mode 100644 index 0000000..9fe5aad --- /dev/null +++ b/highgui/.highgui/cmake_install.cmake @@ -0,0 +1,29 @@ +# Install script for directory: /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui + +# Set the install prefix +IF(NOT DEFINED CMAKE_INSTALL_PREFIX) + SET(CMAKE_INSTALL_PREFIX "/usr/local") +ENDIF(NOT DEFINED CMAKE_INSTALL_PREFIX) +STRING(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +IF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + IF(BUILD_TYPE) + STRING(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + ELSE(BUILD_TYPE) + SET(CMAKE_INSTALL_CONFIG_NAME "Release") + ENDIF(BUILD_TYPE) + MESSAGE(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +ENDIF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + +# Set the component getting installed. +IF(NOT CMAKE_INSTALL_COMPONENT) + IF(COMPONENT) + MESSAGE(STATUS "Install component: \"${COMPONENT}\"") + SET(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + ELSE(COMPONENT) + SET(CMAKE_INSTALL_COMPONENT) + ENDIF(COMPONENT) +ENDIF(NOT CMAKE_INSTALL_COMPONENT) + diff --git a/highgui/CMakeFiles/CMakeDirectoryInformation.cmake b/highgui/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000..18abf29 --- /dev/null +++ b/highgui/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Relative path conversion top directories. +SET(CMAKE_RELATIVE_PATH_TOP_SOURCE "/Users/beau/Documents/workspace/OpenCV/opencv") +SET(CMAKE_RELATIVE_PATH_TOP_BINARY "/Users/beau/Documents/workspace/OpenCV/opencv") + +# Force unix paths in dependencies. +SET(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +SET(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +SET(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +SET(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +SET(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/highgui/CMakeFiles/opencv_highgui.dir/DependInfo.cmake b/highgui/CMakeFiles/opencv_highgui.dir/DependInfo.cmake new file mode 100644 index 0000000..6556e4d --- /dev/null +++ b/highgui/CMakeFiles/opencv_highgui.dir/DependInfo.cmake @@ -0,0 +1,88 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/bitstrm.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap_ffmpeg.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap_images.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap_qtkit.mm" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_base.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_bmp.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_exr.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_imageio.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_jpeg.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_jpeg2000.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_png.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_pxm.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_sunras.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_tiff.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/loadsave.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/precomp.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/utils.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/window.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/window_cocoa.mm" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o" + ) +SET(CMAKE_CXX_COMPILER_ID "Clang") + +# Preprocessor definitions for this target. +SET(CMAKE_TARGET_DEFINITIONS + "HAVE_CVCONFIG_H" + "HAVE_ALLOCA" + "HAVE_ALLOCA_H" + "HAVE_LIBPTHREAD" + "HAVE_UNISTD_H" + "HAVE_JPEG" + "HAVE_PNG" + "HAVE_TIFF" + "HAVE_JASPER" + "HAVE_OPENEXR" + "HAVE_COCOA=1" + "HAVE_QUICKTIME=1" + "CVAPI_EXPORTS" + "HIGHGUI_EXPORTS" + ) + +# Pairs of files generated by the same build rule. +SET(CMAKE_MULTIPLE_OUTPUT_PAIRS + "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_highgui.2.4.dylib" "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_highgui.2.4.9.dylib" + "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_highgui.dylib" "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_highgui.2.4.9.dylib" + ) + + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib/CMakeFiles/zlib.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libjpeg/CMakeFiles/libjpeg.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libpng/CMakeFiles/libpng.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libtiff/CMakeFiles/libtiff.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libjasper/CMakeFiles/libjasper.dir/DependInfo.cmake" + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "modules/highgui/perf" + "modules/highgui/include" + "modules/ts/include" + "modules/imgproc/include" + "modules/core/include" + "modules/highgui" + "modules/highgui/src" + "modules/highgui/test" + "3rdparty/libjasper" + "3rdparty/libtiff" + "3rdparty/libpng" + "3rdparty/libjpeg" + "3rdparty/zlib" + "." + "/opt/local/include" + "/opt/local/include/eigen3" + "/opt/local/include/OpenEXR" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/highgui/CMakeFiles/opencv_highgui.dir/build.make b/highgui/CMakeFiles/opencv_highgui.dir/build.make new file mode 100644 index 0000000..9a3c150 --- /dev/null +++ b/highgui/CMakeFiles/opencv_highgui.dir/build.make @@ -0,0 +1,620 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# Include any dependencies generated for this target. +include modules/highgui/CMakeFiles/opencv_highgui.dir/depend.make + +# Include the progress variables for this target. +include modules/highgui/CMakeFiles/opencv_highgui.dir/progress.make + +# Include the compile flags for this target's objects. +include modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o: modules/highgui/src/cap.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/cap.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/cap.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap.cpp > CMakeFiles/opencv_highgui.dir/src/cap.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/cap.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap.cpp -o CMakeFiles/opencv_highgui.dir/src/cap.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o: modules/highgui/src/cap_images.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_2) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap_images.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap_images.cpp > CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap_images.cpp -o CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o: modules/highgui/src/cap_ffmpeg.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_3) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap_ffmpeg.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap_ffmpeg.cpp > CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap_ffmpeg.cpp -o CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o: modules/highgui/src/loadsave.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_4) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/loadsave.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/loadsave.cpp > CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/loadsave.cpp -o CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o: modules/highgui/src/precomp.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_5) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/precomp.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/precomp.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/precomp.cpp > CMakeFiles/opencv_highgui.dir/src/precomp.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/precomp.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/precomp.cpp -o CMakeFiles/opencv_highgui.dir/src/precomp.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o: modules/highgui/src/utils.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_6) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/utils.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/utils.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/utils.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/utils.cpp > CMakeFiles/opencv_highgui.dir/src/utils.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/utils.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/utils.cpp -o CMakeFiles/opencv_highgui.dir/src/utils.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o: modules/highgui/src/window.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_7) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/window.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/window.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/window.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/window.cpp > CMakeFiles/opencv_highgui.dir/src/window.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/window.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/window.cpp -o CMakeFiles/opencv_highgui.dir/src/window.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o: modules/highgui/src/window_cocoa.mm + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_8) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/window_cocoa.mm + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/window_cocoa.mm > CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/window_cocoa.mm -o CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o: modules/highgui/src/cap_qtkit.mm + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_9) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap_qtkit.mm + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap_qtkit.mm > CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/cap_qtkit.mm -o CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o: modules/highgui/src/grfmt_base.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_10) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_base.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_base.cpp > CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_base.cpp -o CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o: modules/highgui/src/grfmt_bmp.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_11) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_bmp.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_bmp.cpp > CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_bmp.cpp -o CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o: modules/highgui/src/grfmt_exr.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_12) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_exr.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_exr.cpp > CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_exr.cpp -o CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o: modules/highgui/src/grfmt_imageio.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_13) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_imageio.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_imageio.cpp > CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_imageio.cpp -o CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o: modules/highgui/src/grfmt_jpeg.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_14) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_jpeg.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_jpeg.cpp > CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_jpeg.cpp -o CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o: modules/highgui/src/grfmt_jpeg2000.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_15) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_jpeg2000.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_jpeg2000.cpp > CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_jpeg2000.cpp -o CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o: modules/highgui/src/grfmt_png.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_16) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_png.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_png.cpp > CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_png.cpp -o CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o: modules/highgui/src/grfmt_pxm.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_17) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_pxm.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_pxm.cpp > CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_pxm.cpp -o CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o: modules/highgui/src/grfmt_sunras.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_18) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_sunras.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_sunras.cpp > CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_sunras.cpp -o CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o: modules/highgui/src/grfmt_tiff.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_19) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_tiff.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_tiff.cpp > CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/grfmt_tiff.cpp -o CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o: modules/highgui/CMakeFiles/opencv_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o: modules/highgui/src/bitstrm.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_20) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/bitstrm.cpp + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/bitstrm.cpp > CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.i + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src/bitstrm.cpp -o CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.s + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o.provides: modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o + +# Object files for target opencv_highgui +opencv_highgui_OBJECTS = \ +"CMakeFiles/opencv_highgui.dir/src/cap.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/utils.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/window.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o" \ +"CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o" \ +"CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o" \ +"CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o" + +# External object files for target opencv_highgui +opencv_highgui_EXTERNAL_OBJECTS = + +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/build.make +lib/libopencv_highgui.2.4.9.dylib: lib/libopencv_core.2.4.9.dylib +lib/libopencv_highgui.2.4.9.dylib: lib/libopencv_imgproc.2.4.9.dylib +lib/libopencv_highgui.2.4.9.dylib: 3rdparty/lib/libzlib.a +lib/libopencv_highgui.2.4.9.dylib: 3rdparty/lib/liblibjpeg.a +lib/libopencv_highgui.2.4.9.dylib: 3rdparty/lib/liblibpng.a +lib/libopencv_highgui.2.4.9.dylib: 3rdparty/lib/liblibtiff.a +lib/libopencv_highgui.2.4.9.dylib: 3rdparty/lib/liblibjasper.a +lib/libopencv_highgui.2.4.9.dylib: /opt/local/lib/libImath.dylib +lib/libopencv_highgui.2.4.9.dylib: /opt/local/lib/libIlmImf.dylib +lib/libopencv_highgui.2.4.9.dylib: /opt/local/lib/libIex.dylib +lib/libopencv_highgui.2.4.9.dylib: /opt/local/lib/libHalf.dylib +lib/libopencv_highgui.2.4.9.dylib: /opt/local/lib/libIlmThread.dylib +lib/libopencv_highgui.2.4.9.dylib: /opt/local/include/../lib/libavcodec.a +lib/libopencv_highgui.2.4.9.dylib: /opt/local/include/../lib/libavformat.a +lib/libopencv_highgui.2.4.9.dylib: /opt/local/include/../lib/libavutil.a +lib/libopencv_highgui.2.4.9.dylib: /opt/local/include/../lib/libswscale.a +lib/libopencv_highgui.2.4.9.dylib: /usr/lib/libbz2.dylib +lib/libopencv_highgui.2.4.9.dylib: lib/libopencv_core.2.4.9.dylib +lib/libopencv_highgui.2.4.9.dylib: 3rdparty/lib/libzlib.a +lib/libopencv_highgui.2.4.9.dylib: modules/highgui/CMakeFiles/opencv_highgui.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX shared library ../../lib/libopencv_highgui.dylib" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/opencv_highgui.dir/link.txt --verbose=$(VERBOSE) + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && $(CMAKE_COMMAND) -E cmake_symlink_library ../../lib/libopencv_highgui.2.4.9.dylib ../../lib/libopencv_highgui.2.4.dylib ../../lib/libopencv_highgui.dylib + +lib/libopencv_highgui.2.4.dylib: lib/libopencv_highgui.2.4.9.dylib + +lib/libopencv_highgui.dylib: lib/libopencv_highgui.2.4.9.dylib + +# Rule to build all files generated by this target. +modules/highgui/CMakeFiles/opencv_highgui.dir/build: lib/libopencv_highgui.dylib +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/build + +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o.requires +modules/highgui/CMakeFiles/opencv_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o.requires +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/requires + +modules/highgui/CMakeFiles/opencv_highgui.dir/clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && $(CMAKE_COMMAND) -P CMakeFiles/opencv_highgui.dir/cmake_clean.cmake +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/clean + +modules/highgui/CMakeFiles/opencv_highgui.dir/depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/depend + diff --git a/highgui/CMakeFiles/opencv_highgui.dir/cmake_clean.cmake b/highgui/CMakeFiles/opencv_highgui.dir/cmake_clean.cmake new file mode 100644 index 0000000..7eb9f6a --- /dev/null +++ b/highgui/CMakeFiles/opencv_highgui.dir/cmake_clean.cmake @@ -0,0 +1,31 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/opencv_highgui.dir/src/cap.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/utils.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/window.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o" + "CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o" + "CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o" + "CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o" + "../../lib/libopencv_highgui.pdb" + "../../lib/libopencv_highgui.dylib" + "../../lib/libopencv_highgui.2.4.9.dylib" + "../../lib/libopencv_highgui.2.4.dylib" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/opencv_highgui.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/highgui/CMakeFiles/opencv_highgui.dir/depend.make b/highgui/CMakeFiles/opencv_highgui.dir/depend.make new file mode 100644 index 0000000..a7901a0 --- /dev/null +++ b/highgui/CMakeFiles/opencv_highgui.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for opencv_highgui. +# This may be replaced when dependencies are built. diff --git a/highgui/CMakeFiles/opencv_highgui.dir/flags.make b/highgui/CMakeFiles/opencv_highgui.dir/flags.make new file mode 100644 index 0000000..8f10b24 --- /dev/null +++ b/highgui/CMakeFiles/opencv_highgui.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -Wno-deprecated-declarations -O3 -DNDEBUG -fPIC -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libjasper -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libtiff -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libpng -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libjpeg -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib -I/Users/beau/Documents/workspace/OpenCV/opencv -I/opt/local/include -I/opt/local/include/eigen3 -I/opt/local/include/OpenEXR + +CXX_DEFINES = -Dopencv_highgui_EXPORTS -DHAVE_CVCONFIG_H -DHAVE_ALLOCA -DHAVE_ALLOCA_H -DHAVE_LIBPTHREAD -DHAVE_UNISTD_H -DHAVE_JPEG -DHAVE_PNG -DHAVE_TIFF -DHAVE_JASPER -DHAVE_OPENEXR -DHAVE_COCOA=1 -DHAVE_QUICKTIME=1 -DCVAPI_EXPORTS -DHIGHGUI_EXPORTS + diff --git a/highgui/CMakeFiles/opencv_highgui.dir/link.txt b/highgui/CMakeFiles/opencv_highgui.dir/link.txt new file mode 100644 index 0000000..dd3c4f4 --- /dev/null +++ b/highgui/CMakeFiles/opencv_highgui.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -Wno-deprecated-declarations -O3 -DNDEBUG -shared -compatibility_version 2.4.0 -current_version 2.4.9 -o ../../lib/libopencv_highgui.2.4.9.dylib -install_name /Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_highgui.2.4.dylib CMakeFiles/opencv_highgui.dir/src/cap.cpp.o CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o CMakeFiles/opencv_highgui.dir/src/utils.cpp.o CMakeFiles/opencv_highgui.dir/src/window.cpp.o CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o -L/opt/local/lib -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib/gcc -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib ../../lib/libopencv_core.2.4.9.dylib ../../lib/libopencv_imgproc.2.4.9.dylib ../../3rdparty/lib/libzlib.a ../../3rdparty/lib/liblibjpeg.a ../../3rdparty/lib/liblibpng.a ../../3rdparty/lib/liblibtiff.a ../../3rdparty/lib/liblibjasper.a /opt/local/lib/libImath.dylib /opt/local/lib/libIlmImf.dylib /opt/local/lib/libIex.dylib /opt/local/lib/libHalf.dylib /opt/local/lib/libIlmThread.dylib -lavcodec -lavformat -lavutil -lswscale /opt/local/include/../lib/libavcodec.a /opt/local/include/../lib/libavformat.a /opt/local/include/../lib/libavutil.a /opt/local/include/../lib/libswscale.a -framework Cocoa /usr/lib/libbz2.dylib -framework VideoDecodeAcceleration -lbz2 -framework QTKit -framework QuartzCore -framework AppKit ../../lib/libopencv_core.2.4.9.dylib ../../3rdparty/lib/libzlib.a diff --git a/highgui/CMakeFiles/opencv_highgui.dir/progress.make b/highgui/CMakeFiles/opencv_highgui.dir/progress.make new file mode 100644 index 0000000..35fe2cc --- /dev/null +++ b/highgui/CMakeFiles/opencv_highgui.dir/progress.make @@ -0,0 +1,21 @@ +CMAKE_PROGRESS_1 = +CMAKE_PROGRESS_2 = +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = +CMAKE_PROGRESS_5 = 38 +CMAKE_PROGRESS_6 = +CMAKE_PROGRESS_7 = +CMAKE_PROGRESS_8 = +CMAKE_PROGRESS_9 = +CMAKE_PROGRESS_10 = +CMAKE_PROGRESS_11 = +CMAKE_PROGRESS_12 = +CMAKE_PROGRESS_13 = 39 +CMAKE_PROGRESS_14 = +CMAKE_PROGRESS_15 = +CMAKE_PROGRESS_16 = +CMAKE_PROGRESS_17 = +CMAKE_PROGRESS_18 = +CMAKE_PROGRESS_19 = +CMAKE_PROGRESS_20 = 40 + diff --git a/highgui/CMakeFiles/opencv_perf_highgui.dir/DependInfo.cmake b/highgui/CMakeFiles/opencv_perf_highgui.dir/DependInfo.cmake new file mode 100644 index 0000000..8402e5d --- /dev/null +++ b/highgui/CMakeFiles/opencv_perf_highgui.dir/DependInfo.cmake @@ -0,0 +1,63 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_input.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_main.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_output.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_precomp.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "Clang") + +# Preprocessor definitions for this target. +SET(CMAKE_TARGET_DEFINITIONS + "HAVE_CVCONFIG_H" + "HAVE_ALLOCA" + "HAVE_ALLOCA_H" + "HAVE_LIBPTHREAD" + "HAVE_UNISTD_H" + "HAVE_JPEG" + "HAVE_PNG" + "HAVE_TIFF" + "HAVE_JASPER" + "HAVE_OPENEXR" + "HAVE_COCOA=1" + "HAVE_QUICKTIME=1" + "CVAPI_EXPORTS" + "HIGHGUI_EXPORTS" + ) + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/CMakeFiles/opencv_ts.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib/CMakeFiles/zlib.dir/DependInfo.cmake" + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "modules/highgui/perf" + "modules/highgui/include" + "modules/ts/include" + "modules/imgproc/include" + "modules/core/include" + "modules/highgui" + "modules/highgui/src" + "modules/highgui/test" + "3rdparty/libjasper" + "3rdparty/libtiff" + "3rdparty/libpng" + "3rdparty/libjpeg" + "3rdparty/zlib" + "." + "/opt/local/include" + "/opt/local/include/eigen3" + "/opt/local/include/OpenEXR" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make b/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make new file mode 100644 index 0000000..d9786b5 --- /dev/null +++ b/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make @@ -0,0 +1,188 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# Include any dependencies generated for this target. +include modules/highgui/CMakeFiles/opencv_perf_highgui.dir/depend.make + +# Include the progress variables for this target. +include modules/highgui/CMakeFiles/opencv_perf_highgui.dir/progress.make + +# Include the compile flags for this target's objects. +include modules/highgui/CMakeFiles/opencv_perf_highgui.dir/flags.make + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o: modules/highgui/perf/perf_input.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_input.cpp + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_input.cpp > CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.i + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_input.cpp -o CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.s + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o.provides: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o: modules/highgui/perf/perf_main.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_2) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_main.cpp + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_main.cpp > CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.i + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_main.cpp -o CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.s + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o.provides: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o: modules/highgui/perf/perf_output.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_3) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_output.cpp + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_output.cpp > CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.i + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_output.cpp -o CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.s + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o.provides: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o: modules/highgui/perf/perf_precomp.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_4) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_precomp.cpp + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_precomp.cpp > CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.i + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf/perf_precomp.cpp -o CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.s + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o.provides: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o + +# Object files for target opencv_perf_highgui +opencv_perf_highgui_OBJECTS = \ +"CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o" \ +"CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o" \ +"CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o" \ +"CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o" + +# External object files for target opencv_perf_highgui +opencv_perf_highgui_EXTERNAL_OBJECTS = + +bin/opencv_perf_highgui: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o +bin/opencv_perf_highgui: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o +bin/opencv_perf_highgui: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o +bin/opencv_perf_highgui: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o +bin/opencv_perf_highgui: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make +bin/opencv_perf_highgui: lib/libopencv_core.2.4.9.dylib +bin/opencv_perf_highgui: lib/libopencv_imgproc.2.4.9.dylib +bin/opencv_perf_highgui: lib/libopencv_highgui.2.4.9.dylib +bin/opencv_perf_highgui: lib/libopencv_ts.2.4.9.dylib +bin/opencv_perf_highgui: lib/libopencv_highgui.2.4.9.dylib +bin/opencv_perf_highgui: lib/libopencv_imgproc.2.4.9.dylib +bin/opencv_perf_highgui: lib/libopencv_core.2.4.9.dylib +bin/opencv_perf_highgui: 3rdparty/lib/libzlib.a +bin/opencv_perf_highgui: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX executable ../../bin/opencv_perf_highgui" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/opencv_perf_highgui.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build: bin/opencv_perf_highgui +.PHONY : modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o.requires +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o.requires +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o.requires +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o.requires +.PHONY : modules/highgui/CMakeFiles/opencv_perf_highgui.dir/requires + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && $(CMAKE_COMMAND) -P CMakeFiles/opencv_perf_highgui.dir/cmake_clean.cmake +.PHONY : modules/highgui/CMakeFiles/opencv_perf_highgui.dir/clean + +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_perf_highgui.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : modules/highgui/CMakeFiles/opencv_perf_highgui.dir/depend + diff --git a/highgui/CMakeFiles/opencv_perf_highgui.dir/cmake_clean.cmake b/highgui/CMakeFiles/opencv_perf_highgui.dir/cmake_clean.cmake new file mode 100644 index 0000000..d12ae83 --- /dev/null +++ b/highgui/CMakeFiles/opencv_perf_highgui.dir/cmake_clean.cmake @@ -0,0 +1,13 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o" + "CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o" + "CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o" + "CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o" + "../../bin/opencv_perf_highgui.pdb" + "../../bin/opencv_perf_highgui" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/opencv_perf_highgui.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/highgui/CMakeFiles/opencv_perf_highgui.dir/depend.make b/highgui/CMakeFiles/opencv_perf_highgui.dir/depend.make new file mode 100644 index 0000000..7a6cc90 --- /dev/null +++ b/highgui/CMakeFiles/opencv_perf_highgui.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for opencv_perf_highgui. +# This may be replaced when dependencies are built. diff --git a/highgui/CMakeFiles/opencv_perf_highgui.dir/flags.make b/highgui/CMakeFiles/opencv_perf_highgui.dir/flags.make new file mode 100644 index 0000000..024e0c6 --- /dev/null +++ b/highgui/CMakeFiles/opencv_perf_highgui.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -Wno-deprecated-declarations -O3 -DNDEBUG -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libjasper -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libtiff -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libpng -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libjpeg -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib -I/Users/beau/Documents/workspace/OpenCV/opencv -I/opt/local/include -I/opt/local/include/eigen3 -I/opt/local/include/OpenEXR + +CXX_DEFINES = -DHAVE_CVCONFIG_H -DHAVE_ALLOCA -DHAVE_ALLOCA_H -DHAVE_LIBPTHREAD -DHAVE_UNISTD_H -DHAVE_JPEG -DHAVE_PNG -DHAVE_TIFF -DHAVE_JASPER -DHAVE_OPENEXR -DHAVE_COCOA=1 -DHAVE_QUICKTIME=1 -DCVAPI_EXPORTS -DHIGHGUI_EXPORTS + diff --git a/highgui/CMakeFiles/opencv_perf_highgui.dir/link.txt b/highgui/CMakeFiles/opencv_perf_highgui.dir/link.txt new file mode 100644 index 0000000..d4e4adf --- /dev/null +++ b/highgui/CMakeFiles/opencv_perf_highgui.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -Wno-deprecated-declarations -O3 -DNDEBUG -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o -o ../../bin/opencv_perf_highgui -L/opt/local/lib -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib/gcc -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib ../../lib/libopencv_core.2.4.9.dylib ../../lib/libopencv_imgproc.2.4.9.dylib ../../lib/libopencv_highgui.2.4.9.dylib ../../lib/libopencv_ts.2.4.9.dylib ../../lib/libopencv_highgui.2.4.9.dylib ../../lib/libopencv_imgproc.2.4.9.dylib ../../lib/libopencv_core.2.4.9.dylib ../../3rdparty/lib/libzlib.a diff --git a/highgui/CMakeFiles/opencv_perf_highgui.dir/progress.make b/highgui/CMakeFiles/opencv_perf_highgui.dir/progress.make new file mode 100644 index 0000000..5873373 --- /dev/null +++ b/highgui/CMakeFiles/opencv_perf_highgui.dir/progress.make @@ -0,0 +1,5 @@ +CMAKE_PROGRESS_1 = +CMAKE_PROGRESS_2 = 67 +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = + diff --git a/highgui/CMakeFiles/opencv_test_highgui.dir/DependInfo.cmake b/highgui/CMakeFiles/opencv_test_highgui.dir/DependInfo.cmake new file mode 100644 index 0000000..9e62f49 --- /dev/null +++ b/highgui/CMakeFiles/opencv_test_highgui.dir/DependInfo.cmake @@ -0,0 +1,69 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_drawing.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_ffmpeg.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_framecount.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_grfmt.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_gui.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_main.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_positioning.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_precomp.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_video_io.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_video_pos.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "Clang") + +# Preprocessor definitions for this target. +SET(CMAKE_TARGET_DEFINITIONS + "HAVE_CVCONFIG_H" + "HAVE_ALLOCA" + "HAVE_ALLOCA_H" + "HAVE_LIBPTHREAD" + "HAVE_UNISTD_H" + "HAVE_JPEG" + "HAVE_PNG" + "HAVE_TIFF" + "HAVE_JASPER" + "HAVE_OPENEXR" + "HAVE_COCOA=1" + "HAVE_QUICKTIME=1" + "CVAPI_EXPORTS" + "HIGHGUI_EXPORTS" + ) + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/CMakeFiles/opencv_ts.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib/CMakeFiles/zlib.dir/DependInfo.cmake" + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "modules/highgui/perf" + "modules/highgui/include" + "modules/ts/include" + "modules/imgproc/include" + "modules/core/include" + "modules/highgui" + "modules/highgui/src" + "modules/highgui/test" + "3rdparty/libjasper" + "3rdparty/libtiff" + "3rdparty/libpng" + "3rdparty/libjpeg" + "3rdparty/zlib" + "." + "/opt/local/include" + "/opt/local/include/eigen3" + "/opt/local/include/OpenEXR" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/highgui/CMakeFiles/opencv_test_highgui.dir/build.make b/highgui/CMakeFiles/opencv_test_highgui.dir/build.make new file mode 100644 index 0000000..13e9685 --- /dev/null +++ b/highgui/CMakeFiles/opencv_test_highgui.dir/build.make @@ -0,0 +1,344 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# Include any dependencies generated for this target. +include modules/highgui/CMakeFiles/opencv_test_highgui.dir/depend.make + +# Include the progress variables for this target. +include modules/highgui/CMakeFiles/opencv_test_highgui.dir/progress.make + +# Include the compile flags for this target's objects. +include modules/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o: modules/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o: modules/highgui/test/test_drawing.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_drawing.cpp + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_drawing.cpp > CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.i + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_drawing.cpp -o CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.s + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o.provides: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o: modules/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o: modules/highgui/test/test_ffmpeg.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_2) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_ffmpeg.cpp + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_ffmpeg.cpp > CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.i + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_ffmpeg.cpp -o CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.s + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o.provides: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o: modules/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o: modules/highgui/test/test_framecount.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_3) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_framecount.cpp + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_framecount.cpp > CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.i + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_framecount.cpp -o CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.s + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o.provides: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o: modules/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o: modules/highgui/test/test_grfmt.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_4) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_grfmt.cpp + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_grfmt.cpp > CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.i + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_grfmt.cpp -o CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.s + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o.provides: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o: modules/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o: modules/highgui/test/test_gui.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_5) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_gui.cpp + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_gui.cpp > CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.i + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_gui.cpp -o CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.s + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o.provides: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o: modules/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o: modules/highgui/test/test_main.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_6) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_main.cpp + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_main.cpp > CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.i + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_main.cpp -o CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.s + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o.provides: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o: modules/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o: modules/highgui/test/test_positioning.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_7) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_positioning.cpp + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_positioning.cpp > CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.i + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_positioning.cpp -o CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.s + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o.provides: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o: modules/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o: modules/highgui/test/test_precomp.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_8) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_precomp.cpp + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_precomp.cpp > CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.i + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_precomp.cpp -o CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.s + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o.provides: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o: modules/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o: modules/highgui/test/test_video_io.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_9) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_video_io.cpp + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_video_io.cpp > CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.i + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_video_io.cpp -o CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.s + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o.provides: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o: modules/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o: modules/highgui/test/test_video_pos.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_10) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_video_pos.cpp + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_video_pos.cpp > CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.i + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test/test_video_pos.cpp -o CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.s + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o.requires: +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o.requires + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o.provides: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o.requires + $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o.provides.build +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o.provides + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o.provides.build: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o + +# Object files for target opencv_test_highgui +opencv_test_highgui_OBJECTS = \ +"CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o" \ +"CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o" \ +"CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o" \ +"CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o" \ +"CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o" \ +"CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o" \ +"CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o" \ +"CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o" \ +"CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o" \ +"CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o" + +# External object files for target opencv_test_highgui +opencv_test_highgui_EXTERNAL_OBJECTS = + +bin/opencv_test_highgui: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o +bin/opencv_test_highgui: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o +bin/opencv_test_highgui: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o +bin/opencv_test_highgui: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o +bin/opencv_test_highgui: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o +bin/opencv_test_highgui: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o +bin/opencv_test_highgui: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o +bin/opencv_test_highgui: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o +bin/opencv_test_highgui: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o +bin/opencv_test_highgui: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o +bin/opencv_test_highgui: modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make +bin/opencv_test_highgui: lib/libopencv_core.2.4.9.dylib +bin/opencv_test_highgui: lib/libopencv_imgproc.2.4.9.dylib +bin/opencv_test_highgui: lib/libopencv_highgui.2.4.9.dylib +bin/opencv_test_highgui: lib/libopencv_ts.2.4.9.dylib +bin/opencv_test_highgui: lib/libopencv_highgui.2.4.9.dylib +bin/opencv_test_highgui: lib/libopencv_imgproc.2.4.9.dylib +bin/opencv_test_highgui: lib/libopencv_core.2.4.9.dylib +bin/opencv_test_highgui: 3rdparty/lib/libzlib.a +bin/opencv_test_highgui: modules/highgui/CMakeFiles/opencv_test_highgui.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX executable ../../bin/opencv_test_highgui" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/opencv_test_highgui.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +modules/highgui/CMakeFiles/opencv_test_highgui.dir/build: bin/opencv_test_highgui +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/build + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o.requires +modules/highgui/CMakeFiles/opencv_test_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o.requires +modules/highgui/CMakeFiles/opencv_test_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o.requires +modules/highgui/CMakeFiles/opencv_test_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o.requires +modules/highgui/CMakeFiles/opencv_test_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o.requires +modules/highgui/CMakeFiles/opencv_test_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o.requires +modules/highgui/CMakeFiles/opencv_test_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o.requires +modules/highgui/CMakeFiles/opencv_test_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o.requires +modules/highgui/CMakeFiles/opencv_test_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o.requires +modules/highgui/CMakeFiles/opencv_test_highgui.dir/requires: modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o.requires +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/requires + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui && $(CMAKE_COMMAND) -P CMakeFiles/opencv_test_highgui.dir/cmake_clean.cmake +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/clean + +modules/highgui/CMakeFiles/opencv_test_highgui.dir/depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_test_highgui.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/depend + diff --git a/highgui/CMakeFiles/opencv_test_highgui.dir/cmake_clean.cmake b/highgui/CMakeFiles/opencv_test_highgui.dir/cmake_clean.cmake new file mode 100644 index 0000000..7e53084 --- /dev/null +++ b/highgui/CMakeFiles/opencv_test_highgui.dir/cmake_clean.cmake @@ -0,0 +1,19 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o" + "CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o" + "CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o" + "CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o" + "CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o" + "CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o" + "CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o" + "CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o" + "CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o" + "CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o" + "../../bin/opencv_test_highgui.pdb" + "../../bin/opencv_test_highgui" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/opencv_test_highgui.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/highgui/CMakeFiles/opencv_test_highgui.dir/depend.make b/highgui/CMakeFiles/opencv_test_highgui.dir/depend.make new file mode 100644 index 0000000..119e9fb --- /dev/null +++ b/highgui/CMakeFiles/opencv_test_highgui.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for opencv_test_highgui. +# This may be replaced when dependencies are built. diff --git a/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make b/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make new file mode 100644 index 0000000..024e0c6 --- /dev/null +++ b/highgui/CMakeFiles/opencv_test_highgui.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -Wno-deprecated-declarations -O3 -DNDEBUG -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/perf -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/src -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/test -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libjasper -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libtiff -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libpng -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/libjpeg -I/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib -I/Users/beau/Documents/workspace/OpenCV/opencv -I/opt/local/include -I/opt/local/include/eigen3 -I/opt/local/include/OpenEXR + +CXX_DEFINES = -DHAVE_CVCONFIG_H -DHAVE_ALLOCA -DHAVE_ALLOCA_H -DHAVE_LIBPTHREAD -DHAVE_UNISTD_H -DHAVE_JPEG -DHAVE_PNG -DHAVE_TIFF -DHAVE_JASPER -DHAVE_OPENEXR -DHAVE_COCOA=1 -DHAVE_QUICKTIME=1 -DCVAPI_EXPORTS -DHIGHGUI_EXPORTS + diff --git a/highgui/CMakeFiles/opencv_test_highgui.dir/link.txt b/highgui/CMakeFiles/opencv_test_highgui.dir/link.txt new file mode 100644 index 0000000..cf358da --- /dev/null +++ b/highgui/CMakeFiles/opencv_test_highgui.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -Wno-deprecated-declarations -O3 -DNDEBUG -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o -o ../../bin/opencv_test_highgui -L/opt/local/lib -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib/gcc -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib ../../lib/libopencv_core.2.4.9.dylib ../../lib/libopencv_imgproc.2.4.9.dylib ../../lib/libopencv_highgui.2.4.9.dylib ../../lib/libopencv_ts.2.4.9.dylib ../../lib/libopencv_highgui.2.4.9.dylib ../../lib/libopencv_imgproc.2.4.9.dylib ../../lib/libopencv_core.2.4.9.dylib ../../3rdparty/lib/libzlib.a diff --git a/highgui/CMakeFiles/opencv_test_highgui.dir/progress.make b/highgui/CMakeFiles/opencv_test_highgui.dir/progress.make new file mode 100644 index 0000000..1bc3b19 --- /dev/null +++ b/highgui/CMakeFiles/opencv_test_highgui.dir/progress.make @@ -0,0 +1,11 @@ +CMAKE_PROGRESS_1 = +CMAKE_PROGRESS_2 = +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = 84 +CMAKE_PROGRESS_5 = +CMAKE_PROGRESS_6 = +CMAKE_PROGRESS_7 = +CMAKE_PROGRESS_8 = +CMAKE_PROGRESS_9 = +CMAKE_PROGRESS_10 = + diff --git a/highgui/CMakeFiles/progress.marks b/highgui/CMakeFiles/progress.marks new file mode 100644 index 0000000..bb95160 --- /dev/null +++ b/highgui/CMakeFiles/progress.marks @@ -0,0 +1 @@ +33 diff --git a/highgui/CMakeLists.txt b/highgui/CMakeLists.txt new file mode 100644 index 0000000..d53c17c --- /dev/null +++ b/highgui/CMakeLists.txt @@ -0,0 +1,274 @@ +set(the_description "High-level GUI and Media I/O") +ocv_add_module(highgui opencv_imgproc OPTIONAL opencv_androidcamera) + +# ---------------------------------------------------------------------------- +# CMake file for highgui. See root CMakeLists.txt +# Some parts taken from version of Hartmut Seichter, HIT Lab NZ. +# Jose Luis Blanco, 2008 +# ---------------------------------------------------------------------------- + +ocv_clear_vars(GRFMT_LIBS) + +if(WITH_PNG OR WITH_TIFF OR WITH_OPENEXR) + ocv_include_directories(${ZLIB_INCLUDE_DIR}) + list(APPEND GRFMT_LIBS ${ZLIB_LIBRARIES}) +endif() + +if(WITH_JPEG) + add_definitions(-DHAVE_JPEG) + ocv_include_directories(${JPEG_INCLUDE_DIR}) + list(APPEND GRFMT_LIBS ${JPEG_LIBRARIES}) +endif() + +if(WITH_PNG) + add_definitions(-DHAVE_PNG) + add_definitions(${PNG_DEFINITIONS}) + ocv_include_directories(${PNG_INCLUDE_DIR}) + list(APPEND GRFMT_LIBS ${PNG_LIBRARIES}) +endif() + +if(WITH_TIFF) + add_definitions(-DHAVE_TIFF) + ocv_include_directories(${TIFF_INCLUDE_DIR}) + list(APPEND GRFMT_LIBS ${TIFF_LIBRARIES}) +endif() + +if(WITH_JASPER) + add_definitions(-DHAVE_JASPER) + ocv_include_directories(${JASPER_INCLUDE_DIR}) + list(APPEND GRFMT_LIBS ${JASPER_LIBRARIES}) +endif() + +if(WITH_OPENEXR AND OPENEXR_FOUND) + add_definitions(-DHAVE_OPENEXR) + ocv_include_directories(${OPENEXR_INCLUDE_PATHS}) + list(APPEND GRFMT_LIBS ${OPENEXR_LIBRARIES}) +endif() + +file(GLOB grfmt_hdrs src/grfmt*.hpp) +file(GLOB grfmt_srcs src/grfmt*.cpp) +list(APPEND grfmt_hdrs src/bitstrm.hpp) +list(APPEND grfmt_srcs src/bitstrm.cpp) + +source_group("Src\\grfmts" FILES ${grfmt_hdrs} ${grfmt_srcs}) + +set(highgui_hdrs + src/precomp.hpp + src/utils.hpp + src/cap_ffmpeg_impl.hpp + ) + +set(highgui_srcs + src/cap.cpp + src/cap_images.cpp + src/cap_ffmpeg.cpp + src/loadsave.cpp + src/precomp.cpp + src/utils.cpp + src/window.cpp + ) + +file(GLOB highgui_ext_hdrs "include/opencv2/${name}/*.hpp" "include/opencv2/${name}/*.h") + +if(HAVE_QT) + if (HAVE_QT_OPENGL) + set(QT_USE_QTOPENGL TRUE) + endif() + include(${QT_USE_FILE}) + + if(QT_INCLUDE_DIR) + ocv_include_directories(${QT_INCLUDE_DIR}) + endif() + + QT4_ADD_RESOURCES(_RCC_OUTFILES src/window_QT.qrc) + QT4_WRAP_CPP(_MOC_OUTFILES src/window_QT.h) + + list(APPEND HIGHGUI_LIBRARIES ${QT_LIBRARIES} ${QT_QTTEST_LIBRARY}) + list(APPEND highgui_srcs src/window_QT.cpp ${_MOC_OUTFILES} ${_RCC_OUTFILES}) + ocv_check_flag_support(CXX -Wno-missing-declarations _have_flag) + if(${_have_flag}) + set_source_files_properties(${_RCC_OUTFILES} PROPERTIES COMPILE_FLAGS -Wno-missing-declarations) + endif() +elseif(WIN32) + list(APPEND highgui_srcs src/window_w32.cpp) +elseif(HAVE_GTK) + list(APPEND highgui_srcs src/window_gtk.cpp) +elseif(APPLE) + if(WITH_CARBON) + add_definitions(-DHAVE_CARBON=1) + list(APPEND highgui_srcs src/window_carbon.cpp) + list(APPEND HIGHGUI_LIBRARIES "-framework Carbon" "-framework QuickTime") + elseif(NOT IOS) + add_definitions(-DHAVE_COCOA=1) + list(APPEND highgui_srcs src/window_cocoa.mm) + list(APPEND HIGHGUI_LIBRARIES "-framework Cocoa") + endif() +endif() + +if(WIN32) + list(APPEND highgui_srcs src/cap_vfw.cpp src/cap_cmu.cpp src/cap_dshow.cpp) +endif(WIN32) + +if(HAVE_XINE) + list(APPEND highgui_srcs src/cap_xine.cpp) +endif(HAVE_XINE) + +if(HAVE_DC1394_2) + list(APPEND highgui_srcs src/cap_dc1394_v2.cpp) +endif(HAVE_DC1394_2) + +if(HAVE_DC1394) + list(APPEND highgui_srcs src/cap_dc1394.cpp) +endif(HAVE_DC1394) + +if(HAVE_GSTREAMER) + list(APPEND highgui_srcs src/cap_gstreamer.cpp) +endif(HAVE_GSTREAMER) + +if(HAVE_UNICAP) + list(APPEND highgui_srcs src/cap_unicap.cpp) +endif(HAVE_UNICAP) + +if(HAVE_LIBV4L) + list(APPEND highgui_srcs src/cap_libv4l.cpp) +elseif(HAVE_CAMV4L OR HAVE_CAMV4L2) + list(APPEND highgui_srcs src/cap_v4l.cpp) +endif() + +if(HAVE_OPENNI) + list(APPEND highgui_srcs src/cap_openni.cpp) + ocv_include_directories(${OPENNI_INCLUDE_DIR}) + list(APPEND HIGHGUI_LIBRARIES ${OPENNI_LIBRARY}) +endif(HAVE_OPENNI) + +if(HAVE_opencv_androidcamera) + list(APPEND highgui_srcs src/cap_android.cpp) + add_definitions(-DHAVE_ANDROID_NATIVE_CAMERA)#TODO: remove this line +endif(HAVE_opencv_androidcamera) + +if(HAVE_XIMEA) + list(APPEND highgui_srcs src/cap_ximea.cpp) + ocv_include_directories(${XIMEA_PATH}) + if(XIMEA_LIBRARY_DIR) + link_directories(${XIMEA_LIBRARY_DIR}) + endif() + list(APPEND HIGHGUI_LIBRARIES m3api) +endif(HAVE_XIMEA) + +if(HAVE_FFMPEG) + if(UNIX AND BZIP2_LIBRARIES) + list(APPEND HIGHGUI_LIBRARIES ${BZIP2_LIBRARIES}) + endif() + if(APPLE) + list(APPEND HIGHGUI_LIBRARIES "-framework VideoDecodeAcceleration" bz2) + endif() +endif(HAVE_FFMPEG) + +if(HAVE_PVAPI) + add_definitions(-DHAVE_PVAPI) + ocv_include_directories(${PVAPI_INCLUDE_PATH}) + set(highgui_srcs src/cap_pvapi.cpp ${highgui_srcs}) + list(APPEND HIGHGUI_LIBRARIES ${PVAPI_LIBRARY}) +endif() + +if(WITH_IMAGEIO) + add_definitions(-DHAVE_IMAGEIO=1) + if(IOS) + list(APPEND HIGHGUI_LIBRARIES "-framework ImageIO") + endif() +endif(WITH_IMAGEIO) + +if(WITH_AVFOUNDATION) + add_definitions(-DHAVE_AVFOUNDATION=1) + list(APPEND highgui_srcs src/cap_avfoundation.mm) + list(APPEND HIGHGUI_LIBRARIES "-framework AVFoundation" "-framework QuartzCore") +elseif(APPLE) + add_definitions(-DHAVE_QUICKTIME=1) + if(WITH_QUICKTIME) + list(APPEND highgui_srcs src/cap_qt.cpp) + list(APPEND HIGHGUI_LIBRARIES "-framework Carbon" "-framework QuickTime" "-framework CoreFoundation" "-framework QuartzCore") + else() + list(APPEND highgui_srcs src/cap_qtkit.mm) + list(APPEND HIGHGUI_LIBRARIES "-framework QTKit" "-framework QuartzCore" "-framework AppKit") + endif() +endif() + +if(IOS) + add_definitions(-DHAVE_IOS=1) + list(APPEND highgui_srcs src/cap_ios_abstract_camera.mm src/cap_ios_photo_camera.mm src/cap_ios_video_camera.mm) + list(APPEND HIGHGUI_LIBRARIES "-framework Accelerate" "-framework AVFoundation" "-framework CoreGraphics" "-framework CoreImage" "-framework CoreMedia" "-framework CoreVideo" "-framework QuartzCore" "-framework AssetsLibrary") +endif() + +if(WIN32) + link_directories("${OpenCV_SOURCE_DIR}/3rdparty/lib") # for ffmpeg wrapper only + include_directories(AFTER SYSTEM "${OpenCV_SOURCE_DIR}/3rdparty/include") # for directshow in VS2005 and multi-monitor support on MinGW +endif() + +if(UNIX) + #these variables are set by CHECK_MODULE macro + foreach(P ${HIGHGUI_INCLUDE_DIRS}) + ocv_include_directories(${P}) + endforeach() + + foreach(P ${HIGHGUI_LIBRARY_DIRS}) + link_directories(${P}) + endforeach() +endif() + +source_group("Src" FILES ${highgui_srcs} ${highgui_hdrs}) +source_group("Include" FILES ${highgui_ext_hdrs}) +ocv_set_module_sources(HEADERS ${highgui_ext_hdrs} SOURCES ${highgui_srcs} ${highgui_hdrs} ${grfmt_srcs} ${grfmt_hdrs}) +ocv_module_include_directories() + +ocv_list_unique(HIGHGUI_LIBRARIES) +ocv_create_module(${GRFMT_LIBS} ${HIGHGUI_LIBRARIES}) + +if(BUILD_SHARED_LIBS) + add_definitions(-DHIGHGUI_EXPORTS) +endif() + +if(MSVC) + set_target_properties(${the_module} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:atlthunk.lib /NODEFAULTLIB:atlsd.lib /NODEFAULTLIB:libcmt.lib /DEBUG") +endif() + +#stop automatic dependencies propagation for this module +set_target_properties(${the_module} PROPERTIES LINK_INTERFACE_LIBRARIES "") + +ocv_add_precompiled_headers(${the_module}) +ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-deprecated-declarations) + +if(WIN32 AND WITH_FFMPEG) + #copy ffmpeg dll to the output folder + if(MSVC64 OR MINGW64) + set(FFMPEG_SUFFIX _64) + endif() + + set(ffmpeg_bare_name "opencv_ffmpeg${FFMPEG_SUFFIX}.dll") + set(ffmpeg_bare_name_ver "opencv_ffmpeg${OPENCV_DLLVERSION}${FFMPEG_SUFFIX}.dll") + set(ffmpeg_path "${OpenCV_SOURCE_DIR}/3rdparty/ffmpeg/${ffmpeg_bare_name}") + + #if(MSVC AND CMAKE_VERSION VERSION_GREATER "2.8.2") + # add_custom_command(TARGET ${the_module} POST_BUILD + # COMMAND ${CMAKE_COMMAND} -E copy "${ffmpeg_path}" "${EXECUTABLE_OUTPUT_PATH}/$/${ffmpeg_bare_name_ver}" + # COMMENT "Copying ${ffmpeg_path} to the output directory") + #else + if(MSVC_IDE) + add_custom_command(TARGET ${the_module} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy "${ffmpeg_path}" "${EXECUTABLE_OUTPUT_PATH}/Release/${ffmpeg_bare_name_ver}" + COMMAND ${CMAKE_COMMAND} -E copy "${ffmpeg_path}" "${EXECUTABLE_OUTPUT_PATH}/Debug/${ffmpeg_bare_name_ver}" + COMMENT "Copying ${ffmpeg_path} to the output directory") + elseif(MSVC) + add_custom_command(TARGET ${the_module} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy "${ffmpeg_path}" "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_BUILD_TYPE}/${ffmpeg_bare_name_ver}" + COMMENT "Copying ${ffmpeg_path} to the output directory") + else() + add_custom_command(TARGET ${the_module} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy "${ffmpeg_path}" "${EXECUTABLE_OUTPUT_PATH}/${ffmpeg_bare_name_ver}" + COMMENT "Copying ${ffmpeg_path} to the output directory") + endif() + + install(FILES "${ffmpeg_path}" DESTINATION bin COMPONENT main RENAME "${ffmpeg_bare_name_ver}") +endif() + +ocv_add_accuracy_tests() +ocv_add_perf_tests() diff --git a/highgui/Makefile b/highgui/Makefile new file mode 100644 index 0000000..bf82e30 --- /dev/null +++ b/highgui/Makefile @@ -0,0 +1,1130 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." + /opt/local/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /opt/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: install/local +.PHONY : install/local/fast + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /opt/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: install/strip +.PHONY : install/strip/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\" \"main\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /opt/local/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_progress_start /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/progress.marks + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/highgui/all + $(CMAKE_COMMAND) -E cmake_progress_start /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/highgui/clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/highgui/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/highgui/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Convenience name for target. +modules/highgui/CMakeFiles/opencv_highgui.dir/rule: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/highgui/CMakeFiles/opencv_highgui.dir/rule +.PHONY : modules/highgui/CMakeFiles/opencv_highgui.dir/rule + +# Convenience name for target. +opencv_highgui: modules/highgui/CMakeFiles/opencv_highgui.dir/rule +.PHONY : opencv_highgui + +# fast build rule for target. +opencv_highgui/fast: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/build +.PHONY : opencv_highgui/fast + +# Convenience name for target. +modules/highgui/CMakeFiles/opencv_perf_highgui.dir/rule: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/highgui/CMakeFiles/opencv_perf_highgui.dir/rule +.PHONY : modules/highgui/CMakeFiles/opencv_perf_highgui.dir/rule + +# Convenience name for target. +opencv_perf_highgui: modules/highgui/CMakeFiles/opencv_perf_highgui.dir/rule +.PHONY : opencv_perf_highgui + +# fast build rule for target. +opencv_perf_highgui/fast: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build +.PHONY : opencv_perf_highgui/fast + +# Convenience name for target. +modules/highgui/CMakeFiles/opencv_test_highgui.dir/rule: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/highgui/CMakeFiles/opencv_test_highgui.dir/rule +.PHONY : modules/highgui/CMakeFiles/opencv_test_highgui.dir/rule + +# Convenience name for target. +opencv_test_highgui: modules/highgui/CMakeFiles/opencv_test_highgui.dir/rule +.PHONY : opencv_test_highgui + +# fast build rule for target. +opencv_test_highgui/fast: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/build +.PHONY : opencv_test_highgui/fast + +perf/perf_input.o: perf/perf_input.cpp.o +.PHONY : perf/perf_input.o + +# target to build an object file +perf/perf_input.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.o +.PHONY : perf/perf_input.cpp.o + +perf/perf_input.i: perf/perf_input.cpp.i +.PHONY : perf/perf_input.i + +# target to preprocess a source file +perf/perf_input.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.i +.PHONY : perf/perf_input.cpp.i + +perf/perf_input.s: perf/perf_input.cpp.s +.PHONY : perf/perf_input.s + +# target to generate assembly for a file +perf/perf_input.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_input.cpp.s +.PHONY : perf/perf_input.cpp.s + +perf/perf_main.o: perf/perf_main.cpp.o +.PHONY : perf/perf_main.o + +# target to build an object file +perf/perf_main.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.o +.PHONY : perf/perf_main.cpp.o + +perf/perf_main.i: perf/perf_main.cpp.i +.PHONY : perf/perf_main.i + +# target to preprocess a source file +perf/perf_main.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.i +.PHONY : perf/perf_main.cpp.i + +perf/perf_main.s: perf/perf_main.cpp.s +.PHONY : perf/perf_main.s + +# target to generate assembly for a file +perf/perf_main.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_main.cpp.s +.PHONY : perf/perf_main.cpp.s + +perf/perf_output.o: perf/perf_output.cpp.o +.PHONY : perf/perf_output.o + +# target to build an object file +perf/perf_output.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.o +.PHONY : perf/perf_output.cpp.o + +perf/perf_output.i: perf/perf_output.cpp.i +.PHONY : perf/perf_output.i + +# target to preprocess a source file +perf/perf_output.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.i +.PHONY : perf/perf_output.cpp.i + +perf/perf_output.s: perf/perf_output.cpp.s +.PHONY : perf/perf_output.s + +# target to generate assembly for a file +perf/perf_output.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_output.cpp.s +.PHONY : perf/perf_output.cpp.s + +perf/perf_precomp.o: perf/perf_precomp.cpp.o +.PHONY : perf/perf_precomp.o + +# target to build an object file +perf/perf_precomp.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.o +.PHONY : perf/perf_precomp.cpp.o + +perf/perf_precomp.i: perf/perf_precomp.cpp.i +.PHONY : perf/perf_precomp.i + +# target to preprocess a source file +perf/perf_precomp.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.i +.PHONY : perf/perf_precomp.cpp.i + +perf/perf_precomp.s: perf/perf_precomp.cpp.s +.PHONY : perf/perf_precomp.s + +# target to generate assembly for a file +perf/perf_precomp.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_perf_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_perf_highgui.dir/perf/perf_precomp.cpp.s +.PHONY : perf/perf_precomp.cpp.s + +src/bitstrm.o: src/bitstrm.cpp.o +.PHONY : src/bitstrm.o + +# target to build an object file +src/bitstrm.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.o +.PHONY : src/bitstrm.cpp.o + +src/bitstrm.i: src/bitstrm.cpp.i +.PHONY : src/bitstrm.i + +# target to preprocess a source file +src/bitstrm.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.i +.PHONY : src/bitstrm.cpp.i + +src/bitstrm.s: src/bitstrm.cpp.s +.PHONY : src/bitstrm.s + +# target to generate assembly for a file +src/bitstrm.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/bitstrm.cpp.s +.PHONY : src/bitstrm.cpp.s + +src/cap.o: src/cap.cpp.o +.PHONY : src/cap.o + +# target to build an object file +src/cap.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.o +.PHONY : src/cap.cpp.o + +src/cap.i: src/cap.cpp.i +.PHONY : src/cap.i + +# target to preprocess a source file +src/cap.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.i +.PHONY : src/cap.cpp.i + +src/cap.s: src/cap.cpp.s +.PHONY : src/cap.s + +# target to generate assembly for a file +src/cap.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap.cpp.s +.PHONY : src/cap.cpp.s + +src/cap_ffmpeg.o: src/cap_ffmpeg.cpp.o +.PHONY : src/cap_ffmpeg.o + +# target to build an object file +src/cap_ffmpeg.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.o +.PHONY : src/cap_ffmpeg.cpp.o + +src/cap_ffmpeg.i: src/cap_ffmpeg.cpp.i +.PHONY : src/cap_ffmpeg.i + +# target to preprocess a source file +src/cap_ffmpeg.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.i +.PHONY : src/cap_ffmpeg.cpp.i + +src/cap_ffmpeg.s: src/cap_ffmpeg.cpp.s +.PHONY : src/cap_ffmpeg.s + +# target to generate assembly for a file +src/cap_ffmpeg.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_ffmpeg.cpp.s +.PHONY : src/cap_ffmpeg.cpp.s + +src/cap_images.o: src/cap_images.cpp.o +.PHONY : src/cap_images.o + +# target to build an object file +src/cap_images.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.o +.PHONY : src/cap_images.cpp.o + +src/cap_images.i: src/cap_images.cpp.i +.PHONY : src/cap_images.i + +# target to preprocess a source file +src/cap_images.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.i +.PHONY : src/cap_images.cpp.i + +src/cap_images.s: src/cap_images.cpp.s +.PHONY : src/cap_images.s + +# target to generate assembly for a file +src/cap_images.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_images.cpp.s +.PHONY : src/cap_images.cpp.s + +src/cap_qtkit.o: src/cap_qtkit.mm.o +.PHONY : src/cap_qtkit.o + +# target to build an object file +src/cap_qtkit.mm.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.o +.PHONY : src/cap_qtkit.mm.o + +src/cap_qtkit.i: src/cap_qtkit.mm.i +.PHONY : src/cap_qtkit.i + +# target to preprocess a source file +src/cap_qtkit.mm.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.i +.PHONY : src/cap_qtkit.mm.i + +src/cap_qtkit.s: src/cap_qtkit.mm.s +.PHONY : src/cap_qtkit.s + +# target to generate assembly for a file +src/cap_qtkit.mm.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/cap_qtkit.mm.s +.PHONY : src/cap_qtkit.mm.s + +src/grfmt_base.o: src/grfmt_base.cpp.o +.PHONY : src/grfmt_base.o + +# target to build an object file +src/grfmt_base.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.o +.PHONY : src/grfmt_base.cpp.o + +src/grfmt_base.i: src/grfmt_base.cpp.i +.PHONY : src/grfmt_base.i + +# target to preprocess a source file +src/grfmt_base.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.i +.PHONY : src/grfmt_base.cpp.i + +src/grfmt_base.s: src/grfmt_base.cpp.s +.PHONY : src/grfmt_base.s + +# target to generate assembly for a file +src/grfmt_base.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_base.cpp.s +.PHONY : src/grfmt_base.cpp.s + +src/grfmt_bmp.o: src/grfmt_bmp.cpp.o +.PHONY : src/grfmt_bmp.o + +# target to build an object file +src/grfmt_bmp.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.o +.PHONY : src/grfmt_bmp.cpp.o + +src/grfmt_bmp.i: src/grfmt_bmp.cpp.i +.PHONY : src/grfmt_bmp.i + +# target to preprocess a source file +src/grfmt_bmp.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.i +.PHONY : src/grfmt_bmp.cpp.i + +src/grfmt_bmp.s: src/grfmt_bmp.cpp.s +.PHONY : src/grfmt_bmp.s + +# target to generate assembly for a file +src/grfmt_bmp.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_bmp.cpp.s +.PHONY : src/grfmt_bmp.cpp.s + +src/grfmt_exr.o: src/grfmt_exr.cpp.o +.PHONY : src/grfmt_exr.o + +# target to build an object file +src/grfmt_exr.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.o +.PHONY : src/grfmt_exr.cpp.o + +src/grfmt_exr.i: src/grfmt_exr.cpp.i +.PHONY : src/grfmt_exr.i + +# target to preprocess a source file +src/grfmt_exr.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.i +.PHONY : src/grfmt_exr.cpp.i + +src/grfmt_exr.s: src/grfmt_exr.cpp.s +.PHONY : src/grfmt_exr.s + +# target to generate assembly for a file +src/grfmt_exr.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_exr.cpp.s +.PHONY : src/grfmt_exr.cpp.s + +src/grfmt_imageio.o: src/grfmt_imageio.cpp.o +.PHONY : src/grfmt_imageio.o + +# target to build an object file +src/grfmt_imageio.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.o +.PHONY : src/grfmt_imageio.cpp.o + +src/grfmt_imageio.i: src/grfmt_imageio.cpp.i +.PHONY : src/grfmt_imageio.i + +# target to preprocess a source file +src/grfmt_imageio.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.i +.PHONY : src/grfmt_imageio.cpp.i + +src/grfmt_imageio.s: src/grfmt_imageio.cpp.s +.PHONY : src/grfmt_imageio.s + +# target to generate assembly for a file +src/grfmt_imageio.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_imageio.cpp.s +.PHONY : src/grfmt_imageio.cpp.s + +src/grfmt_jpeg.o: src/grfmt_jpeg.cpp.o +.PHONY : src/grfmt_jpeg.o + +# target to build an object file +src/grfmt_jpeg.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.o +.PHONY : src/grfmt_jpeg.cpp.o + +src/grfmt_jpeg.i: src/grfmt_jpeg.cpp.i +.PHONY : src/grfmt_jpeg.i + +# target to preprocess a source file +src/grfmt_jpeg.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.i +.PHONY : src/grfmt_jpeg.cpp.i + +src/grfmt_jpeg.s: src/grfmt_jpeg.cpp.s +.PHONY : src/grfmt_jpeg.s + +# target to generate assembly for a file +src/grfmt_jpeg.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg.cpp.s +.PHONY : src/grfmt_jpeg.cpp.s + +src/grfmt_jpeg2000.o: src/grfmt_jpeg2000.cpp.o +.PHONY : src/grfmt_jpeg2000.o + +# target to build an object file +src/grfmt_jpeg2000.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.o +.PHONY : src/grfmt_jpeg2000.cpp.o + +src/grfmt_jpeg2000.i: src/grfmt_jpeg2000.cpp.i +.PHONY : src/grfmt_jpeg2000.i + +# target to preprocess a source file +src/grfmt_jpeg2000.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.i +.PHONY : src/grfmt_jpeg2000.cpp.i + +src/grfmt_jpeg2000.s: src/grfmt_jpeg2000.cpp.s +.PHONY : src/grfmt_jpeg2000.s + +# target to generate assembly for a file +src/grfmt_jpeg2000.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_jpeg2000.cpp.s +.PHONY : src/grfmt_jpeg2000.cpp.s + +src/grfmt_png.o: src/grfmt_png.cpp.o +.PHONY : src/grfmt_png.o + +# target to build an object file +src/grfmt_png.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.o +.PHONY : src/grfmt_png.cpp.o + +src/grfmt_png.i: src/grfmt_png.cpp.i +.PHONY : src/grfmt_png.i + +# target to preprocess a source file +src/grfmt_png.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.i +.PHONY : src/grfmt_png.cpp.i + +src/grfmt_png.s: src/grfmt_png.cpp.s +.PHONY : src/grfmt_png.s + +# target to generate assembly for a file +src/grfmt_png.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_png.cpp.s +.PHONY : src/grfmt_png.cpp.s + +src/grfmt_pxm.o: src/grfmt_pxm.cpp.o +.PHONY : src/grfmt_pxm.o + +# target to build an object file +src/grfmt_pxm.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.o +.PHONY : src/grfmt_pxm.cpp.o + +src/grfmt_pxm.i: src/grfmt_pxm.cpp.i +.PHONY : src/grfmt_pxm.i + +# target to preprocess a source file +src/grfmt_pxm.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.i +.PHONY : src/grfmt_pxm.cpp.i + +src/grfmt_pxm.s: src/grfmt_pxm.cpp.s +.PHONY : src/grfmt_pxm.s + +# target to generate assembly for a file +src/grfmt_pxm.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_pxm.cpp.s +.PHONY : src/grfmt_pxm.cpp.s + +src/grfmt_sunras.o: src/grfmt_sunras.cpp.o +.PHONY : src/grfmt_sunras.o + +# target to build an object file +src/grfmt_sunras.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.o +.PHONY : src/grfmt_sunras.cpp.o + +src/grfmt_sunras.i: src/grfmt_sunras.cpp.i +.PHONY : src/grfmt_sunras.i + +# target to preprocess a source file +src/grfmt_sunras.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.i +.PHONY : src/grfmt_sunras.cpp.i + +src/grfmt_sunras.s: src/grfmt_sunras.cpp.s +.PHONY : src/grfmt_sunras.s + +# target to generate assembly for a file +src/grfmt_sunras.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_sunras.cpp.s +.PHONY : src/grfmt_sunras.cpp.s + +src/grfmt_tiff.o: src/grfmt_tiff.cpp.o +.PHONY : src/grfmt_tiff.o + +# target to build an object file +src/grfmt_tiff.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.o +.PHONY : src/grfmt_tiff.cpp.o + +src/grfmt_tiff.i: src/grfmt_tiff.cpp.i +.PHONY : src/grfmt_tiff.i + +# target to preprocess a source file +src/grfmt_tiff.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.i +.PHONY : src/grfmt_tiff.cpp.i + +src/grfmt_tiff.s: src/grfmt_tiff.cpp.s +.PHONY : src/grfmt_tiff.s + +# target to generate assembly for a file +src/grfmt_tiff.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/grfmt_tiff.cpp.s +.PHONY : src/grfmt_tiff.cpp.s + +src/loadsave.o: src/loadsave.cpp.o +.PHONY : src/loadsave.o + +# target to build an object file +src/loadsave.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.o +.PHONY : src/loadsave.cpp.o + +src/loadsave.i: src/loadsave.cpp.i +.PHONY : src/loadsave.i + +# target to preprocess a source file +src/loadsave.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.i +.PHONY : src/loadsave.cpp.i + +src/loadsave.s: src/loadsave.cpp.s +.PHONY : src/loadsave.s + +# target to generate assembly for a file +src/loadsave.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/loadsave.cpp.s +.PHONY : src/loadsave.cpp.s + +src/precomp.o: src/precomp.cpp.o +.PHONY : src/precomp.o + +# target to build an object file +src/precomp.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.o +.PHONY : src/precomp.cpp.o + +src/precomp.i: src/precomp.cpp.i +.PHONY : src/precomp.i + +# target to preprocess a source file +src/precomp.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.i +.PHONY : src/precomp.cpp.i + +src/precomp.s: src/precomp.cpp.s +.PHONY : src/precomp.s + +# target to generate assembly for a file +src/precomp.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/precomp.cpp.s +.PHONY : src/precomp.cpp.s + +src/utils.o: src/utils.cpp.o +.PHONY : src/utils.o + +# target to build an object file +src/utils.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.o +.PHONY : src/utils.cpp.o + +src/utils.i: src/utils.cpp.i +.PHONY : src/utils.i + +# target to preprocess a source file +src/utils.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.i +.PHONY : src/utils.cpp.i + +src/utils.s: src/utils.cpp.s +.PHONY : src/utils.s + +# target to generate assembly for a file +src/utils.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/utils.cpp.s +.PHONY : src/utils.cpp.s + +src/window.o: src/window.cpp.o +.PHONY : src/window.o + +# target to build an object file +src/window.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.o +.PHONY : src/window.cpp.o + +src/window.i: src/window.cpp.i +.PHONY : src/window.i + +# target to preprocess a source file +src/window.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.i +.PHONY : src/window.cpp.i + +src/window.s: src/window.cpp.s +.PHONY : src/window.s + +# target to generate assembly for a file +src/window.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/window.cpp.s +.PHONY : src/window.cpp.s + +src/window_cocoa.o: src/window_cocoa.mm.o +.PHONY : src/window_cocoa.o + +# target to build an object file +src/window_cocoa.mm.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.o +.PHONY : src/window_cocoa.mm.o + +src/window_cocoa.i: src/window_cocoa.mm.i +.PHONY : src/window_cocoa.i + +# target to preprocess a source file +src/window_cocoa.mm.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.i +.PHONY : src/window_cocoa.mm.i + +src/window_cocoa.s: src/window_cocoa.mm.s +.PHONY : src/window_cocoa.s + +# target to generate assembly for a file +src/window_cocoa.mm.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_highgui.dir/src/window_cocoa.mm.s +.PHONY : src/window_cocoa.mm.s + +test/test_drawing.o: test/test_drawing.cpp.o +.PHONY : test/test_drawing.o + +# target to build an object file +test/test_drawing.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.o +.PHONY : test/test_drawing.cpp.o + +test/test_drawing.i: test/test_drawing.cpp.i +.PHONY : test/test_drawing.i + +# target to preprocess a source file +test/test_drawing.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.i +.PHONY : test/test_drawing.cpp.i + +test/test_drawing.s: test/test_drawing.cpp.s +.PHONY : test/test_drawing.s + +# target to generate assembly for a file +test/test_drawing.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_drawing.cpp.s +.PHONY : test/test_drawing.cpp.s + +test/test_ffmpeg.o: test/test_ffmpeg.cpp.o +.PHONY : test/test_ffmpeg.o + +# target to build an object file +test/test_ffmpeg.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.o +.PHONY : test/test_ffmpeg.cpp.o + +test/test_ffmpeg.i: test/test_ffmpeg.cpp.i +.PHONY : test/test_ffmpeg.i + +# target to preprocess a source file +test/test_ffmpeg.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.i +.PHONY : test/test_ffmpeg.cpp.i + +test/test_ffmpeg.s: test/test_ffmpeg.cpp.s +.PHONY : test/test_ffmpeg.s + +# target to generate assembly for a file +test/test_ffmpeg.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_ffmpeg.cpp.s +.PHONY : test/test_ffmpeg.cpp.s + +test/test_framecount.o: test/test_framecount.cpp.o +.PHONY : test/test_framecount.o + +# target to build an object file +test/test_framecount.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.o +.PHONY : test/test_framecount.cpp.o + +test/test_framecount.i: test/test_framecount.cpp.i +.PHONY : test/test_framecount.i + +# target to preprocess a source file +test/test_framecount.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.i +.PHONY : test/test_framecount.cpp.i + +test/test_framecount.s: test/test_framecount.cpp.s +.PHONY : test/test_framecount.s + +# target to generate assembly for a file +test/test_framecount.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_framecount.cpp.s +.PHONY : test/test_framecount.cpp.s + +test/test_grfmt.o: test/test_grfmt.cpp.o +.PHONY : test/test_grfmt.o + +# target to build an object file +test/test_grfmt.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.o +.PHONY : test/test_grfmt.cpp.o + +test/test_grfmt.i: test/test_grfmt.cpp.i +.PHONY : test/test_grfmt.i + +# target to preprocess a source file +test/test_grfmt.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.i +.PHONY : test/test_grfmt.cpp.i + +test/test_grfmt.s: test/test_grfmt.cpp.s +.PHONY : test/test_grfmt.s + +# target to generate assembly for a file +test/test_grfmt.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_grfmt.cpp.s +.PHONY : test/test_grfmt.cpp.s + +test/test_gui.o: test/test_gui.cpp.o +.PHONY : test/test_gui.o + +# target to build an object file +test/test_gui.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.o +.PHONY : test/test_gui.cpp.o + +test/test_gui.i: test/test_gui.cpp.i +.PHONY : test/test_gui.i + +# target to preprocess a source file +test/test_gui.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.i +.PHONY : test/test_gui.cpp.i + +test/test_gui.s: test/test_gui.cpp.s +.PHONY : test/test_gui.s + +# target to generate assembly for a file +test/test_gui.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_gui.cpp.s +.PHONY : test/test_gui.cpp.s + +test/test_main.o: test/test_main.cpp.o +.PHONY : test/test_main.o + +# target to build an object file +test/test_main.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.o +.PHONY : test/test_main.cpp.o + +test/test_main.i: test/test_main.cpp.i +.PHONY : test/test_main.i + +# target to preprocess a source file +test/test_main.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.i +.PHONY : test/test_main.cpp.i + +test/test_main.s: test/test_main.cpp.s +.PHONY : test/test_main.s + +# target to generate assembly for a file +test/test_main.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_main.cpp.s +.PHONY : test/test_main.cpp.s + +test/test_positioning.o: test/test_positioning.cpp.o +.PHONY : test/test_positioning.o + +# target to build an object file +test/test_positioning.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.o +.PHONY : test/test_positioning.cpp.o + +test/test_positioning.i: test/test_positioning.cpp.i +.PHONY : test/test_positioning.i + +# target to preprocess a source file +test/test_positioning.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.i +.PHONY : test/test_positioning.cpp.i + +test/test_positioning.s: test/test_positioning.cpp.s +.PHONY : test/test_positioning.s + +# target to generate assembly for a file +test/test_positioning.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_positioning.cpp.s +.PHONY : test/test_positioning.cpp.s + +test/test_precomp.o: test/test_precomp.cpp.o +.PHONY : test/test_precomp.o + +# target to build an object file +test/test_precomp.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.o +.PHONY : test/test_precomp.cpp.o + +test/test_precomp.i: test/test_precomp.cpp.i +.PHONY : test/test_precomp.i + +# target to preprocess a source file +test/test_precomp.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.i +.PHONY : test/test_precomp.cpp.i + +test/test_precomp.s: test/test_precomp.cpp.s +.PHONY : test/test_precomp.s + +# target to generate assembly for a file +test/test_precomp.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_precomp.cpp.s +.PHONY : test/test_precomp.cpp.s + +test/test_video_io.o: test/test_video_io.cpp.o +.PHONY : test/test_video_io.o + +# target to build an object file +test/test_video_io.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.o +.PHONY : test/test_video_io.cpp.o + +test/test_video_io.i: test/test_video_io.cpp.i +.PHONY : test/test_video_io.i + +# target to preprocess a source file +test/test_video_io.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.i +.PHONY : test/test_video_io.cpp.i + +test/test_video_io.s: test/test_video_io.cpp.s +.PHONY : test/test_video_io.s + +# target to generate assembly for a file +test/test_video_io.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_io.cpp.s +.PHONY : test/test_video_io.cpp.s + +test/test_video_pos.o: test/test_video_pos.cpp.o +.PHONY : test/test_video_pos.o + +# target to build an object file +test/test_video_pos.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.o +.PHONY : test/test_video_pos.cpp.o + +test/test_video_pos.i: test/test_video_pos.cpp.i +.PHONY : test/test_video_pos.i + +# target to preprocess a source file +test/test_video_pos.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.i +.PHONY : test/test_video_pos.cpp.i + +test/test_video_pos.s: test/test_video_pos.cpp.s +.PHONY : test/test_video_pos.s + +# target to generate assembly for a file +test/test_video_pos.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/highgui/CMakeFiles/opencv_test_highgui.dir/build.make modules/highgui/CMakeFiles/opencv_test_highgui.dir/test/test_video_pos.cpp.s +.PHONY : test/test_video_pos.cpp.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... opencv_highgui" + @echo "... opencv_perf_highgui" + @echo "... opencv_test_highgui" + @echo "... rebuild_cache" + @echo "... perf/perf_input.o" + @echo "... perf/perf_input.i" + @echo "... perf/perf_input.s" + @echo "... perf/perf_main.o" + @echo "... perf/perf_main.i" + @echo "... perf/perf_main.s" + @echo "... perf/perf_output.o" + @echo "... perf/perf_output.i" + @echo "... perf/perf_output.s" + @echo "... perf/perf_precomp.o" + @echo "... perf/perf_precomp.i" + @echo "... perf/perf_precomp.s" + @echo "... src/bitstrm.o" + @echo "... src/bitstrm.i" + @echo "... src/bitstrm.s" + @echo "... src/cap.o" + @echo "... src/cap.i" + @echo "... src/cap.s" + @echo "... src/cap_ffmpeg.o" + @echo "... src/cap_ffmpeg.i" + @echo "... src/cap_ffmpeg.s" + @echo "... src/cap_images.o" + @echo "... src/cap_images.i" + @echo "... src/cap_images.s" + @echo "... src/cap_qtkit.o" + @echo "... src/cap_qtkit.i" + @echo "... src/cap_qtkit.s" + @echo "... src/grfmt_base.o" + @echo "... src/grfmt_base.i" + @echo "... src/grfmt_base.s" + @echo "... src/grfmt_bmp.o" + @echo "... src/grfmt_bmp.i" + @echo "... src/grfmt_bmp.s" + @echo "... src/grfmt_exr.o" + @echo "... src/grfmt_exr.i" + @echo "... src/grfmt_exr.s" + @echo "... src/grfmt_imageio.o" + @echo "... src/grfmt_imageio.i" + @echo "... src/grfmt_imageio.s" + @echo "... src/grfmt_jpeg.o" + @echo "... src/grfmt_jpeg.i" + @echo "... src/grfmt_jpeg.s" + @echo "... src/grfmt_jpeg2000.o" + @echo "... src/grfmt_jpeg2000.i" + @echo "... src/grfmt_jpeg2000.s" + @echo "... src/grfmt_png.o" + @echo "... src/grfmt_png.i" + @echo "... src/grfmt_png.s" + @echo "... src/grfmt_pxm.o" + @echo "... src/grfmt_pxm.i" + @echo "... src/grfmt_pxm.s" + @echo "... src/grfmt_sunras.o" + @echo "... src/grfmt_sunras.i" + @echo "... src/grfmt_sunras.s" + @echo "... src/grfmt_tiff.o" + @echo "... src/grfmt_tiff.i" + @echo "... src/grfmt_tiff.s" + @echo "... src/loadsave.o" + @echo "... src/loadsave.i" + @echo "... src/loadsave.s" + @echo "... src/precomp.o" + @echo "... src/precomp.i" + @echo "... src/precomp.s" + @echo "... src/utils.o" + @echo "... src/utils.i" + @echo "... src/utils.s" + @echo "... src/window.o" + @echo "... src/window.i" + @echo "... src/window.s" + @echo "... src/window_cocoa.o" + @echo "... src/window_cocoa.i" + @echo "... src/window_cocoa.s" + @echo "... test/test_drawing.o" + @echo "... test/test_drawing.i" + @echo "... test/test_drawing.s" + @echo "... test/test_ffmpeg.o" + @echo "... test/test_ffmpeg.i" + @echo "... test/test_ffmpeg.s" + @echo "... test/test_framecount.o" + @echo "... test/test_framecount.i" + @echo "... test/test_framecount.s" + @echo "... test/test_grfmt.o" + @echo "... test/test_grfmt.i" + @echo "... test/test_grfmt.s" + @echo "... test/test_gui.o" + @echo "... test/test_gui.i" + @echo "... test/test_gui.s" + @echo "... test/test_main.o" + @echo "... test/test_main.i" + @echo "... test/test_main.s" + @echo "... test/test_positioning.o" + @echo "... test/test_positioning.i" + @echo "... test/test_positioning.s" + @echo "... test/test_precomp.o" + @echo "... test/test_precomp.i" + @echo "... test/test_precomp.s" + @echo "... test/test_video_io.o" + @echo "... test/test_video_io.i" + @echo "... test/test_video_io.s" + @echo "... test/test_video_pos.o" + @echo "... test/test_video_pos.i" + @echo "... test/test_video_pos.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/highgui/cmake_install.cmake b/highgui/cmake_install.cmake new file mode 100644 index 0000000..e88a655 --- /dev/null +++ b/highgui/cmake_install.cmake @@ -0,0 +1,66 @@ +# Install script for directory: /Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui + +# Set the install prefix +IF(NOT DEFINED CMAKE_INSTALL_PREFIX) + SET(CMAKE_INSTALL_PREFIX "/usr/local") +ENDIF(NOT DEFINED CMAKE_INSTALL_PREFIX) +STRING(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +IF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + IF(BUILD_TYPE) + STRING(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + ELSE(BUILD_TYPE) + SET(CMAKE_INSTALL_CONFIG_NAME "Release") + ENDIF(BUILD_TYPE) + MESSAGE(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +ENDIF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + +# Set the component getting installed. +IF(NOT CMAKE_INSTALL_COMPONENT) + IF(COMPONENT) + MESSAGE(STATUS "Install component: \"${COMPONENT}\"") + SET(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + ELSE(COMPONENT) + SET(CMAKE_INSTALL_COMPONENT) + ENDIF(COMPONENT) +ENDIF(NOT CMAKE_INSTALL_COMPONENT) + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE SHARED_LIBRARY FILES + "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_highgui.2.4.9.dylib" + "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_highgui.2.4.dylib" + "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_highgui.dylib" + ) + FOREACH(file + "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libopencv_highgui.2.4.9.dylib" + "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libopencv_highgui.2.4.dylib" + "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libopencv_highgui.dylib" + ) + IF(EXISTS "${file}" AND + NOT IS_SYMLINK "${file}") + EXECUTE_PROCESS(COMMAND "/usr/bin/install_name_tool" + -id "lib/libopencv_highgui.2.4.dylib" + -change "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_core.2.4.dylib" "lib/libopencv_core.2.4.dylib" + -change "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_imgproc.2.4.dylib" "lib/libopencv_imgproc.2.4.dylib" + "${file}") + IF(CMAKE_INSTALL_DO_STRIP) + EXECUTE_PROCESS(COMMAND "/usr/bin/strip" "${file}") + ENDIF(CMAKE_INSTALL_DO_STRIP) + ENDIF() + ENDFOREACH() +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/include/opencv2/highgui" TYPE FILE FILES "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/include/opencv2/highgui/highgui.hpp") +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/include/opencv2/highgui" TYPE FILE FILES "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/include/opencv2/highgui/cap_ios.h") +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/include/opencv2/highgui" TYPE FILE FILES "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/include/opencv2/highgui/highgui_c.h") +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + diff --git a/highgui/doc/highgui.rst b/highgui/doc/highgui.rst new file mode 100644 index 0000000..02beddb --- /dev/null +++ b/highgui/doc/highgui.rst @@ -0,0 +1,20 @@ +************************************* +highgui. High-level GUI and Media I/O +************************************* + +While OpenCV was designed for use in full-scale +applications and can be used within functionally rich UI frameworks (such as Qt*, WinForms*, or Cocoa*) or without any UI at all, sometimes there it is required to try functionality quickly and visualize the results. This is what the HighGUI module has been designed for. + +It provides easy interface to: + +* Create and manipulate windows that can display images and "remember" their content (no need to handle repaint events from OS). +* Add trackbars to the windows, handle simple mouse events as well as keyboard commands. +* Read and write images to/from disk or memory. +* Read video from camera or file and write video to a file. + +.. toctree:: + :maxdepth: 2 + + user_interface + reading_and_writing_images_and_video + qt_new_functions diff --git a/highgui/doc/pics/qtgui.png b/highgui/doc/pics/qtgui.png new file mode 100644 index 0000000..6815d56 Binary files /dev/null and b/highgui/doc/pics/qtgui.png differ diff --git a/highgui/doc/qt_new_functions.rst b/highgui/doc/qt_new_functions.rst new file mode 100644 index 0000000..bd889db --- /dev/null +++ b/highgui/doc/qt_new_functions.rst @@ -0,0 +1,338 @@ +Qt New Functions +================ +.. highlight:: cpp + +.. image:: pics/qtgui.png + +This figure explains new functionality implemented with Qt* GUI. The new GUI provides a statusbar, a toolbar, and a control panel. The control panel can have trackbars and buttonbars attached to it. If you cannot see the control panel, press Ctrl+P or right-click any Qt window and select **Display properties window**. + +* + To attach a trackbar, the window name parameter must be NULL. + +* + To attach a buttonbar, a button must be created. + If the last bar attached to the control panel is a buttonbar, the new button is added to the right of the last button. + If the last bar attached to the control panel is a trackbar, or the control panel is empty, a new buttonbar is created. Then, a new button is attached to it. + +See below the example used to generate the figure: :: + + int main(int argc, char *argv[]) + int value = 50; + int value2 = 0; + + cvNamedWindow("main1",CV_WINDOW_NORMAL); + cvNamedWindow("main2",CV_WINDOW_AUTOSIZE | CV_GUI_NORMAL); + + cvCreateTrackbar( "track1", "main1", &value, 255, NULL);//OK tested + char* nameb1 = "button1"; + char* nameb2 = "button2"; + cvCreateButton(nameb1,callbackButton,nameb1,CV_CHECKBOX,1); + + cvCreateButton(nameb2,callbackButton,nameb2,CV_CHECKBOX,0); + cvCreateTrackbar( "track2", NULL, &value2, 255, NULL); + cvCreateButton("button5",callbackButton1,NULL,CV_RADIOBOX,0); + cvCreateButton("button6",callbackButton2,NULL,CV_RADIOBOX,1); + + cvSetMouseCallback( "main2",on_mouse,NULL ); + + IplImage* img1 = cvLoadImage("files/flower.jpg"); + IplImage* img2 = cvCreateImage(cvGetSize(img1),8,3); + CvCapture* video = cvCaptureFromFile("files/hockey.avi"); + IplImage* img3 = cvCreateImage(cvGetSize(cvQueryFrame(video)),8,3); + + while(cvWaitKey(33) != 27) + { + cvAddS(img1,cvScalarAll(value),img2); + cvAddS(cvQueryFrame(video),cvScalarAll(value2),img3); + cvShowImage("main1",img2); + cvShowImage("main2",img3); + } + + cvDestroyAllWindows(); + cvReleaseImage(&img1); + cvReleaseImage(&img2); + cvReleaseImage(&img3); + cvReleaseCapture(&video); + return 0; + } + + +setWindowProperty +--------------------- +Changes parameters of a window dynamically. + +.. ocv:function:: void setWindowProperty( const string& winname, int prop_id, double prop_value ) + +.. ocv:pyfunction:: cv2.setWindowProperty(winname, prop_id, prop_value) -> None + +.. ocv:cfunction:: void cvSetWindowProperty( const char* name, int prop_id, double prop_value ) + + :param name: Name of the window. + + :param prop_id: Window property to edit. The following operation flags are available: + + * **CV_WND_PROP_FULLSCREEN** Change if the window is fullscreen ( ``CV_WINDOW_NORMAL`` or ``CV_WINDOW_FULLSCREEN`` ). + + * **CV_WND_PROP_AUTOSIZE** Change if the window is resizable (``CV_WINDOW_NORMAL`` or ``CV_WINDOW_AUTOSIZE`` ). + + * **CV_WND_PROP_ASPECTRATIO** Change if the aspect ratio of the image is preserved ( ``CV_WINDOW_FREERATIO`` or ``CV_WINDOW_KEEPRATIO`` ). + + + :param prop_value: New value of the window property. The following operation flags are available: + + * **CV_WINDOW_NORMAL** Change the window to normal size or make the window resizable. + + * **CV_WINDOW_AUTOSIZE** Constrain the size by the displayed image. The window is not resizable. + + * **CV_WINDOW_FULLSCREEN** Change the window to fullscreen. + + * **CV_WINDOW_FREERATIO** Make the window resizable without any ratio constraints. + + * **CV_WINDOW_KEEPRATIO** Make the window resizable, but preserve the proportions of the displayed image. + + +The function ``setWindowProperty`` enables changing properties of a window. + +getWindowProperty +--------------------- +Provides parameters of a window. + +.. ocv:function:: double getWindowProperty( const string& winname, int prop_id ) + +.. ocv:pyfunction:: cv2.getWindowProperty(winname, prop_id) -> retval + +.. ocv:cfunction:: double cvGetWindowProperty( const char* name, int prop_id ) + + :param name: Name of the window. + + :param prop_id: Window property to retrieve. The following operation flags are available: + + * **CV_WND_PROP_FULLSCREEN** Change if the window is fullscreen ( ``CV_WINDOW_NORMAL`` or ``CV_WINDOW_FULLSCREEN`` ). + + * **CV_WND_PROP_AUTOSIZE** Change if the window is resizable (``CV_WINDOW_NORMAL`` or ``CV_WINDOW_AUTOSIZE`` ). + + * **CV_WND_PROP_ASPECTRATIO** Change if the aspect ratio of the image is preserved (``CV_WINDOW_FREERATIO`` or ``CV_WINDOW_KEEPRATIO`` ). + + +See +:ocv:func:`setWindowProperty` to know the meaning of the returned values. + +The function ``getWindowProperty`` returns properties of a window. + +fontQt +---------- +Creates the font to draw a text on an image. + +.. ocv:function:: CvFont fontQt(const string& nameFont, int pointSize = -1, Scalar color = Scalar::all(0), int weight = CV_FONT_NORMAL, int style = CV_STYLE_NORMAL, int spacing = 0) + +.. ocv:cfunction:: CvFont cvFontQt(const char* nameFont, int pointSize=-1, CvScalar color=cvScalarAll(0), int weight=CV_FONT_NORMAL, int style=CV_STYLE_NORMAL, int spacing=0) + + :param nameFont: Name of the font. The name should match the name of a system font (such as *Times*). If the font is not found, a default one is used. + + :param pointSize: Size of the font. If not specified, equal zero or negative, the point size of the font is set to a system-dependent default value. Generally, this is 12 points. + + :param color: Color of the font in BGRA where A = 255 is fully transparent. Use the macro ``CV _ RGB`` for simplicity. + + :param weight: Font weight. The following operation flags are available: + + * **CV_FONT_LIGHT** Weight of 25 + + * **CV_FONT_NORMAL** Weight of 50 + + * **CV_FONT_DEMIBOLD** Weight of 63 + + * **CV_FONT_BOLD** Weight of 75 + + * **CV_FONT_BLACK** Weight of 87 + + You can also specify a positive integer for better control. + + :param style: Font style. The following operation flags are available: + + * **CV_STYLE_NORMAL** Normal font + + * **CV_STYLE_ITALIC** Italic font + + * **CV_STYLE_OBLIQUE** Oblique font + + :param spacing: Spacing between characters. It can be negative or positive. + +The function ``fontQt`` creates a ``CvFont`` object. This ``CvFont`` is not compatible with ``putText`` . + +A basic usage of this function is the following: :: + + CvFont font = fontQt(''Times''); + addText( img1, ``Hello World !'', Point(50,50), font); + + +addText +----------- +Creates the font to draw a text on an image. + +.. ocv:function:: void addText( const Mat& img, const string& text, Point org, CvFont font ) + +.. ocv:cfunction:: void cvAddText( const CvArr* img, const char* text, CvPoint org, CvFont * arg2 ) + + :param img: 8-bit 3-channel image where the text should be drawn. + + :param text: Text to write on an image. + + :param org: Point(x,y) where the text should start on an image. + + :param font: Font to use to draw a text. + +The function ``addText`` draws +*text* +on an image +*img* +using a specific font +*font* +(see example :ocv:func:`fontQt` ) + +.. index:: displayOverlay + +displayOverlay +------------------ +Displays a text on a window image as an overlay for a specified duration. + +.. ocv:function:: void displayOverlay( const string& winname, const string& text, int delayms=0 ) + +.. ocv:cfunction:: void cvDisplayOverlay(const char* name, const char* text, int delayms = 0) + + :param name: Name of the window. + + :param text: Overlay text to write on a window image. + + :param delayms: The period (in milliseconds), during which the overlay text is displayed. If this function is called before the previous overlay text timed out, the timer is restarted and the text is updated. If this value is zero, the text never disappears. + +The function ``displayOverlay`` displays useful information/tips on top of the window for a certain amount of time *delayms*. The function does not modify the image, displayed in the window, that is, after the specified delay the original content of the window is restored. + + +displayStatusBar +-------------------- +Displays a text on the window statusbar during the specified period of time. + +.. ocv:function:: void displayStatusBar( const string& winname, const string& text, int delayms=0 ) + +.. ocv:cfunction:: void cvDisplayStatusBar(const char* name, const char* text, int delayms = 0) + + :param name: Name of the window. + + :param text: Text to write on the window statusbar. + + :param delayms: Duration (in milliseconds) to display the text. If this function is called before the previous text timed out, the timer is restarted and the text is updated. If this value is zero, the text never disappears. + +The function ``displayOverlay`` displays useful information/tips on top of the window for a certain amount of time +*delayms* +. This information is displayed on the window statusbar (the window must be created with the ``CV_GUI_EXPANDED`` flags). + +setOpenGlDrawCallback +------------------------ +Sets a callback function to be called to draw on top of displayed image. + +.. ocv:function:: void setOpenGlDrawCallback( const string& winname, OpenGlDrawCallback onOpenGlDraw, void* userdata=0 ) + +.. ocv:cfunction:: void cvSetOpenGlDrawCallback( const char* window_name, CvOpenGlDrawCallback callback, void* userdata=NULL ) + + :param window_name: Name of the window. + + :param onOpenGlDraw: Pointer to the function to be called every frame. This function should be prototyped as ``void Foo(void*)`` . + + :param userdata: Pointer passed to the callback function. *(Optional)* + +The function ``setOpenGlDrawCallback`` can be used to draw 3D data on the window. See the example of callback function below: :: + + void on_opengl(void* param) + { + glLoadIdentity(); + + glTranslated(0.0, 0.0, -1.0); + + glRotatef( 55, 1, 0, 0 ); + glRotatef( 45, 0, 1, 0 ); + glRotatef( 0, 0, 0, 1 ); + + static const int coords[6][4][3] = { + { { +1, -1, -1 }, { -1, -1, -1 }, { -1, +1, -1 }, { +1, +1, -1 } }, + { { +1, +1, -1 }, { -1, +1, -1 }, { -1, +1, +1 }, { +1, +1, +1 } }, + { { +1, -1, +1 }, { +1, -1, -1 }, { +1, +1, -1 }, { +1, +1, +1 } }, + { { -1, -1, -1 }, { -1, -1, +1 }, { -1, +1, +1 }, { -1, +1, -1 } }, + { { +1, -1, +1 }, { -1, -1, +1 }, { -1, -1, -1 }, { +1, -1, -1 } }, + { { -1, -1, +1 }, { +1, -1, +1 }, { +1, +1, +1 }, { -1, +1, +1 } } + }; + + for (int i = 0; i < 6; ++i) { + glColor3ub( i*20, 100+i*10, i*42 ); + glBegin(GL_QUADS); + for (int j = 0; j < 4; ++j) { + glVertex3d(0.2 * coords[i][j][0], 0.2 * coords[i][j][1], 0.2 * coords[i][j][2]); + } + glEnd(); + } + } + + +saveWindowParameters +------------------------ +Saves parameters of the specified window. + +.. ocv:function:: void saveWindowParameters( const string& windowName ) + +.. ocv:cfunction:: void cvSaveWindowParameters(const char* name) + + :param name: Name of the window. + +The function ``saveWindowParameters`` saves size, location, flags, trackbars value, zoom and panning location of the window +``window_name`` . + +loadWindowParameters +------------------------ +Loads parameters of the specified window. + +.. ocv:function:: void loadWindowParameters( const string& windowName ) + +.. ocv:cfunction:: void cvLoadWindowParameters(const char* name) + + :param name: Name of the window. + +The function ``loadWindowParameters`` loads size, location, flags, trackbars value, zoom and panning location of the window +``window_name`` . + +createButton +---------------- +Attaches a button to the control panel. + +.. ocv:function:: int createButton( const string& bar_name, ButtonCallback on_change, void* userdata=NULL, int type=CV_PUSH_BUTTON, bool initial_button_state=0 ) + +.. ocv:cfunction:: int cvCreateButton( const char* button_name=NULL, CvButtonCallback on_change=NULL, void* userdata=NULL, int button_type=CV_PUSH_BUTTON, int initial_button_state=0 ) + + :param button_name: Name of the button. + + :param on_change: Pointer to the function to be called every time the button changes its state. This function should be prototyped as ``void Foo(int state,*void);`` . *state* is the current state of the button. It could be -1 for a push button, 0 or 1 for a check/radio box button. + + :param userdata: Pointer passed to the callback function. + + :param button_type: Optional type of the button. + + * **CV_PUSH_BUTTON** Push button + + * **CV_CHECKBOX** Checkbox button + + * **CV_RADIOBOX** Radiobox button. The radiobox on the same buttonbar (same line) are exclusive, that is only one can be selected at a time. + + :param initial_button_state: Default state of the button. Use for checkbox and radiobox. Its value could be 0 or 1. *(Optional)* + +The function ``createButton`` attaches a button to the control panel. Each button is added to a buttonbar to the right of the last button. +A new buttonbar is created if nothing was attached to the control panel before, or if the last element attached to the control panel was a trackbar. + +See below various examples of the ``createButton`` function call: :: + + createButton(NULL,callbackButton);//create a push button "button 0", that will call callbackButton. + createButton("button2",callbackButton,NULL,CV_CHECKBOX,0); + createButton("button3",callbackButton,&value); + createButton("button5",callbackButton1,NULL,CV_RADIOBOX); + createButton("button6",callbackButton2,NULL,CV_PUSH_BUTTON,1); + +.. + + diff --git a/highgui/doc/reading_and_writing_images_and_video.rst b/highgui/doc/reading_and_writing_images_and_video.rst new file mode 100644 index 0000000..f694ccd --- /dev/null +++ b/highgui/doc/reading_and_writing_images_and_video.rst @@ -0,0 +1,534 @@ +Reading and Writing Images and Video +==================================== + +.. highlight:: cpp + +imdecode +------------ +Reads an image from a buffer in memory. + +.. ocv:function:: Mat imdecode( InputArray buf, int flags ) + +.. ocv:cfunction:: IplImage* cvDecodeImage( const CvMat* buf, int iscolor=CV_LOAD_IMAGE_COLOR) + +.. ocv:cfunction:: CvMat* cvDecodeImageM( const CvMat* buf, int iscolor=CV_LOAD_IMAGE_COLOR) + +.. ocv:pyfunction:: cv2.imdecode(buf, flags) -> retval + + :param buf: Input array or vector of bytes. + + :param flags: The same flags as in :ocv:func:`imread` . + +The function reads an image from the specified buffer in the memory. +If the buffer is too short or contains invalid data, the empty matrix/image is returned. + +See +:ocv:func:`imread` for the list of supported formats and flags description. + +imencode +------------ +Encodes an image into a memory buffer. + +.. ocv:function:: bool imencode( const string& ext, InputArray img, vector& buf, const vector& params=vector()) + +.. ocv:cfunction:: CvMat* cvEncodeImage( const char* ext, const CvArr* image, const int* params=0 ) + +.. ocv:pyfunction:: cv2.imencode(ext, img[, params]) -> retval, buf + + :param ext: File extension that defines the output format. + + :param img: Image to be written. + + :param buf: Output buffer resized to fit the compressed image. + + :param params: Format-specific parameters. See :ocv:func:`imwrite` . + +The function compresses the image and stores it in the memory buffer that is resized to fit the result. +See +:ocv:func:`imwrite` for the list of supported formats and flags description. + +.. note:: ``cvEncodeImage`` returns single-row matrix of type ``CV_8UC1`` that contains encoded image as array of bytes. + +imread +---------- +Loads an image from a file. + +.. ocv:function:: Mat imread( const string& filename, int flags=1 ) + +.. ocv:pyfunction:: cv2.imread(filename[, flags]) -> retval + +.. ocv:cfunction:: IplImage* cvLoadImage( const char* filename, int iscolor=CV_LOAD_IMAGE_COLOR ) + +.. ocv:cfunction:: CvMat* cvLoadImageM( const char* filename, int iscolor=CV_LOAD_IMAGE_COLOR ) + +.. ocv:pyoldfunction:: cv.LoadImage(filename, iscolor=CV_LOAD_IMAGE_COLOR) -> None + +.. ocv:pyoldfunction:: cv.LoadImageM(filename, iscolor=CV_LOAD_IMAGE_COLOR) -> None + + :param filename: Name of file to be loaded. + + :param flags: Flags specifying the color type of a loaded image: + + * **>0** Return a 3-channel color image + + * **=0** Return a grayscale image + + * **<0** Return the loaded image as is. Note that in the current implementation the alpha channel, if any, is stripped from the output image. For example, a 4-channel RGBA image is loaded as RGB if :math:`flags\ge0` . + +The function ``imread`` loads an image from the specified file and returns it. If the image cannot be read (because of missing file, improper permissions, unsupported or invalid format), the function returns an empty matrix ( ``Mat::data==NULL`` ). Currently, the following file formats are supported: + + * Windows bitmaps - ``*.bmp, *.dib`` (always supported) + + * JPEG files - ``*.jpeg, *.jpg, *.jpe`` (see the *Notes* section) + + * JPEG 2000 files - ``*.jp2`` (see the *Notes* section) + + * Portable Network Graphics - ``*.png`` (see the *Notes* section) + + * Portable image format - ``*.pbm, *.pgm, *.ppm`` (always supported) + + * Sun rasters - ``*.sr, *.ras`` (always supported) + + * TIFF files - ``*.tiff, *.tif`` (see the *Notes* section) + +.. note:: + + * The function determines the type of an image by the content, not by the file extension. + + * On Microsoft Windows* OS and MacOSX*, the codecs shipped with an OpenCV image (libjpeg, libpng, libtiff, and libjasper) are used by default. So, OpenCV can always read JPEGs, PNGs, and TIFFs. On MacOSX, there is also an option to use native MacOSX image readers. But beware that currently these native image loaders give images with different pixel values because of the color management embedded into MacOSX. + + * On Linux*, BSD flavors and other Unix-like open-source operating systems, OpenCV looks for codecs supplied with an OS image. Install the relevant packages (do not forget the development files, for example, "libjpeg-dev", in Debian* and Ubuntu*) to get the codec support or turn on the ``OPENCV_BUILD_3RDPARTY_LIBS`` flag in CMake. + +imwrite +----------- +Saves an image to a specified file. + +.. ocv:function:: bool imwrite( const string& filename, InputArray img, const vector& params=vector() ) + +.. ocv:pyfunction:: cv2.imwrite(filename, img[, params]) -> retval + +.. ocv:cfunction:: int cvSaveImage( const char* filename, const CvArr* image, const int* params=0 ) + +.. ocv:pyoldfunction:: cv.SaveImage(filename, image)-> None + + :param filename: Name of the file. + + :param image: Image to be saved. + + :param params: Format-specific save parameters encoded as pairs ``paramId_1, paramValue_1, paramId_2, paramValue_2, ...`` . The following parameters are currently supported: + + * For JPEG, it can be a quality ( ``CV_IMWRITE_JPEG_QUALITY`` ) from 0 to 100 (the higher is the better). Default value is 95. + + * For PNG, it can be the compression level ( ``CV_IMWRITE_PNG_COMPRESSION`` ) from 0 to 9. A higher value means a smaller size and longer compression time. Default value is 3. + + * For PPM, PGM, or PBM, it can be a binary format flag ( ``CV_IMWRITE_PXM_BINARY`` ), 0 or 1. Default value is 1. + +The function ``imwrite`` saves the image to the specified file. The image format is chosen based on the ``filename`` extension (see +:ocv:func:`imread` for the list of extensions). Only 8-bit (or 16-bit in case of PNG, JPEG 2000, and TIFF) single-channel or 3-channel (with 'BGR' channel order) images can be saved using this function. If the format, depth or channel order is different, use +:ocv:func:`Mat::convertTo` , and +:ocv:func:`cvtColor` to convert it before saving. Or, use the universal XML I/O functions to save the image to XML or YAML format. + +It is possible to store PNG images with an alpha channel using this function. To do this, create 8-bit (or 16-bit) 4-channel image BGRA, where the alpha channel goes last. Fully transparent pixels should have alpha set to 0, fully opaque pixels should have alpha set to 255/65535. The sample below shows how to create such a BGRA image and store to PNG file. It also demonstrates how to set custom compression parameters :: + + #include + #include + #include + + using namespace cv; + using namespace std; + + void createAlphaMat(Mat &mat) + { + for (int i = 0; i < mat.rows; ++i) { + for (int j = 0; j < mat.cols; ++j) { + Vec4b& rgba = mat.at(i, j); + rgba[0] = UCHAR_MAX; + rgba[1] = saturate_cast((float (mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX); + rgba[2] = saturate_cast((float (mat.rows - i)) / ((float)mat.rows) * UCHAR_MAX); + rgba[3] = saturate_cast(0.5 * (rgba[1] + rgba[2])); + } + } + } + + int main(int argv, char **argc) + { + // Create mat with alpha channel + Mat mat(480, 640, CV_8UC4); + createAlphaMat(mat); + + vector compression_params; + compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION); + compression_params.push_back(9); + + try { + imwrite("alpha.png", mat, compression_params); + } + catch (runtime_error& ex) { + fprintf(stderr, "Exception converting image to PNG format: %s\n", ex.what()); + return 1; + } + + fprintf(stdout, "Saved PNG file with alpha data.\n"); + return 0; + } + + +VideoCapture +------------ +.. ocv:class:: VideoCapture + +Class for video capturing from video files or cameras. +The class provides C++ API for capturing video from cameras or for reading video files. Here is how the class can be used: :: + + #include "opencv2/opencv.hpp" + + using namespace cv; + + int main(int, char**) + { + VideoCapture cap(0); // open the default camera + if(!cap.isOpened()) // check if we succeeded + return -1; + + Mat edges; + namedWindow("edges",1); + for(;;) + { + Mat frame; + cap >> frame; // get a new frame from camera + cvtColor(frame, edges, CV_BGR2GRAY); + GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5); + Canny(edges, edges, 0, 30, 3); + imshow("edges", edges); + if(waitKey(30) >= 0) break; + } + // the camera will be deinitialized automatically in VideoCapture destructor + return 0; + } + + +.. note:: In C API the black-box structure ``CvCapture`` is used instead of ``VideoCapture``. + + +VideoCapture::VideoCapture +------------------------------ +VideoCapture constructors. + +.. ocv:function:: VideoCapture::VideoCapture() + +.. ocv:function:: VideoCapture::VideoCapture(const string& filename) + +.. ocv:function:: VideoCapture::VideoCapture(int device) + +.. ocv:pyfunction:: cv2.VideoCapture() -> +.. ocv:pyfunction:: cv2.VideoCapture(filename) -> +.. ocv:pyfunction:: cv2.VideoCapture(device) -> + +.. ocv:cfunction:: CvCapture* cvCaptureFromCAM( int device ) +.. ocv:pyoldfunction:: cv.CaptureFromCAM(index) -> CvCapture +.. ocv:cfunction:: CvCapture* cvCaptureFromFile( const char* filename ) +.. ocv:pyoldfunction:: cv.CaptureFromFile(filename) -> CvCapture + + :param filename: name of the opened video file + + :param device: id of the opened video capturing device (i.e. a camera index). If there is a single camera connected, just pass 0. + +.. note:: In C API, when you finished working with video, release ``CvCapture`` structure with ``cvReleaseCapture()``, or use ``Ptr`` that calls ``cvReleaseCapture()`` automatically in the destructor. + + +VideoCapture::open +--------------------- +Open video file or a capturing device for video capturing + +.. ocv:function:: bool VideoCapture::open(const string& filename) +.. ocv:function:: bool VideoCapture::open(int device) + +.. ocv:pyfunction:: cv2.VideoCapture.open(filename) -> retval +.. ocv:pyfunction:: cv2.VideoCapture.open(device) -> retval + + :param filename: name of the opened video file + + :param device: id of the opened video capturing device (i.e. a camera index). + +The methods first call :ocv:func:`VideoCapture::release` to close the already opened file or camera. + + +VideoCapture::isOpened +---------------------- +Returns true if video capturing has been initialized already. + +.. ocv:function:: bool VideoCapture::isOpened() + +.. ocv:pyfunction:: cv2.VideoCapture.isOpened() -> retval + +If the previous call to ``VideoCapture`` constructor or ``VideoCapture::open`` succeeded, the method returns true. + +VideoCapture::release +--------------------- +Closes video file or capturing device. + +.. ocv:function:: void VideoCapture::release() + +.. ocv:pyfunction:: cv2.VideoCapture.release() -> None + +.. ocv:cfunction:: void cvReleaseCapture(CvCapture** capture) + +The methods are automatically called by subsequent :ocv:func:`VideoCapture::open` and by ``VideoCapture`` destructor. + +The C function also deallocates memory and clears ``*capture`` pointer. + + +VideoCapture::grab +--------------------- +Grabs the next frame from video file or capturing device. + +.. ocv:function:: bool VideoCapture::grab() + +.. ocv:pyfunction:: cv2.VideoCapture.grab() -> retval + +.. ocv:cfunction:: int cvGrabFrame(CvCapture* capture) + +.. ocv:pyoldfunction:: cv.GrabFrame(capture) -> int + +The methods/functions grab the next frame from video file or camera and return true (non-zero) in the case of success. + +The primary use of the function is in multi-camera environments, especially when the cameras do not have hardware synchronization. That is, you call ``VideoCapture::grab()`` for each camera and after that call the slower method ``VideoCapture::retrieve()`` to decode and get frame from each camera. This way the overhead on demosaicing or motion jpeg decompression etc. is eliminated and the retrieved frames from different cameras will be closer in time. + +Also, when a connected camera is multi-head (for example, a stereo camera or a Kinect device), the correct way of retrieving data from it is to call `VideoCapture::grab` first and then call :ocv:func:`VideoCapture::retrieve` one or more times with different values of the ``channel`` parameter. See http://code.opencv.org/projects/opencv/repository/revisions/master/entry/samples/cpp/kinect_maps.cpp + + +VideoCapture::retrieve +---------------------- +Decodes and returns the grabbed video frame. + +.. ocv:function:: bool VideoCapture::retrieve(Mat& image, int channel=0) + +.. ocv:pyfunction:: cv2.VideoCapture.retrieve([image[, channel]]) -> retval, image + +.. ocv:cfunction:: IplImage* cvRetrieveFrame( CvCapture* capture, int streamIdx=0 ) + +.. ocv:pyoldfunction:: cv.RetrieveFrame(capture) -> image + +The methods/functions decode and return the just grabbed frame. If no frames has been grabbed (camera has been disconnected, or there are no more frames in video file), the methods return false and the functions return NULL pointer. + +.. note:: OpenCV 1.x functions ``cvRetrieveFrame`` and ``cv.RetrieveFrame`` return image stored inside the video capturing structure. It is not allowed to modify or release the image! You can copy the frame using :ocv:cfunc:`cvCloneImage` and then do whatever you want with the copy. + + +VideoCapture::read +---------------------- +Grabs, decodes and returns the next video frame. + +.. ocv:function:: VideoCapture& VideoCapture::operator >> (Mat& image) + +.. ocv:function:: bool VideoCapture::read(Mat& image) + +.. ocv:pyfunction:: cv2.VideoCapture.read([image]) -> retval, image + +.. ocv:cfunction:: IplImage* cvQueryFrame(CvCapture* capture) + +.. ocv:pyoldfunction:: cv.QueryFrame(capture) -> image + +The methods/functions combine :ocv:func:`VideoCapture::grab` and :ocv:func:`VideoCapture::retrieve` in one call. This is the most convenient method for reading video files or capturing data from decode and return the just grabbed frame. If no frames has been grabbed (camera has been disconnected, or there are no more frames in video file), the methods return false and the functions return NULL pointer. + +.. note:: OpenCV 1.x functions ``cvRetrieveFrame`` and ``cv.RetrieveFrame`` return image stored inside the video capturing structure. It is not allowed to modify or release the image! You can copy the frame using :ocv:cfunc:`cvCloneImage` and then do whatever you want with the copy. + + +VideoCapture::get +--------------------- +Returns the specified ``VideoCapture`` property + +.. ocv:function:: double VideoCapture::get(int propId) + +.. ocv:pyfunction:: cv2.VideoCapture.get(propId) -> retval + +.. ocv:cfunction:: double cvGetCaptureProperty( CvCapture* capture, int property_id ) + +.. ocv:pyoldfunction:: cv.GetCaptureProperty(capture, property_id) -> float + + + :param propId: Property identifier. It can be one of the following: + + * **CV_CAP_PROP_POS_MSEC** Current position of the video file in milliseconds or video capture timestamp. + + * **CV_CAP_PROP_POS_FRAMES** 0-based index of the frame to be decoded/captured next. + + * **CV_CAP_PROP_POS_AVI_RATIO** Relative position of the video file: 0 - start of the film, 1 - end of the film. + + * **CV_CAP_PROP_FRAME_WIDTH** Width of the frames in the video stream. + + * **CV_CAP_PROP_FRAME_HEIGHT** Height of the frames in the video stream. + + * **CV_CAP_PROP_FPS** Frame rate. + + * **CV_CAP_PROP_FOURCC** 4-character code of codec. + + * **CV_CAP_PROP_FRAME_COUNT** Number of frames in the video file. + + * **CV_CAP_PROP_FORMAT** Format of the Mat objects returned by ``retrieve()`` . + + * **CV_CAP_PROP_MODE** Backend-specific value indicating the current capture mode. + + * **CV_CAP_PROP_BRIGHTNESS** Brightness of the image (only for cameras). + + * **CV_CAP_PROP_CONTRAST** Contrast of the image (only for cameras). + + * **CV_CAP_PROP_SATURATION** Saturation of the image (only for cameras). + + * **CV_CAP_PROP_HUE** Hue of the image (only for cameras). + + * **CV_CAP_PROP_GAIN** Gain of the image (only for cameras). + + * **CV_CAP_PROP_EXPOSURE** Exposure (only for cameras). + + * **CV_CAP_PROP_CONVERT_RGB** Boolean flags indicating whether images should be converted to RGB. + + * **CV_CAP_PROP_WHITE_BALANCE** Currently not supported + + * **CV_CAP_PROP_RECTIFICATION** Rectification flag for stereo cameras (note: only supported by DC1394 v 2.x backend currently) + + +**Note**: When querying a property that is not supported by the backend used by the ``VideoCapture`` class, value 0 is returned. + +VideoCapture::set +--------------------- +Sets a property in the ``VideoCapture``. + +.. ocv:function:: bool VideoCapture::set( int propId, double value ) + +.. ocv:pyfunction:: cv2.VideoCapture.set(propId, value) -> retval + +.. ocv:cfunction:: int cvSetCaptureProperty( CvCapture* capture, int property_id, double value ) + +.. ocv:pyoldfunction:: cv.SetCaptureProperty(capture, property_id, value) -> retval + + :param propId: Property identifier. It can be one of the following: + + * **CV_CAP_PROP_POS_MSEC** Current position of the video file in milliseconds. + + * **CV_CAP_PROP_POS_FRAMES** 0-based index of the frame to be decoded/captured next. + + * **CV_CAP_PROP_POS_AVI_RATIO** Relative position of the video file: 0 - start of the film, 1 - end of the film. + + * **CV_CAP_PROP_FRAME_WIDTH** Width of the frames in the video stream. + + * **CV_CAP_PROP_FRAME_HEIGHT** Height of the frames in the video stream. + + * **CV_CAP_PROP_FPS** Frame rate. + + * **CV_CAP_PROP_FOURCC** 4-character code of codec. + + * **CV_CAP_PROP_FRAME_COUNT** Number of frames in the video file. + + * **CV_CAP_PROP_FORMAT** Format of the Mat objects returned by ``retrieve()`` . + + * **CV_CAP_PROP_MODE** Backend-specific value indicating the current capture mode. + + * **CV_CAP_PROP_BRIGHTNESS** Brightness of the image (only for cameras). + + * **CV_CAP_PROP_CONTRAST** Contrast of the image (only for cameras). + + * **CV_CAP_PROP_SATURATION** Saturation of the image (only for cameras). + + * **CV_CAP_PROP_HUE** Hue of the image (only for cameras). + + * **CV_CAP_PROP_GAIN** Gain of the image (only for cameras). + + * **CV_CAP_PROP_EXPOSURE** Exposure (only for cameras). + + * **CV_CAP_PROP_CONVERT_RGB** Boolean flags indicating whether images should be converted to RGB. + + * **CV_CAP_PROP_WHITE_BALANCE** Currently unsupported + + * **CV_CAP_PROP_RECTIFICATION** Rectification flag for stereo cameras (note: only supported by DC1394 v 2.x backend currently) + + :param value: Value of the property. + + + +VideoWriter +----------- +.. ocv:class:: VideoWriter + +Video writer class. + + + +VideoWriter::VideoWriter +------------------------ +VideoWriter constructors + +.. ocv:function:: VideoWriter::VideoWriter() + +.. ocv:function:: VideoWriter::VideoWriter(const string& filename, int fourcc, double fps, Size frameSize, bool isColor=true) + +.. ocv:pyfunction:: cv2.VideoWriter([filename, fourcc, fps, frameSize[, isColor]]) -> + +.. ocv:cfunction:: CvVideoWriter* cvCreateVideoWriter( const char* filename, int fourcc, double fps, CvSize frame_size, int is_color=1 ) +.. ocv:pyoldfunction:: cv.CreateVideoWriter(filename, fourcc, fps, frame_size, is_color=true) -> CvVideoWriter + +.. ocv:pyfunction:: cv2.VideoWriter.isOpened() -> retval +.. ocv:pyfunction:: cv2.VideoWriter.open(filename, fourcc, fps, frameSize[, isColor]) -> retval +.. ocv:pyfunction:: cv2.VideoWriter.write(image) -> None + + :param filename: Name of the output video file. + + :param fourcc: 4-character code of codec used to compress the frames. For example, ``CV_FOURCC('P','I','M,'1')`` is a MPEG-1 codec, ``CV_FOURCC('M','J','P','G')`` is a motion-jpeg codec etc. + + :param fps: Framerate of the created video stream. + + :param frameSize: Size of the video frames. + + :param isColor: If it is not zero, the encoder will expect and encode color frames, otherwise it will work with grayscale frames (the flag is currently supported on Windows only). + +The constructors/functions initialize video writers. On Linux FFMPEG is used to write videos; on Windows FFMPEG or VFW is used; on MacOSX QTKit is used. + + + +ReleaseVideoWriter +------------------ +Releases the AVI writer. + +.. ocv:cfunction:: void cvReleaseVideoWriter( CvVideoWriter** writer ) + +The function should be called after you finished using ``CvVideoWriter`` opened with :ocv:cfunc:`CreateVideoWriter`. + + +VideoWriter::open +----------------- +Initializes or reinitializes video writer. + +.. ocv:function:: bool VideoWriter::open(const string& filename, int fourcc, double fps, Size frameSize, bool isColor=true) + +.. ocv:pyfunction:: cv2.VideoWriter.open(filename, fourcc, fps, frameSize[, isColor]) -> retval + +The method opens video writer. Parameters are the same as in the constructor :ocv:func:`VideoWriter::VideoWriter`. + + +VideoWriter::isOpened +--------------------- +Returns true if video writer has been successfully initialized. + +.. ocv:function:: bool VideoWriter::isOpened() + +.. ocv:pyfunction:: cv2.VideoWriter.isOpened() -> retval + + +VideoWriter::write +------------------ +Writes the next video frame + +.. ocv:function:: VideoWriter& VideoWriter::operator << (const Mat& image) + +.. ocv:function:: void VideoWriter::write(const Mat& image) + +.. ocv:pyfunction:: cv2.VideoWriter.write(image) -> None + +.. ocv:cfunction:: int cvWriteFrame( CvVideoWriter* writer, const IplImage* image ) +.. ocv:pyoldfunction:: cv.WriteFrame(writer, image)->int + + :param writer: Video writer structure (OpenCV 1.x API) + + :param image: The written frame + +The functions/methods write the specified image to video file. It must have the same size as has been specified when opening the video writer. + diff --git a/highgui/doc/user_interface.rst b/highgui/doc/user_interface.rst new file mode 100644 index 0000000..def8451 --- /dev/null +++ b/highgui/doc/user_interface.rst @@ -0,0 +1,258 @@ +User Interface +============== + +.. highlight:: cpp + +createTrackbar +------------------ +Creates a trackbar and attaches it to the specified window. + +.. ocv:function:: int createTrackbar( const string& trackbarname, const string& winname, int* value, int count, TrackbarCallback onChange=0, void* userdata=0) + +.. ocv:cfunction:: int cvCreateTrackbar( const char* trackbar_name, const char* window_name, int* value, int count, CvTrackbarCallback on_change=NULL ) + +.. ocv:pyoldfunction:: cv.CreateTrackbar(trackbarName, windowName, value, count, onChange) -> None + + :param trackbarname: Name of the created trackbar. + + :param winname: Name of the window that will be used as a parent of the created trackbar. + + :param value: Optional pointer to an integer variable whose value reflects the position of the slider. Upon creation, the slider position is defined by this variable. + + :param count: Maximal position of the slider. The minimal position is always 0. + + :param onChange: Pointer to the function to be called every time the slider changes position. This function should be prototyped as ``void Foo(int,void*);`` , where the first parameter is the trackbar position and the second parameter is the user data (see the next parameter). If the callback is the NULL pointer, no callbacks are called, but only ``value`` is updated. + + :param userdata: User data that is passed as is to the callback. It can be used to handle trackbar events without using global variables. + +The function ``createTrackbar`` creates a trackbar (a slider or range control) with the specified name and range, assigns a variable ``value`` to be a position synchronized with the trackbar and specifies the callback function ``onChange`` to be called on the trackbar position change. The created trackbar is displayed in the specified window ``winname``. + +.. note:: + + **[Qt Backend Only]** ``winname`` can be empty (or NULL) if the trackbar should be attached to the control panel. + +Clicking the label of each trackbar enables editing the trackbar values manually. + +getTrackbarPos +------------------ +Returns the trackbar position. + +.. ocv:function:: int getTrackbarPos( const string& trackbarname, const string& winname ) + +.. ocv:pyfunction:: cv2.getTrackbarPos(trackbarname, winname) -> retval + +.. ocv:cfunction:: int cvGetTrackbarPos( const char* trackbar_name, const char* window_name ) + +.. ocv:pyoldfunction:: cv.GetTrackbarPos(trackbarName, windowName) -> retval + + :param trackbarname: Name of the trackbar. + + :param winname: Name of the window that is the parent of the trackbar. + +The function returns the current position of the specified trackbar. + +.. note:: + + **[Qt Backend Only]** ``winname`` can be empty (or NULL) if the trackbar is attached to the control panel. + +imshow +---------- +Displays an image in the specified window. + +.. ocv:function:: void imshow( const string& winname, InputArray mat ) + +.. ocv:pyfunction:: cv2.imshow(winname, mat) -> None + +.. ocv:cfunction:: void cvShowImage( const char* name, const CvArr* image ) + +.. ocv:pyoldfunction:: cv.ShowImage(name, image) -> None + + :param winname: Name of the window. + + :param image: Image to be shown. + +The function ``imshow`` displays an image in the specified window. If the window was created with the ``CV_WINDOW_AUTOSIZE`` flag, the image is shown with its original size. Otherwise, the image is scaled to fit the window. The function may scale the image, depending on its depth: + + * If the image is 8-bit unsigned, it is displayed as is. + + * If the image is 16-bit unsigned or 32-bit integer, the pixels are divided by 256. That is, the value range [0,255*256] is mapped to [0,255]. + + * If the image is 32-bit floating-point, the pixel values are multiplied by 255. That is, the value range [0,1] is mapped to [0,255]. + + +namedWindow +--------------- +Creates a window. + +.. ocv:function:: void namedWindow( const string& winname, int flags=WINDOW_AUTOSIZE ) + +.. ocv:pyfunction:: cv2.namedWindow(winname[, flags]) -> None + +.. ocv:cfunction:: int cvNamedWindow( const char* name, int flags=CV_WINDOW_AUTOSIZE ) + +.. ocv:pyoldfunction:: cv.NamedWindow(name, flags=CV_WINDOW_AUTOSIZE)-> None + + :param name: Name of the window in the window caption that may be used as a window identifier. + + :param flags: Flags of the window. Currently the only supported flag is ``CV_WINDOW_AUTOSIZE`` . If this is set, the window size is automatically adjusted to fit the displayed image (see :ocv:func:`imshow` ), and you cannot change the window size manually. + +The function ``namedWindow`` creates a window that can be used as a placeholder for images and trackbars. Created windows are referred to by their names. + +If a window with the same name already exists, the function does nothing. + +You can call :ocv:func:`destroyWindow` or :ocv:func:`destroyAllWindows` to close the window and de-allocate any associated memory usage. For a simple program, you do not really have to call these functions because all the resources and windows of the application are closed automatically by the operating system upon exit. + +.. note:: + + Qt backend supports additional flags: + + * **CV_WINDOW_NORMAL or CV_WINDOW_AUTOSIZE:** ``CV_WINDOW_NORMAL`` enables you to resize the window, whereas ``CV_WINDOW_AUTOSIZE`` adjusts automatically the window size to fit the displayed image (see :ocv:func:`imshow` ), and you cannot change the window size manually. + + * **CV_WINDOW_FREERATIO or CV_WINDOW_KEEPRATIO:** ``CV_WINDOW_FREERATIO`` adjusts the image with no respect to its ratio, whereas ``CV_WINDOW_KEEPRATIO`` keeps the image ratio. + + * **CV_GUI_NORMAL or CV_GUI_EXPANDED:** ``CV_GUI_NORMAL`` is the old way to draw the window without statusbar and toolbar, whereas ``CV_GUI_EXPANDED`` is a new enhanced GUI. + + By default, ``flags == CV_WINDOW_AUTOSIZE | CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED`` + + +destroyWindow +------------- +Destroys a window. + +.. ocv:function:: void destroyWindow( const string& winname ) + +.. ocv:pyfunction:: cv2.destroyWindow(winname) -> None + +.. ocv:cfunction:: void cvDestroyWindow( const char* name ) + +.. ocv:pyoldfunction:: cv.DestroyWindow(name)-> None + + :param winname: Name of the window to be destroyed. + +The function ``destroyWindow`` destroys the window with the given name. + + +destroyAllWindows +----------------- +Destroys all of the HighGUI windows. + +.. ocv:function:: void destroyAllWindows() + +.. ocv:pyfunction:: cv2.destroyAllWindows() -> None + +.. ocv:cfunction:: void cvDestroyAllWindows() + +.. ocv:pyoldfunction:: cv.DestroyAllWindows()-> None + +The function ``destroyAllWindows`` destroys all of the opened HighGUI windows. + + +MoveWindow +---------- +Moves window to the specified position + +.. ocv:function:: void moveWindow( const string& winname, int x, int y ) + +.. ocv:pyfunction:: cv2.moveWindow(winname, x, y) -> None + +.. ocv:cfunction:: void cvMoveWindow( const char* name, int x, int y ) + +.. ocv:pyoldfunction:: cv.MoveWindow(name, x, y)-> None + + :param winname: Window name + + :param x: The new x-coordinate of the window + + :param y: The new y-coordinate of the window + + +ResizeWindow +------------ +Resizes window to the specified size + +.. ocv:function:: void resizeWindow( const string& winname, int width, int height ) + +.. ocv:pyfunction:: cv2.resizeWindow(winname, width, height) -> None + +.. ocv:cfunction:: void cvResizeWindow( const char* name, int width, int height ) + +.. ocv:pyoldfunction:: cv.ResizeWindow(name, width, height)-> None + + :param winname: Window name + + :param width: The new window width + + :param height: The new window height + +.. note:: + + * The specified window size is for the image area. Toolbars are not counted. + + * Only windows created without CV_WINDOW_AUTOSIZE flag can be resized. + + +SetMouseCallback +---------------- +Sets mouse handler for the specified window + +.. ocv:function:: void setMouseCallback( const string& winname, MouseCallback onMouse, void* userdata=0 ) + +.. ocv:cfunction:: void cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param=NULL ) + +.. ocv:pyoldfunction:: cv.SetMouseCallback(windowName, onMouse, param=None) -> None + + :param winname: Window name + + :param onMouse: Mouse callback. See OpenCV samples, such as http://code.opencv.org/projects/opencv/repository/revisions/master/entry/samples/cpp/ffilldemo.cpp, on how to specify and use the callback. + + :param userdata: The optional parameter passed to the callback. + + +setTrackbarPos +------------------ +Sets the trackbar position. + +.. ocv:function:: void setTrackbarPos( const string& trackbarname, const string& winname, int pos ) + +.. ocv:pyfunction:: cv2.setTrackbarPos(trackbarname, winname, pos) -> None + +.. ocv:cfunction:: void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos ) + +.. ocv:pyoldfunction:: cv.SetTrackbarPos(trackbarName, windowName, pos)-> None + + :param trackbarname: Name of the trackbar. + + :param winname: Name of the window that is the parent of trackbar. + + :param pos: New position. + +The function sets the position of the specified trackbar in the specified window. + +.. note:: + + **[Qt Backend Only]** ``winname`` can be empty (or NULL) if the trackbar is attached to the control panel. + +waitKey +----------- +Waits for a pressed key. + +.. ocv:function:: int waitKey(int delay=0) + +.. ocv:pyfunction:: cv2.waitKey([delay]) -> retval + +.. ocv:cfunction:: int cvWaitKey( int delay=0 ) + +.. ocv:pyoldfunction:: cv.WaitKey(delay=0)-> int + + :param delay: Delay in milliseconds. 0 is the special value that means "forever". + +The function ``waitKey`` waits for a key event infinitely (when +:math:`\texttt{delay}\leq 0` ) or for ``delay`` milliseconds, when it is positive. Since the OS has a minimum time between switching threads, the function will not wait exactly ``delay`` ms, it will wait at least ``delay`` ms, depending on what else is running on your computer at that time. It returns the code of the pressed key or -1 if no key was pressed before the specified time had elapsed. + +.. note:: + + This function is the only method in HighGUI that can fetch and handle events, so it needs to be called periodically for normal event processing unless HighGUI is used within an environment that takes care of event processing. + +.. note:: + + The function only works if there is at least one HighGUI window created and the window is active. If there are several HighGUI windows, any of them can be active. diff --git a/highgui/include/opencv2/highgui/cap_ios.h b/highgui/include/opencv2/highgui/cap_ios.h new file mode 100644 index 0000000..26a28c0 --- /dev/null +++ b/highgui/include/opencv2/highgui/cap_ios.h @@ -0,0 +1,163 @@ +/* + * cap_ios.h + * For iOS video I/O + * by Eduard Feicho on 29/07/12 + * Copyright 2012. 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. + * + */ + +#import +#import +#import +#import +#include "opencv2/core/core.hpp" + +/////////////////////////////////////// CvAbstractCamera ///////////////////////////////////// + +@class CvAbstractCamera; + +@interface CvAbstractCamera : NSObject +{ + AVCaptureSession* captureSession; + AVCaptureConnection* videoCaptureConnection; + AVCaptureVideoPreviewLayer *captureVideoPreviewLayer; + + UIDeviceOrientation currentDeviceOrientation; + + BOOL cameraAvailable; + BOOL captureSessionLoaded; + BOOL running; + BOOL useAVCaptureVideoPreviewLayer; + + AVCaptureDevicePosition defaultAVCaptureDevicePosition; + AVCaptureVideoOrientation defaultAVCaptureVideoOrientation; + NSString *const defaultAVCaptureSessionPreset; + + int defaultFPS; + + UIView* parentView; + + int imageWidth; + int imageHeight; +} + +@property (nonatomic, retain) AVCaptureSession* captureSession; +@property (nonatomic, retain) AVCaptureConnection* videoCaptureConnection; + +@property (nonatomic, readonly) BOOL running; +@property (nonatomic, readonly) BOOL captureSessionLoaded; + +@property (nonatomic, assign) int defaultFPS; +@property (nonatomic, assign) AVCaptureDevicePosition defaultAVCaptureDevicePosition; +@property (nonatomic, assign) AVCaptureVideoOrientation defaultAVCaptureVideoOrientation; +@property (nonatomic, assign) BOOL useAVCaptureVideoPreviewLayer; +@property (nonatomic, strong) NSString *const defaultAVCaptureSessionPreset; + +@property (nonatomic, assign) int imageWidth; +@property (nonatomic, assign) int imageHeight; + +@property (nonatomic, retain) UIView* parentView; + +- (void)start; +- (void)stop; +- (void)switchCameras; + +- (id)initWithParentView:(UIView*)parent; + +- (void)createCaptureOutput; +- (void)createVideoPreviewLayer; +- (void)updateOrientation; + + +@end + +///////////////////////////////// CvVideoCamera /////////////////////////////////////////// + +@class CvVideoCamera; + +@protocol CvVideoCameraDelegate + +#ifdef __cplusplus +// delegate method for processing image frames +- (void)processImage:(cv::Mat&)image; +#endif + +@end + +@interface CvVideoCamera : CvAbstractCamera +{ + AVCaptureVideoDataOutput *videoDataOutput; + + dispatch_queue_t videoDataOutputQueue; + CALayer *customPreviewLayer; + + BOOL grayscaleMode; + + BOOL recordVideo; + AVAssetWriterInput* recordAssetWriterInput; + AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor; + AVAssetWriter* recordAssetWriter; + + CMTime lastSampleTime; + +} + +@property (nonatomic, assign) id delegate; +@property (nonatomic, assign) BOOL grayscaleMode; + +@property (nonatomic, assign) BOOL recordVideo; +@property (nonatomic, retain) AVAssetWriterInput* recordAssetWriterInput; +@property (nonatomic, retain) AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor; +@property (nonatomic, retain) AVAssetWriter* recordAssetWriter; + +- (void)adjustLayoutToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; +- (void)layoutPreviewLayer; +- (void)saveVideo; +- (NSURL *)videoFileURL; + + +@end + +///////////////////////////////// CvPhotoCamera /////////////////////////////////////////// + +@class CvPhotoCamera; + +@protocol CvPhotoCameraDelegate + +- (void)photoCamera:(CvPhotoCamera*)photoCamera capturedImage:(UIImage *)image; +- (void)photoCameraCancel:(CvPhotoCamera*)photoCamera; + +@end + +@interface CvPhotoCamera : CvAbstractCamera +{ + AVCaptureStillImageOutput *stillImageOutput; +} + +@property (nonatomic, assign) id delegate; + +- (void)takePicture; + +@end diff --git a/highgui/include/opencv2/highgui/highgui.hpp b/highgui/include/opencv2/highgui/highgui.hpp new file mode 100644 index 0000000..5c5d24b --- /dev/null +++ b/highgui/include/opencv2/highgui/highgui.hpp @@ -0,0 +1,251 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_HIGHGUI_HPP__ +#define __OPENCV_HIGHGUI_HPP__ + +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui_c.h" + +#ifdef __cplusplus + +struct CvCapture; +struct CvVideoWriter; + +namespace cv +{ + +enum { + // Flags for namedWindow + WINDOW_NORMAL = CV_WINDOW_NORMAL, // the user can resize the window (no constraint) / also use to switch a fullscreen window to a normal size + WINDOW_AUTOSIZE = CV_WINDOW_AUTOSIZE, // the user cannot resize the window, the size is constrainted by the image displayed + WINDOW_OPENGL = CV_WINDOW_OPENGL, // window with opengl support + + // Flags for set / getWindowProperty + WND_PROP_FULLSCREEN = CV_WND_PROP_FULLSCREEN, // fullscreen property + WND_PROP_AUTOSIZE = CV_WND_PROP_AUTOSIZE, // autosize property + WND_PROP_ASPECT_RATIO = CV_WND_PROP_ASPECTRATIO, // window's aspect ration + WND_PROP_OPENGL = CV_WND_PROP_OPENGL // opengl support +}; + +CV_EXPORTS_W void namedWindow(const string& winname, int flags = WINDOW_AUTOSIZE); +CV_EXPORTS_W void destroyWindow(const string& winname); +CV_EXPORTS_W void destroyAllWindows(); + +CV_EXPORTS_W int startWindowThread(); + +CV_EXPORTS_W int waitKey(int delay = 0); + +CV_EXPORTS_W void imshow(const string& winname, InputArray mat); + +CV_EXPORTS_W void resizeWindow(const string& winname, int width, int height); +CV_EXPORTS_W void moveWindow(const string& winname, int x, int y); + +CV_EXPORTS_W void setWindowProperty(const string& winname, int prop_id, double prop_value);//YV +CV_EXPORTS_W double getWindowProperty(const string& winname, int prop_id);//YV + +enum +{ + EVENT_MOUSEMOVE =0, + EVENT_LBUTTONDOWN =1, + EVENT_RBUTTONDOWN =2, + EVENT_MBUTTONDOWN =3, + EVENT_LBUTTONUP =4, + EVENT_RBUTTONUP =5, + EVENT_MBUTTONUP =6, + EVENT_LBUTTONDBLCLK =7, + EVENT_RBUTTONDBLCLK =8, + EVENT_MBUTTONDBLCLK =9 +}; + +enum +{ + EVENT_FLAG_LBUTTON =1, + EVENT_FLAG_RBUTTON =2, + EVENT_FLAG_MBUTTON =4, + EVENT_FLAG_CTRLKEY =8, + EVENT_FLAG_SHIFTKEY =16, + EVENT_FLAG_ALTKEY =32 +}; + +typedef void (*MouseCallback)(int event, int x, int y, int flags, void* userdata); + +//! assigns callback for mouse events +CV_EXPORTS void setMouseCallback(const string& winname, MouseCallback onMouse, void* userdata = 0); + + +typedef void (CV_CDECL *TrackbarCallback)(int pos, void* userdata); + +CV_EXPORTS int createTrackbar(const string& trackbarname, const string& winname, + int* value, int count, + TrackbarCallback onChange = 0, + void* userdata = 0); + +CV_EXPORTS_W int getTrackbarPos(const string& trackbarname, const string& winname); +CV_EXPORTS_W void setTrackbarPos(const string& trackbarname, const string& winname, int pos); + +// OpenGL support + +typedef void (*OpenGlDrawCallback)(void* userdata); +CV_EXPORTS void setOpenGlDrawCallback(const string& winname, OpenGlDrawCallback onOpenGlDraw, void* userdata = 0); + +CV_EXPORTS void setOpenGlContext(const string& winname); + +CV_EXPORTS void updateWindow(const string& winname); + +CV_EXPORTS void pointCloudShow(const string& winname, const GlCamera& camera, const GlArrays& arr); +CV_EXPORTS void pointCloudShow(const string& winname, const GlCamera& camera, InputArray points, InputArray colors = noArray()); + +//Only for Qt + +CV_EXPORTS CvFont fontQt(const string& nameFont, int pointSize=-1, + Scalar color=Scalar::all(0), int weight=CV_FONT_NORMAL, + int style=CV_STYLE_NORMAL, int spacing=0); +CV_EXPORTS void addText( const Mat& img, const string& text, Point org, CvFont font); + +CV_EXPORTS void displayOverlay(const string& winname, const string& text, int delayms CV_DEFAULT(0)); +CV_EXPORTS void displayStatusBar(const string& winname, const string& text, int delayms CV_DEFAULT(0)); + +CV_EXPORTS void saveWindowParameters(const string& windowName); +CV_EXPORTS void loadWindowParameters(const string& windowName); +CV_EXPORTS int startLoop(int (*pt2Func)(int argc, char *argv[]), int argc, char* argv[]); +CV_EXPORTS void stopLoop(); + +typedef void (CV_CDECL *ButtonCallback)(int state, void* userdata); +CV_EXPORTS int createButton( const string& bar_name, ButtonCallback on_change, + void* userdata=NULL, int type=CV_PUSH_BUTTON, + bool initial_button_state=0); + +//------------------------- + +enum +{ + // 8bit, color or not + IMREAD_UNCHANGED =-1, + // 8bit, gray + IMREAD_GRAYSCALE =0, + // ?, color + IMREAD_COLOR =1, + // any depth, ? + IMREAD_ANYDEPTH =2, + // ?, any color + IMREAD_ANYCOLOR =4 +}; + +enum +{ + IMWRITE_JPEG_QUALITY =1, + IMWRITE_PNG_COMPRESSION =16, + IMWRITE_PNG_STRATEGY =17, + IMWRITE_PNG_STRATEGY_DEFAULT =0, + IMWRITE_PNG_STRATEGY_FILTERED =1, + IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY =2, + IMWRITE_PNG_STRATEGY_RLE =3, + IMWRITE_PNG_STRATEGY_FIXED =4, + IMWRITE_PXM_BINARY =32 +}; + +CV_EXPORTS_W Mat imread( const string& filename, int flags=1 ); +CV_EXPORTS_W bool imwrite( const string& filename, InputArray img, + const vector& params=vector()); +CV_EXPORTS_W Mat imdecode( InputArray buf, int flags ); +CV_EXPORTS_W bool imencode( const string& ext, InputArray img, + CV_OUT vector& buf, + const vector& params=vector()); + +#ifndef CV_NO_VIDEO_CAPTURE_CPP_API + +template<> void CV_EXPORTS Ptr::delete_obj(); +template<> void CV_EXPORTS Ptr::delete_obj(); + +class CV_EXPORTS_W VideoCapture +{ +public: + CV_WRAP VideoCapture(); + CV_WRAP VideoCapture(const string& filename); + CV_WRAP VideoCapture(int device); + + virtual ~VideoCapture(); + CV_WRAP virtual bool open(const string& filename); + CV_WRAP virtual bool open(int device); + CV_WRAP virtual bool isOpened() const; + CV_WRAP virtual void release(); + + CV_WRAP virtual bool grab(); + CV_WRAP virtual bool retrieve(CV_OUT Mat& image, int channel=0); + virtual VideoCapture& operator >> (CV_OUT Mat& image); + CV_WRAP virtual bool read(CV_OUT Mat& image); + + CV_WRAP virtual bool set(int propId, double value); + CV_WRAP virtual double get(int propId); + +protected: + Ptr cap; +}; + + +class CV_EXPORTS_W VideoWriter +{ +public: + CV_WRAP VideoWriter(); + CV_WRAP VideoWriter(const string& filename, int fourcc, double fps, + Size frameSize, bool isColor=true); + + virtual ~VideoWriter(); + CV_WRAP virtual bool open(const string& filename, int fourcc, double fps, + Size frameSize, bool isColor=true); + CV_WRAP virtual bool isOpened() const; + CV_WRAP virtual void release(); + virtual VideoWriter& operator << (const Mat& image); + CV_WRAP virtual void write(const Mat& image); + +protected: + Ptr writer; +}; + +#endif + +} + +#endif + +#endif diff --git a/highgui/include/opencv2/highgui/highgui_c.h b/highgui/include/opencv2/highgui/highgui_c.h new file mode 100644 index 0000000..ddd3003 --- /dev/null +++ b/highgui/include/opencv2/highgui/highgui_c.h @@ -0,0 +1,601 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_HIGHGUI_H__ +#define __OPENCV_HIGHGUI_H__ + +#include "opencv2/core/core_c.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/****************************************************************************************\ +* Basic GUI functions * +\****************************************************************************************/ +//YV +//-----------New for Qt +/* For font */ +enum { CV_FONT_LIGHT = 25,//QFont::Light, + CV_FONT_NORMAL = 50,//QFont::Normal, + CV_FONT_DEMIBOLD = 63,//QFont::DemiBold, + CV_FONT_BOLD = 75,//QFont::Bold, + CV_FONT_BLACK = 87 //QFont::Black +}; + +enum { CV_STYLE_NORMAL = 0,//QFont::StyleNormal, + CV_STYLE_ITALIC = 1,//QFont::StyleItalic, + CV_STYLE_OBLIQUE = 2 //QFont::StyleOblique +}; +/* ---------*/ + +//for color cvScalar(blue_component, green_component, red\_component[, alpha_component]) +//and alpha= 0 <-> 0xFF (not transparent <-> transparent) +CVAPI(CvFont) cvFontQt(const char* nameFont, int pointSize CV_DEFAULT(-1), CvScalar color CV_DEFAULT(cvScalarAll(0)), int weight CV_DEFAULT(CV_FONT_NORMAL), int style CV_DEFAULT(CV_STYLE_NORMAL), int spacing CV_DEFAULT(0)); + +CVAPI(void) cvAddText(const CvArr* img, const char* text, CvPoint org, CvFont *arg2); + +CVAPI(void) cvDisplayOverlay(const char* name, const char* text, int delayms CV_DEFAULT(0)); +CVAPI(void) cvDisplayStatusBar(const char* name, const char* text, int delayms CV_DEFAULT(0)); + +CVAPI(void) cvSaveWindowParameters(const char* name); +CVAPI(void) cvLoadWindowParameters(const char* name); +CVAPI(int) cvStartLoop(int (*pt2Func)(int argc, char *argv[]), int argc, char* argv[]); +CVAPI(void) cvStopLoop( void ); + +typedef void (CV_CDECL *CvButtonCallback)(int state, void* userdata); +enum {CV_PUSH_BUTTON = 0, CV_CHECKBOX = 1, CV_RADIOBOX = 2}; +CVAPI(int) cvCreateButton( const char* button_name CV_DEFAULT(NULL),CvButtonCallback on_change CV_DEFAULT(NULL), void* userdata CV_DEFAULT(NULL) , int button_type CV_DEFAULT(CV_PUSH_BUTTON), int initial_button_state CV_DEFAULT(0)); +//---------------------- + + +/* this function is used to set some external parameters in case of X Window */ +CVAPI(int) cvInitSystem( int argc, char** argv ); + +CVAPI(int) cvStartWindowThread( void ); + +// --------- YV --------- +enum +{ + //These 3 flags are used by cvSet/GetWindowProperty + CV_WND_PROP_FULLSCREEN = 0, //to change/get window's fullscreen property + CV_WND_PROP_AUTOSIZE = 1, //to change/get window's autosize property + CV_WND_PROP_ASPECTRATIO= 2, //to change/get window's aspectratio property + CV_WND_PROP_OPENGL = 3, //to change/get window's opengl support + + //These 2 flags are used by cvNamedWindow and cvSet/GetWindowProperty + CV_WINDOW_NORMAL = 0x00000000, //the user can resize the window (no constraint) / also use to switch a fullscreen window to a normal size + CV_WINDOW_AUTOSIZE = 0x00000001, //the user cannot resize the window, the size is constrainted by the image displayed + CV_WINDOW_OPENGL = 0x00001000, //window with opengl support + + //Those flags are only for Qt + CV_GUI_EXPANDED = 0x00000000, //status bar and tool bar + CV_GUI_NORMAL = 0x00000010, //old fashious way + + //These 3 flags are used by cvNamedWindow and cvSet/GetWindowProperty + CV_WINDOW_FULLSCREEN = 1,//change the window to fullscreen + CV_WINDOW_FREERATIO = 0x00000100,//the image expends as much as it can (no ratio constraint) + CV_WINDOW_KEEPRATIO = 0x00000000//the ration image is respected. +}; + +/* create window */ +CVAPI(int) cvNamedWindow( const char* name, int flags CV_DEFAULT(CV_WINDOW_AUTOSIZE) ); + +/* Set and Get Property of the window */ +CVAPI(void) cvSetWindowProperty(const char* name, int prop_id, double prop_value); +CVAPI(double) cvGetWindowProperty(const char* name, int prop_id); + +/* display image within window (highgui windows remember their content) */ +CVAPI(void) cvShowImage( const char* name, const CvArr* image ); + +/* resize/move window */ +CVAPI(void) cvResizeWindow( const char* name, int width, int height ); +CVAPI(void) cvMoveWindow( const char* name, int x, int y ); + + +/* destroy window and all the trackers associated with it */ +CVAPI(void) cvDestroyWindow( const char* name ); + +CVAPI(void) cvDestroyAllWindows(void); + +/* get native window handle (HWND in case of Win32 and Widget in case of X Window) */ +CVAPI(void*) cvGetWindowHandle( const char* name ); + +/* get name of highgui window given its native handle */ +CVAPI(const char*) cvGetWindowName( void* window_handle ); + + +typedef void (CV_CDECL *CvTrackbarCallback)(int pos); + +/* create trackbar and display it on top of given window, set callback */ +CVAPI(int) cvCreateTrackbar( const char* trackbar_name, const char* window_name, + int* value, int count, CvTrackbarCallback on_change CV_DEFAULT(NULL)); + +typedef void (CV_CDECL *CvTrackbarCallback2)(int pos, void* userdata); + +CVAPI(int) cvCreateTrackbar2( const char* trackbar_name, const char* window_name, + int* value, int count, CvTrackbarCallback2 on_change, + void* userdata CV_DEFAULT(0)); + +/* retrieve or set trackbar position */ +CVAPI(int) cvGetTrackbarPos( const char* trackbar_name, const char* window_name ); +CVAPI(void) cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos ); + +enum +{ + CV_EVENT_MOUSEMOVE =0, + CV_EVENT_LBUTTONDOWN =1, + CV_EVENT_RBUTTONDOWN =2, + CV_EVENT_MBUTTONDOWN =3, + CV_EVENT_LBUTTONUP =4, + CV_EVENT_RBUTTONUP =5, + CV_EVENT_MBUTTONUP =6, + CV_EVENT_LBUTTONDBLCLK =7, + CV_EVENT_RBUTTONDBLCLK =8, + CV_EVENT_MBUTTONDBLCLK =9 +}; + +enum +{ + CV_EVENT_FLAG_LBUTTON =1, + CV_EVENT_FLAG_RBUTTON =2, + CV_EVENT_FLAG_MBUTTON =4, + CV_EVENT_FLAG_CTRLKEY =8, + CV_EVENT_FLAG_SHIFTKEY =16, + CV_EVENT_FLAG_ALTKEY =32 +}; + +typedef void (CV_CDECL *CvMouseCallback )(int event, int x, int y, int flags, void* param); + +/* assign callback for mouse events */ +CVAPI(void) cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, + void* param CV_DEFAULT(NULL)); + +enum +{ +/* 8bit, color or not */ + CV_LOAD_IMAGE_UNCHANGED =-1, +/* 8bit, gray */ + CV_LOAD_IMAGE_GRAYSCALE =0, +/* ?, color */ + CV_LOAD_IMAGE_COLOR =1, +/* any depth, ? */ + CV_LOAD_IMAGE_ANYDEPTH =2, +/* ?, any color */ + CV_LOAD_IMAGE_ANYCOLOR =4 +}; + +/* load image from file + iscolor can be a combination of above flags where CV_LOAD_IMAGE_UNCHANGED + overrides the other flags + using CV_LOAD_IMAGE_ANYCOLOR alone is equivalent to CV_LOAD_IMAGE_UNCHANGED + unless CV_LOAD_IMAGE_ANYDEPTH is specified images are converted to 8bit +*/ +CVAPI(IplImage*) cvLoadImage( const char* filename, int iscolor CV_DEFAULT(CV_LOAD_IMAGE_COLOR)); +CVAPI(CvMat*) cvLoadImageM( const char* filename, int iscolor CV_DEFAULT(CV_LOAD_IMAGE_COLOR)); + +enum +{ + CV_IMWRITE_JPEG_QUALITY =1, + CV_IMWRITE_PNG_COMPRESSION =16, + CV_IMWRITE_PNG_STRATEGY =17, + CV_IMWRITE_PNG_STRATEGY_DEFAULT =0, + CV_IMWRITE_PNG_STRATEGY_FILTERED =1, + CV_IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY =2, + CV_IMWRITE_PNG_STRATEGY_RLE =3, + CV_IMWRITE_PNG_STRATEGY_FIXED =4, + CV_IMWRITE_PXM_BINARY =32 +}; + +/* save image to file */ +CVAPI(int) cvSaveImage( const char* filename, const CvArr* image, + const int* params CV_DEFAULT(0) ); + +/* decode image stored in the buffer */ +CVAPI(IplImage*) cvDecodeImage( const CvMat* buf, int iscolor CV_DEFAULT(CV_LOAD_IMAGE_COLOR)); +CVAPI(CvMat*) cvDecodeImageM( const CvMat* buf, int iscolor CV_DEFAULT(CV_LOAD_IMAGE_COLOR)); + +/* encode image and store the result as a byte vector (single-row 8uC1 matrix) */ +CVAPI(CvMat*) cvEncodeImage( const char* ext, const CvArr* image, + const int* params CV_DEFAULT(0) ); + +enum +{ + CV_CVTIMG_FLIP =1, + CV_CVTIMG_SWAP_RB =2 +}; + +/* utility function: convert one image to another with optional vertical flip */ +CVAPI(void) cvConvertImage( const CvArr* src, CvArr* dst, int flags CV_DEFAULT(0)); + +/* wait for key event infinitely (delay<=0) or for "delay" milliseconds */ +CVAPI(int) cvWaitKey(int delay CV_DEFAULT(0)); + +// OpenGL support + +typedef void (CV_CDECL *CvOpenGlDrawCallback)(void* userdata); +CVAPI(void) cvSetOpenGlDrawCallback(const char* window_name, CvOpenGlDrawCallback callback, void* userdata CV_DEFAULT(NULL)); + +CVAPI(void) cvSetOpenGlContext(const char* window_name); +CVAPI(void) cvUpdateWindow(const char* window_name); + + +/****************************************************************************************\ +* Working with Video Files and Cameras * +\****************************************************************************************/ + +/* "black box" capture structure */ +typedef struct CvCapture CvCapture; + +/* start capturing frames from video file */ +CVAPI(CvCapture*) cvCreateFileCapture( const char* filename ); + +enum +{ + CV_CAP_ANY =0, // autodetect + + CV_CAP_MIL =100, // MIL proprietary drivers + + CV_CAP_VFW =200, // platform native + CV_CAP_V4L =200, + CV_CAP_V4L2 =200, + + CV_CAP_FIREWARE =300, // IEEE 1394 drivers + CV_CAP_FIREWIRE =300, + CV_CAP_IEEE1394 =300, + CV_CAP_DC1394 =300, + CV_CAP_CMU1394 =300, + + CV_CAP_STEREO =400, // TYZX proprietary drivers + CV_CAP_TYZX =400, + CV_TYZX_LEFT =400, + CV_TYZX_RIGHT =401, + CV_TYZX_COLOR =402, + CV_TYZX_Z =403, + + CV_CAP_QT =500, // QuickTime + + CV_CAP_UNICAP =600, // Unicap drivers + + CV_CAP_DSHOW =700, // DirectShow (via videoInput) + + CV_CAP_PVAPI =800, // PvAPI, Prosilica GigE SDK + + CV_CAP_OPENNI =900, // OpenNI (for Kinect) + CV_CAP_OPENNI_ASUS =910, // OpenNI (for Asus Xtion) + + CV_CAP_ANDROID =1000, // Android + + CV_CAP_XIAPI =1100, // XIMEA Camera API + + CV_CAP_AVFOUNDATION = 1200 // AVFoundation framework for iOS (OS X Lion will have the same API) +}; + +/* start capturing frames from camera: index = camera_index + domain_offset (CV_CAP_*) */ +CVAPI(CvCapture*) cvCreateCameraCapture( int index ); + +/* grab a frame, return 1 on success, 0 on fail. + this function is thought to be fast */ +CVAPI(int) cvGrabFrame( CvCapture* capture ); + +/* get the frame grabbed with cvGrabFrame(..) + This function may apply some frame processing like + frame decompression, flipping etc. + !!!DO NOT RELEASE or MODIFY the retrieved frame!!! */ +CVAPI(IplImage*) cvRetrieveFrame( CvCapture* capture, int streamIdx CV_DEFAULT(0) ); + +/* Just a combination of cvGrabFrame and cvRetrieveFrame + !!!DO NOT RELEASE or MODIFY the retrieved frame!!! */ +CVAPI(IplImage*) cvQueryFrame( CvCapture* capture ); + +/* stop capturing/reading and free resources */ +CVAPI(void) cvReleaseCapture( CvCapture** capture ); + +enum +{ + // modes of the controlling registers (can be: auto, manual, auto single push, absolute Latter allowed with any other mode) + // every feature can have only one mode turned on at a time + CV_CAP_PROP_DC1394_OFF = -4, //turn the feature off (not controlled manually nor automatically) + CV_CAP_PROP_DC1394_MODE_MANUAL = -3, //set automatically when a value of the feature is set by the user + CV_CAP_PROP_DC1394_MODE_AUTO = -2, + CV_CAP_PROP_DC1394_MODE_ONE_PUSH_AUTO = -1, + CV_CAP_PROP_POS_MSEC =0, + CV_CAP_PROP_POS_FRAMES =1, + CV_CAP_PROP_POS_AVI_RATIO =2, + CV_CAP_PROP_FRAME_WIDTH =3, + CV_CAP_PROP_FRAME_HEIGHT =4, + CV_CAP_PROP_FPS =5, + CV_CAP_PROP_FOURCC =6, + CV_CAP_PROP_FRAME_COUNT =7, + CV_CAP_PROP_FORMAT =8, + CV_CAP_PROP_MODE =9, + CV_CAP_PROP_BRIGHTNESS =10, + CV_CAP_PROP_CONTRAST =11, + CV_CAP_PROP_SATURATION =12, + CV_CAP_PROP_HUE =13, + CV_CAP_PROP_GAIN =14, + CV_CAP_PROP_EXPOSURE =15, + CV_CAP_PROP_CONVERT_RGB =16, + CV_CAP_PROP_WHITE_BALANCE_BLUE_U =17, + CV_CAP_PROP_RECTIFICATION =18, + CV_CAP_PROP_MONOCROME =19, + CV_CAP_PROP_SHARPNESS =20, + CV_CAP_PROP_AUTO_EXPOSURE =21, // exposure control done by camera, + // user can adjust refernce level + // using this feature + CV_CAP_PROP_GAMMA =22, + CV_CAP_PROP_TEMPERATURE =23, + CV_CAP_PROP_TRIGGER =24, + CV_CAP_PROP_TRIGGER_DELAY =25, + CV_CAP_PROP_WHITE_BALANCE_RED_V =26, + CV_CAP_PROP_ZOOM =27, + CV_CAP_PROP_FOCUS =28, + CV_CAP_PROP_GUID =29, + CV_CAP_PROP_ISO_SPEED =30, + CV_CAP_PROP_MAX_DC1394 =31, + CV_CAP_PROP_BACKLIGHT =32, + CV_CAP_PROP_PAN =33, + CV_CAP_PROP_TILT =34, + CV_CAP_PROP_ROLL =35, + CV_CAP_PROP_IRIS =36, + CV_CAP_PROP_SETTINGS =37, + + CV_CAP_PROP_AUTOGRAB =1024, // property for highgui class CvCapture_Android only + CV_CAP_PROP_SUPPORTED_PREVIEW_SIZES_STRING=1025, // readonly, tricky property, returns cpnst char* indeed + CV_CAP_PROP_PREVIEW_FORMAT=1026, // readonly, tricky property, returns cpnst char* indeed + + // OpenNI map generators + CV_CAP_OPENNI_DEPTH_GENERATOR = 1 << 31, + CV_CAP_OPENNI_IMAGE_GENERATOR = 1 << 30, + CV_CAP_OPENNI_GENERATORS_MASK = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_OPENNI_IMAGE_GENERATOR, + + // Properties of cameras available through OpenNI interfaces + CV_CAP_PROP_OPENNI_OUTPUT_MODE = 100, + CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH = 101, // in mm + CV_CAP_PROP_OPENNI_BASELINE = 102, // in mm + CV_CAP_PROP_OPENNI_FOCAL_LENGTH = 103, // in pixels + CV_CAP_PROP_OPENNI_REGISTRATION = 104, // flag + CV_CAP_PROP_OPENNI_REGISTRATION_ON = CV_CAP_PROP_OPENNI_REGISTRATION, // flag that synchronizes the remapping depth map to image map + // by changing depth generator's view point (if the flag is "on") or + // sets this view point to its normal one (if the flag is "off"). + CV_CAP_PROP_OPENNI_APPROX_FRAME_SYNC = 105, + CV_CAP_PROP_OPENNI_MAX_BUFFER_SIZE = 106, + CV_CAP_PROP_OPENNI_CIRCLE_BUFFER = 107, + CV_CAP_PROP_OPENNI_MAX_TIME_DURATION = 108, + + CV_CAP_PROP_OPENNI_GENERATOR_PRESENT = 109, + + CV_CAP_OPENNI_IMAGE_GENERATOR_PRESENT = CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_PROP_OPENNI_GENERATOR_PRESENT, + CV_CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE = CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_PROP_OPENNI_OUTPUT_MODE, + CV_CAP_OPENNI_DEPTH_GENERATOR_BASELINE = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_BASELINE, + CV_CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_FOCAL_LENGTH, + CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_REGISTRATION, + CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION_ON = CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION, + + // Properties of cameras available through GStreamer interface + CV_CAP_GSTREAMER_QUEUE_LENGTH = 200, // default is 1 + CV_CAP_PROP_PVAPI_MULTICASTIP = 300, // ip for anable multicast master mode. 0 for disable multicast + + // Properties of cameras available through XIMEA SDK interface + CV_CAP_PROP_XI_DOWNSAMPLING = 400, // Change image resolution by binning or skipping. + CV_CAP_PROP_XI_DATA_FORMAT = 401, // Output data format. + CV_CAP_PROP_XI_OFFSET_X = 402, // Horizontal offset from the origin to the area of interest (in pixels). + CV_CAP_PROP_XI_OFFSET_Y = 403, // Vertical offset from the origin to the area of interest (in pixels). + CV_CAP_PROP_XI_TRG_SOURCE = 404, // Defines source of trigger. + CV_CAP_PROP_XI_TRG_SOFTWARE = 405, // Generates an internal trigger. PRM_TRG_SOURCE must be set to TRG_SOFTWARE. + CV_CAP_PROP_XI_GPI_SELECTOR = 406, // Selects general purpose input + CV_CAP_PROP_XI_GPI_MODE = 407, // Set general purpose input mode + CV_CAP_PROP_XI_GPI_LEVEL = 408, // Get general purpose level + CV_CAP_PROP_XI_GPO_SELECTOR = 409, // Selects general purpose output + CV_CAP_PROP_XI_GPO_MODE = 410, // Set general purpose output mode + CV_CAP_PROP_XI_LED_SELECTOR = 411, // Selects camera signalling LED + CV_CAP_PROP_XI_LED_MODE = 412, // Define camera signalling LED functionality + CV_CAP_PROP_XI_MANUAL_WB = 413, // Calculates White Balance(must be called during acquisition) + CV_CAP_PROP_XI_AUTO_WB = 414, // Automatic white balance + CV_CAP_PROP_XI_AEAG = 415, // Automatic exposure/gain + CV_CAP_PROP_XI_EXP_PRIORITY = 416, // Exposure priority (0.5 - exposure 50%, gain 50%). + CV_CAP_PROP_XI_AE_MAX_LIMIT = 417, // Maximum limit of exposure in AEAG procedure + CV_CAP_PROP_XI_AG_MAX_LIMIT = 418, // Maximum limit of gain in AEAG procedure + CV_CAP_PROP_XI_AEAG_LEVEL = 419, // Average intensity of output signal AEAG should achieve(in %) + CV_CAP_PROP_XI_TIMEOUT = 420, // Image capture timeout in milliseconds + + // Properties for Android cameras + CV_CAP_PROP_ANDROID_FLASH_MODE = 8001, + CV_CAP_PROP_ANDROID_FOCUS_MODE = 8002, + CV_CAP_PROP_ANDROID_WHITE_BALANCE = 8003, + CV_CAP_PROP_ANDROID_ANTIBANDING = 8004, + CV_CAP_PROP_ANDROID_FOCAL_LENGTH = 8005, + CV_CAP_PROP_ANDROID_FOCUS_DISTANCE_NEAR = 8006, + CV_CAP_PROP_ANDROID_FOCUS_DISTANCE_OPTIMAL = 8007, + CV_CAP_PROP_ANDROID_FOCUS_DISTANCE_FAR = 8008, + + // Properties of cameras available through AVFOUNDATION interface + CV_CAP_PROP_IOS_DEVICE_FOCUS = 9001, + CV_CAP_PROP_IOS_DEVICE_EXPOSURE = 9002, + CV_CAP_PROP_IOS_DEVICE_FLASH = 9003, + CV_CAP_PROP_IOS_DEVICE_WHITEBALANCE = 9004, + CV_CAP_PROP_IOS_DEVICE_TORCH = 9005 +}; + +enum +{ + // Data given from depth generator. + CV_CAP_OPENNI_DEPTH_MAP = 0, // Depth values in mm (CV_16UC1) + CV_CAP_OPENNI_POINT_CLOUD_MAP = 1, // XYZ in meters (CV_32FC3) + CV_CAP_OPENNI_DISPARITY_MAP = 2, // Disparity in pixels (CV_8UC1) + CV_CAP_OPENNI_DISPARITY_MAP_32F = 3, // Disparity in pixels (CV_32FC1) + CV_CAP_OPENNI_VALID_DEPTH_MASK = 4, // CV_8UC1 + + // Data given from RGB image generator. + CV_CAP_OPENNI_BGR_IMAGE = 5, + CV_CAP_OPENNI_GRAY_IMAGE = 6 +}; + +// Supported output modes of OpenNI image generator +enum +{ + CV_CAP_OPENNI_VGA_30HZ = 0, + CV_CAP_OPENNI_SXGA_15HZ = 1, + CV_CAP_OPENNI_SXGA_30HZ = 2 +}; + +//supported by Android camera output formats +enum +{ + CV_CAP_ANDROID_COLOR_FRAME_BGR = 0, //BGR + CV_CAP_ANDROID_COLOR_FRAME = CV_CAP_ANDROID_COLOR_FRAME_BGR, + CV_CAP_ANDROID_GREY_FRAME = 1, //Y + CV_CAP_ANDROID_COLOR_FRAME_RGB = 2, + CV_CAP_ANDROID_COLOR_FRAME_BGRA = 3, + CV_CAP_ANDROID_COLOR_FRAME_RGBA = 4 +}; + +// supported Android camera flash modes +enum { + CV_CAP_ANDROID_FLASH_MODE_AUTO = 0, + CV_CAP_ANDROID_FLASH_MODE_OFF, + CV_CAP_ANDROID_FLASH_MODE_ON, + CV_CAP_ANDROID_FLASH_MODE_RED_EYE, + CV_CAP_ANDROID_FLASH_MODE_TORCH +}; + +// supported Android camera focus modes +enum { + CV_CAP_ANDROID_FOCUS_MODE_AUTO = 0, + CV_CAP_ANDROID_FOCUS_MODE_CONTINUOUS_VIDEO, + CV_CAP_ANDROID_FOCUS_MODE_EDOF, + CV_CAP_ANDROID_FOCUS_MODE_FIXED, + CV_CAP_ANDROID_FOCUS_MODE_INFINITY, + CV_CAP_ANDROID_FOCUS_MODE_MACRO +}; + +// supported Android camera white balance modes +enum { + CV_CAP_ANDROID_WHITE_BALANCE_AUTO = 0, + CV_CAP_ANDROID_WHITE_BALANCE_CLOUDY_DAYLIGHT, + CV_CAP_ANDROID_WHITE_BALANCE_DAYLIGHT, + CV_CAP_ANDROID_WHITE_BALANCE_FLUORESCENT, + CV_CAP_ANDROID_WHITE_BALANCE_INCANDESCENT, + CV_CAP_ANDROID_WHITE_BALANCE_SHADE, + CV_CAP_ANDROID_WHITE_BALANCE_TWILIGHT, + CV_CAP_ANDROID_WHITE_BALANCE_WARM_FLUORESCENT +}; + +// supported Android camera antibanding modes +enum { + CV_CAP_ANDROID_ANTIBANDING_50HZ = 0, + CV_CAP_ANDROID_ANTIBANDING_60HZ, + CV_CAP_ANDROID_ANTIBANDING_AUTO, + CV_CAP_ANDROID_ANTIBANDING_OFF +}; + +/* retrieve or set capture properties */ +CVAPI(double) cvGetCaptureProperty( CvCapture* capture, int property_id ); +CVAPI(int) cvSetCaptureProperty( CvCapture* capture, int property_id, double value ); + +// Return the type of the capturer (eg, CV_CAP_V4W, CV_CAP_UNICAP), which is unknown if created with CV_CAP_ANY +CVAPI(int) cvGetCaptureDomain( CvCapture* capture); + +/* "black box" video file writer structure */ +typedef struct CvVideoWriter CvVideoWriter; + +CV_INLINE int CV_FOURCC(char c1, char c2, char c3, char c4) +{ + return (c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + ((c4 & 255) << 24); +} + +#define CV_FOURCC_PROMPT -1 /* Open Codec Selection Dialog (Windows only) */ +#define CV_FOURCC_DEFAULT CV_FOURCC('I', 'Y', 'U', 'V') /* Use default codec for specified filename (Linux only) */ + +/* initialize video file writer */ +CVAPI(CvVideoWriter*) cvCreateVideoWriter( const char* filename, int fourcc, + double fps, CvSize frame_size, + int is_color CV_DEFAULT(1)); + +//CVAPI(CvVideoWriter*) cvCreateImageSequenceWriter( const char* filename, +// int is_color CV_DEFAULT(1)); + +/* write frame to video file */ +CVAPI(int) cvWriteFrame( CvVideoWriter* writer, const IplImage* image ); + +/* close video file writer */ +CVAPI(void) cvReleaseVideoWriter( CvVideoWriter** writer ); + +/****************************************************************************************\ +* Obsolete functions/synonyms * +\****************************************************************************************/ + +#define cvCaptureFromFile cvCreateFileCapture +#define cvCaptureFromCAM cvCreateCameraCapture +#define cvCaptureFromAVI cvCaptureFromFile +#define cvCreateAVIWriter cvCreateVideoWriter +#define cvWriteToAVI cvWriteFrame +#define cvAddSearchPath(path) +#define cvvInitSystem cvInitSystem +#define cvvNamedWindow cvNamedWindow +#define cvvShowImage cvShowImage +#define cvvResizeWindow cvResizeWindow +#define cvvDestroyWindow cvDestroyWindow +#define cvvCreateTrackbar cvCreateTrackbar +#define cvvLoadImage(name) cvLoadImage((name),1) +#define cvvSaveImage cvSaveImage +#define cvvAddSearchPath cvAddSearchPath +#define cvvWaitKey(name) cvWaitKey(0) +#define cvvWaitKeyEx(name,delay) cvWaitKey(delay) +#define cvvConvertImage cvConvertImage +#define HG_AUTOSIZE CV_WINDOW_AUTOSIZE +#define set_preprocess_func cvSetPreprocessFuncWin32 +#define set_postprocess_func cvSetPostprocessFuncWin32 + +#if defined WIN32 || defined _WIN32 + +CVAPI(void) cvSetPreprocessFuncWin32_(const void* callback); +CVAPI(void) cvSetPostprocessFuncWin32_(const void* callback); +#define cvSetPreprocessFuncWin32(callback) cvSetPreprocessFuncWin32_((const void*)(callback)) +#define cvSetPostprocessFuncWin32(callback) cvSetPostprocessFuncWin32_((const void*)(callback)) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/highgui/perf/perf_input.cpp b/highgui/perf/perf_input.cpp new file mode 100644 index 0000000..4215895 --- /dev/null +++ b/highgui/perf/perf_input.cpp @@ -0,0 +1,27 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef std::tr1::tuple VideoCapture_Reading_t; +typedef perf::TestBaseWithParam VideoCapture_Reading; + +PERF_TEST_P(VideoCapture_Reading, ReadFile, + testing::Combine( testing::Values( "highgui/video/big_buck_bunny.avi", + "highgui/video/big_buck_bunny.mov", + "highgui/video/big_buck_bunny.mp4", + "highgui/video/big_buck_bunny.mpg", + "highgui/video/big_buck_bunny.wmv" ), + testing::Values(true, true, true, true, true) )) +{ + string filename = getDataPath(get<0>(GetParam())); + + VideoCapture cap; + + TEST_CYCLE() cap.open(filename); + + SANITY_CHECK(cap.isOpened()); +} diff --git a/highgui/perf/perf_main.cpp b/highgui/perf/perf_main.cpp new file mode 100644 index 0000000..ebe94ab --- /dev/null +++ b/highgui/perf/perf_main.cpp @@ -0,0 +1,3 @@ +#include "perf_precomp.hpp" + +CV_PERF_TEST_MAIN(highgui) diff --git a/highgui/perf/perf_output.cpp b/highgui/perf/perf_output.cpp new file mode 100644 index 0000000..e7ddaa6 --- /dev/null +++ b/highgui/perf/perf_output.cpp @@ -0,0 +1,29 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef std::tr1::tuple VideoWriter_Writing_t; +typedef perf::TestBaseWithParam VideoWriter_Writing; + +PERF_TEST_P(VideoWriter_Writing, WriteFrame, + testing::Combine( testing::Values( "python/images/QCIF_00.bmp", + "python/images/QCIF_01.bmp", + "python/images/QCIF_02.bmp", + "python/images/QCIF_03.bmp", + "python/images/QCIF_04.bmp", + "python/images/QCIF_05.bmp" ), + testing::Bool())) +{ + string filename = getDataPath(get<0>(GetParam())); + bool isColor = get<1>(GetParam()); + + VideoWriter writer("perf_writer.avi", CV_FOURCC('X', 'V', 'I', 'D'), 25, cv::Size(640, 480), isColor); + + TEST_CYCLE() { Mat image = imread(filename, 1); writer << image; } + + SANITY_CHECK(writer.isOpened()); +} diff --git a/highgui/perf/perf_precomp.cpp b/highgui/perf/perf_precomp.cpp new file mode 100644 index 0000000..8552ac3 --- /dev/null +++ b/highgui/perf/perf_precomp.cpp @@ -0,0 +1 @@ +#include "perf_precomp.hpp" diff --git a/highgui/perf/perf_precomp.hpp b/highgui/perf/perf_precomp.hpp new file mode 100644 index 0000000..f7fb98d --- /dev/null +++ b/highgui/perf/perf_precomp.hpp @@ -0,0 +1,16 @@ +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wmissing-declarations" +# pragma GCC diagnostic ignored "-Wmissing-prototypes" //OSX +#endif + +#ifndef __OPENCV_PERF_PRECOMP_HPP__ +#define __OPENCV_PERF_PRECOMP_HPP__ + +#include "opencv2/ts/ts.hpp" +#include "opencv2/highgui/highgui.hpp" + +#ifdef GTEST_CREATE_SHARED_LIBRARY +#error no modules except ts should have GTEST_CREATE_SHARED_LIBRARY defined +#endif + +#endif diff --git a/highgui/src/bitstrm.cpp b/highgui/src/bitstrm.cpp new file mode 100644 index 0000000..8e92f8a --- /dev/null +++ b/highgui/src/bitstrm.cpp @@ -0,0 +1,582 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include "bitstrm.hpp" + +namespace cv +{ + +const int BS_DEF_BLOCK_SIZE = 1<<15; + +bool bsIsBigEndian( void ) +{ + return (((const int*)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0; +} + +///////////////////////// RBaseStream //////////////////////////// + +bool RBaseStream::isOpened() +{ + return m_is_opened; +} + +void RBaseStream::allocate() +{ + if( !m_allocated ) + { + m_start = new uchar[m_block_size]; + m_end = m_start + m_block_size; + m_current = m_end; + m_allocated = true; + } +} + + +RBaseStream::RBaseStream() +{ + m_start = m_end = m_current = 0; + m_file = 0; + m_block_size = BS_DEF_BLOCK_SIZE; + m_is_opened = false; + m_allocated = false; +} + + +RBaseStream::~RBaseStream() +{ + close(); // Close files + release(); // free buffers +} + + +void RBaseStream::readBlock() +{ + setPos( getPos() ); // normalize position + + if( m_file == 0 ) + { + if( m_block_pos == 0 && m_current < m_end ) + return; + throw RBS_THROW_EOS; + } + + fseek( m_file, m_block_pos, SEEK_SET ); + size_t readed = fread( m_start, 1, m_block_size, m_file ); + m_end = m_start + readed; + m_current = m_start; + + if( readed == 0 || m_current >= m_end ) + throw RBS_THROW_EOS; +} + + +bool RBaseStream::open( const string& filename ) +{ + close(); + allocate(); + + m_file = fopen( filename.c_str(), "rb" ); + if( m_file ) + { + m_is_opened = true; + setPos(0); + readBlock(); + } + return m_file != 0; +} + +bool RBaseStream::open( const Mat& buf ) +{ + close(); + if( buf.empty() ) + return false; + CV_Assert(buf.isContinuous()); + m_start = buf.data; + m_end = m_start + buf.cols*buf.rows*buf.elemSize(); + m_allocated = false; + m_is_opened = true; + setPos(0); + + return true; +} + +void RBaseStream::close() +{ + if( m_file ) + { + fclose( m_file ); + m_file = 0; + } + m_is_opened = false; + if( !m_allocated ) + m_start = m_end = m_current = 0; +} + + +void RBaseStream::release() +{ + if( m_allocated ) + delete[] m_start; + m_start = m_end = m_current = 0; + m_allocated = false; +} + + +void RBaseStream::setPos( int pos ) +{ + assert( isOpened() && pos >= 0 ); + + if( !m_file ) + { + m_current = m_start + pos; + m_block_pos = 0; + return; + } + + int offset = pos % m_block_size; + m_block_pos = pos - offset; + m_current = m_start + offset; +} + + +int RBaseStream::getPos() +{ + assert( isOpened() ); + return m_block_pos + (int)(m_current - m_start); +} + +void RBaseStream::skip( int bytes ) +{ + assert( bytes >= 0 ); + m_current += bytes; +} + +///////////////////////// RLByteStream //////////////////////////// + +RLByteStream::~RLByteStream() +{ +} + +int RLByteStream::getByte() +{ + uchar *current = m_current; + int val; + + if( current >= m_end ) + { + readBlock(); + current = m_current; + } + + val = *((uchar*)current); + m_current = current + 1; + return val; +} + + +int RLByteStream::getBytes( void* buffer, int count ) +{ + uchar* data = (uchar*)buffer; + int readed = 0; + assert( count >= 0 ); + + while( count > 0 ) + { + int l; + + for(;;) + { + l = (int)(m_end - m_current); + if( l > count ) l = count; + if( l > 0 ) break; + readBlock(); + } + memcpy( data, m_current, l ); + m_current += l; + data += l; + count -= l; + readed += l; + } + return readed; +} + + +//////////// RLByteStream & RMByteStream s //////////////// + +RMByteStream::~RMByteStream() +{ +} + + +int RLByteStream::getWord() +{ + uchar *current = m_current; + int val; + + if( current+1 < m_end ) + { + val = current[0] + (current[1] << 8); + m_current = current + 2; + } + else + { + val = getByte(); + val|= getByte() << 8; + } + return val; +} + + +int RLByteStream::getDWord() +{ + uchar *current = m_current; + int val; + + if( current+3 < m_end ) + { + val = current[0] + (current[1] << 8) + + (current[2] << 16) + (current[3] << 24); + m_current = current + 4; + } + else + { + val = getByte(); + val |= getByte() << 8; + val |= getByte() << 16; + val |= getByte() << 24; + } + return val; +} + + +int RMByteStream::getWord() +{ + uchar *current = m_current; + int val; + + if( current+1 < m_end ) + { + val = (current[0] << 8) + current[1]; + m_current = current + 2; + } + else + { + val = getByte() << 8; + val|= getByte(); + } + return val; +} + + +int RMByteStream::getDWord() +{ + uchar *current = m_current; + int val; + + if( current+3 < m_end ) + { + val = (current[0] << 24) + (current[1] << 16) + + (current[2] << 8) + current[3]; + m_current = current + 4; + } + else + { + val = getByte() << 24; + val |= getByte() << 16; + val |= getByte() << 8; + val |= getByte(); + } + return val; +} + +/////////////////////////// WBaseStream ///////////////////////////////// + +// WBaseStream - base class for output streams +WBaseStream::WBaseStream() +{ + m_start = m_end = m_current = 0; + m_file = 0; + m_block_size = BS_DEF_BLOCK_SIZE; + m_is_opened = false; + m_buf = 0; +} + + +WBaseStream::~WBaseStream() +{ + close(); + release(); +} + + +bool WBaseStream::isOpened() +{ + return m_is_opened; +} + + +void WBaseStream::allocate() +{ + if( !m_start ) + m_start = new uchar[m_block_size]; + + m_end = m_start + m_block_size; + m_current = m_start; +} + + +void WBaseStream::writeBlock() +{ + int size = (int)(m_current - m_start); + + assert( isOpened() ); + if( size == 0 ) + return; + + if( m_buf ) + { + size_t sz = m_buf->size(); + m_buf->resize( sz + size ); + memcpy( &(*m_buf)[sz], m_start, size ); + } + else + { + fwrite( m_start, 1, size, m_file ); + } + m_current = m_start; + m_block_pos += size; +} + + +bool WBaseStream::open( const string& filename ) +{ + close(); + allocate(); + + m_file = fopen( filename.c_str(), "wb" ); + if( m_file ) + { + m_is_opened = true; + m_block_pos = 0; + m_current = m_start; + } + return m_file != 0; +} + +bool WBaseStream::open( vector& buf ) +{ + close(); + allocate(); + + m_buf = &buf; + m_is_opened = true; + m_block_pos = 0; + m_current = m_start; + + return true; +} + +void WBaseStream::close() +{ + if( m_is_opened ) + writeBlock(); + if( m_file ) + { + fclose( m_file ); + m_file = 0; + } + m_buf = 0; + m_is_opened = false; +} + + +void WBaseStream::release() +{ + if( m_start ) + delete[] m_start; + m_start = m_end = m_current = 0; +} + + +int WBaseStream::getPos() +{ + assert( isOpened() ); + return m_block_pos + (int)(m_current - m_start); +} + + +///////////////////////////// WLByteStream /////////////////////////////////// + +WLByteStream::~WLByteStream() +{ +} + +void WLByteStream::putByte( int val ) +{ + *m_current++ = (uchar)val; + if( m_current >= m_end ) + writeBlock(); +} + + +void WLByteStream::putBytes( const void* buffer, int count ) +{ + uchar* data = (uchar*)buffer; + + assert( data && m_current && count >= 0 ); + + while( count ) + { + int l = (int)(m_end - m_current); + + if( l > count ) + l = count; + + if( l > 0 ) + { + memcpy( m_current, data, l ); + m_current += l; + data += l; + count -= l; + } + if( m_current == m_end ) + writeBlock(); + } +} + + +void WLByteStream::putWord( int val ) +{ + uchar *current = m_current; + + if( current+1 < m_end ) + { + current[0] = (uchar)val; + current[1] = (uchar)(val >> 8); + m_current = current + 2; + if( m_current == m_end ) + writeBlock(); + } + else + { + putByte(val); + putByte(val >> 8); + } +} + + +void WLByteStream::putDWord( int val ) +{ + uchar *current = m_current; + + if( current+3 < m_end ) + { + current[0] = (uchar)val; + current[1] = (uchar)(val >> 8); + current[2] = (uchar)(val >> 16); + current[3] = (uchar)(val >> 24); + m_current = current + 4; + if( m_current == m_end ) + writeBlock(); + } + else + { + putByte(val); + putByte(val >> 8); + putByte(val >> 16); + putByte(val >> 24); + } +} + + +///////////////////////////// WMByteStream /////////////////////////////////// + +WMByteStream::~WMByteStream() +{ +} + + +void WMByteStream::putWord( int val ) +{ + uchar *current = m_current; + + if( current+1 < m_end ) + { + current[0] = (uchar)(val >> 8); + current[1] = (uchar)val; + m_current = current + 2; + if( m_current == m_end ) + writeBlock(); + } + else + { + putByte(val >> 8); + putByte(val); + } +} + + +void WMByteStream::putDWord( int val ) +{ + uchar *current = m_current; + + if( current+3 < m_end ) + { + current[0] = (uchar)(val >> 24); + current[1] = (uchar)(val >> 16); + current[2] = (uchar)(val >> 8); + current[3] = (uchar)val; + m_current = current + 4; + if( m_current == m_end ) + writeBlock(); + } + else + { + putByte(val >> 24); + putByte(val >> 16); + putByte(val >> 8); + putByte(val); + } +} + +} diff --git a/highgui/src/bitstrm.hpp b/highgui/src/bitstrm.hpp new file mode 100644 index 0000000..f6ee779 --- /dev/null +++ b/highgui/src/bitstrm.hpp @@ -0,0 +1,182 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _BITSTRM_H_ +#define _BITSTRM_H_ + +#include + +namespace cv +{ + +enum +{ + RBS_THROW_EOS=-123, // exception code + RBS_THROW_FORB=-124, // exception code + RBS_HUFF_FORB=2047, // forrbidden huffman code "value" + RBS_BAD_HEADER=-125, // invalid header +}; + +typedef unsigned long ulong; + +// class RBaseStream - base class for other reading streams. +class RBaseStream +{ +public: + //methods + RBaseStream(); + virtual ~RBaseStream(); + + virtual bool open( const string& filename ); + virtual bool open( const Mat& buf ); + virtual void close(); + bool isOpened(); + void setPos( int pos ); + int getPos(); + void skip( int bytes ); + +protected: + + bool m_allocated; + uchar* m_start; + uchar* m_end; + uchar* m_current; + FILE* m_file; + int m_block_size; + int m_block_pos; + bool m_is_opened; + + virtual void readBlock(); + virtual void release(); + virtual void allocate(); +}; + + +// class RLByteStream - uchar-oriented stream. +// l in prefix means that the least significant uchar of a multi-uchar value goes first +class RLByteStream : public RBaseStream +{ +public: + virtual ~RLByteStream(); + + int getByte(); + int getBytes( void* buffer, int count ); + int getWord(); + int getDWord(); +}; + +// class RMBitStream - uchar-oriented stream. +// m in prefix means that the most significant uchar of a multi-uchar value go first +class RMByteStream : public RLByteStream +{ +public: + virtual ~RMByteStream(); + + int getWord(); + int getDWord(); +}; + +// WBaseStream - base class for output streams +class WBaseStream +{ +public: + //methods + WBaseStream(); + virtual ~WBaseStream(); + + virtual bool open( const string& filename ); + virtual bool open( vector& buf ); + virtual void close(); + bool isOpened(); + int getPos(); + +protected: + + uchar* m_start; + uchar* m_end; + uchar* m_current; + int m_block_size; + int m_block_pos; + FILE* m_file; + bool m_is_opened; + vector* m_buf; + + virtual void writeBlock(); + virtual void release(); + virtual void allocate(); +}; + + +// class WLByteStream - uchar-oriented stream. +// l in prefix means that the least significant uchar of a multi-byte value goes first +class WLByteStream : public WBaseStream +{ +public: + virtual ~WLByteStream(); + + void putByte( int val ); + void putBytes( const void* buffer, int count ); + void putWord( int val ); + void putDWord( int val ); +}; + + +// class WLByteStream - uchar-oriented stream. +// m in prefix means that the least significant uchar of a multi-byte value goes last +class WMByteStream : public WLByteStream +{ +public: + virtual ~WMByteStream(); + void putWord( int val ); + void putDWord( int val ); +}; + +inline unsigned BSWAP(unsigned v) +{ + return (v<<24)|((v&0xff00)<<8)|((v>>8)&0xff00)|((unsigned)v>>24); +} + +bool bsIsBigEndian( void ); + +} + +#endif/*_BITSTRM_H_*/ diff --git a/highgui/src/cap.cpp b/highgui/src/cap.cpp new file mode 100644 index 0000000..fdc40d1 --- /dev/null +++ b/highgui/src/cap.cpp @@ -0,0 +1,557 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#if defined _M_X64 && defined _MSC_VER && !defined CV_ICC +#pragma optimize("",off) +#pragma warning(disable: 4748) +#endif + +namespace cv +{ + +template<> void Ptr::delete_obj() +{ cvReleaseCapture(&obj); } + +template<> void Ptr::delete_obj() +{ cvReleaseVideoWriter(&obj); } + +} + +/************************* Reading AVIs & Camera data **************************/ + +CV_IMPL void cvReleaseCapture( CvCapture** pcapture ) +{ + if( pcapture && *pcapture ) + { + delete *pcapture; + *pcapture = 0; + } +} + +CV_IMPL IplImage* cvQueryFrame( CvCapture* capture ) +{ + if(!capture) + return 0; + if(!capture->grabFrame()) + return 0; + return capture->retrieveFrame(0); +} + + +CV_IMPL int cvGrabFrame( CvCapture* capture ) +{ + return capture ? capture->grabFrame() : 0; +} + +CV_IMPL IplImage* cvRetrieveFrame( CvCapture* capture, int idx ) +{ + return capture ? capture->retrieveFrame(idx) : 0; +} + +CV_IMPL double cvGetCaptureProperty( CvCapture* capture, int id ) +{ + return capture ? capture->getProperty(id) : 0; +} + +CV_IMPL int cvSetCaptureProperty( CvCapture* capture, int id, double value ) +{ + return capture ? capture->setProperty(id, value) : 0; +} + +CV_IMPL int cvGetCaptureDomain( CvCapture* capture) +{ + return capture ? capture->getCaptureDomain() : 0; +} + + +/** + * Camera dispatching method: index is the camera number. + * If given an index from 0 to 99, it tries to find the first + * API that can access a given camera index. + * Add multiples of 100 to select an API. + */ +CV_IMPL CvCapture * cvCreateCameraCapture (int index) +{ + int domains[] = + { +#ifdef HAVE_VIDEOINPUT + CV_CAP_DSHOW, +#endif +#if 1 + CV_CAP_IEEE1394, // identical to CV_CAP_DC1394 +#endif +#ifdef HAVE_TYZX + CV_CAP_STEREO, +#endif +#ifdef HAVE_PVAPI + CV_CAP_PVAPI, +#endif +#if 1 + CV_CAP_VFW, // identical to CV_CAP_V4L +#endif +#ifdef HAVE_MIL + CV_CAP_MIL, +#endif +#ifdef HAVE_QUICKTIME + CV_CAP_QT, +#endif +#ifdef HAVE_UNICAP + CV_CAP_UNICAP, +#endif +#ifdef HAVE_OPENNI + CV_CAP_OPENNI, +#endif +#ifdef HAVE_ANDROID_NATIVE_CAMERA + CV_CAP_ANDROID, +#endif +#ifdef HAVE_XIMEA + CV_CAP_XIAPI, +#endif +#ifdef HAVE_AVFOUNDATION + CV_CAP_AVFOUNDATION, +#endif + -1 + }; + + // interpret preferred interface (0 = autodetect) + int pref = (index / 100) * 100; + if (pref) + { + domains[0]=pref; + index %= 100; + domains[1]=-1; + } + + // try every possibly installed camera API + for (int i = 0; domains[i] >= 0; i++) + { +#if defined(HAVE_VIDEOINPUT) || \ + defined(HAVE_TYZX) || \ + defined(HAVE_VFW) || \ + defined(HAVE_LIBV4L) || \ + (defined(HAVE_CAMV4L) && defined(HAVE_CAMV4L2)) || \ + defined(HAVE_GSTREAMER) || \ + defined(HAVE_DC1394_2) || \ + defined(HAVE_DC1394) || \ + defined(HAVE_CMU1394) || \ + defined(HAVE_MIL) || \ + defined(HAVE_QUICKTIME) || \ + defined(HAVE_UNICAP) || \ + defined(HAVE_PVAPI) || \ + defined(HAVE_OPENNI) || \ + defined(HAVE_XIMEA) || \ + defined(HAVE_AVFOUNDATION) || \ + defined(HAVE_ANDROID_NATIVE_CAMERA) || \ + (0) + // local variable to memorize the captured device + CvCapture *capture; +#endif + + switch (domains[i]) + { +#ifdef HAVE_VIDEOINPUT + case CV_CAP_DSHOW: + capture = cvCreateCameraCapture_DShow (index); + if (capture) + return capture; + break; +#endif + +#ifdef HAVE_TYZX + case CV_CAP_STEREO: + capture = cvCreateCameraCapture_TYZX (index); + if (capture) + return capture; + break; +#endif + + case CV_CAP_VFW: +#ifdef HAVE_VFW + capture = cvCreateCameraCapture_VFW (index); + if (capture) + return capture; +#endif + +#if defined HAVE_LIBV4L || (defined (HAVE_CAMV4L) && defined (HAVE_CAMV4L2)) + capture = cvCreateCameraCapture_V4L (index); + if (capture) + return capture; +#endif + +#ifdef HAVE_GSTREAMER + capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L2, 0); + if (capture) + return capture; + capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L, 0); + if (capture) + return capture; +#endif + break; //CV_CAP_VFW + + case CV_CAP_FIREWIRE: +#ifdef HAVE_DC1394_2 + capture = cvCreateCameraCapture_DC1394_2 (index); + if (capture) + return capture; +#endif + +#ifdef HAVE_DC1394 + capture = cvCreateCameraCapture_DC1394 (index); + if (capture) + return capture; +#endif + +#ifdef HAVE_CMU1394 + capture = cvCreateCameraCapture_CMU (index); + if (capture) + return capture; +#endif + +#if defined(HAVE_GSTREAMER) && 0 + //Re-enable again when gstreamer 1394 support will land in the backend code + capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_1394, 0); + if (capture) + return capture; +#endif + break; //CV_CAP_FIREWIRE + +#ifdef HAVE_MIL + case CV_CAP_MIL: + capture = cvCreateCameraCapture_MIL (index); + if (capture) + return capture; + break; +#endif + +#ifdef HAVE_QUICKTIME + case CV_CAP_QT: + capture = cvCreateCameraCapture_QT (index); + if (capture) + return capture; + break; +#endif + +#ifdef HAVE_UNICAP + case CV_CAP_UNICAP: + capture = cvCreateCameraCapture_Unicap (index); + if (capture) + return capture; + break; +#endif + +#ifdef HAVE_PVAPI + case CV_CAP_PVAPI: + capture = cvCreateCameraCapture_PvAPI (index); + if (capture) + return capture; + break; +#endif + +#ifdef HAVE_OPENNI + case CV_CAP_OPENNI: + capture = cvCreateCameraCapture_OpenNI (index); + if (capture) + return capture; + break; +#endif + +#ifdef HAVE_ANDROID_NATIVE_CAMERA + case CV_CAP_ANDROID: + capture = cvCreateCameraCapture_Android (index); + if (capture) + return capture; + break; +#endif + +#ifdef HAVE_XIMEA + case CV_CAP_XIAPI: + capture = cvCreateCameraCapture_XIMEA (index); + if (capture) + return capture; + break; +#endif + +#ifdef HAVE_AVFOUNDATION + case CV_CAP_AVFOUNDATION: + capture = cvCreateCameraCapture_AVFoundation (index); + if (capture) + return capture; + break; +#endif + } + } + + // failed open a camera + return 0; +} + +/** + * Videoreader dispatching method: it tries to find the first + * API that can access a given filename. + */ +CV_IMPL CvCapture * cvCreateFileCapture (const char * filename) +{ + CvCapture * result = 0; + + if (! result) + result = cvCreateFileCapture_FFMPEG_proxy (filename); + +#ifdef HAVE_XINE + if (! result) + result = cvCreateFileCapture_XINE (filename); +#endif + +#ifdef HAVE_GSTREAMER + if (! result) + result = cvCreateCapture_GStreamer (CV_CAP_GSTREAMER_FILE, filename); +#endif + +#ifdef HAVE_QUICKTIME + if (! result) + result = cvCreateFileCapture_QT (filename); +#endif + +#ifdef HAVE_AVFOUNDATION + if (! result) + result = cvCreateFileCapture_AVFoundation (filename); +#endif + +#ifdef HAVE_OPENNI + if (! result) + result = cvCreateFileCapture_OpenNI (filename); +#endif + + if (! result) + result = cvCreateFileCapture_Images (filename); + + return result; +} + +/** + * Videowriter dispatching method: it tries to find the first + * API that can write a given stream. + */ +CV_IMPL CvVideoWriter* cvCreateVideoWriter( const char* filename, int fourcc, + double fps, CvSize frameSize, int is_color ) +{ + //CV_FUNCNAME( "cvCreateVideoWriter" ); + + CvVideoWriter *result = 0; + + if(!fourcc || !fps) + result = cvCreateVideoWriter_Images(filename); + + if(!result) + result = cvCreateVideoWriter_FFMPEG_proxy (filename, fourcc, fps, frameSize, is_color); + +/* #ifdef HAVE_XINE + if(!result) + result = cvCreateVideoWriter_XINE(filename, fourcc, fps, frameSize, is_color); + #endif +*/ +#ifdef HAVE_AVFOUNDATION + if (! result) + result = cvCreateVideoWriter_AVFoundation(filename, fourcc, fps, frameSize, is_color); +#endif + +#ifdef HAVE_QUICKTIME + if(!result) + result = cvCreateVideoWriter_QT(filename, fourcc, fps, frameSize, is_color); +#endif + +#ifdef HAVE_GSTREAMER + if (! result) + result = cvCreateVideoWriter_GStreamer(filename, fourcc, fps, frameSize, is_color); +#endif + + if(!result) + result = cvCreateVideoWriter_Images(filename); + + return result; +} + +CV_IMPL int cvWriteFrame( CvVideoWriter* writer, const IplImage* image ) +{ + + return writer ? writer->writeFrame(image) : 0; +} + +CV_IMPL void cvReleaseVideoWriter( CvVideoWriter** pwriter ) +{ + if( pwriter && *pwriter ) + { + delete *pwriter; + *pwriter = 0; + } +} + +namespace cv +{ + +VideoCapture::VideoCapture() +{} + +VideoCapture::VideoCapture(const string& filename) +{ + open(filename); +} + +VideoCapture::VideoCapture(int device) +{ + open(device); +} + +VideoCapture::~VideoCapture() +{ + cap.release(); +} + +bool VideoCapture::open(const string& filename) +{ + cap = cvCreateFileCapture(filename.c_str()); + return isOpened(); +} + +bool VideoCapture::open(int device) +{ + cap = cvCreateCameraCapture(device); + return isOpened(); +} + +bool VideoCapture::isOpened() const { return !cap.empty(); } + +void VideoCapture::release() +{ + cap.release(); +} + +bool VideoCapture::grab() +{ + return cvGrabFrame(cap) != 0; +} + +bool VideoCapture::retrieve(Mat& image, int channel) +{ + IplImage* _img = cvRetrieveFrame(cap, channel); + if( !_img ) + { + image.release(); + return false; + } + if(_img->origin == IPL_ORIGIN_TL) + image = Mat(_img); + else + { + Mat temp(_img); + flip(temp, image, 0); + } + return true; +} + +bool VideoCapture::read(Mat& image) +{ + if(grab()) + retrieve(image); + else + image.release(); + return !image.empty(); +} + +VideoCapture& VideoCapture::operator >> (Mat& image) +{ + read(image); + return *this; +} + +bool VideoCapture::set(int propId, double value) +{ + return cvSetCaptureProperty(cap, propId, value) != 0; +} + +double VideoCapture::get(int propId) +{ + return cvGetCaptureProperty(cap, propId); +} + +VideoWriter::VideoWriter() +{} + +VideoWriter::VideoWriter(const string& filename, int fourcc, double fps, Size frameSize, bool isColor) +{ + open(filename, fourcc, fps, frameSize, isColor); +} + +void VideoWriter::release() +{ + writer.release(); +} + +VideoWriter::~VideoWriter() +{ + release(); +} + +bool VideoWriter::open(const string& filename, int fourcc, double fps, Size frameSize, bool isColor) +{ + writer = cvCreateVideoWriter(filename.c_str(), fourcc, fps, frameSize, isColor); + return isOpened(); +} + +bool VideoWriter::isOpened() const +{ + return !writer.empty(); +} + +void VideoWriter::write(const Mat& image) +{ + IplImage _img = image; + cvWriteFrame(writer, &_img); +} + +VideoWriter& VideoWriter::operator << (const Mat& image) +{ + write(image); + return *this; +} + +} diff --git a/highgui/src/cap_android.cpp b/highgui/src/cap_android.cpp new file mode 100644 index 0000000..b67e56d --- /dev/null +++ b/highgui/src/cap_android.cpp @@ -0,0 +1,540 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#ifdef HAVE_ANDROID_NATIVE_CAMERA + +#include +#include +#include +#include + +#undef LOG_TAG +#undef LOGD +#undef LOGE +#undef LOGI +#define LOG_TAG "OpenCV::camera" +#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) + +class HighguiAndroidCameraActivity; + +class CvCapture_Android : public CvCapture +{ +public: + CvCapture_Android(int); + virtual ~CvCapture_Android(); + + virtual double getProperty(int propIdx); + virtual bool setProperty(int probIdx, double propVal); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int outputType); + virtual int getCaptureDomain() { return CV_CAP_ANDROID; } + + bool isOpened() const; + +protected: + struct OutputMap + { + public: + cv::Mat mat; + IplImage* getIplImagePtr(); + private: + IplImage iplHeader; + }; + + CameraActivity* m_activity; + + //raw from camera + int m_width; + int m_height; + cv::Mat m_frameYUV420; + cv::Mat m_frameYUV420next; + + enum YUVformat + { + noformat = 0, + yuv420sp, + yvu420sp, + yuvUnknown + }; + + YUVformat m_frameFormat; + + void setFrame(const void* buffer, int bufferSize); + +private: + bool m_isOpened; + bool m_CameraParamsChanged; + + //frames counter for statistics + int m_framesGrabbed; + + //cached converted frames + OutputMap m_frameGray; + OutputMap m_frameColor; + bool m_hasGray; + bool m_hasColor; + + enum CvCapture_Android_DataState { + CVCAPTURE_ANDROID_STATE_NO_FRAME=0, + CVCAPTURE_ANDROID_STATE_HAS_NEW_FRAME_UNGRABBED, + CVCAPTURE_ANDROID_STATE_HAS_FRAME_GRABBED + }; + volatile CvCapture_Android_DataState m_dataState; + + //synchronization + pthread_mutex_t m_nextFrameMutex; + pthread_cond_t m_nextFrameCond; + volatile bool m_waitingNextFrame; + volatile bool m_shouldAutoGrab; + + void prepareCacheForYUV(int width, int height); + bool convertYUV2Grey(int width, int height, const unsigned char* yuv, cv::Mat& resmat); + bool convertYUV2BGR(int width, int height, const unsigned char* yuv, cv::Mat& resmat, bool inRGBorder, bool withAlpha); + + friend class HighguiAndroidCameraActivity; +}; + + +class HighguiAndroidCameraActivity : public CameraActivity +{ +public: + HighguiAndroidCameraActivity(CvCapture_Android* capture) + { + m_capture = capture; + m_framesReceived = 0; + } + + virtual bool onFrameBuffer(void* buffer, int bufferSize) + { + if(isConnected() && buffer != 0 && bufferSize > 0) + { + m_framesReceived++; + if (m_capture->m_waitingNextFrame || m_capture->m_shouldAutoGrab) + { + pthread_mutex_lock(&m_capture->m_nextFrameMutex); + + m_capture->setFrame(buffer, bufferSize); + + pthread_cond_broadcast(&m_capture->m_nextFrameCond); + pthread_mutex_unlock(&m_capture->m_nextFrameMutex); + } + return true; + } + return false; + } + + void LogFramesRate() + { + LOGI("FRAMES received: %d grabbed: %d", m_framesReceived, m_capture->m_framesGrabbed); + } + +private: + CvCapture_Android* m_capture; + int m_framesReceived; +}; + +IplImage* CvCapture_Android::OutputMap::getIplImagePtr() +{ + if( mat.empty() ) + return 0; + + iplHeader = IplImage(mat); + return &iplHeader; +} + +CvCapture_Android::CvCapture_Android(int cameraId) +{ + //defaults + m_width = 0; + m_height = 0; + m_activity = 0; + m_isOpened = false; + // m_frameYUV420 = 0; + // m_frameYUV420next = 0; + m_hasGray = false; + m_hasColor = false; + m_dataState = CVCAPTURE_ANDROID_STATE_NO_FRAME; + m_waitingNextFrame = false; + m_shouldAutoGrab = false; + m_framesGrabbed = 0; + m_CameraParamsChanged = false; + m_frameFormat = noformat; + + //try connect to camera + m_activity = new HighguiAndroidCameraActivity(this); + + if (m_activity == 0) return; + + pthread_mutex_init(&m_nextFrameMutex, NULL); + pthread_cond_init (&m_nextFrameCond, NULL); + + CameraActivity::ErrorCode errcode = m_activity->connect(cameraId); + + if(errcode == CameraActivity::NO_ERROR) + m_isOpened = true; + else + { + LOGE("Native_camera returned opening error: %d", errcode); + delete m_activity; + m_activity = 0; + } +} + +bool CvCapture_Android::isOpened() const +{ + return m_isOpened; +} + +CvCapture_Android::~CvCapture_Android() +{ + if (m_activity) + { + ((HighguiAndroidCameraActivity*)m_activity)->LogFramesRate(); + + pthread_mutex_lock(&m_nextFrameMutex); + + // unsigned char *tmp1=m_frameYUV420; + // unsigned char *tmp2=m_frameYUV420next; + // m_frameYUV420 = 0; + // m_frameYUV420next = 0; + // delete tmp1; + // delete tmp2; + + m_dataState=CVCAPTURE_ANDROID_STATE_NO_FRAME; + pthread_cond_broadcast(&m_nextFrameCond); + + pthread_mutex_unlock(&m_nextFrameMutex); + + //m_activity->disconnect() will be automatically called inside destructor; + delete m_activity; + m_activity = 0; + + pthread_mutex_destroy(&m_nextFrameMutex); + pthread_cond_destroy(&m_nextFrameCond); + } +} + +double CvCapture_Android::getProperty( int propIdx ) +{ + switch ( propIdx ) + { + case CV_CAP_PROP_FRAME_WIDTH: + return (double)m_activity->getFrameWidth(); + case CV_CAP_PROP_FRAME_HEIGHT: + return (double)m_activity->getFrameHeight(); + case CV_CAP_PROP_SUPPORTED_PREVIEW_SIZES_STRING: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_SUPPORTED_PREVIEW_SIZES_STRING); + case CV_CAP_PROP_PREVIEW_FORMAT: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_PREVIEW_FORMAT_STRING); + case CV_CAP_PROP_FPS: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FPS); + case CV_CAP_PROP_EXPOSURE: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_EXPOSURE); + case CV_CAP_PROP_ANDROID_FLASH_MODE: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FLASH_MODE); + case CV_CAP_PROP_ANDROID_FOCUS_MODE: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FOCUS_MODE); + case CV_CAP_PROP_ANDROID_WHITE_BALANCE: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_WHITE_BALANCE); + case CV_CAP_PROP_ANDROID_ANTIBANDING: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_ANTIBANDING); + case CV_CAP_PROP_ANDROID_FOCAL_LENGTH: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FOCAL_LENGTH); + case CV_CAP_PROP_ANDROID_FOCUS_DISTANCE_NEAR: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_NEAR); + case CV_CAP_PROP_ANDROID_FOCUS_DISTANCE_OPTIMAL: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_OPTIMAL); + case CV_CAP_PROP_ANDROID_FOCUS_DISTANCE_FAR: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_FAR); + default: + CV_Error( CV_StsOutOfRange, "Failed attempt to GET unsupported camera property." ); + break; + } + return -1.0; +} + +bool CvCapture_Android::setProperty( int propIdx, double propValue ) +{ + bool res = false; + if( isOpened() ) + { + switch ( propIdx ) + { + case CV_CAP_PROP_FRAME_WIDTH: + m_activity->setProperty(ANDROID_CAMERA_PROPERTY_FRAMEWIDTH, propValue); + break; + case CV_CAP_PROP_FRAME_HEIGHT: + m_activity->setProperty(ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT, propValue); + break; + case CV_CAP_PROP_AUTOGRAB: + m_shouldAutoGrab=(propValue != 0); + break; + case CV_CAP_PROP_EXPOSURE: + m_activity->setProperty(ANDROID_CAMERA_PROPERTY_EXPOSURE, propValue); + break; + case CV_CAP_PROP_ANDROID_FLASH_MODE: + m_activity->setProperty(ANDROID_CAMERA_PROPERTY_FLASH_MODE, propValue); + break; + case CV_CAP_PROP_ANDROID_FOCUS_MODE: + m_activity->setProperty(ANDROID_CAMERA_PROPERTY_FOCUS_MODE, propValue); + break; + case CV_CAP_PROP_ANDROID_WHITE_BALANCE: + m_activity->setProperty(ANDROID_CAMERA_PROPERTY_WHITE_BALANCE, propValue); + break; + case CV_CAP_PROP_ANDROID_ANTIBANDING: + m_activity->setProperty(ANDROID_CAMERA_PROPERTY_ANTIBANDING, propValue); + break; + default: + CV_Error( CV_StsOutOfRange, "Failed attempt to SET unsupported camera property." ); + return false; + } + + if (propIdx != CV_CAP_PROP_AUTOGRAB) {// property for highgui class CvCapture_Android only + m_CameraParamsChanged = true; + } + res = true; + } + + return res; +} + +bool CvCapture_Android::grabFrame() +{ + if( !isOpened() ) { + LOGE("CvCapture_Android::grabFrame(): camera is not opened"); + return false; + } + + bool res=false; + pthread_mutex_lock(&m_nextFrameMutex); + if (m_CameraParamsChanged) + { + m_activity->applyProperties(); + m_CameraParamsChanged = false; + m_dataState= CVCAPTURE_ANDROID_STATE_NO_FRAME;//we will wait new frame + } + + if (m_dataState!=CVCAPTURE_ANDROID_STATE_HAS_NEW_FRAME_UNGRABBED) + { + m_waitingNextFrame = true; + pthread_cond_wait(&m_nextFrameCond, &m_nextFrameMutex); + } + + if (m_dataState == CVCAPTURE_ANDROID_STATE_HAS_NEW_FRAME_UNGRABBED) + { + //LOGD("CvCapture_Android::grabFrame: get new frame"); + //swap current and new frames + cv::swap(m_frameYUV420, m_frameYUV420next); + + //discard cached frames + m_hasGray = false; + m_hasColor = false; + + m_dataState=CVCAPTURE_ANDROID_STATE_HAS_FRAME_GRABBED; + m_framesGrabbed++; + + res=true; + } else { + LOGE("CvCapture_Android::grabFrame: NO new frame"); + } + + + int res_unlock=pthread_mutex_unlock(&m_nextFrameMutex); + if (res_unlock) { + LOGE("Error in CvCapture_Android::grabFrame: pthread_mutex_unlock returned %d --- probably, this object has been destroyed", res_unlock); + return false; + } + + return res; +} + +IplImage* CvCapture_Android::retrieveFrame( int outputType ) +{ + IplImage* image = NULL; + + cv::Mat m_frameYUV420_ref = m_frameYUV420; + unsigned char *current_frameYUV420=m_frameYUV420_ref.ptr(); + //Attention! all the operations in this function below should occupy less time than the period between two frames from camera + if (NULL != current_frameYUV420) + { + if (m_frameFormat == noformat) + { + union {double prop; const char* name;} u; + u.prop = getProperty(CV_CAP_PROP_PREVIEW_FORMAT); + if (0 == strcmp(u.name, "yuv420sp")) + m_frameFormat = yuv420sp; + else if (0 == strcmp(u.name, "yvu420sp")) + m_frameFormat = yvu420sp; + else + m_frameFormat = yuvUnknown; + } + + switch(outputType) + { + case CV_CAP_ANDROID_GREY_FRAME: + if (!m_hasGray) + if (!(m_hasGray = convertYUV2Grey(m_width, m_height, current_frameYUV420, m_frameGray.mat))) + return NULL; + image = m_frameGray.getIplImagePtr(); + break; + case CV_CAP_ANDROID_COLOR_FRAME_BGR: case CV_CAP_ANDROID_COLOR_FRAME_RGB: + if (!m_hasColor) + if (!(m_hasColor = convertYUV2BGR(m_width, m_height, current_frameYUV420, m_frameColor.mat, outputType == CV_CAP_ANDROID_COLOR_FRAME_RGB, false))) + return NULL; + image = m_frameColor.getIplImagePtr(); + break; + case CV_CAP_ANDROID_COLOR_FRAME_BGRA: case CV_CAP_ANDROID_COLOR_FRAME_RGBA: + if (!m_hasColor) + if (!(m_hasColor = convertYUV2BGR(m_width, m_height, current_frameYUV420, m_frameColor.mat, outputType == CV_CAP_ANDROID_COLOR_FRAME_RGBA, true))) + return NULL; + image = m_frameColor.getIplImagePtr(); + break; + default: + LOGE("Unsupported frame output format: %d", outputType); + CV_Error( CV_StsOutOfRange, "Output frame format is not supported." ); + image = NULL; + break; + } + } + return image; +} + +//Attention: this method should be called inside pthread_mutex_lock(m_nextFrameMutex) only +void CvCapture_Android::setFrame(const void* buffer, int bufferSize) +{ + int width = m_activity->getFrameWidth(); + int height = m_activity->getFrameHeight(); + int expectedSize = (width * height * 3) >> 1; + + if ( expectedSize != bufferSize) + { + LOGE("ERROR reading YUV buffer: width=%d, height=%d, size=%d, receivedSize=%d", width, height, expectedSize, bufferSize); + return; + } + + //allocate memory if needed + prepareCacheForYUV(width, height); + + //copy data + cv::Mat m_frameYUV420next_ref = m_frameYUV420next; + memcpy(m_frameYUV420next_ref.ptr(), buffer, bufferSize); + // LOGD("CvCapture_Android::setFrame -- memcpy is done"); + // ((HighguiAndroidCameraActivity*)m_activity)->LogFramesRate(); + + m_dataState = CVCAPTURE_ANDROID_STATE_HAS_NEW_FRAME_UNGRABBED; + m_waitingNextFrame = false;//set flag that no more frames required at this moment +} + +//Attention: this method should be called inside pthread_mutex_lock(m_nextFrameMutex) only +void CvCapture_Android::prepareCacheForYUV(int width, int height) +{ + if (width != m_width || height != m_height) + { + LOGD("CvCapture_Android::prepareCacheForYUV: Changing size of buffers: from width=%d height=%d to width=%d height=%d", m_width, m_height, width, height); + m_width = width; + m_height = height; + /* + unsigned char *tmp = m_frameYUV420next; + m_frameYUV420next = new unsigned char [width * height * 3 / 2]; + if (tmp != NULL) + { + delete[] tmp; + } + + tmp = m_frameYUV420; + m_frameYUV420 = new unsigned char [width * height * 3 / 2]; + if (tmp != NULL) + { + delete[] tmp; + }*/ + m_frameYUV420.create(height * 3 / 2, width, CV_8UC1); + m_frameYUV420next.create(height * 3 / 2, width, CV_8UC1); + } +} + +bool CvCapture_Android::convertYUV2Grey(int width, int height, const unsigned char* yuv, cv::Mat& resmat) +{ + if (yuv == 0) return false; + if (m_frameFormat != yuv420sp && m_frameFormat != yvu420sp) return false; +#define ALWAYS_COPY_GRAY 0 +#if ALWAYS_COPY_GRAY + resmat.create(height, width, CV_8UC1); + unsigned char* matBuff = resmat.ptr (0); + memcpy(matBuff, yuv, width * height); +#else + resmat = cv::Mat(height, width, CV_8UC1, (void*)yuv); +#endif + return !resmat.empty(); +} + +bool CvCapture_Android::convertYUV2BGR(int width, int height, const unsigned char* yuv, cv::Mat& resmat, bool inRGBorder, bool withAlpha) +{ + if (yuv == 0) return false; + if (m_frameFormat != yuv420sp && m_frameFormat != yvu420sp) return false; + + CV_Assert(width % 2 == 0 && height % 2 == 0); + + cv::Mat src(height*3/2, width, CV_8UC1, (void*)yuv); + + if (m_frameFormat == yuv420sp) + cv::cvtColor(src, resmat, inRGBorder ? CV_YUV420sp2RGB : CV_YUV420sp2BGR, withAlpha ? 4 : 3); + else if (m_frameFormat == yvu420sp) + cv::cvtColor(src, resmat, inRGBorder ? CV_YUV2RGB_NV21 : CV_YUV2BGR_NV12, withAlpha ? 4 : 3); + + return !resmat.empty(); +} + +CvCapture* cvCreateCameraCapture_Android( int cameraId ) +{ + CvCapture_Android* capture = new CvCapture_Android(cameraId); + + if( capture->isOpened() ) + return capture; + + delete capture; + return 0; +} + +#endif diff --git a/highgui/src/cap_avfoundation.mm b/highgui/src/cap_avfoundation.mm new file mode 100644 index 0000000..0241c0d --- /dev/null +++ b/highgui/src/cap_avfoundation.mm @@ -0,0 +1,1332 @@ +/* + * cap_avfoundation.mm + * For iOS video I/O + * by Xiaochao Yang on 06/15/11 modified from + * cap_qtkit.mm for Nicholas Butko for Mac OS version. + * Copyright 2011. 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. + * + */ + +#include "precomp.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include +#import +#import + + +//#import + +using namespace std; + +/********************** Declaration of class headers ************************/ + +/***************************************************************************** + * + * CaptureDelegate Declaration. + * + * CaptureDelegate is notified on a separate thread by the OS whenever there + * is a new frame. When "updateImage" is called from the main thread, it + * copies this new frame into an IplImage, but only if this frame has not + * been copied before. When "getOutput" is called from the main thread, + * it gives the last copied IplImage. + * + *****************************************************************************/ + +#define DISABLE_AUTO_RESTART 999 + +@interface CaptureDelegate : NSObject +{ + int newFrame; + CVImageBufferRef mCurrentImageBuffer; + char* imagedata; + IplImage* image; + char* bgr_imagedata; + IplImage* bgr_image; + IplImage* bgr_image_r90; + size_t currSize; +} + +- (void)captureOutput:(AVCaptureOutput *)captureOutput +didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer +fromConnection:(AVCaptureConnection *)connection; + + +- (int)updateImage; +- (IplImage*)getOutput; + +@end + +/***************************************************************************** + * + * CvCaptureCAM Declaration. + * + * CvCaptureCAM is the instantiation of a capture source for cameras. + * + *****************************************************************************/ + +class CvCaptureCAM : public CvCapture { + public: + CvCaptureCAM(int cameraNum = -1) ; + ~CvCaptureCAM(); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual IplImage* queryFrame(); + virtual double getProperty(int property_id); + virtual bool setProperty(int property_id, double value); + virtual int didStart(); + + private: + AVCaptureSession *mCaptureSession; + AVCaptureDeviceInput *mCaptureDeviceInput; + AVCaptureVideoDataOutput *mCaptureDecompressedVideoOutput; + AVCaptureDevice *mCaptureDevice; + CaptureDelegate *capture; + + int startCaptureDevice(int cameraNum); + void stopCaptureDevice(); + + void setWidthHeight(); + bool grabFrame(double timeOut); + + int camNum; + int width; + int height; + int settingWidth; + int settingHeight; + int started; + int disableAutoRestart; +}; + + +/***************************************************************************** + * + * CvCaptureFile Declaration. + * + * CvCaptureFile is the instantiation of a capture source for video files. + * + *****************************************************************************/ + +class CvCaptureFile : public CvCapture { + public: + + CvCaptureFile(const char* filename) ; + ~CvCaptureFile(); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual IplImage* queryFrame(); + virtual double getProperty(int property_id); + virtual bool setProperty(int property_id, double value); + virtual int didStart(); + + private: + + AVAssetReader *mMovieReader; + char* imagedata; + IplImage* image; + char* bgr_imagedata; + IplImage* bgr_image; + size_t currSize; + + IplImage* retrieveFramePixelBuffer(); + double getFPS(); + + int movieWidth; + int movieHeight; + double movieFPS; + double currentFPS; + double movieDuration; + int changedPos; + + int started; +}; + + +/***************************************************************************** + * + * CvCaptureFile Declaration. + * + * CvCaptureFile is the instantiation of a capture source for video files. + * + *****************************************************************************/ + +class CvVideoWriter_AVFoundation : public CvVideoWriter{ + public: + CvVideoWriter_AVFoundation(const char* filename, int fourcc, + double fps, CvSize frame_size, + int is_color=1); + ~CvVideoWriter_AVFoundation(); + bool writeFrame(const IplImage* image); + private: + IplImage* argbimage; + + AVAssetWriter *mMovieWriter; + AVAssetWriterInput* mMovieWriterInput; + AVAssetWriterInputPixelBufferAdaptor* mMovieWriterAdaptor; + + unsigned char* imagedata; + NSString* path; + NSString* codec; + NSString* fileType; + double movieFPS; + CvSize movieSize; + int movieColor; + unsigned long frameCount; +}; + + +/****************** Implementation of interface functions ********************/ + + +CvCapture* cvCreateFileCapture_AVFoundation(const char* filename) { + CvCaptureFile *retval = new CvCaptureFile(filename); + + if(retval->didStart()) + return retval; + delete retval; + return NULL; +} + +CvCapture* cvCreateCameraCapture_AVFoundation(int index ) { + + CvCapture* retval = new CvCaptureCAM(index); + if (!((CvCaptureCAM *)retval)->didStart()) + cvReleaseCapture(&retval); + return retval; + +} + +CvVideoWriter* cvCreateVideoWriter_AVFoundation(const char* filename, int fourcc, + double fps, CvSize frame_size, + int is_color) { + return new CvVideoWriter_AVFoundation(filename, fourcc, fps, frame_size,is_color); +} + +/********************** Implementation of Classes ****************************/ +/***************************************************************************** + * + * CvCaptureCAM Implementation. + * + * CvCaptureCAM is the instantiation of a capture source for cameras. + * + *****************************************************************************/ + +CvCaptureCAM::CvCaptureCAM(int cameraNum) { + mCaptureSession = nil; + mCaptureDeviceInput = nil; + mCaptureDecompressedVideoOutput = nil; + capture = nil; + + width = 0; + height = 0; + settingWidth = 0; + settingHeight = 0; + disableAutoRestart = 0; + + camNum = cameraNum; + + if (!startCaptureDevice(camNum)) { + cout << "Warning, camera failed to properly initialize!" << endl; + started = 0; + } else { + started = 1; + } + +} + +CvCaptureCAM::~CvCaptureCAM() { + stopCaptureDevice(); + //cout << "Cleaned up camera." << endl; +} + +int CvCaptureCAM::didStart() { + return started; +} + + +bool CvCaptureCAM::grabFrame() { + return grabFrame(5); +} + +bool CvCaptureCAM::grabFrame(double timeOut) { + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + double sleepTime = 0.005; + double total = 0; + + NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:sleepTime]; + while (![capture updateImage] && (total += sleepTime)<=timeOut && + [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode + beforeDate:loopUntil]) + loopUntil = [NSDate dateWithTimeIntervalSinceNow:sleepTime]; + + [localpool drain]; + + return total <= timeOut; +} + +IplImage* CvCaptureCAM::retrieveFrame(int) { + return [capture getOutput]; +} + +IplImage* CvCaptureCAM::queryFrame() { + while (!grabFrame()) { + cout << "WARNING: Couldn't grab new frame from camera!!!" << endl; + /* + cout << "Attempting to restart camera; set capture property DISABLE_AUTO_RESTART to disable." << endl; + stopCaptureDevice(); + startCaptureDevice(camNum); + */ + } + return retrieveFrame(0); +} + +void CvCaptureCAM::stopCaptureDevice() { + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + [mCaptureSession stopRunning]; + + [mCaptureSession release]; + [mCaptureDeviceInput release]; + + [mCaptureDecompressedVideoOutput release]; + [capture release]; + [localpool drain]; + +} + +int CvCaptureCAM::startCaptureDevice(int cameraNum) { + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + capture = [[CaptureDelegate alloc] init]; + + AVCaptureDevice *device; + NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + if ([devices count] == 0) { + cout << "AV Foundation didn't find any attached Video Input Devices!" << endl; + [localpool drain]; + return 0; + } + + if (cameraNum >= 0) { + camNum = cameraNum % [devices count]; + if (camNum != cameraNum) { + cout << "Warning: Max Camera Num is " << [devices count]-1 << "; Using camera " << camNum << endl; + } + device = [devices objectAtIndex:camNum]; + } else { + device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] ; + } + mCaptureDevice = device; + //int success; + NSError* error; + + if (device) { + + mCaptureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error] ; + mCaptureSession = [[AVCaptureSession alloc] init] ; + + /* + success = [mCaptureSession addInput:mCaptureDeviceInput]; + + if (!success) { + cout << "AV Foundation failed to start capture session with opened Capture Device" << endl; + [localpool drain]; + return 0; + } + */ + + mCaptureDecompressedVideoOutput = [[AVCaptureVideoDataOutput alloc] init]; + + dispatch_queue_t queue = dispatch_queue_create("cameraQueue", NULL); + [mCaptureDecompressedVideoOutput setSampleBufferDelegate:capture queue:queue]; + dispatch_release(queue); + + + NSDictionary *pixelBufferOptions ; + if (width > 0 && height > 0) { + pixelBufferOptions = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithDouble:1.0*width], (id)kCVPixelBufferWidthKey, + [NSNumber numberWithDouble:1.0*height], (id)kCVPixelBufferHeightKey, + [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], + (id)kCVPixelBufferPixelFormatTypeKey, + nil]; + } else { + pixelBufferOptions = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], + (id)kCVPixelBufferPixelFormatTypeKey, + nil]; + } + + //TODO: add new interface for setting fps and capturing resolution. + [mCaptureDecompressedVideoOutput setVideoSettings:pixelBufferOptions]; + mCaptureDecompressedVideoOutput.alwaysDiscardsLateVideoFrames = YES; + +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + mCaptureDecompressedVideoOutput.minFrameDuration = CMTimeMake(1, 30); +#endif + + //Slow. 1280*720 for iPhone4, iPod back camera. 640*480 for front camera + //mCaptureSession.sessionPreset = AVCaptureSessionPresetHigh; // fps ~= 5 slow for OpenCV + + mCaptureSession.sessionPreset = AVCaptureSessionPresetMedium; //480*360 + if (width == 0 ) width = 480; + if (height == 0 ) height = 360; + + [mCaptureSession addInput:mCaptureDeviceInput]; + [mCaptureSession addOutput:mCaptureDecompressedVideoOutput]; + + /* + // Does not work! This is the preferred way (hardware acceleration) to change pixel buffer orientation. + // I'm now using cvtranspose and cvflip instead, which takes cpu cycles. + AVCaptureConnection *connection = [[mCaptureDecompressedVideoOutput connections] objectAtIndex:0]; + if([connection isVideoOrientationSupported]) { + //NSLog(@"Setting pixel buffer orientation"); + connection.videoOrientation = AVCaptureVideoOrientationPortrait; + } + */ + + [mCaptureSession startRunning]; + + grabFrame(60); + [localpool drain]; + return 1; + } + + [localpool drain]; + return 0; +} + +void CvCaptureCAM::setWidthHeight() { + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + NSDictionary* pixelBufferOptions = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithDouble:1.0*width], (id)kCVPixelBufferWidthKey, + [NSNumber numberWithDouble:1.0*height], (id)kCVPixelBufferHeightKey, + [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], + (id)kCVPixelBufferPixelFormatTypeKey, + nil]; + + [mCaptureDecompressedVideoOutput setVideoSettings:pixelBufferOptions]; + grabFrame(60); + [localpool drain]; +} + +//added macros into headers in highgui_c.h +/* +#define CV_CAP_PROP_IOS_DEVICE_FOCUS 9001 +#define CV_CAP_PROP_IOS_DEVICE_EXPOSURE 9002 +#define CV_CAP_PROP_IOS_DEVICE_FLASH 9003 +#define CV_CAP_PROP_IOS_DEVICE_WHITEBALANCE 9004 +#define CV_CAP_PROP_IOS_DEVICE_TORCH 9005 +*/ + + +/* +// All available settings are taken from iOS API + +enum { + AVCaptureFlashModeOff = 0, + AVCaptureFlashModeOn = 1, + AVCaptureFlashModeAuto = 2 +}; +typedef NSInteger AVCaptureFlashMode; + +enum { + AVCaptureTorchModeOff = 0, + AVCaptureTorchModeOn = 1, + AVCaptureTorchModeAuto = 2 +}; +typedef NSInteger AVCaptureTorchMode; + +enum { + AVCaptureFocusModeLocked = 0, + AVCaptureFocusModeAutoFocus = 1, + AVCaptureFocusModeContinuousAutoFocus = 2, +}; +typedef NSInteger AVCaptureFocusMode; + +enum { + AVCaptureExposureModeLocked = 0, + AVCaptureExposureModeAutoExpose = 1, + AVCaptureExposureModeContinuousAutoExposure = 2, +}; +typedef NSInteger AVCaptureExposureMode; + +enum { + AVCaptureWhiteBalanceModeLocked = 0, + AVCaptureWhiteBalanceModeAutoWhiteBalance = 1, + AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance = 2, +}; +typedef NSInteger AVCaptureWhiteBalanceMode; +*/ + +double CvCaptureCAM::getProperty(int property_id){ + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + /* + NSArray* connections = [mCaptureDeviceInput connections]; + QTFormatDescription* format = [[connections objectAtIndex:0] formatDescription]; + NSSize s1 = [[format attributeForKey:QTFormatDescriptionVideoCleanApertureDisplaySizeAttribute] sizeValue]; + */ + + NSArray* ports = mCaptureDeviceInput.ports; + CMFormatDescriptionRef format = [[ports objectAtIndex:0] formatDescription]; + CGSize s1 = CMVideoFormatDescriptionGetPresentationDimensions(format, YES, YES); + + int width=(int)s1.width, height=(int)s1.height; + + [localpool drain]; + + switch (property_id) { + case CV_CAP_PROP_FRAME_WIDTH: + return width; + case CV_CAP_PROP_FRAME_HEIGHT: + return height; + + case CV_CAP_PROP_IOS_DEVICE_FOCUS: + return mCaptureDevice.focusMode; + case CV_CAP_PROP_IOS_DEVICE_EXPOSURE: + return mCaptureDevice.exposureMode; + case CV_CAP_PROP_IOS_DEVICE_FLASH: + return mCaptureDevice.flashMode; + case CV_CAP_PROP_IOS_DEVICE_WHITEBALANCE: + return mCaptureDevice.whiteBalanceMode; + case CV_CAP_PROP_IOS_DEVICE_TORCH: + return mCaptureDevice.torchMode; + + default: + return 0; + } + + +} + +bool CvCaptureCAM::setProperty(int property_id, double value) { + switch (property_id) { + case CV_CAP_PROP_FRAME_WIDTH: + width = value; + settingWidth = 1; + if (settingWidth && settingHeight) { + setWidthHeight(); + settingWidth =0; + settingHeight = 0; + } + return true; + + case CV_CAP_PROP_FRAME_HEIGHT: + height = value; + settingHeight = 1; + if (settingWidth && settingHeight) { + setWidthHeight(); + settingWidth =0; + settingHeight = 0; + } + return true; + + case CV_CAP_PROP_IOS_DEVICE_FOCUS: + if ([mCaptureDevice isFocusModeSupported:(int)value]){ + NSError* error = nil; + [mCaptureDevice lockForConfiguration:&error]; + if (error) return false; + [mCaptureDevice setFocusMode:(int)value]; + [mCaptureDevice unlockForConfiguration]; + //NSLog(@"Focus set"); + return true; + }else { + return false; + } + + case CV_CAP_PROP_IOS_DEVICE_EXPOSURE: + if ([mCaptureDevice isExposureModeSupported:(int)value]){ + NSError* error = nil; + [mCaptureDevice lockForConfiguration:&error]; + if (error) return false; + [mCaptureDevice setExposureMode:(int)value]; + [mCaptureDevice unlockForConfiguration]; + //NSLog(@"Exposure set"); + return true; + }else { + return false; + } + + case CV_CAP_PROP_IOS_DEVICE_FLASH: + if ( [mCaptureDevice hasFlash] && [mCaptureDevice isFlashModeSupported:(int)value]){ + NSError* error = nil; + [mCaptureDevice lockForConfiguration:&error]; + if (error) return false; + [mCaptureDevice setFlashMode:(int)value]; + [mCaptureDevice unlockForConfiguration]; + //NSLog(@"Flash mode set"); + return true; + }else { + return false; + } + + case CV_CAP_PROP_IOS_DEVICE_WHITEBALANCE: + if ([mCaptureDevice isWhiteBalanceModeSupported:(int)value]){ + NSError* error = nil; + [mCaptureDevice lockForConfiguration:&error]; + if (error) return false; + [mCaptureDevice setWhiteBalanceMode:(int)value]; + [mCaptureDevice unlockForConfiguration]; + //NSLog(@"White balance set"); + return true; + }else { + return false; + } + + case CV_CAP_PROP_IOS_DEVICE_TORCH: + if ([mCaptureDevice hasFlash] && [mCaptureDevice isTorchModeSupported:(int)value]){ + NSError* error = nil; + [mCaptureDevice lockForConfiguration:&error]; + if (error) return false; + [mCaptureDevice setTorchMode:(int)value]; + [mCaptureDevice unlockForConfiguration]; + //NSLog(@"Torch mode set"); + return true; + }else { + return false; + } + + case DISABLE_AUTO_RESTART: + disableAutoRestart = value; + return 1; + default: + return false; + } +} + + +/***************************************************************************** + * + * CaptureDelegate Implementation. + * + * CaptureDelegate is notified on a separate thread by the OS whenever there + * is a new frame. When "updateImage" is called from the main thread, it + * copies this new frame into an IplImage, but only if this frame has not + * been copied before. When "getOutput" is called from the main thread, + * it gives the last copied IplImage. + * + *****************************************************************************/ + + +@implementation CaptureDelegate + +- (id)init { + [super init]; + newFrame = 0; + imagedata = NULL; + bgr_imagedata = NULL; + currSize = 0; + image = NULL; + bgr_image = NULL; + bgr_image_r90 = NULL; + return self; +} + + +-(void)dealloc { + if (imagedata != NULL) free(imagedata); + if (bgr_imagedata != NULL) free(bgr_imagedata); + cvReleaseImage(&image); + cvReleaseImage(&bgr_image); + cvReleaseImage(&bgr_image_r90); + [super dealloc]; +} + + + +- (void)captureOutput:(AVCaptureOutput *)captureOutput +didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer +fromConnection:(AVCaptureConnection *)connection{ + + // Failed + // connection.videoOrientation = AVCaptureVideoOrientationPortrait; + + CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); + + CVBufferRetain(imageBuffer); + CVImageBufferRef imageBufferToRelease = mCurrentImageBuffer; + + @synchronized (self) { + + mCurrentImageBuffer = imageBuffer; + newFrame = 1; + } + + CVBufferRelease(imageBufferToRelease); + +} + + +-(IplImage*) getOutput { + //return bgr_image; + return bgr_image_r90; +} + +-(int) updateImage { + if (newFrame==0) return 0; + CVPixelBufferRef pixels; + + @synchronized (self){ + pixels = CVBufferRetain(mCurrentImageBuffer); + newFrame = 0; + } + + CVPixelBufferLockBaseAddress(pixels, 0); + uint32_t* baseaddress = (uint32_t*)CVPixelBufferGetBaseAddress(pixels); + + size_t width = CVPixelBufferGetWidth(pixels); + size_t height = CVPixelBufferGetHeight(pixels); + size_t rowBytes = CVPixelBufferGetBytesPerRow(pixels); + + if (rowBytes != 0) { + + if (currSize != rowBytes*height*sizeof(char)) { + currSize = rowBytes*height*sizeof(char); + if (imagedata != NULL) free(imagedata); + if (bgr_imagedata != NULL) free(bgr_imagedata); + imagedata = (char*)malloc(currSize); + bgr_imagedata = (char*)malloc(currSize); + } + + memcpy(imagedata, baseaddress, currSize); + + if (image == NULL) { + image = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, 4); + } + image->width =width; + image->height = height; + image->nChannels = 4; + image->depth = IPL_DEPTH_8U; + image->widthStep = (int)rowBytes; + image->imageData = imagedata; + image->imageSize = currSize; + + if (bgr_image == NULL) { + bgr_image = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, 3); + } + bgr_image->width =width; + bgr_image->height = height; + bgr_image->nChannels = 3; + bgr_image->depth = IPL_DEPTH_8U; + bgr_image->widthStep = (int)rowBytes; + bgr_image->imageData = bgr_imagedata; + bgr_image->imageSize = currSize; + + cvCvtColor(image, bgr_image, CV_BGRA2BGR); + + // image taken from the buffer is incorrected rotated. I'm using cvTranspose + cvFlip. + // There should be an option in iOS API to rotate the buffer output orientation. + // iOS provides hardware accelerated rotation through AVCaptureConnection class + // I can't get it work. + if (bgr_image_r90 == NULL){ + bgr_image_r90 = cvCreateImage(cvSize(height, width), IPL_DEPTH_8U, 3); + } + cvTranspose(bgr_image, bgr_image_r90); + cvFlip(bgr_image_r90, NULL, 1); + + } + + CVPixelBufferUnlockBaseAddress(pixels, 0); + CVBufferRelease(pixels); + + return 1; +} + +@end + + +/***************************************************************************** + * + * CvCaptureFile Implementation. + * + * CvCaptureFile is the instantiation of a capture source for video files. + * + *****************************************************************************/ + +CvCaptureFile::CvCaptureFile(const char* filename) { + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + mMovieReader = nil; + image = NULL; + bgr_image = NULL; + imagedata = NULL; + bgr_imagedata = NULL; + currSize = 0; + + movieWidth = 0; + movieHeight = 0; + movieFPS = 0; + currentFPS = 0; + movieDuration = 0; + changedPos = 0; + + started = 0; + + AVURLAsset *asset = [AVURLAsset URLAssetWithURL: + [NSURL fileURLWithPath: [NSString stringWithUTF8String:filename]] + options:nil]; + + AVAssetTrack* videoTrack = nil; + NSArray* tracks = [asset tracksWithMediaType:AVMediaTypeVideo]; + if ([tracks count] == 1) + { + videoTrack = [tracks objectAtIndex:0]; + + movieWidth = videoTrack.naturalSize.width; + movieHeight = videoTrack.naturalSize.height; + movieFPS = videoTrack.nominalFrameRate; + + currentFPS = movieFPS; //Debugging !! should be getFPS(); + //Debugging. need to be checked + + // In ms + movieDuration = videoTrack.timeRange.duration.value/videoTrack.timeRange.duration.timescale * 1000; + + started = 1; + NSError* error = nil; + mMovieReader = [[AVAssetReader alloc] initWithAsset:asset error:&error]; + if (error) + NSLog(@"%@", [error localizedDescription]); + + NSDictionary* videoSettings = + [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA] + forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey]; + + [mMovieReader addOutput:[AVAssetReaderTrackOutput + assetReaderTrackOutputWithTrack:videoTrack + outputSettings:videoSettings]]; + [mMovieReader startReading]; + } + + /* + // Asynchronously open the video in another thread. Always fail. + [asset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:@"tracks"] completionHandler: + ^{ + // The completion block goes here. + dispatch_async(dispatch_get_main_queue(), + ^{ + AVAssetTrack* ::videoTrack = nil; + NSArray* ::tracks = [asset tracksWithMediaType:AVMediaTypeVideo]; + if ([tracks count] == 1) + { + videoTrack = [tracks objectAtIndex:0]; + + movieWidth = videoTrack.naturalSize.width; + movieHeight = videoTrack.naturalSize.height; + movieFPS = videoTrack.nominalFrameRate; + currentFPS = movieFPS; //Debugging !! should be getFPS(); + //Debugging. need to be checked + movieDuration = videoTrack.timeRange.duration.value/videoTrack.timeRange.duration.timescale * 1000; + started = 1; + + NSError* ::error = nil; + // mMovieReader is a member variable + mMovieReader = [[AVAssetReader alloc] initWithAsset:asset error:&error]; + if (error) + NSLog(@"%@", [error localizedDescription]); + + NSDictionary* ::videoSettings = + [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA] +forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey]; + +[mMovieReader addOutput:[AVAssetReaderTrackOutput +assetReaderTrackOutputWithTrack:videoTrack +outputSettings:videoSettings]]; +[mMovieReader startReading]; +} +}); + +}]; + */ + +[localpool drain]; +} + +CvCaptureFile::~CvCaptureFile() { + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + if (imagedata != NULL) free(imagedata); + if (bgr_imagedata != NULL) free(bgr_imagedata); + cvReleaseImage(&image); + cvReleaseImage(&bgr_image); + [mMovieReader release]; + [localpool drain]; +} + +int CvCaptureFile::didStart() { + return started; +} + +bool CvCaptureFile::grabFrame() { + + //everything is done in queryFrame; + currentFPS = movieFPS; + return 1; + + + /* + double t1 = getProperty(CV_CAP_PROP_POS_MSEC); + [mCaptureSession stepForward]; + double t2 = getProperty(CV_CAP_PROP_POS_MSEC); + if (t2>t1 && !changedPos) { + currentFPS = 1000.0/(t2-t1); + } else { + currentFPS = movieFPS; + } + changedPos = 0; + + */ + +} + + +IplImage* CvCaptureFile::retrieveFramePixelBuffer() { + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + if (mMovieReader.status != AVAssetReaderStatusReading){ + + return NULL; + } + + + AVAssetReaderTrackOutput * output = [mMovieReader.outputs objectAtIndex:0]; + CMSampleBufferRef sampleBuffer = [output copyNextSampleBuffer]; + if (!sampleBuffer) { + [localpool drain]; + return NULL; + } + CVPixelBufferRef frame = CMSampleBufferGetImageBuffer(sampleBuffer); + CVPixelBufferRef pixels = CVBufferRetain(frame); + + CVPixelBufferLockBaseAddress(pixels, 0); + + uint32_t* baseaddress = (uint32_t*)CVPixelBufferGetBaseAddress(pixels); + size_t width = CVPixelBufferGetWidth(pixels); + size_t height = CVPixelBufferGetHeight(pixels); + size_t rowBytes = CVPixelBufferGetBytesPerRow(pixels); + + if (rowBytes != 0) { + + if (currSize != rowBytes*height*sizeof(char)) { + currSize = rowBytes*height*sizeof(char); + if (imagedata != NULL) free(imagedata); + if (bgr_imagedata != NULL) free(bgr_imagedata); + imagedata = (char*)malloc(currSize); + bgr_imagedata = (char*)malloc(currSize); + } + + memcpy(imagedata, baseaddress, currSize); + + if (image == NULL) { + image = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, 4); + } + + image->width =width; + image->height = height; + image->nChannels = 4; + image->depth = IPL_DEPTH_8U; + image->widthStep = rowBytes; + image->imageData = imagedata; + image->imageSize = currSize; + + + if (bgr_image == NULL) { + bgr_image = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, 3); + } + + bgr_image->width =width; + bgr_image->height = height; + bgr_image->nChannels = 3; + bgr_image->depth = IPL_DEPTH_8U; + bgr_image->widthStep = rowBytes; + bgr_image->imageData = bgr_imagedata; + bgr_image->imageSize = currSize; + + cvCvtColor(image, bgr_image,CV_BGRA2BGR); + + } + + CVPixelBufferUnlockBaseAddress(pixels, 0); + CVBufferRelease(pixels); + CMSampleBufferInvalidate(sampleBuffer); + CFRelease(sampleBuffer); + + [localpool drain]; + return bgr_image; +} + + +IplImage* CvCaptureFile::retrieveFrame(int) { + return retrieveFramePixelBuffer(); +} + +IplImage* CvCaptureFile::queryFrame() { + grabFrame(); + return retrieveFrame(0); +} + +double CvCaptureFile::getFPS() { + + /* + if (mCaptureSession == nil) return 0; + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + double now = getProperty(CV_CAP_PROP_POS_MSEC); + double retval = 0; + if (now == 0) { + [mCaptureSession stepForward]; + double t2 = getProperty(CV_CAP_PROP_POS_MSEC); + [mCaptureSession stepBackward]; + retval = 1000.0 / (t2-now); + } else { + [mCaptureSession stepBackward]; + double t2 = getProperty(CV_CAP_PROP_POS_MSEC); + [mCaptureSession stepForward]; + retval = 1000.0 / (now-t2); + } + [localpool drain]; + return retval; + */ + return 30.0; //TODO: Debugging +} + +double CvCaptureFile::getProperty(int property_id){ + + /* + if (mCaptureSession == nil) return 0; + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + double retval; + QTTime t; + + switch (property_id) { + case CV_CAP_PROP_POS_MSEC: + [[mCaptureSession attributeForKey:QTMovieCurrentTimeAttribute] getValue:&t]; + retval = t.timeValue * 1000.0 / t.timeScale; + break; + case CV_CAP_PROP_POS_FRAMES: + retval = movieFPS * getProperty(CV_CAP_PROP_POS_MSEC) / 1000; + break; + case CV_CAP_PROP_POS_AVI_RATIO: + retval = (getProperty(CV_CAP_PROP_POS_MSEC)) / (movieDuration ); + break; + case CV_CAP_PROP_FRAME_WIDTH: + retval = movieWidth; + break; + case CV_CAP_PROP_FRAME_HEIGHT: + retval = movieHeight; + break; + case CV_CAP_PROP_FPS: + retval = currentFPS; + break; + case CV_CAP_PROP_FOURCC: + default: + retval = 0; + } + + [localpool drain]; + return retval; + */ + return 1.0; //Debugging +} + +bool CvCaptureFile::setProperty(int property_id, double value) { + + /* + if (mCaptureSession == nil) return false; + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + bool retval = false; + QTTime t; + + double ms; + + switch (property_id) { + case CV_CAP_PROP_POS_MSEC: + [[mCaptureSession attributeForKey:QTMovieCurrentTimeAttribute] getValue:&t]; + t.timeValue = value * t.timeScale / 1000; + [mCaptureSession setCurrentTime:t]; + changedPos = 1; + retval = true; + break; + case CV_CAP_PROP_POS_FRAMES: + ms = (value*1000.0 -5)/ currentFPS; + retval = setProperty(CV_CAP_PROP_POS_MSEC, ms); + break; + case CV_CAP_PROP_POS_AVI_RATIO: + ms = value * movieDuration; + retval = setProperty(CV_CAP_PROP_POS_MSEC, ms); + break; + case CV_CAP_PROP_FRAME_WIDTH: + //retval = movieWidth; + break; + case CV_CAP_PROP_FRAME_HEIGHT: + //retval = movieHeight; + break; + case CV_CAP_PROP_FPS: + //etval = currentFPS; + break; + case CV_CAP_PROP_FOURCC: + default: + retval = false; + } + + [localpool drain]; + + return retval; + */ + return true; +} + + +/***************************************************************************** + * + * CvVideoWriter Implementation. + * + * CvVideoWriter is the instantiation of a video output class + * + *****************************************************************************/ + + +CvVideoWriter_AVFoundation::CvVideoWriter_AVFoundation(const char* filename, int fourcc, + double fps, CvSize frame_size, + int is_color) { + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + + frameCount = 0; + movieFPS = fps; + movieSize = frame_size; + movieColor = is_color; + argbimage = cvCreateImage(movieSize, IPL_DEPTH_8U, 4); + path = [[[NSString stringWithCString:filename encoding:NSASCIIStringEncoding] stringByExpandingTildeInPath] retain]; + + + /* + AVFileTypeQuickTimeMovie + UTI for the QuickTime movie file format. + The value of this UTI is com.apple.quicktime-movie. Files are identified with the .mov and .qt extensions. + + AVFileTypeMPEG4 + UTI for the MPEG-4 file format. + The value of this UTI is public.mpeg-4. Files are identified with the .mp4 extension. + + AVFileTypeAppleM4V + UTI for the iTunes video file format. + The value of this UTI is com.apple.mpeg-4-video. Files are identified with the .m4v extension. + + AVFileType3GPP + UTI for the 3GPP file format. + The value of this UTI is public.3gpp. Files are identified with the .3gp, .3gpp, and .sdv extensions. + */ + + NSString *fileExt =[[[path pathExtension] lowercaseString] copy]; + if ([fileExt isEqualToString:@"mov"] || [fileExt isEqualToString:@"qt"]){ + fileType = [AVFileTypeQuickTimeMovie copy]; + }else if ([fileExt isEqualToString:@"mp4"]){ + fileType = [AVFileTypeMPEG4 copy]; + }else if ([fileExt isEqualToString:@"m4v"]){ + fileType = [AVFileTypeAppleM4V copy]; +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + }else if ([fileExt isEqualToString:@"3gp"] || [fileExt isEqualToString:@"3gpp"] || [fileExt isEqualToString:@"sdv"] ){ + fileType = [AVFileType3GPP copy]; +#endif + } else{ + fileType = [AVFileTypeMPEG4 copy]; //default mp4 + } + [fileExt release]; + + char cc[5]; + cc[0] = fourcc & 255; + cc[1] = (fourcc >> 8) & 255; + cc[2] = (fourcc >> 16) & 255; + cc[3] = (fourcc >> 24) & 255; + cc[4] = 0; + int cc2 = CV_FOURCC(cc[0], cc[1], cc[2], cc[3]); + if (cc2!=fourcc) { + cout << "WARNING: Didn't properly encode FourCC. Expected " << fourcc + << " but got " << cc2 << "." << endl; + //exception; + } + + // Two codec supported AVVideoCodecH264 AVVideoCodecJPEG + // On iPhone 3G H264 is not supported. + if (fourcc == CV_FOURCC('J','P','E','G') || fourcc == CV_FOURCC('j','p','e','g') || + fourcc == CV_FOURCC('M','J','P','G') || fourcc == CV_FOURCC('m','j','p','g') ){ + codec = [AVVideoCodecJPEG copy]; // Use JPEG codec if specified, otherwise H264 + }else if(fourcc == CV_FOURCC('H','2','6','4') || fourcc == CV_FOURCC('a','v','c','1')){ + codec = [AVVideoCodecH264 copy]; + }else{ + codec = [AVVideoCodecH264 copy]; // default canonical H264. + + } + + //NSLog(@"Path: %@", path); + + NSError *error = nil; + + + // Make sure the file does not already exist. Necessary to overwirte?? + /* + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:path]){ + [fileManager removeItemAtPath:path error:&error]; + } + */ + + // Wire the writer: + // Supported file types: + // AVFileTypeQuickTimeMovie AVFileTypeMPEG4 AVFileTypeAppleM4V AVFileType3GPP + + mMovieWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:path] + fileType:fileType + error:&error]; + //NSParameterAssert(mMovieWriter); + + NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: + codec, AVVideoCodecKey, + [NSNumber numberWithInt:movieSize.width], AVVideoWidthKey, + [NSNumber numberWithInt:movieSize.height], AVVideoHeightKey, + nil]; + + mMovieWriterInput = [[AVAssetWriterInput + assetWriterInputWithMediaType:AVMediaTypeVideo + outputSettings:videoSettings] retain]; + + //NSParameterAssert(mMovieWriterInput); + //NSParameterAssert([mMovieWriter canAddInput:mMovieWriterInput]); + + [mMovieWriter addInput:mMovieWriterInput]; + + mMovieWriterAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc] initWithAssetWriterInput:mMovieWriterInput sourcePixelBufferAttributes:nil]; + + + //Start a session: + [mMovieWriter startWriting]; + [mMovieWriter startSessionAtSourceTime:kCMTimeZero]; + + + if(mMovieWriter.status == AVAssetWriterStatusFailed){ + NSLog(@"%@", [mMovieWriter.error localizedDescription]); + // TODO: error handling, cleanup. Throw execption? + // return; + } + + [localpool drain]; +} + + +CvVideoWriter_AVFoundation::~CvVideoWriter_AVFoundation() { + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + [mMovieWriterInput markAsFinished]; + [mMovieWriter finishWriting]; + [mMovieWriter release]; + [mMovieWriterInput release]; + [mMovieWriterAdaptor release]; + [path release]; + [codec release]; + [fileType release]; + cvReleaseImage(&argbimage); + + [localpool drain]; + +} + +bool CvVideoWriter_AVFoundation::writeFrame(const IplImage* iplimage) { + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + // writer status check + if (![mMovieWriterInput isReadyForMoreMediaData] || mMovieWriter.status != AVAssetWriterStatusWriting ) { + NSLog(@"[mMovieWriterInput isReadyForMoreMediaData] Not ready for media data or ..."); + NSLog(@"mMovieWriter.status: %d. Error: %@", mMovieWriter.status, [mMovieWriter.error localizedDescription]); + [localpool drain]; + return false; + } + + BOOL success = FALSE; + + if (iplimage->height!=movieSize.height || iplimage->width!=movieSize.width){ + cout<<"Frame size does not match video size."<nChannels == 3); + cvCvtColor(iplimage, argbimage, CV_BGR2BGRA); + }else{ + //assert(iplimage->nChannels == 1); + cvCvtColor(iplimage, argbimage, CV_GRAY2BGRA); + } + //IplImage -> CGImage conversion + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + NSData *nsData = [NSData dataWithBytes:argbimage->imageData length:argbimage->imageSize]; + CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)nsData); + CGImageRef cgImage = CGImageCreate(argbimage->width, argbimage->height, + argbimage->depth, argbimage->depth * argbimage->nChannels, argbimage->widthStep, + colorSpace, kCGImageAlphaLast|kCGBitmapByteOrderDefault, + provider, NULL, false, kCGRenderingIntentDefault); + + //CGImage -> CVPixelBufferRef coversion + CVPixelBufferRef pixelBuffer = NULL; + CFDataRef cfData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage)); + int status = CVPixelBufferCreateWithBytes(NULL, + movieSize.width, + movieSize.height, + kCVPixelFormatType_32BGRA, + (void*)CFDataGetBytePtr(cfData), + CGImageGetBytesPerRow(cgImage), + NULL, + 0, + NULL, + &pixelBuffer); + if(status == kCVReturnSuccess){ + success = [mMovieWriterAdaptor appendPixelBuffer:pixelBuffer + withPresentationTime:CMTimeMake(frameCount, movieFPS)]; + } + + //cleanup + CGImageRelease(cgImage); + CGDataProviderRelease(provider); + CGColorSpaceRelease(colorSpace); + + [localpool drain]; + + if (success) { + frameCount ++; + //NSLog(@"Frame #%d", frameCount); + return true; + }else{ + NSLog(@"Frame appendPixelBuffer failed."); + return false; + } + +} + diff --git a/highgui/src/cap_cmu.cpp b/highgui/src/cap_cmu.cpp new file mode 100644 index 0000000..357b106 --- /dev/null +++ b/highgui/src/cap_cmu.cpp @@ -0,0 +1,551 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#ifdef WIN32 + +/****************** Capturing video from camera via CMU lib *******************/ + +#ifdef HAVE_CMU1394 + +// This firewire capability added by Philip Gruebele (pgruebele@cox.net). +// For this to work you need to install the CMU firewire DCAM drivers, +// located at http://www-2.cs.cmu.edu/~iwan/1394/. +#include "1394camera.h" + +class CvCaptureCAM_CMU : public CvCapture +{ +public: + CvCaptureCAM_CMU() + { + index = -1; + image = 0; + } + + virtual ~CvCaptureCAM_CMU() + { + close(); + } + + virtual bool open(int cameraId); + virtual void close(); + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + +protected: + C1394Camera* camera(); + CvSize getSize(); + int getDepth(); + int getNChannels(); + + bool setVideoSize(int, int); + bool setMode(int mode); + bool setFrameRate(int rate); + bool setFormat(int format); + + int fps; // 0-5 + int mode; // 0-7 + int format; // 0-2, 7 ? + int index; + IplImage* image; +}; + +// CMU 1394 camera stuff. +// This firewire capability added by Philip Gruebele (pgruebele@cox.net) +// and modified by Roman Stanchak (rstanchak@yahoo.com). +// For this to work you need to install the CMU firewire DCAM drivers, +// located at http://www-2.cs.cmu.edu/~iwan/1394/. +#define CMU_MAX_CAMERAS 20 +int CMU_numCameras = 0; +int CMU_numActiveCameras = 0; +bool CMU_useCameraFlags[CMU_MAX_CAMERAS]; +C1394Camera *CMU_theCamera = 0; + +// stupid defines for mode, format, FPS +#define CV_CAP_IEEE1394_FPS_1_875 0 +#define CV_CAP_IEEE1394_FPS_3_75 1 +#define CV_CAP_IEEE1394_FPS_7_5 2 +#define CV_CAP_IEEE1394_FPS_15 3 +#define CV_CAP_IEEE1394_FPS_30 4 +#define CV_CAP_IEEE1394_FPS_60 5 + +// index by size, color +#define CV_CAP_IEEE1394_COLOR_MONO 0 +#define CV_CAP_IEEE1394_COLOR_MONO16 1 +#define CV_CAP_IEEE1394_COLOR_YUV444 2 +#define CV_CAP_IEEE1394_COLOR_YUV422 3 +#define CV_CAP_IEEE1394_COLOR_YUV411 4 +#define CV_CAP_IEEE1394_COLOR_RGB 5 + +#define CV_CAP_IEEE1394_SIZE_160X120 0 +#define CV_CAP_IEEE1394_SIZE_320X240 1 +#define CV_CAP_IEEE1394_SIZE_640X480 2 +#define CV_CAP_IEEE1394_SIZE_800X600 3 +#define CV_CAP_IEEE1394_SIZE_1024X768 4 +#define CV_CAP_IEEE1394_SIZE_1280X960 5 +#define CV_CAP_IEEE1394_SIZE_1600X1200 6 + +// given color, size, output format +// 1 16 444 422 411 RGB +static char CV_CAP_IEEE1394_FORMAT[7][6] = +{ + {-1, -1, 0, -1, -1, -1}, // 160x120 + {-1, -1, -1, 0, -1, -1}, // 320x240 + { 0, 0, -1, 0, 0, 0}, // 640x480 + { 1, 1, -1, 1, -1, 1}, // 800x600 + { 1, 1, -1, 1, -1, 1}, // 1024x768 + { 2, 2, -1, 2, -1, 2}, // 1280x960 + { 2, 2, -1, 2, -1, 2} // 1600x1200 +}; + +// given color, size, output corresponding mode +static char CV_CAP_IEEE1394_MODE[7][6] = +{ + {-1, -1, 0, -1, -1, -1}, // 160x120 + {-1, -1, -1, 1, -1, -1}, // 320x240 + { 5, 6, -1, 3, 2, 4}, // 640x480 + { 2, 6, -1, 0, -1, 1}, // 800x600 + { 5, 7, -1, 3, -1, 4}, // 1024x768 + { 2, 6, -1, 0, -1, 1}, // 1280x960 + { 5, 7, -1, 3, -1, 4} // 1600x1200 +}; + +// given format, mode, return COLOR +static char CV_CAP_IEEE1394_COLOR[2][8] = +{ + { + CV_CAP_IEEE1394_COLOR_YUV444, + CV_CAP_IEEE1394_COLOR_YUV422, + CV_CAP_IEEE1394_COLOR_YUV411, + CV_CAP_IEEE1394_COLOR_YUV422, + CV_CAP_IEEE1394_COLOR_RGB, + CV_CAP_IEEE1394_COLOR_MONO, + CV_CAP_IEEE1394_COLOR_MONO16 + }, + { + CV_CAP_IEEE1394_COLOR_YUV422, + CV_CAP_IEEE1394_COLOR_RGB, + CV_CAP_IEEE1394_COLOR_MONO, + CV_CAP_IEEE1394_COLOR_YUV422, + CV_CAP_IEEE1394_COLOR_RGB, + CV_CAP_IEEE1394_COLOR_MONO, + CV_CAP_IEEE1394_COLOR_MONO16, + CV_CAP_IEEE1394_COLOR_MONO16 + } +}; + +// convert frame rate to suitable enum +/*static int icvFrameRateToIndex_CMU(double framerate){ + if(framerate > 30) return CV_CAP_IEEE1394_FPS_60; + else if(framerate > 15) return CV_CAP_IEEE1394_FPS_30; + else if(framerate > 7.5) return CV_CAP_IEEE1394_FPS_15; + else if(framerate > 3.75) return CV_CAP_IEEE1394_FPS_7_5; + else if(framerate > 1.875) return CV_CAP_IEEE1394_FPS_3_75; + return CV_CAP_IEEE1394_FPS_1_875; +}*/ + +#if _MSC_VER >= 1200 +#pragma comment(lib,"1394camera.lib") +#endif + +C1394Camera* CvCaptureCAM_CMU::camera() +{ + return CMU_theCamera && index >= 0 ? &CMU_theCamera[index] : 0; +} + +// return the size of the image +CvSize CvCaptureCAM_CMU::getSize() +{ + C1394Camera* cmucam = camera(); + unsigned long width = 0, height = 0; + cmucam->GetVideoFrameDimensions( &width, &height ); + return cvSize((int)width, (int)height); +} + +// return the opencv depth flag corresponding to the camera format +int CvCaptureCAM_CMU::getDepth() +{ + C1394Camera* cmucam = camera(); + int format = cmucam->GetVideoFormat(); + int mode = cmucam->GetVideoMode(); + + // TODO + if( format==7 ) { + assert(0); + return 1; + } + // irrelvant to depth + if( format > 1 ) + format = 1; + + if( CV_CAP_IEEE1394_COLOR[format][mode]==CV_CAP_IEEE1394_COLOR_MONO16 ) + return IPL_DEPTH_16S; + + return IPL_DEPTH_8U; +} + +// return the number of channels for camera +int CvCaptureCAM_CMU::getNChannels() +{ + C1394Camera* cmucam = camera(); + int format = cmucam->GetVideoFormat(); + int mode = cmucam->GetVideoMode(); + + if( format==7 ){ + assert(0); + return 1; + } + + // irrelvant to nchannels + if( format > 1 ) + format = 1; + + switch(CV_CAP_IEEE1394_COLOR[format][mode]){ + case CV_CAP_IEEE1394_COLOR_RGB: + return 3; + case CV_CAP_IEEE1394_COLOR_MONO: + case CV_CAP_IEEE1394_COLOR_MONO16: + return 1; + case CV_CAP_IEEE1394_COLOR_YUV422: + case CV_CAP_IEEE1394_COLOR_YUV444: + case CV_CAP_IEEE1394_COLOR_YUV411: + return 3; + default: + ; + } + return -1; +} + +bool CvCaptureCAM_CMU::open( int _index ) +{ + close(); + + // if first time, then allocate all available cameras + if( CMU_numCameras == 0 ) + { + CMU_numActiveCameras = 0; + CMU_theCamera = new C1394Camera[CMU_MAX_CAMERAS]; + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // create all cameras + try + { + // create camera0 + if( CMU_theCamera[0].CheckLink() != CAM_SUCCESS ) + throw 1; + + // we have one pin per camera + CMU_numCameras = CMU_theCamera[0].GetNumberCameras(); + + // allocate remaining cameras + for(int i = 1; i < CMU_numCameras && i=0 && !found_format; rate--) + { + for (int color=CV_CAP_IEEE1394_COLOR_RGB; color>=0 && !found_format; color--) + { + for (int size=CV_CAP_IEEE1394_SIZE_1600X1200; size>=0 && !found_format; size--) + { + int format = CV_CAP_IEEE1394_FORMAT[size][color]; + int mode = CV_CAP_IEEE1394_MODE[size][color]; + if (format!=-1 && mode!=-1 && + CMU_theCamera[_index].HasVideoFrameRate(format,mode,rate)) + { + CMU_theCamera[_index].SetVideoFormat(format); + CMU_theCamera[_index].SetVideoMode(mode); + CMU_theCamera[_index].SetVideoFrameRate(rate); + found_format = (CMU_theCamera[_index].StartImageAcquisition() == CAM_SUCCESS); + } + } + } + } + + // try format 7 + if(!found_format){ + CMU_theCamera[_index].SetVideoFormat(7); + CMU_theCamera[_index].SetVideoMode(0); + if(CMU_theCamera[_index].StartImageAcquisition() != CAM_SUCCESS){ + // no format found + throw 9; + } + } + + index = _index; + size = getSize(); + // allocate image frame + image = cvCreateImage( size, 8, 3 ); + cvZero(image); + + // successfully activated camera + CMU_numActiveCameras++; + CMU_useCameraFlags[_index] = true; + } + catch ( int ) + { + return false; + } + + return true; +} + +void CvCaptureCAM_CMU::close() +{ + C1394Camera* cmucam = camera(); + if( cmucam ) + { + cvReleaseImage( &image ); + cmucam->StopImageAcquisition(); + CMU_useCameraFlags[index] = false; + index = -1; + + if( --CMU_numActiveCameras == 0 ) + { + delete[] CMU_theCamera; + CMU_theCamera = 0; + CMU_numCameras = 0; + } + } +} + + +bool CvCaptureCAM_CMU::grabFrame() +{ + C1394Camera* cmucam = camera(); + return cmucam ? cmucam->AcquireImage() == CAM_SUCCESS : false; +} + +/*static void swapRedBlue(IplImage * im) +{ + uchar * ptr = (uchar *) im->imageData; + uchar t; + for(int i=0; iheight; i++){ + ptr = (uchar *) im->imageData+im->widthStep*i; + for(int j=0; jwidth; j++){ + t = ptr[0]; + ptr[0] = ptr[2]; + ptr[2] = t; + ptr+=3; + } + } +}*/ + +IplImage* CvCaptureCAM_CMU::retrieveFrame(int) +{ + C1394Camera* cmucam = camera(); + if( !cmucam ) + return 0; + cmucam->getRGB((uchar*)image->imageData, image->imageSize); + cvConvertImage( image, image, CV_CVTIMG_SWAP_RB ); + return image; +} + + +double CvCaptureCAM_CMU::getProperty( int property_id ) +{ + C1394Camera* cmucam = camera(); + if( !cmucam ) + return 0; + switch( property_id ) + { + case CV_CAP_PROP_FRAME_WIDTH: + return image->width; + case CV_CAP_PROP_FRAME_HEIGHT: + return image->height; + case CV_CAP_PROP_FPS: + return cmucam->GetVideoFrameRate(); + case CV_CAP_PROP_MODE: + return cmucam->GetVideoMode(); + case CV_CAP_PROP_FORMAT: + return cmucam->GetVideoFormat(); + } + return 0; +} + +bool CvCaptureCAM_CMU::setVideoSize(int, int) +{ + return false; +} + +bool CvCaptureCAM_CMU::setMode(int mode) +{ + int format; + C1394Camera* cmucam = camera(); + if( !cmucam ) + return false; + format = cmucam->GetVideoFormat(); + if( mode < 0 || mode > 7 || !cmucam->HasVideoMode(format, mode)) + return false; + cmucam->StopImageAcquisition(); + cmucam->SetVideoMode(mode); + cmucam->StartImageAcquisition(); + return true; +} + +bool CvCaptureCAM_CMU::setFrameRate(int rate) +{ + int format, mode; + C1394Camera* cmucam = camera(); + if( !cmucam ) + return false; + mode = cmucam->GetVideoMode(); + format = cmucam->GetVideoFormat(); + if( rate < 0 || rate > 5 || !cmucam->HasVideoFrameRate(format, mode, rate) ) + return false; + cmucam->StopImageAcquisition(); + cmucam->SetVideoFrameRate(rate); + cmucam->StartImageAcquisition(); + return true; +} + +bool CvCaptureCAM_CMU::setFormat(int format) +{ + C1394Camera* cmucam = camera(); + if( !cmucam ) + return false; + if( format < 0 || format > 2 || !cmucam->HasVideoFormat(format) ) + return false; + cmucam->StopImageAcquisition(); + cmucam->SetVideoFormat(format); + cmucam->StartImageAcquisition(); + return true; +} + +bool CvCaptureCAM_CMU::setProperty( int property_id, double value ) +{ + bool retval = false; + int ival = cvRound(value); + C1394Camera* cmucam = camera(); + if( !cmucam ) + return false; + + switch (property_id) { + case CV_CAP_PROP_FRAME_WIDTH: + case CV_CAP_PROP_FRAME_HEIGHT: + { + int width, height; + if (property_id == CV_CAP_PROP_FRAME_WIDTH) + { + width = ival; + height = width*3/4; + } + else { + height = ival; + width = height*4/3; + } + retval = setVideoSize(width, height); + } + break; + case CV_CAP_PROP_FPS: + retval = setFrameRate(ival); + break; + case CV_CAP_PROP_MODE: + retval = setMode(ival); + break; + case CV_CAP_PROP_FORMAT: + retval = setFormat(ival); + break; + } + + // resize image if its not the right size anymore + CvSize size = getSize(); + if( !image || image->width != size.width || image->height != size.height ) + { + cvReleaseImage( &image ); + image = cvCreateImage( size, 8, 3 ); + } + return retval; +} + +CvCapture * cvCreateCameraCapture_CMU (int index) +{ + CvCaptureCAM_CMU* capture = new CvCaptureCAM_CMU; + if( capture->open(index) ) + return capture; + delete capture; + return 0; +} + +#endif // CMU +#endif // WIN32 diff --git a/highgui/src/cap_dc1394.cpp b/highgui/src/cap_dc1394.cpp new file mode 100644 index 0000000..1ac7db6 --- /dev/null +++ b/highgui/src/cap_dc1394.cpp @@ -0,0 +1,1121 @@ +/* This is the contributed code: +Firewire and video4linux camera support for highgui + +2003-03-12 Magnus Lundin +lundin@mlu.mine.nu + +THIS EXEPERIMENTAL CODE +Tested on 2.4.19 with 1394, video1394, v4l, dc1394 and raw1394 support + +This set of files adds support for firevre and usb cameras. +First it tries to install a firewire camera, +if that fails it tries a v4l/USB camera + +It has been tested with the motempl sample program + +INSTALLATION +Install OpenCV +Install v4l +Install dc1394 raw1394 - coriander should work with your camera + Backup highgui folder + Copy new files + cd into highgui folder + make clean (cvcap.cpp must be rebuilt) + make + make install + + +The build is controlled by the following entries in the highgui Makefile: + +libhighgui_la_LIBADD = -L/usr/X11R6/lib -lXm -lMrm -lUil -lpng -ljpeg -lz -ltiff -lavcodec -lraw1394 -ldc1394_control +DEFS = -DHAVE_CONFIG_H -DHAVE_DC1394 HAVE_CAMV4L + + +Now it should be possible to use highgui camera functions, works for me. + + +THINGS TO DO +Better ways to select 1394 or v4l camera +Better support for videosize +Format7 + +Comments and changes welcome +/Magnus + +2005-10-19 Roman Stanchak +rstanchak@yahoo.com + +Support added for setting MODE and other DC1394 properties. Also added CONVERT_RGB flag +which indicates whether or not color conversion is performed in cvRetrieveFrame. The default +for CONVERT_RGB=1 for backward compatibility. + +Tested with 2.6.12 with libdc1394-1.0.0, libraw1394-0.10.1 using a Point Grey Flea + +*/ + + +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#if !defined WIN32 && defined HAVE_DC1394 + +#include +#include +#include +#include + +#ifdef NDEBUG +#define CV_WARN(message) +#else +#define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__) +#endif + +#define CV_DC1394_CALL(expr) \ +if((expr)<0){ \ + OPENCV_ERROR(CV_StsInternal, "", "libdc1394 function call returned < 0"); \ +} + +#define DELAY 50000 + +// bpp for 16-bits cameras... this value works for PtGrey DragonFly... +#define MONO16_BPP 8 + +/* should be in pixelformat */ +static void uyv2bgr(const unsigned char *src, unsigned char *dest, unsigned long long int NumPixels); +static void uyvy2bgr(const unsigned char *src, unsigned char *dest, unsigned long long int NumPixels); +static void uyyvyy2bgr(const unsigned char *src, unsigned char *dest, unsigned long long int NumPixels); +static void y2bgr(const unsigned char *src, unsigned char *dest, unsigned long long int NumPixels); +static void y162bgr(const unsigned char *src, unsigned char *dest, unsigned long long int NumPixels, int bits); +static void rgb482bgr(const unsigned char *src8, unsigned char *dest, unsigned long long int NumPixels, int bits); + +static const char * videodev[4]={ + "/dev/video1394/0", + "/dev/video1394/1", + "/dev/video1394/2", + "/dev/video1394/3" +}; + +typedef struct CvCaptureCAM_DC1394 +{ + raw1394handle_t handle; + nodeid_t camera_node; + dc1394_cameracapture* camera; + int format; + int mode; + int color_mode; + int frame_rate; + const char * device_name; + IplImage frame; + int convert; + int buffer_is_writeable; // indicates whether frame.imageData is allocated by OpenCV or DC1394 +} +CvCaptureCAM_DC1394; + +static void icvCloseCAM_DC1394( CvCaptureCAM_DC1394* capture ); + +static int icvGrabFrameCAM_DC1394( CvCaptureCAM_DC1394* capture ); +static IplImage* icvRetrieveFrameCAM_DC1394( CvCaptureCAM_DC1394* capture, int ); + +static double icvGetPropertyCAM_DC1394( CvCaptureCAM_DC1394* capture, int property_id ); +static int icvSetPropertyCAM_DC1394( CvCaptureCAM_DC1394* capture, int property_id, double value ); + +// utility functions +static int icvFormatSupportedCAM_DC1394(int format, quadlet_t formats); +static int icvModeSupportedCAM_DC1394(int format, int mode, quadlet_t modes); +static int icvColorMode( int mode ); +static unsigned int icvGetBestFrameRate( CvCaptureCAM_DC1394 * capture, int format, int mode); +static int icvResizeFrame(CvCaptureCAM_DC1394 * capture); + +/*********************** Implementations ***************************************/ +#define MAX_PORTS 3 +#define MAX_CAMERAS 8 +#define NUM_BUFFERS 8 +struct raw1394_portinfo ports[MAX_PORTS]; +static raw1394handle_t handles[MAX_PORTS]; +static int camCount[MAX_PORTS]; +static int numPorts = -1; +static int numCameras = 0; +static nodeid_t *camera_nodes; +struct camnode {dc1394_cameracapture cam;int portnum;} cameras[MAX_CAMERAS]; + +static const int preferred_modes[] += { + // uncomment the following line to test a particular mode: + //FORMAT_VGA_NONCOMPRESSED, MODE_640x480_MONO16, 0, + FORMAT_SVGA_NONCOMPRESSED_2, + MODE_1600x1200_RGB, MODE_1600x1200_YUV422, MODE_1280x960_RGB, MODE_1280x960_YUV422, + MODE_1600x1200_MONO, MODE_1280x960_MONO, MODE_1600x1200_MONO16, MODE_1280x960_MONO16, + FORMAT_SVGA_NONCOMPRESSED_1, + MODE_1024x768_RGB, MODE_1024x768_YUV422, MODE_800x600_RGB, MODE_800x600_YUV422, + MODE_1024x768_MONO, MODE_800x600_MONO, MODE_1024x768_MONO16, MODE_800x600_MONO16, + FORMAT_VGA_NONCOMPRESSED, + MODE_640x480_RGB, MODE_640x480_YUV422, MODE_640x480_YUV411, MODE_320x240_YUV422, + MODE_160x120_YUV444, MODE_640x480_MONO, MODE_640x480_MONO16, + FORMAT_SCALABLE_IMAGE_SIZE, + MODE_FORMAT7_0, MODE_FORMAT7_1, MODE_FORMAT7_2, MODE_FORMAT7_3, + MODE_FORMAT7_4, MODE_FORMAT7_5, MODE_FORMAT7_6, MODE_FORMAT7_7, + 0 +}; + +void icvInitCapture_DC1394(){ + int p; + + raw1394handle_t raw_handle = raw1394_new_handle(); + if( raw_handle == 0 ) { + numPorts = 0; + return; + } + numPorts = raw1394_get_port_info(raw_handle, ports, MAX_PORTS); + raw1394_destroy_handle(raw_handle); + for (p = 0; p < numPorts; p++) { + handles[p] = dc1394_create_handle(p); + if (handles[p]==NULL) { numPorts=-1; return; /*ERROR_CLEANUP_EXIT*/ } + + /* get the camera nodes and describe them as we find them */ + camera_nodes = dc1394_get_camera_nodes(handles[p], &camCount[p], 0); + for (int i=0;i=numCameras) + return 0; + if (index<0) + return 0; + + CvCaptureCAM_DC1394 * pcap = (CvCaptureCAM_DC1394*)cvAlloc(sizeof(*pcap)); + + /* Select a port and camera */ + pcap->device_name = videodev[cameras[index].portnum]; + pcap->handle = handles[cameras[index].portnum]; + pcap->camera = &cameras[index].cam; + + // get supported formats + if (dc1394_query_supported_formats(pcap->handle, pcap->camera->node, &formats)<0) { + fprintf(stderr,"%s:%d: Could not query supported formats\n",__FILE__,__LINE__); + formats=0x0; + } + for (i=0; i < NUM_FORMATS; i++) { + modes[i]=0; + if (icvFormatSupportedCAM_DC1394(i+FORMAT_MIN, formats)){ + if (dc1394_query_supported_modes(pcap->handle, pcap->camera->node, i+FORMAT_MIN, &modes[i])<0) { + fprintf(stderr,"%s:%d: Could not query Format%d modes\n",__FILE__,__LINE__,i); + } + } + } + + pcap->format = 0; + pcap->mode = 0; + pcap->color_mode = 0; + pcap->frame_rate = 0; + + int format_idx = -1; + + // scan the list of preferred modes, and find a supported one + for(i=0; (pcap->mode == 0) && (preferred_modes[i] != 0); i++) { + if((preferred_modes[i] >= FORMAT_MIN) && (preferred_modes[i] <= FORMAT_MAX)) { + pcap->format = preferred_modes[i]; + format_idx = preferred_modes[i] - FORMAT_MIN; + continue; + } + assert(format_idx != -1); + if ( ! icvFormatSupportedCAM_DC1394(pcap->format, formats) ) + continue; + if ( icvModeSupportedCAM_DC1394(pcap->format, preferred_modes[i], modes[format_idx]) ){ + pcap->mode = preferred_modes[i]; + } + } + if (pcap->mode == 0) { + fprintf(stderr,"%s:%d: Could not find a supported mode for this camera\n",__FILE__,__LINE__); + goto ERROR; + } + + pcap->color_mode = icvColorMode( pcap->mode ); + if( pcap->color_mode == -1){ + fprintf(stderr,"%s:%d: ERROR: BPP is Unsupported!!\n",__FILE__,__LINE__); + goto ERROR; + } + + // set frame rate to optimal value given format and mode + pcap->frame_rate = icvGetBestFrameRate(pcap, pcap->format, pcap->mode); + + if (pcap->format!=FORMAT_SCALABLE_IMAGE_SIZE) { // everything except Format 7 + if (dc1394_dma_setup_capture(pcap->handle, pcap->camera->node, index+1 /*channel*/, + pcap->format, pcap->mode, SPEED_400, + pcap->frame_rate, NUM_BUFFERS, +#ifdef HAVE_DC1394_095 + 0 /*do_extra_buffering*/, +#endif + 1 /*DROP_FRAMES*/, + pcap->device_name, pcap->camera) != DC1394_SUCCESS) { + fprintf(stderr,"%s:%d: Failed to setup DMA capture with VIDEO1394\n",__FILE__,__LINE__); + goto ERROR; + } + } + else { + if(dc1394_dma_setup_format7_capture(pcap->handle,pcap->camera->node,index+1 /*channel*/, + pcap->mode, SPEED_400, QUERY_FROM_CAMERA, + (unsigned int)QUERY_FROM_CAMERA, (unsigned int)QUERY_FROM_CAMERA, + (unsigned int)QUERY_FROM_CAMERA, (unsigned int)QUERY_FROM_CAMERA, + NUM_BUFFERS, +#ifdef HAVE_DC1394_095 + 0 /*do_extra_buffering*/, +#endif + 1 /*DROP_FRAMES*/, + pcap->device_name, pcap->camera) != DC1394_SUCCESS) { + fprintf(stderr,"%s:%d: Failed to setup DMA capture with VIDEO1394\n",__FILE__,__LINE__); + goto ERROR; + } + } + + if (dc1394_start_iso_transmission(pcap->handle, pcap->camera->node)!=DC1394_SUCCESS) { + fprintf(stderr,"%s:%d: Could not start ISO transmission\n",__FILE__,__LINE__); + goto ERROR; + } + + usleep(DELAY); + + dc1394bool_t status; + if (dc1394_get_iso_status(pcap->handle, pcap->camera->node, &status)!=DC1394_SUCCESS) { + fprintf(stderr,"%s:%d: Could get ISO status",__FILE__,__LINE__); + goto ERROR; + } + if (status==DC1394_FALSE) { + fprintf(stderr,"%s:%d: ISO transmission refuses to start",__FILE__,__LINE__); + goto ERROR; + } + + // convert camera image to RGB by default + pcap->convert=1; + + // no image data allocated yet + pcap->buffer_is_writeable = 0; + + memset(&(pcap->frame), 0, sizeof(IplImage)); + icvResizeFrame( pcap ); + return pcap; + +ERROR: + return 0; +}; + +static void icvCloseCAM_DC1394( CvCaptureCAM_DC1394* capture ){ + dc1394_stop_iso_transmission(capture->handle, capture->camera->node); + dc1394_dma_unlisten (capture->handle, capture->camera); + /* Deallocate space for RGBA data */ + if(capture->convert){ + cvFree(&capture->frame.imageData); + } +} + +static int icvGrabFrameCAM_DC1394( CvCaptureCAM_DC1394* capture ){ + // TODO: should this function wait until the next frame is available or return + // immediately ? + float waiting = 0; + do{ + int result = dc1394_dma_single_capture_poll(capture->camera); + if(result==DC1394_SUCCESS){ + return 1; + } + else if(result==DC1394_NO_FRAME){ + usleep(1000000/120); //sleep for at least a 1/2 of the frame rate + waiting += 1.0/120.0; + } + else{ + printf("dc1394_dma_single_capture_poll failed\n"); + return 0; + } + } while(waiting<2); + printf("dc1394_dma_single_capture_poll timed out\n"); + return 0; +} + +static IplImage* icvRetrieveFrameCAM_DC1394( CvCaptureCAM_DC1394* capture, int ){ + if(capture->camera->capture_buffer ) + { + if(capture->convert){ + /* Convert to RGBA */ + unsigned char * src = (unsigned char *)capture->camera->capture_buffer; + unsigned char * dst = (unsigned char *)capture->frame.imageData; + switch (capture->color_mode) { + case COLOR_FORMAT7_RGB8: + //printf("icvRetrieveFrame convert RGB to BGR\n"); + /* Convert RGB to BGR */ + for (int i=0;iframe.imageSize;i+=6) { + dst[i] = src[i+2]; + dst[i+1] = src[i+1]; + dst[i+2] = src[i]; + dst[i+3] = src[i+5]; + dst[i+4] = src[i+4]; + dst[i+5] = src[i+3]; + } + break; + case COLOR_FORMAT7_YUV422: + //printf("icvRetrieveFrame convert YUV422 to BGR %d\n"); + uyvy2bgr(src, + dst, + capture->camera->frame_width * capture->camera->frame_height); + break; + case COLOR_FORMAT7_MONO8: + //printf("icvRetrieveFrame convert MONO8 to BGR %d\n"); + y2bgr(src, + dst, + capture->camera->frame_width * capture->camera->frame_height); + break; + case COLOR_FORMAT7_YUV411: + //printf("icvRetrieveFrame convert YUV411 to BGR %d\n"); + uyyvyy2bgr(src, + dst, + capture->camera->frame_width * capture->camera->frame_height); + break; + case COLOR_FORMAT7_YUV444: + //printf("icvRetrieveFrame convert YUV444 to BGR %d\n"); + uyv2bgr(src, + dst, + capture->camera->frame_width * capture->camera->frame_height); + break; + case COLOR_FORMAT7_MONO16: + //printf("icvRetrieveFrame convert MONO16 to BGR %d\n"); + y162bgr(src, + dst, + capture->camera->frame_width * capture->camera->frame_height, MONO16_BPP); + break; + case COLOR_FORMAT7_RGB16: + //printf("icvRetrieveFrame convert RGB16 to BGR %d\n"); + rgb482bgr(src, + dst, + capture->camera->frame_width * capture->camera->frame_height, MONO16_BPP); + break; + default: + fprintf(stderr,"%s:%d: Unsupported color mode %d\n",__FILE__,__LINE__,capture->color_mode); + return 0; + } /* switch (capture->mode) */ + } + else{ + // return raw data + capture->frame.imageData = (char *) capture->camera->capture_buffer; + capture->frame.imageDataOrigin = (char *) capture->camera->capture_buffer; + } + + // TODO: if convert=0, we are not actually done with the buffer + // but this seems to work anyway. + dc1394_dma_done_with_buffer(capture->camera); + + return &capture->frame; + } + return 0; +}; + +static double icvGetPropertyCAM_DC1394( CvCaptureCAM_DC1394* capture, int property_id ){ + int index=-1; + switch ( property_id ) { + case CV_CAP_PROP_CONVERT_RGB: + return capture->convert; + case CV_CAP_PROP_MODE: + return capture->mode; + case CV_CAP_PROP_FORMAT: + return capture->format; + case CV_CAP_PROP_FPS: + CV_DC1394_CALL(dc1394_get_video_framerate(capture->handle, capture->camera->node, + (unsigned int *) &capture->camera->frame_rate)); + switch(capture->camera->frame_rate) { + case FRAMERATE_1_875: + return 1.875; + case FRAMERATE_3_75: + return 3.75; + case FRAMERATE_7_5: + return 7.5; + case FRAMERATE_15: + return 15.; + case FRAMERATE_30: + return 30.; + case FRAMERATE_60: + return 60; +#if NUM_FRAMERATES > 6 + case FRAMERATE_120: + return 120; +#endif +#if NUM_FRAMERATES > 7 + case FRAMERATE_240: + return 240; +#endif + } + default: + index = property_id; // did they pass in a LIBDC1394 feature flag? + break; + } + if(index>=FEATURE_MIN && index<=FEATURE_MAX){ + dc1394bool_t has_feature; + CV_DC1394_CALL( dc1394_is_feature_present(capture->handle, capture->camera->node, + index, &has_feature)); + if(!has_feature){ + CV_WARN("Feature is not supported by this camera"); + } + else{ + unsigned int value; + dc1394_get_feature_value(capture->handle, capture->camera->node, index, &value); + return (double) value; + } + } + + return 0; +}; + +// resize capture->frame appropriately depending on camera and capture settings +static int icvResizeFrame(CvCaptureCAM_DC1394 * capture){ + if(capture->convert){ + // resize if sizes are different, formats are different + // or conversion option has changed + if(capture->camera->frame_width != capture->frame.width || + capture->camera->frame_height != capture->frame.height || + capture->frame.depth != 8 || + capture->frame.nChannels != 3 || + capture->frame.imageData == NULL || + capture->buffer_is_writeable == 0) + { + if(capture->frame.imageData && capture->buffer_is_writeable){ + cvReleaseData( &(capture->frame)); + } + cvInitImageHeader( &capture->frame, cvSize( capture->camera->frame_width, + capture->camera->frame_height ), + IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 ); + cvCreateData( &(capture->frame) ); + capture->buffer_is_writeable = 1; + } + + } + else { + // free image data if allocated by opencv + if(capture->buffer_is_writeable){ + cvReleaseData(&(capture->frame)); + } + + // figure out number of channels and bpp + int bpp = 8; + int nch = 3; + int width = capture->camera->frame_width; + int height = capture->camera->frame_height; + double code = CV_FOURCC('B','G','R',0); + switch(capture->color_mode){ + case COLOR_FORMAT7_YUV422: + nch = 2; + code = CV_FOURCC('Y','4','2','2'); + break; + case COLOR_FORMAT7_MONO8: + code = CV_FOURCC('Y',0,0,0); + nch = 1; + break; + case COLOR_FORMAT7_YUV411: + code = CV_FOURCC('Y','4','1','1'); + width *= 2; + nch = 3; //yy[u/v] + break; + case COLOR_FORMAT7_YUV444: + code = CV_FOURCC('Y','U','V',0); + nch = 3; + break; + case COLOR_FORMAT7_MONO16: + code = CV_FOURCC('Y',0,0,0); + bpp = IPL_DEPTH_16S; + nch = 1; + break; + case COLOR_FORMAT7_RGB16: + bpp = IPL_DEPTH_16S; + nch = 3; + break; + default: + break; + } + // reset image header + cvInitImageHeader( &capture->frame,cvSize( width, height ), bpp, nch, IPL_ORIGIN_TL, 4 ); + //assert(capture->frame.imageSize == capture->camera->quadlets_per_frame*4); + capture->buffer_is_writeable = 0; + } + return 1; +} + +// Toggle setting about whether or not RGB color conversion is to be performed +// Allocates/Initializes capture->frame appropriately +int icvSetConvertRGB(CvCaptureCAM_DC1394 * capture, int convert){ + if(convert==capture->convert){ + // no action necessary + return 1; + } + capture->convert = convert; + return icvResizeFrame( capture ); +} + +// given desired format, mode, and modes bitmask from camera, determine if format and mode are supported +static int +icvFormatSupportedCAM_DC1394(int format, quadlet_t formats){ + // formats is a bitmask whose higher order bits indicate whether format is supported + int shift = 31 - (format - FORMAT_MIN); + int mask = 1 << shift; + return (formats & mask) != 0; +} + +// analyze modes bitmask from camera to determine if desired format and mode are supported +static int +icvModeSupportedCAM_DC1394(int format, int mode, quadlet_t modes){ + // modes is a bitmask whose higher order bits indicate whether mode is supported + int format_idx = format - FORMAT_MIN; + int mode_format_min = MODE_FORMAT0_MIN + 32*format_idx; + int shift = 31 - (mode - mode_format_min); + int mask = 0x1 << shift; + return (modes & mask) != 0; +} + +// Setup camera to use given dc1394 mode +static int +icvSetModeCAM_DC1394( CvCaptureCAM_DC1394 * capture, int mode ){ + quadlet_t modes, formats; + //printf("\n"); + + // figure out corrent format for this mode + int format = (mode - MODE_FORMAT0_MIN) / 32 + FORMAT_MIN; + + // get supported formats + if (dc1394_query_supported_formats(capture->handle, capture->camera->node, &formats)<0) { + fprintf(stderr,"%s:%d: Could not query supported formats\n",__FILE__,__LINE__); + return 0; + } + + // is format for requested mode supported ? + if(icvFormatSupportedCAM_DC1394(format, formats)==0){ + return 0; + } + + // get supported modes for requested format + if (dc1394_query_supported_modes(capture->handle, capture->camera->node, format, &modes)<0){ + fprintf(stderr,"%s:%d: Could not query supported modes for format %d\n",__FILE__,__LINE__, capture->format); + return 0; + } + + // is requested mode supported ? + if(! icvModeSupportedCAM_DC1394(format, mode, modes) ){ + return 0; + } + + int color_mode = icvColorMode( mode ); + + if(color_mode == -1){ + return 0; + } + + int frame_rate = icvGetBestFrameRate(capture, format, mode); + + dc1394_dma_unlisten(capture->handle, capture->camera); + if (dc1394_dma_setup_capture(capture->handle, capture->camera->node, capture->camera->channel /*channel*/, + format, mode, SPEED_400, + frame_rate, NUM_BUFFERS, +#ifdef HAVE_DC1394_095 + 0 /*do_extra_buffering*/, +#endif + 1 /*DROP_FRAMES*/, + capture->device_name, capture->camera) != DC1394_SUCCESS) { + fprintf(stderr,"%s:%d: Failed to setup DMA capture with VIDEO1394\n",__FILE__,__LINE__); + return 0; + } + dc1394_start_iso_transmission(capture->handle, capture->camera->node); + + capture->frame_rate = frame_rate; + capture->format = format; + capture->mode = mode; + capture->color_mode = color_mode; + + // now fix image size to match new mode + icvResizeFrame( capture ); + return 1; +} + +// query camera for supported frame rates and select fastest for given format and mode +static unsigned int icvGetBestFrameRate( CvCaptureCAM_DC1394 * capture, int format, int mode ){ + quadlet_t framerates; + if (dc1394_query_supported_framerates(capture->handle, capture->camera->node, + format, mode, &framerates)!=DC1394_SUCCESS) + { + fprintf(stderr,"%s:%d: Could not query supported framerates\n",__FILE__,__LINE__); + framerates = 0; + } + + for (int f=FRAMERATE_MAX; f>=FRAMERATE_MIN; f--) { + if (framerates & (0x1<< (31-(f-FRAMERATE_MIN)))) { + return f; + } + } + return 0; +} + +static int +icvSetFrameRateCAM_DC1394( CvCaptureCAM_DC1394 * capture, double value ){ + unsigned int fps=15; + if(capture->format == FORMAT_SCALABLE_IMAGE_SIZE) + return 0; /* format 7 has no fixed framerates */ + if (value==-1){ + fps=icvGetBestFrameRate( capture, capture->format, capture->mode ); + } + else if (value==1.875) + fps=FRAMERATE_1_875; + else if (value==3.75) + fps=FRAMERATE_3_75; + else if (value==7.5) + fps=FRAMERATE_7_5; + else if (value==15) + fps=FRAMERATE_15; + else if (value==30) + fps=FRAMERATE_30; + else if (value==60) + fps=FRAMERATE_60; +#if NUM_FRAMERATES > 6 + else if (value==120) + fps=FRAMERATE_120; +#endif +#if NUM_FRAMERATES > 7 + else if (value==240) + fps=FRAMERATE_240; +#endif + dc1394_set_video_framerate(capture->handle, capture->camera->node,fps); + dc1394_get_video_framerate(capture->handle, capture->camera->node, + (unsigned int *) &capture->camera->frame_rate); + + return fps==(unsigned int) capture->camera->frame_rate; +} + +// for given mode return color format +static int +icvColorMode( int mode ){ + switch(mode) { + case MODE_160x120_YUV444: + return COLOR_FORMAT7_YUV444; + case MODE_320x240_YUV422: + case MODE_640x480_YUV422: + case MODE_800x600_YUV422: + case MODE_1024x768_YUV422: + case MODE_1280x960_YUV422: + case MODE_1600x1200_YUV422: + return COLOR_FORMAT7_YUV422; + case MODE_640x480_YUV411: + return COLOR_FORMAT7_YUV411; + case MODE_640x480_RGB: + case MODE_800x600_RGB: + case MODE_1024x768_RGB: + case MODE_1280x960_RGB: + case MODE_1600x1200_RGB: + return COLOR_FORMAT7_RGB8; + case MODE_640x480_MONO: + case MODE_800x600_MONO: + case MODE_1024x768_MONO: + case MODE_1280x960_MONO: + case MODE_1600x1200_MONO: + return COLOR_FORMAT7_MONO8; + case MODE_640x480_MONO16: + case MODE_800x600_MONO16: + case MODE_1024x768_MONO16: + case MODE_1280x960_MONO16: + case MODE_1600x1200_MONO16: + return COLOR_FORMAT7_MONO16; + case MODE_FORMAT7_0: + case MODE_FORMAT7_1: + case MODE_FORMAT7_2: + case MODE_FORMAT7_3: + case MODE_FORMAT7_4: + case MODE_FORMAT7_5: + case MODE_FORMAT7_6: + case MODE_FORMAT7_7: + fprintf(stderr,"%s:%d: Format7 not yet supported\n",__FILE__,__LINE__); + default: + break; + } + return -1; +} + +// function to set camera properties using dc1394 feature enum +// val == -1 indicates to set this property to 'auto' +static int +icvSetFeatureCAM_DC1394( CvCaptureCAM_DC1394* capture, int feature_id, int val){ + dc1394bool_t isOn = DC1394_FALSE; + dc1394bool_t hasAutoCapability = DC1394_FALSE; + dc1394bool_t isAutoOn = DC1394_FALSE; + unsigned int nval; + unsigned int minval,maxval; + + // Turn the feature on if it is OFF + if( dc1394_is_feature_on(capture->handle, capture->camera->node, feature_id, &isOn) + == DC1394_FAILURE ) { + return 0; + } + if( isOn == DC1394_FALSE ) { + // try to turn it on. + if( dc1394_feature_on_off(capture->handle, capture->camera->node, feature_id, 1) == DC1394_FAILURE ) { + fprintf(stderr, "error turning feature %d on!\n", feature_id); + return 0; + } + } + + // Check if the feature supports auto mode + dc1394_has_auto_mode(capture->handle, capture->camera->node, feature_id, &hasAutoCapability); + if( hasAutoCapability ) { + + // now check if the auto is on. + if( dc1394_is_feature_auto(capture->handle, capture->camera->node, feature_id, &isAutoOn ) == DC1394_FAILURE ) { + fprintf(stderr, "error determining if feature %d has auto on!\n", feature_id); + return 0; + } + } + // Caller requested auto mode, but cannot support it + else if(val==-1){ + fprintf(stderr, "feature %d does not support auto mode\n", feature_id); + return 0; + } + + if(val==-1){ + // if the auto mode isn't enabled, enable it + if( isAutoOn == DC1394_FALSE ) { + if(dc1394_auto_on_off(capture->handle, capture->camera->node, feature_id, 1) == DC1394_FAILURE ) { + fprintf(stderr, "error turning feature %d auto ON!\n", feature_id); + return 0; + } + } + return 1; + } + + // ELSE turn OFF auto and adjust feature manually + if( isAutoOn == DC1394_TRUE ) { + if(dc1394_auto_on_off(capture->handle, capture->camera->node, feature_id, 0) == DC1394_FAILURE ) { + fprintf(stderr, "error turning feature %d auto OFF!\n", feature_id); + return 0; + } + } + + // Clamp val to within feature range + CV_DC1394_CALL( dc1394_get_min_value(capture->handle, capture->camera->node, feature_id, &minval)); + CV_DC1394_CALL( dc1394_get_max_value(capture->handle, capture->camera->node, feature_id, &maxval)); + val = (int)MIN(maxval, MAX((unsigned)val, minval)); + + + if (dc1394_set_feature_value(capture->handle, capture->camera->node, feature_id, val) == + DC1394_FAILURE){ + fprintf(stderr, "error setting feature value\n"); + return 0; + } + if (dc1394_get_feature_value(capture->handle, capture->camera->node, feature_id, &nval) == + DC1394_FAILURE){ + fprintf(stderr, "error setting feature value\n"); + return 0; + } + return nval==(unsigned int)val; + +} + +// cvSetCaptureProperty callback function implementation +static int +icvSetPropertyCAM_DC1394( CvCaptureCAM_DC1394* capture, int property_id, double value ){ + int index=-1; + switch ( property_id ) { + case CV_CAP_PROP_CONVERT_RGB: + return icvSetConvertRGB( capture, value != 0 ); + case CV_CAP_PROP_MODE: + return icvSetModeCAM_DC1394( capture, (int) value ); + case CV_CAP_PROP_FPS: + return icvSetFrameRateCAM_DC1394( capture, value ); + case CV_CAP_PROP_BRIGHTNESS: + index = FEATURE_BRIGHTNESS; + break; + case CV_CAP_PROP_CONTRAST: + index = FEATURE_GAMMA; + break; + case CV_CAP_PROP_SATURATION: + index = FEATURE_SATURATION; + break; + case CV_CAP_PROP_HUE: + index = FEATURE_HUE; + break; + case CV_CAP_PROP_GAIN: + index = FEATURE_GAIN; + break; + default: + index = property_id; // did they pass in a LIBDC1394 feature flag? + break; + } + if(index>=FEATURE_MIN && index<=FEATURE_MAX){ + return icvSetFeatureCAM_DC1394(capture, index, (int) value); + } + return 0; +}; + +/********************************************************************** + * + * CONVERSION FUNCTIONS TO RGB 24bpp + * + **********************************************************************/ + +/* color conversion functions from Bart Nabbe. *//* corrected by Damien: bad coeficients in YUV2RGB */ +#define YUV2RGB(y, u, v, r, g, b)\ + r = y + ((v*1436) >> 10);\ +g = y - ((u*352 + v*731) >> 10);\ +b = y + ((u*1814) >> 10);\ +r = r < 0 ? 0 : r;\ +g = g < 0 ? 0 : g;\ +b = b < 0 ? 0 : b;\ +r = r > 255 ? 255 : r;\ +g = g > 255 ? 255 : g;\ +b = b > 255 ? 255 : b + + static void +uyv2bgr(const unsigned char *src, unsigned char *dest, + unsigned long long int NumPixels) +{ + register int i = NumPixels + (NumPixels << 1) - 1; + register int j = NumPixels + (NumPixels << 1) - 1; + register int y, u, v; + register int r, g, b; + + while (i > 0) { + v = src[i--] - 128; + y = src[i--]; + u = src[i--] - 128; + YUV2RGB(y, u, v, r, g, b); + dest[j--] = r; + dest[j--] = g; + dest[j--] = b; + } +} + + static void +uyvy2bgr(const unsigned char *src, unsigned char *dest, + unsigned long long int NumPixels) +{ + register int i = (NumPixels << 1) - 1; + register int j = NumPixels + (NumPixels << 1) - 1; + register int y0, y1, u, v; + register int r, g, b; + + while (i > 0) { + y1 = src[i--]; + v = src[i--] - 128; + y0 = src[i--]; + u = src[i--] - 128; + YUV2RGB(y1, u, v, r, g, b); + dest[j--] = r; + dest[j--] = g; + dest[j--] = b; + YUV2RGB(y0, u, v, r, g, b); + dest[j--] = r; + dest[j--] = g; + dest[j--] = b; + } +} + + + static void +uyyvyy2bgr(const unsigned char *src, unsigned char *dest, + unsigned long long int NumPixels) +{ + register int i = NumPixels + (NumPixels >> 1) - 1; + register int j = NumPixels + (NumPixels << 1) - 1; + register int y0, y1, y2, y3, u, v; + register int r, g, b; + + while (i > 0) { + y3 = src[i--]; + y2 = src[i--]; + v = src[i--] - 128; + y1 = src[i--]; + y0 = src[i--]; + u = src[i--] - 128; + YUV2RGB(y3, u, v, r, g, b); + dest[j--] = r; + dest[j--] = g; + dest[j--] = b; + YUV2RGB(y2, u, v, r, g, b); + dest[j--] = r; + dest[j--] = g; + dest[j--] = b; + YUV2RGB(y1, u, v, r, g, b); + dest[j--] = r; + dest[j--] = g; + dest[j--] = b; + YUV2RGB(y0, u, v, r, g, b); + dest[j--] = r; + dest[j--] = g; + dest[j--] = b; + } +} + + static void +y2bgr(const unsigned char *src, unsigned char *dest, + unsigned long long int NumPixels) +{ + register int i = NumPixels - 1; + register int j = NumPixels + (NumPixels << 1) - 1; + register int y; + + while (i > 0) { + y = src[i--]; + dest[j--] = y; + dest[j--] = y; + dest[j--] = y; + } +} + + static void +y162bgr(const unsigned char *src, unsigned char *dest, + unsigned long long int NumPixels, int bits) +{ + register int i = (NumPixels << 1) - 1; + register int j = NumPixels + (NumPixels << 1) - 1; + register int y; + + while (i > 0) { + y = src[i--]; + y = (y + (src[i--] << 8)) >> (bits - 8); + dest[j--] = y; + dest[j--] = y; + dest[j--] = y; + } +} + +// this one was in coriander but didn't take bits into account + static void +rgb482bgr(const unsigned char *src, unsigned char *dest, + unsigned long long int NumPixels, int bits) +{ + register int i = (NumPixels << 1) - 1; + register int j = NumPixels + (NumPixels << 1) - 1; + register int y; + + while (i > 0) { + y = src[i--]; + dest[j-2] = (y + (src[i--] << 8)) >> (bits - 8); + j--; + y = src[i--]; + dest[j] = (y + (src[i--] << 8)) >> (bits - 8); + j--; + y = src[i--]; + dest[j+2] = (y + (src[i--] << 8)) >> (bits - 8); + j--; + } +} + + +class CvCaptureCAM_DC1394_CPP : public CvCapture +{ +public: + CvCaptureCAM_DC1394_CPP() { captureDC1394 = 0; } + virtual ~CvCaptureCAM_DC1394_CPP() { close(); } + + virtual bool open( int index ); + virtual void close(); + + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual int getCaptureDomain() { return CV_CAP_DC1394; } // Return the type of the capture object: CV_CAP_VFW, etc... +protected: + + CvCaptureCAM_DC1394* captureDC1394; +}; + +bool CvCaptureCAM_DC1394_CPP::open( int index ) +{ + close(); + captureDC1394 = icvCaptureFromCAM_DC1394(index); + return captureDC1394 != 0; +} + +void CvCaptureCAM_DC1394_CPP::close() +{ + if( captureDC1394 ) + { + icvCloseCAM_DC1394( captureDC1394 ); + cvFree( &captureDC1394 ); + } +} + +bool CvCaptureCAM_DC1394_CPP::grabFrame() +{ + return captureDC1394 ? icvGrabFrameCAM_DC1394( captureDC1394 ) != 0 : false; +} + +IplImage* CvCaptureCAM_DC1394_CPP::retrieveFrame(int) +{ + return captureDC1394 ? (IplImage*)icvRetrieveFrameCAM_DC1394( captureDC1394, 0 ) : 0; +} + +double CvCaptureCAM_DC1394_CPP::getProperty( int propId ) +{ + return captureDC1394 ? icvGetPropertyCAM_DC1394( captureDC1394, propId ) : 0; +} + +bool CvCaptureCAM_DC1394_CPP::setProperty( int propId, double value ) +{ + return captureDC1394 ? icvSetPropertyCAM_DC1394( captureDC1394, propId, value ) != 0 : false; +} + +CvCapture* cvCreateCameraCapture_DC1394( int index ) +{ + CvCaptureCAM_DC1394_CPP* capture = new CvCaptureCAM_DC1394_CPP; + + if( capture->open( index )) + return capture; + + delete capture; + return 0; +} + +#endif diff --git a/highgui/src/cap_dc1394_v2.cpp b/highgui/src/cap_dc1394_v2.cpp new file mode 100644 index 0000000..8821095 --- /dev/null +++ b/highgui/src/cap_dc1394_v2.cpp @@ -0,0 +1,918 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#ifdef HAVE_DC1394_2 + +#include +#include +#include +#include +#include +#include + +static dc1394error_t adaptBufferStereoLocal(dc1394video_frame_t *in, dc1394video_frame_t *out) +{ + uint32_t bpp; + + // buffer position is not changed. Size is boubled in Y + out->size[0] = in->size[0]; + out->size[1] = in->size[1] * 2; + out->position[0] = in->position[0]; + out->position[1] = in->position[1]; + + // color coding is set to mono8 or raw8. + switch (in->color_coding) + { + case DC1394_COLOR_CODING_RAW16: + out->color_coding = DC1394_COLOR_CODING_RAW8; + break; + case DC1394_COLOR_CODING_MONO16: + case DC1394_COLOR_CODING_YUV422: + out->color_coding = DC1394_COLOR_CODING_MONO8; + break; + default: + return DC1394_INVALID_COLOR_CODING; + } + + // keep the color filter value in all cases. if the format is not raw it will not be further used anyway + out->color_filter = in->color_filter; + + // the output YUV byte order must be already set if the buffer is YUV422 at the output + // if the output is not YUV we don't care about this field. + // Hence nothing to do. + // we always convert to 8bits (at this point) we can safely set this value to 8. + out->data_depth = 8; + + // don't know what to do with stride... >>>> TODO: STRIDE SHOULD BE TAKEN INTO ACCOUNT... <<<< + // out->stride=?? + // the video mode should not change. Color coding and other stuff can be accessed in specific fields of this struct + out->video_mode = in->video_mode; + + // padding is kept: + out->padding_bytes = in->padding_bytes; + + // image bytes changes: >>>> TODO: STRIDE SHOULD BE TAKEN INTO ACCOUNT... <<<< + dc1394_get_color_coding_bit_size(out->color_coding, &bpp); + out->image_bytes = (out->size[0] * out->size[1] * bpp) / 8; + + // total is image_bytes + padding_bytes + out->total_bytes = out->image_bytes + out->padding_bytes; + + // bytes-per-packet and packets_per_frame are internal data that can be kept as is. + out->packet_size = in->packet_size; + out->packets_per_frame = in->packets_per_frame; + + // timestamp, frame_behind, id and camera are copied too: + out->timestamp = in->timestamp; + out->frames_behind = in->frames_behind; + out->camera = in->camera; + out->id = in->id; + + // verify memory allocation: + if (out->total_bytes > out->allocated_image_bytes) + { + free(out->image); + out->image = (uint8_t*)malloc(out->total_bytes * sizeof(uint8_t)); + out->allocated_image_bytes = out->total_bytes; + } + + // Copy padding bytes: + memcpy(&(out->image[out->image_bytes]), &(in->image[in->image_bytes]), out->padding_bytes); + out->little_endian = DC1394_FALSE; // not used before 1.32 is out. + out->data_in_padding = DC1394_FALSE; // not used before 1.32 is out. + return DC1394_SUCCESS; +} + +static dc1394error_t dc1394_deinterlace_stereo_frames_fixed(dc1394video_frame_t *in, + dc1394video_frame_t *out, dc1394stereo_method_t method) +{ + if((in->color_coding == DC1394_COLOR_CODING_RAW16) || + (in->color_coding == DC1394_COLOR_CODING_MONO16) || + (in->color_coding == DC1394_COLOR_CODING_YUV422)) + { + switch (method) + { + + case DC1394_STEREO_METHOD_INTERLACED: + adaptBufferStereoLocal(in, out); +//FIXED by AB: +// dc1394_deinterlace_stereo(in->image, out->image, in->size[0], in->size[1]); + dc1394_deinterlace_stereo(in->image, out->image, out->size[0], out->size[1]); + break; + + case DC1394_STEREO_METHOD_FIELD: + adaptBufferStereoLocal(in, out); + memcpy(out->image, in->image, out->image_bytes); + break; + } + + return DC1394_INVALID_STEREO_METHOD; + } + else + return DC1394_FUNCTION_NOT_SUPPORTED; +} + +static uint32_t getControlRegister(dc1394camera_t *camera, uint64_t offset) +{ + uint32_t value = 0; + dc1394error_t err = dc1394_get_control_register(camera, offset, &value); + + assert(err == DC1394_SUCCESS); + return err == DC1394_SUCCESS ? value : 0xffffffff; +} + +struct CvDC1394 +{ + CvDC1394(); + ~CvDC1394(); + + dc1394_t* dc; + fd_set camFds; +}; + +CvDC1394::CvDC1394() +{ + dc = dc1394_new(); + FD_ZERO(&camFds); +} + +CvDC1394::~CvDC1394() +{ + if (dc) + dc1394_free(dc); + dc = 0; +} + +static CvDC1394 dc1394; + +class CvCaptureCAM_DC1394_v2_CPP : public CvCapture +{ +public: + static int dc1394properties[CV_CAP_PROP_MAX_DC1394]; + CvCaptureCAM_DC1394_v2_CPP(); + virtual ~CvCaptureCAM_DC1394_v2_CPP() + { + close(); + } + + virtual bool open(int index); + virtual void close(); + + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual int getCaptureDomain() { return CV_CAP_DC1394; } // Return the type of the capture object: CV_CAP_VFW, etc... + + +protected: + virtual bool startCapture(); + virtual bool getVidereCalibrationInfo( char* buf, int bufSize ); + virtual bool initVidereRectifyMaps( const char* info, IplImage* ml[2], IplImage* mr[2] ); + + uint64_t guid; + dc1394camera_t* dcCam; + int isoSpeed; + int videoMode; + int frameWidth, frameHeight; + double fps; + int nDMABufs; + bool started; + int userMode; + + enum { VIDERE = 0x5505 }; + + int cameraId; + bool colorStereo; + dc1394bayer_method_t bayer; + dc1394color_filter_t bayerFilter; + + enum { NIMG = 2 }; + IplImage *img[NIMG]; + dc1394video_frame_t* frameC; + int nimages; + + bool rectify; + bool init_rectify; + IplImage *maps[NIMG][2]; + dc1394featureset_t feature_set; +}; +//mapping CV_CAP_PROP_ to DC1394_FEATUREs +int CvCaptureCAM_DC1394_v2_CPP::dc1394properties[CV_CAP_PROP_MAX_DC1394] = { +-1, //no corresponding feature for CV_CAP_PROP_POS_MSEC +-1,-1,-1,-1, +DC1394_FEATURE_FRAME_RATE, //CV_CAP_PROP_FPS - fps can be set for format 7 only! +-1,-1,-1,-1, +DC1394_FEATURE_BRIGHTNESS, //CV_CAP_PROP_BRIGHTNESS 10 +-1, +DC1394_FEATURE_SATURATION, //CV_CAP_PROP_SATURATION +DC1394_FEATURE_HUE, +DC1394_FEATURE_GAIN, +DC1394_FEATURE_SHUTTER, //CV_CAP_PROP_EXPOSURE +-1, //CV_CAP_PROP_CONVERT_RGB +DC1394_FEATURE_WHITE_BALANCE, //corresponds to CV_CAP_PROP_WHITE_BALANCE_BLUE_U and CV_CAP_PROP_WHITE_BALANCE_RED_V, see set function to check these props are set +-1,-1, +DC1394_FEATURE_SHARPNESS, //20 +DC1394_FEATURE_EXPOSURE, //CV_CAP_PROP_AUTO_EXPOSURE - this is auto exposure according to the IIDC standard +DC1394_FEATURE_GAMMA, //CV_CAP_PROP_GAMMA +DC1394_FEATURE_TEMPERATURE, //CV_CAP_PROP_TEMPERATURE +DC1394_FEATURE_TRIGGER, //CV_CAP_PROP_TRIGGER +DC1394_FEATURE_TRIGGER_DELAY, //CV_CAP_PROP_TRIGGER_DELAY +DC1394_FEATURE_WHITE_BALANCE, //CV_CAP_PROP_WHITE_BALANCE_RED_V +DC1394_FEATURE_ZOOM, //CV_CAP_PROP_ZOOM +DC1394_FEATURE_FOCUS, //CV_CAP_PROP_FOCUS +-1 //CV_CAP_PROP_GUID +}; +CvCaptureCAM_DC1394_v2_CPP::CvCaptureCAM_DC1394_v2_CPP() +{ + guid = 0; + dcCam = 0; + isoSpeed = 400; + fps = 15; + nDMABufs = 8; + started = false; + cameraId = 0; + colorStereo = false; + bayer = DC1394_BAYER_METHOD_BILINEAR; + bayerFilter = DC1394_COLOR_FILTER_GRBG; + frameWidth = 640; + frameHeight = 480; + + for (int i = 0; i < NIMG; i++) + img[i] = maps[i][0] = maps[i][1] = 0; + frameC = 0; + nimages = 1; + rectify = false; + userMode = -1; +} + + +bool CvCaptureCAM_DC1394_v2_CPP::startCapture() +{ + int i; + int code = 0; + if (!dcCam) + return false; + if (isoSpeed > 0) + { + code = dc1394_video_set_iso_speed(dcCam, + isoSpeed <= 100 ? DC1394_ISO_SPEED_100 : + isoSpeed <= 200 ? DC1394_ISO_SPEED_200 : + isoSpeed <= 400 ? DC1394_ISO_SPEED_400 : + isoSpeed <= 800 ? DC1394_ISO_SPEED_800 : + isoSpeed == 1600 ? DC1394_ISO_SPEED_1600 : + DC1394_ISO_SPEED_3200); + } + + // should a specific mode be used + if (userMode >= 0) + + { + dc1394video_mode_t wantedMode; + dc1394video_modes_t videoModes; + dc1394_video_get_supported_modes(dcCam, &videoModes); + + //set mode from number, for example the second supported mode, i.e userMode = 1 + + if (userMode < (int)videoModes.num) + { + wantedMode = videoModes.modes[userMode]; + } + + //set modes directly from DC134 constants (from dc1394video_mode_t) + else if ((userMode >= DC1394_VIDEO_MODE_MIN) && (userMode <= DC1394_VIDEO_MODE_MAX )) + { + //search for wanted mode, to check if camera supports it + int j = 0; + while ((j< (int)videoModes.num) && videoModes.modes[j]!=userMode) + { + j++; + } + + if ((int)videoModes.modes[j]==userMode) + { + wantedMode = videoModes.modes[j]; + } + else + { + userMode = -1; // wanted mode not supported, search for best mode + } + } + else + { + userMode = -1; // wanted mode not supported, search for best mode + } + //if userMode is available: set it and update size + if (userMode != -1) + { + code = dc1394_video_set_mode(dcCam, wantedMode); + uint32_t width, height; + dc1394_get_image_size_from_video_mode(dcCam, wantedMode, &width, &height); + frameWidth = (int)width; + frameHeight = (int)height; + } + } + + if (userMode == -1 && (frameWidth > 0 || frameHeight > 0)) + { + dc1394video_mode_t bestMode = (dc1394video_mode_t) - 1; + dc1394video_modes_t videoModes; + dc1394_video_get_supported_modes(dcCam, &videoModes); + for (i = 0; i < (int)videoModes.num; i++) + { + dc1394video_mode_t mode = videoModes.modes[i]; + if (mode >= DC1394_VIDEO_MODE_FORMAT7_MIN && mode <= DC1394_VIDEO_MODE_FORMAT7_MAX) + continue; + int pref = -1; + dc1394color_coding_t colorCoding; + dc1394_get_color_coding_from_video_mode(dcCam, mode, &colorCoding); + + uint32_t width, height; + dc1394_get_image_size_from_video_mode(dcCam, mode, &width, &height); + if ((int)width == frameWidth || (int)height == frameHeight) + { + if (colorCoding == DC1394_COLOR_CODING_RGB8 || + colorCoding == DC1394_COLOR_CODING_RAW8) + { + bestMode = mode; + break; + } + + if (colorCoding == DC1394_COLOR_CODING_YUV411 || + colorCoding == DC1394_COLOR_CODING_YUV422 || + (colorCoding == DC1394_COLOR_CODING_YUV444 && + pref < 1)) + { + bestMode = mode; + pref = 1; + break; + } + + if (colorCoding == DC1394_COLOR_CODING_MONO8) + { + bestMode = mode; + pref = 0; + } + } + } + if ((int)bestMode >= 0) + code = dc1394_video_set_mode(dcCam, bestMode); + } + + if (fps > 0) + { + dc1394video_mode_t mode; + dc1394framerates_t framerates; + double minDiff = DBL_MAX; + dc1394framerate_t bestFps = (dc1394framerate_t) - 1; + + dc1394_video_get_mode(dcCam, &mode); + dc1394_video_get_supported_framerates(dcCam, mode, &framerates); + + for (i = 0; i < (int)framerates.num; i++) + { + dc1394framerate_t ifps = framerates.framerates[i]; + double fps1 = (1 << (ifps - DC1394_FRAMERATE_1_875)) * 1.875; + double diff = fabs(fps1 - fps); + if (diff < minDiff) + { + minDiff = diff; + bestFps = ifps; + } + } + if ((int)bestFps >= 0) + code = dc1394_video_set_framerate(dcCam, bestFps); + } + + if (cameraId == VIDERE) + { + bayerFilter = DC1394_COLOR_FILTER_GBRG; + nimages = 2; + uint32_t value = 0; + dc1394_get_control_register(dcCam, 0x50c, &value); + colorStereo = (value & 0x80000000) != 0; + } + + code = dc1394_capture_setup(dcCam, nDMABufs, DC1394_CAPTURE_FLAGS_DEFAULT); + if (code >= 0) + { + FD_SET(dc1394_capture_get_fileno(dcCam), &dc1394.camFds); + dc1394_video_set_transmission(dcCam, DC1394_ON); + if (cameraId == VIDERE) + { + enum { PROC_MODE_OFF, PROC_MODE_NONE, PROC_MODE_TEST, PROC_MODE_RECTIFIED, PROC_MODE_DISPARITY, PROC_MODE_DISPARITY_RAW }; + int procMode = PROC_MODE_RECTIFIED; + usleep(100000); + uint32_t qval1 = 0x08000000 | (0x90 << 16) | ((procMode & 0x7) << 16); + uint32_t qval2 = 0x08000000 | (0x9C << 16); + dc1394_set_control_register(dcCam, 0xFF000, qval1); + dc1394_set_control_register(dcCam, 0xFF000, qval2); + } + started = true; + } + + return code >= 0; +} + +bool CvCaptureCAM_DC1394_v2_CPP::open(int index) +{ + bool result = false; + dc1394camera_list_t* cameraList = 0; + dc1394error_t err; + + close(); + + if (!dc1394.dc) + goto _exit_; + + err = dc1394_camera_enumerate(dc1394.dc, &cameraList); + if (err < 0 || !cameraList || (unsigned)index >= (unsigned)cameraList->num) + goto _exit_; + + guid = cameraList->ids[index].guid; + dcCam = dc1394_camera_new(dc1394.dc, guid); + if (!dcCam) + goto _exit_; + + cameraId = dcCam->vendor_id; + //get all features + if (dc1394_feature_get_all(dcCam,&feature_set) == DC1394_SUCCESS) + result = true; + else + result = false; + +_exit_: + if (cameraList) + dc1394_camera_free_list(cameraList); + + return result; +} + +void CvCaptureCAM_DC1394_v2_CPP::close() +{ + if (dcCam) + { + // check for fileno valid before using + int fileno=dc1394_capture_get_fileno(dcCam); + + if (fileno>=0 && FD_ISSET(fileno, &dc1394.camFds)) + FD_CLR(fileno, &dc1394.camFds); + dc1394_video_set_transmission(dcCam, DC1394_OFF); + dc1394_capture_stop(dcCam); + dc1394_camera_free(dcCam); + dcCam = 0; + started = false; + } + + for (int i = 0; i < NIMG; i++) + { + cvReleaseImage(&img[i]); + cvReleaseImage(&maps[i][0]); + cvReleaseImage(&maps[i][1]); + } + if (frameC) + { + if (frameC->image) + free(frameC->image); + free(frameC); + frameC = 0; + } +} + + +bool CvCaptureCAM_DC1394_v2_CPP::grabFrame() +{ + dc1394capture_policy_t policy = DC1394_CAPTURE_POLICY_WAIT; + bool code = false, isColor; + dc1394video_frame_t *dcFrame = 0, *fs = 0; + int i, nch; + + if (!dcCam || (!started && !startCapture())) + return false; + + dc1394_capture_dequeue(dcCam, policy, &dcFrame); + + if (!dcFrame) + return false; + + if (/*dcFrame->frames_behind > 1 ||*/ dc1394_capture_is_frame_corrupt(dcCam, dcFrame) == DC1394_TRUE) + { + goto _exit_; + } + + isColor = dcFrame->color_coding != DC1394_COLOR_CODING_MONO8 && + dcFrame->color_coding != DC1394_COLOR_CODING_MONO16 && + dcFrame->color_coding != DC1394_COLOR_CODING_MONO16S; + + if (nimages == 2) + { + fs = (dc1394video_frame_t*)calloc(1, sizeof(*fs)); + + //dc1394_deinterlace_stereo_frames(dcFrame, fs, DC1394_STEREO_METHOD_INTERLACED); + dc1394_deinterlace_stereo_frames_fixed(dcFrame, fs, DC1394_STEREO_METHOD_INTERLACED); + + dc1394_capture_enqueue(dcCam, dcFrame); // release the captured frame as soon as possible + dcFrame = 0; + if (!fs->image) + goto _exit_; + isColor = colorStereo; + } + nch = isColor ? 3 : 1; + + for (i = 0; i < nimages; i++) + { + IplImage fhdr; + dc1394video_frame_t f = fs ? *fs : *dcFrame, *fc = &f; + f.size[1] /= nimages; + f.image += f.size[0] * f.size[1] * i; // TODO: make it more universal + if (isColor) + { + if (!frameC) + frameC = (dc1394video_frame_t*)calloc(1, sizeof(*frameC)); + frameC->color_coding = nch == 3 ? DC1394_COLOR_CODING_RGB8 : DC1394_COLOR_CODING_MONO8; + if (nimages == 1) + { + dc1394_convert_frames(&f, frameC); + dc1394_capture_enqueue(dcCam, dcFrame); + dcFrame = 0; + } + else + { + f.color_filter = bayerFilter; + dc1394_debayer_frames(&f, frameC, bayer); + } + fc = frameC; + } + if (!img[i]) + img[i] = cvCreateImage(cvSize(fc->size[0], fc->size[1]), 8, nch); + cvInitImageHeader(&fhdr, cvSize(fc->size[0], fc->size[1]), 8, nch); + cvSetData(&fhdr, fc->image, fc->size[0]*nch); + + // Swap R&B channels: + if (nch==3) + cvConvertImage(&fhdr,&fhdr,CV_CVTIMG_SWAP_RB); + + if( rectify && cameraId == VIDERE && nimages == 2 ) + { + if( !maps[0][0] || maps[0][0]->width != img[i]->width || maps[0][0]->height != img[i]->height ) + { + CvSize size = cvGetSize(img[i]); + cvReleaseImage(&maps[0][0]); + cvReleaseImage(&maps[0][1]); + cvReleaseImage(&maps[1][0]); + cvReleaseImage(&maps[1][1]); + maps[0][0] = cvCreateImage(size, IPL_DEPTH_16S, 2); + maps[0][1] = cvCreateImage(size, IPL_DEPTH_16S, 1); + maps[1][0] = cvCreateImage(size, IPL_DEPTH_16S, 2); + maps[1][1] = cvCreateImage(size, IPL_DEPTH_16S, 1); + char buf[4*4096]; + if( getVidereCalibrationInfo( buf, (int)sizeof(buf) ) && + initVidereRectifyMaps( buf, maps[0], maps[1] )) + ; + else + rectify = false; + } + cvRemap(&fhdr, img[i], maps[i][0], maps[i][1]); + } + else + cvCopy(&fhdr, img[i]); + } + + code = true; + +_exit_: + if (dcFrame) + dc1394_capture_enqueue(dcCam, dcFrame); + if (fs) + { + if (fs->image) + free(fs->image); + free(fs); + } + + return code; +} + +IplImage* CvCaptureCAM_DC1394_v2_CPP::retrieveFrame(int idx) +{ + return 0 <= idx && idx < nimages ? img[idx] : 0; +} + +double CvCaptureCAM_DC1394_v2_CPP::getProperty(int propId) +{ + switch (propId) + { + case CV_CAP_PROP_FRAME_WIDTH: + return frameWidth ? frameWidth : frameHeight*4 / 3; + case CV_CAP_PROP_FRAME_HEIGHT: + return frameHeight ? frameHeight : frameWidth*3 / 4; + case CV_CAP_PROP_FPS: + return fps; + case CV_CAP_PROP_RECTIFICATION: + return rectify ? 1 : 0; + case CV_CAP_PROP_WHITE_BALANCE_BLUE_U: + if (dc1394_feature_whitebalance_get_value(dcCam, + &feature_set.feature[DC1394_FEATURE_WHITE_BALANCE-DC1394_FEATURE_MIN].BU_value, + &feature_set.feature[DC1394_FEATURE_WHITE_BALANCE-DC1394_FEATURE_MIN].RV_value) == DC1394_SUCCESS) + return feature_set.feature[DC1394_FEATURE_WHITE_BALANCE-DC1394_FEATURE_MIN].BU_value; + break; + case CV_CAP_PROP_WHITE_BALANCE_RED_V: + if (dc1394_feature_whitebalance_get_value(dcCam, + &feature_set.feature[DC1394_FEATURE_WHITE_BALANCE-DC1394_FEATURE_MIN].BU_value, + &feature_set.feature[DC1394_FEATURE_WHITE_BALANCE-DC1394_FEATURE_MIN].RV_value) == DC1394_SUCCESS) + return feature_set.feature[DC1394_FEATURE_WHITE_BALANCE-DC1394_FEATURE_MIN].RV_value; + break; + case CV_CAP_PROP_GUID: + //the least 32 bits are enough to identify the camera + return (double) (guid & 0x00000000FFFFFFFF); + break; + case CV_CAP_PROP_MODE: + return (double) userMode; + break; + case CV_CAP_PROP_ISO_SPEED: + return (double) isoSpeed; + default: + if (propId FLT_EPSILON; + break; + case CV_CAP_PROP_MODE: + if(started) + return false; + userMode = cvRound(value); + break; + case CV_CAP_PROP_ISO_SPEED: + if(started) + return false; + isoSpeed = cvRound(value); + break; + //The code below is based on coriander, callbacks.c:795, refer to case RANGE_MENU_MAN : + default: + if (propIdon_off_capable) + && (dc1394_feature_set_power(dcCam, act_feature->id, DC1394_OFF) == DC1394_SUCCESS)) + { + act_feature->is_on=DC1394_OFF; + return true; + } + return false; + } + //try to turn the feature ON, feature can be ON and at the same time it can be not capable to change state to OFF + if ( (act_feature->is_on == DC1394_OFF) && (act_feature->on_off_capable == DC1394_TRUE)) + { + if (dc1394_feature_set_power(dcCam, act_feature->id, DC1394_ON) == DC1394_SUCCESS) + feature_set.feature[dc1394properties[propId]-DC1394_FEATURE_MIN].is_on=DC1394_ON; + } + //turn off absolute mode - the actual value will be stored in the value field, + //otherwise it would be stored into CSR (control and status register) absolute value + if (act_feature->absolute_capable + && dc1394_feature_set_absolute_control(dcCam, act_feature->id, DC1394_OFF) !=DC1394_SUCCESS) + return false; + else + act_feature->abs_control=DC1394_OFF; + //set AUTO + if (cvRound(value) == CV_CAP_PROP_DC1394_MODE_AUTO) + { + if (dc1394_feature_set_mode(dcCam, act_feature->id, DC1394_FEATURE_MODE_AUTO)!=DC1394_SUCCESS) + return false; + act_feature->current_mode=DC1394_FEATURE_MODE_AUTO; + return true; + } + //set ONE PUSH + if (cvRound(value) == CV_CAP_PROP_DC1394_MODE_ONE_PUSH_AUTO) + { + //have to set to manual first, otherwise one push will be ignored (AVT manual 4.3.0 p. 115) + if (dc1394_feature_set_mode(dcCam, act_feature->id, DC1394_FEATURE_MODE_ONE_PUSH_AUTO)!=DC1394_SUCCESS) + return false; + //will change to + act_feature->current_mode=DC1394_FEATURE_MODE_ONE_PUSH_AUTO; + return true; + } + //set the feature to MANUAL mode, + if (dc1394_feature_set_mode(dcCam, act_feature->id, DC1394_FEATURE_MODE_MANUAL)!=DC1394_SUCCESS) + return false; + else + act_feature->current_mode=DC1394_FEATURE_MODE_MANUAL; + // if property is one of the white balance features treat it in different way + if (propId == CV_CAP_PROP_WHITE_BALANCE_BLUE_U) + { + if (dc1394_feature_whitebalance_set_value(dcCam,cvRound(value), act_feature->RV_value)!=DC1394_SUCCESS) + return false; + else + { + act_feature->BU_value = cvRound(value); + return true; + } + } + if (propId == CV_CAP_PROP_WHITE_BALANCE_RED_V) + { + if (dc1394_feature_whitebalance_set_value(dcCam, act_feature->BU_value, cvRound(value))!=DC1394_SUCCESS) + return false; + else + { + act_feature->RV_value = cvRound(value); + return true; + } + } + + //first: check boundaries + if (value < act_feature->min) + { + value = act_feature->min; + } + else if (value > act_feature->max) + { + value = act_feature->max; + } + + if (dc1394_feature_set_value(dcCam, act_feature->id, cvRound(value)) == DC1394_SUCCESS) + { + act_feature->value = value; + return true; + } + } + return false; + } + return true; +} + + +bool CvCaptureCAM_DC1394_v2_CPP::getVidereCalibrationInfo( char* buf, int bufSize ) +{ + int pos; + + for( pos = 0; pos < bufSize - 4; pos += 4 ) + { + uint32_t quad = getControlRegister(dcCam, 0xF0800 + pos); + if( quad == 0 || quad == 0xffffffff ) + break; + buf[pos] = (uchar)(quad >> 24); + buf[pos+1] = (uchar)(quad >> 16); + buf[pos+2] = (uchar)(quad >> 8); + buf[pos+3] = (uchar)(quad); + } + + if( pos == 0 ) + return false; + + buf[pos] = '\0'; + return true; +} + + +bool CvCaptureCAM_DC1394_v2_CPP::initVidereRectifyMaps( const char* info, + IplImage* ml[2], IplImage* mr[2] ) +{ + float identity_data[] = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + CvMat l_rect = cvMat(3, 3, CV_32F, identity_data), r_rect = l_rect; + float l_intrinsic_data[] = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + float r_intrinsic_data[] = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + CvMat l_intrinsic = cvMat(3, 3, CV_32F, l_intrinsic_data); + CvMat r_intrinsic = cvMat(3, 3, CV_32F, r_intrinsic_data); + float l_distortion_data[] = {0,0,0,0,0}, r_distortion_data[] = {0,0,0,0,0}; + CvMat l_distortion = cvMat(1, 5, CV_32F, l_distortion_data); + CvMat r_distortion = cvMat(1, 5, CV_32F, r_distortion_data); + IplImage* mx = cvCreateImage(cvGetSize(ml[0]), IPL_DEPTH_32F, 1); + IplImage* my = cvCreateImage(cvGetSize(ml[0]), IPL_DEPTH_32F, 1); + int k, j; + + for( k = 0; k < 2; k++ ) + { + const char* section_name = k == 0 ? "[left_camera]" : "[right_camera]"; + static const char* param_names[] = { "f ", "fy", "Cx", "Cy" "kappa1", "kappa2", "tau1", "tau2", "kappa3", 0 }; + const char* section_start = strstr( info, section_name ); + CvMat* intrinsic = k == 0 ? &l_intrinsic : &r_intrinsic; + CvMat* distortion = k == 0 ? &l_distortion : &r_distortion; + CvMat* rectification = k == 0 ? &l_rect : &r_rect; + IplImage** dst = k == 0 ? ml : mr; + if( !section_start ) + break; + section_start += strlen(section_name); + for( j = 0; param_names[j] != 0; j++ ) + { + const char* param_value_start = strstr(section_start, param_names[j]); + float val=0; + if(!param_value_start) + break; + sscanf(param_value_start + strlen(param_names[j]), "%f", &val); + if( j < 4 ) + intrinsic->data.fl[j == 0 ? 0 : j == 1 ? 4 : j == 2 ? 2 : 5] = val; + else + distortion->data.fl[j - 4] = val; + } + if( param_names[j] != 0 ) + break; + + // some sanity check for the principal point + if( fabs(mx->width*0.5 - intrinsic->data.fl[2]) > mx->width*0.1 || + fabs(my->height*0.5 - intrinsic->data.fl[5]) > my->height*0.1 ) + { + cvScale( &intrinsic, &intrinsic, 0.5 ); // try the corrected intrinsic matrix for 2x lower resolution + if( fabs(mx->width*0.5 - intrinsic->data.fl[2]) > mx->width*0.05 || + fabs(my->height*0.5 - intrinsic->data.fl[5]) > my->height*0.05 ) + cvScale( &intrinsic, &intrinsic, 2 ); // revert it back if the new variant is not much better + intrinsic->data.fl[8] = 1; + } + + cvInitUndistortRectifyMap( intrinsic, distortion, + rectification, intrinsic, mx, my ); + cvConvertMaps( mx, my, dst[0], dst[1] ); + } + + cvReleaseImage( &mx ); + cvReleaseImage( &my ); + return k >= 2; +} + + +CvCapture* cvCreateCameraCapture_DC1394_2(int index) +{ + CvCaptureCAM_DC1394_v2_CPP* capture = new CvCaptureCAM_DC1394_v2_CPP; + + if (capture->open(index)) + return capture; + + delete capture; + return 0; +} + +#endif diff --git a/highgui/src/cap_dshow.cpp b/highgui/src/cap_dshow.cpp new file mode 100644 index 0000000..49c8463 --- /dev/null +++ b/highgui/src/cap_dshow.cpp @@ -0,0 +1,3366 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#if (defined WIN32 || defined _WIN32) && defined HAVE_VIDEOINPUT + +/* + DirectShow-based Video Capturing module is based on + videoInput library by Theodore Watson: + http://muonics.net/school/spring05/videoInput/ + + Below is the original copyright +*/ + +//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. + +////////////////////////////////////////////////////////// +//Written by Theodore Watson - theo.watson@gmail.com // +//Do whatever you want with this code but if you find // +//a bug or make an improvement I would love to know! // +// // +//Warning This code is experimental // +//use at your own risk :) // +////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +/* Shoutouts + +Thanks to: + + Dillip Kumar Kara for crossbar code. + Zachary Lieberman for getting me into this stuff + and for being so generous with time and code. + The guys at Potion Design for helping me with VC++ + Josh Fisher for being a serious C++ nerd :) + Golan Levin for helping me debug the strangest + and slowest bug in the world! + + And all the people using this library who send in + bugs, suggestions and improvements who keep me working on + the next version - yeah thanks a lot ;) + +*/ +///////////////////////////////////////////////////////// + +#include "precomp.hpp" + +#if defined _MSC_VER && _MSC_VER >= 100 +//'sprintf': name was marked as #pragma deprecated +#pragma warning(disable: 4995) +#endif + +#include +#include +#include +#include +#include +#include + +#include + +//Include Directshow stuff here so we don't worry about needing all the h files. +#if defined _MSC_VER && _MSC_VER >= 1500 +# include "DShow.h" +# include "strmif.h" +# include "Aviriff.h" +# include "dvdmedia.h" +# include "bdaiface.h" +#else +# ifdef _MSC_VER +# define __extension__ + typedef BOOL WINBOOL; +#endif + +#include "dshow/dshow.h" +#include "dshow/dvdmedia.h" +#include "dshow/bdatypes.h" + +interface IEnumPIDMap : public IUnknown +{ +public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [in] */ ULONG cRequest, + /* [size_is][out][in] */ PID_MAP *pPIDMap, + /* [out] */ ULONG *pcReceived) = 0; + + virtual HRESULT STDMETHODCALLTYPE Skip( + /* [in] */ ULONG cRecords) = 0; + + virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE Clone( + /* [out] */ IEnumPIDMap **ppIEnumPIDMap) = 0; + + virtual ~IEnumPIDMap() {} +}; + +interface IMPEG2PIDMap : public IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE MapPID( + /* [in] */ ULONG culPID, + /* [in] */ ULONG *pulPID, + /* [in] */ MEDIA_SAMPLE_CONTENT MediaSampleContent) = 0; + + virtual HRESULT STDMETHODCALLTYPE UnmapPID( + /* [in] */ ULONG culPID, + /* [in] */ ULONG *pulPID) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnumPIDMap( + /* [out] */ IEnumPIDMap **pIEnumPIDMap) = 0; + + virtual ~IMPEG2PIDMap() {} +}; + +#endif + +//for threading +#include + +//this is for TryEnterCriticalSection +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x400 +#endif + + +/* +MEDIASUBTYPE_I420 : TGUID ='{30323449-0000-0010-8000-00AA00389B71}'; +MEDIASUBTYPE_Y800 : TGUID ='{30303859-0000-0010-8000-00AA00389B71}'; +MEDIASUBTYPE_Y8 : TGUID ='{20203859-0000-0010-8000-00AA00389B71}'; +MEDIASUBTYPE_Y160 : TGUID ='{30363159-0000-0010-8000-00AA00389B71}'; +MEDIASUBTYPE_YV16 : TGUID ='{32315659-0000-0010-8000-00AA00389B71}'; +MEDIASUBTYPE_Y422 : TGUID ='{32323459-0000-0010-8000-00AA00389B71}'; +MEDIASUBTYPE_GREY : TGUID ='{59455247-0000-0010-8000-00AA00389B71}'; +*/ + +#include + +DEFINE_GUID(MEDIASUBTYPE_GREY, 0x59455247, 0x0000, 0x0010, 0x80, 0x00, + 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +DEFINE_GUID(MEDIASUBTYPE_Y8, 0x20203859, 0x0000, 0x0010, 0x80, 0x00, + 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +DEFINE_GUID(MEDIASUBTYPE_Y800, 0x30303859, 0x0000, 0x0010, 0x80, 0x00, + 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(CLSID_CaptureGraphBuilder2,0xbf87b6e1,0x8c27,0x11d0,0xb3,0xf0,0x00,0xaa,0x00,0x37,0x61,0xc5); +DEFINE_GUID(CLSID_FilterGraph,0xe436ebb3,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_GUID(CLSID_NullRenderer,0xc1f400a4,0x3f08,0x11d3,0x9f,0x0b,0x00,0x60,0x08,0x03,0x9e,0x37); +DEFINE_GUID(CLSID_SampleGrabber,0xc1f400a0,0x3f08,0x11d3,0x9f,0x0b,0x00,0x60,0x08,0x03,0x9e,0x37); +DEFINE_GUID(CLSID_SystemDeviceEnum,0x62be5d10,0x60eb,0x11d0,0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86); +DEFINE_GUID(CLSID_VideoInputDeviceCategory,0x860bb310,0x5d01,0x11d0,0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86); +DEFINE_GUID(FORMAT_VideoInfo,0x05589f80,0xc356,0x11ce,0xbf,0x01,0x00,0xaa,0x00,0x55,0x59,0x5a); +DEFINE_GUID(IID_IAMAnalogVideoDecoder,0xc6e13350,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56); +DEFINE_GUID(IID_IAMCameraControl,0xc6e13370,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56); +DEFINE_GUID(IID_IAMCrossbar,0xc6e13380,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56); +DEFINE_GUID(IID_IAMStreamConfig,0xc6e13340,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56); +DEFINE_GUID(IID_IAMVideoProcAmp,0xc6e13360,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56); +DEFINE_GUID(IID_IBaseFilter,0x56a86895,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_GUID(IID_ICaptureGraphBuilder2,0x93e5a4e0,0x2d50,0x11d2,0xab,0xfa,0x00,0xa0,0xc9,0xc6,0xe3,0x8d); +DEFINE_GUID(IID_ICreateDevEnum,0x29840822,0x5b84,0x11d0,0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86); +DEFINE_GUID(IID_IGraphBuilder,0x56a868a9,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_GUID(IID_IMPEG2PIDMap,0xafb6c2a1,0x2c41,0x11d3,0x8a,0x60,0x00,0x00,0xf8,0x1e,0x0e,0x4a); +DEFINE_GUID(IID_IMediaControl,0x56a868b1,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_GUID(IID_IMediaFilter,0x56a86899,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_GUID(IID_ISampleGrabber,0x6b652fff,0x11fe,0x4fce,0x92,0xad,0x02,0x66,0xb5,0xd7,0xc7,0x8f); +DEFINE_GUID(LOOK_UPSTREAM_ONLY,0xac798be0,0x98e3,0x11d1,0xb3,0xf1,0x00,0xaa,0x00,0x37,0x61,0xc5); +DEFINE_GUID(MEDIASUBTYPE_AYUV,0x56555941,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(MEDIASUBTYPE_IYUV,0x56555949,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(MEDIASUBTYPE_RGB24,0xe436eb7d,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_GUID(MEDIASUBTYPE_RGB32,0xe436eb7e,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_GUID(MEDIASUBTYPE_RGB555,0xe436eb7c,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_GUID(MEDIASUBTYPE_RGB565,0xe436eb7b,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_GUID(MEDIASUBTYPE_I420,0x49343230,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(MEDIASUBTYPE_UYVY,0x59565955,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(MEDIASUBTYPE_Y211,0x31313259,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(MEDIASUBTYPE_Y411,0x31313459,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(MEDIASUBTYPE_Y41P,0x50313459,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(MEDIASUBTYPE_YUY2,0x32595559,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(MEDIASUBTYPE_YUYV,0x56595559,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(MEDIASUBTYPE_YV12,0x32315659,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(MEDIASUBTYPE_YVU9,0x39555659,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(MEDIASUBTYPE_YVYU,0x55595659,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(MEDIASUBTYPE_MJPG,0x47504A4D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); // MGB +DEFINE_GUID(MEDIATYPE_Interleaved,0x73766169,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(MEDIATYPE_Video,0x73646976,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(PIN_CATEGORY_CAPTURE,0xfb6c4281,0x0353,0x11d1,0x90,0x5f,0x00,0x00,0xc0,0xcc,0x16,0xba); +DEFINE_GUID(PIN_CATEGORY_PREVIEW,0xfb6c4282,0x0353,0x11d1,0x90,0x5f,0x00,0x00,0xc0,0xcc,0x16,0xba); + +interface ISampleGrabberCB : public IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE SampleCB( + double SampleTime, + IMediaSample *pSample) = 0; + + virtual HRESULT STDMETHODCALLTYPE BufferCB( + double SampleTime, + BYTE *pBuffer, + LONG BufferLen) = 0; + + virtual ~ISampleGrabberCB() {} +}; + +interface ISampleGrabber : public IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE SetOneShot( + BOOL OneShot) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetMediaType( + const AM_MEDIA_TYPE *pType) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType( + AM_MEDIA_TYPE *pType) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetBufferSamples( + BOOL BufferThem) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCurrentBuffer( + LONG *pBufferSize, + LONG *pBuffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCurrentSample( + IMediaSample **ppSample) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + ISampleGrabberCB *pCallback, + LONG WhichMethodToCallback) = 0; + + virtual ~ISampleGrabber() {} +}; + +#ifndef HEADER +#define HEADER(p) (&(((VIDEOINFOHEADER*)(p))->bmiHeader)) +#endif + +//Example Usage +/* + //create a videoInput object + videoInput VI; + + //Prints out a list of available devices and returns num of devices found + int numDevices = VI.listDevices(); + + int device1 = 0; //this could be any deviceID that shows up in listDevices + int device2 = 1; //this could be any deviceID that shows up in listDevices + + //if you want to capture at a different frame rate (default is 30) + //specify it here, you are not guaranteed to get this fps though. + //VI.setIdealFramerate(dev, 60); + + //setup the first device - there are a number of options: + + VI.setupDevice(device1); //setup the first device with the default settings + //VI.setupDevice(device1, VI_COMPOSITE); //or setup device with specific connection type + //VI.setupDevice(device1, 320, 240); //or setup device with specified video size + //VI.setupDevice(device1, 320, 240, VI_COMPOSITE); //or setup device with video size and connection type + + //VI.setFormat(device1, VI_NTSC_M); //if your card doesn't remember what format it should be + //call this with the appropriate format listed above + //NOTE: must be called after setupDevice! + + //optionally setup a second (or third, fourth ...) device - same options as above + VI.setupDevice(device2); + + //As requested width and height can not always be accomodated + //make sure to check the size once the device is setup + + int width = VI.getWidth(device1); + int height = VI.getHeight(device1); + int size = VI.getSize(device1); + + unsigned char * yourBuffer1 = new unsigned char[size]; + unsigned char * yourBuffer2 = new unsigned char[size]; + + //to get the data from the device first check if the data is new + if(VI.isFrameNew(device1)){ + VI.getPixels(device1, yourBuffer1, false, false); //fills pixels as a BGR (for openCV) unsigned char array - no flipping + VI.getPixels(device1, yourBuffer2, true, true); //fills pixels as a RGB (for openGL) unsigned char array - flipping! + } + + //same applies to device2 etc + + //to get a settings dialog for the device + VI.showSettingsWindow(device1); + + + //Shut down devices properly + VI.stopDevice(device1); + VI.stopDevice(device2); +*/ + + +////////////////////////////////////// VARS AND DEFS ////////////////////////////////// + + +//STUFF YOU CAN CHANGE + +//change for verbose debug info +static bool verbose = true; + +//if you need VI to use multi threaded com +//#define VI_COM_MULTI_THREADED + +//STUFF YOU DON'T CHANGE + +//videoInput defines +#define VI_VERSION 0.1995 +#define VI_MAX_CAMERAS 20 +#define VI_NUM_TYPES 20 //MGB +#define VI_NUM_FORMATS 18 //DON'T TOUCH + +//defines for setPhyCon - tuner is not as well supported as composite and s-video +#define VI_COMPOSITE 0 +#define VI_S_VIDEO 1 +#define VI_TUNER 2 +#define VI_USB 3 +#define VI_1394 4 + +//defines for formats +#define VI_NTSC_M 0 +#define VI_PAL_B 1 +#define VI_PAL_D 2 +#define VI_PAL_G 3 +#define VI_PAL_H 4 +#define VI_PAL_I 5 +#define VI_PAL_M 6 +#define VI_PAL_N 7 +#define VI_PAL_NC 8 +#define VI_SECAM_B 9 +#define VI_SECAM_D 10 +#define VI_SECAM_G 11 +#define VI_SECAM_H 12 +#define VI_SECAM_K 13 +#define VI_SECAM_K1 14 +#define VI_SECAM_L 15 +#define VI_NTSC_M_J 16 +#define VI_NTSC_433 17 + + +//allows us to directShow classes here with the includes in the cpp +struct ICaptureGraphBuilder2; +struct IGraphBuilder; +struct IBaseFilter; +struct IAMCrossbar; +struct IMediaControl; +struct ISampleGrabber; +struct IMediaEventEx; +struct IAMStreamConfig; +struct _AMMediaType; +class SampleGrabberCallback; +typedef _AMMediaType AM_MEDIA_TYPE; + +//keeps track of how many instances of VI are being used +//don't touch +//static int comInitCount = 0; + + +//////////////////////////////////////// VIDEO DEVICE /////////////////////////////////// + +class videoDevice{ + + + public: + + videoDevice(); + void setSize(int w, int h); + void NukeDownstream(IBaseFilter *pBF); + void destroyGraph(); + ~videoDevice(); + + int videoSize; + int width; + int height; + + int tryWidth; + int tryHeight; + GUID tryVideoType; + + ICaptureGraphBuilder2 *pCaptureGraph; // Capture graph builder object + IGraphBuilder *pGraph; // Graph builder object + IMediaControl *pControl; // Media control object + IBaseFilter *pVideoInputFilter; // Video Capture filter + IBaseFilter *pGrabberF; + IBaseFilter * pDestFilter; + IAMStreamConfig *streamConf; + ISampleGrabber * pGrabber; // Grabs frame + AM_MEDIA_TYPE * pAmMediaType; + + IMediaEventEx * pMediaEvent; + + GUID videoType; + long formatType; + + SampleGrabberCallback * sgCallback; + + bool tryDiffSize; + bool useCrossbar; + bool readyToCapture; + bool sizeSet; + bool setupStarted; + bool specificFormat; + bool autoReconnect; + int nFramesForReconnect; + unsigned long nFramesRunning; + int connection; + int storeConn; + int myID; + long requestedFrameTime; //ie fps + + char nDeviceName[255]; + WCHAR wDeviceName[255]; + + unsigned char * pixels; + char * pBuffer; + +}; + + + + +////////////////////////////////////// VIDEO INPUT ///////////////////////////////////// + + + +class videoInput{ + + public: + videoInput(); + ~videoInput(); + + //turns off console messages - default is to print messages + static void setVerbose(bool _verbose); + + //Functions in rough order they should be used. + static int listDevices(bool silent = false); + + //needs to be called after listDevices - otherwise returns NULL + static char * getDeviceName(int deviceID); + + //choose to use callback based capture - or single threaded + void setUseCallback(bool useCallback); + + //call before setupDevice + //directshow will try and get the closest possible framerate to what is requested + void setIdealFramerate(int deviceID, int idealFramerate); + + //some devices will stop delivering frames after a while - this method gives you the option to try and reconnect + //to a device if videoInput detects that a device has stopped delivering frames. + //you MUST CALL isFrameNew every app loop for this to have any effect + void setAutoReconnectOnFreeze(int deviceNumber, bool doReconnect, int numMissedFramesBeforeReconnect); + + //Choose one of these five to setup your device + bool setupDevice(int deviceID); + bool setupDevice(int deviceID, int w, int h); + bool setupDeviceFourcc(int deviceID, int w, int h,int fourcc); + + //These two are only for capture cards + //USB and Firewire cameras souldn't specify connection + bool setupDevice(int deviceID, int connection); + bool setupDevice(int deviceID, int w, int h, int connection); + + bool setFourcc(int deviceNumber, int fourcc); + + //If you need to you can set your NTSC/PAL/SECAM + //preference here. if it is available it will be used. + //see #defines above for available formats - eg VI_NTSC_M or VI_PAL_B + //should be called after setupDevice + //can be called multiple times + bool setFormat(int deviceNumber, int format); + + //Tells you when a new frame has arrived - you should call this if you have specified setAutoReconnectOnFreeze to true + bool isFrameNew(int deviceID); + + bool isDeviceSetup(int deviceID); + + //Returns the pixels - flipRedAndBlue toggles RGB/BGR flipping - and you can flip the image too + unsigned char * getPixels(int deviceID, bool flipRedAndBlue = true, bool flipImage = false); + + //Or pass in a buffer for getPixels to fill returns true if successful. + bool getPixels(int id, unsigned char * pixels, bool flipRedAndBlue = true, bool flipImage = false); + + //Launches a pop up settings window + //For some reason in GLUT you have to call it twice each time. + void showSettingsWindow(int deviceID); + + //Manual control over settings thanks..... + //These are experimental for now. + bool setVideoSettingFilter(int deviceID, long Property, long lValue, long Flags = 0, bool useDefaultValue = false); + bool setVideoSettingFilterPct(int deviceID, long Property, float pctValue, long Flags = 0); + bool getVideoSettingFilter(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long ¤tValue, long &flags, long &defaultValue); + + bool setVideoSettingCamera(int deviceID, long Property, long lValue, long Flags = 0, bool useDefaultValue = false); + bool setVideoSettingCameraPct(int deviceID, long Property, float pctValue, long Flags = 0); + bool getVideoSettingCamera(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long ¤tValue, long &flags, long &defaultValue); + + //bool setVideoSettingCam(int deviceID, long Property, long lValue, long Flags = NULL, bool useDefaultValue = false); + + //get width, height and number of pixels + int getWidth(int deviceID); + int getHeight(int deviceID); + int getSize(int deviceID); + int getFourcc(int deviceID); + double getFPS(int deviceID); + + //completely stops and frees a device + void stopDevice(int deviceID); + + //as above but then sets it up with same settings + bool restartDevice(int deviceID); + + //number of devices available + int devicesFound; + + // mapping from OpenCV CV_CAP_PROP to videoinput/dshow properties + int getVideoPropertyFromCV(int cv_property); + int getCameraPropertyFromCV(int cv_property); + + private: + void setPhyCon(int deviceID, int conn); + void setAttemptCaptureSize(int deviceID, int w, int h,GUID mediaType=MEDIASUBTYPE_RGB24); + bool setup(int deviceID); + void processPixels(unsigned char * src, unsigned char * dst, int width, int height, bool bRGB, bool bFlip); + int start(int deviceID, videoDevice * VD); + int getDeviceCount(); + void getMediaSubtypeAsString(GUID type, char * typeAsString); + GUID *getMediaSubtypeFromFourcc(int fourcc); + int getFourccFromMediaSubtype(GUID type); + + void getVideoPropertyAsString(int prop, char * propertyAsString); + void getCameraPropertyAsString(int prop, char * propertyAsString); + + HRESULT getDevice(IBaseFilter **pSrcFilter, int deviceID, WCHAR * wDeviceName, char * nDeviceName); + static HRESULT ShowFilterPropertyPages(IBaseFilter *pFilter); + static HRESULT ShowStreamPropertyPages(IAMStreamConfig *pStream); + + HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath); + HRESULT routeCrossbar(ICaptureGraphBuilder2 **ppBuild, IBaseFilter **pVidInFilter, int conType, GUID captureMode); + + //don't touch + static bool comInit(); + static bool comUnInit(); + + int connection; + int callbackSetCount; + bool bCallback; + + GUID CAPTURE_MODE; + + //Extra video subtypes + GUID MEDIASUBTYPE_Y800; + GUID MEDIASUBTYPE_Y8; + GUID MEDIASUBTYPE_GREY; + + videoDevice * VDList[VI_MAX_CAMERAS]; + GUID mediaSubtypes[VI_NUM_TYPES]; + long formatTypes[VI_NUM_FORMATS]; + + static void __cdecl basicThread(void * objPtr); + + static char deviceNames[VI_MAX_CAMERAS][255]; + +}; + +/////////////////////////// HANDY FUNCTIONS ///////////////////////////// + +static void MyFreeMediaType(AM_MEDIA_TYPE& mt){ + if (mt.cbFormat != 0) + { + CoTaskMemFree((PVOID)mt.pbFormat); + mt.cbFormat = 0; + mt.pbFormat = NULL; + } + if (mt.pUnk != NULL) + { + // Unecessary because pUnk should not be used, but safest. + mt.pUnk->Release(); + mt.pUnk = NULL; + } +} + +static void MyDeleteMediaType(AM_MEDIA_TYPE *pmt) +{ + if (pmt != NULL) + { + MyFreeMediaType(*pmt); + CoTaskMemFree(pmt); + } +} + +////////////////////////////// CALLBACK //////////////////////////////// + +//Callback class +class SampleGrabberCallback : public ISampleGrabberCB{ +public: + + //------------------------------------------------ + SampleGrabberCallback(){ + InitializeCriticalSection(&critSection); + freezeCheck = 0; + + + bufferSetup = false; + newFrame = false; + latestBufferLength = 0; + + hEvent = CreateEvent(NULL, true, false, NULL); + } + + + //------------------------------------------------ + virtual ~SampleGrabberCallback(){ + ptrBuffer = NULL; + DeleteCriticalSection(&critSection); + CloseHandle(hEvent); + if(bufferSetup){ + delete[] pixels; + } + } + + + //------------------------------------------------ + bool setupBuffer(int numBytesIn){ + if(bufferSetup){ + return false; + }else{ + numBytes = numBytesIn; + pixels = new unsigned char[numBytes]; + bufferSetup = true; + newFrame = false; + latestBufferLength = 0; + } + return true; + } + + + //------------------------------------------------ + STDMETHODIMP_(ULONG) AddRef() { return 1; } + STDMETHODIMP_(ULONG) Release() { return 2; } + + + //------------------------------------------------ + STDMETHODIMP QueryInterface(REFIID, void **ppvObject){ + *ppvObject = static_cast(this); + return S_OK; + } + + + //This method is meant to have less overhead + //------------------------------------------------ + STDMETHODIMP SampleCB(double , IMediaSample *pSample){ + if(WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0) return S_OK; + + HRESULT hr = pSample->GetPointer(&ptrBuffer); + + if(hr == S_OK){ + latestBufferLength = pSample->GetActualDataLength(); + if(latestBufferLength == numBytes){ + EnterCriticalSection(&critSection); + memcpy(pixels, ptrBuffer, latestBufferLength); + newFrame = true; + freezeCheck = 1; + LeaveCriticalSection(&critSection); + SetEvent(hEvent); + }else{ + printf("ERROR: SampleCB() - buffer sizes do not match\n"); + } + } + + return S_OK; + } + + + //This method is meant to have more overhead + STDMETHODIMP BufferCB(double, BYTE *, long){ + return E_NOTIMPL; + } + + int freezeCheck; + + int latestBufferLength; + int numBytes; + bool newFrame; + bool bufferSetup; + unsigned char * pixels; + unsigned char * ptrBuffer; + CRITICAL_SECTION critSection; + HANDLE hEvent; +}; + + +////////////////////////////// VIDEO DEVICE //////////////////////////////// + +// ---------------------------------------------------------------------- +// Should this class also be the callback? +// +// ---------------------------------------------------------------------- + +videoDevice::videoDevice(){ + + pCaptureGraph = NULL; // Capture graph builder object + pGraph = NULL; // Graph builder object + pControl = NULL; // Media control object + pVideoInputFilter = NULL; // Video Capture filter + pGrabber = NULL; // Grabs frame + pDestFilter = NULL; // Null Renderer Filter + pGrabberF = NULL; // Grabber Filter + pMediaEvent = NULL; + streamConf = NULL; + pAmMediaType = NULL; + + //This is our callback class that processes the frame. + sgCallback = new SampleGrabberCallback(); + sgCallback->newFrame = false; + + //Default values for capture type + videoType = MEDIASUBTYPE_RGB24; + connection = PhysConn_Video_Composite; + storeConn = 0; + + videoSize = 0; + width = 0; + height = 0; + + tryWidth = 640; + tryHeight = 480; + tryVideoType = MEDIASUBTYPE_RGB24; + nFramesForReconnect= 10000; + nFramesRunning = 0; + myID = -1; + + tryDiffSize = true; + useCrossbar = false; + readyToCapture = false; + sizeSet = false; + setupStarted = false; + specificFormat = false; + autoReconnect = false; + requestedFrameTime = -1; + + memset(wDeviceName, 0, sizeof(WCHAR) * 255); + memset(nDeviceName, 0, sizeof(char) * 255); + +} + + +// ---------------------------------------------------------------------- +// The only place we are doing new +// +// ---------------------------------------------------------------------- + +void videoDevice::setSize(int w, int h){ + if(sizeSet){ + if(verbose)printf("SETUP: Error device size should not be set more than once \n"); + } + else + { + width = w; + height = h; + videoSize = w*h*3; + sizeSet = true; + pixels = new unsigned char[videoSize]; + pBuffer = new char[videoSize]; + + memset(pixels, 0 , videoSize); + sgCallback->setupBuffer(videoSize); + + } +} + + +// ---------------------------------------------------------------------- +// Borrowed from the SDK, use it to take apart the graph from +// the capture device downstream to the null renderer +// ---------------------------------------------------------------------- + +void videoDevice::NukeDownstream(IBaseFilter *pBF){ + IPin *pP, *pTo; + ULONG u; + IEnumPins *pins = NULL; + PIN_INFO pininfo; + HRESULT hr = pBF->EnumPins(&pins); + pins->Reset(); + while (hr == NOERROR) + { + hr = pins->Next(1, &pP, &u); + if (hr == S_OK && pP) + { + pP->ConnectedTo(&pTo); + if (pTo) + { + hr = pTo->QueryPinInfo(&pininfo); + if (hr == NOERROR) + { + if (pininfo.dir == PINDIR_INPUT) + { + NukeDownstream(pininfo.pFilter); + pGraph->Disconnect(pTo); + pGraph->Disconnect(pP); + pGraph->RemoveFilter(pininfo.pFilter); + } + pininfo.pFilter->Release(); + pininfo.pFilter = NULL; + } + pTo->Release(); + } + pP->Release(); + } + } + if (pins) pins->Release(); +} + + +// ---------------------------------------------------------------------- +// Also from SDK +// ---------------------------------------------------------------------- + +void videoDevice::destroyGraph(){ + HRESULT hr = 0; + //int FuncRetval=0; + //int NumFilters=0; + + int i = 0; + while (hr == NOERROR) + { + IEnumFilters * pEnum = 0; + ULONG cFetched; + + // We must get the enumerator again every time because removing a filter from the graph + // invalidates the enumerator. We always get only the first filter from each enumerator. + hr = pGraph->EnumFilters(&pEnum); + if (FAILED(hr)) { if(verbose)printf("SETUP: pGraph->EnumFilters() failed. \n"); return; } + + IBaseFilter * pFilter = NULL; + if (pEnum->Next(1, &pFilter, &cFetched) == S_OK) + { + FILTER_INFO FilterInfo; + memset(&FilterInfo, 0, sizeof(FilterInfo)); + hr = pFilter->QueryFilterInfo(&FilterInfo); + FilterInfo.pGraph->Release(); + + int count = 0; + char buffer[255]; + memset(buffer, 0, 255 * sizeof(char)); + + while( FilterInfo.achName[count] != 0x00 ) + { + buffer[count] = (char)FilterInfo.achName[count]; + count++; + } + + if(verbose)printf("SETUP: removing filter %s...\n", buffer); + hr = pGraph->RemoveFilter(pFilter); + if (FAILED(hr)) { if(verbose)printf("SETUP: pGraph->RemoveFilter() failed. \n"); return; } + if(verbose)printf("SETUP: filter removed %s \n",buffer); + + pFilter->Release(); + pFilter = NULL; + } + else break; + pEnum->Release(); + pEnum = NULL; + i++; + } + + return; +} + + +// ---------------------------------------------------------------------- +// Our deconstructor, attempts to tear down graph and release filters etc +// Does checking to make sure it only is freeing if it needs to +// Probably could be a lot cleaner! :) +// ---------------------------------------------------------------------- + +videoDevice::~videoDevice(){ + + if(setupStarted){ if(verbose)printf("\nSETUP: Disconnecting device %i\n", myID); } + else{ + if(sgCallback){ + sgCallback->Release(); + delete sgCallback; + } + return; + } + + HRESULT HR = NOERROR; + + //Stop the callback and free it + if( (sgCallback) && (pGrabber) ) + { + pGrabber->SetCallback(NULL, 1); + if(verbose)printf("SETUP: freeing Grabber Callback\n"); + sgCallback->Release(); + + //delete our pixels + if(sizeSet){ + delete[] pixels; + delete[] pBuffer; + } + + delete sgCallback; + } + + //Check to see if the graph is running, if so stop it. + if( (pControl) ) + { + HR = pControl->Pause(); + if (FAILED(HR)) if(verbose)printf("ERROR - Could not pause pControl\n"); + + HR = pControl->Stop(); + if (FAILED(HR)) if(verbose)printf("ERROR - Could not stop pControl\n"); + } + + //Disconnect filters from capture device + if( (pVideoInputFilter) )NukeDownstream(pVideoInputFilter); + + //Release and zero pointers to our filters etc + if( (pDestFilter) ){ if(verbose)printf("SETUP: freeing Renderer \n"); + (pDestFilter)->Release(); + (pDestFilter) = 0; + } + if( (pVideoInputFilter) ){ if(verbose)printf("SETUP: freeing Capture Source \n"); + (pVideoInputFilter)->Release(); + (pVideoInputFilter) = 0; + } + if( (pGrabberF) ){ if(verbose)printf("SETUP: freeing Grabber Filter \n"); + (pGrabberF)->Release(); + (pGrabberF) = 0; + } + if( (pGrabber) ){ if(verbose)printf("SETUP: freeing Grabber \n"); + (pGrabber)->Release(); + (pGrabber) = 0; + } + if( (pControl) ){ if(verbose)printf("SETUP: freeing Control \n"); + (pControl)->Release(); + (pControl) = 0; + } + if( (pMediaEvent) ){ if(verbose)printf("SETUP: freeing Media Event \n"); + (pMediaEvent)->Release(); + (pMediaEvent) = 0; + } + if( (streamConf) ){ if(verbose)printf("SETUP: freeing Stream \n"); + (streamConf)->Release(); + (streamConf) = 0; + } + + if( (pAmMediaType) ){ if(verbose)printf("SETUP: freeing Media Type \n"); + MyDeleteMediaType(pAmMediaType); + } + + if((pMediaEvent)){ + if(verbose)printf("SETUP: freeing Media Event \n"); + (pMediaEvent)->Release(); + (pMediaEvent) = 0; + } + + //Destroy the graph + if( (pGraph) )destroyGraph(); + + //Release and zero our capture graph and our main graph + if( (pCaptureGraph) ){ if(verbose)printf("SETUP: freeing Capture Graph \n"); + (pCaptureGraph)->Release(); + (pCaptureGraph) = 0; + } + if( (pGraph) ){ if(verbose)printf("SETUP: freeing Main Graph \n"); + (pGraph)->Release(); + (pGraph) = 0; + } + + //delete our pointers + delete pDestFilter; + delete pVideoInputFilter; + delete pGrabberF; + delete pGrabber; + delete pControl; + delete streamConf; + delete pMediaEvent; + delete pCaptureGraph; + delete pGraph; + + if(verbose)printf("SETUP: Device %i disconnected and freed\n\n",myID); +} + + +////////////////////////////// VIDEO INPUT //////////////////////////////// +//////////////////////////// PUBLIC METHODS /////////////////////////////// + + +// ---------------------------------------------------------------------- +// Constructor - creates instances of videoDevice and adds the various +// media subtypes to check. +// ---------------------------------------------------------------------- + +videoInput::videoInput(){ + //start com + comInit(); + + devicesFound = 0; + callbackSetCount = 0; + bCallback = true; + + //setup a max no of device objects + for(int i=0; i= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return; + + if( idealFramerate > 0 ){ + VDList[deviceNumber]->requestedFrameTime = (unsigned long)(10000000 / idealFramerate); + } +} + + +// ---------------------------------------------------------------------- +// Set the requested framerate - no guarantee you will get this +// +// ---------------------------------------------------------------------- + +void videoInput::setAutoReconnectOnFreeze(int deviceNumber, bool doReconnect, int numMissedFramesBeforeReconnect){ + if(deviceNumber >= VI_MAX_CAMERAS) return; + + VDList[deviceNumber]->autoReconnect = doReconnect; + VDList[deviceNumber]->nFramesForReconnect = numMissedFramesBeforeReconnect; + +} + + +// ---------------------------------------------------------------------- +// Setup a device with the default settings +// +// ---------------------------------------------------------------------- + +bool videoInput::setupDevice(int deviceNumber){ + if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false; + + if(setup(deviceNumber))return true; + return false; +} + + +// ---------------------------------------------------------------------- +// Setup a device with the default size but specify input type +// +// ---------------------------------------------------------------------- + +bool videoInput::setupDevice(int deviceNumber, int _connection){ + if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false; + + setPhyCon(deviceNumber, _connection); + if(setup(deviceNumber))return true; + return false; +} + + +// ---------------------------------------------------------------------- +// Setup a device with the default connection but specify size +// +// ---------------------------------------------------------------------- + +bool videoInput::setupDevice(int deviceNumber, int w, int h){ + if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false; + + setAttemptCaptureSize(deviceNumber,w,h); + if(setup(deviceNumber))return true; + return false; +} + +// ---------------------------------------------------------------------- +// Setup a device with the default connection but specify size and image format +// +// Note: +// Need a new name for this since signature clashes with ",int connection)" +// ---------------------------------------------------------------------- + +bool videoInput::setupDeviceFourcc(int deviceNumber, int w, int h,int fourcc){ + if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false; + + if ( fourcc > 0 ) { + GUID *mediaType = getMediaSubtypeFromFourcc(fourcc); + if ( mediaType ) { + setAttemptCaptureSize(deviceNumber,w,h,*mediaType); + } + } else { + setAttemptCaptureSize(deviceNumber,w,h); + } + if(setup(deviceNumber))return true; + return false; +} + + +// ---------------------------------------------------------------------- +// Setup a device with specific size and connection +// +// ---------------------------------------------------------------------- + +bool videoInput::setupDevice(int deviceNumber, int w, int h, int _connection){ + if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false; + + setAttemptCaptureSize(deviceNumber,w,h); + setPhyCon(deviceNumber, _connection); + if(setup(deviceNumber))return true; + return false; +} + + +// ---------------------------------------------------------------------- +// Setup the default video format of the device +// Must be called after setup! +// See #define formats in header file (eg VI_NTSC_M ) +// +// ---------------------------------------------------------------------- + +bool videoInput::setFormat(int deviceNumber, int format){ + if(deviceNumber >= VI_MAX_CAMERAS || !VDList[deviceNumber]->readyToCapture) return false; + + bool returnVal = false; + + if(format >= 0 && format < VI_NUM_FORMATS){ + VDList[deviceNumber]->formatType = formatTypes[format]; + VDList[deviceNumber]->specificFormat = true; + + if(VDList[deviceNumber]->specificFormat){ + + HRESULT hr = getDevice(&VDList[deviceNumber]->pVideoInputFilter, deviceNumber, VDList[deviceNumber]->wDeviceName, VDList[deviceNumber]->nDeviceName); + if(hr != S_OK){ + return false; + } + + IAMAnalogVideoDecoder *pVideoDec = NULL; + hr = VDList[deviceNumber]->pCaptureGraph->FindInterface(NULL, &MEDIATYPE_Video, VDList[deviceNumber]->pVideoInputFilter, IID_IAMAnalogVideoDecoder, (void **)&pVideoDec); + + + //in case the settings window some how freed them first + if(VDList[deviceNumber]->pVideoInputFilter)VDList[deviceNumber]->pVideoInputFilter->Release(); + if(VDList[deviceNumber]->pVideoInputFilter)VDList[deviceNumber]->pVideoInputFilter = NULL; + + if(FAILED(hr)){ + printf("SETUP: couldn't set requested format\n"); + }else{ + long lValue = 0; + hr = pVideoDec->get_AvailableTVFormats(&lValue); + if( SUCCEEDED(hr) && (lValue & VDList[deviceNumber]->formatType) ) + { + hr = pVideoDec->put_TVFormat(VDList[deviceNumber]->formatType); + if( FAILED(hr) ){ + printf("SETUP: couldn't set requested format\n"); + }else{ + returnVal = true; + } + } + + pVideoDec->Release(); + pVideoDec = NULL; + } + } + } + + return returnVal; +} + +// ---------------------------------------------------------------------- +// Our static function for returning device names - thanks Peter! +// Must call listDevices first. +// +// ---------------------------------------------------------------------- +char videoInput::deviceNames[VI_MAX_CAMERAS][255]={{0}}; + +char * videoInput::getDeviceName(int deviceID){ + if( deviceID >= VI_MAX_CAMERAS ){ + return NULL; + } + return deviceNames[deviceID]; +} + + +// ---------------------------------------------------------------------- +// Our static function for finding num devices available etc +// +// ---------------------------------------------------------------------- + +int videoInput::listDevices(bool silent){ + + //COM Library Intialization + comInit(); + + if(!silent)printf("\nVIDEOINPUT SPY MODE!\n\n"); + + + ICreateDevEnum *pDevEnum = NULL; + IEnumMoniker *pEnum = NULL; + int deviceCounter = 0; + + HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, + CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, + reinterpret_cast(&pDevEnum)); + + + if (SUCCEEDED(hr)) + { + // Create an enumerator for the video capture category. + hr = pDevEnum->CreateClassEnumerator( + CLSID_VideoInputDeviceCategory, + &pEnum, 0); + + if(hr == S_OK){ + + if(!silent)printf("SETUP: Looking For Capture Devices\n"); + IMoniker *pMoniker = NULL; + + while (pEnum->Next(1, &pMoniker, NULL) == S_OK){ + + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, + (void**)(&pPropBag)); + + if (FAILED(hr)){ + pMoniker->Release(); + continue; // Skip this one, maybe the next one will work. + } + + + // Find the description or friendly name. + VARIANT varName; + VariantInit(&varName); + hr = pPropBag->Read(L"Description", &varName, 0); + + if (FAILED(hr)) hr = pPropBag->Read(L"FriendlyName", &varName, 0); + + if (SUCCEEDED(hr)){ + + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + + int count = 0; + int maxLen = sizeof(deviceNames[0])/sizeof(deviceNames[0][0]) - 2; + while( varName.bstrVal[count] != 0x00 && count < maxLen) { + deviceNames[deviceCounter][count] = (char)varName.bstrVal[count]; + count++; + } + deviceNames[deviceCounter][count] = 0; + + if(!silent)printf("SETUP: %i) %s \n",deviceCounter, deviceNames[deviceCounter]); + } + + pPropBag->Release(); + pPropBag = NULL; + + pMoniker->Release(); + pMoniker = NULL; + + deviceCounter++; + } + + pDevEnum->Release(); + pDevEnum = NULL; + + pEnum->Release(); + pEnum = NULL; + } + + if(!silent)printf("SETUP: %i Device(s) found\n\n", deviceCounter); + } + + comUnInit(); + + return deviceCounter; +} + + +// ---------------------------------------------------------------------- +// +// +// ---------------------------------------------------------------------- + +int videoInput::getWidth(int id){ + + if(isDeviceSetup(id)) + { + return VDList[id] ->width; + } + + return 0; + +} + + +// ---------------------------------------------------------------------- +// +// +// ---------------------------------------------------------------------- + +int videoInput::getHeight(int id){ + + if(isDeviceSetup(id)) + { + return VDList[id] ->height; + } + + return 0; + +} + +// ---------------------------------------------------------------------- +// +// +// ---------------------------------------------------------------------- +int videoInput::getFourcc(int id){ + + if(isDeviceSetup(id)) + { + return getFourccFromMediaSubtype(VDList[id]->videoType); + } + + return 0; + +} + +double videoInput::getFPS(int id){ + + if(isDeviceSetup(id)) + { + double frameTime= VDList[id]->requestedFrameTime; + if (frameTime>0) { + return (10000000.0 / frameTime); + } + } + + return 0; + +} + + +// ---------------------------------------------------------------------- +// +// +// ---------------------------------------------------------------------- + +int videoInput::getSize(int id){ + + if(isDeviceSetup(id)) + { + return VDList[id] ->videoSize; + } + + return 0; + +} + + +// ---------------------------------------------------------------------- +// Uses a supplied buffer +// ---------------------------------------------------------------------- + +bool videoInput::getPixels(int id, unsigned char * dstBuffer, bool flipRedAndBlue, bool flipImage){ + + bool success = false; + + if(isDeviceSetup(id)){ + if(bCallback){ + //callback capture + + DWORD result = WaitForSingleObject(VDList[id]->sgCallback->hEvent, 1000); + if( result != WAIT_OBJECT_0) return false; + + //double paranoia - mutexing with both event and critical section + EnterCriticalSection(&VDList[id]->sgCallback->critSection); + + unsigned char * src = VDList[id]->sgCallback->pixels; + unsigned char * dst = dstBuffer; + int height = VDList[id]->height; + int width = VDList[id]->width; + + processPixels(src, dst, width, height, flipRedAndBlue, flipImage); + VDList[id]->sgCallback->newFrame = false; + + LeaveCriticalSection(&VDList[id]->sgCallback->critSection); + + ResetEvent(VDList[id]->sgCallback->hEvent); + + success = true; + + } + else{ + //regular capture method + long bufferSize = VDList[id]->videoSize; + HRESULT hr = VDList[id]->pGrabber->GetCurrentBuffer(&bufferSize, (long *)VDList[id]->pBuffer); + if(hr==S_OK){ + int numBytes = VDList[id]->videoSize; + if (numBytes == bufferSize){ + + unsigned char * src = (unsigned char * )VDList[id]->pBuffer; + unsigned char * dst = dstBuffer; + int height = VDList[id]->height; + int width = VDList[id]->width; + + processPixels(src, dst, width, height, flipRedAndBlue, flipImage); + success = true; + }else{ + if(verbose)printf("ERROR: GetPixels() - bufferSizes do not match!\n"); + } + }else{ + if(verbose)printf("ERROR: GetPixels() - Unable to grab frame for device %i\n", id); + } + } + } + + return success; +} + + +// ---------------------------------------------------------------------- +// Returns a buffer +// ---------------------------------------------------------------------- +unsigned char * videoInput::getPixels(int id, bool flipRedAndBlue, bool flipImage){ + + if(isDeviceSetup(id)){ + getPixels(id, VDList[id]->pixels, flipRedAndBlue, flipImage); + } + + return VDList[id]->pixels; +} + + + +// ---------------------------------------------------------------------- +// +// +// ---------------------------------------------------------------------- +bool videoInput::isFrameNew(int id){ + if(!isDeviceSetup(id)) return false; + if(!bCallback)return true; + + bool result = false; + bool freeze = false; + + //again super paranoia! + EnterCriticalSection(&VDList[id]->sgCallback->critSection); + result = VDList[id]->sgCallback->newFrame; + + //we need to give it some time at the begining to start up so lets check after 400 frames + if(VDList[id]->nFramesRunning > 400 && VDList[id]->sgCallback->freezeCheck > VDList[id]->nFramesForReconnect ){ + freeze = true; + } + + //we increment the freezeCheck var here - the callback resets it to 1 + //so as long as the callback is running this var should never get too high. + //if the callback is not running then this number will get high and trigger the freeze action below + VDList[id]->sgCallback->freezeCheck++; + LeaveCriticalSection(&VDList[id]->sgCallback->critSection); + + VDList[id]->nFramesRunning++; + + if(freeze && VDList[id]->autoReconnect){ + if(verbose)printf("ERROR: Device seems frozen - attempting to reconnect\n"); + if( !restartDevice(VDList[id]->myID) ){ + if(verbose)printf("ERROR: Unable to reconnect to device\n"); + }else{ + if(verbose)printf("SUCCESS: Able to reconnect to device\n"); + } + } + + return result; +} + + +// ---------------------------------------------------------------------- +// +// +// ---------------------------------------------------------------------- + +bool videoInput::isDeviceSetup(int id){ + + if(idreadyToCapture)return true; + else return false; + +} + + +// ---------------------------------------------------------------------- +// Gives us a little pop up window to adjust settings +// We do this in a seperate thread now! +// ---------------------------------------------------------------------- + + +void __cdecl videoInput::basicThread(void * objPtr){ + + //get a reference to the video device + //not a copy as we need to free the filter + videoDevice * vd = *( (videoDevice **)(objPtr) ); + ShowFilterPropertyPages(vd->pVideoInputFilter); + + + + //now we free the filter and make sure it set to NULL + if(vd->pVideoInputFilter)vd->pVideoInputFilter->Release(); + if(vd->pVideoInputFilter)vd->pVideoInputFilter = NULL; + + return; +} + +void videoInput::showSettingsWindow(int id){ + + if(isDeviceSetup(id)){ + //HANDLE myTempThread; + + //we reconnect to the device as we have freed our reference to it + //why have we freed our reference? because there seemed to be an issue + //with some mpeg devices if we didn't + HRESULT hr = getDevice(&VDList[id]->pVideoInputFilter, id, VDList[id]->wDeviceName, VDList[id]->nDeviceName); + if(hr == S_OK){ + //myTempThread = (HANDLE) + _beginthread(basicThread, 0, (void *)&VDList[id]); + } + } +} + + +// Set a video signal setting using IAMVideoProcAmp +bool videoInput::getVideoSettingFilter(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long ¤tValue, long &flags, long &defaultValue){ + if( !isDeviceSetup(deviceID) )return false; + + HRESULT hr; + //bool isSuccessful = false; + + videoDevice * VD = VDList[deviceID]; + + hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName); + if (FAILED(hr)){ + printf("setVideoSetting - getDevice Error\n"); + return false; + } + + IAMVideoProcAmp *pAMVideoProcAmp = NULL; + + hr = VD->pVideoInputFilter->QueryInterface(IID_IAMVideoProcAmp, (void**)&pAMVideoProcAmp); + if(FAILED(hr)){ + printf("setVideoSetting - QueryInterface Error\n"); + if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release(); + if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; + return false; + } + + char propStr[16]; + getVideoPropertyAsString(Property,propStr); + + if (verbose) printf("Setting video setting %s.\n", propStr); + + pAMVideoProcAmp->GetRange(Property, &min, &max, &SteppingDelta, &defaultValue, &flags); + if (verbose) printf("Range for video setting %s: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", propStr, min, max, SteppingDelta, defaultValue, flags); + pAMVideoProcAmp->Get(Property, ¤tValue, &flags); + + if(pAMVideoProcAmp)pAMVideoProcAmp->Release(); + if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release(); + if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; + + return true; + +} + + +// Set a video signal setting using IAMVideoProcAmp +bool videoInput::setVideoSettingFilterPct(int deviceID, long Property, float pctValue, long Flags){ + if( !isDeviceSetup(deviceID) )return false; + + long min, max, currentValue, flags, defaultValue, stepAmnt; + + if( !getVideoSettingFilter(deviceID, Property, min, max, stepAmnt, currentValue, flags, defaultValue) )return false; + + if(pctValue > 1.0)pctValue = 1.0; + else if(pctValue < 0)pctValue = 0.0; + + float range = (float)max - (float)min; + if(range <= 0)return false; + if(stepAmnt == 0) return false; + + long value = (long)( (float)min + range * pctValue ); + long rasterValue = value; + + //if the range is the stepAmnt then it is just a switch + //so we either set the value to low or high + if( range == stepAmnt ){ + if( pctValue < 0.5)rasterValue = min; + else rasterValue = max; + }else{ + //we need to rasterize the value to the stepping amnt + long mod = value % stepAmnt; + float halfStep = (float)stepAmnt * 0.5f; + if( mod < halfStep ) rasterValue -= mod; + else rasterValue += stepAmnt - mod; + printf("RASTER - pctValue is %f - value is %li - step is %li - mod is %li - rasterValue is %li\n", pctValue, value, stepAmnt, mod, rasterValue); + } + + return setVideoSettingFilter(deviceID, Property, rasterValue, Flags, false); +} + + +// Set a video signal setting using IAMVideoProcAmp +bool videoInput::setVideoSettingFilter(int deviceID, long Property, long lValue, long Flags, bool useDefaultValue){ + if( !isDeviceSetup(deviceID) )return false; + + HRESULT hr; + //bool isSuccessful = false; + + char propStr[16]; + getVideoPropertyAsString(Property,propStr); + + videoDevice * VD = VDList[deviceID]; + + hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName); + if (FAILED(hr)){ + printf("setVideoSetting - getDevice Error\n"); + return false; + } + + IAMVideoProcAmp *pAMVideoProcAmp = NULL; + + hr = VD->pVideoInputFilter->QueryInterface(IID_IAMVideoProcAmp, (void**)&pAMVideoProcAmp); + if(FAILED(hr)){ + printf("setVideoSetting - QueryInterface Error\n"); + if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release(); + if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; + return false; + } + + if (verbose) printf("Setting video setting %s.\n", propStr); + long CurrVal, Min, Max, SteppingDelta, Default, CapsFlags, AvailableCapsFlags = 0; + + + pAMVideoProcAmp->GetRange(Property, &Min, &Max, &SteppingDelta, &Default, &AvailableCapsFlags); + if (verbose) printf("Range for video setting %s: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", propStr, Min, Max, SteppingDelta, Default, AvailableCapsFlags); + pAMVideoProcAmp->Get(Property, &CurrVal, &CapsFlags); + + if (verbose) printf("Current value: %ld Flags %ld (%s)\n", CurrVal, CapsFlags, (CapsFlags == 1 ? "Auto" : (CapsFlags == 2 ? "Manual" : "Unknown"))); + + if (useDefaultValue) { + pAMVideoProcAmp->Set(Property, Default, VideoProcAmp_Flags_Auto); + } + else{ + // Perhaps add a check that lValue and Flags are within the range aquired from GetRange above + pAMVideoProcAmp->Set(Property, lValue, Flags); + } + + if(pAMVideoProcAmp)pAMVideoProcAmp->Release(); + if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release(); + if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; + + return true; + +} + + +bool videoInput::setVideoSettingCameraPct(int deviceID, long Property, float pctValue, long Flags){ + if( !isDeviceSetup(deviceID) )return false; + + long min, max, currentValue, flags, defaultValue, stepAmnt; + + if( !getVideoSettingCamera(deviceID, Property, min, max, stepAmnt, currentValue, flags, defaultValue) )return false; + + if(pctValue > 1.0)pctValue = 1.0; + else if(pctValue < 0)pctValue = 0.0; + + float range = (float)max - (float)min; + if(range <= 0)return false; + if(stepAmnt == 0) return false; + + long value = (long)( (float)min + range * pctValue ); + long rasterValue = value; + + //if the range is the stepAmnt then it is just a switch + //so we either set the value to low or high + if( range == stepAmnt ){ + if( pctValue < 0.5)rasterValue = min; + else rasterValue = max; + }else{ + //we need to rasterize the value to the stepping amnt + long mod = value % stepAmnt; + float halfStep = (float)stepAmnt * 0.5f; + if( mod < halfStep ) rasterValue -= mod; + else rasterValue += stepAmnt - mod; + printf("RASTER - pctValue is %f - value is %li - step is %li - mod is %li - rasterValue is %li\n", pctValue, value, stepAmnt, mod, rasterValue); + } + + return setVideoSettingCamera(deviceID, Property, rasterValue, Flags, false); +} + + +bool videoInput::setVideoSettingCamera(int deviceID, long Property, long lValue, long Flags, bool useDefaultValue){ + IAMCameraControl *pIAMCameraControl; + if(isDeviceSetup(deviceID)) + { + HRESULT hr; + hr = getDevice(&VDList[deviceID]->pVideoInputFilter, deviceID, VDList[deviceID]->wDeviceName, VDList[deviceID]->nDeviceName); + + char propStr[16]; + getVideoPropertyAsString(Property,propStr); + + if (verbose) printf("Setting video setting %s.\n", propStr); + hr = VDList[deviceID]->pVideoInputFilter->QueryInterface(IID_IAMCameraControl, (void**)&pIAMCameraControl); + if (FAILED(hr)) { + printf("Error\n"); + return false; + } + else + { + long CurrVal, Min, Max, SteppingDelta, Default, CapsFlags, AvailableCapsFlags; + pIAMCameraControl->GetRange(Property, &Min, &Max, &SteppingDelta, &Default, &AvailableCapsFlags); + if (verbose) printf("Range for video setting %s: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", propStr, Min, Max, SteppingDelta, Default, AvailableCapsFlags); + pIAMCameraControl->Get(Property, &CurrVal, &CapsFlags); + if (verbose) printf("Current value: %ld Flags %ld (%s)\n", CurrVal, CapsFlags, (CapsFlags == 1 ? "Auto" : (CapsFlags == 2 ? "Manual" : "Unknown"))); + if (useDefaultValue) { + pIAMCameraControl->Set(Property, Default, CameraControl_Flags_Auto); + } + else + { + // Perhaps add a check that lValue and Flags are within the range aquired from GetRange above + pIAMCameraControl->Set(Property, lValue, Flags); + } + pIAMCameraControl->Release(); + return true; + } + } + return false; +} + + + +bool videoInput::getVideoSettingCamera(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long ¤tValue, long &flags, long &defaultValue){ + if( !isDeviceSetup(deviceID) )return false; + + HRESULT hr; + //bool isSuccessful = false; + + videoDevice * VD = VDList[deviceID]; + + hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName); + if (FAILED(hr)){ + printf("setVideoSetting - getDevice Error\n"); + return false; + } + + IAMCameraControl *pIAMCameraControl = NULL; + + hr = VD->pVideoInputFilter->QueryInterface(IID_IAMCameraControl, (void**)&pIAMCameraControl); + if(FAILED(hr)){ + printf("setVideoSetting - QueryInterface Error\n"); + if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release(); + if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; + return false; + } + + char propStr[16]; + getVideoPropertyAsString(Property,propStr); + if (verbose) printf("Setting video setting %s.\n", propStr); + + pIAMCameraControl->GetRange(Property, &min, &max, &SteppingDelta, &defaultValue, &flags); + if (verbose) printf("Range for video setting %s: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", propStr, min, max, SteppingDelta, defaultValue, flags); + pIAMCameraControl->Get(Property, ¤tValue, &flags); + + if(pIAMCameraControl)pIAMCameraControl->Release(); + if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release(); + if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; + + return true; + +} + + +// ---------------------------------------------------------------------- +// Shutsdown the device, deletes the object and creates a new object +// so it is ready to be setup again +// ---------------------------------------------------------------------- + +void videoInput::stopDevice(int id){ + if(id < VI_MAX_CAMERAS) + { + delete VDList[id]; + VDList[id] = new videoDevice(); + } + +} + +// ---------------------------------------------------------------------- +// Restarts the device with the same settings it was using +// +// ---------------------------------------------------------------------- + +bool videoInput::restartDevice(int id){ + if(isDeviceSetup(id)) + { + int conn = VDList[id]->storeConn; + int tmpW = VDList[id]->width; + int tmpH = VDList[id]->height; + + bool bFormat = VDList[id]->specificFormat; + long format = VDList[id]->formatType; + + int nReconnect = VDList[id]->nFramesForReconnect; + bool bReconnect = VDList[id]->autoReconnect; + + unsigned long avgFrameTime = VDList[id]->requestedFrameTime; + + stopDevice(id); + + //set our fps if needed + if( avgFrameTime != (unsigned long)-1){ + VDList[id]->requestedFrameTime = avgFrameTime; + } + + if( setupDevice(id, tmpW, tmpH, conn) ){ + //reapply the format - ntsc / pal etc + if( bFormat ){ + setFormat(id, format); + } + if( bReconnect ){ + setAutoReconnectOnFreeze(id, true, nReconnect); + } + return true; + } + } + return false; +} + +// ---------------------------------------------------------------------- +// Shuts down all devices, deletes objects and unitializes com if needed +// +// ---------------------------------------------------------------------- +videoInput::~videoInput(){ + + for(int i = 0; i < VI_MAX_CAMERAS; i++) + { + delete VDList[i]; + } + //Unitialize com + comUnInit(); +} + + +////////////////////////////// VIDEO INPUT //////////////////////////////// +//////////////////////////// PRIVATE METHODS ////////////////////////////// + +// ---------------------------------------------------------------------- +// We only should init com if it hasn't been done so by our apps thread +// Use a static counter to keep track of other times it has been inited +// (do we need to worry about multithreaded apps?) +// ---------------------------------------------------------------------- + +bool videoInput::comInit(){ + /*HRESULT hr = NOERROR; + + //no need for us to start com more than once + if(comInitCount == 0 ){ + + // Initialize the COM library. + //CoInitializeEx so videoInput can run in another thread + #ifdef VI_COM_MULTI_THREADED + hr = CoInitializeEx(NULL,COINIT_MULTITHREADED); + #else + hr = CoInitialize(NULL); + #endif + //this is the only case where there might be a problem + //if another library has started com as single threaded + //and we need it multi-threaded - send warning but don't fail + if( hr == RPC_E_CHANGED_MODE){ + if(verbose)printf("SETUP - COM already setup - threaded VI might not be possible\n"); + } + } + + comInitCount++;*/ + return true; +} + + +// ---------------------------------------------------------------------- +// Same as above but to unitialize com, decreases counter and frees com +// if no one else is using it +// ---------------------------------------------------------------------- + +bool videoInput::comUnInit(){ + /*if(comInitCount > 0)comInitCount--; //decrease the count of instances using com + + if(comInitCount == 0){ + CoUninitialize(); //if there are no instances left - uninitialize com + return true; + } + + return false;*/ + return true; +} + + +// ---------------------------------------------------------------------- +// This is the size we ask for - we might not get it though :) +// +// ---------------------------------------------------------------------- + +void videoInput::setAttemptCaptureSize(int id, int w, int h,GUID mediaType){ + + VDList[id]->tryWidth = w; + VDList[id]->tryHeight = h; + VDList[id]->tryDiffSize = true; + VDList[id]->tryVideoType = mediaType; + +} + +// ---------------------------------------------------------------------- +// Set the connection type +// (maybe move to private?) +// ---------------------------------------------------------------------- + +void videoInput::setPhyCon(int id, int conn){ + + switch(conn){ + + case 0: + VDList[id]->connection = PhysConn_Video_Composite; + break; + case 1: + VDList[id]->connection = PhysConn_Video_SVideo; + break; + case 2: + VDList[id]->connection = PhysConn_Video_Tuner; + break; + case 3: + VDList[id]->connection = PhysConn_Video_USB; + break; + case 4: + VDList[id]->connection = PhysConn_Video_1394; + break; + default: + return; //if it is not these types don't set crossbar + break; + } + + VDList[id]->storeConn = conn; + VDList[id]->useCrossbar = true; +} + + +// ---------------------------------------------------------------------- +// Check that we are not trying to setup a non-existant device +// Then start the graph building! +// ---------------------------------------------------------------------- + +bool videoInput::setup(int deviceNumber){ + devicesFound = getDeviceCount(); + + if(deviceNumber>devicesFound-1) + { + if(verbose)printf("SETUP: device[%i] not found - you have %i devices available\n", deviceNumber, devicesFound); + if(devicesFound>=0) if(verbose)printf("SETUP: this means that the last device you can use is device[%i] \n", devicesFound-1); + return false; + } + + if(VDList[deviceNumber]->readyToCapture) + { + if(verbose)printf("SETUP: can't setup, device %i is currently being used\n",VDList[deviceNumber]->myID); + return false; + } + + HRESULT hr = start(deviceNumber, VDList[deviceNumber]); + if(hr == S_OK)return true; + else return false; +} + + +// ---------------------------------------------------------------------- +// Does both vertical buffer flipping and bgr to rgb swapping +// You have any combination of those. +// ---------------------------------------------------------------------- + +void videoInput::processPixels(unsigned char * src, unsigned char * dst, int width, int height, bool bRGB, bool bFlip){ + + int widthInBytes = width * 3; + int numBytes = widthInBytes * height; + + if(!bRGB){ + + //int x = 0; + //int y = 0; + + if(bFlip){ + for(int y = 0; y < height; y++){ + memcpy(dst + (y * widthInBytes), src + ( (height -y -1) * widthInBytes), widthInBytes); + } + + }else{ + memcpy(dst, src, numBytes); + } + }else{ + if(bFlip){ + + int x = 0; + int y = (height - 1) * widthInBytes; + src += y; + + for(int i = 0; i < numBytes; i+=3){ + if(x >= width){ + x = 0; + src -= widthInBytes*2; + } + + *dst = *(src+2); + dst++; + + *dst = *(src+1); + dst++; + + *dst = *src; + dst++; + + src+=3; + x++; + } + } + else{ + for(int i = 0; i < numBytes; i+=3){ + *dst = *(src+2); + dst++; + + *dst = *(src+1); + dst++; + + *dst = *src; + dst++; + + src+=3; + } + } + } +} + + +//------------------------------------------------------------------------------------------ +void videoInput::getMediaSubtypeAsString(GUID type, char * typeAsString){ + + char tmpStr[8]; + if( type == MEDIASUBTYPE_RGB24) sprintf(tmpStr, "RGB24"); + else if(type == MEDIASUBTYPE_RGB32) sprintf(tmpStr, "RGB32"); + else if(type == MEDIASUBTYPE_RGB555)sprintf(tmpStr, "RGB555"); + else if(type == MEDIASUBTYPE_RGB565)sprintf(tmpStr, "RGB565"); + else if(type == MEDIASUBTYPE_YUY2) sprintf(tmpStr, "YUY2"); + else if(type == MEDIASUBTYPE_YVYU) sprintf(tmpStr, "YVYU"); + else if(type == MEDIASUBTYPE_YUYV) sprintf(tmpStr, "YUYV"); + else if(type == MEDIASUBTYPE_IYUV) sprintf(tmpStr, "IYUV"); + else if(type == MEDIASUBTYPE_UYVY) sprintf(tmpStr, "UYVY"); + else if(type == MEDIASUBTYPE_YV12) sprintf(tmpStr, "YV12"); + else if(type == MEDIASUBTYPE_YVU9) sprintf(tmpStr, "YVU9"); + else if(type == MEDIASUBTYPE_Y411) sprintf(tmpStr, "Y411"); + else if(type == MEDIASUBTYPE_Y41P) sprintf(tmpStr, "Y41P"); + else if(type == MEDIASUBTYPE_Y211) sprintf(tmpStr, "Y211"); + else if(type == MEDIASUBTYPE_AYUV) sprintf(tmpStr, "AYUV"); + else if(type == MEDIASUBTYPE_MJPG) sprintf(tmpStr, "MJPG"); + else if(type == MEDIASUBTYPE_Y800) sprintf(tmpStr, "Y800"); + else if(type == MEDIASUBTYPE_Y8) sprintf(tmpStr, "Y8"); + else if(type == MEDIASUBTYPE_GREY) sprintf(tmpStr, "GREY"); + else if(type == MEDIASUBTYPE_I420) sprintf(tmpStr, "I420"); + else sprintf(tmpStr, "OTHER"); + + memcpy(typeAsString, tmpStr, sizeof(char)*8); +} + +int videoInput::getFourccFromMediaSubtype(GUID type) { + return type.Data1; +} + +GUID *videoInput::getMediaSubtypeFromFourcc(int fourcc){ + + for (int i=0;istreamConf->GetNumberOfCapabilities(&iCount, &iSize); + + if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) + { + //For each format type RGB24 YUV2 etc + for (int iFormat = 0; iFormat < iCount; iFormat++) + { + VIDEO_STREAM_CONFIG_CAPS scc; + AM_MEDIA_TYPE *pmtConfig; + hr = VD->streamConf->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc); + + if (SUCCEEDED(hr)){ + + //his is how many diff sizes are available for the format + int stepX = scc.OutputGranularityX; + int stepY = scc.OutputGranularityY; + + int tempW = 999999; + int tempH = 999999; + + //Don't want to get stuck in a loop + if(stepX < 1 || stepY < 1) continue; + + //if(verbose)printf("min is %i %i max is %i %i - res is %i %i \n", scc.MinOutputSize.cx, scc.MinOutputSize.cy, scc.MaxOutputSize.cx, scc.MaxOutputSize.cy, stepX, stepY); + //if(verbose)printf("min frame duration is %i max duration is %i\n", scc.MinFrameInterval, scc.MaxFrameInterval); + + bool exactMatch = false; + bool exactMatchX = false; + bool exactMatchY = false; + + for(int x = scc.MinOutputSize.cx; x <= scc.MaxOutputSize.cx; x+= stepX){ + //If we find an exact match + if( widthIn == x ){ + exactMatchX = true; + tempW = x; + } + //Otherwise lets find the closest match based on width + else if( abs(widthIn-x) < abs(widthIn-tempW) ){ + tempW = x; + } + } + + for(int y = scc.MinOutputSize.cy; y <= scc.MaxOutputSize.cy; y+= stepY){ + //If we find an exact match + if( heightIn == y){ + exactMatchY = true; + tempH = y; + } + //Otherwise lets find the closest match based on height + else if( abs(heightIn-y) < abs(heightIn-tempH) ){ + tempH = y; + } + } + + //see if we have an exact match! + if(exactMatchX && exactMatchY){ + //foundClosestMatch = false; + exactMatch = true; + + widthOut = widthIn; + heightOut = heightIn; + mediatypeOut = pmtConfig->subtype; + } + + //otherwise lets see if this filters closest size is the closest + //available. the closest size is determined by the sum difference + //of the widths and heights + else if( abs(widthIn - tempW) + abs(heightIn - tempH) < abs(widthIn - nearW) + abs(heightIn - nearH) ) + { + nearW = tempW; + nearH = tempH; + + widthOut = nearW; + heightOut = nearH; + mediatypeOut = pmtConfig->subtype; + } + + MyDeleteMediaType(pmtConfig); + + //If we have found an exact match no need to search anymore + if(exactMatch)break; + } + } + } + +} + + +//--------------------------------------------------------------------------------------------------- +static bool setSizeAndSubtype(videoDevice * VD, int attemptWidth, int attemptHeight, GUID mediatype){ + VIDEOINFOHEADER *pVih = reinterpret_cast(VD->pAmMediaType->pbFormat); + + //store current size + //int tmpWidth = HEADER(pVih)->biWidth; + //int tmpHeight = HEADER(pVih)->biHeight; + AM_MEDIA_TYPE * tmpType = NULL; + + HRESULT hr = VD->streamConf->GetFormat(&tmpType); + if(hr != S_OK)return false; + + //set new size: + //width and height + HEADER(pVih)->biWidth = attemptWidth; + HEADER(pVih)->biHeight = attemptHeight; + + VD->pAmMediaType->formattype = FORMAT_VideoInfo; + VD->pAmMediaType->majortype = MEDIATYPE_Video; + VD->pAmMediaType->subtype = mediatype; + + //buffer size + VD->pAmMediaType->lSampleSize = attemptWidth*attemptHeight*3; + + //set fps if requested + if( VD->requestedFrameTime != -1){ + pVih->AvgTimePerFrame = VD->requestedFrameTime; + } + + //okay lets try new size + hr = VD->streamConf->SetFormat(VD->pAmMediaType); + if(hr == S_OK){ + if( tmpType != NULL )MyDeleteMediaType(tmpType); + return true; + }else{ + VD->streamConf->SetFormat(tmpType); + if( tmpType != NULL )MyDeleteMediaType(tmpType); + } + + return false; +} + +// ---------------------------------------------------------------------- +// Where all the work happens! +// Attempts to build a graph for the specified device +// ---------------------------------------------------------------------- + +int videoInput::start(int deviceID, videoDevice *VD){ + + HRESULT hr = NOERROR; + VD->myID = deviceID; + VD->setupStarted = true; + CAPTURE_MODE = PIN_CATEGORY_CAPTURE; //Don't worry - it ends up being preview (which is faster) + callbackSetCount = 1; //make sure callback method is not changed after setup called + + if(verbose)printf("SETUP: Setting up device %i\n",deviceID); + + // CREATE THE GRAPH BUILDER // + // Create the filter graph manager and query for interfaces. + hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&VD->pCaptureGraph); + if (FAILED(hr)) // FAILED is a macro that tests the return value + { + if(verbose)printf("ERROR - Could not create the Filter Graph Manager\n"); + return hr; + } + + //FITLER GRAPH MANAGER// + // Create the Filter Graph Manager. + hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void**)&VD->pGraph); + if (FAILED(hr)) + { + if(verbose)printf("ERROR - Could not add the graph builder!\n"); + stopDevice(deviceID); + return hr; + } + + //SET THE FILTERGRAPH// + hr = VD->pCaptureGraph->SetFiltergraph(VD->pGraph); + if (FAILED(hr)) + { + if(verbose)printf("ERROR - Could not set filtergraph\n"); + stopDevice(deviceID); + return hr; + } + + //MEDIA CONTROL (START/STOPS STREAM)// + // Using QueryInterface on the graph builder, + // Get the Media Control object. + hr = VD->pGraph->QueryInterface(IID_IMediaControl, (void **)&VD->pControl); + if (FAILED(hr)) + { + if(verbose)printf("ERROR - Could not create the Media Control object\n"); + stopDevice(deviceID); + return hr; + } + + + //FIND VIDEO DEVICE AND ADD TO GRAPH// + //gets the device specified by the second argument. + hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName); + + if (SUCCEEDED(hr)){ + if(verbose)printf("SETUP: %s\n", VD->nDeviceName); + hr = VD->pGraph->AddFilter(VD->pVideoInputFilter, VD->wDeviceName); + }else{ + if(verbose)printf("ERROR - Could not find specified video device\n"); + stopDevice(deviceID); + return hr; + } + + //LOOK FOR PREVIEW PIN IF THERE IS NONE THEN WE USE CAPTURE PIN AND THEN SMART TEE TO PREVIEW + IAMStreamConfig *streamConfTest = NULL; + hr = VD->pCaptureGraph->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, VD->pVideoInputFilter, IID_IAMStreamConfig, (void **)&streamConfTest); + if(FAILED(hr)){ + if(verbose)printf("SETUP: Couldn't find preview pin using SmartTee\n"); + }else{ + CAPTURE_MODE = PIN_CATEGORY_PREVIEW; + streamConfTest->Release(); + streamConfTest = NULL; + } + + //CROSSBAR (SELECT PHYSICAL INPUT TYPE)// + //my own function that checks to see if the device can support a crossbar and if so it routes it. + //webcams tend not to have a crossbar so this function will also detect a webcams and not apply the crossbar + if(VD->useCrossbar) + { + if(verbose)printf("SETUP: Checking crossbar\n"); + routeCrossbar(&VD->pCaptureGraph, &VD->pVideoInputFilter, VD->connection, CAPTURE_MODE); + } + + + //we do this because webcams don't have a preview mode + hr = VD->pCaptureGraph->FindInterface(&CAPTURE_MODE, &MEDIATYPE_Video, VD->pVideoInputFilter, IID_IAMStreamConfig, (void **)&VD->streamConf); + if(FAILED(hr)){ + if(verbose)printf("ERROR: Couldn't config the stream!\n"); + stopDevice(deviceID); + return hr; + } + + //NOW LETS DEAL WITH GETTING THE RIGHT SIZE + hr = VD->streamConf->GetFormat(&VD->pAmMediaType); + if(FAILED(hr)){ + if(verbose)printf("ERROR: Couldn't getFormat for pAmMediaType!\n"); + stopDevice(deviceID); + return hr; + } + + VIDEOINFOHEADER *pVih = reinterpret_cast(VD->pAmMediaType->pbFormat); + int currentWidth = HEADER(pVih)->biWidth; + int currentHeight = HEADER(pVih)->biHeight; + + bool customSize = VD->tryDiffSize; + + bool foundSize = false; + + if(customSize){ + if(verbose) printf("SETUP: Default Format is set to %i by %i \n", currentWidth, currentHeight); + + char guidStr[8]; + // try specified format and size + getMediaSubtypeAsString(VD->tryVideoType, guidStr); + if(verbose)printf("SETUP: trying specified format %s @ %i by %i\n", guidStr, VD->tryWidth, VD->tryHeight); + + if( setSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, VD->tryVideoType) ){ + VD->setSize(VD->tryWidth, VD->tryHeight); + foundSize = true; + } else { + // try specified size with all formats + for(int i = 0; i < VI_NUM_TYPES; i++){ + + getMediaSubtypeAsString(mediaSubtypes[i], guidStr); + + if(verbose)printf("SETUP: trying format %s @ %i by %i\n", guidStr, VD->tryWidth, VD->tryHeight); + if( setSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, mediaSubtypes[i]) ){ + VD->setSize(VD->tryWidth, VD->tryHeight); + foundSize = true; + break; + } + } + } + + + //if we didn't find the requested size - lets try and find the closest matching size + if( foundSize == false ){ + if( verbose )printf("SETUP: couldn't find requested size - searching for closest matching size\n"); + + int closestWidth = -1; + int closestHeight = -1; + GUID newMediaSubtype; + + findClosestSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, closestWidth, closestHeight, newMediaSubtype); + + if( closestWidth != -1 && closestHeight != -1){ + getMediaSubtypeAsString(newMediaSubtype, guidStr); + + if(verbose)printf("SETUP: closest supported size is %s @ %i %i\n", guidStr, closestWidth, closestHeight); + if( setSizeAndSubtype(VD, closestWidth, closestHeight, newMediaSubtype) ){ + VD->setSize(closestWidth, closestHeight); + foundSize = true; + } + } + } + } + + //if we didn't specify a custom size or if we did but couldn't find it lets setup with the default settings + if(customSize == false || foundSize == false){ + if( VD->requestedFrameTime != -1 ){ + pVih->AvgTimePerFrame = VD->requestedFrameTime; + hr = VD->streamConf->SetFormat(VD->pAmMediaType); + } + VD->setSize(currentWidth, currentHeight); + } + + //SAMPLE GRABBER (ALLOWS US TO GRAB THE BUFFER)// + // Create the Sample Grabber. + hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void**)&VD->pGrabberF); + if (FAILED(hr)){ + if(verbose)printf("Could not Create Sample Grabber - CoCreateInstance()\n"); + stopDevice(deviceID); + return hr; + } + + hr = VD->pGraph->AddFilter(VD->pGrabberF, L"Sample Grabber"); + if (FAILED(hr)){ + if(verbose)printf("Could not add Sample Grabber - AddFilter()\n"); + stopDevice(deviceID); + return hr; + } + + hr = VD->pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&VD->pGrabber); + if (FAILED(hr)){ + if(verbose)printf("ERROR: Could not query SampleGrabber\n"); + stopDevice(deviceID); + return hr; + } + + + //Set Params - One Shot should be false unless you want to capture just one buffer + hr = VD->pGrabber->SetOneShot(FALSE); + if(bCallback){ + hr = VD->pGrabber->SetBufferSamples(FALSE); + }else{ + hr = VD->pGrabber->SetBufferSamples(TRUE); + } + + if(bCallback){ + //Tell the grabber to use our callback function - 0 is for SampleCB and 1 for BufferCB + //We use SampleCB + hr = VD->pGrabber->SetCallback(VD->sgCallback, 0); + if (FAILED(hr)){ + if(verbose)printf("ERROR: problem setting callback\n"); + stopDevice(deviceID); + return hr; + }else{ + if(verbose)printf("SETUP: Capture callback set\n"); + } + } + + //MEDIA CONVERSION + //Get video properties from the stream's mediatype and apply to the grabber (otherwise we don't get an RGB image) + //zero the media type - lets try this :) - maybe this works? + AM_MEDIA_TYPE mt; + ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE)); + + mt.majortype = MEDIATYPE_Video; + mt.subtype = MEDIASUBTYPE_RGB24; + mt.formattype = FORMAT_VideoInfo; + + //VD->pAmMediaType->subtype = VD->videoType; + hr = VD->pGrabber->SetMediaType(&mt); + + //lets try freeing our stream conf here too + //this will fail if the device is already running + if(VD->streamConf){ + VD->streamConf->Release(); + VD->streamConf = NULL; + }else{ + if(verbose)printf("ERROR: connecting device - prehaps it is already being used?\n"); + stopDevice(deviceID); + return S_FALSE; + } + + + //NULL RENDERER// + //used to give the video stream somewhere to go to. + hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)(&VD->pDestFilter)); + if (FAILED(hr)){ + if(verbose)printf("ERROR: Could not create filter - NullRenderer\n"); + stopDevice(deviceID); + return hr; + } + + hr = VD->pGraph->AddFilter(VD->pDestFilter, L"NullRenderer"); + if (FAILED(hr)){ + if(verbose)printf("ERROR: Could not add filter - NullRenderer\n"); + stopDevice(deviceID); + return hr; + } + + //RENDER STREAM// + //This is where the stream gets put together. + hr = VD->pCaptureGraph->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, VD->pVideoInputFilter, VD->pGrabberF, VD->pDestFilter); + + if (FAILED(hr)){ + if(verbose)printf("ERROR: Could not connect pins - RenderStream()\n"); + stopDevice(deviceID); + return hr; + } + + + //EXP - lets try setting the sync source to null - and make it run as fast as possible + { + IMediaFilter *pMediaFilter = 0; + hr = VD->pGraph->QueryInterface(IID_IMediaFilter, (void**)&pMediaFilter); + if (FAILED(hr)){ + if(verbose)printf("ERROR: Could not get IID_IMediaFilter interface\n"); + }else{ + pMediaFilter->SetSyncSource(NULL); + pMediaFilter->Release(); + } + } + + + //LETS RUN THE STREAM! + hr = VD->pControl->Run(); + + if (FAILED(hr)){ + if(verbose)printf("ERROR: Could not start graph\n"); + stopDevice(deviceID); + return hr; + } + + + //MAKE SURE THE DEVICE IS SENDING VIDEO BEFORE WE FINISH + if(!bCallback){ + + long bufferSize = VD->videoSize; + + while( hr != S_OK){ + hr = VD->pGrabber->GetCurrentBuffer(&bufferSize, (long *)VD->pBuffer); + Sleep(10); + } + + } + + if(verbose)printf("SETUP: Device is setup and ready to capture.\n\n"); + VD->readyToCapture = true; + + //Release filters - seen someone else do this + //looks like it solved the freezes + + //if we release this then we don't have access to the settings + //we release our video input filter but then reconnect with it + //each time we need to use it + VD->pVideoInputFilter->Release(); + VD->pVideoInputFilter = NULL; + + VD->pGrabberF->Release(); + VD->pGrabberF = NULL; + + VD->pDestFilter->Release(); + VD->pDestFilter = NULL; + + return S_OK; +} + + +// ---------------------------------------------------------------------- +// Returns number of good devices +// +// ---------------------------------------------------------------------- + +int videoInput::getDeviceCount(){ + + + ICreateDevEnum *pDevEnum = NULL; + IEnumMoniker *pEnum = NULL; + int deviceCounter = 0; + + HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, + CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, + reinterpret_cast(&pDevEnum)); + + + if (SUCCEEDED(hr)) + { + // Create an enumerator for the video capture category. + hr = pDevEnum->CreateClassEnumerator( + CLSID_VideoInputDeviceCategory, + &pEnum, 0); + + if(hr == S_OK){ + IMoniker *pMoniker = NULL; + while (pEnum->Next(1, &pMoniker, NULL) == S_OK){ + + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, + (void**)(&pPropBag)); + + if (FAILED(hr)){ + pMoniker->Release(); + continue; // Skip this one, maybe the next one will work. + } + + pPropBag->Release(); + pPropBag = NULL; + + pMoniker->Release(); + pMoniker = NULL; + + deviceCounter++; + } + + pEnum->Release(); + pEnum = NULL; + } + + pDevEnum->Release(); + pDevEnum = NULL; + } + return deviceCounter; +} + + +// ---------------------------------------------------------------------- +// Do we need this? +// +// Enumerate all of the video input devices +// Return the filter with a matching friendly name +// ---------------------------------------------------------------------- + +HRESULT videoInput::getDevice(IBaseFilter** gottaFilter, int deviceId, WCHAR * wDeviceName, char * nDeviceName){ + BOOL done = false; + int deviceCounter = 0; + + // Create the System Device Enumerator. + ICreateDevEnum *pSysDevEnum = NULL; + HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum); + if (FAILED(hr)) + { + return hr; + } + + // Obtain a class enumerator for the video input category. + IEnumMoniker *pEnumCat = NULL; + hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0); + + if (hr == S_OK) + { + // Enumerate the monikers. + IMoniker *pMoniker = NULL; + ULONG cFetched; + while ((pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) && (!done)) + { + if(deviceCounter == deviceId) + { + // Bind the first moniker to an object + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); + if (SUCCEEDED(hr)) + { + // To retrieve the filter's friendly name, do the following: + VARIANT varName; + VariantInit(&varName); + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if (SUCCEEDED(hr)) + { + + //copy the name to nDeviceName & wDeviceName + int count = 0; + while( varName.bstrVal[count] != 0x00 ) { + wDeviceName[count] = varName.bstrVal[count]; + nDeviceName[count] = (char)varName.bstrVal[count]; + count++; + } + + // We found it, so send it back to the caller + hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)gottaFilter); + done = true; + } + VariantClear(&varName); + pPropBag->Release(); + pPropBag = NULL; + pMoniker->Release(); + pMoniker = NULL; + } + } + deviceCounter++; + } + pEnumCat->Release(); + pEnumCat = NULL; + } + pSysDevEnum->Release(); + pSysDevEnum = NULL; + + if (done) { + return hr; // found it, return native error + } else { + return VFW_E_NOT_FOUND; // didn't find it error + } +} + + +// ---------------------------------------------------------------------- +// Show the property pages for a filter +// This is stolen from the DX9 SDK +// ---------------------------------------------------------------------- + +HRESULT videoInput::ShowFilterPropertyPages(IBaseFilter *pFilter){ + + ISpecifyPropertyPages *pProp; + + HRESULT hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp); + if (SUCCEEDED(hr)) + { + // Get the filter's name and IUnknown pointer. + FILTER_INFO FilterInfo; + hr = pFilter->QueryFilterInfo(&FilterInfo); + IUnknown *pFilterUnk; + pFilter->QueryInterface(IID_IUnknown, (void **)&pFilterUnk); + + // Show the page. + CAUUID caGUID; + pProp->GetPages(&caGUID); + pProp->Release(); + OleCreatePropertyFrame( + NULL, // Parent window + 0, 0, // Reserved + FilterInfo.achName, // Caption for the dialog box + 1, // Number of objects (just the filter) + &pFilterUnk, // Array of object pointers. + caGUID.cElems, // Number of property pages + caGUID.pElems, // Array of property page CLSIDs + 0, // Locale identifier + 0, NULL // Reserved + ); + + // Clean up. + if(pFilterUnk)pFilterUnk->Release(); + if(FilterInfo.pGraph)FilterInfo.pGraph->Release(); + CoTaskMemFree(caGUID.pElems); + } + return hr; +} + +HRESULT videoInput::ShowStreamPropertyPages(IAMStreamConfig * /*pStream*/){ + + HRESULT hr = NOERROR; + return hr; +} + +// ---------------------------------------------------------------------- +// This code was also brazenly stolen from the DX9 SDK +// Pass it a file name in wszPath, and it will save the filter graph to that file. +// ---------------------------------------------------------------------- + +HRESULT videoInput::SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath) { + const WCHAR wszStreamName[] = L"ActiveMovieGraph"; + HRESULT hr; + IStorage *pStorage = NULL; + + // First, create a document file which will hold the GRF file + hr = StgCreateDocfile( + wszPath, + STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, + 0, &pStorage); + if(FAILED(hr)) + { + return hr; + } + + // Next, create a stream to store. + IStream *pStream; + hr = pStorage->CreateStream( + wszStreamName, + STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, + 0, 0, &pStream); + if (FAILED(hr)) + { + pStorage->Release(); + return hr; + } + + // The IPersistStream converts a stream into a persistent object. + IPersistStream *pPersist = NULL; + pGraph->QueryInterface(IID_IPersistStream, reinterpret_cast(&pPersist)); + hr = pPersist->Save(pStream, TRUE); + pStream->Release(); + pPersist->Release(); + if (SUCCEEDED(hr)) + { + hr = pStorage->Commit(STGC_DEFAULT); + } + pStorage->Release(); + return hr; +} + + +// ---------------------------------------------------------------------- +// For changing the input types +// +// ---------------------------------------------------------------------- + +HRESULT videoInput::routeCrossbar(ICaptureGraphBuilder2 **ppBuild, IBaseFilter **pVidInFilter, int conType, GUID captureMode){ + + //create local ICaptureGraphBuilder2 + ICaptureGraphBuilder2 *pBuild = NULL; + pBuild = *ppBuild; + + //create local IBaseFilter + IBaseFilter *pVidFilter = NULL; + pVidFilter = * pVidInFilter; + + // Search upstream for a crossbar. + IAMCrossbar *pXBar1 = NULL; + HRESULT hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, NULL, pVidFilter, + IID_IAMCrossbar, (void**)&pXBar1); + if (SUCCEEDED(hr)) + { + + bool foundDevice = false; + + if(verbose)printf("SETUP: You are not a webcam! Setting Crossbar\n"); + pXBar1->Release(); + + IAMCrossbar *Crossbar; + hr = pBuild->FindInterface(&captureMode, &MEDIATYPE_Interleaved, pVidFilter, IID_IAMCrossbar, (void **)&Crossbar); + + if(hr != NOERROR){ + hr = pBuild->FindInterface(&captureMode, &MEDIATYPE_Video, pVidFilter, IID_IAMCrossbar, (void **)&Crossbar); + } + + LONG lInpin, lOutpin; + hr = Crossbar->get_PinCounts(&lOutpin , &lInpin); + + BOOL iPin=TRUE; LONG pIndex=0 , pRIndex=0 , pType=0; + + while( pIndex < lInpin) + { + hr = Crossbar->get_CrossbarPinInfo( iPin , pIndex , &pRIndex , &pType); + + if( pType == conType){ + if(verbose)printf("SETUP: Found Physical Interface"); + + switch(conType){ + + case PhysConn_Video_Composite: + if(verbose)printf(" - Composite\n"); + break; + case PhysConn_Video_SVideo: + if(verbose)printf(" - S-Video\n"); + break; + case PhysConn_Video_Tuner: + if(verbose)printf(" - Tuner\n"); + break; + case PhysConn_Video_USB: + if(verbose)printf(" - USB\n"); + break; + case PhysConn_Video_1394: + if(verbose)printf(" - Firewire\n"); + break; + } + + foundDevice = true; + break; + } + pIndex++; + + } + + if(foundDevice){ + BOOL OPin=FALSE; LONG pOIndex=0 , pORIndex=0 , pOType=0; + while( pOIndex < lOutpin) + { + hr = Crossbar->get_CrossbarPinInfo( OPin , pOIndex , &pORIndex , &pOType); + if( pOType == PhysConn_Video_VideoDecoder) + break; + } + Crossbar->Route(pOIndex,pIndex); + }else{ + if(verbose) printf("SETUP: Didn't find specified Physical Connection type. Using Defualt. \n"); + } + + //we only free the crossbar when we close or restart the device + //we were getting a crash otherwise + //if(Crossbar)Crossbar->Release(); + //if(Crossbar)Crossbar = NULL; + + if(pXBar1)pXBar1->Release(); + if(pXBar1)pXBar1 = NULL; + + }else{ + if(verbose) printf("SETUP: You are a webcam or snazzy firewire cam! No Crossbar needed\n"); + return hr; + } + + return hr; +} + +/********************* Capturing video from camera via DirectShow *********************/ + +class CvCaptureCAM_DShow : public CvCapture +{ +public: + CvCaptureCAM_DShow(); + virtual ~CvCaptureCAM_DShow(); + + virtual bool open( int index ); + virtual void close(); + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual int getCaptureDomain() { return CV_CAP_DSHOW; } // Return the type of the capture object: CV_CAP_VFW, etc... + +protected: + void init(); + + int index, width, height,fourcc; + IplImage* frame; + static videoInput VI; +}; + + +struct SuppressVideoInputMessages +{ + SuppressVideoInputMessages() { videoInput::setVerbose(false); } +}; + +static SuppressVideoInputMessages do_it; +videoInput CvCaptureCAM_DShow::VI; + +CvCaptureCAM_DShow::CvCaptureCAM_DShow() +{ + index = -1; + frame = 0; + width = height = fourcc = -1; + CoInitialize(0); +} + +CvCaptureCAM_DShow::~CvCaptureCAM_DShow() +{ + close(); + CoUninitialize(); +} + +void CvCaptureCAM_DShow::close() +{ + if( index >= 0 ) + { + VI.stopDevice(index); + index = -1; + cvReleaseImage(&frame); + } + width = height = -1; +} + +// Initialize camera input +bool CvCaptureCAM_DShow::open( int _index ) +{ + int try_index = _index; + int devices = 0; + + close(); + devices = VI.listDevices(true); + if (devices == 0) + return false; + try_index = try_index < 0 ? 0 : (try_index > devices-1 ? devices-1 : try_index); + VI.setupDevice(try_index); + if( !VI.isDeviceSetup(try_index) ) + return false; + index = try_index; + return true; +} + +bool CvCaptureCAM_DShow::grabFrame() +{ + return true; +} + + +IplImage* CvCaptureCAM_DShow::retrieveFrame(int) +{ + if( !frame || VI.getWidth(index) != frame->width || VI.getHeight(index) != frame->height ) + { + if (frame) + cvReleaseImage( &frame ); + int w = VI.getWidth(index), h = VI.getHeight(index); + frame = cvCreateImage( cvSize(w,h), 8, 3 ); + } + + VI.getPixels( index, (uchar*)frame->imageData, false, true ); + return frame; +} + +double CvCaptureCAM_DShow::getProperty( int property_id ) +{ + + long min_value,max_value,stepping_delta,current_value,flags,defaultValue; + + // image format proprrties + switch( property_id ) + { + case CV_CAP_PROP_FRAME_WIDTH: + return VI.getWidth(index); + + case CV_CAP_PROP_FRAME_HEIGHT: + return VI.getHeight(index); + + case CV_CAP_PROP_FOURCC: + return VI.getFourcc(index); + + case CV_CAP_PROP_FPS: + return VI.getFPS(index); + } + + // video filter properties + switch( property_id ) + { + case CV_CAP_PROP_BRIGHTNESS: + case CV_CAP_PROP_CONTRAST: + case CV_CAP_PROP_HUE: + case CV_CAP_PROP_SATURATION: + case CV_CAP_PROP_SHARPNESS: + case CV_CAP_PROP_GAMMA: + case CV_CAP_PROP_MONOCROME: + case CV_CAP_PROP_WHITE_BALANCE_BLUE_U: + case CV_CAP_PROP_BACKLIGHT: + case CV_CAP_PROP_GAIN: + if (VI.getVideoSettingFilter(index,VI.getVideoPropertyFromCV(property_id),min_value,max_value,stepping_delta,current_value,flags,defaultValue) ) return (double)current_value; + } + + // camera properties + switch( property_id ) + { + case CV_CAP_PROP_PAN: + case CV_CAP_PROP_TILT: + case CV_CAP_PROP_ROLL: + case CV_CAP_PROP_ZOOM: + case CV_CAP_PROP_EXPOSURE: + case CV_CAP_PROP_IRIS: + case CV_CAP_PROP_FOCUS: + if (VI.getVideoSettingCamera(index,VI.getCameraPropertyFromCV(property_id),min_value,max_value,stepping_delta,current_value,flags,defaultValue) ) return (double)current_value; + + } + + // unknown parameter or value not available + return -1; +} + +bool CvCaptureCAM_DShow::setProperty( int property_id, double value ) +{ + // image capture properties + bool handled = false; + switch( property_id ) + { + case CV_CAP_PROP_FRAME_WIDTH: + width = cvRound(value); + handled = true; + break; + + case CV_CAP_PROP_FRAME_HEIGHT: + height = cvRound(value); + handled = true; + break; + + case CV_CAP_PROP_FOURCC: + fourcc = cvRound(value); + if ( fourcc < 0 ) { + // following cvCreateVideo usage will pop up caprturepindialog here if fourcc=-1 + // TODO - how to create a capture pin dialog + } + handled = true; + break; + + case CV_CAP_PROP_FPS: + int fps = cvRound(value); + if (fps != VI.getFPS(index)) + { + VI.stopDevice(index); + VI.setIdealFramerate(index,fps); + VI.setupDevice(index); + } + break; + + } + + if ( handled ) { + // a stream setting + if( width > 0 && height > 0 ) + { + if( width != VI.getWidth(index) || height != VI.getHeight(index) )//|| fourcc != VI.getFourcc(index) ) + { + int fps = static_cast(VI.getFPS(index)); + VI.stopDevice(index); + VI.setIdealFramerate(index, fps); + VI.setupDeviceFourcc(index, width, height, fourcc); + } + width = height = fourcc = -1; + return VI.isDeviceSetup(index); + } + return true; + } + + // show video/camera filter dialog + if ( property_id == CV_CAP_PROP_SETTINGS ) { + VI.showSettingsWindow(index); + return true; + } + + //video Filter properties + switch( property_id ) + { + case CV_CAP_PROP_BRIGHTNESS: + case CV_CAP_PROP_CONTRAST: + case CV_CAP_PROP_HUE: + case CV_CAP_PROP_SATURATION: + case CV_CAP_PROP_SHARPNESS: + case CV_CAP_PROP_GAMMA: + case CV_CAP_PROP_MONOCROME: + case CV_CAP_PROP_WHITE_BALANCE_BLUE_U: + case CV_CAP_PROP_BACKLIGHT: + case CV_CAP_PROP_GAIN: + return VI.setVideoSettingFilter(index,VI.getVideoPropertyFromCV(property_id),(long)value); + } + + //camera properties + switch( property_id ) + { + case CV_CAP_PROP_PAN: + case CV_CAP_PROP_TILT: + case CV_CAP_PROP_ROLL: + case CV_CAP_PROP_ZOOM: + case CV_CAP_PROP_EXPOSURE: + case CV_CAP_PROP_IRIS: + case CV_CAP_PROP_FOCUS: + return VI.setVideoSettingCamera(index,VI.getCameraPropertyFromCV(property_id),(long)value); + } + + return false; +} + + +CvCapture* cvCreateCameraCapture_DShow( int index ) +{ + CvCaptureCAM_DShow* capture = new CvCaptureCAM_DShow; + + try + { + if( capture->open( index )) + return capture; + } + catch(...) + { + delete capture; + throw; + } + + delete capture; + return 0; +} + +#endif diff --git a/highgui/src/cap_ffmpeg.cpp b/highgui/src/cap_ffmpeg.cpp new file mode 100644 index 0000000..0cc60e3 --- /dev/null +++ b/highgui/src/cap_ffmpeg.cpp @@ -0,0 +1,251 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#ifdef HAVE_FFMPEG +#include "cap_ffmpeg_impl.hpp" +#else +#include "cap_ffmpeg_api.hpp" +#endif + +static CvCreateFileCapture_Plugin icvCreateFileCapture_FFMPEG_p = 0; +static CvReleaseCapture_Plugin icvReleaseCapture_FFMPEG_p = 0; +static CvGrabFrame_Plugin icvGrabFrame_FFMPEG_p = 0; +static CvRetrieveFrame_Plugin icvRetrieveFrame_FFMPEG_p = 0; +static CvSetCaptureProperty_Plugin icvSetCaptureProperty_FFMPEG_p = 0; +static CvGetCaptureProperty_Plugin icvGetCaptureProperty_FFMPEG_p = 0; +static CvCreateVideoWriter_Plugin icvCreateVideoWriter_FFMPEG_p = 0; +static CvReleaseVideoWriter_Plugin icvReleaseVideoWriter_FFMPEG_p = 0; +static CvWriteFrame_Plugin icvWriteFrame_FFMPEG_p = 0; + +static void +icvInitFFMPEG(void) +{ + static int ffmpegInitialized = 0; + if( !ffmpegInitialized ) + { + #if defined WIN32 || defined _WIN32 + const char* module_name = "opencv_ffmpeg" + CVAUX_STR(CV_MAJOR_VERSION) CVAUX_STR(CV_MINOR_VERSION) CVAUX_STR(CV_SUBMINOR_VERSION) + #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__) + "_64" + #endif + ".dll"; + + static HMODULE icvFFOpenCV = LoadLibrary( module_name ); + if( icvFFOpenCV ) + { + icvCreateFileCapture_FFMPEG_p = + (CvCreateFileCapture_Plugin)GetProcAddress(icvFFOpenCV, "cvCreateFileCapture_FFMPEG"); + icvReleaseCapture_FFMPEG_p = + (CvReleaseCapture_Plugin)GetProcAddress(icvFFOpenCV, "cvReleaseCapture_FFMPEG"); + icvGrabFrame_FFMPEG_p = + (CvGrabFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvGrabFrame_FFMPEG"); + icvRetrieveFrame_FFMPEG_p = + (CvRetrieveFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvRetrieveFrame_FFMPEG"); + icvSetCaptureProperty_FFMPEG_p = + (CvSetCaptureProperty_Plugin)GetProcAddress(icvFFOpenCV, "cvSetCaptureProperty_FFMPEG"); + icvGetCaptureProperty_FFMPEG_p = + (CvGetCaptureProperty_Plugin)GetProcAddress(icvFFOpenCV, "cvGetCaptureProperty_FFMPEG"); + icvCreateVideoWriter_FFMPEG_p = + (CvCreateVideoWriter_Plugin)GetProcAddress(icvFFOpenCV, "cvCreateVideoWriter_FFMPEG"); + icvReleaseVideoWriter_FFMPEG_p = + (CvReleaseVideoWriter_Plugin)GetProcAddress(icvFFOpenCV, "cvReleaseVideoWriter_FFMPEG"); + icvWriteFrame_FFMPEG_p = + (CvWriteFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvWriteFrame_FFMPEG"); + +#if 0 + if( icvCreateFileCapture_FFMPEG_p != 0 && + icvReleaseCapture_FFMPEG_p != 0 && + icvGrabFrame_FFMPEG_p != 0 && + icvRetrieveFrame_FFMPEG_p != 0 && + icvSetCaptureProperty_FFMPEG_p != 0 && + icvGetCaptureProperty_FFMPEG_p != 0 && + icvCreateVideoWriter_FFMPEG_p != 0 && + icvReleaseVideoWriter_FFMPEG_p != 0 && + icvWriteFrame_FFMPEG_p != 0 ) + { + printf("Successfully initialized ffmpeg plugin!\n"); + } + else + { + printf("Failed to load FFMPEG plugin: module handle=%p\n", icvFFOpenCV); + } +#endif + } + #elif defined HAVE_FFMPEG + icvCreateFileCapture_FFMPEG_p = (CvCreateFileCapture_Plugin)cvCreateFileCapture_FFMPEG; + icvReleaseCapture_FFMPEG_p = (CvReleaseCapture_Plugin)cvReleaseCapture_FFMPEG; + icvGrabFrame_FFMPEG_p = (CvGrabFrame_Plugin)cvGrabFrame_FFMPEG; + icvRetrieveFrame_FFMPEG_p = (CvRetrieveFrame_Plugin)cvRetrieveFrame_FFMPEG; + icvSetCaptureProperty_FFMPEG_p = (CvSetCaptureProperty_Plugin)cvSetCaptureProperty_FFMPEG; + icvGetCaptureProperty_FFMPEG_p = (CvGetCaptureProperty_Plugin)cvGetCaptureProperty_FFMPEG; + icvCreateVideoWriter_FFMPEG_p = (CvCreateVideoWriter_Plugin)cvCreateVideoWriter_FFMPEG; + icvReleaseVideoWriter_FFMPEG_p = (CvReleaseVideoWriter_Plugin)cvReleaseVideoWriter_FFMPEG; + icvWriteFrame_FFMPEG_p = (CvWriteFrame_Plugin)cvWriteFrame_FFMPEG; + #endif + + ffmpegInitialized = 1; + } +} + + +class CvCapture_FFMPEG_proxy : public CvCapture +{ +public: + CvCapture_FFMPEG_proxy() { ffmpegCapture = 0; } + virtual ~CvCapture_FFMPEG_proxy() { close(); } + + virtual double getProperty(int propId) + { + return ffmpegCapture ? icvGetCaptureProperty_FFMPEG_p(ffmpegCapture, propId) : 0; + } + virtual bool setProperty(int propId, double value) + { + return ffmpegCapture ? icvSetCaptureProperty_FFMPEG_p(ffmpegCapture, propId, value)!=0 : false; + } + virtual bool grabFrame() + { + return ffmpegCapture ? icvGrabFrame_FFMPEG_p(ffmpegCapture)!=0 : false; + } + virtual IplImage* retrieveFrame(int) + { + unsigned char* data = 0; + int step=0, width=0, height=0, cn=0; + + if(!ffmpegCapture || + !icvRetrieveFrame_FFMPEG_p(ffmpegCapture,&data,&step,&width,&height,&cn)) + return 0; + cvInitImageHeader(&frame, cvSize(width, height), 8, cn); + cvSetData(&frame, data, step); + return &frame; + } + virtual bool open( const char* filename ) + { + close(); + + icvInitFFMPEG(); + if( !icvCreateFileCapture_FFMPEG_p ) + return false; + ffmpegCapture = icvCreateFileCapture_FFMPEG_p( filename ); + return ffmpegCapture != 0; + } + virtual void close() + { + if( ffmpegCapture && icvReleaseCapture_FFMPEG_p ) + icvReleaseCapture_FFMPEG_p( &ffmpegCapture ); + assert( ffmpegCapture == 0 ); + ffmpegCapture = 0; + } + +protected: + void* ffmpegCapture; + IplImage frame; +}; + + +CvCapture* cvCreateFileCapture_FFMPEG_proxy(const char * filename) +{ + CvCapture_FFMPEG_proxy* result = new CvCapture_FFMPEG_proxy; + if( result->open( filename )) + return result; + delete result; +#if defined WIN32 || defined _WIN32 + return cvCreateFileCapture_VFW(filename); +#else + return 0; +#endif +} + + +class CvVideoWriter_FFMPEG_proxy : public CvVideoWriter +{ +public: + CvVideoWriter_FFMPEG_proxy() { ffmpegWriter = 0; } + virtual ~CvVideoWriter_FFMPEG_proxy() { close(); } + + virtual bool writeFrame( const IplImage* image ) + { + if(!ffmpegWriter) + return false; + CV_Assert(image->depth == 8); + + return icvWriteFrame_FFMPEG_p(ffmpegWriter, (const uchar*)image->imageData, + image->widthStep, image->width, image->height, image->nChannels, image->origin) !=0; + } + virtual bool open( const char* filename, int fourcc, double fps, CvSize frameSize, bool isColor ) + { + close(); + icvInitFFMPEG(); + if( !icvCreateVideoWriter_FFMPEG_p ) + return false; + ffmpegWriter = icvCreateVideoWriter_FFMPEG_p( filename, fourcc, fps, frameSize.width, frameSize.height, isColor ); + return ffmpegWriter != 0; + } + + virtual void close() + { + if( ffmpegWriter && icvReleaseVideoWriter_FFMPEG_p ) + icvReleaseVideoWriter_FFMPEG_p( &ffmpegWriter ); + assert( ffmpegWriter == 0 ); + ffmpegWriter = 0; + } + +protected: + void* ffmpegWriter; +}; + + +CvVideoWriter* cvCreateVideoWriter_FFMPEG_proxy( const char* filename, int fourcc, + double fps, CvSize frameSize, int isColor ) +{ + CvVideoWriter_FFMPEG_proxy* result = new CvVideoWriter_FFMPEG_proxy; + + if( result->open( filename, fourcc, fps, frameSize, isColor != 0 )) + return result; + delete result; +#if defined WIN32 || defined _WIN32 + return cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, isColor); +#else + return 0; +#endif +} diff --git a/highgui/src/cap_ffmpeg_api.hpp b/highgui/src/cap_ffmpeg_api.hpp new file mode 100644 index 0000000..b585214 --- /dev/null +++ b/highgui/src/cap_ffmpeg_api.hpp @@ -0,0 +1,97 @@ +#ifndef __OPENCV_FFMPEG_H__ +#define __OPENCV_FFMPEG_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if defined WIN32 || defined _WIN32 +#define OPENCV_FFMPEG_API __declspec(dllexport) +#else +#define OPENCV_FFMPEG_API +#endif + +enum +{ + CV_FFMPEG_CAP_PROP_POS_MSEC=0, + CV_FFMPEG_CAP_PROP_POS_FRAMES=1, + CV_FFMPEG_CAP_PROP_POS_AVI_RATIO=2, + CV_FFMPEG_CAP_PROP_FRAME_WIDTH=3, + CV_FFMPEG_CAP_PROP_FRAME_HEIGHT=4, + CV_FFMPEG_CAP_PROP_FPS=5, + CV_FFMPEG_CAP_PROP_FOURCC=6, + CV_FFMPEG_CAP_PROP_FRAME_COUNT=7 +}; + + +OPENCV_FFMPEG_API struct CvCapture_FFMPEG* cvCreateFileCapture_FFMPEG(const char* filename); +OPENCV_FFMPEG_API struct CvCapture_FFMPEG_2* cvCreateFileCapture_FFMPEG_2(const char* filename); +OPENCV_FFMPEG_API int cvSetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap, + int prop, double value); +OPENCV_FFMPEG_API int cvSetCaptureProperty_FFMPEG_2(struct CvCapture_FFMPEG_2* cap, + int prop, double value); +OPENCV_FFMPEG_API double cvGetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap, int prop); +OPENCV_FFMPEG_API double cvGetCaptureProperty_FFMPEG_2(struct CvCapture_FFMPEG_2* cap, int prop); +OPENCV_FFMPEG_API int cvGrabFrame_FFMPEG(struct CvCapture_FFMPEG* cap); +OPENCV_FFMPEG_API int cvGrabFrame_FFMPEG_2(struct CvCapture_FFMPEG_2* cap); +OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG(struct CvCapture_FFMPEG* capture, unsigned char** data, + int* step, int* width, int* height, int* cn); +OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG_2(struct CvCapture_FFMPEG_2* capture, unsigned char** data, + int* step, int* width, int* height, int* cn); +OPENCV_FFMPEG_API void cvReleaseCapture_FFMPEG(struct CvCapture_FFMPEG** cap); +OPENCV_FFMPEG_API void cvReleaseCapture_FFMPEG_2(struct CvCapture_FFMPEG_2** cap); +OPENCV_FFMPEG_API struct CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG(const char* filename, + int fourcc, double fps, int width, int height, int isColor ); +OPENCV_FFMPEG_API struct CvVideoWriter_FFMPEG_2* cvCreateVideoWriter_FFMPEG_2(const char* filename, + int fourcc, double fps, int width, int height, int isColor ); + +OPENCV_FFMPEG_API int cvWriteFrame_FFMPEG(struct CvVideoWriter_FFMPEG* writer, const unsigned char* data, + int step, int width, int height, int cn, int origin); + +OPENCV_FFMPEG_API void cvReleaseVideoWriter_FFMPEG(struct CvVideoWriter_FFMPEG** writer); + +typedef void* (*CvCreateFileCapture_Plugin)( const char* filename ); +typedef void* (*CvCreateCameraCapture_Plugin)( int index ); +typedef int (*CvGrabFrame_Plugin)( void* capture_handle ); +typedef int (*CvRetrieveFrame_Plugin)( void* capture_handle, unsigned char** data, int* step, + int* width, int* height, int* cn ); +typedef int (*CvSetCaptureProperty_Plugin)( void* capture_handle, int prop_id, double value ); +typedef double (*CvGetCaptureProperty_Plugin)( void* capture_handle, int prop_id ); +typedef void (*CvReleaseCapture_Plugin)( void** capture_handle ); +typedef void* (*CvCreateVideoWriter_Plugin)( const char* filename, int fourcc, + double fps, int width, int height, int iscolor ); +typedef int (*CvWriteFrame_Plugin)( void* writer_handle, const unsigned char* data, int step, + int width, int height, int cn, int origin); +typedef void (*CvReleaseVideoWriter_Plugin)( void** writer ); + +/* + * For CUDA encoder + */ + +OPENCV_FFMPEG_API struct OutputMediaStream_FFMPEG* create_OutputMediaStream_FFMPEG(const char* fileName, int width, int height, double fps); +OPENCV_FFMPEG_API void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream); +OPENCV_FFMPEG_API void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size, int keyFrame); + +typedef struct OutputMediaStream_FFMPEG* (*Create_OutputMediaStream_FFMPEG_Plugin)(const char* fileName, int width, int height, double fps); +typedef void (*Release_OutputMediaStream_FFMPEG_Plugin)(struct OutputMediaStream_FFMPEG* stream); +typedef void (*Write_OutputMediaStream_FFMPEG_Plugin)(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size, int keyFrame); + +/* + * For CUDA decoder + */ + +OPENCV_FFMPEG_API struct InputMediaStream_FFMPEG* create_InputMediaStream_FFMPEG(const char* fileName, int* codec, int* chroma_format, int* width, int* height); +OPENCV_FFMPEG_API void release_InputMediaStream_FFMPEG(struct InputMediaStream_FFMPEG* stream); +OPENCV_FFMPEG_API int read_InputMediaStream_FFMPEG(struct InputMediaStream_FFMPEG* stream, unsigned char** data, int* size, int* endOfFile); + +typedef struct InputMediaStream_FFMPEG* (*Create_InputMediaStream_FFMPEG_Plugin)(const char* fileName, int* codec, int* chroma_format, int* width, int* height); +typedef void (*Release_InputMediaStream_FFMPEG_Plugin)(struct InputMediaStream_FFMPEG* stream); +typedef int (*Read_InputMediaStream_FFMPEG_Plugin)(struct InputMediaStream_FFMPEG* stream, unsigned char** data, int* size, int* endOfFile); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/highgui/src/cap_ffmpeg_impl.hpp b/highgui/src/cap_ffmpeg_impl.hpp new file mode 100644 index 0000000..d3a5ed3 --- /dev/null +++ b/highgui/src/cap_ffmpeg_impl.hpp @@ -0,0 +1,2096 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "cap_ffmpeg_api.hpp" +#include +#include +#include + +#if defined _MSC_VER && _MSC_VER >= 1200 +#pragma warning( disable: 4244 4510 4512 4610 ) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ffmpeg_codecs.hpp" + +#include + +#ifdef WIN32 + #define HAVE_FFMPEG_SWSCALE 1 + #include + #include +#else + +#ifndef HAVE_FFMPEG_SWSCALE + #error "libswscale is necessary to build the newer OpenCV ffmpeg wrapper" +#endif + +// if the header path is not specified explicitly, let's deduce it +#if !defined HAVE_FFMPEG_AVCODEC_H && !defined HAVE_LIBAVCODEC_AVCODEC_H + +#if defined(HAVE_GENTOO_FFMPEG) + #define HAVE_LIBAVCODEC_AVCODEC_H 1 + #if defined(HAVE_FFMPEG_SWSCALE) + #define HAVE_LIBSWSCALE_SWSCALE_H 1 + #endif +#elif defined HAVE_FFMPEG + #define HAVE_FFMPEG_AVCODEC_H 1 + #if defined(HAVE_FFMPEG_SWSCALE) + #define HAVE_FFMPEG_SWSCALE_H 1 + #endif +#endif + +#endif + +#if defined(HAVE_FFMPEG_AVCODEC_H) + #include +#endif +#if defined(HAVE_FFMPEG_SWSCALE_H) + #include +#endif + +#if defined(HAVE_LIBAVCODEC_AVCODEC_H) + #include +#endif +#if defined(HAVE_LIBSWSCALE_SWSCALE_H) + #include +#endif + +#endif + +#ifdef __cplusplus +} +#endif + +#if defined _MSC_VER && _MSC_VER >= 1200 +#pragma warning( default: 4244 4510 4512 4610 ) +#endif + +#ifdef NDEBUG +#define CV_WARN(message) +#else +#define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__) +#endif + +/* PIX_FMT_RGBA32 macro changed in newer ffmpeg versions */ +#ifndef PIX_FMT_RGBA32 +#define PIX_FMT_RGBA32 PIX_FMT_RGB32 +#endif + +#define CALC_FFMPEG_VERSION(a,b,c) ( a<<16 | b<<8 | c ) + +#if defined WIN32 || defined _WIN32 + #include +#elif defined __linux__ || defined __APPLE__ + #include + #include + #include + #include +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#if defined(__APPLE__) +#define AV_NOPTS_VALUE_ ((int64_t)0x8000000000000000LL) +#else +#define AV_NOPTS_VALUE_ ((int64_t)AV_NOPTS_VALUE) +#endif + +static int get_number_of_cpus(void) +{ +#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(52, 111, 0) + return 1; +#elif defined WIN32 || defined _WIN32 + SYSTEM_INFO sysinfo; + GetSystemInfo( &sysinfo ); + + return (int)sysinfo.dwNumberOfProcessors; +#elif defined __linux__ + return (int)sysconf( _SC_NPROCESSORS_ONLN ); +#elif defined __APPLE__ + int numCPU=0; + int mib[4]; + size_t len = sizeof(numCPU); + + // set the mib for hw.ncpu + mib[0] = CTL_HW; + mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU; + + // get the number of CPUs from the system + sysctl(mib, 2, &numCPU, &len, NULL, 0); + + if( numCPU < 1 ) + { + mib[1] = HW_NCPU; + sysctl( mib, 2, &numCPU, &len, NULL, 0 ); + + if( numCPU < 1 ) + numCPU = 1; + } + + return (int)numCPU; +#else + return 1; +#endif +} + + +struct Image_FFMPEG +{ + unsigned char* data; + int step; + int width; + int height; + int cn; +}; + + +inline void _opencv_ffmpeg_free(void** ptr) +{ + if(*ptr) free(*ptr); + *ptr = 0; +} + + +struct CvCapture_FFMPEG +{ + bool open( const char* filename ); + void close(); + + double getProperty(int); + bool setProperty(int, double); + bool grabFrame(); + bool retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn); + + void init(); + + void seek(int64_t frame_number); + void seek(double sec); + bool slowSeek( int framenumber ); + + int64_t get_total_frames(); + double get_duration_sec(); + double get_fps(); + int get_bitrate(); + + double r2d(AVRational r); + int64_t dts_to_frame_number(int64_t dts); + double dts_to_sec(int64_t dts); + + AVFormatContext * ic; + AVCodec * avcodec; + int video_stream; + AVStream * video_st; + AVFrame * picture; + AVFrame rgb_picture; + int64_t picture_pts; + + AVPacket packet; + Image_FFMPEG frame; + struct SwsContext *img_convert_ctx; + + int64_t frame_number, first_frame_number; + + double eps_zero; +/* + 'filename' contains the filename of the videosource, + 'filename==NULL' indicates that ffmpeg's seek support works + for the particular file. + 'filename!=NULL' indicates that the slow fallback function is used for seeking, + and so the filename is needed to reopen the file on backward seeking. +*/ + char * filename; +}; + +void CvCapture_FFMPEG::init() +{ + ic = 0; + video_stream = -1; + video_st = 0; + picture = 0; + picture_pts = AV_NOPTS_VALUE_; + first_frame_number = -1; + memset( &rgb_picture, 0, sizeof(rgb_picture) ); + memset( &frame, 0, sizeof(frame) ); + filename = 0; + memset(&packet, 0, sizeof(packet)); + av_init_packet(&packet); + img_convert_ctx = 0; + + avcodec = 0; + frame_number = 0; + eps_zero = 0.000025; +} + + +void CvCapture_FFMPEG::close() +{ + if( img_convert_ctx ) + { + sws_freeContext(img_convert_ctx); + img_convert_ctx = 0; + } + + if( picture ) + av_free(picture); + + if( video_st ) + { +#if LIBAVFORMAT_BUILD > 4628 + avcodec_close( video_st->codec ); + +#else + avcodec_close( &(video_st->codec) ); + +#endif + video_st = NULL; + } + + if( ic ) + { +#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 24, 2) + av_close_input_file(ic); +#else + avformat_close_input(&ic); +#endif + + ic = NULL; + } + + if( rgb_picture.data[0] ) + { + free( rgb_picture.data[0] ); + rgb_picture.data[0] = 0; + } + + // free last packet if exist + if (packet.data) { + av_free_packet (&packet); + packet.data = NULL; + } + + init(); +} + + +#ifndef AVSEEK_FLAG_FRAME +#define AVSEEK_FLAG_FRAME 0 +#endif +#ifndef AVSEEK_FLAG_ANY +#define AVSEEK_FLAG_ANY 1 +#endif + +static void icvInitFFMPEG_internal() +{ + static volatile bool initialized = false; + if( !initialized ) + { + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0) + avformat_network_init(); + #endif + + /* register all codecs, demux and protocols */ + av_register_all(); + + av_log_set_level(AV_LOG_ERROR); + + initialized = true; + } +} + +bool CvCapture_FFMPEG::open( const char* _filename ) +{ + icvInitFFMPEG_internal(); + + unsigned i; + bool valid = false; + + close(); + +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0) + int err = avformat_open_input(&ic, _filename, NULL, NULL); +#else + int err = av_open_input_file(&ic, _filename, NULL, 0, NULL); +#endif + + if (err < 0) { + CV_WARN("Error opening file"); + goto exit_func; + } + err = +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 3, 0) + avformat_find_stream_info(ic, NULL); +#else + av_find_stream_info(ic); +#endif + if (err < 0) { + CV_WARN("Could not find codec parameters"); + goto exit_func; + } + for(i = 0; i < ic->nb_streams; i++) + { +#if LIBAVFORMAT_BUILD > 4628 + AVCodecContext *enc = ic->streams[i]->codec; +#else + AVCodecContext *enc = &ic->streams[i]->codec; +#endif + +#ifdef FF_API_THREAD_INIT + avcodec_thread_init(enc, get_number_of_cpus()); +#else + enc->thread_count = get_number_of_cpus(); +#endif + +#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) +#define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO +#endif + + if( AVMEDIA_TYPE_VIDEO == enc->codec_type && video_stream < 0) { + AVCodec *codec = avcodec_find_decoder(enc->codec_id); + if (!codec || +#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) + avcodec_open2(enc, codec, NULL) +#else + avcodec_open(enc, codec) +#endif + < 0) goto exit_func; + + video_stream = i; + video_st = ic->streams[i]; + picture = avcodec_alloc_frame(); + + rgb_picture.data[0] = (uint8_t*)malloc( + avpicture_get_size( PIX_FMT_BGR24, + enc->width, enc->height )); + avpicture_fill( (AVPicture*)&rgb_picture, rgb_picture.data[0], + PIX_FMT_BGR24, enc->width, enc->height ); + + frame.width = enc->width; + frame.height = enc->height; + frame.cn = 3; + frame.step = rgb_picture.linesize[0]; + frame.data = rgb_picture.data[0]; + break; + } + } + + if(video_stream >= 0) valid = true; + +exit_func: + + if( !valid ) + close(); + + return valid; +} + + +bool CvCapture_FFMPEG::grabFrame() +{ + bool valid = false; + int got_picture; + + int count_errs = 0; + const int max_number_of_attempts = 1 << 16; + + if( !ic || !video_st ) return false; + + if( ic->streams[video_stream]->nb_frames > 0 && + frame_number > ic->streams[video_stream]->nb_frames ) + return false; + + av_free_packet (&packet); + + picture_pts = AV_NOPTS_VALUE_; + + // get the next frame + while (!valid) + { + int ret = av_read_frame(ic, &packet); + if (ret == AVERROR(EAGAIN)) continue; + + /* else if (ret < 0) break; */ + + if( packet.stream_index != video_stream ) + { + av_free_packet (&packet); + count_errs++; + if (count_errs > max_number_of_attempts) + break; + continue; + } + + // Decode video frame + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) + avcodec_decode_video2(video_st->codec, picture, &got_picture, &packet); + #elif LIBAVFORMAT_BUILD > 4628 + avcodec_decode_video(video_st->codec, + picture, &got_picture, + packet.data, packet.size); + #else + avcodec_decode_video(&video_st->codec, + picture, &got_picture, + packet.data, packet.size); + #endif + + // Did we get a video frame? + if(got_picture) + { + //picture_pts = picture->best_effort_timestamp; + if( picture_pts == AV_NOPTS_VALUE_ ) + picture_pts = packet.pts != AV_NOPTS_VALUE_ && packet.pts != 0 ? packet.pts : packet.dts; + frame_number++; + valid = true; + } + else + { + count_errs++; + if (count_errs > max_number_of_attempts) + break; + } + + av_free_packet (&packet); + } + + if( valid && first_frame_number < 0 ) + first_frame_number = dts_to_frame_number(picture_pts); + + // return if we have a new picture or not + return valid; +} + + +bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn) +{ + if( !video_st || !picture->data[0] ) + return false; + + avpicture_fill((AVPicture*)&rgb_picture, rgb_picture.data[0], PIX_FMT_RGB24, + video_st->codec->width, video_st->codec->height); + + if( img_convert_ctx == NULL || + frame.width != video_st->codec->width || + frame.height != video_st->codec->height ) + { + if( img_convert_ctx ) + sws_freeContext(img_convert_ctx); + + frame.width = video_st->codec->width; + frame.height = video_st->codec->height; + + img_convert_ctx = sws_getCachedContext( + NULL, + video_st->codec->width, video_st->codec->height, + video_st->codec->pix_fmt, + video_st->codec->width, video_st->codec->height, + PIX_FMT_BGR24, + SWS_BICUBIC, + NULL, NULL, NULL + ); + + if (img_convert_ctx == NULL) + return false;//CV_Error(0, "Cannot initialize the conversion context!"); + } + + sws_scale( + img_convert_ctx, + picture->data, + picture->linesize, + 0, video_st->codec->height, + rgb_picture.data, + rgb_picture.linesize + ); + + *data = frame.data; + *step = frame.step; + *width = frame.width; + *height = frame.height; + *cn = frame.cn; + + return true; +} + + +double CvCapture_FFMPEG::getProperty( int property_id ) +{ + if( !video_st ) return 0; + + switch( property_id ) + { + case CV_FFMPEG_CAP_PROP_POS_MSEC: + return 1000.0*(double)frame_number/get_fps(); + case CV_FFMPEG_CAP_PROP_POS_FRAMES: + return (double)frame_number; + case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO: + return r2d(ic->streams[video_stream]->time_base); + case CV_FFMPEG_CAP_PROP_FRAME_COUNT: + return (double)get_total_frames(); + case CV_FFMPEG_CAP_PROP_FRAME_WIDTH: + return (double)frame.width; + case CV_FFMPEG_CAP_PROP_FRAME_HEIGHT: + return (double)frame.height; + case CV_FFMPEG_CAP_PROP_FPS: +#if LIBAVCODEC_BUILD > 4753 + return av_q2d(video_st->r_frame_rate); +#else + return (double)video_st->codec.frame_rate + / (double)video_st->codec.frame_rate_base; +#endif + case CV_FFMPEG_CAP_PROP_FOURCC: +#if LIBAVFORMAT_BUILD > 4628 + return (double)video_st->codec->codec_tag; +#else + return (double)video_st->codec.codec_tag; +#endif + default: + break; + } + + return 0; +} + +double CvCapture_FFMPEG::r2d(AVRational r) +{ + return r.num == 0 || r.den == 0 ? 0. : (double)r.num / (double)r.den; +} + +double CvCapture_FFMPEG::get_duration_sec() +{ + double sec = (double)ic->duration / (double)AV_TIME_BASE; + + if (sec < eps_zero) + { + sec = (double)ic->streams[video_stream]->duration * r2d(ic->streams[video_stream]->time_base); + } + + if (sec < eps_zero) + { + sec = (double)ic->streams[video_stream]->duration * r2d(ic->streams[video_stream]->time_base); + } + + return sec; +} + +int CvCapture_FFMPEG::get_bitrate() +{ + return ic->bit_rate; +} + +double CvCapture_FFMPEG::get_fps() +{ + double fps = r2d(ic->streams[video_stream]->r_frame_rate); + +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0) + if (fps < eps_zero) + { + fps = r2d(ic->streams[video_stream]->avg_frame_rate); + } +#endif + + if (fps < eps_zero) + { + fps = 1.0 / r2d(ic->streams[video_stream]->codec->time_base); + } + + return fps; +} + +int64_t CvCapture_FFMPEG::get_total_frames() +{ + int64_t nbf = ic->streams[video_stream]->nb_frames; + + if (nbf == 0) + { + nbf = (int64_t)floor(get_duration_sec() * get_fps() + 0.5); + } + return nbf; +} + +int64_t CvCapture_FFMPEG::dts_to_frame_number(int64_t dts) +{ + double sec = dts_to_sec(dts); + return (int64_t)(get_fps() * sec + 0.5); +} + +double CvCapture_FFMPEG::dts_to_sec(int64_t dts) +{ + return (double)(dts - ic->streams[video_stream]->start_time) * + r2d(ic->streams[video_stream]->time_base); +} + +void CvCapture_FFMPEG::seek(int64_t _frame_number) +{ + _frame_number = std::min(_frame_number, get_total_frames()); + int delta = 16; + + // if we have not grabbed a single frame before first seek, let's read the first frame + // and get some valuable information during the process + if( first_frame_number < 0 && get_total_frames() > 1 ) + grabFrame(); + + for(;;) + { + int64_t _frame_number_temp = std::max(_frame_number-delta, (int64_t)0); + double sec = (double)_frame_number_temp / get_fps(); + int64_t time_stamp = ic->streams[video_stream]->start_time; + double time_base = r2d(ic->streams[video_stream]->time_base); + time_stamp += (int64_t)(sec / time_base + 0.5); + if (get_total_frames() > 1) av_seek_frame(ic, video_stream, time_stamp, AVSEEK_FLAG_BACKWARD); + avcodec_flush_buffers(ic->streams[video_stream]->codec); + if( _frame_number > 0 ) + { + grabFrame(); + + if( _frame_number > 1 ) + { + frame_number = dts_to_frame_number(picture_pts) - first_frame_number; + //printf("_frame_number = %d, frame_number = %d, delta = %d\n", + // (int)_frame_number, (int)frame_number, delta); + + if( frame_number < 0 || frame_number > _frame_number-1 ) + { + if( _frame_number_temp == 0 || delta >= INT_MAX/4 ) + break; + delta = delta < 16 ? delta*2 : delta*3/2; + continue; + } + while( frame_number < _frame_number-1 ) + { + if(!grabFrame()) + break; + } + frame_number++; + break; + } + else + { + frame_number = 1; + break; + } + } + else + { + frame_number = 0; + break; + } + } +} + +void CvCapture_FFMPEG::seek(double sec) +{ + seek((int64_t)(sec * get_fps() + 0.5)); +} + +bool CvCapture_FFMPEG::setProperty( int property_id, double value ) +{ + if( !video_st ) return false; + + switch( property_id ) + { + case CV_FFMPEG_CAP_PROP_POS_MSEC: + case CV_FFMPEG_CAP_PROP_POS_FRAMES: + case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO: + { + switch( property_id ) + { + case CV_FFMPEG_CAP_PROP_POS_FRAMES: + seek((int64_t)value); + break; + + case CV_FFMPEG_CAP_PROP_POS_MSEC: + seek(value/1000.0); + break; + + case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO: + seek((int64_t)(value*ic->duration)); + break; + } + + picture_pts=(int64_t)value; + } + break; + default: + return false; + } + + return true; +} + + +///////////////// FFMPEG CvVideoWriter implementation ////////////////////////// +struct CvVideoWriter_FFMPEG +{ + bool open( const char* filename, int fourcc, + double fps, int width, int height, bool isColor ); + void close(); + bool writeFrame( const unsigned char* data, int step, int width, int height, int cn, int origin ); + + void init(); + + AVOutputFormat * fmt; + AVFormatContext * oc; + uint8_t * outbuf; + uint32_t outbuf_size; + FILE * outfile; + AVFrame * picture; + AVFrame * input_picture; + uint8_t * picbuf; + AVStream * video_st; + int input_pix_fmt; + Image_FFMPEG temp_image; + int frame_width, frame_height; + bool ok; + struct SwsContext *img_convert_ctx; +}; + +static const char * icvFFMPEGErrStr(int err) +{ +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) + switch(err) { + case AVERROR_BSF_NOT_FOUND: + return "Bitstream filter not found"; + case AVERROR_DECODER_NOT_FOUND: + return "Decoder not found"; + case AVERROR_DEMUXER_NOT_FOUND: + return "Demuxer not found"; + case AVERROR_ENCODER_NOT_FOUND: + return "Encoder not found"; + case AVERROR_EOF: + return "End of file"; + case AVERROR_EXIT: + return "Immediate exit was requested; the called function should not be restarted"; + case AVERROR_FILTER_NOT_FOUND: + return "Filter not found"; + case AVERROR_INVALIDDATA: + return "Invalid data found when processing input"; + case AVERROR_MUXER_NOT_FOUND: + return "Muxer not found"; + case AVERROR_OPTION_NOT_FOUND: + return "Option not found"; + case AVERROR_PATCHWELCOME: + return "Not yet implemented in FFmpeg, patches welcome"; + case AVERROR_PROTOCOL_NOT_FOUND: + return "Protocol not found"; + case AVERROR_STREAM_NOT_FOUND: + return "Stream not found"; + default: + break; + } +#else + switch(err) { + case AVERROR_NUMEXPECTED: + return "Incorrect filename syntax"; + case AVERROR_INVALIDDATA: + return "Invalid data in header"; + case AVERROR_NOFMT: + return "Unknown format"; + case AVERROR_IO: + return "I/O error occurred"; + case AVERROR_NOMEM: + return "Memory allocation error"; + default: + break; + } +#endif + + return "Unspecified error"; +} + +/* function internal to FFMPEG (libavformat/riff.c) to lookup codec id by fourcc tag*/ +extern "C" { + enum CodecID codec_get_bmp_id(unsigned int tag); +} + +void CvVideoWriter_FFMPEG::init() +{ + fmt = 0; + oc = 0; + outbuf = 0; + outbuf_size = 0; + outfile = 0; + picture = 0; + input_picture = 0; + picbuf = 0; + video_st = 0; + input_pix_fmt = 0; + memset(&temp_image, 0, sizeof(temp_image)); + img_convert_ctx = 0; + frame_width = frame_height = 0; + ok = false; +} + +/** + * the following function is a modified version of code + * found in ffmpeg-0.4.9-pre1/output_example.c + */ +static AVFrame * icv_alloc_picture_FFMPEG(int pix_fmt, int width, int height, bool alloc) +{ + AVFrame * picture; + uint8_t * picture_buf; + int size; + + picture = avcodec_alloc_frame(); + if (!picture) + return NULL; + size = avpicture_get_size( (PixelFormat) pix_fmt, width, height); + if(alloc){ + picture_buf = (uint8_t *) malloc(size); + if (!picture_buf) + { + av_free(picture); + return NULL; + } + avpicture_fill((AVPicture *)picture, picture_buf, + (PixelFormat) pix_fmt, width, height); + } + else { + } + return picture; +} + +/* add a video output stream to the container */ +static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc, + CodecID codec_id, + int w, int h, int bitrate, + double fps, int pixel_format) +{ + AVCodecContext *c; + AVStream *st; + int frame_rate, frame_rate_base; + AVCodec *codec; + +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 10, 0) + st = avformat_new_stream(oc, 0); +#else + st = av_new_stream(oc, 0); +#endif + + if (!st) { + CV_WARN("Could not allocate stream"); + return NULL; + } + +#if LIBAVFORMAT_BUILD > 4628 + c = st->codec; +#else + c = &(st->codec); +#endif + +#if LIBAVFORMAT_BUILD > 4621 + c->codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_VIDEO); +#else + c->codec_id = oc->oformat->video_codec; +#endif + + if(codec_id != CODEC_ID_NONE){ + c->codec_id = codec_id; + } + + //if(codec_tag) c->codec_tag=codec_tag; + codec = avcodec_find_encoder(c->codec_id); + + c->codec_type = AVMEDIA_TYPE_VIDEO; + + /* put sample parameters */ + int64_t lbit_rate = (int64_t)bitrate; + lbit_rate += (bitrate / 2); + lbit_rate = std::min(lbit_rate, (int64_t)INT_MAX); + c->bit_rate = lbit_rate; + + // took advice from + // http://ffmpeg-users.933282.n4.nabble.com/warning-clipping-1-dct-coefficients-to-127-127-td934297.html + c->qmin = 3; + + /* resolution must be a multiple of two */ + c->width = w; + c->height = h; + + /* time base: this is the fundamental unit of time (in seconds) in terms + of which frame timestamps are represented. for fixed-fps content, + timebase should be 1/framerate and timestamp increments should be + identically 1. */ + frame_rate=(int)(fps+0.5); + frame_rate_base=1; + while (fabs((double)frame_rate/frame_rate_base) - fps > 0.001){ + frame_rate_base*=10; + frame_rate=(int)(fps*frame_rate_base + 0.5); + } +#if LIBAVFORMAT_BUILD > 4752 + c->time_base.den = frame_rate; + c->time_base.num = frame_rate_base; + /* adjust time base for supported framerates */ + if(codec && codec->supported_framerates){ + const AVRational *p= codec->supported_framerates; + AVRational req = {frame_rate, frame_rate_base}; + const AVRational *best=NULL; + AVRational best_error= {INT_MAX, 1}; + for(; p->den!=0; p++){ + AVRational error= av_sub_q(req, *p); + if(error.num <0) error.num *= -1; + if(av_cmp_q(error, best_error) < 0){ + best_error= error; + best= p; + } + } + c->time_base.den= best->num; + c->time_base.num= best->den; + } +#else + c->frame_rate = frame_rate; + c->frame_rate_base = frame_rate_base; +#endif + + c->gop_size = 12; /* emit one intra frame every twelve frames at most */ + c->pix_fmt = (PixelFormat) pixel_format; + + if (c->codec_id == CODEC_ID_MPEG2VIDEO) { + c->max_b_frames = 2; + } + if (c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MSMPEG4V3){ + /* needed to avoid using macroblocks in which some coeffs overflow + this doesnt happen with normal video, it just happens here as the + motion of the chroma plane doesnt match the luma plane */ + /* avoid FFMPEG warning 'clipping 1 dct coefficients...' */ + c->mb_decision=2; + } +#if LIBAVCODEC_VERSION_INT>0x000409 + // some formats want stream headers to be seperate + if(oc->oformat->flags & AVFMT_GLOBALHEADER) + { + c->flags |= CODEC_FLAG_GLOBAL_HEADER; + } +#endif + + return st; +} + +static const int OPENCV_NO_FRAMES_WRITTEN_CODE = 1000; + +static int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st, uint8_t * outbuf, uint32_t outbuf_size, AVFrame * picture ) +{ +#if LIBAVFORMAT_BUILD > 4628 + AVCodecContext * c = video_st->codec; +#else + AVCodecContext * c = &(video_st->codec); +#endif + int out_size; + int ret = 0; + + if (oc->oformat->flags & AVFMT_RAWPICTURE) { + /* raw video case. The API will change slightly in the near + futur for that */ + AVPacket pkt; + av_init_packet(&pkt); + +#ifndef PKT_FLAG_KEY +#define PKT_FLAG_KEY AV_PKT_FLAG_KEY +#endif + + pkt.flags |= PKT_FLAG_KEY; + pkt.stream_index= video_st->index; + pkt.data= (uint8_t *)picture; + pkt.size= sizeof(AVPicture); + + ret = av_write_frame(oc, &pkt); + } else { + /* encode the image */ + out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture); + /* if zero size, it means the image was buffered */ + if (out_size > 0) { + AVPacket pkt; + av_init_packet(&pkt); + +#if LIBAVFORMAT_BUILD > 4752 + if(c->coded_frame->pts != (int64_t)AV_NOPTS_VALUE) + pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, video_st->time_base); +#else + pkt.pts = c->coded_frame->pts; +#endif + if(c->coded_frame->key_frame) + pkt.flags |= PKT_FLAG_KEY; + pkt.stream_index= video_st->index; + pkt.data= outbuf; + pkt.size= out_size; + + /* write the compressed frame in the media file */ + ret = av_write_frame(oc, &pkt); + } else { + ret = OPENCV_NO_FRAMES_WRITTEN_CODE; + } + } + return ret; +} + +/// write a frame with FFMPEG +bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int width, int height, int cn, int origin ) +{ + bool ret = false; + + if( (width & -2) != frame_width || (height & -2) != frame_height || !data ) + return false; + width = frame_width; + height = frame_height; + + // typecast from opaque data type to implemented struct +#if LIBAVFORMAT_BUILD > 4628 + AVCodecContext *c = video_st->codec; +#else + AVCodecContext *c = &(video_st->codec); +#endif + +#if LIBAVFORMAT_BUILD < 5231 + // It is not needed in the latest versions of the ffmpeg + if( c->codec_id == CODEC_ID_RAWVIDEO && origin != 1 ) + { + if( !temp_image.data ) + { + temp_image.step = (width*cn + 3) & -4; + temp_image.width = width; + temp_image.height = height; + temp_image.cn = cn; + temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height); + } + for( int y = 0; y < height; y++ ) + memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, width*cn); + data = temp_image.data; + step = temp_image.step; + } +#else + if( width*cn != step ) + { + if( !temp_image.data ) + { + temp_image.step = width*cn; + temp_image.width = width; + temp_image.height = height; + temp_image.cn = cn; + temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height); + } + if (origin == 1) + for( int y = 0; y < height; y++ ) + memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, temp_image.step); + else + for( int y = 0; y < height; y++ ) + memcpy(temp_image.data + y*temp_image.step, data + y*step, temp_image.step); + data = temp_image.data; + step = temp_image.step; + } +#endif + + // check parameters + if (input_pix_fmt == PIX_FMT_BGR24) { + if (cn != 3) { + return false; + } + } + else if (input_pix_fmt == PIX_FMT_GRAY8) { + if (cn != 1) { + return false; + } + } + else { + assert(false); + } + + if ( c->pix_fmt != input_pix_fmt ) { + assert( input_picture ); + // let input_picture point to the raw data buffer of 'image' + avpicture_fill((AVPicture *)input_picture, (uint8_t *) data, + (PixelFormat)input_pix_fmt, width, height); + + if( !img_convert_ctx ) + { + img_convert_ctx = sws_getContext(width, + height, + (PixelFormat)input_pix_fmt, + c->width, + c->height, + c->pix_fmt, + SWS_BICUBIC, + NULL, NULL, NULL); + if( !img_convert_ctx ) + return false; + } + + if ( sws_scale(img_convert_ctx, input_picture->data, + input_picture->linesize, 0, + height, + picture->data, picture->linesize) < 0 ) + return false; + } + else{ + avpicture_fill((AVPicture *)picture, (uint8_t *) data, + (PixelFormat)input_pix_fmt, width, height); + } + + ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, picture) >= 0; + + return ret; +} + +/// close video output stream and free associated memory +void CvVideoWriter_FFMPEG::close() +{ + unsigned i; + + // nothing to do if already released + if ( !picture ) + return; + + /* no more frame to compress. The codec has a latency of a few + frames if using B frames, so we get the last frames by + passing the same picture again */ + // TODO -- do we need to account for latency here? + + /* write the trailer, if any */ + if(ok && oc) + { + if( (oc->oformat->flags & AVFMT_RAWPICTURE) == 0 ) + { + for(;;) + { + int ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, NULL); + if( ret == OPENCV_NO_FRAMES_WRITTEN_CODE || ret < 0 ) + break; + } + } + av_write_trailer(oc); + } + + if( img_convert_ctx ) + { + sws_freeContext(img_convert_ctx); + img_convert_ctx = 0; + } + + // free pictures +#if LIBAVFORMAT_BUILD > 4628 + if( video_st->codec->pix_fmt != input_pix_fmt) +#else + if( video_st->codec.pix_fmt != input_pix_fmt) +#endif + { + if(picture->data[0]) + free(picture->data[0]); + picture->data[0] = 0; + } + av_free(picture); + + if (input_picture) + av_free(input_picture); + + /* close codec */ +#if LIBAVFORMAT_BUILD > 4628 + avcodec_close(video_st->codec); +#else + avcodec_close(&(video_st->codec)); +#endif + + av_free(outbuf); + + /* free the streams */ + for(i = 0; i < oc->nb_streams; i++) + { + av_freep(&oc->streams[i]->codec); + av_freep(&oc->streams[i]); + } + + if (!(fmt->flags & AVFMT_NOFILE)) + { + /* close the output file */ + +#if LIBAVCODEC_VERSION_INT < ((52<<16)+(123<<8)+0) +#if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0) + url_fclose(oc->pb); +#else + url_fclose(&oc->pb); +#endif +#else + avio_close(oc->pb); +#endif + + } + + /* free the stream */ + av_free(oc); + + if( temp_image.data ) + { + free(temp_image.data); + temp_image.data = 0; + } + + init(); +} + +/// Create a video writer object that uses FFMPEG +bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, + double fps, int width, int height, bool is_color ) +{ + icvInitFFMPEG_internal(); + + CodecID codec_id = CODEC_ID_NONE; + int err, codec_pix_fmt; + double bitrate_scale = 1; + + close(); + + // check arguments + if( !filename ) + return false; + if(fps <= 0) + return false; + + // we allow frames of odd width or height, but in this case we truncate + // the rightmost column/the bottom row. Probably, this should be handled more elegantly, + // but some internal functions inside FFMPEG swscale require even width/height. + width &= -2; + height &= -2; + if( width <= 0 || height <= 0 ) + return false; + + /* auto detect the output format from the name and fourcc code. */ + +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) + fmt = av_guess_format(NULL, filename, NULL); +#else + fmt = guess_format(NULL, filename, NULL); +#endif + + if (!fmt) + return false; + + /* determine optimal pixel format */ + if (is_color) { + input_pix_fmt = PIX_FMT_BGR24; + } + else { + input_pix_fmt = PIX_FMT_GRAY8; + } + + /* Lookup codec_id for given fourcc */ +#if LIBAVCODEC_VERSION_INT<((51<<16)+(49<<8)+0) + if( (codec_id = codec_get_bmp_id( fourcc )) == CODEC_ID_NONE ) + return false; +#else + const struct AVCodecTag * tags[] = { codec_bmp_tags, NULL}; + if( (codec_id = av_codec_get_id(tags, fourcc)) == CODEC_ID_NONE ) + return false; +#endif + + // alloc memory for context +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) + oc = avformat_alloc_context(); +#else + oc = av_alloc_format_context(); +#endif + assert (oc); + + /* set file name */ + oc->oformat = fmt; + snprintf(oc->filename, sizeof(oc->filename), "%s", filename); + + /* set some options */ + oc->max_delay = (int)(0.7*AV_TIME_BASE); /* This reduces buffer underrun warnings with MPEG */ + + // set a few optimal pixel formats for lossless codecs of interest.. + switch (codec_id) { +#if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0) + case CODEC_ID_JPEGLS: + // BGR24 or GRAY8 depending on is_color... + codec_pix_fmt = input_pix_fmt; + break; +#endif + case CODEC_ID_HUFFYUV: + codec_pix_fmt = PIX_FMT_YUV422P; + break; + case CODEC_ID_MJPEG: + case CODEC_ID_LJPEG: + codec_pix_fmt = PIX_FMT_YUVJ420P; + bitrate_scale = 3; + break; + case CODEC_ID_RAWVIDEO: + codec_pix_fmt = input_pix_fmt == PIX_FMT_GRAY8 || + input_pix_fmt == PIX_FMT_GRAY16LE || + input_pix_fmt == PIX_FMT_GRAY16BE ? input_pix_fmt : PIX_FMT_YUV420P; + break; + default: + // good for lossy formats, MPEG, etc. + codec_pix_fmt = PIX_FMT_YUV420P; + break; + } + + double bitrate = MIN(bitrate_scale*fps*width*height, (double)INT_MAX/2); + + // TODO -- safe to ignore output audio stream? + video_st = icv_add_video_stream_FFMPEG(oc, codec_id, + width, height, (int)(bitrate + 0.5), + fps, codec_pix_fmt); + + /* set the output parameters (must be done even if no + parameters). */ +#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) + if (av_set_parameters(oc, NULL) < 0) { + return false; + } +#endif + +#if 0 +#if FF_API_DUMP_FORMAT + dump_format(oc, 0, filename, 1); +#else + av_dump_format(oc, 0, filename, 1); +#endif +#endif + + /* now that all the parameters are set, we can open the audio and + video codecs and allocate the necessary encode buffers */ + if (!video_st){ + return false; + } + + AVCodec *codec; + AVCodecContext *c; + +#if LIBAVFORMAT_BUILD > 4628 + c = (video_st->codec); +#else + c = &(video_st->codec); +#endif + + c->codec_tag = fourcc; + /* find the video encoder */ + codec = avcodec_find_encoder(c->codec_id); + if (!codec) { + fprintf(stderr, "Could not find encoder for codec id %d: %s", c->codec_id, icvFFMPEGErrStr( + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) + AVERROR_ENCODER_NOT_FOUND + #else + -1 + #endif + )); + return false; + } + + int64_t lbit_rate = (int64_t)c->bit_rate; + lbit_rate += (bitrate / 2); + lbit_rate = std::min(lbit_rate, (int64_t)INT_MAX); + c->bit_rate_tolerance = (int)lbit_rate; + c->bit_rate = (int)lbit_rate; + + /* open the codec */ + if ((err= +#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) + avcodec_open2(c, codec, NULL) +#else + avcodec_open(c, codec) +#endif + ) < 0) { + fprintf(stderr, "Could not open codec '%s': %s", codec->name, icvFFMPEGErrStr(err)); + return false; + } + + outbuf = NULL; + + if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) { + /* allocate output buffer */ + /* assume we will never get codec output with more than 4 bytes per pixel... */ + outbuf_size = width*height*4; + outbuf = (uint8_t *) av_malloc(outbuf_size); + } + + bool need_color_convert; + need_color_convert = (c->pix_fmt != input_pix_fmt); + + /* allocate the encoded raw picture */ + picture = icv_alloc_picture_FFMPEG(c->pix_fmt, c->width, c->height, need_color_convert); + if (!picture) { + return false; + } + + /* if the output format is not our input format, then a temporary + picture of the input format is needed too. It is then converted + to the required output format */ + input_picture = NULL; + if ( need_color_convert ) { + input_picture = icv_alloc_picture_FFMPEG(input_pix_fmt, c->width, c->height, false); + if (!input_picture) { + return false; + } + } + + /* open the output file, if needed */ + if (!(fmt->flags & AVFMT_NOFILE)) { +#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) + if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) +#else + if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) +#endif + { + return false; + } + } + +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0) + /* write the stream header, if any */ + err=avformat_write_header(oc, NULL); +#else + err=av_write_header( oc ); +#endif + + if(err < 0) + { + close(); + remove(filename); + return false; + } + frame_width = width; + frame_height = height; + ok = true; + return true; +} + + + +CvCapture_FFMPEG* cvCreateFileCapture_FFMPEG( const char* filename ) +{ + CvCapture_FFMPEG* capture = (CvCapture_FFMPEG*)malloc(sizeof(*capture)); + capture->init(); + if( capture->open( filename )) + return capture; + capture->close(); + free(capture); + return 0; +} + + +void cvReleaseCapture_FFMPEG(CvCapture_FFMPEG** capture) +{ + if( capture && *capture ) + { + (*capture)->close(); + free(*capture); + *capture = 0; + } +} + +int cvSetCaptureProperty_FFMPEG(CvCapture_FFMPEG* capture, int prop_id, double value) +{ + return capture->setProperty(prop_id, value); +} + +double cvGetCaptureProperty_FFMPEG(CvCapture_FFMPEG* capture, int prop_id) +{ + return capture->getProperty(prop_id); +} + +int cvGrabFrame_FFMPEG(CvCapture_FFMPEG* capture) +{ + return capture->grabFrame(); +} + +int cvRetrieveFrame_FFMPEG(CvCapture_FFMPEG* capture, unsigned char** data, int* step, int* width, int* height, int* cn) +{ + return capture->retrieveFrame(0, data, step, width, height, cn); +} + +CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG( const char* filename, int fourcc, double fps, + int width, int height, int isColor ) +{ + CvVideoWriter_FFMPEG* writer = (CvVideoWriter_FFMPEG*)malloc(sizeof(*writer)); + writer->init(); + if( writer->open( filename, fourcc, fps, width, height, isColor != 0 )) + return writer; + writer->close(); + free(writer); + return 0; +} + + +void cvReleaseVideoWriter_FFMPEG( CvVideoWriter_FFMPEG** writer ) +{ + if( writer && *writer ) + { + (*writer)->close(); + free(*writer); + *writer = 0; + } +} + + +int cvWriteFrame_FFMPEG( CvVideoWriter_FFMPEG* writer, + const unsigned char* data, int step, + int width, int height, int cn, int origin) +{ + return writer->writeFrame(data, step, width, height, cn, origin); +} + + + +/* + * For CUDA encoder + */ + +struct OutputMediaStream_FFMPEG +{ + bool open(const char* fileName, int width, int height, double fps); + void close(); + + void write(unsigned char* data, int size, int keyFrame); + + // add a video output stream to the container + static AVStream* addVideoStream(AVFormatContext *oc, CodecID codec_id, int w, int h, int bitrate, double fps, PixelFormat pixel_format); + + AVOutputFormat* fmt_; + AVFormatContext* oc_; + AVStream* video_st_; +}; + +void OutputMediaStream_FFMPEG::close() +{ + // no more frame to compress. The codec has a latency of a few + // frames if using B frames, so we get the last frames by + // passing the same picture again + + // TODO -- do we need to account for latency here? + + if (oc_) + { + // write the trailer, if any + av_write_trailer(oc_); + + // free the streams + for (unsigned int i = 0; i < oc_->nb_streams; ++i) + { + av_freep(&oc_->streams[i]->codec); + av_freep(&oc_->streams[i]); + } + + if (!(fmt_->flags & AVFMT_NOFILE) && oc_->pb) + { + // close the output file + + #if LIBAVCODEC_VERSION_INT < ((52<<16)+(123<<8)+0) + #if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0) + url_fclose(oc_->pb); + #else + url_fclose(&oc_->pb); + #endif + #else + avio_close(oc_->pb); + #endif + } + + // free the stream + av_free(oc_); + } +} + +AVStream* OutputMediaStream_FFMPEG::addVideoStream(AVFormatContext *oc, CodecID codec_id, int w, int h, int bitrate, double fps, PixelFormat pixel_format) +{ + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 10, 0) + AVStream* st = avformat_new_stream(oc, 0); + #else + AVStream* st = av_new_stream(oc, 0); + #endif + if (!st) + return 0; + + #if LIBAVFORMAT_BUILD > 4628 + AVCodecContext* c = st->codec; + #else + AVCodecContext* c = &(st->codec); + #endif + + c->codec_id = codec_id; + c->codec_type = AVMEDIA_TYPE_VIDEO; + + // put sample parameters + unsigned long long lbit_rate = static_cast(bitrate); + lbit_rate += (bitrate / 4); + lbit_rate = std::min(lbit_rate, static_cast(std::numeric_limits::max())); + c->bit_rate = bitrate; + + // took advice from + // http://ffmpeg-users.933282.n4.nabble.com/warning-clipping-1-dct-coefficients-to-127-127-td934297.html + c->qmin = 3; + + // resolution must be a multiple of two + c->width = w; + c->height = h; + + AVCodec* codec = avcodec_find_encoder(c->codec_id); + + // time base: this is the fundamental unit of time (in seconds) in terms + // of which frame timestamps are represented. for fixed-fps content, + // timebase should be 1/framerate and timestamp increments should be + // identically 1 + + int frame_rate = static_cast(fps+0.5); + int frame_rate_base = 1; + while (fabs(static_cast(frame_rate)/frame_rate_base) - fps > 0.001) + { + frame_rate_base *= 10; + frame_rate = static_cast(fps*frame_rate_base + 0.5); + } + c->time_base.den = frame_rate; + c->time_base.num = frame_rate_base; + + #if LIBAVFORMAT_BUILD > 4752 + // adjust time base for supported framerates + if (codec && codec->supported_framerates) + { + AVRational req = {frame_rate, frame_rate_base}; + const AVRational* best = NULL; + AVRational best_error = {INT_MAX, 1}; + + for (const AVRational* p = codec->supported_framerates; p->den!=0; ++p) + { + AVRational error = av_sub_q(req, *p); + + if (error.num < 0) + error.num *= -1; + + if (av_cmp_q(error, best_error) < 0) + { + best_error= error; + best= p; + } + } + + c->time_base.den= best->num; + c->time_base.num= best->den; + } + #endif + + c->gop_size = 12; // emit one intra frame every twelve frames at most + c->pix_fmt = pixel_format; + + if (c->codec_id == CODEC_ID_MPEG2VIDEO) + c->max_b_frames = 2; + + if (c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MSMPEG4V3) + { + // needed to avoid using macroblocks in which some coeffs overflow + // this doesnt happen with normal video, it just happens here as the + // motion of the chroma plane doesnt match the luma plane + + // avoid FFMPEG warning 'clipping 1 dct coefficients...' + + c->mb_decision = 2; + } + + #if LIBAVCODEC_VERSION_INT > 0x000409 + // some formats want stream headers to be seperate + if (oc->oformat->flags & AVFMT_GLOBALHEADER) + { + c->flags |= CODEC_FLAG_GLOBAL_HEADER; + } + #endif + + return st; +} + +bool OutputMediaStream_FFMPEG::open(const char* fileName, int width, int height, double fps) +{ + fmt_ = 0; + oc_ = 0; + video_st_ = 0; + + // tell FFMPEG to register codecs + av_register_all(); + + av_log_set_level(AV_LOG_ERROR); + + // auto detect the output format from the name and fourcc code + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) + fmt_ = av_guess_format(NULL, fileName, NULL); + #else + fmt_ = guess_format(NULL, fileName, NULL); + #endif + if (!fmt_) + return false; + + CodecID codec_id = CODEC_ID_H264; + + // alloc memory for context + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) + oc_ = avformat_alloc_context(); + #else + oc_ = av_alloc_format_context(); + #endif + if (!oc_) + return false; + + // set some options + oc_->oformat = fmt_; + snprintf(oc_->filename, sizeof(oc_->filename), "%s", fileName); + + oc_->max_delay = (int)(0.7 * AV_TIME_BASE); // This reduces buffer underrun warnings with MPEG + + // set a few optimal pixel formats for lossless codecs of interest.. + PixelFormat codec_pix_fmt = PIX_FMT_YUV420P; + int bitrate_scale = 64; + + // TODO -- safe to ignore output audio stream? + video_st_ = addVideoStream(oc_, codec_id, width, height, width * height * bitrate_scale, fps, codec_pix_fmt); + if (!video_st_) + return false; + + // set the output parameters (must be done even if no parameters) + #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) + if (av_set_parameters(oc_, NULL) < 0) + return false; + #endif + + // now that all the parameters are set, we can open the audio and + // video codecs and allocate the necessary encode buffers + + #if LIBAVFORMAT_BUILD > 4628 + AVCodecContext* c = (video_st_->codec); + #else + AVCodecContext* c = &(video_st_->codec); + #endif + + c->codec_tag = MKTAG('H', '2', '6', '4'); + c->bit_rate_tolerance = c->bit_rate; + + // open the output file, if needed + if (!(fmt_->flags & AVFMT_NOFILE)) + { + #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) + int err = url_fopen(&oc_->pb, fileName, URL_WRONLY); + #else + int err = avio_open(&oc_->pb, fileName, AVIO_FLAG_WRITE); + #endif + + if (err != 0) + return false; + } + + // write the stream header, if any + #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) + av_write_header(oc_); + #else + avformat_write_header(oc_, NULL); + #endif + + return true; +} + +void OutputMediaStream_FFMPEG::write(unsigned char* data, int size, int keyFrame) +{ + // if zero size, it means the image was buffered + if (size > 0) + { + AVPacket pkt; + av_init_packet(&pkt); + + if (keyFrame) + pkt.flags |= PKT_FLAG_KEY; + + pkt.stream_index = video_st_->index; + pkt.data = data; + pkt.size = size; + + // write the compressed frame in the media file + av_write_frame(oc_, &pkt); + } +} + +struct OutputMediaStream_FFMPEG* create_OutputMediaStream_FFMPEG(const char* fileName, int width, int height, double fps) +{ + OutputMediaStream_FFMPEG* stream = (OutputMediaStream_FFMPEG*) malloc(sizeof(OutputMediaStream_FFMPEG)); + + if (stream->open(fileName, width, height, fps)) + return stream; + + stream->close(); + free(stream); + + return 0; +} + +void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream) +{ + stream->close(); + free(stream); +} + +void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size, int keyFrame) +{ + stream->write(data, size, keyFrame); +} + +/* + * For CUDA decoder + */ + +enum +{ + VideoCodec_MPEG1 = 0, + VideoCodec_MPEG2, + VideoCodec_MPEG4, + VideoCodec_VC1, + VideoCodec_H264, + VideoCodec_JPEG, + VideoCodec_H264_SVC, + VideoCodec_H264_MVC, + + // Uncompressed YUV + VideoCodec_YUV420 = (('I'<<24)|('Y'<<16)|('U'<<8)|('V')), // Y,U,V (4:2:0) + VideoCodec_YV12 = (('Y'<<24)|('V'<<16)|('1'<<8)|('2')), // Y,V,U (4:2:0) + VideoCodec_NV12 = (('N'<<24)|('V'<<16)|('1'<<8)|('2')), // Y,UV (4:2:0) + VideoCodec_YUYV = (('Y'<<24)|('U'<<16)|('Y'<<8)|('V')), // YUYV/YUY2 (4:2:2) + VideoCodec_UYVY = (('U'<<24)|('Y'<<16)|('V'<<8)|('Y')), // UYVY (4:2:2) +}; + +enum +{ + VideoChromaFormat_Monochrome = 0, + VideoChromaFormat_YUV420, + VideoChromaFormat_YUV422, + VideoChromaFormat_YUV444, +}; + +struct InputMediaStream_FFMPEG +{ +public: + bool open(const char* fileName, int* codec, int* chroma_format, int* width, int* height); + void close(); + + bool read(unsigned char** data, int* size, int* endOfFile); + +private: + InputMediaStream_FFMPEG(const InputMediaStream_FFMPEG&); + InputMediaStream_FFMPEG& operator =(const InputMediaStream_FFMPEG&); + + AVFormatContext* ctx_; + int video_stream_id_; + AVPacket pkt_; +}; + +bool InputMediaStream_FFMPEG::open(const char* fileName, int* codec, int* chroma_format, int* width, int* height) +{ + int err; + + ctx_ = 0; + video_stream_id_ = -1; + memset(&pkt_, 0, sizeof(AVPacket)); + + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0) + avformat_network_init(); + #endif + + // register all codecs, demux and protocols + av_register_all(); + + av_log_set_level(AV_LOG_ERROR); + + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 6, 0) + err = avformat_open_input(&ctx_, fileName, 0, 0); + #else + err = av_open_input_file(&ctx_, fileName, 0, 0, 0); + #endif + if (err < 0) + return false; + + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 3, 0) + err = avformat_find_stream_info(ctx_, 0); + #else + err = av_find_stream_info(ctx_); + #endif + if (err < 0) + return false; + + for (unsigned int i = 0; i < ctx_->nb_streams; ++i) + { + #if LIBAVFORMAT_BUILD > 4628 + AVCodecContext *enc = ctx_->streams[i]->codec; + #else + AVCodecContext *enc = &ctx_->streams[i]->codec; + #endif + + if (enc->codec_type == AVMEDIA_TYPE_VIDEO) + { + video_stream_id_ = static_cast(i); + + switch (enc->codec_id) + { + case CODEC_ID_MPEG1VIDEO: + *codec = ::VideoCodec_MPEG1; + break; + + case CODEC_ID_MPEG2VIDEO: + *codec = ::VideoCodec_MPEG2; + break; + + case CODEC_ID_MPEG4: + *codec = ::VideoCodec_MPEG4; + break; + + case CODEC_ID_VC1: + *codec = ::VideoCodec_VC1; + break; + + case CODEC_ID_H264: + *codec = ::VideoCodec_H264; + break; + + default: + return false; + }; + + switch (enc->pix_fmt) + { + case PIX_FMT_YUV420P: + *chroma_format = ::VideoChromaFormat_YUV420; + break; + + case PIX_FMT_YUV422P: + *chroma_format = ::VideoChromaFormat_YUV422; + break; + + case PIX_FMT_YUV444P: + *chroma_format = ::VideoChromaFormat_YUV444; + break; + + default: + return false; + } + + *width = enc->coded_width; + *height = enc->coded_height; + + break; + } + } + + if (video_stream_id_ < 0) + return false; + + av_init_packet(&pkt_); + + return true; +} + +void InputMediaStream_FFMPEG::close() +{ + if (ctx_) + { + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 24, 2) + avformat_close_input(&ctx_); + #else + av_close_input_file(ctx_); + #endif + } + + // free last packet if exist + if (pkt_.data) + av_free_packet(&pkt_); +} + +bool InputMediaStream_FFMPEG::read(unsigned char** data, int* size, int* endOfFile) +{ + // free last packet if exist + if (pkt_.data) + av_free_packet(&pkt_); + + // get the next frame + for (;;) + { + int ret = av_read_frame(ctx_, &pkt_); + + if (ret == AVERROR(EAGAIN)) + continue; + + if (ret < 0) + { + if ((int64_t)ret == (int64_t)AVERROR_EOF) + *endOfFile = true; + return false; + } + + if (pkt_.stream_index != video_stream_id_) + { + av_free_packet(&pkt_); + continue; + } + + break; + } + + *data = pkt_.data; + *size = pkt_.size; + *endOfFile = false; + + return true; +} + +InputMediaStream_FFMPEG* create_InputMediaStream_FFMPEG(const char* fileName, int* codec, int* chroma_format, int* width, int* height) +{ + InputMediaStream_FFMPEG* stream = (InputMediaStream_FFMPEG*) malloc(sizeof(InputMediaStream_FFMPEG)); + + if (stream && stream->open(fileName, codec, chroma_format, width, height)) + return stream; + + stream->close(); + free(stream); + + return 0; +} + +void release_InputMediaStream_FFMPEG(InputMediaStream_FFMPEG* stream) +{ + stream->close(); + free(stream); +} + +int read_InputMediaStream_FFMPEG(InputMediaStream_FFMPEG* stream, unsigned char** data, int* size, int* endOfFile) +{ + return stream->read(data, size, endOfFile); +} diff --git a/highgui/src/cap_gstreamer.cpp b/highgui/src/cap_gstreamer.cpp new file mode 100644 index 0000000..ecce0b5 --- /dev/null +++ b/highgui/src/cap_gstreamer.cpp @@ -0,0 +1,750 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2008, 2011, Nils Hasler, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +// Author: Nils Hasler +// +// Max-Planck-Institut Informatik +// +// this implementation was inspired by gnash's gstreamer interface + +// +// use GStreamer to read a video +// + +#include "precomp.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef NDEBUG +#define CV_WARN(message) +#else +#define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__) +#endif + +static bool isInited = false; +class CvCapture_GStreamer : public CvCapture +{ +public: + CvCapture_GStreamer() { init(); } + virtual ~CvCapture_GStreamer() { close(); } + + virtual bool open( int type, const char* filename ); + virtual void close(); + + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + +protected: + void init(); + bool reopen(); + void handleMessage(); + void restartPipeline(); + void setFilter(const char*, int, int, int); + void removeFilter(const char *filter); + void static newPad(GstElement *myelement, + GstPad *pad, + gpointer data); + GstElement *pipeline; + GstElement *uridecodebin; + GstElement *color; + GstElement *sink; + + GstBuffer *buffer; + GstCaps *caps; + IplImage *frame; +}; + +void CvCapture_GStreamer::init() +{ + pipeline=0; + frame=0; + buffer=0; + frame=0; + +} + +void CvCapture_GStreamer::handleMessage() +{ + GstBus* bus = gst_element_get_bus(pipeline); + + while(gst_bus_have_pending(bus)) { + GstMessage* msg = gst_bus_pop(bus); + +// printf("Got %s message\n", GST_MESSAGE_TYPE_NAME(msg)); + + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_STATE_CHANGED: + GstState oldstate, newstate, pendstate; + gst_message_parse_state_changed(msg, &oldstate, &newstate, &pendstate); +// printf("state changed from %d to %d (%d)\n", oldstate, newstate, pendstate); + break; + case GST_MESSAGE_ERROR: { + GError *err; + gchar *debug; + gst_message_parse_error(msg, &err, &debug); + + fprintf(stderr, "GStreamer Plugin: Embedded video playback halted; module %s reported: %s\n", + gst_element_get_name(GST_MESSAGE_SRC (msg)), err->message); + + g_error_free(err); + g_free(debug); + + gst_element_set_state(pipeline, GST_STATE_NULL); + + break; + } + case GST_MESSAGE_EOS: +// CV_WARN("NetStream has reached the end of the stream."); + + break; + default: +// CV_WARN("unhandled message\n"); + break; + } + + gst_message_unref(msg); + } + + gst_object_unref(GST_OBJECT(bus)); +} + +// +// start the pipeline, grab a buffer, and pause again +// +bool CvCapture_GStreamer::grabFrame() +{ + + if(!pipeline) + return false; + + if(gst_app_sink_is_eos(GST_APP_SINK(sink))) + return false; + + if(buffer) + gst_buffer_unref(buffer); + handleMessage(); + + buffer = gst_app_sink_pull_buffer(GST_APP_SINK(sink)); + if(!buffer) + return false; + + return true; +} + +// +// decode buffer +// +IplImage * CvCapture_GStreamer::retrieveFrame(int) +{ + if(!buffer) + return false; + + if(!frame) { + gint height, width; + GstCaps *buff_caps = gst_buffer_get_caps(buffer); + assert(gst_caps_get_size(buff_caps) == 1); + GstStructure* structure = gst_caps_get_structure(buff_caps, 0); + + if(!gst_structure_get_int(structure, "width", &width) || + !gst_structure_get_int(structure, "height", &height)) + return false; + + frame = cvCreateImageHeader(cvSize(width, height), IPL_DEPTH_8U, 3); + gst_caps_unref(buff_caps); + } + + // no need to memcpy, just use gstreamer's buffer :-) + frame->imageData = (char *)GST_BUFFER_DATA(buffer); + //memcpy (frame->imageData, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE (buffer)); + //gst_buffer_unref(buffer); + //buffer = 0; + return frame; +} + +void CvCapture_GStreamer::restartPipeline() +{ + CV_FUNCNAME("icvRestartPipeline"); + + __BEGIN__; + + printf("restarting pipeline, going to ready\n"); + + if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_READY) == + GST_STATE_CHANGE_FAILURE) { + CV_ERROR(CV_StsError, "GStreamer: unable to start pipeline\n"); + return; + } + + printf("ready, relinking\n"); + + gst_element_unlink(uridecodebin, color); + printf("filtering with %s\n", gst_caps_to_string(caps)); + gst_element_link_filtered(uridecodebin, color, caps); + + printf("relinked, pausing\n"); + + if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + CV_ERROR(CV_StsError, "GStreamer: unable to start pipeline\n"); + return; + } + + printf("state now paused\n"); + + __END__; +} + +void CvCapture_GStreamer::setFilter(const char *property, int type, int v1, int v2) +{ + + if(!caps) { + if(type == G_TYPE_INT) + caps = gst_caps_new_simple("video/x-raw-rgb", property, type, v1, NULL); + else + caps = gst_caps_new_simple("video/x-raw-rgb", property, type, v1, v2, NULL); + } else { + //printf("caps before setting %s\n", gst_caps_to_string(caps)); + if(type == G_TYPE_INT) + gst_caps_set_simple(caps, "video/x-raw-rgb", property, type, v1, NULL); + else + gst_caps_set_simple(caps, "video/x-raw-rgb", property, type, v1, v2, NULL); + } + + restartPipeline(); +} + +void CvCapture_GStreamer::removeFilter(const char *filter) +{ + if(!caps) + return; + + GstStructure *s = gst_caps_get_structure(caps, 0); + gst_structure_remove_field(s, filter); + + restartPipeline(); +} + + +// +// connect uridecodebin dynamically created source pads to colourconverter +// +void CvCapture_GStreamer::newPad(GstElement * /*uridecodebin*/, + GstPad *pad, + gpointer data) +{ + GstPad *sinkpad; + GstElement *color = (GstElement *) data; + + + sinkpad = gst_element_get_static_pad (color, "sink"); + +// printf("linking dynamic pad to colourconverter %p %p\n", uridecodebin, pad); + + gst_pad_link (pad, sinkpad); + + gst_object_unref (sinkpad); +} + +bool CvCapture_GStreamer::open( int type, const char* filename ) +{ + close(); + CV_FUNCNAME("cvCaptureFromCAM_GStreamer"); + + __BEGIN__; + + if(!isInited) { +// printf("gst_init\n"); + gst_init (NULL, NULL); + +// gst_debug_set_active(TRUE); +// gst_debug_set_colored(TRUE); +// gst_debug_set_default_threshold(GST_LEVEL_WARNING); + + isInited = true; + } + bool stream = false; + bool manualpipeline = false; + char *uri = NULL; + uridecodebin = NULL; + if(type != CV_CAP_GSTREAMER_FILE) { + close(); + return false; + } + + if(!gst_uri_is_valid(filename)) { + uri = realpath(filename, NULL); + stream=false; + if(uri) { + uri = g_filename_to_uri(uri, NULL, NULL); + if(!uri) { + CV_WARN("GStreamer: Error opening file\n"); + close(); + return false; + } + } else { + GError *err = NULL; + //uridecodebin = gst_parse_bin_from_description(filename, FALSE, &err); + uridecodebin = gst_parse_launch(filename, &err); + if(!uridecodebin) { + CV_WARN("GStreamer: Error opening bin\n"); + close(); + return false; + } + stream = true; + manualpipeline = true; + } + } else { + stream = true; + uri = g_strdup(filename); + } + + if(!uridecodebin) { + uridecodebin = gst_element_factory_make ("uridecodebin", NULL); + g_object_set(G_OBJECT(uridecodebin),"uri",uri, NULL); + if(!uridecodebin) { + CV_WARN("GStreamer: Failed to create uridecodebin\n"); + close(); + return false; + } + } + + if(manualpipeline) { + GstIterator *it = gst_bin_iterate_sinks(GST_BIN(uridecodebin)); + if(gst_iterator_next(it, (gpointer *)&sink) != GST_ITERATOR_OK) { + CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n"); + return false; + } + + pipeline = uridecodebin; + } else { + pipeline = gst_pipeline_new (NULL); + + color = gst_element_factory_make("ffmpegcolorspace", NULL); + sink = gst_element_factory_make("appsink", NULL); + + gst_bin_add_many(GST_BIN(pipeline), uridecodebin, color, sink, NULL); + g_signal_connect(uridecodebin, "pad-added", G_CALLBACK(newPad), color); + + if(!gst_element_link(color, sink)) { + CV_ERROR(CV_StsError, "GStreamer: cannot link color -> sink\n"); + gst_object_unref(pipeline); + return false; + } + } + + gst_app_sink_set_max_buffers (GST_APP_SINK(sink), 1); + gst_app_sink_set_drop (GST_APP_SINK(sink), stream); + + gst_app_sink_set_caps(GST_APP_SINK(sink), gst_caps_new_simple("video/x-raw-rgb", + "red_mask", G_TYPE_INT, 0x0000FF, + "green_mask", G_TYPE_INT, 0x00FF00, + "blue_mask", G_TYPE_INT, 0xFF0000, + NULL)); + gst_caps_unref(caps); + + if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_READY) == + GST_STATE_CHANGE_FAILURE) { + CV_WARN("GStreamer: unable to set pipeline to ready\n"); + gst_object_unref(pipeline); + return false; + } + + if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL); + CV_WARN("GStreamer: unable to set pipeline to playing\n"); + gst_object_unref(pipeline); + return false; + } + + + + handleMessage(); + + __END__; + + return true; +} + +// +// +// gstreamer image sequence writer +// +// +class CvVideoWriter_GStreamer : public CvVideoWriter +{ +public: + CvVideoWriter_GStreamer() { init(); } + virtual ~CvVideoWriter_GStreamer() { close(); } + + virtual bool open( const char* filename, int fourcc, + double fps, CvSize frameSize, bool isColor ); + virtual void close(); + virtual bool writeFrame( const IplImage* image ); +protected: + void init(); + std::map encs; + GstElement* source; + GstElement* file; + GstElement* enc; + GstElement* mux; + GstElement* color; + GstBuffer* buffer; + GstElement* pipeline; + int input_pix_fmt; +}; + +void CvVideoWriter_GStreamer::init() +{ + encs[CV_FOURCC('H','F','Y','U')]=(char*)"ffenc_huffyuv"; + encs[CV_FOURCC('D','R','A','C')]=(char*)"diracenc"; + encs[CV_FOURCC('X','V','I','D')]=(char*)"xvidenc"; + encs[CV_FOURCC('X','2','6','4')]=(char*)"x264enc"; + encs[CV_FOURCC('M','P','1','V')]=(char*)"mpeg2enc"; + //encs[CV_FOURCC('M','P','2','V')]=(char*)"mpeg2enc"; + pipeline=0; + buffer=0; +} +void CvVideoWriter_GStreamer::close() +{ + if (pipeline) { + gst_app_src_end_of_stream(GST_APP_SRC(source)); + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (GST_OBJECT (pipeline)); + } +} +bool CvVideoWriter_GStreamer::open( const char * filename, int fourcc, + double fps, CvSize frameSize, bool is_color ) +{ + CV_FUNCNAME("CvVideoWriter_GStreamer::open"); + + __BEGIN__; + //actually doesn't support fourcc parameter and encode an avi with jpegenc + //we need to find a common api between backend to support fourcc for avi + //but also to choose in a common way codec and container format (ogg,dirac,matroska) + // check arguments + + assert (filename); + assert (fps > 0); + assert (frameSize.width > 0 && frameSize.height > 0); + std::map::iterator encit; + encit=encs.find(fourcc); + if (encit==encs.end()) + CV_ERROR( CV_StsUnsupportedFormat,"Gstreamer Opencv backend doesn't support this codec acutally."); + if(!isInited) { + gst_init (NULL, NULL); + isInited = true; + } + close(); + source=gst_element_factory_make("appsrc",NULL); + file=gst_element_factory_make("filesink", NULL); + enc=gst_element_factory_make(encit->second, NULL); + mux=gst_element_factory_make("avimux", NULL); + color = gst_element_factory_make("ffmpegcolorspace", NULL); + if (!enc) + CV_ERROR( CV_StsUnsupportedFormat, "Your version of Gstreamer doesn't support this codec acutally or needed plugin missing."); + g_object_set(G_OBJECT(file), "location", filename, NULL); + pipeline = gst_pipeline_new (NULL); + GstCaps* caps; + if (is_color) { + input_pix_fmt=1; + caps= gst_video_format_new_caps(GST_VIDEO_FORMAT_BGR, + frameSize.width, + frameSize.height, + (int) (fps * 1000), + 1000, + 1, + 1); + } + else { + input_pix_fmt=0; + caps= gst_caps_new_simple("video/x-raw-gray", + "width", G_TYPE_INT, frameSize.width, + "height", G_TYPE_INT, frameSize.height, + "framerate", GST_TYPE_FRACTION, int(fps),1, + "bpp",G_TYPE_INT,8, + "depth",G_TYPE_INT,8, + NULL); + } + gst_app_src_set_caps(GST_APP_SRC(source), caps); + if (fourcc==CV_FOURCC_DEFAULT) { + gst_bin_add_many(GST_BIN(pipeline), source, color,mux, file, NULL); + if(!gst_element_link_many(source,color,enc,mux,file,NULL)) { + CV_ERROR(CV_StsError, "GStreamer: cannot link elements\n"); + } + } + else { + gst_bin_add_many(GST_BIN(pipeline), source, color,enc,mux, file, NULL); + if(!gst_element_link_many(source,color,enc,mux,file,NULL)) { + CV_ERROR(CV_StsError, "GStreamer: cannot link elements\n"); + } + } + + + if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + CV_ERROR(CV_StsError, "GStreamer: cannot put pipeline to play\n"); + } + __END__; + return true; +} +bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image ) +{ + + CV_FUNCNAME("CvVideoWriter_GStreamer::writerFrame"); + + __BEGIN__; + if (input_pix_fmt == 1) { + if (image->nChannels != 3 || image->depth != IPL_DEPTH_8U) { + CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 3."); + } + } + else if (input_pix_fmt == 0) { + if (image->nChannels != 1 || image->depth != IPL_DEPTH_8U) { + CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 1."); + } + } + else { + assert(false); + } + int size; + size = image->imageSize; + buffer = gst_buffer_new_and_alloc (size); + //gst_buffer_set_data (buffer,(guint8*)image->imageData, size); + memcpy (GST_BUFFER_DATA(buffer),image->imageData, size); + gst_app_src_push_buffer(GST_APP_SRC(source),buffer); + //gst_buffer_unref(buffer); + //buffer = 0; + __END__; + return true; +} +CvVideoWriter* cvCreateVideoWriter_GStreamer(const char* filename, int fourcc, double fps, + CvSize frameSize, int isColor ) +{ + CvVideoWriter_GStreamer* wrt = new CvVideoWriter_GStreamer; + if( wrt->open(filename, fourcc, fps,frameSize, isColor)) + return wrt; + + delete wrt; + return false; +} + +void CvCapture_GStreamer::close() +{ + if(pipeline) { + gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL); + gst_object_unref(GST_OBJECT(pipeline)); + } + if(buffer) + gst_buffer_unref(buffer); + if(frame) { + frame->imageData = 0; + cvReleaseImage(&frame); + } +} + +double CvCapture_GStreamer::getProperty( int propId ) +{ + GstFormat format; + //GstQuery q; + gint64 value; + + if(!pipeline) { + CV_WARN("GStreamer: no pipeline"); + return false; + } + + switch(propId) { + case CV_CAP_PROP_POS_MSEC: + format = GST_FORMAT_TIME; + if(!gst_element_query_position(sink, &format, &value)) { + CV_WARN("GStreamer: unable to query position of stream"); + return false; + } + return value * 1e-6; // nano seconds to milli seconds + case CV_CAP_PROP_POS_FRAMES: + format = GST_FORMAT_DEFAULT; + if(!gst_element_query_position(sink, &format, &value)) { + CV_WARN("GStreamer: unable to query position of stream"); + return false; + } + return value; + case CV_CAP_PROP_POS_AVI_RATIO: + format = GST_FORMAT_PERCENT; + if(!gst_element_query_position(pipeline, &format, &value)) { + CV_WARN("GStreamer: unable to query position of stream"); + return false; + } + return ((double) value) / GST_FORMAT_PERCENT_MAX; + case CV_CAP_PROP_FRAME_WIDTH: + case CV_CAP_PROP_FRAME_HEIGHT: + case CV_CAP_PROP_FPS: + case CV_CAP_PROP_FOURCC: + break; + case CV_CAP_PROP_FRAME_COUNT: + format = GST_FORMAT_DEFAULT; + if(!gst_element_query_duration(pipeline, &format, &value)) { + CV_WARN("GStreamer: unable to query position of stream"); + return false; + } + return value; + case CV_CAP_PROP_FORMAT: + case CV_CAP_PROP_MODE: + case CV_CAP_PROP_BRIGHTNESS: + case CV_CAP_PROP_CONTRAST: + case CV_CAP_PROP_SATURATION: + case CV_CAP_PROP_HUE: + case CV_CAP_PROP_GAIN: + case CV_CAP_PROP_CONVERT_RGB: + break; + case CV_CAP_GSTREAMER_QUEUE_LENGTH: + if(!sink) { + CV_WARN("GStreamer: there is no sink yet"); + return false; + } + return gst_app_sink_get_max_buffers(GST_APP_SINK(sink)); + default: + CV_WARN("GStreamer: unhandled property"); + break; + } + return false; +} + +bool CvCapture_GStreamer::setProperty( int propId, double value ) +{ + GstFormat format; + GstSeekFlags flags; + + if(!pipeline) { + CV_WARN("GStreamer: no pipeline"); + return false; + } + + switch(propId) { + case CV_CAP_PROP_POS_MSEC: + format = GST_FORMAT_TIME; + flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_ACCURATE); + if(!gst_element_seek_simple(GST_ELEMENT(pipeline), format, + flags, (gint64) (value * GST_MSECOND))) { + CV_WARN("GStreamer: unable to seek"); + } + break; + case CV_CAP_PROP_POS_FRAMES: + format = GST_FORMAT_DEFAULT; + flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_ACCURATE); + if(!gst_element_seek_simple(GST_ELEMENT(pipeline), format, + flags, (gint64) value)) { + CV_WARN("GStreamer: unable to seek"); + } + break; + case CV_CAP_PROP_POS_AVI_RATIO: + format = GST_FORMAT_PERCENT; + flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_ACCURATE); + if(!gst_element_seek_simple(GST_ELEMENT(pipeline), format, + flags, (gint64) (value * GST_FORMAT_PERCENT_MAX))) { + CV_WARN("GStreamer: unable to seek"); + } + break; + case CV_CAP_PROP_FRAME_WIDTH: + if(value > 0) + setFilter("width", G_TYPE_INT, (int) value, 0); + else + removeFilter("width"); + break; + case CV_CAP_PROP_FRAME_HEIGHT: + if(value > 0) + setFilter("height", G_TYPE_INT, (int) value, 0); + else + removeFilter("height"); + break; + case CV_CAP_PROP_FPS: + if(value > 0) { + int num, denom; + num = (int) value; + if(value != num) { // FIXME this supports only fractions x/1 and x/2 + num = (int) (value * 2); + denom = 2; + } else + denom = 1; + + setFilter("framerate", GST_TYPE_FRACTION, num, denom); + } else + removeFilter("framerate"); + break; + case CV_CAP_PROP_FOURCC: + case CV_CAP_PROP_FRAME_COUNT: + case CV_CAP_PROP_FORMAT: + case CV_CAP_PROP_MODE: + case CV_CAP_PROP_BRIGHTNESS: + case CV_CAP_PROP_CONTRAST: + case CV_CAP_PROP_SATURATION: + case CV_CAP_PROP_HUE: + case CV_CAP_PROP_GAIN: + case CV_CAP_PROP_CONVERT_RGB: + break; + case CV_CAP_GSTREAMER_QUEUE_LENGTH: + if(!sink) + break; + gst_app_sink_set_max_buffers(GST_APP_SINK(sink), (guint) value); + break; + default: + CV_WARN("GStreamer: unhandled property"); + } + return false; +} +CvCapture* cvCreateCapture_GStreamer(int type, const char* filename ) +{ + CvCapture_GStreamer* capture = new CvCapture_GStreamer; + + if( capture->open( type, filename )) + return capture; + + delete capture; + return false; +} diff --git a/highgui/src/cap_images.cpp b/highgui/src/cap_images.cpp new file mode 100644 index 0000000..4cf51d8 --- /dev/null +++ b/highgui/src/cap_images.cpp @@ -0,0 +1,364 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2008, Nils Hasler, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +// Author: Nils Hasler +// +// Max-Planck-Institut Informatik + +// +// capture video from a sequence of images +// the filename when opening can either be a printf pattern such as +// video%04d.png or the first frame of the sequence i.e. video0001.png +// + +#include "precomp.hpp" +#include + +#ifdef NDEBUG +#define CV_WARN(message) +#else +#define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__) +#endif + +#ifndef _MAX_PATH +#define _MAX_PATH 1024 +#endif + +class CvCapture_Images : public CvCapture +{ +public: + CvCapture_Images() + { + filename = 0; + currentframe = firstframe = 0; + length = 0; + frame = 0; + } + + virtual ~CvCapture_Images() + { + close(); + } + + virtual bool open(const char* _filename); + virtual void close(); + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + +protected: + char* filename; // actually a printf-pattern + unsigned currentframe; + unsigned firstframe; // number of first frame + unsigned length; // length of sequence + + IplImage* frame; +}; + + +void CvCapture_Images::close() +{ + if( filename ) + { + free(filename); + filename = 0; + } + currentframe = firstframe = 0; + length = 0; + cvReleaseImage( &frame ); +} + + +bool CvCapture_Images::grabFrame() +{ + char str[_MAX_PATH]; + sprintf(str, filename, firstframe + currentframe); + + cvReleaseImage(&frame); + frame = cvLoadImage(str, CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR); + if( frame ) + currentframe++; + + return frame != 0; +} + +IplImage* CvCapture_Images::retrieveFrame(int) +{ + return frame; +} + +double CvCapture_Images::getProperty(int id) +{ + switch(id) + { + case CV_CAP_PROP_POS_MSEC: + CV_WARN("collections of images don't have framerates\n"); + return 0; + case CV_CAP_PROP_POS_FRAMES: + return currentframe; + case CV_CAP_PROP_POS_AVI_RATIO: + return (double)currentframe / (double)(length - 1); + case CV_CAP_PROP_FRAME_WIDTH: + return frame ? frame->width : 0; + case CV_CAP_PROP_FRAME_HEIGHT: + return frame ? frame->height : 0; + case CV_CAP_PROP_FPS: + CV_WARN("collections of images don't have framerates\n"); + return 1; + case CV_CAP_PROP_FOURCC: + CV_WARN("collections of images don't have 4-character codes\n"); + return 0; + } + return 0; +} + +bool CvCapture_Images::setProperty(int id, double value) +{ + switch(id) + { + case CV_CAP_PROP_POS_MSEC: + case CV_CAP_PROP_POS_FRAMES: + if(value < 0) { + CV_WARN("seeking to negative positions does not work - clamping\n"); + value = 0; + } + if(value >= length) { + CV_WARN("seeking beyond end of sequence - clamping\n"); + value = length - 1; + } + currentframe = cvRound(value); + return true; + case CV_CAP_PROP_POS_AVI_RATIO: + if(value > 1) { + CV_WARN("seeking beyond end of sequence - clamping\n"); + value = 1; + } else if(value < 0) { + CV_WARN("seeking to negative positions does not work - clamping\n"); + value = 0; + } + currentframe = cvRound((length - 1) * value); + return true; + } + CV_WARN("unknown/unhandled property\n"); + return false; +} + +static char* icvExtractPattern(const char *filename, unsigned *offset) +{ + char *name = (char *)filename; + + if( !filename ) + return 0; + + // check whether this is a valid image sequence filename + char *at = strchr(name, '%'); + if(at) + { + int dummy; + if(sscanf(at + 1, "%ud", &dummy) != 1) + return 0; + name = strdup(filename); + } + else // no pattern filename was given - extract the pattern + { + for(at = name; *at && !isdigit(*at); at++) + ; + + if(!at) + return 0; + + sscanf(at, "%u", offset); + + int size = (int)strlen(filename) + 20; + name = (char *)malloc(size); + strncpy(name, filename, at - filename); + name[at - filename] = 0; + + strcat(name, "%0"); + + int i; + char *extension; + for(i = 0, extension = at; isdigit(at[i]); i++, extension++) + ; + char places[10]; + sprintf(places, "%dd", i); + + strcat(name, places); + strcat(name, extension); + } + + return name; +} + + +bool CvCapture_Images::open(const char * _filename) +{ + unsigned offset = 0; + close(); + + filename = icvExtractPattern(_filename, &offset); + if(!filename) + return false; + + // determine the length of the sequence + length = 0; + char str[_MAX_PATH]; + for(;;) + { + sprintf(str, filename, offset + length); + struct stat s; + if(stat(str, &s)) + { + if(length == 0 && offset == 0) // allow starting with 0 or 1 + { + offset++; + continue; + } + } + + if(!cvHaveImageReader(str)) + break; + + length++; + } + + if(length == 0) + { + close(); + return false; + } + + firstframe = offset; + return true; +} + + +CvCapture* cvCreateFileCapture_Images(const char * filename) +{ + CvCapture_Images* capture = new CvCapture_Images; + + if( capture->open(filename) ) + return capture; + + delete capture; + return 0; +} + +// +// +// image sequence writer +// +// +class CvVideoWriter_Images : public CvVideoWriter +{ +public: + CvVideoWriter_Images() + { + filename = 0; + currentframe = 0; + } + virtual ~CvVideoWriter_Images() { close(); } + + virtual bool open( const char* _filename ); + virtual void close(); + virtual bool writeFrame( const IplImage* ); + +protected: + char* filename; + unsigned currentframe; +}; + +bool CvVideoWriter_Images::writeFrame( const IplImage* image ) +{ + char str[_MAX_PATH]; + sprintf(str, filename, currentframe); + int ret = cvSaveImage(str, image); + + currentframe++; + + return ret > 0; +} + +void CvVideoWriter_Images::close() +{ + if( filename ) + { + free( filename ); + filename = 0; + } + currentframe = 0; +} + + +bool CvVideoWriter_Images::open( const char* _filename ) +{ + unsigned offset = 0; + + close(); + + filename = icvExtractPattern(_filename, &offset); + if(!filename) + return false; + + char str[_MAX_PATH]; + sprintf(str, filename, 0); + if(!cvHaveImageWriter(str)) + { + close(); + return false; + } + + currentframe = offset; + return true; +} + + +CvVideoWriter* cvCreateVideoWriter_Images( const char* filename ) +{ + CvVideoWriter_Images *writer = new CvVideoWriter_Images; + + if( writer->open( filename )) + return writer; + + delete writer; + return 0; +} diff --git a/highgui/src/cap_ios_abstract_camera.mm b/highgui/src/cap_ios_abstract_camera.mm new file mode 100644 index 0000000..45b53b0 --- /dev/null +++ b/highgui/src/cap_ios_abstract_camera.mm @@ -0,0 +1,408 @@ +/* + * cap_ios_abstract_camera.mm + * For iOS video I/O + * by Eduard Feicho on 29/07/12 + * Copyright 2012. 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. + * + */ + + +#import "opencv2/highgui/cap_ios.h" +#include "precomp.hpp" + +#pragma mark - Private Interface + +@interface CvAbstractCamera () + +@property (nonatomic, retain) AVCaptureVideoPreviewLayer* captureVideoPreviewLayer; + +- (void)deviceOrientationDidChange:(NSNotification*)notification; +- (void)startCaptureSession; + +- (void)setDesiredCameraPosition:(AVCaptureDevicePosition)desiredPosition; + +- (void)updateSize; + +@end + + +#pragma mark - Implementation + + +@implementation CvAbstractCamera + + + +#pragma mark Public + +@synthesize imageWidth; +@synthesize imageHeight; + + +@synthesize defaultFPS; +@synthesize defaultAVCaptureDevicePosition; +@synthesize defaultAVCaptureVideoOrientation; +@synthesize defaultAVCaptureSessionPreset; + + + +@synthesize captureSession; +@synthesize captureVideoPreviewLayer; +@synthesize videoCaptureConnection; +@synthesize running; +@synthesize captureSessionLoaded; +@synthesize useAVCaptureVideoPreviewLayer; + +@synthesize parentView; + +#pragma mark - Constructors + +- (id)init; +{ + self = [super init]; + if (self) { + // react to device orientation notifications + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(deviceOrientationDidChange:) + name:UIDeviceOrientationDidChangeNotification + object:nil]; + [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; + currentDeviceOrientation = [[UIDevice currentDevice] orientation]; + + + // check if camera available + cameraAvailable = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]; + NSLog(@"camera available: %@", (cameraAvailable == YES ? @"YES" : @"NO") ); + + running = NO; + + // set camera default configuration + self.defaultAVCaptureDevicePosition = AVCaptureDevicePositionFront; + self.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationLandscapeLeft; + self.defaultFPS = 15; + self.defaultAVCaptureSessionPreset = AVCaptureSessionPreset352x288; + + self.parentView = nil; + self.useAVCaptureVideoPreviewLayer = NO; + } + return self; +} + + + +- (id)initWithParentView:(UIView*)parent; +{ + self = [super init]; + if (self) { + // react to device orientation notifications + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(deviceOrientationDidChange:) + name:UIDeviceOrientationDidChangeNotification + object:nil]; + [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; + currentDeviceOrientation = [[UIDevice currentDevice] orientation]; + + + // check if camera available + cameraAvailable = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]; + NSLog(@"camera available: %@", (cameraAvailable == YES ? @"YES" : @"NO") ); + + running = NO; + + // set camera default configuration + self.defaultAVCaptureDevicePosition = AVCaptureDevicePositionFront; + self.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationLandscapeLeft; + self.defaultFPS = 15; + self.defaultAVCaptureSessionPreset = AVCaptureSessionPreset640x480; + + self.parentView = parent; + self.useAVCaptureVideoPreviewLayer = YES; + } + return self; +} + + + +- (void)dealloc; +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; +} + + +#pragma mark - Public interface + + +- (void)start; +{ + if (![NSThread isMainThread]) { + NSLog(@"[Camera] Warning: Call start only from main thread"); + [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO]; + return; + } + + if (running == YES) { + return; + } + running = YES; + + // TOOD update image size data before actually starting (needed for recording) + [self updateSize]; + + if (cameraAvailable) { + [self startCaptureSession]; + } +} + + +- (void)pause; +{ + running = NO; + [self.captureSession stopRunning]; +} + + + +- (void)stop; +{ + running = NO; + + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; + + [self.captureSession stopRunning]; + self.captureSession = nil; + self.captureVideoPreviewLayer = nil; + self.videoCaptureConnection = nil; + captureSessionLoaded = NO; +} + + + +// use front/back camera +- (void)switchCameras; +{ + BOOL was_running = self.running; + if (was_running) { + [self stop]; + } + if (self.defaultAVCaptureDevicePosition == AVCaptureDevicePositionFront) { + self.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack; + } else { + self.defaultAVCaptureDevicePosition = AVCaptureDevicePositionFront; + } + if (was_running) { + [self start]; + } +} + + + +#pragma mark - Device Orientation Changes + + +- (void)deviceOrientationDidChange:(NSNotification*)notification +{ + UIDeviceOrientation orientation = [UIDevice currentDevice].orientation; + + switch (orientation) + { + case UIDeviceOrientationPortrait: + case UIDeviceOrientationPortraitUpsideDown: + case UIDeviceOrientationLandscapeLeft: + case UIDeviceOrientationLandscapeRight: + currentDeviceOrientation = orientation; + break; + + case UIDeviceOrientationFaceUp: + case UIDeviceOrientationFaceDown: + default: + break; + } + NSLog(@"deviceOrientationDidChange: %d", orientation); + + [self updateOrientation]; +} + + + +#pragma mark - Private Interface + +- (void)createCaptureSession; +{ + // set a av capture session preset + self.captureSession = [[AVCaptureSession alloc] init]; + if ([self.captureSession canSetSessionPreset:self.defaultAVCaptureSessionPreset]) { + [self.captureSession setSessionPreset:self.defaultAVCaptureSessionPreset]; + } else if ([self.captureSession canSetSessionPreset:AVCaptureSessionPresetLow]) { + [self.captureSession setSessionPreset:AVCaptureSessionPresetLow]; + } else { + NSLog(@"[Camera] Error: could not set session preset"); + } +} + +- (void)createCaptureDevice; +{ + // setup the device + AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + [self setDesiredCameraPosition:self.defaultAVCaptureDevicePosition]; + NSLog(@"[Camera] device connected? %@", device.connected ? @"YES" : @"NO"); + NSLog(@"[Camera] device position %@", (device.position == AVCaptureDevicePositionBack) ? @"back" : @"front"); +} + + +- (void)createVideoPreviewLayer; +{ + self.captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession]; + + if ([self.captureVideoPreviewLayer isOrientationSupported]) { + [self.captureVideoPreviewLayer setOrientation:self.defaultAVCaptureVideoOrientation]; + } + + if (parentView != nil) { + self.captureVideoPreviewLayer.frame = self.parentView.bounds; + self.captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; + [self.parentView.layer addSublayer:self.captureVideoPreviewLayer]; + } + NSLog(@"[Camera] created AVCaptureVideoPreviewLayer"); +} + + + + +- (void)setDesiredCameraPosition:(AVCaptureDevicePosition)desiredPosition; +{ + for (AVCaptureDevice *device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) { + if ([device position] == desiredPosition) { + [self.captureSession beginConfiguration]; + + NSError* error; + AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error]; + if (!input) { + NSLog(@"error creating input %@", [error localizedDescription]); + } + + // support for autofocus + if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) { + NSError *error = nil; + if ([device lockForConfiguration:&error]) { + device.focusMode = AVCaptureFocusModeContinuousAutoFocus; + [device unlockForConfiguration]; + } else { + NSLog(@"unable to lock device for autofocos configuration %@", [error localizedDescription]); + } + } + [self.captureSession addInput:input]; + + for (AVCaptureInput *oldInput in self.captureSession.inputs) { + [self.captureSession removeInput:oldInput]; + } + [self.captureSession addInput:input]; + [self.captureSession commitConfiguration]; + + break; + } + } +} + + + +- (void)startCaptureSession +{ + if (!cameraAvailable) { + return; + } + + if (self.captureSessionLoaded == NO) { + [self createCaptureSession]; + [self createCaptureDevice]; + [self createCaptureOutput]; + + // setup preview layer + if (self.useAVCaptureVideoPreviewLayer) { + [self createVideoPreviewLayer]; + } else { + [self createCustomVideoPreview]; + } + + captureSessionLoaded = YES; + } + + [self.captureSession startRunning]; +} + + +- (void)createCaptureOutput; +{ + [NSException raise:NSInternalInconsistencyException + format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]; +} + +- (void)createCustomVideoPreview; +{ + [NSException raise:NSInternalInconsistencyException + format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]; +} + +- (void)updateOrientation; +{ + // nothing to do here +} + + +- (void)updateSize; +{ + if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPresetPhoto]) { + //TODO: find the correct resolution + self.imageWidth = 640; + self.imageHeight = 480; + } else if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPresetHigh]) { + //TODO: find the correct resolution + self.imageWidth = 640; + self.imageHeight = 480; + } else if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPresetMedium]) { + //TODO: find the correct resolution + self.imageWidth = 640; + self.imageHeight = 480; + } else if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPresetLow]) { + //TODO: find the correct resolution + self.imageWidth = 640; + self.imageHeight = 480; + } else if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPreset352x288]) { + self.imageWidth = 352; + self.imageHeight = 288; + } else if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPreset640x480]) { + self.imageWidth = 640; + self.imageHeight = 480; + } else if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPreset1280x720]) { + self.imageWidth = 1280; + self.imageHeight = 720; + } else { + self.imageWidth = 640; + self.imageHeight = 480; + } +} + +@end diff --git a/highgui/src/cap_ios_photo_camera.mm b/highgui/src/cap_ios_photo_camera.mm new file mode 100644 index 0000000..51e5ce2 --- /dev/null +++ b/highgui/src/cap_ios_photo_camera.mm @@ -0,0 +1,165 @@ +/* + * cap_ios_photo_camera.mm + * For iOS video I/O + * by Eduard Feicho on 29/07/12 + * Copyright 2012. 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. + * + */ + + +#import "opencv2/highgui/cap_ios.h" +#include "precomp.hpp" + +#pragma mark - Private Interface + + +@interface CvPhotoCamera () + +@property (nonatomic, retain) AVCaptureStillImageOutput* stillImageOutput; + +@end + + + +#pragma mark - Implementation + + +@implementation CvPhotoCamera + + + +#pragma mark Public + +@synthesize stillImageOutput; +@synthesize delegate; + + +#pragma mark - Public interface + + +- (void)takePicture +{ + if (cameraAvailable == NO) { + return; + } + cameraAvailable = NO; + + + [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:self.videoCaptureConnection + completionHandler: + ^(CMSampleBufferRef imageSampleBuffer, NSError *error) + { + if (error == nil && imageSampleBuffer != NULL) + { + // TODO check + // NSNumber* imageOrientation = [UIImage cgImageOrientationForUIDeviceOrientation:currentDeviceOrientation]; + // CMSetAttachment(imageSampleBuffer, kCGImagePropertyOrientation, imageOrientation, 1); + + NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.captureSession stopRunning]; + + // Make sure we create objects on the main thread in the main context + UIImage* newImage = [UIImage imageWithData:jpegData]; + + //UIImageOrientation orientation = [newImage imageOrientation]; + + // TODO: only apply rotation, don't scale, since we can set this directly in the camera + /* + switch (orientation) { + case UIImageOrientationUp: + case UIImageOrientationDown: + newImage = [newImage imageWithAppliedRotationAndMaxSize:CGSizeMake(640.0, 480.0)]; + break; + case UIImageOrientationLeft: + case UIImageOrientationRight: + newImage = [newImage imageWithMaxSize:CGSizeMake(640.0, 480.0)]; + default: + break; + } + */ + + // We have captured the image, we can allow the user to take another picture + cameraAvailable = YES; + + NSLog(@"CvPhotoCamera captured image"); + if (self.delegate) { + [self.delegate photoCamera:self capturedImage:newImage]; + } + + [self.captureSession startRunning]; + }); + } + }]; + + +} + +- (void)stop; +{ + [super stop]; + self.stillImageOutput = nil; +} + + +#pragma mark - Private Interface + + +- (void)createStillImageOutput; +{ + // setup still image output with jpeg codec + self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init]; + NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil]; + [self.stillImageOutput setOutputSettings:outputSettings]; + [self.captureSession addOutput:self.stillImageOutput]; + + for (AVCaptureConnection *connection in self.stillImageOutput.connections) { + for (AVCaptureInputPort *port in [connection inputPorts]) { + if ([port.mediaType isEqual:AVMediaTypeVideo]) { + self.videoCaptureConnection = connection; + break; + } + } + if (self.videoCaptureConnection) { + break; + } + } + NSLog(@"[Camera] still image output created"); +} + + +- (void)createCaptureOutput; +{ + [self createStillImageOutput]; +} + +- (void)createCustomVideoPreview; +{ + //do nothing, always use AVCaptureVideoPreviewLayer +} + + +@end diff --git a/highgui/src/cap_ios_video_camera.mm b/highgui/src/cap_ios_video_camera.mm new file mode 100644 index 0000000..0a162eb --- /dev/null +++ b/highgui/src/cap_ios_video_camera.mm @@ -0,0 +1,585 @@ +/* + * cap_ios_video_camera.mm + * For iOS video I/O + * by Eduard Feicho on 29/07/12 + * Copyright 2012. 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. + * + */ + +#import "opencv2/highgui/cap_ios.h" +#include "precomp.hpp" + +#import + + +static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; + +#pragma mark - Private Interface + + + + +@interface CvVideoCamera () + +- (void)createVideoDataOutput; +- (void)createVideoFileOutput; + + +@property (nonatomic, retain) CALayer *customPreviewLayer; +@property (nonatomic, retain) AVCaptureVideoDataOutput *videoDataOutput; + +@end + + + +#pragma mark - Implementation + + + +@implementation CvVideoCamera + + + + +@synthesize delegate; +@synthesize grayscaleMode; + +@synthesize customPreviewLayer; +@synthesize videoDataOutput; + +@synthesize recordVideo; +//@synthesize videoFileOutput; +@synthesize recordAssetWriterInput; +@synthesize recordPixelBufferAdaptor; +@synthesize recordAssetWriter; + + + +#pragma mark - Constructors + +- (id)initWithParentView:(UIView*)parent; +{ + self = [super initWithParentView:parent]; + if (self) { + self.useAVCaptureVideoPreviewLayer = NO; + self.recordVideo = NO; + } + return self; +} + + + +#pragma mark - Public interface + + +- (void)start; +{ + [super start]; + + if (self.recordVideo == YES) { + NSError* error; + if ([[NSFileManager defaultManager] fileExistsAtPath:[self videoFileString]]) { + [[NSFileManager defaultManager] removeItemAtPath:[self videoFileString] error:&error]; + } + if (error == nil) { + NSLog(@"[Camera] Delete file %@", [self videoFileString]); + } + } +} + + + +- (void)stop; +{ + [super stop]; + + self.videoDataOutput = nil; + if (videoDataOutputQueue) { + dispatch_release(videoDataOutputQueue); + } + + if (self.recordVideo == YES) { + + if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) { + [self.recordAssetWriter finishWriting]; + NSLog(@"[Camera] recording stopped"); + } else { + NSLog(@"[Camera] Recording Error: asset writer status is not writing"); + } + + self.recordAssetWriter = nil; + self.recordAssetWriterInput = nil; + self.recordPixelBufferAdaptor = nil; + } + + [self.customPreviewLayer removeFromSuperlayer]; + self.customPreviewLayer = nil; +} + +// TODO fix +- (void)adjustLayoutToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; +{ + + NSLog(@"layout preview layer"); + if (self.parentView != nil) { + + CALayer* layer = self.customPreviewLayer; + CGRect bounds = self.customPreviewLayer.bounds; + int rotation_angle = 0; + bool flip_bounds = false; + + switch (interfaceOrientation) { + case UIInterfaceOrientationPortrait: + NSLog(@"to Portrait"); + rotation_angle = 270; + break; + case UIInterfaceOrientationPortraitUpsideDown: + rotation_angle = 90; + NSLog(@"to UpsideDown"); + break; + case UIInterfaceOrientationLandscapeLeft: + rotation_angle = 0; + NSLog(@"to LandscapeLeft"); + break; + case UIInterfaceOrientationLandscapeRight: + rotation_angle = 180; + NSLog(@"to LandscapeRight"); + break; + default: + break; // leave the layer in its last known orientation + } + + switch (defaultAVCaptureVideoOrientation) { + case AVCaptureVideoOrientationLandscapeRight: + rotation_angle += 180; + break; + case AVCaptureVideoOrientationPortraitUpsideDown: + rotation_angle += 270; + break; + case AVCaptureVideoOrientationPortrait: + rotation_angle += 90; + case AVCaptureVideoOrientationLandscapeLeft: + break; + default: + break; + } + rotation_angle = rotation_angle % 360; + + if (rotation_angle == 90 || rotation_angle == 270) { + flip_bounds = true; + } + + if (flip_bounds) { + NSLog(@"flip bounds"); + bounds = CGRectMake(0, 0, bounds.size.height, bounds.size.width); + } + + layer.position = CGPointMake(self.parentView.frame.size.width/2., self.parentView.frame.size.height/2.); + self.customPreviewLayer.bounds = CGRectMake(0, 0, self.parentView.frame.size.width, self.parentView.frame.size.height); + + layer.affineTransform = CGAffineTransformMakeRotation( DegreesToRadians(rotation_angle) ); + layer.bounds = bounds; + } + +} + +// TODO fix +- (void)layoutPreviewLayer; +{ + NSLog(@"layout preview layer"); + if (self.parentView != nil) { + + CALayer* layer = self.customPreviewLayer; + CGRect bounds = self.customPreviewLayer.bounds; + int rotation_angle = 0; + bool flip_bounds = false; + + switch (currentDeviceOrientation) { + case UIDeviceOrientationPortrait: + rotation_angle = 270; + break; + case UIDeviceOrientationPortraitUpsideDown: + rotation_angle = 90; + break; + case UIDeviceOrientationLandscapeLeft: + NSLog(@"left"); + rotation_angle = 180; + break; + case UIDeviceOrientationLandscapeRight: + NSLog(@"right"); + rotation_angle = 0; + break; + case UIDeviceOrientationFaceUp: + case UIDeviceOrientationFaceDown: + default: + break; // leave the layer in its last known orientation + } + + switch (defaultAVCaptureVideoOrientation) { + case AVCaptureVideoOrientationLandscapeRight: + rotation_angle += 180; + break; + case AVCaptureVideoOrientationPortraitUpsideDown: + rotation_angle += 270; + break; + case AVCaptureVideoOrientationPortrait: + rotation_angle += 90; + case AVCaptureVideoOrientationLandscapeLeft: + break; + default: + break; + } + rotation_angle = rotation_angle % 360; + + if (rotation_angle == 90 || rotation_angle == 270) { + flip_bounds = true; + } + + if (flip_bounds) { + NSLog(@"flip bounds"); + bounds = CGRectMake(0, 0, bounds.size.height, bounds.size.width); + } + + layer.position = CGPointMake(self.parentView.frame.size.width/2., self.parentView.frame.size.height/2.); + layer.affineTransform = CGAffineTransformMakeRotation( DegreesToRadians(rotation_angle) ); + layer.bounds = bounds; + } + +} + + + + +#pragma mark - Private Interface + + + +- (void)createVideoDataOutput; +{ + // Make a video data output + self.videoDataOutput = [AVCaptureVideoDataOutput new]; + + // In grayscale mode we want YUV (YpCbCr 4:2:0) so we can directly access the graylevel intensity values (Y component) + // In color mode we, BGRA format is used + OSType format = self.grayscaleMode ? kCVPixelFormatType_420YpCbCr8BiPlanarFullRange : kCVPixelFormatType_32BGRA; + + self.videoDataOutput.videoSettings = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:format] + forKey:(id)kCVPixelBufferPixelFormatTypeKey]; + + // discard if the data output queue is blocked (as we process the still image) + [self.videoDataOutput setAlwaysDiscardsLateVideoFrames:YES]; + + if ( [self.captureSession canAddOutput:self.videoDataOutput] ) { + [self.captureSession addOutput:self.videoDataOutput]; + } + [[self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo] setEnabled:YES]; + + + // set default FPS + if ([self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].supportsVideoMinFrameDuration) { + [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].videoMinFrameDuration = CMTimeMake(1, self.defaultFPS); + } + if ([self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].supportsVideoMaxFrameDuration) { + [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].videoMaxFrameDuration = CMTimeMake(1, self.defaultFPS); + } + + // set video mirroring for front camera (more intuitive) + if ([self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].supportsVideoMirroring) { + if (self.defaultAVCaptureDevicePosition == AVCaptureDevicePositionFront) { + [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].videoMirrored = YES; + } else { + [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].videoMirrored = NO; + } + } + + // set default video orientation + if ([self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].supportsVideoOrientation) { + [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].videoOrientation = self.defaultAVCaptureVideoOrientation; + } + + + // create a custom preview layer + self.customPreviewLayer = [CALayer layer]; + self.customPreviewLayer.bounds = CGRectMake(0, 0, self.parentView.frame.size.width, self.parentView.frame.size.height); + [self layoutPreviewLayer]; + + // create a serial dispatch queue used for the sample buffer delegate as well as when a still image is captured + // a serial dispatch queue must be used to guarantee that video frames will be delivered in order + // see the header doc for setSampleBufferDelegate:queue: for more information + videoDataOutputQueue = dispatch_queue_create("VideoDataOutputQueue", DISPATCH_QUEUE_SERIAL); + [self.videoDataOutput setSampleBufferDelegate:self queue:videoDataOutputQueue]; + + + NSLog(@"[Camera] created AVCaptureVideoDataOutput at %d FPS", self.defaultFPS); +} + + + +- (void)createVideoFileOutput; +{ + /* Video File Output in H.264, via AVAsserWriter */ + NSLog(@"Create Video with dimensions %dx%d", self.imageWidth, self.imageHeight); + + NSDictionary *outputSettings + = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:self.imageWidth], AVVideoWidthKey, + [NSNumber numberWithInt:self.imageHeight], AVVideoHeightKey, + AVVideoCodecH264, AVVideoCodecKey, + nil + ]; + + + self.recordAssetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:outputSettings]; + + + int pixelBufferFormat = (self.grayscaleMode == YES) ? kCVPixelFormatType_420YpCbCr8BiPlanarFullRange : kCVPixelFormatType_32BGRA; + + self.recordPixelBufferAdaptor = + [[AVAssetWriterInputPixelBufferAdaptor alloc] + initWithAssetWriterInput:self.recordAssetWriterInput + sourcePixelBufferAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:pixelBufferFormat], kCVPixelBufferPixelFormatTypeKey, nil]]; + + NSError* error = nil; + NSLog(@"Create AVAssetWriter with url: %@", [self videoFileURL]); + self.recordAssetWriter = [AVAssetWriter assetWriterWithURL:[self videoFileURL] + fileType:AVFileTypeMPEG4 + error:&error]; + if (error != nil) { + NSLog(@"[Camera] Unable to create AVAssetWriter: %@", error); + } + + [self.recordAssetWriter addInput:self.recordAssetWriterInput]; + self.recordAssetWriterInput.expectsMediaDataInRealTime = YES; + + NSLog(@"[Camera] created AVAssetWriter"); +} + + +- (void)createCaptureOutput; +{ + [self createVideoDataOutput]; + if (self.recordVideo == YES) { + [self createVideoFileOutput]; + } +} + +- (void)createCustomVideoPreview; +{ + [self.parentView.layer addSublayer:self.customPreviewLayer]; +} + + +#pragma mark - Protocol AVCaptureVideoDataOutputSampleBufferDelegate + + +- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection +{ + if (self.delegate) { + + // convert from Core Media to Core Video + CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); + CVPixelBufferLockBaseAddress(imageBuffer, 0); + + void* bufferAddress; + size_t width; + size_t height; + size_t bytesPerRow; + + CGColorSpaceRef colorSpace; + CGContextRef context; + + int format_opencv; + + OSType format = CVPixelBufferGetPixelFormatType(imageBuffer); + if (format == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { + + format_opencv = CV_8UC1; + + bufferAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0); + width = CVPixelBufferGetWidthOfPlane(imageBuffer, 0); + height = CVPixelBufferGetHeightOfPlane(imageBuffer, 0); + bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0); + + } else { // expect kCVPixelFormatType_32BGRA + + format_opencv = CV_8UC4; + + bufferAddress = CVPixelBufferGetBaseAddress(imageBuffer); + width = CVPixelBufferGetWidth(imageBuffer); + height = CVPixelBufferGetHeight(imageBuffer); + bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); + + } + + // delegate image processing to the delegate + cv::Mat image(height, width, format_opencv, bufferAddress, bytesPerRow); + + cv::Mat* result = NULL; + CGImage* dstImage; + + if ([self.delegate respondsToSelector:@selector(processImage:)]) { + [self.delegate processImage:image]; + } + + // check if matrix data pointer or dimensions were changed by the delegate + bool iOSimage = false; + if (height == image.rows && width == image.cols && format_opencv == image.type() && bufferAddress == image.data && bytesPerRow == image.step) { + iOSimage = true; + } + + + // (create color space, create graphics context, render buffer) + CGBitmapInfo bitmapInfo; + + // basically we decide if it's a grayscale, rgb or rgba image + if (image.channels() == 1) { + colorSpace = CGColorSpaceCreateDeviceGray(); + bitmapInfo = kCGImageAlphaNone; + } else if (image.channels() == 3) { + colorSpace = CGColorSpaceCreateDeviceRGB(); + bitmapInfo = kCGImageAlphaNone; + if (iOSimage) { + bitmapInfo |= kCGBitmapByteOrder32Little; + } else { + bitmapInfo |= kCGBitmapByteOrder32Big; + } + } else { + colorSpace = CGColorSpaceCreateDeviceRGB(); + bitmapInfo = kCGImageAlphaPremultipliedFirst; + if (iOSimage) { + bitmapInfo |= kCGBitmapByteOrder32Little; + } else { + bitmapInfo |= kCGBitmapByteOrder32Big; + } + } + + if (iOSimage) { + context = CGBitmapContextCreate(bufferAddress, width, height, 8, bytesPerRow, colorSpace, bitmapInfo); + dstImage = CGBitmapContextCreateImage(context); + CGContextRelease(context); + } else { + + NSData *data = [NSData dataWithBytes:image.data length:image.elemSize()*image.total()]; + CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); + + // Creating CGImage from cv::Mat + dstImage = CGImageCreate(image.cols, // width + image.rows, // height + 8, // bits per component + 8 * image.elemSize(), // bits per pixel + image.step, // bytesPerRow + colorSpace, // colorspace + bitmapInfo, // bitmap info + provider, // CGDataProviderRef + NULL, // decode + false, // should interpolate + kCGRenderingIntentDefault // intent + ); + + CGDataProviderRelease(provider); + } + + + // render buffer + dispatch_sync(dispatch_get_main_queue(), ^{ + self.customPreviewLayer.contents = (__bridge id)dstImage; + }); + + + if (self.recordVideo == YES) { + lastSampleTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer); +// CMTimeShow(lastSampleTime); + if (self.recordAssetWriter.status != AVAssetWriterStatusWriting) { + [self.recordAssetWriter startWriting]; + [self.recordAssetWriter startSessionAtSourceTime:lastSampleTime]; + if (self.recordAssetWriter.status != AVAssetWriterStatusWriting) { + NSLog(@"[Camera] Recording Error: asset writer status is not writing: %@", self.recordAssetWriter.error); + return; + } else { + NSLog(@"[Camera] Video recording started"); + } + } + + if (self.recordAssetWriterInput.readyForMoreMediaData) { + if (! [self.recordPixelBufferAdaptor appendPixelBuffer:imageBuffer + withPresentationTime:lastSampleTime] ) { + NSLog(@"Video Writing Error"); + } + } + + } + + + // cleanup + CGImageRelease(dstImage); + + CGColorSpaceRelease(colorSpace); + + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + } +} + + +- (void)updateOrientation; +{ + NSLog(@"rotate.."); + self.customPreviewLayer.bounds = CGRectMake(0, 0, self.parentView.frame.size.width, self.parentView.frame.size.height); + [self layoutPreviewLayer]; +} + + +- (void)saveVideo; +{ + if (self.recordVideo == NO) { + return; + } + + ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; + if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:[self videoFileURL]]) { + [library writeVideoAtPathToSavedPhotosAlbum:[self videoFileURL] + completionBlock:^(NSURL *assetURL, NSError *error){}]; + } +} + + +- (NSURL *)videoFileURL; +{ + NSString *outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"]; + NSURL *outputURL = [NSURL fileURLWithPath:outputPath]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:outputPath]) { + NSLog(@"file exists"); + } + return outputURL; +} + + + +- (NSString *)videoFileString; +{ + NSString *outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"]; + return outputPath; +} + +@end diff --git a/highgui/src/cap_libv4l.cpp b/highgui/src/cap_libv4l.cpp new file mode 100644 index 0000000..6dcc567 --- /dev/null +++ b/highgui/src/cap_libv4l.cpp @@ -0,0 +1,1785 @@ +/* This is the contributed code: + +File: cvcap_v4l.cpp +Current Location: ../opencv-0.9.6/otherlibs/highgui + +Original Version: 2003-03-12 Magnus Lundin lundin@mlu.mine.nu +Original Comments: + +ML:This set of files adds support for firevre and usb cameras. +First it tries to install a firewire camera, +if that fails it tries a v4l/USB camera +It has been tested with the motempl sample program + +First Patch: August 24, 2004 Travis Wood TravisOCV@tkwood.com +For Release: OpenCV-Linux Beta4 opencv-0.9.6 +Tested On: LMLBT44 with 8 video inputs +Problems? Post problems/fixes to OpenCV group on groups.yahoo.com +Patched Comments: + +TW: The cv cam utils that came with the initial release of OpenCV for LINUX Beta4 +were not working. I have rewritten them so they work for me. At the same time, trying +to keep the original code as ML wrote it as unchanged as possible. No one likes to debug +someone elses code, so I resisted changes as much as possible. I have tried to keep the +same "ideas" where applicable, that is, where I could figure out what the previous author +intended. Some areas I just could not help myself and had to "spiffy-it-up" my way. + +These drivers should work with other V4L frame capture cards other then my bttv +driven frame capture card. + +Re Written driver for standard V4L mode. Tested using LMLBT44 video capture card. +Standard bttv drivers are on the LMLBT44 with up to 8 Inputs. + +This utility was written with the help of the document: +http://pages.cpsc.ucalgary.ca/~sayles/VFL_HowTo +as a general guide for interfacing into the V4l standard. + +Made the index value passed for icvOpenCAM_V4L(index) be the number of the +video device source in the /dev tree. The -1 uses original /dev/video. + +Index Device + 0 /dev/video0 + 1 /dev/video1 + 2 /dev/video2 + 3 /dev/video3 + ... + 7 /dev/video7 +with + -1 /dev/video + +TW: You can select any video source, but this package was limited from the start to only +ONE camera opened at any ONE time. +This is an original program limitation. +If you are interested, I will make my version available to other OpenCV users. The big +difference in mine is you may pass the camera number as part of the cv argument, but this +convention is non standard for current OpenCV calls and the camera number is not currently +passed into the called routine. + +Second Patch: August 28, 2004 Sfuncia Fabio fiblan@yahoo.it +For Release: OpenCV-Linux Beta4 Opencv-0.9.6 + +FS: this patch fix not sequential index of device (unplugged device), and real numCameras. + for -1 index (icvOpenCAM_V4L) i dont use /dev/video but real device available, because + if /dev/video is a link to /dev/video0 and i unplugged device on /dev/video0, /dev/video + is a bad link. I search the first available device with indexList. + +Third Patch: December 9, 2004 Frederic Devernay Frederic.Devernay@inria.fr +For Release: OpenCV-Linux Beta4 Opencv-0.9.6 + +[FD] I modified the following: + - handle YUV420P, YUV420, and YUV411P palettes (for many webcams) without using floating-point + - cvGrabFrame should not wait for the end of the first frame, and should return quickly + (see highgui doc) + - cvRetrieveFrame should in turn wait for the end of frame capture, and should not + trigger the capture of the next frame (the user choses when to do it using GrabFrame) + To get the old behavior, re-call cvRetrieveFrame just after cvGrabFrame. + - having global bufferIndex and FirstCapture variables makes the code non-reentrant + (e.g. when using several cameras), put these in the CvCapture struct. + - according to V4L HowTo, incrementing the buffer index must be done before VIDIOCMCAPTURE. + - the VID_TYPE_SCALES stuff from V4L HowTo is wrong: image size can be changed + even if the hardware does not support scaling (e.g. webcams can have several + resolutions available). Just don't try to set the size at 640x480 if the hardware supports + scaling: open with the default (probably best) image size, and let the user scale it + using SetProperty. + - image size can be changed by two subsequent calls to SetProperty (for width and height) + - bug fix: if the image size changes, realloc the new image only when it is grabbed + - issue errors only when necessary, fix error message formatting. + +Fourth Patch: Sept 7, 2005 Csaba Kertesz sign@freemail.hu +For Release: OpenCV-Linux Beta5 OpenCV-0.9.7 + +I modified the following: + - Additional Video4Linux2 support :) + - Use mmap functions (v4l2) + - New methods are internal: + try_palette_v4l2 -> rewrite try_palette for v4l2 + mainloop_v4l2, read_image_v4l2 -> this methods are moved from official v4l2 capture.c example + try_init_v4l -> device v4l initialisation + try_init_v4l2 -> device v4l2 initialisation + autosetup_capture_mode_v4l -> autodetect capture modes for v4l + autosetup_capture_mode_v4l2 -> autodetect capture modes for v4l2 + - Modifications are according with Video4Linux old codes + - Video4Linux handling is automatically if it does not recognize a Video4Linux2 device + - Tested succesful with Logitech Quickcam Express (V4L), Creative Vista (V4L) and Genius VideoCam Notebook (V4L2) + - Correct source lines with compiler warning messages + - Information message from v4l/v4l2 detection + +Fifth Patch: Sept 7, 2005 Csaba Kertesz sign@freemail.hu +For Release: OpenCV-Linux Beta5 OpenCV-0.9.7 + +I modified the following: + - SN9C10x chip based webcams support + - New methods are internal: + bayer2rgb24, sonix_decompress -> decoder routines for SN9C10x decoding from Takafumi Mizuno with his pleasure :) + - Tested succesful with Genius VideoCam Notebook (V4L2) + +Sixth Patch: Sept 10, 2005 Csaba Kertesz sign@freemail.hu +For Release: OpenCV-Linux Beta5 OpenCV-0.9.7 + +I added the following: + - Add capture control support (hue, saturation, brightness, contrast, gain) + - Get and change V4L capture controls (hue, saturation, brightness, contrast) + - New method is internal: + icvSetControl -> set capture controls + - Tested succesful with Creative Vista (V4L) + +Seventh Patch: Sept 10, 2005 Csaba Kertesz sign@freemail.hu +For Release: OpenCV-Linux Beta5 OpenCV-0.9.7 + +I added the following: + - Detect, get and change V4L2 capture controls (hue, saturation, brightness, contrast, gain) + - New methods are internal: + v4l2_scan_controls_enumerate_menu, v4l2_scan_controls -> detect capture control intervals + - Tested succesful with Genius VideoCam Notebook (V4L2) + +8th patch: Jan 5, 2006, Olivier.Bornet@idiap.ch +Add support of V4L2_PIX_FMT_YUYV and V4L2_PIX_FMT_MJPEG. +With this patch, new webcams of Logitech, like QuickCam Fusion works. +Note: For use these webcams, look at the UVC driver at +http://linux-uvc.berlios.de/ + +9th patch: Mar 4, 2006, Olivier.Bornet@idiap.ch +- try V4L2 before V4L, because some devices are V4L2 by default, + but they try to implement the V4L compatibility layer. + So, I think this is better to support V4L2 before V4L. +- better separation between V4L2 and V4L initialization. (this was needed to support + some drivers working, but not fully with V4L2. (so, we do not know when we + need to switch from V4L2 to V4L. + +10th patch: July 02, 2008, Mikhail Afanasyev fopencv@theamk.com +Fix reliability problems with high-resolution UVC cameras on linux +the symptoms were damaged image and 'Corrupt JPEG data: premature end of data segment' on stderr +- V4L_ABORT_BADJPEG detects JPEG warnings and turns them into errors, so bad images + could be filtered out +- USE_TEMP_BUFFER fixes the main problem (improper buffer management) and + prevents bad images in the first place + +11th patch: Apr 13, 2010, Filipe Almeida filipe.almeida@ist.utl.pt +- Tries to setup all properties first through v4l2_ioctl call. +- Allows seting up all Video4Linux properties through cvSetCaptureProperty instead of only CV_CAP_PROP_BRIGHTNESS, CV_CAP_PROP_CONTRAST, CV_CAP_PROP_SATURATION, CV_CAP_PROP_HUE, CV_CAP_PROP_GAIN and CV_CAP_PROP_EXPOSURE. + +12th patch: Apr 16, 2010, Filipe Almeida filipe.almeida@ist.utl.pt +- CvCaptureCAM_V4L structure cleanup (no longer needs _{min,max,} variables) +- Introduction of v4l2_ctrl_range - minimum and maximum allowed values for v4l controls +- Allows seting up all Video4Linux properties through cvSetCaptureProperty using input values between 0.0 and 1.0 +- Gets v4l properties first through v4l2_ioctl call (ignores capture->is_v4l2_device) +- cvGetCaptureProperty adjusted to support the changes +- Returns device properties to initial values after device closes + +13th patch: Apr 27, 2010, Filipe Almeida filipe.almeida@ist.utl.pt +- Solved problem mmaping the device using uvcvideo driver (use o v4l2_mmap instead of mmap) +make & enjoy! + +14th patch: May 10, 2010, Filipe Almeida filipe.almeida@ist.utl.pt +- Bug #142: Solved/Workaround "setting frame width and height does not work" + There was a problem setting up the size when the input is a v4l2 device + The workaround closes the camera and reopens it with the new definition + Planning for future rewrite of this whole library (July/August 2010) + +15th patch: May 12, 2010, Filipe Almeida filipe.almeida@ist.utl.pt +- Broken compile of library (include "_highgui.h") +*/ + +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#if !defined WIN32 && defined HAVE_LIBV4L + +#define CLEAR(x) memset (&(x), 0, sizeof (x)) + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for videodev2.h */ +#include +#include +#include + +#ifdef HAVE_CAMV4L +#include +#endif +#ifdef HAVE_CAMV4L2 +#include +#endif + +#include +#include + +/* Defaults - If your board can do better, set it here. Set for the most common type inputs. */ +#define DEFAULT_V4L_WIDTH 640 +#define DEFAULT_V4L_HEIGHT 480 + +#define CHANNEL_NUMBER 1 +#define MAX_CAMERAS 8 + + +// default and maximum number of V4L buffers, not including last, 'special' buffer +#define MAX_V4L_BUFFERS 10 +#define DEFAULT_V4L_BUFFERS 4 + +// if enabled, copies data from the buffer. this uses a bit more memory, +// but much more reliable for some UVC cameras +#define USE_TEMP_BUFFER + +#define MAX_DEVICE_DRIVER_NAME 80 + +/* Device Capture Objects */ +/* V4L2 structure */ +struct buffer +{ + void * start; + size_t length; +}; +static unsigned int n_buffers = 0; + +/* TODO: Dilemas: */ +/* TODO: Consider drop the use of this data structure and perform ioctl to obtain needed values */ +/* TODO: Consider at program exit return controls to the initial values - See v4l2_free_ranges function */ +/* TODO: Consider at program exit reset the device to default values - See v4l2_free_ranges function */ +typedef struct v4l2_ctrl_range { + __u32 ctrl_id; + __s32 initial_value; + __s32 current_value; + __s32 minimum; + __s32 maximum; + __s32 default_value; +} v4l2_ctrl_range; + +typedef struct CvCaptureCAM_V4L +{ + char* deviceName; + int deviceHandle; + int bufferIndex; + int FirstCapture; + + int width; int height; + + struct video_capability capability; + struct video_window captureWindow; + struct video_picture imageProperties; + struct video_mbuf memoryBuffer; + struct video_mmap *mmaps; + char *memoryMap; + IplImage frame; + + /* V4L2 variables */ + buffer buffers[MAX_V4L_BUFFERS + 1]; + struct v4l2_capability cap; + struct v4l2_input inp; + struct v4l2_format form; + struct v4l2_crop crop; + struct v4l2_cropcap cropcap; + struct v4l2_requestbuffers req; + struct v4l2_jpegcompression compr; + struct v4l2_control control; + enum v4l2_buf_type type; + struct v4l2_queryctrl queryctrl; + struct v4l2_querymenu querymenu; + + /* V4L2 control variables */ + v4l2_ctrl_range** v4l2_ctrl_ranges; + int v4l2_ctrl_count; + + int is_v4l2_device; +} +CvCaptureCAM_V4L; + +static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture ); + +static int icvGrabFrameCAM_V4L( CvCaptureCAM_V4L* capture ); +static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int ); +CvCapture* cvCreateCameraCapture_V4L( int index ); + +static double icvGetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id ); +static int icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id, double value ); + +static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h); + +/*********************** Implementations ***************************************/ + +static int numCameras = 0; +static int indexList = 0; + +// IOCTL handling for V4L2 +static int xioctl( int fd, int request, void *arg) +{ + + int r; + + + do r = v4l2_ioctl (fd, request, arg); + while (-1 == r && EINTR == errno); + + return r; + +} + + +/* Simple test program: Find number of Video Sources available. + Start from 0 and go to MAX_CAMERAS while checking for the device with that name. + If it fails on the first attempt of /dev/video0, then check if /dev/video is valid. + Returns the global numCameras with the correct value (we hope) */ + +static void icvInitCapture_V4L() { + int deviceHandle; + int CameraNumber; + char deviceName[MAX_DEVICE_DRIVER_NAME]; + + CameraNumber = 0; + while(CameraNumber < MAX_CAMERAS) { + /* Print the CameraNumber at the end of the string with a width of one character */ + sprintf(deviceName, "/dev/video%1d", CameraNumber); + /* Test using an open to see if this new device name really does exists. */ + deviceHandle = open(deviceName, O_RDONLY); + if (deviceHandle != -1) { + /* This device does indeed exist - add it to the total so far */ + // add indexList + indexList|=(1 << CameraNumber); + numCameras++; + } + if (deviceHandle != -1) + close(deviceHandle); + /* Set up to test the next /dev/video source in line */ + CameraNumber++; + } /* End while */ + +}; /* End icvInitCapture_V4L */ + + +static int try_init_v4l(CvCaptureCAM_V4L* capture, char *deviceName) + +{ + + // if detect = -1 then unable to open device + // if detect = 0 then detected nothing + // if detect = 1 then V4L device + int detect = 0; + + + // Test device for V4L compability + + /* Test using an open to see if this new device name really does exists. */ + /* No matter what the name - it still must be opened! */ + capture->deviceHandle = v4l1_open(deviceName, O_RDWR); + + + if (capture->deviceHandle == 0) + { + detect = -1; + + icvCloseCAM_V4L(capture); + } + + if (detect == 0) + { + /* Query the newly opened device for its capabilities */ + if (v4l1_ioctl(capture->deviceHandle, VIDIOCGCAP, &capture->capability) < 0) + { + detect = 0; + + icvCloseCAM_V4L(capture); + } + else + { + detect = 1; + } + } + + return detect; + +} + + +static int try_init_v4l2(CvCaptureCAM_V4L* capture, char *deviceName) +{ + + // if detect = -1 then unable to open device + // if detect = 0 then detected nothing + // if detect = 1 then V4L2 device + int detect = 0; + + + // Test device for V4L2 compability + + /* Open and test V4L2 device */ + capture->deviceHandle = v4l2_open (deviceName, O_RDWR /* required */ | O_NONBLOCK, 0); + + + + if (capture->deviceHandle == 0) + { + detect = -1; + + icvCloseCAM_V4L(capture); + } + + if (detect == 0) + { + CLEAR (capture->cap); + if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYCAP, &capture->cap)) + { + detect = 0; + + icvCloseCAM_V4L(capture); + } + else + { + CLEAR (capture->capability); + capture->capability.type = capture->cap.capabilities; + + /* Query channels number */ + if (-1 != xioctl (capture->deviceHandle, VIDIOC_G_INPUT, &capture->capability.channels)) + { + detect = 1; + } + } + } + + return detect; + +} + + +static void v4l2_scan_controls_enumerate_menu(CvCaptureCAM_V4L* capture) +{ +// printf (" Menu items:\n"); + CLEAR (capture->querymenu); + capture->querymenu.id = capture->queryctrl.id; + for (capture->querymenu.index = capture->queryctrl.minimum; + (int)capture->querymenu.index <= capture->queryctrl.maximum; + capture->querymenu.index++) + { + if (0 == xioctl (capture->deviceHandle, VIDIOC_QUERYMENU, + &capture->querymenu)) + { + //printf (" %s\n", capture->querymenu.name); + } else { + perror ("VIDIOC_QUERYMENU"); + } + } +} + +static void v4l2_free_ranges(CvCaptureCAM_V4L* capture) { + int i; + if (capture->v4l2_ctrl_ranges != NULL) { + for (i = 0; i < capture->v4l2_ctrl_count; i++) { + /* Return device to initial values: */ + /* double value = (capture->v4l2_ctrl_ranges[i]->initial_value == 0)?0.0:((float)capture->v4l2_ctrl_ranges[i]->initial_value - capture->v4l2_ctrl_ranges[i]->minimum) / (capture->v4l2_ctrl_ranges[i]->maximum - capture->v4l2_ctrl_ranges[i]->minimum); */ + /* Return device to default values: */ + /* double value = (capture->v4l2_ctrl_ranges[i]->default_value == 0)?0.0:((float)capture->v4l2_ctrl_ranges[i]->default_value - capture->v4l2_ctrl_ranges[i]->minimum + 1) / (capture->v4l2_ctrl_ranges[i]->maximum - capture->v4l2_ctrl_ranges[i]->minimum); */ + + /* icvSetPropertyCAM_V4L(capture, capture->v4l2_ctrl_ranges[i]->ctrl_id, value); */ + free(capture->v4l2_ctrl_ranges[i]); + } + } + free(capture->v4l2_ctrl_ranges); + capture->v4l2_ctrl_count = 0; + capture->v4l2_ctrl_ranges = NULL; +} + +static void v4l2_add_ctrl_range(CvCaptureCAM_V4L* capture, v4l2_control* ctrl) { + v4l2_ctrl_range* range = (v4l2_ctrl_range*)malloc(sizeof(v4l2_ctrl_range)); + range->ctrl_id = ctrl->id; + range->initial_value = ctrl->value; + range->current_value = ctrl->value; + range->minimum = capture->queryctrl.minimum; + range->maximum = capture->queryctrl.maximum; + range->default_value = capture->queryctrl.default_value; + capture->v4l2_ctrl_ranges[capture->v4l2_ctrl_count] = range; + capture->v4l2_ctrl_count += 1; + capture->v4l2_ctrl_ranges = (v4l2_ctrl_range**)realloc((v4l2_ctrl_range**)capture->v4l2_ctrl_ranges, (capture->v4l2_ctrl_count + 1) * sizeof(v4l2_ctrl_range*)); +} + +static int v4l2_get_ctrl_default(CvCaptureCAM_V4L* capture, __u32 id) { + int i; + for (i = 0; i < capture->v4l2_ctrl_count; i++) { + if (id == capture->v4l2_ctrl_ranges[i]->ctrl_id) { + return capture->v4l2_ctrl_ranges[i]->default_value; + } + } + return -1; +} + +static int v4l2_get_ctrl_min(CvCaptureCAM_V4L* capture, __u32 id) { + int i; + for (i = 0; i < capture->v4l2_ctrl_count; i++) { + if (id == capture->v4l2_ctrl_ranges[i]->ctrl_id) { + return capture->v4l2_ctrl_ranges[i]->minimum; + } + } + return -1; +} + +static int v4l2_get_ctrl_max(CvCaptureCAM_V4L* capture, __u32 id) { + int i; + for (i = 0; i < capture->v4l2_ctrl_count; i++) { + if (id == capture->v4l2_ctrl_ranges[i]->ctrl_id) { + return capture->v4l2_ctrl_ranges[i]->maximum; + } + } + return -1; +} + + +static void v4l2_scan_controls(CvCaptureCAM_V4L* capture) { + + __u32 ctrl_id; + struct v4l2_control c; + if (capture->v4l2_ctrl_ranges != NULL) { + v4l2_free_ranges(capture); + } + capture->v4l2_ctrl_ranges = (v4l2_ctrl_range**)malloc(sizeof(v4l2_ctrl_range*)); +#ifdef V4L2_CTRL_FLAG_NEXT_CTRL + /* Try the extended control API first */ + capture->queryctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; + if(0 == v4l2_ioctl (capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl)) { + do { + c.id = capture->queryctrl.id; + capture->queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; + if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) { + continue; + } + if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU) { + v4l2_scan_controls_enumerate_menu(capture); + } + if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER && + capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN && + capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) { + continue; + } + if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) { + v4l2_add_ctrl_range(capture, &c); + } + + } while(0 == v4l2_ioctl (capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl)); + } else +#endif + { + /* Check all the standard controls */ + for(ctrl_id=V4L2_CID_BASE; ctrl_idqueryctrl.id = ctrl_id; + if(v4l2_ioctl(capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl) == 0) { + if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) { + continue; + } + if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU) { + v4l2_scan_controls_enumerate_menu(capture); + } + if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER && + capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN && + capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) { + continue; + } + c.id = ctrl_id; + + if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) { + v4l2_add_ctrl_range(capture, &c); + } + } + } + + /* Check any custom controls */ + for(ctrl_id=V4L2_CID_PRIVATE_BASE; ; ctrl_id++) { + capture->queryctrl.id = ctrl_id; + if(v4l2_ioctl(capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl) == 0) { + if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) { + continue; + } + + if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU) { + v4l2_scan_controls_enumerate_menu(capture); + } + + if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER && + capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN && + capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) { + continue; + } + + c.id = ctrl_id; + + if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) { + v4l2_add_ctrl_range(capture, &c); + } + } else { + break; + } + } + } +} + +static int _capture_V4L2 (CvCaptureCAM_V4L *capture, char *deviceName) +{ + int detect_v4l2 = 0; + + capture->deviceName = strdup(deviceName); + + detect_v4l2 = try_init_v4l2(capture, deviceName); + + if (detect_v4l2 != 1) { + /* init of the v4l2 device is not OK */ + return -1; + } + + /* starting from here, we assume we are in V4L2 mode */ + capture->is_v4l2_device = 1; + + capture->v4l2_ctrl_ranges = NULL; + capture->v4l2_ctrl_count = 0; + + /* Scan V4L2 controls */ + v4l2_scan_controls(capture); + + if ((capture->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { + /* Nope. */ + fprintf( stderr, "HIGHGUI ERROR: V4L2: device %s is unable to capture video memory.\n",deviceName); + icvCloseCAM_V4L(capture); + return -1; + } + + /* The following code sets the CHANNEL_NUMBER of the video input. Some video sources + have sub "Channel Numbers". For a typical V4L TV capture card, this is usually 1. + I myself am using a simple NTSC video input capture card that uses the value of 1. + If you are not in North America or have a different video standard, you WILL have to change + the following settings and recompile/reinstall. This set of settings is based on + the most commonly encountered input video source types (like my bttv card) */ + + if(capture->inp.index > 0) { + CLEAR (capture->inp); + capture->inp.index = CHANNEL_NUMBER; + /* Set only channel number to CHANNEL_NUMBER */ + /* V4L2 have a status field from selected video mode */ + if (-1 == xioctl (capture->deviceHandle, VIDIOC_ENUMINPUT, &capture->inp)) + { + fprintf (stderr, "HIGHGUI ERROR: V4L2: Aren't able to set channel number\n"); + icvCloseCAM_V4L (capture); + return -1; + } + } /* End if */ + + /* Find Window info */ + CLEAR (capture->form); + capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) { + fprintf( stderr, "HIGHGUI ERROR: V4L2: Could not obtain specifics of capture window.\n\n"); + icvCloseCAM_V4L(capture); + return -1; + } + + /* libv4l will convert from any format to V4L2_PIX_FMT_BGR24 */ + CLEAR (capture->form); + capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + capture->form.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24; + capture->form.fmt.pix.field = V4L2_FIELD_ANY; + capture->form.fmt.pix.width = capture->width; + capture->form.fmt.pix.height = capture->height; + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form)) { + fprintf(stderr, "HIGHGUI ERROR: libv4l unable to ioctl S_FMT\n"); + return -1; + } + + if (V4L2_PIX_FMT_BGR24 != capture->form.fmt.pix.pixelformat) { + fprintf( stderr, "HIGHGUI ERROR: libv4l unable convert to requested pixfmt\n"); + return -1; + } + + /* icvSetVideoSize(capture, DEFAULT_V4L_WIDTH, DEFAULT_V4L_HEIGHT); */ + + unsigned int min; + + /* Buggy driver paranoia. */ + min = capture->form.fmt.pix.width * 2; + + if (capture->form.fmt.pix.bytesperline < min) + capture->form.fmt.pix.bytesperline = min; + + min = capture->form.fmt.pix.bytesperline * capture->form.fmt.pix.height; + + if (capture->form.fmt.pix.sizeimage < min) + capture->form.fmt.pix.sizeimage = min; + + CLEAR (capture->req); + + unsigned int buffer_number = DEFAULT_V4L_BUFFERS; + + try_again: + + capture->req.count = buffer_number; + capture->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + capture->req.memory = V4L2_MEMORY_MMAP; + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_REQBUFS, &capture->req)) + { + if (EINVAL == errno) + { + fprintf (stderr, "%s does not support memory mapping\n", deviceName); + } else { + perror ("VIDIOC_REQBUFS"); + } + /* free capture, and returns an error code */ + icvCloseCAM_V4L (capture); + return -1; + } + + if (capture->req.count < buffer_number) + { + if (buffer_number == 1) + { + fprintf (stderr, "Insufficient buffer memory on %s\n", deviceName); + + /* free capture, and returns an error code */ + icvCloseCAM_V4L (capture); + return -1; + } else { + buffer_number--; + fprintf (stderr, "Insufficient buffer memory on %s -- decreaseing buffers\n", deviceName); + + goto try_again; + } + } + + for (n_buffers = 0; n_buffers < capture->req.count; ++n_buffers) + { + struct v4l2_buffer buf; + + CLEAR (buf); + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = n_buffers; + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYBUF, &buf)) { + perror ("VIDIOC_QUERYBUF"); + + /* free capture, and returns an error code */ + icvCloseCAM_V4L (capture); + return -1; + } + + capture->buffers[n_buffers].length = buf.length; + capture->buffers[n_buffers].start = + v4l2_mmap (NULL /* start anywhere */, + buf.length, + PROT_READ | PROT_WRITE /* required */, + MAP_SHARED /* recommended */, + capture->deviceHandle, buf.m.offset); + + if (MAP_FAILED == capture->buffers[n_buffers].start) { + perror ("mmap"); + + /* free capture, and returns an error code */ + icvCloseCAM_V4L (capture); + return -1; + } + +#ifdef USE_TEMP_BUFFER + if (n_buffers == 0) { + if (capture->buffers[MAX_V4L_BUFFERS].start) { + free(capture->buffers[MAX_V4L_BUFFERS].start); + capture->buffers[MAX_V4L_BUFFERS].start = NULL; + } + + capture->buffers[MAX_V4L_BUFFERS].start = malloc(buf.length); + capture->buffers[MAX_V4L_BUFFERS].length = buf.length; + }; +#endif + } + + /* Set up Image data */ + cvInitImageHeader( &capture->frame, + cvSize( capture->captureWindow.width, + capture->captureWindow.height ), + IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 ); + /* Allocate space for RGBA data */ + capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize); + + return 1; +}; /* End _capture_V4L2 */ + + +static int _capture_V4L (CvCaptureCAM_V4L *capture, char *deviceName) +{ + int detect_v4l = 0; + + detect_v4l = try_init_v4l(capture, deviceName); + + if ((detect_v4l == -1) + ) + { + fprintf (stderr, "HIGHGUI ERROR: V4L" + ": device %s: Unable to open for READ ONLY\n", deviceName); + + return -1; + } + + if ((detect_v4l <= 0) + ) + { + fprintf (stderr, "HIGHGUI ERROR: V4L" + ": device %s: Unable to query number of channels\n", deviceName); + + return -1; + } + + { + if ((capture->capability.type & VID_TYPE_CAPTURE) == 0) { + /* Nope. */ + fprintf( stderr, "HIGHGUI ERROR: V4L: " + "device %s is unable to capture video memory.\n",deviceName); + icvCloseCAM_V4L(capture); + return -1; + } + + } + + + /* The following code sets the CHANNEL_NUMBER of the video input. Some video sources + have sub "Channel Numbers". For a typical V4L TV capture card, this is usually 1. + I myself am using a simple NTSC video input capture card that uses the value of 1. + If you are not in North America or have a different video standard, you WILL have to change + the following settings and recompile/reinstall. This set of settings is based on + the most commonly encountered input video source types (like my bttv card) */ + + { + + if(capture->capability.channels>0) { + + struct video_channel selectedChannel; + + selectedChannel.channel=CHANNEL_NUMBER; + if (v4l1_ioctl(capture->deviceHandle, VIDIOCGCHAN , &selectedChannel) != -1) { + /* set the video mode to ( VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM) */ +// selectedChannel.norm = VIDEO_MODE_NTSC; + if (v4l1_ioctl(capture->deviceHandle, VIDIOCSCHAN , &selectedChannel) == -1) { + /* Could not set selected channel - Oh well */ + //printf("\n%d, %s not NTSC capable.\n",selectedChannel.channel, selectedChannel.name); + } /* End if */ + } /* End if */ + } /* End if */ + + } + + { + + if(v4l1_ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) == -1) { + fprintf( stderr, "HIGHGUI ERROR: V4L: " + "Could not obtain specifics of capture window.\n\n"); + icvCloseCAM_V4L(capture); + return -1; + } + + } + + { + if(v4l1_ioctl(capture->deviceHandle, VIDIOCGPICT, &capture->imageProperties) < 0) { + fprintf( stderr, "HIGHGUI ERROR: V4L: Unable to determine size of incoming image\n"); + icvCloseCAM_V4L(capture); + return -1; + } + + capture->imageProperties.palette = VIDEO_PALETTE_RGB24; + capture->imageProperties.depth = 24; + if (v4l1_ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties) < 0) { + fprintf( stderr, "HIGHGUI ERROR: libv4l unable to ioctl VIDIOCSPICT\n\n"); + icvCloseCAM_V4L(capture); + return -1; + } + if (v4l1_ioctl(capture->deviceHandle, VIDIOCGPICT, &capture->imageProperties) < 0) { + fprintf( stderr, "HIGHGUI ERROR: libv4l unable to ioctl VIDIOCGPICT\n\n"); + icvCloseCAM_V4L(capture); + return -1; + } + if (capture->imageProperties.palette != VIDEO_PALETTE_RGB24) { + fprintf( stderr, "HIGHGUI ERROR: libv4l unable convert to requested pixfmt\n\n"); + icvCloseCAM_V4L(capture); + return -1; + } + + } + + { + + v4l1_ioctl(capture->deviceHandle, VIDIOCGMBUF, &capture->memoryBuffer); + capture->memoryMap = (char *)v4l1_mmap(0, + capture->memoryBuffer.size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + capture->deviceHandle, + 0); + if (capture->memoryMap == MAP_FAILED) { + fprintf( stderr, "HIGHGUI ERROR: V4L: Mapping Memmory from video source error: %s\n", strerror(errno)); + icvCloseCAM_V4L(capture); + return -1; + } + + /* Set up video_mmap structure pointing to this memory mapped area so each image may be + retrieved from an index value */ + capture->mmaps = (struct video_mmap *) + (malloc(capture->memoryBuffer.frames * sizeof(struct video_mmap))); + if (!capture->mmaps) { + fprintf( stderr, "HIGHGUI ERROR: V4L: Could not memory map video frames.\n"); + icvCloseCAM_V4L(capture); + return -1; + } + + } + + /* Set up Image data */ + cvInitImageHeader( &capture->frame, + cvSize( capture->captureWindow.width, + capture->captureWindow.height ), + IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 ); + /* Allocate space for RGBA data */ + capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize); + + return 1; +}; /* End _capture_V4L */ + +static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (int index) +{ + static int autoindex; + autoindex = 0; + + char deviceName[MAX_DEVICE_DRIVER_NAME]; + + if (!numCameras) + icvInitCapture_V4L(); /* Havent called icvInitCapture yet - do it now! */ + if (!numCameras) + return NULL; /* Are there any /dev/video input sources? */ + + //search index in indexList + if ( (index>-1) && ! ((1 << index) & indexList) ) + { + fprintf( stderr, "HIGHGUI ERROR: V4L: index %d is not correct!\n",index); + return NULL; /* Did someone ask for not correct video source number? */ + } + /* Allocate memory for this humongus CvCaptureCAM_V4L structure that contains ALL + the handles for V4L processing */ + CvCaptureCAM_V4L * capture = (CvCaptureCAM_V4L*)cvAlloc(sizeof(CvCaptureCAM_V4L)); + if (!capture) { + fprintf( stderr, "HIGHGUI ERROR: V4L: Could not allocate memory for capture process.\n"); + return NULL; + } + + /* set the default size */ + capture->width = DEFAULT_V4L_WIDTH; + capture->height = DEFAULT_V4L_HEIGHT; + +#ifdef USE_TEMP_BUFFER + capture->buffers[MAX_V4L_BUFFERS].start = NULL; +#endif + + /* Select camera, or rather, V4L video source */ + if (index<0) { // Asking for the first device available + for (; autoindexFirstCapture = 1; + + + if (_capture_V4L2 (capture, deviceName) == -1) { + icvCloseCAM_V4L(capture); + capture->is_v4l2_device = 0; + if (_capture_V4L (capture, deviceName) == -1) { + icvCloseCAM_V4L(capture); + return NULL; + } + } else { + capture->is_v4l2_device = 1; + } + + return capture; +}; /* End icvOpenCAM_V4L */ + +#ifdef HAVE_CAMV4L2 + +static int read_frame_v4l2(CvCaptureCAM_V4L* capture) { + struct v4l2_buffer buf; + + CLEAR (buf); + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_DQBUF, &buf)) { + switch (errno) { + case EAGAIN: + return 0; + + case EIO: + /* Could ignore EIO, see spec. */ + + /* fall through */ + + default: + /* display the error and stop processing */ + perror ("VIDIOC_DQBUF"); + return 1; + } + } + + assert(buf.index < capture->req.count); + +#ifdef USE_TEMP_BUFFER + memcpy(capture->buffers[MAX_V4L_BUFFERS].start, + capture->buffers[buf.index].start, + capture->buffers[MAX_V4L_BUFFERS].length ); + capture->bufferIndex = MAX_V4L_BUFFERS; + //printf("got data in buff %d, len=%d, flags=0x%X, seq=%d, used=%d)\n", + // buf.index, buf.length, buf.flags, buf.sequence, buf.bytesused); +#else + capture->bufferIndex = buf.index; +#endif + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf)) + perror ("VIDIOC_QBUF"); + + return 1; +} + +static void mainloop_v4l2(CvCaptureCAM_V4L* capture) { + unsigned int count; + + count = 1; + + while (count-- > 0) { + for (;;) { + fd_set fds; + struct timeval tv; + int r; + + FD_ZERO (&fds); + FD_SET (capture->deviceHandle, &fds); + + /* Timeout. */ + tv.tv_sec = 2; + tv.tv_usec = 0; + + r = select (capture->deviceHandle+1, &fds, NULL, NULL, &tv); + + if (-1 == r) { + if (EINTR == errno) + continue; + + perror ("select"); + } + + if (0 == r) { + fprintf (stderr, "select timeout\n"); + + /* end the infinite loop */ + break; + } + + if (read_frame_v4l2 (capture)) + break; + } + } +} + +static int icvGrabFrameCAM_V4L(CvCaptureCAM_V4L* capture) { + + if (capture->FirstCapture) { + /* Some general initialization must take place the first time through */ + + /* This is just a technicality, but all buffers must be filled up before any + staggered SYNC is applied. SO, filler up. (see V4L HowTo) */ + + if (capture->is_v4l2_device == 1) + { + + for (capture->bufferIndex = 0; + capture->bufferIndex < ((int)capture->req.count); + ++capture->bufferIndex) + { + + struct v4l2_buffer buf; + + CLEAR (buf); + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = (unsigned long)capture->bufferIndex; + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf)) { + perror ("VIDIOC_QBUF"); + return 0; + } + } + + /* enable the streaming */ + capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl (capture->deviceHandle, VIDIOC_STREAMON, + &capture->type)) { + /* error enabling the stream */ + perror ("VIDIOC_STREAMON"); + return 0; + } + } else + { + + for (capture->bufferIndex = 0; + capture->bufferIndex < (capture->memoryBuffer.frames-1); + ++capture->bufferIndex) { + + capture->mmaps[capture->bufferIndex].frame = capture->bufferIndex; + capture->mmaps[capture->bufferIndex].width = capture->captureWindow.width; + capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height; + capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette; + + if (v4l1_ioctl(capture->deviceHandle, VIDIOCMCAPTURE, &capture->mmaps[capture->bufferIndex]) == -1) { + fprintf( stderr, "HIGHGUI ERROR: V4L: Initial Capture Error: Unable to load initial memory buffers.\n"); + return 0; + } + } + + } + + /* preparation is ok */ + capture->FirstCapture = 0; + } + + if (capture->is_v4l2_device == 1) + { + + mainloop_v4l2(capture); + + } else + { + + capture->mmaps[capture->bufferIndex].frame = capture->bufferIndex; + capture->mmaps[capture->bufferIndex].width = capture->captureWindow.width; + capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height; + capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette; + + if (v4l1_ioctl (capture->deviceHandle, VIDIOCMCAPTURE, + &capture->mmaps[capture->bufferIndex]) == -1) { + /* capture is on the way, so just exit */ + return 1; + } + + ++capture->bufferIndex; + if (capture->bufferIndex == capture->memoryBuffer.frames) { + capture->bufferIndex = 0; + } + + } + + return(1); +} + +static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int) { + + if (capture->is_v4l2_device == 0) + { + + /* [FD] this really belongs here */ + if (v4l1_ioctl(capture->deviceHandle, VIDIOCSYNC, &capture->mmaps[capture->bufferIndex].frame) == -1) { + fprintf( stderr, "HIGHGUI ERROR: V4L: Could not SYNC to video stream. %s\n", strerror(errno)); + } + + } + + /* Now get what has already been captured as a IplImage return */ + + /* First, reallocate imageData if the frame size changed */ + + if (capture->is_v4l2_device == 1) + { + + if(((unsigned long)capture->frame.width != capture->form.fmt.pix.width) + || ((unsigned long)capture->frame.height != capture->form.fmt.pix.height)) { + cvFree(&capture->frame.imageData); + cvInitImageHeader( &capture->frame, + cvSize( capture->form.fmt.pix.width, + capture->form.fmt.pix.height ), + IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 ); + capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize); + } + + } else + { + + if((capture->frame.width != capture->mmaps[capture->bufferIndex].width) + || (capture->frame.height != capture->mmaps[capture->bufferIndex].height)) { + cvFree(&capture->frame.imageData); + cvInitImageHeader( &capture->frame, + cvSize( capture->captureWindow.width, + capture->captureWindow.height ), + IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 ); + capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize); + } + + } + + if (capture->is_v4l2_device == 1) + { + + if(capture->buffers[capture->bufferIndex].start){ + memcpy((char *)capture->frame.imageData, + (char *)capture->buffers[capture->bufferIndex].start, + capture->frame.imageSize); + } + + } else +#endif /* HAVE_CAMV4L2 */ + { + + switch(capture->imageProperties.palette) { + case VIDEO_PALETTE_RGB24: + memcpy((char *)capture->frame.imageData, + (char *)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]), + capture->frame.imageSize); + break; + default: + fprintf( stderr, + "HIGHGUI ERROR: V4L: Cannot convert from palette %d to RGB\n", + capture->imageProperties.palette); + return 0; + } + + } + + return(&capture->frame); +} + +/* TODO: review this adaptation */ +static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture, + int property_id ) { + char name[32]; + int is_v4l2_device = 0; + /* initialize the control structure */ + switch (property_id) { + case CV_CAP_PROP_FRAME_WIDTH: + case CV_CAP_PROP_FRAME_HEIGHT: + CLEAR (capture->form); + capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) { + /* display an error message, and return an error code */ + perror ("VIDIOC_G_FMT"); + if (v4l1_ioctl (capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) { + fprintf (stderr, "HIGHGUI ERROR: V4L: Unable to determine size of incoming image\n"); + icvCloseCAM_V4L(capture); + return -1; + } else { + int retval = (property_id == CV_CAP_PROP_FRAME_WIDTH)?capture->captureWindow.width:capture->captureWindow.height; + return retval / 0xFFFF; + } + } + return (property_id == CV_CAP_PROP_FRAME_WIDTH)?capture->form.fmt.pix.width:capture->form.fmt.pix.height; + case CV_CAP_PROP_BRIGHTNESS: + sprintf(name, "Brightness"); + capture->control.id = V4L2_CID_BRIGHTNESS; + break; + case CV_CAP_PROP_CONTRAST: + sprintf(name, "Contrast"); + capture->control.id = V4L2_CID_CONTRAST; + break; + case CV_CAP_PROP_SATURATION: + sprintf(name, "Saturation"); + capture->control.id = V4L2_CID_SATURATION; + break; + case CV_CAP_PROP_HUE: + sprintf(name, "Hue"); + capture->control.id = V4L2_CID_HUE; + break; + case CV_CAP_PROP_GAIN: + sprintf(name, "Gain"); + capture->control.id = V4L2_CID_GAIN; + break; + case CV_CAP_PROP_EXPOSURE: + sprintf(name, "Exposure"); + capture->control.id = V4L2_CID_EXPOSURE; + break; + default: + sprintf(name, ""); + capture->control.id = property_id; + } + + if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &capture->control) == 0) { + /* all went well */ + is_v4l2_device = 1; + } else { + fprintf(stderr, "HIGHGUI ERROR: V4L2: Unable to get property %s(%u) - %s\n", name, capture->control.id, strerror(errno)); + } + + if (is_v4l2_device == 1) { + /* get the min/max values */ + int v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id); + int v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id); + + if ((v4l2_min == -1) && (v4l2_max == -1)) { + fprintf(stderr, "HIGHGUI ERROR: V4L2: Property %s(%u) not supported by device\n", name, property_id); + return -1; + } + + /* all was OK, so convert to 0.0 - 1.0 range, and return the value */ + return ((float)capture->control.value - v4l2_min) / (v4l2_max - v4l2_min); + + } else { + /* TODO: review this section */ + int retval = -1; + + switch (property_id) { + case CV_CAP_PROP_BRIGHTNESS: + retval = capture->imageProperties.brightness; + break; + case CV_CAP_PROP_CONTRAST: + retval = capture->imageProperties.contrast; + break; + case CV_CAP_PROP_SATURATION: + retval = capture->imageProperties.colour; + break; + case CV_CAP_PROP_HUE: + retval = capture->imageProperties.hue; + break; + case CV_CAP_PROP_GAIN: + fprintf(stderr, "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n"); + return -1; + break; + case CV_CAP_PROP_EXPOSURE: + fprintf(stderr, "HIGHGUI ERROR: V4L: Exposure control in V4L is not supported\n"); + return -1; + break; + } + + if (retval == -1) { + /* there was a problem */ + return -1; + } + /* all was OK, so convert to 0.0 - 1.0 range, and return the value */ + return float (retval) / 0xFFFF; + } +} + +static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h) { + + if (capture->is_v4l2_device == 1) + { + char deviceName[MAX_DEVICE_DRIVER_NAME]; + sprintf(deviceName, "%s", capture->deviceName); + icvCloseCAM_V4L(capture); + _capture_V4L2(capture, deviceName); + + CLEAR (capture->crop); + capture->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + capture->crop.c.left = 0; + capture->crop.c.top = 0; + capture->crop.c.height = h*24; + capture->crop.c.width = w*24; + + /* set the crop area, but don't exit if the device don't support croping */ + xioctl (capture->deviceHandle, VIDIOC_S_CROP, &capture->crop); + + CLEAR (capture->form); + capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* read the current setting, mainly to retreive the pixelformat information */ + xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form); + + /* set the values we want to change */ + capture->form.fmt.pix.width = w; + capture->form.fmt.pix.height = h; + capture->form.fmt.win.chromakey = 0; + capture->form.fmt.win.field = V4L2_FIELD_ANY; + capture->form.fmt.win.clips = 0; + capture->form.fmt.win.clipcount = 0; + capture->form.fmt.pix.field = V4L2_FIELD_ANY; + + /* ask the device to change the size + * don't test if the set of the size is ok, because some device + * don't allow changing the size, and we will get the real size + * later */ + xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form); + + /* try to set framerate to 30 fps */ + struct v4l2_streamparm setfps; + memset (&setfps, 0, sizeof(struct v4l2_streamparm)); + setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + setfps.parm.capture.timeperframe.numerator = 1; + setfps.parm.capture.timeperframe.denominator = 30; + xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps); + + /* we need to re-initialize some things, like buffers, because the size has + * changed */ + capture->FirstCapture = 1; + + /* Get window info again, to get the real value */ + if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) + { + fprintf(stderr, "HIGHGUI ERROR: V4L/V4L2: Could not obtain specifics of capture window.\n\n"); + + icvCloseCAM_V4L(capture); + + return 0; + } + + return 0; + + } else + { + + if (capture==0) return 0; + if (w>capture->capability.maxwidth) { + w=capture->capability.maxwidth; + } + if (h>capture->capability.maxheight) { + h=capture->capability.maxheight; + } + + capture->captureWindow.width=w; + capture->captureWindow.height=h; + + if (ioctl(capture->deviceHandle, VIDIOCSWIN, &capture->captureWindow) < 0) { + icvCloseCAM_V4L(capture); + return 0; + } + + if (ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) { + icvCloseCAM_V4L(capture); + return 0; + } + + capture->FirstCapture = 1; + + } + + return 0; + +} + +static int icvSetControl (CvCaptureCAM_V4L* capture, int property_id, double value) { + struct v4l2_control c; + __s32 ctrl_value; + char name[32]; + int is_v4l2 = 1; + int v4l2_min = 0; + int v4l2_max = 255; + if (capture->v4l2_ctrl_ranges == NULL) { + v4l2_scan_controls(capture); + } + + CLEAR (capture->control); + CLEAR (capture->queryctrl); + + /* get current values */ + switch (property_id) { + case CV_CAP_PROP_BRIGHTNESS: + sprintf(name, "Brightness"); + capture->control.id = V4L2_CID_BRIGHTNESS; + break; + case CV_CAP_PROP_CONTRAST: + sprintf(name, "Contrast"); + capture->control.id = V4L2_CID_CONTRAST; + break; + case CV_CAP_PROP_SATURATION: + sprintf(name, "Saturation"); + capture->control.id = V4L2_CID_SATURATION; + break; + case CV_CAP_PROP_HUE: + sprintf(name, "Hue"); + capture->control.id = V4L2_CID_HUE; + break; + case CV_CAP_PROP_GAIN: + sprintf(name, "Gain"); + capture->control.id = V4L2_CID_GAIN; + break; + case CV_CAP_PROP_EXPOSURE: + sprintf(name, "Exposure"); + capture->control.id = V4L2_CID_EXPOSURE; + break; + default: + sprintf(name, ""); + capture->control.id = property_id; + } + + v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id); + v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id); + + if ((v4l2_min == -1) && (v4l2_max == -1)) { + fprintf(stderr, "HIGHGUI ERROR: V4L: Property %s(%u) not supported by device\n", name, property_id); + return -1; + } + + if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &capture->control) == 0) { + /* all went well */ + } else { + fprintf(stderr, "HIGHGUI ERROR: V4L2: Unable to get property %s(%u) - %s\n", name, capture->control.id, strerror(errno)); + } + + if (v4l2_max != 0) { + double val = value; + if (value < 0.0) { + val = 0.0; + } else if (value > 1.0) { + val = 1.0; + } + ctrl_value = val * (double)(v4l2_max - v4l2_min) + v4l2_min; + } else { + ctrl_value = v4l2_get_ctrl_default(capture, capture->control.id) * (double)(v4l2_max - v4l2_min) + v4l2_min; + } + + /* try and set value as if it was a v4l2 device */ + c.id = capture->control.id; + c.value = ctrl_value; + if (v4l2_ioctl(capture->deviceHandle, VIDIOC_S_CTRL, &c) != 0) { + /* The driver may clamp the value or return ERANGE, ignored here */ + if (errno != ERANGE) { + fprintf(stderr, "HIGHGUI ERROR: V4L2: Failed to set control \"%d\": %s (value %d)\n", c.id, strerror(errno), c.value); + is_v4l2 = 0; + } else { + return 0; + } + } else { + return 0; + } + + if (is_v4l2 == 0) { /* use v4l1_ioctl */ + fprintf(stderr, "HIGHGUI WARNING: Setting property %u through v4l2 failed. Trying with v4l1.\n", c.id); + int v4l_value; + /* scale the value to the wanted integer one */ + v4l_value = (int)(0xFFFF * value); + + switch (property_id) { + case CV_CAP_PROP_BRIGHTNESS: + capture->imageProperties.brightness = v4l_value; + break; + case CV_CAP_PROP_CONTRAST: + capture->imageProperties.contrast = v4l_value; + break; + case CV_CAP_PROP_SATURATION: + capture->imageProperties.colour = v4l_value; + break; + case CV_CAP_PROP_HUE: + capture->imageProperties.hue = v4l_value; + break; + case CV_CAP_PROP_GAIN: + fprintf(stderr, "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n"); + return -1; + case CV_CAP_PROP_EXPOSURE: + fprintf(stderr, "HIGHGUI ERROR: V4L: Exposure control in V4L is not supported\n"); + return -1; + default: + fprintf(stderr, "HIGHGUI ERROR: V4L: property #%d is not supported\n", property_id); + return -1; + } + + if (v4l1_ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties) < 0){ + fprintf(stderr, "HIGHGUI ERROR: V4L: Unable to set video informations\n"); + icvCloseCAM_V4L(capture); + return -1; + } + } + + /* all was OK */ + return 0; +} + +static int icvSetPropertyCAM_V4L(CvCaptureCAM_V4L* capture, int property_id, double value){ + static int width = 0, height = 0; + int retval; + + /* initialization */ + retval = 0; + + /* two subsequent calls setting WIDTH and HEIGHT will change + the video size */ + /* the first one will return an error, though. */ + + switch (property_id) { + case CV_CAP_PROP_FRAME_WIDTH: + width = cvRound(value); + capture->width = width; + if(width !=0 && height != 0) { + retval = icvSetVideoSize( capture, width, height); + width = height = 0; + } + break; + case CV_CAP_PROP_FRAME_HEIGHT: + height = cvRound(value); + capture->height = height; + if(width !=0 && height != 0) { + retval = icvSetVideoSize( capture, width, height); + width = height = 0; + } + break; + default: + retval = icvSetControl(capture, property_id, value); + } + + /* return the the status */ + return retval; +} + +static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture ){ + /* Deallocate space - Hopefully, no leaks */ + if (capture) { + v4l2_free_ranges(capture); + if (capture->is_v4l2_device == 0) { + if (capture->mmaps) { + free(capture->mmaps); + } + if (capture->memoryMap) { + v4l1_munmap(capture->memoryMap, capture->memoryBuffer.size); + } + if (capture->deviceHandle != -1) { + v4l1_close(capture->deviceHandle); + } + } else { + capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (xioctl(capture->deviceHandle, VIDIOC_STREAMOFF, &capture->type) < 0) { + perror ("Unable to stop the stream."); + } + for (unsigned int n_buffers2 = 0; n_buffers2 < capture->req.count; ++n_buffers2) { + if (-1 == v4l2_munmap (capture->buffers[n_buffers2].start, capture->buffers[n_buffers2].length)) { + perror ("munmap"); + } + } + + if (capture->deviceHandle != -1) { + v4l2_close(capture->deviceHandle); + } + } + + if (capture->frame.imageData) + cvFree(&capture->frame.imageData); + +#ifdef USE_TEMP_BUFFER + if (capture->buffers[MAX_V4L_BUFFERS].start) { + free(capture->buffers[MAX_V4L_BUFFERS].start); + capture->buffers[MAX_V4L_BUFFERS].start = NULL; + } +#endif + + free(capture->deviceName); + //v4l2_free_ranges(capture); + //cvFree((void **)capture); + } +}; + + +class CvCaptureCAM_V4L_CPP : CvCapture +{ +public: + CvCaptureCAM_V4L_CPP() { captureV4L = 0; } + virtual ~CvCaptureCAM_V4L_CPP() { close(); } + + virtual bool open( int index ); + virtual void close(); + + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); +protected: + + CvCaptureCAM_V4L* captureV4L; +}; + +bool CvCaptureCAM_V4L_CPP::open( int index ) +{ + close(); + captureV4L = icvCaptureFromCAM_V4L(index); + return captureV4L != 0; +} + +void CvCaptureCAM_V4L_CPP::close() +{ + if( captureV4L ) + { + icvCloseCAM_V4L( captureV4L ); + cvFree( &captureV4L ); + } +} + +bool CvCaptureCAM_V4L_CPP::grabFrame() +{ + return captureV4L ? icvGrabFrameCAM_V4L( captureV4L ) != 0 : false; +} + +IplImage* CvCaptureCAM_V4L_CPP::retrieveFrame(int) +{ + return captureV4L ? icvRetrieveFrameCAM_V4L( captureV4L, 0 ) : 0; +} + +double CvCaptureCAM_V4L_CPP::getProperty( int propId ) +{ + return captureV4L ? icvGetPropertyCAM_V4L( captureV4L, propId ) : 0.0; +} + +bool CvCaptureCAM_V4L_CPP::setProperty( int propId, double value ) +{ + return captureV4L ? icvSetPropertyCAM_V4L( captureV4L, propId, value ) != 0 : false; +} + +CvCapture* cvCreateCameraCapture_V4L( int index ) +{ + CvCaptureCAM_V4L_CPP* capture = new CvCaptureCAM_V4L_CPP; + + if( capture->open( index )) + return (CvCapture*)capture; + + delete capture; + return 0; +} + +#endif diff --git a/highgui/src/cap_mil.cpp b/highgui/src/cap_mil.cpp new file mode 100644 index 0000000..f2797e2 --- /dev/null +++ b/highgui/src/cap_mil.cpp @@ -0,0 +1,219 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include "mil.h" + +#if _MSC_VER >= 1200 + #pragma warning( disable: 4711 ) + #pragma comment(lib,"mil.lib") + #pragma comment(lib,"milmet2.lib") +#endif + +#if defined _M_X64 + #pragma optimize("",off) +#endif + +/********************* Capturing video from camera via MIL *********************/ + +struct +{ + MIL_ID MilApplication; + int MilUser; +} g_Mil = {0,0}; //global structure for handling MIL application + +class CvCaptureCAM_MIL : public CvCapture +{ +public: + CvCaptureCAM_MIL() { init(); } + virtual ~CvCaptureCAM_MIL() { close(); } + + virtual bool open( int index ); + virtual void close(); + + virtual double getProperty(int); + virtual bool setProperty(int, double) { return false; } + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual int getCaptureDomain() { return CV_CAP_MIL; } // Return the type of the capture object: CV_CAP_VFW, etc... + +protected: + void init(); + + MIL_ID + MilSystem, /* System identifier. */ + MilDisplay, /* Display identifier. */ + MilDigitizer, /* Digitizer identifier. */ + MilImage; /* Image buffer identifier. */ + IplImage* rgb_frame; +}; + + +void CvCaptureCAM_MIL::init() +{ + MilSystem = MilDisplay = MilDigitizer = MilImage = M_NULL; + rgb_frame = 0; +} + +// Initialize camera input +bool CvCaptureCAM_MIL::open( int wIndex ) +{ + close(); + + if( g_Mil.MilApplication == M_NULL ) + { + assert(g_Mil.MilUser == 0); + MappAlloc(M_DEFAULT, &(g_Mil.MilApplication) ); + g_Mil.MilUser = 1; + } + else + { + assert(g_Mil.MilUser>0); + g_Mil.MilUser++; + } + + int dev_table[16] = { M_DEV0, M_DEV1, M_DEV2, M_DEV3, + M_DEV4, M_DEV5, M_DEV6, M_DEV7, + M_DEV8, M_DEV9, M_DEV10, M_DEV11, + M_DEV12, M_DEV13, M_DEV14, M_DEV15 }; + + //set default window size + int w = 320; + int h = 240; + + for( ; wIndex < 16; wIndex++ ) + { + MsysAlloc( M_SYSTEM_SETUP, //we use default system, + //if this does not work + //try to define exact board + //e.g.M_SYSTEM_METEOR,M_SYSTEM_METEOR_II... + dev_table[wIndex], + M_DEFAULT, + &MilSystem ); + + if( MilSystem != M_NULL ) + break; + } + if( MilSystem != M_NULL ) + { + MdigAlloc(MilSystem,M_DEFAULT, + M_CAMERA_SETUP, //default. May be M_NTSC or other + M_DEFAULT,&MilDigitizer); + + rgb_frame = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3 ); + MdigControl(MilDigitizer, M_GRAB_SCALE, 1.0 / 2); + + /*below line enables getting image vertical orientation + consistent with VFW but it introduces some image corruption + on MeteorII, so we left the image as is*/ + //MdigControl(MilDigitizer, M_GRAB_DIRECTION_Y, M_REVERSE ); + + MilImage = MbufAllocColor(MilSystem, 3, w, h, + 8+M_UNSIGNED, M_IMAGE + M_GRAB, M_NULL); + } + + return MilSystem != M_NULL; +} + +void CvCaptureCAM_MIL::close( CvCaptureCAM_MIL* capture ) +{ + if( MilSystem != M_NULL ) + { + MdigFree( MilDigitizer ); + MbufFree( MilImage ); + MsysFree( MilSystem ); + cvReleaseImage(&rgb_frame ); + + g_Mil.MilUser--; + if(!g_Mil.MilUser) + MappFree(g_Mil.MilApplication); + + MilSystem = M_NULL; + MilDigitizer = M_NULL; + } +} + + +bool CvCaptureCAM_MIL::grabFrame() +{ + if( MilSystem ) + { + MdigGrab(MilDigitizer, MilImage); + return true; + } + return false; +} + + +IplImage* CvCaptureCAM_MIL::retrieveFrame(int) +{ + MbufGetColor(MilImage, M_BGR24+M_PACKED, M_ALL_BAND, (void*)(rgb_frame->imageData)); + return rgb_frame; +} + +double CvCaptureCAM_MIL::getProperty( int property_id ) +{ + switch( property_id ) + { + case CV_CAP_PROP_FRAME_WIDTH: + return rgb_frame ? rgb_frame->width : 0; + case CV_CAP_PROP_FRAME_HEIGHT: + return rgb_frame ? rgb_frame->height : 0; + } + return 0; +} + +bool CvCaptureCAM_MIL::setProperty( int, double ) +{ + return false; +} + + +CvCapture* cvCreateCameraCapture_MIL( int index ) +{ + CvCaptureCAM_MIL* capture = new CvCaptureCAM_MIL; + + if( capture->open( index )) + return capture; + + delete capture; + return 0; +} diff --git a/highgui/src/cap_openni.cpp b/highgui/src/cap_openni.cpp new file mode 100644 index 0000000..75aed56 --- /dev/null +++ b/highgui/src/cap_openni.cpp @@ -0,0 +1,1384 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" +#include "opencv2/core/core.hpp" +#include "opencv2/imgproc/imgproc.hpp" + +#ifdef HAVE_OPENNI + +#if defined TBB_INTERFACE_VERSION && TBB_INTERFACE_VERSION < 5000 +# undef HAVE_TBB +#endif + +#include +#include + +#ifndef i386 +# define i386 0 +#endif +#ifndef __arm__ +# define __arm__ 0 +#endif +#ifndef _ARC +# define _ARC 0 +#endif +#ifndef __APPLE__ +# define __APPLE__ 0 +#endif + +#include "XnCppWrapper.h" + +const std::string XMLConfig = +"" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + " " + "" + "" + "" + "" + "" + "" + "" +"\n"; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class ApproximateSyncGrabber +{ +public: + ApproximateSyncGrabber( xn::Context &_context, + xn::DepthGenerator &_depthGenerator, + xn::ImageGenerator &_imageGenerator, + int _maxBufferSize, bool _isCircleBuffer, int _maxTimeDuration ) : + context(_context), depthGenerator(_depthGenerator), imageGenerator(_imageGenerator), + maxBufferSize(_maxBufferSize), isCircleBuffer(_isCircleBuffer), maxTimeDuration(_maxTimeDuration) + { + task = 0; + + CV_Assert( depthGenerator.IsValid() ); + CV_Assert( imageGenerator.IsValid() ); + } + + void setMaxBufferSize( int _maxBufferSize ) + { + maxBufferSize = _maxBufferSize; +#ifdef HAVE_TBB + task->setMaxBufferSize(); +#endif + } + inline int getMaxBufferSize() const { return maxBufferSize; } + + void setIsCircleBuffer( bool _isCircleBuffer ) { isCircleBuffer = _isCircleBuffer; } + bool getIsCircleBuffer() const { return isCircleBuffer; } + + void setMaxTimeDuration( int _maxTimeDuration ) { maxTimeDuration = _maxTimeDuration; } + int getMaxTimeDuration() const { return maxTimeDuration; } + + bool grab( xn::DepthMetaData& depthMetaData, + xn::ImageMetaData& imageMetaData ) + { + CV_Assert( task ); + + + while( task->grab(depthMetaData, imageMetaData) == false ) + { +#ifndef HAVE_TBB + task->spin(); +#endif + } + return true; + + } + + void start() + { + CV_Assert( depthGenerator.IsValid() ); + CV_Assert( imageGenerator.IsValid() ); +#ifdef HAVE_TBB + task = new( tbb::task::allocate_root() ) TBBApproximateSynchronizerTask( *this ); + tbb::task::enqueue(*task); +#else + task = new ApproximateSynchronizer( *this ); +#endif + } + + void finish() + { +#ifdef HAVE_TBB + if( task ) + tbb::task::destroy( *task ); +#else + task.release(); +#endif + } + + bool isRun() const { return task != 0; } + + xn::Context &context; + xn::DepthGenerator &depthGenerator; + xn::ImageGenerator &imageGenerator; + +private: + int maxBufferSize; + bool isCircleBuffer; + int maxTimeDuration; + + class ApproximateSynchronizerBase + { + public: + ApproximateSynchronizerBase( ApproximateSyncGrabber& _approxSyncGrabber ) : + approxSyncGrabber(_approxSyncGrabber), isDepthFilled(false), isImageFilled(false) + {} + + virtual ~ApproximateSynchronizerBase() {} + + virtual bool isSpinContinue() const = 0; + virtual void pushDepthMetaData( xn::DepthMetaData& depthMetaData ) = 0; + virtual void pushImageMetaData( xn::ImageMetaData& imageMetaData ) = 0; + virtual bool popDepthMetaData( xn::DepthMetaData& depthMetaData ) = 0; + virtual bool popImageMetaData( xn::ImageMetaData& imageMetaData ) = 0; + + void spin() + { + while(isSpinContinue() == true) + { + XnStatus status = approxSyncGrabber.context.WaitAnyUpdateAll(); + if( status != XN_STATUS_OK ) + continue; + + //xn::DepthMetaData depth; + //xn::ImageMetaData image; + approxSyncGrabber.depthGenerator.GetMetaData(depth); + approxSyncGrabber.imageGenerator.GetMetaData(image); + + if( depth.Data() && depth.IsDataNew() ) + pushDepthMetaData( depth ); + + if( image.Data() && image.IsDataNew() ) + pushImageMetaData( image ); + } + } + + virtual bool grab( xn::DepthMetaData& depthMetaData, + xn::ImageMetaData& imageMetaData ) + { + while(1) + { + if( !isDepthFilled ) + isDepthFilled = popDepthMetaData(depth); + if( !isImageFilled ) + isImageFilled = popImageMetaData(image); + + if( !isDepthFilled || !isImageFilled ) + break; + + double timeDiff = 1e-3 * std::abs(static_cast(depth.Timestamp()) - static_cast(image.Timestamp())); + + if( timeDiff <= approxSyncGrabber.maxTimeDuration ) + { + depthMetaData.InitFrom(depth); + imageMetaData.InitFrom(image); + isDepthFilled = isImageFilled = false; + return true; + } + else + { + if( depth.Timestamp() < image.Timestamp() ) + isDepthFilled = false; + else + isImageFilled = false; + } + } + + return false; + } + + protected: + ApproximateSyncGrabber& approxSyncGrabber; + xn::DepthMetaData depth; + xn::ImageMetaData image; + bool isDepthFilled; + bool isImageFilled; + }; + + // If there isn't TBB the synchronization will be executed in the main thread. + class ApproximateSynchronizer: public ApproximateSynchronizerBase + { + public: + ApproximateSynchronizer( ApproximateSyncGrabber& _approxSyncGrabber ) : + ApproximateSynchronizerBase(_approxSyncGrabber) + {} + + virtual bool isSpinContinue() const + { + int maxBufferSize = approxSyncGrabber.getMaxBufferSize(); + return (maxBufferSize <= 0) || (static_cast(depthQueue.size()) < maxBufferSize && + static_cast(imageQueue.size()) < maxBufferSize); // "<" to may push + } + + virtual inline void pushDepthMetaData( xn::DepthMetaData& depthMetaData ) + { + cv::Ptr depthPtr = new xn::DepthMetaData; + depthPtr->CopyFrom(depthMetaData); + depthQueue.push(depthPtr); + } + virtual inline void pushImageMetaData( xn::ImageMetaData& imageMetaData ) + { + cv::Ptr imagePtr = new xn::ImageMetaData; + imagePtr->CopyFrom(imageMetaData); + imageQueue.push(imagePtr); + } + virtual inline bool popDepthMetaData( xn::DepthMetaData& depthMetaData ) + { + if( depthQueue.empty() ) + return false; + + depthMetaData.CopyFrom(*depthQueue.front()); + depthQueue.pop(); + return true; + } + virtual inline bool popImageMetaData( xn::ImageMetaData& imageMetaData ) + { + if( imageQueue.empty() ) + return false; + + imageMetaData.CopyFrom(*imageQueue.front()); + imageQueue.pop(); + return true; + } + + private: + std::queue > depthQueue; + std::queue > imageQueue; + }; + +#ifdef HAVE_TBB + // If there is TBB the synchronization will be executed in own thread. + class TBBApproximateSynchronizer: public ApproximateSynchronizerBase + { + public: + TBBApproximateSynchronizer( ApproximateSyncGrabber& approxSyncGrabber ) : + ApproximateSynchronizerBase(approxSyncGrabber) + { + setMaxBufferSize(); + } + + void setMaxBufferSize() + { + int maxBufferSize = ApproximateSynchronizerBase::approxSyncGrabber.getMaxBufferSize(); + if( maxBufferSize >= 0 ) + { + depthQueue.set_capacity( maxBufferSize ); + imageQueue.set_capacity( maxBufferSize ); + } + } + + virtual inline bool isSpinContinue() const { return true; } + + virtual inline void pushDepthMetaData( xn::DepthMetaData& depthMetaData ) + { + cv::Ptr depthPtr = new xn::DepthMetaData, tmp; + depthPtr->CopyFrom(depthMetaData); + + tbb::mutex mtx; + mtx.lock(); + if( depthQueue.try_push(depthPtr) == false ) + { + if( approxSyncGrabber.getIsCircleBuffer() ) + { + CV_Assert( depthQueue.try_pop(tmp) ); + CV_Assert( depthQueue.try_push(depthPtr) ); + } + } + mtx.unlock(); + } + + virtual inline void pushImageMetaData( xn::ImageMetaData& imageMetaData ) + { + cv::Ptr imagePtr = new xn::ImageMetaData, tmp; + imagePtr->CopyFrom(imageMetaData); + + tbb::mutex mtx; + mtx.lock(); + if( imageQueue.try_push(imagePtr) == false ) + { + if( approxSyncGrabber.getIsCircleBuffer() ) + { + CV_Assert( imageQueue.try_pop(tmp) ); + CV_Assert( imageQueue.try_push(imagePtr) ); + } + } + mtx.unlock(); + } + + virtual inline bool popDepthMetaData( xn::DepthMetaData& depthMetaData ) + { + cv::Ptr depthPtr; + bool isPop = depthQueue.try_pop(depthPtr); + if( isPop ) + depthMetaData.CopyFrom(*depthPtr); + return isPop; + } + virtual inline bool popImageMetaData( xn::ImageMetaData& imageMetaData ) + { + cv::Ptr imagePtr; + bool isPop = imageQueue.try_pop(imagePtr); + if( isPop ) + imageMetaData.CopyFrom(*imagePtr); + return isPop; + } + + private: + tbb::concurrent_bounded_queue > depthQueue; + tbb::concurrent_bounded_queue > imageQueue; + }; + + class TBBApproximateSynchronizerTask: public tbb::task + { + public: + TBBApproximateSynchronizerTask( ApproximateSyncGrabber& approxSyncGrabber ) : + synchronizer(approxSyncGrabber) + {} + + void setMaxBufferSize() + { + synchronizer.setMaxBufferSize(); + } + + bool grab( xn::DepthMetaData& depthMetaData, + xn::ImageMetaData& imageMetaData ) + { + return synchronizer.grab( depthMetaData, imageMetaData ); + } + + private: + tbb::task* execute() + { + synchronizer.spin(); + return 0; + } + TBBApproximateSynchronizer synchronizer; + }; +#endif // HAVE_TBB + +#ifdef HAVE_TBB + TBBApproximateSynchronizerTask* task; +#else + cv::Ptr task; +#endif +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class CvCapture_OpenNI : public CvCapture +{ +public: + enum { DEVICE_DEFAULT=0, DEVICE_MS_KINECT=0, DEVICE_ASUS_XTION=1, DEVICE_MAX=1 }; + + static const int INVALID_PIXEL_VAL = 0; + static const int INVALID_COORDINATE_VAL = 0; + +#ifdef HAVE_TBB + static const int DEFAULT_MAX_BUFFER_SIZE = 8; +#else + static const int DEFAULT_MAX_BUFFER_SIZE = 2; +#endif + static const int DEFAULT_IS_CIRCLE_BUFFER = 0; + static const int DEFAULT_MAX_TIME_DURATION = 20; + + CvCapture_OpenNI(int index=0); + CvCapture_OpenNI(const char * filename); + virtual ~CvCapture_OpenNI(); + + virtual double getProperty(int propIdx); + virtual bool setProperty(int probIdx, double propVal); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int outputType); + + bool isOpened() const; + +protected: + struct OutputMap + { + public: + cv::Mat mat; + IplImage* getIplImagePtr(); + private: + IplImage iplHeader; + }; + + static const int outputMapsTypesCount = 7; + + static XnMapOutputMode defaultMapOutputMode(); + + IplImage* retrieveDepthMap(); + IplImage* retrievePointCloudMap(); + IplImage* retrieveDisparityMap(); + IplImage* retrieveDisparityMap_32F(); + IplImage* retrieveValidDepthMask(); + IplImage* retrieveBGRImage(); + IplImage* retrieveGrayImage(); + + bool readCamerasParams(); + + double getDepthGeneratorProperty(int propIdx); + bool setDepthGeneratorProperty(int propIdx, double propVal); + double getImageGeneratorProperty(int propIdx); + bool setImageGeneratorProperty(int propIdx, double propVal); + double getCommonProperty(int propIdx); + bool setCommonProperty(int propIdx, double propVal); + + // OpenNI context + xn::Context context; + bool isContextOpened; + + xn::ProductionNode productionNode; + + // Data generators with its metadata + xn::DepthGenerator depthGenerator; + xn::DepthMetaData depthMetaData; + + xn::ImageGenerator imageGenerator; + xn::ImageMetaData imageMetaData; + + int maxBufferSize, maxTimeDuration; // for approx sync + bool isCircleBuffer; + cv::Ptr approxSyncGrabber; + + // Cameras settings: + // TODO find in OpenNI function to convert z->disparity and remove fields "baseline" and depthFocalLength_VGA + // Distance between IR projector and IR camera (in meters) + XnDouble baseline; + // Focal length for the IR camera in VGA resolution (in pixels) + XnUInt64 depthFocalLength_VGA; + + // The value for shadow (occluded pixels) + XnUInt64 shadowValue; + // The value for pixels without a valid disparity measurement + XnUInt64 noSampleValue; + + std::vector outputMaps; +}; + +IplImage* CvCapture_OpenNI::OutputMap::getIplImagePtr() +{ + if( mat.empty() ) + return 0; + + iplHeader = IplImage(mat); + return &iplHeader; +} + +bool CvCapture_OpenNI::isOpened() const +{ + return isContextOpened; +} + +XnMapOutputMode CvCapture_OpenNI::defaultMapOutputMode() +{ + XnMapOutputMode mode; + mode.nXRes = XN_VGA_X_RES; + mode.nYRes = XN_VGA_Y_RES; + mode.nFPS = 30; + return mode; +} + +CvCapture_OpenNI::CvCapture_OpenNI( int index ) +{ + int deviceType = DEVICE_DEFAULT; + XnStatus status; + + isContextOpened = false; + maxBufferSize = DEFAULT_MAX_BUFFER_SIZE; + isCircleBuffer = DEFAULT_IS_CIRCLE_BUFFER; + maxTimeDuration = DEFAULT_MAX_TIME_DURATION; + + if( index >= 10 ) + { + deviceType = index / 10; + index %= 10; + } + + if( deviceType > DEVICE_MAX ) + return; + + // Initialize and configure the context. + status = context.Init(); + if( status != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed to initialize the context: " + << std::string(xnGetStatusString(status)) << std::endl; + return; + } + + // Find devices + xn::NodeInfoList devicesList; + status = context.EnumerateProductionTrees( XN_NODE_TYPE_DEVICE, NULL, devicesList, 0 ); + if( status != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed to enumerate production trees: " + << std::string(xnGetStatusString(status)) << std::endl; + return; + } + + // Chose device according to index + xn::NodeInfoList::Iterator it = devicesList.Begin(); + for( int i = 0; i < index && it!=devicesList.End(); ++i ) it++; + if ( it == devicesList.End() ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed device with index " << index << std::endl; + return; + } + + xn::NodeInfo deviceNode = *it; + status = context.CreateProductionTree( deviceNode, productionNode ); + if( status != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed to create production tree: " + << std::string(xnGetStatusString(status)) << std::endl; + return; + } + + xn::ScriptNode scriptNode; + status = context.RunXmlScript( XMLConfig.c_str(), scriptNode ); + if( status != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed to run xml script: " + << std::string(xnGetStatusString(status)) << std::endl; + return; + } + + // Associate generators with context. + // enumerate the nodes to find if depth generator is present + xn::NodeInfoList depthList; + status = context.EnumerateExistingNodes( depthList, XN_NODE_TYPE_DEPTH ); + if( status != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed to enumerate depth generators: " + << std::string(xnGetStatusString(status)) << std::endl; + return; + } + if( depthList.IsEmpty() ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : The device doesn't have depth generator. Such devices aren't supported now." << std::endl; + return; + } + status = depthGenerator.Create( context ); + if( status != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed to create depth generator: " + << std::string(xnGetStatusString(status)) << std::endl; + return; + } + + // enumerate the nodes to find if image generator is present + xn::NodeInfoList imageList; + status = context.EnumerateExistingNodes( imageList, XN_NODE_TYPE_IMAGE ); + if( status != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed to enumerate image generators: " + << std::string(xnGetStatusString(status)) << std::endl; + return; + } + + if( !imageList.IsEmpty() ) + { + status = imageGenerator.Create( context ); + if( status != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed to create image generator: " + << std::string(xnGetStatusString(status)) << std::endl; + return; + } + } + + // Set map output mode. + if( depthGenerator.IsValid() ) + { + CV_DbgAssert( depthGenerator.SetMapOutputMode(defaultMapOutputMode()) == XN_STATUS_OK ); // xn::DepthGenerator supports VGA only! (Jan 2011) + } + if( imageGenerator.IsValid() ) + { + CV_DbgAssert( imageGenerator.SetMapOutputMode(defaultMapOutputMode()) == XN_STATUS_OK ); + } + + if( deviceType == DEVICE_ASUS_XTION ) + { + //ps/asus specific + imageGenerator.SetIntProperty("InputFormat", 1 /*XN_IO_IMAGE_FORMAT_YUV422*/); + imageGenerator.SetPixelFormat(XN_PIXEL_FORMAT_RGB24); + depthGenerator.SetIntProperty("RegistrationType", 1 /*XN_PROCESSING_HARDWARE*/); + } + + // Start generating data. + status = context.StartGeneratingAll(); + if( status != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed to start generating OpenNI data: " + << std::string(xnGetStatusString(status)) << std::endl; + return; + } + + if( !readCamerasParams() ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Could not read cameras parameters" << std::endl; + return; + } + + outputMaps.resize( outputMapsTypesCount ); + + isContextOpened = true; + + setProperty(CV_CAP_PROP_OPENNI_REGISTRATION, 1.0); +} + +CvCapture_OpenNI::CvCapture_OpenNI(const char * filename) +{ + XnStatus status; + + isContextOpened = false; + maxBufferSize = DEFAULT_MAX_BUFFER_SIZE; + isCircleBuffer = DEFAULT_IS_CIRCLE_BUFFER; + maxTimeDuration = DEFAULT_MAX_TIME_DURATION; + + // Initialize and configure the context. + status = context.Init(); + if( status != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed to initialize the context: " + << std::string(xnGetStatusString(status)) << std::endl; + return; + } + + // Open file + status = context.OpenFileRecording( filename, productionNode ); + if( status != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed to open input file (" << filename << "): " + << std::string(xnGetStatusString(status)) << std::endl; + return; + } + + context.FindExistingNode( XN_NODE_TYPE_DEPTH, depthGenerator ); + context.FindExistingNode( XN_NODE_TYPE_IMAGE, imageGenerator ); + + if( !readCamerasParams() ) + { + std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Could not read cameras parameters" << std::endl; + return; + } + + outputMaps.resize( outputMapsTypesCount ); + + isContextOpened = true; +} + +CvCapture_OpenNI::~CvCapture_OpenNI() +{ + context.StopGeneratingAll(); + context.Release(); +} + +bool CvCapture_OpenNI::readCamerasParams() +{ + XnDouble pixelSize = 0; + if( depthGenerator.GetRealProperty( "ZPPS", pixelSize ) != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::readCamerasParams : Could not read pixel size!" << std::endl; + return false; + } + + // pixel size @ VGA = pixel size @ SXGA x 2 + pixelSize *= 2.0; // in mm + + // focal length of IR camera in pixels for VGA resolution + XnUInt64 zeroPlanDistance; // in mm + if( depthGenerator.GetIntProperty( "ZPD", zeroPlanDistance ) != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::readCamerasParams : Could not read virtual plane distance!" << std::endl; + return false; + } + + if( depthGenerator.GetRealProperty( "LDDIS", baseline ) != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::readCamerasParams : Could not read base line!" << std::endl; + return false; + } + + // baseline from cm -> mm + baseline *= 10; + + // focal length from mm -> pixels (valid for 640x480) + depthFocalLength_VGA = (XnUInt64)((double)zeroPlanDistance / (double)pixelSize); + + if( depthGenerator.GetIntProperty( "ShadowValue", shadowValue ) != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::readCamerasParams : Could not read property \"ShadowValue\"!" << std::endl; + return false; + } + + if( depthGenerator.GetIntProperty("NoSampleValue", noSampleValue ) != XN_STATUS_OK ) + { + std::cerr << "CvCapture_OpenNI::readCamerasParams : Could not read property \"NoSampleValue\"!" <isRun() ? 1. : 0.; + break; + case CV_CAP_PROP_OPENNI_MAX_BUFFER_SIZE : + propValue = maxBufferSize; + break; + case CV_CAP_PROP_OPENNI_CIRCLE_BUFFER : + propValue = isCircleBuffer ? 1. : 0.; + break; + case CV_CAP_PROP_OPENNI_MAX_TIME_DURATION : + propValue = maxTimeDuration; + break; + default : + { + std::stringstream ss; + ss << "Such parameter (propIdx=" << propIdx << ") isn't supported for getting.\n"; + CV_Error( CV_StsBadArg, ss.str().c_str() ); + } + } + + return propValue; +} + +bool CvCapture_OpenNI::setCommonProperty( int propIdx, double propValue ) +{ + bool isSet = false; + + switch( propIdx ) + { + // There is a set of properties that correspond to depth generator by default + // (is they are pass without particular generator flag). + case CV_CAP_PROP_OPENNI_REGISTRATION: + isSet = setDepthGeneratorProperty( propIdx, propValue ); + break; + case CV_CAP_PROP_OPENNI_APPROX_FRAME_SYNC : + if( propValue && depthGenerator.IsValid() && imageGenerator.IsValid() ) + { + // start synchronization + if( approxSyncGrabber.empty() ) + { + approxSyncGrabber = new ApproximateSyncGrabber( context, depthGenerator, imageGenerator, maxBufferSize, isCircleBuffer, maxTimeDuration ); + } + else + { + approxSyncGrabber->finish(); + + // update params + approxSyncGrabber->setMaxBufferSize(maxBufferSize); + approxSyncGrabber->setIsCircleBuffer(isCircleBuffer); + approxSyncGrabber->setMaxTimeDuration(maxTimeDuration); + } + approxSyncGrabber->start(); + } + else if( !propValue && !approxSyncGrabber.empty() ) + { + // finish synchronization + approxSyncGrabber->finish(); + } + break; + case CV_CAP_PROP_OPENNI_MAX_BUFFER_SIZE : + maxBufferSize = cvRound(propValue); + if( !approxSyncGrabber.empty() ) + approxSyncGrabber->setMaxBufferSize(maxBufferSize); + break; + case CV_CAP_PROP_OPENNI_CIRCLE_BUFFER : + if( !approxSyncGrabber.empty() ) + approxSyncGrabber->setIsCircleBuffer(isCircleBuffer); + break; + case CV_CAP_PROP_OPENNI_MAX_TIME_DURATION : + maxTimeDuration = cvRound(propValue); + if( !approxSyncGrabber.empty() ) + approxSyncGrabber->setMaxTimeDuration(maxTimeDuration); + break; + default: + { + std::stringstream ss; + ss << "Such parameter (propIdx=" << propIdx << ") isn't supported for setting.\n"; + CV_Error( CV_StsBadArg, ss.str().c_str() ); + } + } + + return isSet; +} + +double CvCapture_OpenNI::getDepthGeneratorProperty( int propIdx ) +{ + double propValue = 0; + if( !depthGenerator.IsValid() ) + return propValue; + + XnMapOutputMode mode; + + switch( propIdx ) + { + case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT : + CV_DbgAssert( depthGenerator.IsValid() ); + propValue = 1.; + break; + case CV_CAP_PROP_FRAME_WIDTH : + if( depthGenerator.GetMapOutputMode(mode) == XN_STATUS_OK ) + propValue = mode.nXRes; + break; + case CV_CAP_PROP_FRAME_HEIGHT : + if( depthGenerator.GetMapOutputMode(mode) == XN_STATUS_OK ) + propValue = mode.nYRes; + break; + case CV_CAP_PROP_FPS : + if( depthGenerator.GetMapOutputMode(mode) == XN_STATUS_OK ) + propValue = mode.nFPS; + break; + case CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH : + propValue = depthGenerator.GetDeviceMaxDepth(); + break; + case CV_CAP_PROP_OPENNI_BASELINE : + propValue = baseline; + break; + case CV_CAP_PROP_OPENNI_FOCAL_LENGTH : + propValue = (double)depthFocalLength_VGA; + break; + case CV_CAP_PROP_OPENNI_REGISTRATION : + propValue = depthGenerator.GetAlternativeViewPointCap().IsViewPointAs(imageGenerator) ? 1.0 : 0.0; + break; + default : + { + std::stringstream ss; + ss << "Depth generator does not support such parameter (propIdx=" << propIdx << ") for getting.\n"; + CV_Error( CV_StsBadArg, ss.str().c_str() ); + } + } + + return propValue; +} + +bool CvCapture_OpenNI::setDepthGeneratorProperty( int propIdx, double propValue ) +{ + bool isSet = false; + + CV_Assert( depthGenerator.IsValid() ); + + switch( propIdx ) + { + case CV_CAP_PROP_OPENNI_REGISTRATION: + { + if( propValue != 0.0 ) // "on" + { + // if there isn't image generator (i.e. ASUS XtionPro doesn't have it) + // then the property isn't avaliable + if( imageGenerator.IsValid() ) + { + if( !depthGenerator.GetAlternativeViewPointCap().IsViewPointAs(imageGenerator) ) + { + if( depthGenerator.GetAlternativeViewPointCap().IsViewPointSupported(imageGenerator) ) + { + XnStatus status = depthGenerator.GetAlternativeViewPointCap().SetViewPoint(imageGenerator); + if( status != XN_STATUS_OK ) + std::cerr << "CvCapture_OpenNI::setDepthGeneratorProperty : " << xnGetStatusString(status) << std::endl; + else + isSet = true; + } + else + std::cerr << "CvCapture_OpenNI::setDepthGeneratorProperty : Unsupported viewpoint." << std::endl; + } + else + isSet = true; + } + } + else // "off" + { + XnStatus status = depthGenerator.GetAlternativeViewPointCap().ResetViewPoint(); + if( status != XN_STATUS_OK ) + std::cerr << "CvCapture_OpenNI::setDepthGeneratorProperty : " << xnGetStatusString(status) << std::endl; + else + isSet = true; + } + } + break; + default: + { + std::stringstream ss; + ss << "Depth generator does not support such parameter (propIdx=" << propIdx << ") for setting.\n"; + CV_Error( CV_StsBadArg, ss.str().c_str() ); + } + } + + return isSet; +} + +double CvCapture_OpenNI::getImageGeneratorProperty( int propIdx ) +{ + double propValue = 0.; + if( !imageGenerator.IsValid() ) + return propValue; + + XnMapOutputMode mode; + switch( propIdx ) + { + case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT : + CV_DbgAssert( imageGenerator.IsValid() ); + propValue = 1.; + break; + case CV_CAP_PROP_FRAME_WIDTH : + if( imageGenerator.GetMapOutputMode(mode) == XN_STATUS_OK ) + propValue = mode.nXRes; + break; + case CV_CAP_PROP_FRAME_HEIGHT : + if( imageGenerator.GetMapOutputMode(mode) == XN_STATUS_OK ) + propValue = mode.nYRes; + break; + case CV_CAP_PROP_FPS : + if( imageGenerator.GetMapOutputMode(mode) == XN_STATUS_OK ) + propValue = mode.nFPS; + break; + default : + { + std::stringstream ss; + ss << "Image generator does not support such parameter (propIdx=" << propIdx << ") for getting.\n"; + CV_Error( CV_StsBadArg, ss.str().c_str() ); + } + } + + return propValue; +} + +bool CvCapture_OpenNI::setImageGeneratorProperty( int propIdx, double propValue ) +{ + bool isSet = false; + if( !imageGenerator.IsValid() ) + return isSet; + + switch( propIdx ) + { + case CV_CAP_PROP_OPENNI_OUTPUT_MODE : + { + XnMapOutputMode mode; + + switch( cvRound(propValue) ) + { + case CV_CAP_OPENNI_VGA_30HZ : + mode.nXRes = XN_VGA_X_RES; + mode.nYRes = XN_VGA_Y_RES; + mode.nFPS = 30; + break; + case CV_CAP_OPENNI_SXGA_15HZ : + mode.nXRes = XN_SXGA_X_RES; + mode.nYRes = XN_SXGA_Y_RES; + mode.nFPS = 15; + break; + case CV_CAP_OPENNI_SXGA_30HZ : + mode.nXRes = XN_SXGA_X_RES; + mode.nYRes = XN_SXGA_Y_RES; + mode.nFPS = 30; + break; + default : + CV_Error( CV_StsBadArg, "Unsupported image generator output mode.\n"); + } + + XnStatus status = imageGenerator.SetMapOutputMode( mode ); + if( status != XN_STATUS_OK ) + std::cerr << "CvCapture_OpenNI::setImageGeneratorProperty : " << xnGetStatusString(status) << std::endl; + else + isSet = true; + break; + } + default: + { + std::stringstream ss; + ss << "Image generator does not support such parameter (propIdx=" << propIdx << ") for setting.\n"; + CV_Error( CV_StsBadArg, ss.str().c_str() ); + } + } + + return isSet; +} + +bool CvCapture_OpenNI::grabFrame() +{ + if( !isOpened() ) + return false; + + bool isGrabbed = false; + if( !approxSyncGrabber.empty() && approxSyncGrabber->isRun() ) + { + isGrabbed = approxSyncGrabber->grab( depthMetaData, imageMetaData ); + } + else + { + XnStatus status = context.WaitAndUpdateAll(); + if( status != XN_STATUS_OK ) + return false; + + if( depthGenerator.IsValid() ) + depthGenerator.GetMetaData( depthMetaData ); + if( imageGenerator.IsValid() ) + imageGenerator.GetMetaData( imageMetaData ); + isGrabbed = true; + } + + return isGrabbed; +} + +inline void getDepthMapFromMetaData( const xn::DepthMetaData& depthMetaData, cv::Mat& depthMap, XnUInt64 noSampleValue, XnUInt64 shadowValue ) +{ + int cols = depthMetaData.XRes(); + int rows = depthMetaData.YRes(); + + depthMap.create( rows, cols, CV_16UC1 ); + + const XnDepthPixel* pDepthMap = depthMetaData.Data(); + + // CV_Assert( sizeof(unsigned short) == sizeof(XnDepthPixel) ); + memcpy( depthMap.data, pDepthMap, cols*rows*sizeof(XnDepthPixel) ); + + cv::Mat badMask = (depthMap == (double)noSampleValue) | (depthMap == (double)shadowValue) | (depthMap == 0); + + // mask the pixels with invalid depth + depthMap.setTo( cv::Scalar::all( CvCapture_OpenNI::INVALID_PIXEL_VAL ), badMask ); +} + +IplImage* CvCapture_OpenNI::retrieveDepthMap() +{ + if( !depthMetaData.Data() ) + return 0; + + getDepthMapFromMetaData( depthMetaData, outputMaps[CV_CAP_OPENNI_DEPTH_MAP].mat, noSampleValue, shadowValue ); + + return outputMaps[CV_CAP_OPENNI_DEPTH_MAP].getIplImagePtr(); +} + +IplImage* CvCapture_OpenNI::retrievePointCloudMap() +{ + if( !depthMetaData.Data() ) + return 0; + + cv::Mat depth; + getDepthMapFromMetaData( depthMetaData, depth, noSampleValue, shadowValue ); + + const int badPoint = INVALID_PIXEL_VAL; + const float badCoord = INVALID_COORDINATE_VAL; + int cols = depthMetaData.XRes(), rows = depthMetaData.YRes(); + cv::Mat pointCloud_XYZ( rows, cols, CV_32FC3, cv::Scalar::all(badPoint) ); + + cv::Ptr proj = new XnPoint3D[cols*rows]; + cv::Ptr real = new XnPoint3D[cols*rows]; + for( int y = 0; y < rows; y++ ) + { + for( int x = 0; x < cols; x++ ) + { + int ind = y*cols+x; + proj[ind].X = (float)x; + proj[ind].Y = (float)y; + proj[ind].Z = depth.at(y, x); + } + } + depthGenerator.ConvertProjectiveToRealWorld(cols*rows, proj, real); + + for( int y = 0; y < rows; y++ ) + { + for( int x = 0; x < cols; x++ ) + { + // Check for invalid measurements + if( depth.at(y, x) == badPoint ) // not valid + pointCloud_XYZ.at(y,x) = cv::Point3f( badCoord, badCoord, badCoord ); + else + { + int ind = y*cols+x; + pointCloud_XYZ.at(y,x) = cv::Point3f( real[ind].X*0.001f, real[ind].Y*0.001f, real[ind].Z*0.001f); // from mm to meters + } + } + } + + outputMaps[CV_CAP_OPENNI_POINT_CLOUD_MAP].mat = pointCloud_XYZ; + + return outputMaps[CV_CAP_OPENNI_POINT_CLOUD_MAP].getIplImagePtr(); +} + +static void computeDisparity_32F( const xn::DepthMetaData& depthMetaData, cv::Mat& disp, XnDouble baseline, XnUInt64 F, + XnUInt64 noSampleValue, XnUInt64 shadowValue ) +{ + cv::Mat depth; + getDepthMapFromMetaData( depthMetaData, depth, noSampleValue, shadowValue ); + CV_Assert( depth.type() == CV_16UC1 ); + + + // disparity = baseline * F / z; + + float mult = (float)(baseline /*mm*/ * F /*pixels*/); + + disp.create( depth.size(), CV_32FC1); + disp = cv::Scalar::all( CvCapture_OpenNI::INVALID_PIXEL_VAL ); + for( int y = 0; y < disp.rows; y++ ) + { + for( int x = 0; x < disp.cols; x++ ) + { + unsigned short curDepth = depth.at(y,x); + if( curDepth != CvCapture_OpenNI::INVALID_PIXEL_VAL ) + disp.at(y,x) = mult / curDepth; + } + } +} + +IplImage* CvCapture_OpenNI::retrieveDisparityMap() +{ + if( !depthMetaData.Data() ) + return 0; + + cv::Mat disp32; + computeDisparity_32F( depthMetaData, disp32, baseline, depthFocalLength_VGA, noSampleValue, shadowValue ); + + disp32.convertTo( outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].mat, CV_8UC1 ); + + return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].getIplImagePtr(); +} + +IplImage* CvCapture_OpenNI::retrieveDisparityMap_32F() +{ + if( !depthMetaData.Data() ) + return 0; + + computeDisparity_32F( depthMetaData, outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].mat, baseline, depthFocalLength_VGA, noSampleValue, shadowValue ); + + return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].getIplImagePtr(); +} + +IplImage* CvCapture_OpenNI::retrieveValidDepthMask() +{ + if( !depthMetaData.Data() ) + return 0; + + cv::Mat depth; + getDepthMapFromMetaData( depthMetaData, depth, noSampleValue, shadowValue ); + + outputMaps[CV_CAP_OPENNI_VALID_DEPTH_MASK].mat = depth != CvCapture_OpenNI::INVALID_PIXEL_VAL; + + return outputMaps[CV_CAP_OPENNI_VALID_DEPTH_MASK].getIplImagePtr(); +} + +inline void getBGRImageFromMetaData( const xn::ImageMetaData& imageMetaData, cv::Mat& bgrImage ) +{ + if( imageMetaData.PixelFormat() != XN_PIXEL_FORMAT_RGB24 ) + CV_Error( CV_StsUnsupportedFormat, "Unsupported format of grabbed image\n" ); + + cv::Mat rgbImage( imageMetaData.YRes(), imageMetaData.XRes(), CV_8UC3 ); + const XnRGB24Pixel* pRgbImage = imageMetaData.RGB24Data(); + + // CV_Assert( 3*sizeof(uchar) == sizeof(XnRGB24Pixel) ); + memcpy( rgbImage.data, pRgbImage, rgbImage.total()*sizeof(XnRGB24Pixel) ); + cv::cvtColor( rgbImage, bgrImage, CV_RGB2BGR ); +} + +IplImage* CvCapture_OpenNI::retrieveBGRImage() +{ + if( !imageMetaData.Data() ) + return 0; + + getBGRImageFromMetaData( imageMetaData, outputMaps[CV_CAP_OPENNI_BGR_IMAGE].mat ); + + return outputMaps[CV_CAP_OPENNI_BGR_IMAGE].getIplImagePtr(); +} + +IplImage* CvCapture_OpenNI::retrieveGrayImage() +{ + if( !imageMetaData.Data() ) + return 0; + + CV_Assert( imageMetaData.BytesPerPixel() == 3 ); // RGB + + cv::Mat rgbImage; + getBGRImageFromMetaData( imageMetaData, rgbImage ); + cv::cvtColor( rgbImage, outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].mat, CV_BGR2GRAY ); + + return outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].getIplImagePtr(); +} + +IplImage* CvCapture_OpenNI::retrieveFrame( int outputType ) +{ + IplImage* image = 0; + CV_Assert( outputType < outputMapsTypesCount && outputType >= 0); + + if( outputType == CV_CAP_OPENNI_DEPTH_MAP ) + { + image = retrieveDepthMap(); + } + else if( outputType == CV_CAP_OPENNI_POINT_CLOUD_MAP ) + { + image = retrievePointCloudMap(); + } + else if( outputType == CV_CAP_OPENNI_DISPARITY_MAP ) + { + image = retrieveDisparityMap(); + } + else if( outputType == CV_CAP_OPENNI_DISPARITY_MAP_32F ) + { + image = retrieveDisparityMap_32F(); + } + else if( outputType == CV_CAP_OPENNI_VALID_DEPTH_MASK ) + { + image = retrieveValidDepthMask(); + } + else if( outputType == CV_CAP_OPENNI_BGR_IMAGE ) + { + image = retrieveBGRImage(); + } + else if( outputType == CV_CAP_OPENNI_GRAY_IMAGE ) + { + image = retrieveGrayImage(); + } + + return image; +} + + +CvCapture* cvCreateCameraCapture_OpenNI( int index ) +{ + CvCapture_OpenNI* capture = new CvCapture_OpenNI( index ); + + if( capture->isOpened() ) + return capture; + + delete capture; + return 0; +} + +CvCapture* cvCreateFileCapture_OpenNI( const char* filename ) +{ + CvCapture_OpenNI* capture = new CvCapture_OpenNI( filename ); + + if( capture->isOpened() ) + return capture; + + delete capture; + return 0; +} + +#endif diff --git a/highgui/src/cap_pvapi.cpp b/highgui/src/cap_pvapi.cpp new file mode 100644 index 0000000..fe94d8c --- /dev/null +++ b/highgui/src/cap_pvapi.cpp @@ -0,0 +1,377 @@ +//////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +// + +// +// The code has been contributed by Justin G. Eskesen on 2010 Jan +// + +#include "precomp.hpp" + +#ifdef HAVE_PVAPI +#if !defined WIN32 && !defined _WIN32 && !defined _LINUX +#define _LINUX +#endif + +#if defined(_x64) || defined (__x86_64) || defined (_M_X64) +#define _x64 1 +#elif defined(_x86) || defined(__i386) || defined (_M_IX86) +#define _x86 1 +#endif + +#include +#ifdef WIN32 +# include +#else +# include +#endif + +#include +//#include + +#define MAX_CAMERAS 10 + +/********************* Capturing video from camera via PvAPI *********************/ + +class CvCaptureCAM_PvAPI : public CvCapture +{ +public: + CvCaptureCAM_PvAPI(); + virtual ~CvCaptureCAM_PvAPI() + { + close(); + } + + virtual bool open( int index ); + virtual void close(); + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual int getCaptureDomain() + { + return CV_CAP_PVAPI; + } + +protected: +#ifndef WIN32 + virtual void Sleep(unsigned int time); +#endif + + typedef struct + { + unsigned long UID; + tPvHandle Handle; + tPvFrame Frame; + } tCamera; + + IplImage *frame; + IplImage *grayframe; + tCamera Camera; + tPvErr Errcode; + bool monocrome; +}; + + +CvCaptureCAM_PvAPI::CvCaptureCAM_PvAPI() +{ + monocrome=false; + memset(&this->Camera, 0, sizeof(this->Camera)); +} + +#ifndef WIN32 +void CvCaptureCAM_PvAPI::Sleep(unsigned int time) +{ + struct timespec t,r; + + t.tv_sec = time / 1000; + t.tv_nsec = (time % 1000) * 1000000; + + while(nanosleep(&t,&r)==-1) + t = r; +} +#endif + +void CvCaptureCAM_PvAPI::close() +{ + // Stop the acquisition & free the camera + PvCommandRun(Camera.Handle, "AcquisitionStop"); + PvCaptureEnd(Camera.Handle); + PvCameraClose(Camera.Handle); + PvUnInitialize(); +} + +// Initialize camera input +bool CvCaptureCAM_PvAPI::open( int index ) +{ + tPvCameraInfo cameraList[MAX_CAMERAS]; + + tPvCameraInfo camInfo; + tPvIpSettings ipSettings; + + + if (PvInitialize()) { + } + //return false; + + Sleep(1000); + + //close(); + + int numCameras=PvCameraList(cameraList, MAX_CAMERAS, NULL); + + if (numCameras <= 0 || index >= numCameras) + return false; + + Camera.UID = cameraList[index].UniqueId; + + if (!PvCameraInfo(Camera.UID,&camInfo) && !PvCameraIpSettingsGet(Camera.UID,&ipSettings)) { + /* + struct in_addr addr; + addr.s_addr = ipSettings.CurrentIpAddress; + printf("Current address:\t%s\n",inet_ntoa(addr)); + addr.s_addr = ipSettings.CurrentIpSubnet; + printf("Current subnet:\t\t%s\n",inet_ntoa(addr)); + addr.s_addr = ipSettings.CurrentIpGateway; + printf("Current gateway:\t%s\n",inet_ntoa(addr)); + */ + } + else { + fprintf(stderr,"ERROR: could not retrieve camera IP settings.\n"); + return false; + } + + + if (PvCameraOpen(Camera.UID, ePvAccessMaster, &(Camera.Handle))==ePvErrSuccess) + { + + //Set Pixel Format to BRG24 to follow conventions + /*Errcode = PvAttrEnumSet(Camera.Handle, "PixelFormat", "Bgr24"); + if (Errcode != ePvErrSuccess) + { + fprintf(stderr, "PvAPI: couldn't set PixelFormat to Bgr24\n"); + return NULL; + } + */ + tPvUint32 frameWidth, frameHeight, frameSize; + unsigned long maxSize; + char pixelFormat[256]; + PvAttrUint32Get(Camera.Handle, "TotalBytesPerFrame", &frameSize); + PvAttrUint32Get(Camera.Handle, "Width", &frameWidth); + PvAttrUint32Get(Camera.Handle, "Height", &frameHeight); + PvAttrEnumGet(Camera.Handle, "PixelFormat", pixelFormat,256,NULL); + maxSize = 8228; + //PvAttrUint32Get(Camera.Handle,"PacketSize",&maxSize); + if (PvCaptureAdjustPacketSize(Camera.Handle,maxSize)!=ePvErrSuccess) + return false; + if (strcmp(pixelFormat, "Mono8")==0) { + grayframe = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_8U, 1); + grayframe->widthStep = (int)frameWidth; + frame = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_8U, 3); + frame->widthStep = (int)frameWidth*3; + Camera.Frame.ImageBufferSize = frameSize; + Camera.Frame.ImageBuffer = grayframe->imageData; + } + else if (strcmp(pixelFormat, "Mono16")==0) { + grayframe = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_16U, 1); + grayframe->widthStep = (int)frameWidth; + frame = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_16U, 3); + frame->widthStep = (int)frameWidth*3; + Camera.Frame.ImageBufferSize = frameSize; + Camera.Frame.ImageBuffer = grayframe->imageData; + } + else if (strcmp(pixelFormat, "Bgr24")==0) { + frame = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_8U, 3); + frame->widthStep = (int)frameWidth*3; + Camera.Frame.ImageBufferSize = frameSize; + Camera.Frame.ImageBuffer = frame->imageData; + } + else + return false; + // Start the camera + PvCaptureStart(Camera.Handle); + + // Set the camera to capture continuously + if(PvAttrEnumSet(Camera.Handle, "AcquisitionMode", "Continuous")!= ePvErrSuccess) + { + fprintf(stderr,"Could not set Prosilica Acquisition Mode\n"); + return false; + } + + if(PvCommandRun(Camera.Handle, "AcquisitionStart")!= ePvErrSuccess) + { + fprintf(stderr,"Could not start Prosilica acquisition\n"); + return false; + } + + if(PvAttrEnumSet(Camera.Handle, "FrameStartTriggerMode", "Freerun")!= ePvErrSuccess) + { + fprintf(stderr,"Error setting Prosilica trigger to \"Freerun\""); + return false; + } + + return true; + } + fprintf(stderr,"Error cannot open camera\n"); + return false; + +} + +bool CvCaptureCAM_PvAPI::grabFrame() +{ + //if(Camera.Frame.Status != ePvErrUnplugged && Camera.Frame.Status != ePvErrCancelled) + return PvCaptureQueueFrame(Camera.Handle, &(Camera.Frame), NULL) == ePvErrSuccess; +} + + +IplImage* CvCaptureCAM_PvAPI::retrieveFrame(int) +{ + + if (PvCaptureWaitForFrameDone(Camera.Handle, &(Camera.Frame), 1000) == ePvErrSuccess) { + if (!monocrome) { + cvMerge(grayframe,grayframe,grayframe,NULL,frame); + return frame; + } + return grayframe; + } + else return NULL; +} + +double CvCaptureCAM_PvAPI::getProperty( int property_id ) +{ + tPvUint32 nTemp; + + switch ( property_id ) + { + case CV_CAP_PROP_FRAME_WIDTH: + PvAttrUint32Get(Camera.Handle, "Width", &nTemp); + return (double)nTemp; + case CV_CAP_PROP_FRAME_HEIGHT: + PvAttrUint32Get(Camera.Handle, "Height", &nTemp); + return (double)nTemp; + case CV_CAP_PROP_EXPOSURE: + PvAttrUint32Get(Camera.Handle,"ExposureValue",&nTemp); + return (double)nTemp; + case CV_CAP_PROP_FPS: + tPvFloat32 nfTemp; + PvAttrFloat32Get(Camera.Handle, "StatFrameRate", &nfTemp); + return (double)nfTemp; + case CV_CAP_PROP_PVAPI_MULTICASTIP: + char mEnable[2]; + char mIp[11]; + PvAttrEnumGet(Camera.Handle,"MulticastEnable",mEnable,sizeof(mEnable),NULL); + if (strcmp(mEnable, "Off") == 0) { + return -1; + } + else { + long int ip; + int a,b,c,d; + PvAttrStringGet(Camera.Handle, "MulticastIPAddress",mIp,sizeof(mIp),NULL); + sscanf(mIp, "%d.%d.%d.%d", &a, &b, &c, &d); ip = ((a*256 + b)*256 + c)*256 + d; + return (double)ip; + } + } + return -1.0; +} + +bool CvCaptureCAM_PvAPI::setProperty( int property_id, double value ) +{ + switch ( property_id ) + { + /* TODO: Camera works, but IplImage must be modified for the new size + case CV_CAP_PROP_FRAME_WIDTH: + PvAttrUint32Set(Camera.Handle, "Width", (tPvUint32)value); + break; + case CV_CAP_PROP_FRAME_HEIGHT: + PvAttrUint32Set(Camera.Handle, "Heigth", (tPvUint32)value); + break; + */ + case CV_CAP_PROP_MONOCROME: + if (value==1) { + char pixelFormat[256]; + PvAttrEnumGet(Camera.Handle, "PixelFormat", pixelFormat,256,NULL); + if ((strcmp(pixelFormat, "Mono8")==0) || strcmp(pixelFormat, "Mono16")==0) { + monocrome=true; + } + else + return false; + } + else + monocrome=false; + break; + case CV_CAP_PROP_EXPOSURE: + if ((PvAttrUint32Set(Camera.Handle,"ExposureValue",(tPvUint32)value)==ePvErrSuccess)) + break; + else + return false; + case CV_CAP_PROP_PVAPI_MULTICASTIP: + + if (value==-1) { + if ((PvAttrEnumSet(Camera.Handle,"MulticastEnable", "Off")==ePvErrSuccess)) + break; + else + return false; + } + else { + std::string ip=cv::format("%d.%d.%d.%d", ((int)value>>24)&255, ((int)value>>16)&255, ((int)value>>8)&255, (int)value&255); + if ((PvAttrEnumSet(Camera.Handle,"MulticastEnable", "On")==ePvErrSuccess) && + (PvAttrStringSet(Camera.Handle, "MulticastIPAddress", ip.c_str())==ePvErrSuccess)) + break; + else + return false; + } + default: + return false; + } + return true; +} + + +CvCapture* cvCreateCameraCapture_PvAPI( int index ) +{ + CvCaptureCAM_PvAPI* capture = new CvCaptureCAM_PvAPI; + + if ( capture->open( index )) + return capture; + + delete capture; + return NULL; +} +#endif diff --git a/highgui/src/cap_qt.cpp b/highgui/src/cap_qt.cpp new file mode 100644 index 0000000..a474fed --- /dev/null +++ b/highgui/src/cap_qt.cpp @@ -0,0 +1,1619 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + + +#include "precomp.hpp" + +// Original implementation by Mark Asbach +// Institute of Communications Engineering +// RWTH Aachen University +// +// For implementation details and background see: +// http://developer.apple.com/samplecode/qtframestepper.win/listing1.html +// +// Please note that timing will only be correct for videos that contain a visual track +// that has full length (compared to other tracks) + + +// standard includes +#include +#include + +// Mac OS includes +#include +#include +#include + + +// Global state (did we call EnterMovies?) +static int did_enter_movies = 0; + +// ---------------------------------------------------------------------------------------- +#pragma mark Reading Video Files + +/// Movie state structure for QuickTime movies +typedef struct CvCapture_QT_Movie +{ + Movie myMovie; // movie handle + GWorldPtr myGWorld; // we render into an offscreen GWorld + + CvSize size; // dimensions of the movie + TimeValue movie_start_time; // movies can start at arbitrary times + long number_of_frames; // duration in frames + long next_frame_time; + long next_frame_number; + + IplImage * image_rgb; // will point to the PixMap of myGWorld + IplImage * image_bgr; // will be returned by icvRetrieveFrame_QT() + +} CvCapture_QT_Movie; + + +static int icvOpenFile_QT_Movie (CvCapture_QT_Movie * capture, const char * filename); +static int icvClose_QT_Movie (CvCapture_QT_Movie * capture); +static double icvGetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id); +static int icvSetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id, double value); +static int icvGrabFrame_QT_Movie (CvCapture_QT_Movie * capture); +static const void * icvRetrieveFrame_QT_Movie (CvCapture_QT_Movie * capture, int); + + +static CvCapture_QT_Movie * icvCaptureFromFile_QT (const char * filename) +{ + static int did_enter_movies = 0; + if (! did_enter_movies) + { + EnterMovies(); + did_enter_movies = 1; + } + + CvCapture_QT_Movie * capture = 0; + + if (filename) + { + capture = (CvCapture_QT_Movie *) cvAlloc (sizeof (*capture)); + memset (capture, 0, sizeof(*capture)); + + if (!icvOpenFile_QT_Movie (capture, filename)) + cvFree( &capture ); + } + + return capture; +} + + + +/** + * convert full path to CFStringRef and open corresponding Movie. Then + * step over 'interesting frame times' to count total number of frames + * for video material with varying frame durations and create offscreen + * GWorld for rendering the movie frames. + * + * @author Mark Asbach + * @date 2005-11-04 + */ +static int icvOpenFile_QT_Movie (CvCapture_QT_Movie * capture, const char * filename) +{ + Rect myRect; + short myResID = 0; + Handle myDataRef = nil; + OSType myDataRefType = 0; + OSErr myErr = noErr; + + + // no old errors please + ClearMoviesStickyError (); + + // initialize pointers to zero + capture->myMovie = 0; + capture->myGWorld = nil; + + // initialize numbers with invalid values + capture->next_frame_time = -1; + capture->next_frame_number = -1; + capture->number_of_frames = -1; + capture->movie_start_time = -1; + capture->size = cvSize (-1,-1); + + + // we would use CFStringCreateWithFileSystemRepresentation (kCFAllocatorDefault, filename) on Mac OS X 10.4 + CFStringRef inPath = CFStringCreateWithCString (kCFAllocatorDefault, filename, kCFStringEncodingISOLatin1); + OPENCV_ASSERT ((inPath != nil), "icvOpenFile_QT_Movie", "couldnt create CFString from a string"); + + // create the data reference + myErr = QTNewDataReferenceFromFullPathCFString (inPath, kQTPOSIXPathStyle, 0, & myDataRef, & myDataRefType); + if (myErr != noErr) + { + fprintf (stderr, "Couldn't create QTNewDataReferenceFromFullPathCFString().\n"); + return 0; + } + + // get the Movie + myErr = NewMovieFromDataRef(& capture->myMovie, newMovieActive | newMovieAsyncOK /* | newMovieIdleImportOK */, + & myResID, myDataRef, myDataRefType); + + // dispose of the data reference handle - we no longer need it + DisposeHandle (myDataRef); + + // if NewMovieFromDataRef failed, we already disposed the DataRef, so just return with an error + if (myErr != noErr) + { + fprintf (stderr, "Couldn't create a NewMovieFromDataRef() - error is %d.\n", myErr); + return 0; + } + + // count the number of video 'frames' in the movie by stepping through all of the + // video 'interesting times', or in other words, the places where the movie displays + // a new video sample. The time between these interesting times is not necessarily constant. + { + OSType whichMediaType = VisualMediaCharacteristic; + TimeValue theTime = -1; + + // find out movie start time + GetMovieNextInterestingTime (capture->myMovie, short (nextTimeMediaSample + nextTimeEdgeOK), + 1, & whichMediaType, TimeValue (0), 0, & theTime, NULL); + if (theTime == -1) + { + fprintf (stderr, "Couldn't inquire first frame time\n"); + return 0; + } + capture->movie_start_time = theTime; + capture->next_frame_time = theTime; + capture->next_frame_number = 0; + + // count all 'interesting times' of the movie + capture->number_of_frames = 0; + while (theTime >= 0) + { + GetMovieNextInterestingTime (capture->myMovie, short (nextTimeMediaSample), + 1, & whichMediaType, theTime, 0, & theTime, NULL); + capture->number_of_frames++; + } + } + + // get the bounding rectangle of the movie + GetMoviesError (); + GetMovieBox (capture->myMovie, & myRect); + capture->size = cvSize (myRect.right - myRect.left, myRect.bottom - myRect.top); + + // create gworld for decompressed image + myErr = QTNewGWorld (& capture->myGWorld, k32ARGBPixelFormat /* k24BGRPixelFormat geht leider nicht */, + & myRect, nil, nil, 0); + OPENCV_ASSERT (myErr == noErr, "icvOpenFile_QT_Movie", "couldnt create QTNewGWorld() for output image"); + SetMovieGWorld (capture->myMovie, capture->myGWorld, nil); + + // build IplImage header that will point to the PixMap of the Movie's GWorld later on + capture->image_rgb = cvCreateImageHeader (capture->size, IPL_DEPTH_8U, 4); + + // create IplImage that hold correctly formatted result + capture->image_bgr = cvCreateImage (capture->size, IPL_DEPTH_8U, 3); + + // okay, that's it - should we wait until the Movie is playable? + return 1; +} + +/** + * dispose of QuickTime Movie and free memory buffers + * + * @author Mark Asbach + * @date 2005-11-04 + */ +static int icvClose_QT_Movie (CvCapture_QT_Movie * capture) +{ + OPENCV_ASSERT (capture, "icvClose_QT_Movie", "'capture' is a NULL-pointer"); + + // deallocate and free resources + if (capture->myMovie) + { + cvReleaseImage (& capture->image_bgr); + cvReleaseImageHeader (& capture->image_rgb); + DisposeGWorld (capture->myGWorld); + DisposeMovie (capture->myMovie); + } + + // okay, that's it + return 1; +} + +/** + * get a capture property + * + * @author Mark Asbach + * @date 2005-11-05 + */ +static double icvGetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id) +{ + OPENCV_ASSERT (capture, "icvGetProperty_QT_Movie", "'capture' is a NULL-pointer"); + OPENCV_ASSERT (capture->myMovie, "icvGetProperty_QT_Movie", "invalid Movie handle"); + OPENCV_ASSERT (capture->number_of_frames > 0, "icvGetProperty_QT_Movie", "movie has invalid number of frames"); + OPENCV_ASSERT (capture->movie_start_time >= 0, "icvGetProperty_QT_Movie", "movie has invalid start time"); + + // inquire desired property + switch (property_id) + { + case CV_CAP_PROP_POS_FRAMES: + return (capture->next_frame_number); + + case CV_CAP_PROP_POS_MSEC: + case CV_CAP_PROP_POS_AVI_RATIO: + { + TimeValue position = capture->next_frame_time - capture->movie_start_time; + + if (property_id == CV_CAP_PROP_POS_MSEC) + { + TimeScale timescale = GetMovieTimeScale (capture->myMovie); + return (static_cast (position) * 1000.0 / timescale); + } + else + { + TimeValue duration = GetMovieDuration (capture->myMovie); + return (static_cast (position) / duration); + } + } + break; // never reached + + case CV_CAP_PROP_FRAME_WIDTH: + return static_cast (capture->size.width); + + case CV_CAP_PROP_FRAME_HEIGHT: + return static_cast (capture->size.height); + + case CV_CAP_PROP_FPS: + { + TimeValue duration = GetMovieDuration (capture->myMovie); + TimeScale timescale = GetMovieTimeScale (capture->myMovie); + + return (capture->number_of_frames / (static_cast (duration) / timescale)); + } + + case CV_CAP_PROP_FRAME_COUNT: + return static_cast (capture->number_of_frames); + + case CV_CAP_PROP_FOURCC: // not implemented + case CV_CAP_PROP_FORMAT: // not implemented + case CV_CAP_PROP_MODE: // not implemented + default: + // unhandled or unknown capture property + OPENCV_ERROR (CV_StsBadArg, "icvSetProperty_QT_Movie", "unknown or unhandled property_id"); + return CV_StsBadArg; + } + + return 0; +} + +/** + * set a capture property. With movie files, it is only possible to set the + * position (i.e. jump to a given time or frame number) + * + * @author Mark Asbach + * @date 2005-11-05 + */ +static int icvSetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id, double value) +{ + OPENCV_ASSERT (capture, "icvSetProperty_QT_Movie", "'capture' is a NULL-pointer"); + OPENCV_ASSERT (capture->myMovie, "icvSetProperty_QT_Movie", "invalid Movie handle"); + OPENCV_ASSERT (capture->number_of_frames > 0, "icvSetProperty_QT_Movie", "movie has invalid number of frames"); + OPENCV_ASSERT (capture->movie_start_time >= 0, "icvSetProperty_QT_Movie", "movie has invalid start time"); + + // inquire desired property + // + // rework these three points to really work through 'interesting times'. + // with the current implementation, they result in wrong times or wrong frame numbers with content that + // features varying frame durations + switch (property_id) + { + case CV_CAP_PROP_POS_MSEC: + case CV_CAP_PROP_POS_AVI_RATIO: + { + TimeValue destination; + OSType myType = VisualMediaCharacteristic; + OSErr myErr = noErr; + + if (property_id == CV_CAP_PROP_POS_MSEC) + { + TimeScale timescale = GetMovieTimeScale (capture->myMovie); + destination = static_cast (value / 1000.0 * timescale + capture->movie_start_time); + } + else + { + TimeValue duration = GetMovieDuration (capture->myMovie); + destination = static_cast (value * duration + capture->movie_start_time); + } + + // really seek? + if (capture->next_frame_time == destination) + break; + + // seek into which direction? + if (capture->next_frame_time < destination) + { + while (capture->next_frame_time < destination) + { + capture->next_frame_number++; + GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, capture->next_frame_time, + 1, & capture->next_frame_time, NULL); + myErr = GetMoviesError(); + if (myErr != noErr) + { + fprintf (stderr, "Couldn't go on to GetMovieNextInterestingTime() in icvGrabFrame_QT.\n"); + return 0; + } + } + } + else + { + while (capture->next_frame_time > destination) + { + capture->next_frame_number--; + GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, capture->next_frame_time, + -1, & capture->next_frame_time, NULL); + myErr = GetMoviesError(); + if (myErr != noErr) + { + fprintf (stderr, "Couldn't go back to GetMovieNextInterestingTime() in icvGrabFrame_QT.\n"); + return 0; + } + } + } + } + break; + + case CV_CAP_PROP_POS_FRAMES: + { + TimeValue destination = static_cast (value); + short direction = (destination > capture->next_frame_number) ? 1 : -1; + OSType myType = VisualMediaCharacteristic; + OSErr myErr = noErr; + + while (destination != capture->next_frame_number) + { + capture->next_frame_number += direction; + GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, capture->next_frame_time, + direction, & capture->next_frame_time, NULL); + myErr = GetMoviesError(); + if (myErr != noErr) + { + fprintf (stderr, "Couldn't step to desired frame number in icvGrabFrame_QT.\n"); + return 0; + } + } + } + break; + + default: + // unhandled or unknown capture property + OPENCV_ERROR (CV_StsBadArg, "icvSetProperty_QT_Movie", "unknown or unhandled property_id"); + return 0; + } + + // positive result means success + return 1; +} + +/** + * the original meaning of this method is to acquire raw frame data for the next video + * frame but not decompress it. With the QuickTime video reader, this is reduced to + * advance to the current frame time. + * + * @author Mark Asbach + * @date 2005-11-06 + */ +static int icvGrabFrame_QT_Movie (CvCapture_QT_Movie * capture) +{ + OPENCV_ASSERT (capture, "icvGrabFrame_QT_Movie", "'capture' is a NULL-pointer"); + OPENCV_ASSERT (capture->myMovie, "icvGrabFrame_QT_Movie", "invalid Movie handle"); + + TimeValue myCurrTime; + OSType myType = VisualMediaCharacteristic; + OSErr myErr = noErr; + + + // jump to current video sample + SetMovieTimeValue (capture->myMovie, capture->next_frame_time); + myErr = GetMoviesError(); + if (myErr != noErr) + { + fprintf (stderr, "Couldn't SetMovieTimeValue() in icvGrabFrame_QT_Movie.\n"); + return 0; + } + + // where are we now? + myCurrTime = GetMovieTime (capture->myMovie, NULL); + + // increment counters + capture->next_frame_number++; + GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, myCurrTime, 1, & capture->next_frame_time, NULL); + myErr = GetMoviesError(); + if (myErr != noErr) + { + fprintf (stderr, "Couldn't GetMovieNextInterestingTime() in icvGrabFrame_QT_Movie.\n"); + return 0; + } + + // that's it + return 1; +} + +/** + * render the current frame into an image buffer and convert to OpenCV IplImage + * buffer layout (BGR sampling) + * + * @author Mark Asbach + * @date 2005-11-06 + */ +static const void * icvRetrieveFrame_QT_Movie (CvCapture_QT_Movie * capture, int) +{ + OPENCV_ASSERT (capture, "icvRetrieveFrame_QT_Movie", "'capture' is a NULL-pointer"); + OPENCV_ASSERT (capture->myMovie, "icvRetrieveFrame_QT_Movie", "invalid Movie handle"); + OPENCV_ASSERT (capture->image_rgb, "icvRetrieveFrame_QT_Movie", "invalid source image"); + OPENCV_ASSERT (capture->image_bgr, "icvRetrieveFrame_QT_Movie", "invalid destination image"); + + PixMapHandle myPixMapHandle = nil; + OSErr myErr = noErr; + + + // invalidates the movie's display state so that the Movie Toolbox + // redraws the movie the next time we call MoviesTask + UpdateMovie (capture->myMovie); + myErr = GetMoviesError (); + if (myErr != noErr) + { + fprintf (stderr, "Couldn't UpdateMovie() in icvRetrieveFrame_QT_Movie().\n"); + return 0; + } + + // service active movie (= redraw immediately) + MoviesTask (capture->myMovie, 0L); + myErr = GetMoviesError (); + if (myErr != noErr) + { + fprintf (stderr, "MoviesTask() didn't succeed in icvRetrieveFrame_QT_Movie().\n"); + return 0; + } + + // update IplImage header that points to PixMap of the Movie's GWorld. + // unfortunately, cvCvtColor doesn't know ARGB, the QuickTime pixel format, + // so we pass a modfied address. + // ATTENTION: don't access the last pixel's alpha entry, it's inexistant + myPixMapHandle = GetGWorldPixMap (capture->myGWorld); + LockPixels (myPixMapHandle); + cvSetData (capture->image_rgb, GetPixBaseAddr (myPixMapHandle) + 1, GetPixRowBytes (myPixMapHandle)); + + // covert RGB of GWorld to BGR + cvCvtColor (capture->image_rgb, capture->image_bgr, CV_RGBA2BGR); + + // allow QuickTime to access the buffer again + UnlockPixels (myPixMapHandle); + + // always return the same image pointer + return capture->image_bgr; +} + + +// ---------------------------------------------------------------------------------------- +#pragma mark - +#pragma mark Capturing from Video Cameras + +#ifdef USE_VDIG_VERSION + + /// SequenceGrabber state structure for QuickTime + typedef struct CvCapture_QT_Cam_vdig + { + ComponentInstance grabber; + short channel; + GWorldPtr myGWorld; + PixMapHandle pixmap; + + CvSize size; + long number_of_frames; + + IplImage * image_rgb; // will point to the PixMap of myGWorld + IplImage * image_bgr; // will be returned by icvRetrieveFrame_QT() + + } CvCapture_QT_Cam; + +#else + + typedef struct CvCapture_QT_Cam_barg + { + SeqGrabComponent grabber; + SGChannel channel; + GWorldPtr gworld; + Rect bounds; + ImageSequence sequence; + + volatile bool got_frame; + + CvSize size; + IplImage * image_rgb; // will point to the PixMap of myGWorld + IplImage * image_bgr; // will be returned by icvRetrieveFrame_QT() + + } CvCapture_QT_Cam; + +#endif + +static int icvOpenCamera_QT (CvCapture_QT_Cam * capture, const int index); +static int icvClose_QT_Cam (CvCapture_QT_Cam * capture); +static double icvGetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id); +static int icvSetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id, double value); +static int icvGrabFrame_QT_Cam (CvCapture_QT_Cam * capture); +static const void * icvRetrieveFrame_QT_Cam (CvCapture_QT_Cam * capture, int); + + +/** + * Initialize memory structure and call method to open camera + * + * @author Mark Asbach + * @date 2006-01-29 + */ +static CvCapture_QT_Cam * icvCaptureFromCam_QT (const int index) +{ + if (! did_enter_movies) + { + EnterMovies(); + did_enter_movies = 1; + } + + CvCapture_QT_Cam * capture = 0; + + if (index >= 0) + { + capture = (CvCapture_QT_Cam *) cvAlloc (sizeof (*capture)); + memset (capture, 0, sizeof(*capture)); + + if (!icvOpenCamera_QT (capture, index)) + cvFree (&capture); + } + + return capture; +} + +/// capture properties currently unimplemented for QuickTime camera interface +static double icvGetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id) +{ + assert (0); + return 0; +} + +/// capture properties currently unimplemented for QuickTime camera interface +static int icvSetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id, double value) +{ + assert (0); + return 0; +} + +#ifdef USE_VDIG_VERSION +#pragma mark Capturing using VDIG + +/** + * Open a quicktime video grabber component. This could be an attached + * IEEE1394 camera, a web cam, an iSight or digitizer card / video converter. + * + * @author Mark Asbach + * @date 2006-01-29 + */ +static int icvOpenCamera_QT (CvCapture_QT_Cam * capture, const int index) +{ + OPENCV_ASSERT (capture, "icvOpenCamera_QT", "'capture' is a NULL-pointer"); + OPENCV_ASSERT (index >=0, "icvOpenCamera_QT", "camera index is negative"); + + ComponentDescription component_description; + Component component = 0; + int number_of_inputs = 0; + Rect myRect; + ComponentResult result = noErr; + + + // travers all components and count video digitizer channels + component_description.componentType = videoDigitizerComponentType; + component_description.componentSubType = 0L; + component_description.componentManufacturer = 0L; + component_description.componentFlags = 0L; + component_description.componentFlagsMask = 0L; + do + { + // traverse component list + component = FindNextComponent (component, & component_description); + + // found a component? + if (component) + { + // dump component name + #ifndef NDEBUG + ComponentDescription desc; + Handle nameHandle = NewHandleClear (200); + char nameBuffer [255]; + + result = GetComponentInfo (component, & desc, nameHandle, nil, nil); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt GetComponentInfo()"); + OPENCV_ASSERT (*nameHandle, "icvOpenCamera_QT", "No name returned by GetComponentInfo()"); + snprintf (nameBuffer, (**nameHandle) + 1, "%s", (char *) (* nameHandle + 1)); + printf ("- Videodevice: %s\n", nameBuffer); + DisposeHandle (nameHandle); + #endif + + // open component to count number of inputs + capture->grabber = OpenComponent (component); + if (capture->grabber) + { + result = VDGetNumberOfInputs (capture->grabber, & capture->channel); + if (result != noErr) + fprintf (stderr, "Couldnt GetNumberOfInputs: %d\n", (int) result); + else + { + #ifndef NDEBUG + printf (" Number of inputs: %d\n", (int) capture->channel + 1); + #endif + + // add to overall number of inputs + number_of_inputs += capture->channel + 1; + + // did the user select an input that falls into this device's + // range of inputs? Then leave the loop + if (number_of_inputs > index) + { + // calculate relative channel index + capture->channel = index - number_of_inputs + capture->channel + 1; + OPENCV_ASSERT (capture->channel >= 0, "icvOpenCamera_QT", "negative channel number"); + + // dump channel name + #ifndef NDEBUG + char name[256]; + Str255 nameBuffer; + + result = VDGetInputName (capture->grabber, capture->channel, nameBuffer); + OPENCV_ASSERT (result == noErr, "ictOpenCamera_QT", "couldnt GetInputName()"); + snprintf (name, *nameBuffer, "%s", (char *) (nameBuffer + 1)); + printf (" Choosing input %d - %s\n", (int) capture->channel, name); + #endif + + // leave the loop + break; + } + } + + // obviously no inputs of this device/component were needed + CloseComponent (capture->grabber); + } + } + } + while (component); + + // did we find the desired input? + if (! component) + { + fprintf(stderr, "Not enough inputs available - can't choose input %d\n", index); + return 0; + } + + // -- Okay now, we selected the digitizer input, lets set up digitizer destination -- + + ClearMoviesStickyError(); + + // Select the desired input + result = VDSetInput (capture->grabber, capture->channel); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt select video digitizer input"); + + // get the bounding rectangle of the video digitizer + result = VDGetActiveSrcRect (capture->grabber, capture->channel, & myRect); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create VDGetActiveSrcRect from digitizer"); + myRect.right = 640; myRect.bottom = 480; + capture->size = cvSize (myRect.right - myRect.left, myRect.bottom - myRect.top); + printf ("Source rect is %d, %d -- %d, %d\n", (int) myRect.left, (int) myRect.top, (int) myRect.right, (int) myRect.bottom); + + // create offscreen GWorld + result = QTNewGWorld (& capture->myGWorld, k32ARGBPixelFormat, & myRect, nil, nil, 0); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create QTNewGWorld() for output image"); + + // get pixmap + capture->pixmap = GetGWorldPixMap (capture->myGWorld); + result = GetMoviesError (); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt get pixmap"); + + // set digitizer rect + result = VDSetDigitizerRect (capture->grabber, & myRect); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create VDGetActiveSrcRect from digitizer"); + + // set destination of digitized input + result = VDSetPlayThruDestination (capture->grabber, capture->pixmap, & myRect, nil, nil); + printf ("QuickTime error: %d\n", (int) result); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video destination"); + + // get destination of digitized images + result = VDGetPlayThruDestination (capture->grabber, & capture->pixmap, nil, nil, nil); + printf ("QuickTime error: %d\n", (int) result); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt get video destination"); + OPENCV_ASSERT (capture->pixmap != nil, "icvOpenCamera_QT", "empty set video destination"); + + // get the bounding rectangle of the video digitizer + GetPixBounds (capture->pixmap, & myRect); + capture->size = cvSize (myRect.right - myRect.left, myRect.bottom - myRect.top); + + // build IplImage header that will point to the PixMap of the Movie's GWorld later on + capture->image_rgb = cvCreateImageHeader (capture->size, IPL_DEPTH_8U, 4); + OPENCV_ASSERT (capture->image_rgb, "icvOpenCamera_QT", "couldnt create image header"); + + // create IplImage that hold correctly formatted result + capture->image_bgr = cvCreateImage (capture->size, IPL_DEPTH_8U, 3); + OPENCV_ASSERT (capture->image_bgr, "icvOpenCamera_QT", "couldnt create image"); + + // notify digitizer component, that we well be starting grabbing soon + result = VDCaptureStateChanging (capture->grabber, vdFlagCaptureIsForRecord | vdFlagCaptureStarting | vdFlagCaptureLowLatency); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set capture state"); + + + // yeah, we did it + return 1; +} + +static int icvClose_QT_Cam (CvCapture_QT_Cam * capture) +{ + OPENCV_ASSERT (capture, "icvClose_QT_Cam", "'capture' is a NULL-pointer"); + + ComponentResult result = noErr; + + // notify digitizer component, that we well be stopping grabbing soon + result = VDCaptureStateChanging (capture->grabber, vdFlagCaptureStopping); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set capture state"); + + // release memory + cvReleaseImage (& capture->image_bgr); + cvReleaseImageHeader (& capture->image_rgb); + DisposeGWorld (capture->myGWorld); + CloseComponent (capture->grabber); + + // sucessful + return 1; +} + +static int icvGrabFrame_QT_Cam (CvCapture_QT_Cam * capture) +{ + OPENCV_ASSERT (capture, "icvGrabFrame_QT_Cam", "'capture' is a NULL-pointer"); + OPENCV_ASSERT (capture->grabber, "icvGrabFrame_QT_Cam", "'grabber' is a NULL-pointer"); + + ComponentResult result = noErr; + + // grab one frame + result = VDGrabOneFrame (capture->grabber); + if (result != noErr) + { + fprintf (stderr, "VDGrabOneFrame failed\n"); + return 0; + } + + // successful + return 1; +} + +static const void * icvRetrieveFrame_QT_Cam (CvCapture_QT_Cam * capture, int) +{ + OPENCV_ASSERT (capture, "icvRetrieveFrame_QT_Cam", "'capture' is a NULL-pointer"); + + PixMapHandle myPixMapHandle = nil; + + // update IplImage header that points to PixMap of the Movie's GWorld. + // unfortunately, cvCvtColor doesn't know ARGB, the QuickTime pixel format, + // so we pass a modfied address. + // ATTENTION: don't access the last pixel's alpha entry, it's inexistant + //myPixMapHandle = GetGWorldPixMap (capture->myGWorld); + myPixMapHandle = capture->pixmap; + LockPixels (myPixMapHandle); + cvSetData (capture->image_rgb, GetPixBaseAddr (myPixMapHandle) + 1, GetPixRowBytes (myPixMapHandle)); + + // covert RGB of GWorld to BGR + cvCvtColor (capture->image_rgb, capture->image_bgr, CV_RGBA2BGR); + + // allow QuickTime to access the buffer again + UnlockPixels (myPixMapHandle); + + // always return the same image pointer + return capture->image_bgr; +} + +#else +#pragma mark Capturing using Sequence Grabber + +static OSErr icvDataProc_QT_Cam (SGChannel channel, Ptr raw_data, long len, long *, long, TimeValue, short, long refCon) +{ + CvCapture_QT_Cam * capture = (CvCapture_QT_Cam *) refCon; + CodecFlags ignore; + ComponentResult err = noErr; + + + // we need valid pointers + OPENCV_ASSERT (capture, "icvDataProc_QT_Cam", "'capture' is a NULL-pointer"); + OPENCV_ASSERT (capture->gworld, "icvDataProc_QT_Cam", "'gworld' is a NULL-pointer"); + OPENCV_ASSERT (raw_data, "icvDataProc_QT_Cam", "'raw_data' is a NULL-pointer"); + + // create a decompression sequence the first time + if (capture->sequence == 0) + { + ImageDescriptionHandle description = (ImageDescriptionHandle) NewHandle(0); + + // we need a decompression sequence that fits the raw data coming from the camera + err = SGGetChannelSampleDescription (channel, (Handle) description); + OPENCV_ASSERT (err == noErr, "icvDataProc_QT_Cam", "couldnt get channel sample description"); + + //*************************************************************************************// + //This fixed a bug when Quicktime is called twice to grab a frame (black band bug) - Yannick Verdie 2010 + Rect sourceRect; + sourceRect.top = 0; + sourceRect.left = 0; + sourceRect.right = (**description).width; + sourceRect.bottom = (**description).height; + + MatrixRecord scaleMatrix; + RectMatrix(&scaleMatrix,&sourceRect,&capture->bounds); + + err = DecompressSequenceBegin (&capture->sequence, description, capture->gworld, 0,&capture->bounds,&scaleMatrix, srcCopy, NULL, 0, codecNormalQuality, bestSpeedCodec); + //**************************************************************************************// + + OPENCV_ASSERT (err == noErr, "icvDataProc_QT_Cam", "couldnt begin decompression sequence"); + DisposeHandle ((Handle) description); + } + + // okay, we have a decompression sequence -> decompress! + err = DecompressSequenceFrameS (capture->sequence, raw_data, len, 0, &ignore, nil); + if (err != noErr) + { + fprintf (stderr, "icvDataProc_QT_Cam: couldn't decompress frame - %d\n", (int) err); + return err; + } + + // check if we dropped a frame + /*#ifndef NDEBUG + if (capture->got_frame) + fprintf (stderr, "icvDataProc_QT_Cam: frame was dropped\n"); + #endif*/ + + // everything worked as expected + capture->got_frame = true; + return noErr; +} + + +static int icvOpenCamera_QT (CvCapture_QT_Cam * capture, const int index) +{ + OPENCV_ASSERT (capture, "icvOpenCamera_QT", "'capture' is a NULL-pointer"); + OPENCV_ASSERT (index >= 0, "icvOpenCamera_QT", "camera index is negative"); + + PixMapHandle pixmap = nil; + OSErr result = noErr; + + // open sequence grabber component + capture->grabber = OpenDefaultComponent (SeqGrabComponentType, 0); + OPENCV_ASSERT (capture->grabber, "icvOpenCamera_QT", "couldnt create image"); + + // initialize sequence grabber component + result = SGInitialize (capture->grabber); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt initialize sequence grabber"); + result = SGSetDataRef (capture->grabber, 0, 0, seqGrabDontMakeMovie); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set data reference of sequence grabber"); + + // set up video channel + result = SGNewChannel (capture->grabber, VideoMediaType, & (capture->channel)); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create new video channel"); + + // select the camera indicated by index + SGDeviceList device_list = 0; + result = SGGetChannelDeviceList (capture->channel, 0, & device_list); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt get channel device list"); + for (int i = 0, current_index = 1; i < (*device_list)->count; i++) + { + SGDeviceName device = (*device_list)->entry[i]; + if (device.flags == 0) + { + if (current_index == index) + { + result = SGSetChannelDevice (capture->channel, device.name); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set the channel video device"); + break; + } + current_index++; + } + } + result = SGDisposeDeviceList (capture->grabber, device_list); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt dispose the channel device list"); + + // query natural camera resolution -- this will be wrong, but will be an upper + // bound on the actual resolution -- the actual resolution is set below + // after starting the frame grabber + result = SGGetSrcVideoBounds (capture->channel, & (capture->bounds)); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video channel bounds"); + + // create offscreen GWorld + result = QTNewGWorld (& (capture->gworld), k32ARGBPixelFormat, & (capture->bounds), 0, 0, 0); + result = SGSetGWorld (capture->grabber, capture->gworld, 0); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set GWorld for sequence grabber"); + result = SGSetChannelBounds (capture->channel, & (capture->bounds)); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video channel bounds"); + result = SGSetChannelUsage (capture->channel, seqGrabRecord); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set channel usage"); + + // start recording so we can size + result = SGStartRecord (capture->grabber); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt start recording"); + + // don't know *actual* resolution until now + ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(0); + result = SGGetChannelSampleDescription(capture->channel, (Handle)imageDesc); + OPENCV_ASSERT( result == noErr, "icvOpenCamera_QT", "couldn't get image size"); + capture->bounds.right = (**imageDesc).width; + capture->bounds.bottom = (**imageDesc).height; + DisposeHandle ((Handle) imageDesc); + + // stop grabber so that we can reset the parameters to the right size + result = SGStop (capture->grabber); + OPENCV_ASSERT (result == noErr, "icveClose_QT_Cam", "couldnt stop recording"); + + // reset GWorld to correct image size + GWorldPtr tmpgworld; + result = QTNewGWorld( &tmpgworld, k32ARGBPixelFormat, &(capture->bounds), 0, 0, 0); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create offscreen GWorld"); + result = SGSetGWorld( capture->grabber, tmpgworld, 0); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set GWorld for sequence grabber"); + DisposeGWorld( capture->gworld ); + capture->gworld = tmpgworld; + + result = SGSetChannelBounds (capture->channel, & (capture->bounds)); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video channel bounds"); + + // allocate images + capture->size = cvSize (capture->bounds.right - capture->bounds.left, capture->bounds.bottom - capture->bounds.top); + + // build IplImage header that points to the PixMap of the Movie's GWorld. + // unfortunately, cvCvtColor doesn't know ARGB, the QuickTime pixel format, + // so we shift the base address by one byte. + // ATTENTION: don't access the last pixel's alpha entry, it's inexistant + capture->image_rgb = cvCreateImageHeader (capture->size, IPL_DEPTH_8U, 4); + OPENCV_ASSERT (capture->image_rgb, "icvOpenCamera_QT", "couldnt create image header"); + pixmap = GetGWorldPixMap (capture->gworld); + OPENCV_ASSERT (pixmap, "icvOpenCamera_QT", "didn't get GWorld PixMap handle"); + LockPixels (pixmap); + cvSetData (capture->image_rgb, GetPixBaseAddr (pixmap) + 1, GetPixRowBytes (pixmap)); + + // create IplImage that hold correctly formatted result + capture->image_bgr = cvCreateImage (capture->size, IPL_DEPTH_8U, 3); + OPENCV_ASSERT (capture->image_bgr, "icvOpenCamera_QT", "couldnt create image"); + + + // tell the sequence grabber to invoke our data proc + result = SGSetDataProc (capture->grabber, NewSGDataUPP (icvDataProc_QT_Cam), (long) capture); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set data proc"); + + // start recording + result = SGStartRecord (capture->grabber); + OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt start recording"); + + return 1; +} + + +static int icvClose_QT_Cam (CvCapture_QT_Cam * capture) +{ + OPENCV_ASSERT (capture, "icvClose_QT_Cam", "'capture' is a NULL-pointer"); + + OSErr result = noErr; + + + // stop recording + result = SGStop (capture->grabber); + OPENCV_ASSERT (result == noErr, "icveClose_QT_Cam", "couldnt stop recording"); + + // close sequence grabber component + result = CloseComponent (capture->grabber); + OPENCV_ASSERT (result == noErr, "icveClose_QT_Cam", "couldnt close sequence grabber component"); + + // end decompression sequence + CDSequenceEnd (capture->sequence); + + // free memory + cvReleaseImage (& capture->image_bgr); + cvReleaseImageHeader (& capture->image_rgb); + DisposeGWorld (capture->gworld); + + // sucessful + return 1; +} + +static int icvGrabFrame_QT_Cam (CvCapture_QT_Cam * capture) +{ + OPENCV_ASSERT (capture, "icvGrabFrame_QT_Cam", "'capture' is a NULL-pointer"); + OPENCV_ASSERT (capture->grabber, "icvGrabFrame_QT_Cam", "'grabber' is a NULL-pointer"); + + ComponentResult result = noErr; + + + // grab one frame + result = SGIdle (capture->grabber); + if (result != noErr) + { + fprintf (stderr, "SGIdle failed in icvGrabFrame_QT_Cam with error %d\n", (int) result); + return 0; + } + + // successful + return 1; +} + +static const void * icvRetrieveFrame_QT_Cam (CvCapture_QT_Cam * capture, int) +{ + OPENCV_ASSERT (capture, "icvRetrieveFrame_QT_Cam", "'capture' is a NULL-pointer"); + OPENCV_ASSERT (capture->image_rgb, "icvRetrieveFrame_QT_Cam", "invalid source image"); + OPENCV_ASSERT (capture->image_bgr, "icvRetrieveFrame_QT_Cam", "invalid destination image"); + + OSErr myErr = noErr; + + + // service active sequence grabbers (= redraw immediately) + while (! capture->got_frame) + { + myErr = SGIdle (capture->grabber); + if (myErr != noErr) + { + fprintf (stderr, "SGIdle() didn't succeed in icvRetrieveFrame_QT_Cam().\n"); + return 0; + } + } + + // covert RGB of GWorld to BGR + cvCvtColor (capture->image_rgb, capture->image_bgr, CV_RGBA2BGR); + + // reset grabbing status + capture->got_frame = false; + + // always return the same image pointer + return capture->image_bgr; +} + +#endif + + +typedef struct CvVideoWriter_QT { + + DataHandler data_handler; + Movie movie; + Track track; + Media video; + + ICMCompressionSessionRef compression_session_ref; + + TimeValue duration_per_sample; +} CvVideoWriter_QT; + + +static TimeScale const TIME_SCALE = 600; + +static OSStatus icvEncodedFrameOutputCallback( + void* writer, + ICMCompressionSessionRef compression_session_ref, + OSStatus error, + ICMEncodedFrameRef encoded_frame_ref, + void* reserved +); + +static void icvSourceTrackingCallback( + void *source_tracking_ref_con, + ICMSourceTrackingFlags source_tracking_flags, + void *source_frame_ref_con, + void *reserved +); + +static int icvWriteFrame_QT( + CvVideoWriter_QT * video_writer, + const IplImage * image +) { + CVPixelBufferRef pixel_buffer_ref = NULL; + CVReturn retval = + CVPixelBufferCreate( + kCFAllocatorDefault, + image->width, image->height, k24RGBPixelFormat, + NULL /* pixel_buffer_attributes */, + &pixel_buffer_ref + ); + + // convert BGR IPL image to RGB pixel buffer + IplImage* image_rgb = + cvCreateImageHeader( + cvSize( image->width, image->height ), + IPL_DEPTH_8U, + 3 + ); + + retval = CVPixelBufferLockBaseAddress( pixel_buffer_ref, 0 ); + + void* base_address = CVPixelBufferGetBaseAddress( pixel_buffer_ref ); + size_t bytes_per_row = CVPixelBufferGetBytesPerRow( pixel_buffer_ref ); + cvSetData( image_rgb, base_address, bytes_per_row ); + + cvConvertImage( image, image_rgb, CV_CVTIMG_SWAP_RB ); + + retval = CVPixelBufferUnlockBaseAddress( pixel_buffer_ref, 0 ); + + cvReleaseImageHeader( &image_rgb ); + + ICMSourceTrackingCallbackRecord source_tracking_callback_record; + source_tracking_callback_record.sourceTrackingCallback = + icvSourceTrackingCallback; + source_tracking_callback_record.sourceTrackingRefCon = NULL; + + OSStatus status = + ICMCompressionSessionEncodeFrame( + video_writer->compression_session_ref, + pixel_buffer_ref, + 0, + video_writer->duration_per_sample, + kICMValidTime_DisplayDurationIsValid, + NULL, + &source_tracking_callback_record, + static_cast( &pixel_buffer_ref ) + ); + + return 0; +} + +static void icvReleaseVideoWriter_QT( CvVideoWriter_QT ** writer ) { + if ( ( writer != NULL ) && ( *writer != NULL ) ) { + CvVideoWriter_QT* video_writer = *writer; + + // force compression session to complete encoding of outstanding source + // frames + ICMCompressionSessionCompleteFrames( + video_writer->compression_session_ref, TRUE, 0, 0 + ); + + EndMediaEdits( video_writer->video ); + + ICMCompressionSessionRelease( video_writer->compression_session_ref ); + + InsertMediaIntoTrack( + video_writer->track, + 0, + 0, + GetMediaDuration( video_writer->video ), + FixRatio( 1, 1 ) + ); + + UpdateMovieInStorage( video_writer->movie, video_writer->data_handler ); + + CloseMovieStorage( video_writer->data_handler ); + +/* + // export to AVI + Handle data_ref; + OSType data_ref_type; + QTNewDataReferenceFromFullPathCFString( + CFSTR( "/Users/seibert/Desktop/test.avi" ), kQTPOSIXPathStyle, 0, + &data_ref, &data_ref_type + ); + + ConvertMovieToDataRef( video_writer->movie, NULL, data_ref, + data_ref_type, kQTFileTypeAVI, 'TVOD', 0, NULL ); + + DisposeHandle( data_ref ); +*/ + + DisposeMovie( video_writer->movie ); + + cvFree( writer ); + } +} + +static OSStatus icvEncodedFrameOutputCallback( + void* writer, + ICMCompressionSessionRef compression_session_ref, + OSStatus error, + ICMEncodedFrameRef encoded_frame_ref, + void* reserved +) { + CvVideoWriter_QT* video_writer = static_cast( writer ); + + OSStatus err = AddMediaSampleFromEncodedFrame( video_writer->video, + encoded_frame_ref, NULL ); + + return err; +} + +static void icvSourceTrackingCallback( + void *source_tracking_ref_con, + ICMSourceTrackingFlags source_tracking_flags, + void *source_frame_ref_con, + void *reserved +) { + if ( source_tracking_flags & kICMSourceTracking_ReleasedPixelBuffer ) { + CVPixelBufferRelease( + *static_cast( source_frame_ref_con ) + ); + } +} + + +static CvVideoWriter_QT* icvCreateVideoWriter_QT( + const char * filename, + int fourcc, + double fps, + CvSize frame_size, + int is_color +) { + CV_FUNCNAME( "icvCreateVideoWriter" ); + + CvVideoWriter_QT* video_writer = + static_cast( cvAlloc( sizeof( CvVideoWriter_QT ) ) ); + memset( video_writer, 0, sizeof( CvVideoWriter_QT ) ); + + Handle data_ref = NULL; + OSType data_ref_type; + DataHandler data_handler = NULL; + Movie movie = NULL; + ICMCompressionSessionOptionsRef options_ref = NULL; + ICMCompressionSessionRef compression_session_ref = NULL; + CFStringRef out_path = nil; + Track video_track = nil; + Media video = nil; + OSErr err = noErr; + CodecType codecType = kRawCodecType; + + __BEGIN__ + + // validate input arguments + if ( filename == NULL ) { + CV_ERROR( CV_StsBadArg, "Video file name must not be NULL" ); + } + if ( fps <= 0.0 ) { + CV_ERROR( CV_StsBadArg, "FPS must be larger than 0.0" ); + } + if ( ( frame_size.width <= 0 ) || ( frame_size.height <= 0 ) ) { + CV_ERROR( CV_StsBadArg, + "Frame width and height must be larger than 0" ); + } + + // initialize QuickTime + if ( !did_enter_movies ) { + err = EnterMovies(); + if ( err != noErr ) { + CV_ERROR( CV_StsInternal, "Unable to initialize QuickTime" ); + } + did_enter_movies = 1; + } + + // convert the file name into a data reference + out_path = CFStringCreateWithCString( kCFAllocatorDefault, filename, kCFStringEncodingISOLatin1 ); + CV_ASSERT( out_path != nil ); + err = QTNewDataReferenceFromFullPathCFString( out_path, kQTPOSIXPathStyle, + 0, &data_ref, &data_ref_type ); + CFRelease( out_path ); + if ( err != noErr ) { + CV_ERROR( CV_StsInternal, + "Cannot create data reference from file name" ); + } + + // create a new movie on disk + err = CreateMovieStorage( data_ref, data_ref_type, 'TVOD', + smCurrentScript, newMovieActive, &data_handler, &movie ); + + if ( err != noErr ) { + CV_ERROR( CV_StsInternal, "Cannot create movie storage" ); + } + + // create a track with video + video_track = NewMovieTrack (movie, + FixRatio( frame_size.width, 1 ), + FixRatio( frame_size.height, 1 ), + kNoVolume); + err = GetMoviesError(); + if ( err != noErr ) { + CV_ERROR( CV_StsInternal, "Cannot create video track" ); + } + video = NewTrackMedia( video_track, VideoMediaType, TIME_SCALE, nil, 0 ); + err = GetMoviesError(); + if ( err != noErr ) { + CV_ERROR( CV_StsInternal, "Cannot create video media" ); + } + + /*if( fourcc == CV_FOURCC( 'D', 'I', 'B', ' ' )) + codecType = kRawCodecType;*/ + + // start a compression session + err = ICMCompressionSessionOptionsCreate( kCFAllocatorDefault, + &options_ref ); + if ( err != noErr ) { + CV_ERROR( CV_StsInternal, "Cannot create compression session options" ); + } + err = ICMCompressionSessionOptionsSetAllowTemporalCompression( options_ref, + true ); + if ( err != noErr) { + CV_ERROR( CV_StsInternal, "Cannot enable temporal compression" ); + } + err = ICMCompressionSessionOptionsSetAllowFrameReordering( options_ref, + true ); + if ( err != noErr) { + CV_ERROR( CV_StsInternal, "Cannot enable frame reordering" ); + } + + ICMEncodedFrameOutputRecord encoded_frame_output_record; + encoded_frame_output_record.encodedFrameOutputCallback = + icvEncodedFrameOutputCallback; + encoded_frame_output_record.encodedFrameOutputRefCon = + static_cast( video_writer ); + encoded_frame_output_record.frameDataAllocator = NULL; + + err = ICMCompressionSessionCreate( kCFAllocatorDefault, frame_size.width, + frame_size.height, codecType, TIME_SCALE, options_ref, + NULL /*source_pixel_buffer_attributes*/, &encoded_frame_output_record, + &compression_session_ref ); + ICMCompressionSessionOptionsRelease( options_ref ); + if ( err != noErr ) { + CV_ERROR( CV_StsInternal, "Cannot create compression session" ); + } + + err = BeginMediaEdits( video ); + if ( err != noErr ) { + CV_ERROR( CV_StsInternal, "Cannot begin media edits" ); + } + + // fill in the video writer structure + video_writer->data_handler = data_handler; + video_writer->movie = movie; + video_writer->track = video_track; + video_writer->video = video; + video_writer->compression_session_ref = compression_session_ref; + video_writer->duration_per_sample = + static_cast( static_cast( TIME_SCALE ) / fps ); + + __END__ + + // clean up in case of error (unless error processing mode is + // CV_ErrModeLeaf) + if ( err != noErr ) { + if ( options_ref != NULL ) { + ICMCompressionSessionOptionsRelease( options_ref ); + } + if ( compression_session_ref != NULL ) { + ICMCompressionSessionRelease( compression_session_ref ); + } + if ( data_handler != NULL ) { + CloseMovieStorage( data_handler ); + } + if ( movie != NULL ) { + DisposeMovie( movie ); + } + if ( data_ref != NULL ) { + DeleteMovieStorage( data_ref, data_ref_type ); + DisposeHandle( data_ref ); + } + cvFree( reinterpret_cast( &video_writer ) ); + video_writer = NULL; + } + + return video_writer; +} + + +/** +* +* Wrappers for the new C++ CvCapture & CvVideoWriter structures +* +*/ + +class CvCapture_QT_Movie_CPP : public CvCapture +{ +public: + CvCapture_QT_Movie_CPP() { captureQT = 0; } + virtual ~CvCapture_QT_Movie_CPP() { close(); } + + virtual bool open( const char* filename ); + virtual void close(); + + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual int getCaptureDomain() { return CV_CAP_QT; } // Return the type of the capture object: CV_CAP_VFW, etc... +protected: + + CvCapture_QT_Movie* captureQT; +}; + +bool CvCapture_QT_Movie_CPP::open( const char* filename ) +{ + close(); + captureQT = icvCaptureFromFile_QT( filename ); + return captureQT != 0; +} + +void CvCapture_QT_Movie_CPP::close() +{ + if( captureQT ) + { + icvClose_QT_Movie( captureQT ); + cvFree( &captureQT ); + } +} + +bool CvCapture_QT_Movie_CPP::grabFrame() +{ + return captureQT ? icvGrabFrame_QT_Movie( captureQT ) != 0 : false; +} + +IplImage* CvCapture_QT_Movie_CPP::retrieveFrame(int) +{ + return captureQT ? (IplImage*)icvRetrieveFrame_QT_Movie( captureQT, 0 ) : 0; +} + +double CvCapture_QT_Movie_CPP::getProperty( int propId ) +{ + return captureQT ? icvGetProperty_QT_Movie( captureQT, propId ) : 0; +} + +bool CvCapture_QT_Movie_CPP::setProperty( int propId, double value ) +{ + return captureQT ? icvSetProperty_QT_Movie( captureQT, propId, value ) != 0 : false; +} + +CvCapture* cvCreateFileCapture_QT( const char* filename ) +{ + CvCapture_QT_Movie_CPP* capture = new CvCapture_QT_Movie_CPP; + + if( capture->open( filename )) + return capture; + + delete capture; + return 0; +} + + +///////////////////////////////////// + +class CvCapture_QT_Cam_CPP : public CvCapture +{ +public: + CvCapture_QT_Cam_CPP() { captureQT = 0; } + virtual ~CvCapture_QT_Cam_CPP() { close(); } + + virtual bool open( int index ); + virtual void close(); + + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual int getCaptureDomain() { return CV_CAP_QT; } // Return the type of the capture object: CV_CAP_VFW, etc... +protected: + + CvCapture_QT_Cam* captureQT; +}; + +bool CvCapture_QT_Cam_CPP::open( int index ) +{ + close(); + captureQT = icvCaptureFromCam_QT( index ); + return captureQT != 0; +} + +void CvCapture_QT_Cam_CPP::close() +{ + if( captureQT ) + { + icvClose_QT_Cam( captureQT ); + cvFree( &captureQT ); + } +} + +bool CvCapture_QT_Cam_CPP::grabFrame() +{ + return captureQT ? icvGrabFrame_QT_Cam( captureQT ) != 0 : false; +} + +IplImage* CvCapture_QT_Cam_CPP::retrieveFrame(int) +{ + return captureQT ? (IplImage*)icvRetrieveFrame_QT_Cam( captureQT, 0 ) : 0; +} + +double CvCapture_QT_Cam_CPP::getProperty( int propId ) +{ + return captureQT ? icvGetProperty_QT_Cam( captureQT, propId ) : 0; +} + +bool CvCapture_QT_Cam_CPP::setProperty( int propId, double value ) +{ + return captureQT ? icvSetProperty_QT_Cam( captureQT, propId, value ) != 0 : false; +} + +CvCapture* cvCreateCameraCapture_QT( int index ) +{ + CvCapture_QT_Cam_CPP* capture = new CvCapture_QT_Cam_CPP; + + if( capture->open( index )) + return capture; + + delete capture; + return 0; +} + +///////////////////////////////// + +class CvVideoWriter_QT_CPP : public CvVideoWriter +{ +public: + CvVideoWriter_QT_CPP() { writerQT = 0; } + virtual ~CvVideoWriter_QT_CPP() { close(); } + + virtual bool open( const char* filename, int fourcc, + double fps, CvSize frameSize, bool isColor ); + virtual void close(); + virtual bool writeFrame( const IplImage* ); + +protected: + CvVideoWriter_QT* writerQT; +}; + +bool CvVideoWriter_QT_CPP::open( const char* filename, int fourcc, + double fps, CvSize frameSize, bool isColor ) +{ + close(); + writerQT = icvCreateVideoWriter_QT( filename, fourcc, fps, frameSize, isColor ); + return writerQT != 0; +} + +void CvVideoWriter_QT_CPP::close() +{ + if( writerQT ) + { + icvReleaseVideoWriter_QT( &writerQT ); + writerQT = 0; + } +} + +bool CvVideoWriter_QT_CPP::writeFrame( const IplImage* image ) +{ + if( !writerQT || !image ) + return false; + return icvWriteFrame_QT( writerQT, image ) >= 0; +} + +CvVideoWriter* cvCreateVideoWriter_QT( const char* filename, int fourcc, + double fps, CvSize frameSize, int isColor ) +{ + CvVideoWriter_QT_CPP* writer = new CvVideoWriter_QT_CPP; + if( writer->open( filename, fourcc, fps, frameSize, isColor != 0 )) + return writer; + delete writer; + return 0; +} diff --git a/highgui/src/cap_qtkit.mm b/highgui/src/cap_qtkit.mm new file mode 100644 index 0000000..ff5d408 --- /dev/null +++ b/highgui/src/cap_qtkit.mm @@ -0,0 +1,1025 @@ +/* + * CvCapture.mm + * + * Created by Nicholas Butko on 11/3/09. + * Copyright 2009. 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. + * + */ + +#include "precomp.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include +#import + +using namespace std; + +/********************** Declaration of class headers ************************/ + +/***************************************************************************** + * + * CaptureDelegate Declaration. + * + * CaptureDelegate is notified on a separate thread by the OS whenever there + * is a new frame. When "updateImage" is called from the main thread, it + * copies this new frame into an IplImage, but only if this frame has not + * been copied before. When "getOutput" is called from the main thread, + * it gives the last copied IplImage. + * + *****************************************************************************/ + +#ifndef QTKIT_VERSION_7_6_3 +#define QTKIT_VERSION_7_6_3 70603 +#define QTKIT_VERSION_7_0 70000 +#endif + +#ifndef QTKIT_VERSION_MAX_ALLOWED +#define QTKIT_VERSION_MAX_ALLOWED QTKIT_VERSION_7_0 +#endif + +#define DISABLE_AUTO_RESTART 999 + +@interface CaptureDelegate : NSObject +{ + int newFrame; + CVImageBufferRef mCurrentImageBuffer; + char* imagedata; + IplImage* image; + char* bgr_imagedata; + IplImage* bgr_image; + size_t currSize; +} + +- (void)captureOutput:(QTCaptureOutput *)captureOutput + didOutputVideoFrame:(CVImageBufferRef)videoFrame + withSampleBuffer:(QTSampleBuffer *)sampleBuffer + fromConnection:(QTCaptureConnection *)connection; + +- (void)captureOutput:(QTCaptureOutput *)captureOutput +didDropVideoFrameWithSampleBuffer:(QTSampleBuffer *)sampleBuffer + fromConnection:(QTCaptureConnection *)connection; + +- (int)updateImage; +- (IplImage*)getOutput; + +@end + +/***************************************************************************** + * + * CvCaptureCAM Declaration. + * + * CvCaptureCAM is the instantiation of a capture source for cameras. + * + *****************************************************************************/ + +class CvCaptureCAM : public CvCapture { +public: + CvCaptureCAM(int cameraNum = -1) ; + ~CvCaptureCAM(); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual double getProperty(int property_id); + virtual bool setProperty(int property_id, double value); + virtual int didStart(); + + +private: + QTCaptureSession *mCaptureSession; + QTCaptureDeviceInput *mCaptureDeviceInput; + QTCaptureDecompressedVideoOutput *mCaptureDecompressedVideoOutput; + CaptureDelegate* capture; + + int startCaptureDevice(int cameraNum); + void stopCaptureDevice(); + + void setWidthHeight(); + bool grabFrame(double timeOut); + + int camNum; + int width; + int height; + int settingWidth; + int settingHeight; + int started; + int disableAutoRestart; + +}; + + +/***************************************************************************** + * + * CvCaptureFile Declaration. + * + * CvCaptureFile is the instantiation of a capture source for video files. + * + *****************************************************************************/ + +class CvCaptureFile : public CvCapture { +public: + CvCaptureFile(const char* filename) ; + ~CvCaptureFile(); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual double getProperty(int property_id); + virtual bool setProperty(int property_id, double value); + virtual int didStart(); + + +private: + QTMovie *mCaptureSession; + + char* imagedata; + IplImage* image; + char* bgr_imagedata; + IplImage* bgr_image; + size_t currSize; + + //IplImage* retrieveFrameBitmap(); + IplImage* retrieveFramePixelBuffer(); + double getFPS(); + + int movieWidth; + int movieHeight; + double movieFPS; + double currentFPS; + double movieDuration; + int changedPos; + + int started; +}; + + +/***************************************************************************** + * + * CvCaptureFile Declaration. + * + * CvCaptureFile is the instantiation of a capture source for video files. + * + *****************************************************************************/ + +class CvVideoWriter_QT : public CvVideoWriter{ +public: + CvVideoWriter_QT(const char* filename, int fourcc, + double fps, CvSize frame_size, + int is_color=1); + ~CvVideoWriter_QT(); + bool writeFrame(const IplImage* image); +private: + IplImage* argbimage; + QTMovie* mMovie; + unsigned char* imagedata; + + NSString* path; + NSString* codec; + double movieFPS; + CvSize movieSize; + int movieColor; +}; + + +/****************** Implementation of interface functions ********************/ + + +CvCapture* cvCreateFileCapture_QT(const char* filename) { + CvCaptureFile *retval = new CvCaptureFile(filename); + + if(retval->didStart()) + return retval; + delete retval; + return NULL; +} + +CvCapture* cvCreateCameraCapture_QT(int index ) { + CvCapture* retval = new CvCaptureCAM(index); + if (!((CvCaptureCAM *)retval)->didStart()) + cvReleaseCapture(&retval); + return retval; +} + +CvVideoWriter* cvCreateVideoWriter_QT(const char* filename, int fourcc, + double fps, CvSize frame_size, + int is_color) { + return new CvVideoWriter_QT(filename, fourcc, fps, frame_size,is_color); +} + +/********************** Implementation of Classes ****************************/ + +/***************************************************************************** + * + * CvCaptureCAM Implementation. + * + * CvCaptureCAM is the instantiation of a capture source for cameras. + * + *****************************************************************************/ + +CvCaptureCAM::CvCaptureCAM(int cameraNum) { + mCaptureSession = nil; + mCaptureDeviceInput = nil; + mCaptureDecompressedVideoOutput = nil; + capture = nil; + + width = 0; + height = 0; + settingWidth = 0; + settingHeight = 0; + disableAutoRestart = 0; + + camNum = cameraNum; + + if (!startCaptureDevice(camNum)) { + cout << "Warning, camera failed to properly initialize!" << endl; + started = 0; + } else { + started = 1; + } + +} + +CvCaptureCAM::~CvCaptureCAM() { + stopCaptureDevice(); + + cout << "Cleaned up camera." << endl; +} + +int CvCaptureCAM::didStart() { + return started; +} + + +bool CvCaptureCAM::grabFrame() { + return grabFrame(5); +} + +bool CvCaptureCAM::grabFrame(double timeOut) { + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + double sleepTime = 0.005; + double total = 0; + + NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:sleepTime]; + while (![capture updateImage] && (total += sleepTime)<=timeOut && + [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode + beforeDate:loopUntil]) + loopUntil = [NSDate dateWithTimeIntervalSinceNow:sleepTime]; + + [localpool drain]; + + return total <= timeOut; +} + +IplImage* CvCaptureCAM::retrieveFrame(int) { + return [capture getOutput]; +} + +void CvCaptureCAM::stopCaptureDevice() { + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + [mCaptureSession stopRunning]; + + QTCaptureDevice *device = [mCaptureDeviceInput device]; + if ([device isOpen]) [device close]; + + [mCaptureSession release]; + [mCaptureDeviceInput release]; + + [mCaptureDecompressedVideoOutput setDelegate:mCaptureDecompressedVideoOutput]; + [mCaptureDecompressedVideoOutput release]; + [capture release]; + [localpool drain]; + +} + +int CvCaptureCAM::startCaptureDevice(int cameraNum) { + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + capture = [[CaptureDelegate alloc] init]; + + QTCaptureDevice *device; + NSArray* devices = [[[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo] + arrayByAddingObjectsFromArray:[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeMuxed]] retain]; + + if ([devices count] == 0) { + cout << "QTKit didn't find any attached Video Input Devices!" << endl; + [localpool drain]; + return 0; + } + + if (cameraNum >= 0) { + int nCameras = [devices count]; + if( cameraNum < 0 || cameraNum >= nCameras ) + return 0; + device = [devices objectAtIndex:cameraNum] ; + } else { + device = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo] ; + } + int success; + NSError* error; + + if (device) { + + success = [device open:&error]; + if (!success) { + cout << "QTKit failed to open a Video Capture Device" << endl; + [localpool drain]; + return 0; + } + + mCaptureDeviceInput = [[QTCaptureDeviceInput alloc] initWithDevice:device] ; + mCaptureSession = [[QTCaptureSession alloc] init] ; + + success = [mCaptureSession addInput:mCaptureDeviceInput error:&error]; + + if (!success) { + cout << "QTKit failed to start capture session with opened Capture Device" << endl; + [localpool drain]; + return 0; + } + + + mCaptureDecompressedVideoOutput = [[QTCaptureDecompressedVideoOutput alloc] init]; + [mCaptureDecompressedVideoOutput setDelegate:capture]; + NSDictionary *pixelBufferOptions ; + if (width > 0 && height > 0) { + pixelBufferOptions = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithDouble:1.0*width], (id)kCVPixelBufferWidthKey, + [NSNumber numberWithDouble:1.0*height], (id)kCVPixelBufferHeightKey, + //[NSNumber numberWithUnsignedInt:k32BGRAPixelFormat], (id)kCVPixelBufferPixelFormatTypeKey, + [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], + (id)kCVPixelBufferPixelFormatTypeKey, + nil]; + } else { + pixelBufferOptions = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], + (id)kCVPixelBufferPixelFormatTypeKey, + nil]; + } + [mCaptureDecompressedVideoOutput setPixelBufferAttributes:pixelBufferOptions]; + +#if QTKIT_VERSION_MAX_ALLOWED >= QTKIT_VERSION_7_6_3 + [mCaptureDecompressedVideoOutput setAutomaticallyDropsLateVideoFrames:YES]; +#endif + + + success = [mCaptureSession addOutput:mCaptureDecompressedVideoOutput error:&error]; + if (!success) { + cout << "QTKit failed to add Output to Capture Session" << endl; + [localpool drain]; + return 0; + } + + [mCaptureSession startRunning]; + + grabFrame(60); + + return 1; + } + + [localpool drain]; + return 0; +} + +void CvCaptureCAM::setWidthHeight() { + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + NSDictionary* pixelBufferOptions = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithDouble:1.0*width], (id)kCVPixelBufferWidthKey, + [NSNumber numberWithDouble:1.0*height], (id)kCVPixelBufferHeightKey, + [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], + (id)kCVPixelBufferPixelFormatTypeKey, + nil]; + + [mCaptureDecompressedVideoOutput setPixelBufferAttributes:pixelBufferOptions]; + grabFrame(60); + [localpool drain]; +} + + +double CvCaptureCAM::getProperty(int property_id){ + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + NSArray* connections = [mCaptureDeviceInput connections]; + QTFormatDescription* format = [[connections objectAtIndex:0] formatDescription]; + NSSize s1 = [[format attributeForKey:QTFormatDescriptionVideoCleanApertureDisplaySizeAttribute] sizeValue]; + + int width=s1.width, height=s1.height; + switch (property_id) { + case CV_CAP_PROP_FRAME_WIDTH: + return width; + case CV_CAP_PROP_FRAME_HEIGHT: + return height; + default: + return 0; + } + + [localpool drain]; + +} + +bool CvCaptureCAM::setProperty(int property_id, double value) { + switch (property_id) { + case CV_CAP_PROP_FRAME_WIDTH: + width = value; + settingWidth = 1; + if (settingWidth && settingHeight) { + setWidthHeight(); + settingWidth =0; + settingHeight = 0; + } + return true; + case CV_CAP_PROP_FRAME_HEIGHT: + height = value; + settingHeight = 1; + if (settingWidth && settingHeight) { + setWidthHeight(); + settingWidth =0; + settingHeight = 0; + } + return true; + case DISABLE_AUTO_RESTART: + disableAutoRestart = value; + return 1; + default: + return false; + } +} + + +/***************************************************************************** + * + * CaptureDelegate Implementation. + * + * CaptureDelegate is notified on a separate thread by the OS whenever there + * is a new frame. When "updateImage" is called from the main thread, it + * copies this new frame into an IplImage, but only if this frame has not + * been copied before. When "getOutput" is called from the main thread, + * it gives the last copied IplImage. + * + *****************************************************************************/ + + +@implementation CaptureDelegate + +- (id)init { + [super init]; + newFrame = 0; + imagedata = NULL; + bgr_imagedata = NULL; + currSize = 0; + image = NULL; + bgr_image = NULL; + return self; +} + + +-(void)dealloc { + if (imagedata != NULL) free(imagedata); + if (bgr_imagedata != NULL) free(bgr_imagedata); + cvReleaseImage(&image); + cvReleaseImage(&bgr_image); + [super dealloc]; +} + +- (void)captureOutput:(QTCaptureOutput *)captureOutput + didOutputVideoFrame:(CVImageBufferRef)videoFrame + withSampleBuffer:(QTSampleBuffer *)sampleBuffer + fromConnection:(QTCaptureConnection *)connection { + + CVBufferRetain(videoFrame); + CVImageBufferRef imageBufferToRelease = mCurrentImageBuffer; + + @synchronized (self) { + + mCurrentImageBuffer = videoFrame; + newFrame = 1; + } + + CVBufferRelease(imageBufferToRelease); + +} +- (void)captureOutput:(QTCaptureOutput *)captureOutput +didDropVideoFrameWithSampleBuffer:(QTSampleBuffer *)sampleBuffer + fromConnection:(QTCaptureConnection *)connection { + cout << "Camera dropped frame!" << endl; +} + +-(IplImage*) getOutput { + return bgr_image; +} + +-(int) updateImage { + if (newFrame==0) return 0; + CVPixelBufferRef pixels; + + @synchronized (self){ + pixels = CVBufferRetain(mCurrentImageBuffer); + newFrame = 0; + } + + CVPixelBufferLockBaseAddress(pixels, 0); + uint32_t* baseaddress = (uint32_t*)CVPixelBufferGetBaseAddress(pixels); + + size_t width = CVPixelBufferGetWidth(pixels); + size_t height = CVPixelBufferGetHeight(pixels); + size_t rowBytes = CVPixelBufferGetBytesPerRow(pixels); + + if (rowBytes != 0) { + + if (currSize != rowBytes*height*sizeof(char)) { + currSize = rowBytes*height*sizeof(char); + if (imagedata != NULL) free(imagedata); + if (bgr_imagedata != NULL) free(bgr_imagedata); + imagedata = (char*)malloc(currSize); + bgr_imagedata = (char*)malloc(currSize); + } + + memcpy(imagedata, baseaddress, currSize); + + if (image == NULL) { + image = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, 4); + } + image->width =width; + image->height = height; + image->nChannels = 4; + image->depth = IPL_DEPTH_8U; + image->widthStep = rowBytes; + image->imageData = imagedata; + image->imageSize = currSize; + + if (bgr_image == NULL) { + bgr_image = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, 3); + } + bgr_image->width =width; + bgr_image->height = height; + bgr_image->nChannels = 3; + bgr_image->depth = IPL_DEPTH_8U; + bgr_image->widthStep = rowBytes; + bgr_image->imageData = bgr_imagedata; + bgr_image->imageSize = currSize; + + cvCvtColor(image, bgr_image, CV_BGRA2BGR); + + } + + CVPixelBufferUnlockBaseAddress(pixels, 0); + CVBufferRelease(pixels); + + return 1; +} + +@end + + +/***************************************************************************** + * + * CvCaptureFile Implementation. + * + * CvCaptureFile is the instantiation of a capture source for video files. + * + *****************************************************************************/ + +CvCaptureFile::CvCaptureFile(const char* filename) { + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + + mCaptureSession = nil; + image = NULL; + bgr_image = NULL; + imagedata = NULL; + bgr_imagedata = NULL; + currSize = 0; + + movieWidth = 0; + movieHeight = 0; + movieFPS = 0; + currentFPS = 0; + movieDuration = 0; + changedPos = 0; + + started = 0; + + NSError* error; + + + mCaptureSession = [[QTMovie movieWithFile:[NSString stringWithCString:filename + encoding:NSASCIIStringEncoding] + error:&error] retain]; + [mCaptureSession setAttribute:[NSNumber numberWithBool:YES] + forKey:QTMovieLoopsAttribute]; + + if (mCaptureSession == nil) { + cout << "WARNING: Couldn't read movie file " << filename << endl; + [localpool drain]; + started = 0; + return; + } + + + [mCaptureSession gotoBeginning]; + + NSSize size = [[mCaptureSession attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]; + + movieWidth = size.width; + movieHeight = size.height; + movieFPS = getFPS(); + currentFPS = movieFPS; + + QTTime t; + + [[mCaptureSession attributeForKey:QTMovieDurationAttribute] getValue:&t]; + movieDuration = (t.timeValue *1000.0 / t.timeScale); + started = 1; + [localpool drain]; + +} + +CvCaptureFile::~CvCaptureFile() { + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + if (imagedata != NULL) free(imagedata); + if (bgr_imagedata != NULL) free(bgr_imagedata); + cvReleaseImage(&image); + cvReleaseImage(&bgr_image); + [mCaptureSession release]; + [localpool drain]; +} + +int CvCaptureFile::didStart() { + return started; +} + +bool CvCaptureFile::grabFrame() { + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + double t1 = getProperty(CV_CAP_PROP_POS_MSEC); + [mCaptureSession stepForward]; + double t2 = getProperty(CV_CAP_PROP_POS_MSEC); + if (t2>t1 && !changedPos) { + currentFPS = 1000.0/(t2-t1); + } else { + currentFPS = movieFPS; + } + changedPos = 0; + [localpool drain]; + return 1; +} + + +IplImage* CvCaptureFile::retrieveFramePixelBuffer() { + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + + NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys: + QTMovieFrameImageTypeCVPixelBufferRef, QTMovieFrameImageType, +#ifdef MAC_OS_X_VERSION_10_6 + [NSNumber numberWithBool:YES], QTMovieFrameImageSessionMode, +#endif + nil]; + CVPixelBufferRef frame = (CVPixelBufferRef)[mCaptureSession frameImageAtTime:[mCaptureSession currentTime] + withAttributes:attributes + error:nil]; + + CVPixelBufferRef pixels = CVBufferRetain(frame); + CVPixelBufferLockBaseAddress(pixels, 0); + + uint32_t* baseaddress = (uint32_t*)CVPixelBufferGetBaseAddress(pixels); + size_t width = CVPixelBufferGetWidth(pixels); + size_t height = CVPixelBufferGetHeight(pixels); + size_t rowBytes = CVPixelBufferGetBytesPerRow(pixels); + + if (rowBytes != 0) { + + if (currSize != rowBytes*height*sizeof(char)) { + currSize = rowBytes*height*sizeof(char); + if (imagedata != NULL) free(imagedata); + if (bgr_imagedata != NULL) free(bgr_imagedata); + imagedata = (char*)malloc(currSize); + bgr_imagedata = (char*)malloc(currSize); + } + + memcpy(imagedata, baseaddress, currSize); + + //ARGB -> BGRA + for (unsigned int i = 0; i < currSize; i+=4) { + char temp = imagedata[i]; + imagedata[i] = imagedata[i+3]; + imagedata[i+3] = temp; + temp = imagedata[i+1]; + imagedata[i+1] = imagedata[i+2]; + imagedata[i+2] = temp; + } + + if (image == NULL) { + image = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, 4); + } + + image->width =width; + image->height = height; + image->nChannels = 4; + image->depth = IPL_DEPTH_8U; + image->widthStep = rowBytes; + image->imageData = imagedata; + image->imageSize = currSize; + + + if (bgr_image == NULL) { + bgr_image = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, 3); + } + + bgr_image->width =width; + bgr_image->height = height; + bgr_image->nChannels = 3; + bgr_image->depth = IPL_DEPTH_8U; + bgr_image->widthStep = rowBytes; + bgr_image->imageData = bgr_imagedata; + bgr_image->imageSize = currSize; + + cvCvtColor(image, bgr_image,CV_BGRA2BGR); + + } + + CVPixelBufferUnlockBaseAddress(pixels, 0); + CVBufferRelease(pixels); + + [localpool drain]; + + return bgr_image; +} + + +IplImage* CvCaptureFile::retrieveFrame(int) { + return retrieveFramePixelBuffer(); +} + +double CvCaptureFile::getFPS() { + if (mCaptureSession == nil) return 0; + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + double now = getProperty(CV_CAP_PROP_POS_MSEC); + double retval = 0; + if (now == 0) { + [mCaptureSession stepForward]; + double t2 = getProperty(CV_CAP_PROP_POS_MSEC); + [mCaptureSession stepBackward]; + retval = 1000.0 / (t2-now); + } else { + [mCaptureSession stepBackward]; + double t2 = getProperty(CV_CAP_PROP_POS_MSEC); + [mCaptureSession stepForward]; + retval = 1000.0 / (now-t2); + } + [localpool drain]; + return retval; +} + +double CvCaptureFile::getProperty(int property_id){ + if (mCaptureSession == nil) return 0; + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + double retval; + QTTime t; + + //cerr << "get_prop"< 0) { + QTMedia *media = [[videoTracks objectAtIndex:0] media]; + retval = [[media attributeForKey:QTMediaSampleCountAttribute] longValue]; + } else { + retval = 0; + } + } + break; + case CV_CAP_PROP_FOURCC: + default: + retval = false; + } + + [localpool drain]; + return retval; +} + + +/***************************************************************************** + * + * CvVideoWriter Implementation. + * + * CvVideoWriter is the instantiation of a video output class + * + *****************************************************************************/ + + +CvVideoWriter_QT::CvVideoWriter_QT(const char* filename, int fourcc, + double fps, CvSize frame_size, + int is_color) { + + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + movieFPS = fps; + movieSize = frame_size; + movieColor = is_color; + mMovie = nil; + path = [[[NSString stringWithCString:filename encoding:NSASCIIStringEncoding] stringByExpandingTildeInPath] retain]; + + argbimage = cvCreateImage(movieSize, IPL_DEPTH_8U, 4); + + + char cc[5]; + cc[0] = fourcc & 255; + cc[1] = (fourcc >> 8) & 255; + cc[2] = (fourcc >> 16) & 255; + cc[3] = (fourcc >> 24) & 255; + cc[4] = 0; + int cc2 = CV_FOURCC(cc[0], cc[1], cc[2], cc[3]); + if (cc2!=fourcc) { + cout << "WARNING: Didn't properly encode FourCC. Expected " << fourcc + << " but got " << cc2 << "." << endl; + } + + codec = [[NSString stringWithCString:cc encoding:NSASCIIStringEncoding] retain]; + + NSError *error = nil; + if (!mMovie) { + + NSFileManager* files = [NSFileManager defaultManager]; + if ([files fileExistsAtPath:path]) { + if (![files removeItemAtPath:path error:nil]) { + cout << "WARNING: Failed to remove existing file " << [path cStringUsingEncoding:NSASCIIStringEncoding] << endl; + } + } + + mMovie = [[QTMovie alloc] initToWritableFile:path error:&error]; + if (!mMovie) { + cout << "WARNING: Could not create empty movie file container." << endl; + [localpool drain]; + return; + } + } + + [mMovie setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute]; + + [localpool drain]; +} + + +CvVideoWriter_QT::~CvVideoWriter_QT() { + cvReleaseImage(&argbimage); + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + [mMovie release]; + [path release]; + [codec release]; + [localpool drain]; +} + +bool CvVideoWriter_QT::writeFrame(const IplImage* image) { + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + + cvCvtColor(image, argbimage, CV_BGR2BGRA); + + + unsigned char* imagedata = (unsigned char*)argbimage->imageData; + //BGRA --> ARGB + + for (int j = 0; j < argbimage->height; j++) { + int rowstart = argbimage->widthStep * j; + for (int i = rowstart; i < rowstart+argbimage->widthStep; i+=4) { + unsigned char temp = imagedata[i]; + imagedata[i] = 255; + imagedata[i+3] = temp; + temp = imagedata[i+2]; + imagedata[i+2] = imagedata[i+1]; + imagedata[i+1] = temp; + } + } + + NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&imagedata + pixelsWide:movieSize.width + pixelsHigh:movieSize.height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bitmapFormat:NSAlphaFirstBitmapFormat + bytesPerRow:argbimage->widthStep + bitsPerPixel:32] ; + + + NSImage* nsimage = [[NSImage alloc] init]; + + [nsimage addRepresentation:imageRep]; + + /* + codecLosslessQuality = 0x00000400, + codecMaxQuality = 0x000003FF, + codecMinQuality = 0x00000000, + codecLowQuality = 0x00000100, + codecNormalQuality = 0x00000200, + codecHighQuality = 0x00000300 + */ + + [mMovie addImage:nsimage forDuration:QTMakeTime(100,100*movieFPS) withAttributes:[NSDictionary dictionaryWithObjectsAndKeys: + codec, QTAddImageCodecType, + //[NSNumber numberWithInt:codecLowQuality], QTAddImageCodecQuality, + [NSNumber numberWithInt:100*movieFPS], QTTrackTimeScaleAttribute,nil]]; + + if (![mMovie updateMovieFile]) { + cout << "Didn't successfully update movie file." << endl; + } + + [imageRep release]; + [nsimage release]; + [localpool drain]; + + return 1; +} + diff --git a/highgui/src/cap_tyzx.cpp b/highgui/src/cap_tyzx.cpp new file mode 100644 index 0000000..5ca43cb --- /dev/null +++ b/highgui/src/cap_tyzx.cpp @@ -0,0 +1,230 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include + +#if _MSC_VER >= 1200 + #pragma comment(lib,"DeepSeaIF.lib") +#endif + + +/****************** Capturing video from TYZX stereo camera *******************/ +/** Initially developed by Roman Stanchak rstanchak@yahoo.com */ + +class CvCaptureCAM_TYZX : public CvCapture +{ +public: + CvCaptureCAM_TYZX() { index = -1; image = 0; } + virtual ~CvCaptureCAM_TYZX() { close(); } + + virtual bool open( int _index ); + virtual void close(); + bool isOpened() { return index >= 0; } + + virtual double getProperty(int); + virtual bool setProperty(int, double) { return false; } + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual int getCaptureDomain() { return CV_CAP_TYZX; } // Return the type of the capture object: CV_CAP_VFW, etc... + +protected: + virtual bool allocateImage(); + + int index; + IplImage* image; +} +CvCaptureCAM_TYZX; + +DeepSeaIF * g_tyzx_camera = 0; +int g_tyzx_refcount = 0; + +bool CvCaptureCAM_TYZX::open( int _index ) +{ + close(); + + if(!g_tyzx_camera){ + g_tyzx_camera = new DeepSeaIF; + if(!g_tyzx_camera) return false; + + if(!g_tyzx_camera->initializeSettings(NULL)){ + delete g_tyzx_camera; + return false; + } + + // set initial sensor mode + // TODO is g_tyzx_camera redundant? + g_tyzx_camera->setSensorMode(g_tyzx_camera->getSensorMode()); + + // mm's + g_tyzx_camera->setZUnits((int) 1000); + + g_tyzx_camera->enableLeftColor(true); + g_tyzx_camera->setColorMode(DeepSeaIF::BGRcolor); + g_tyzx_camera->setDoIntensityCrop(true); + g_tyzx_camera->enable8bitImages(true); + if(!g_tyzx_camera->startCapture()){ + return false; + } + g_tyzx_refcount++; + } + index = _index; + return true; +} + +void CvCaptureCAM_TYZX::close() +{ + if( isOpened() ) + { + cvReleaseImage( &image ); + g_tyzx_refcount--; + if(g_tyzx_refcount==0){ + delete g_tyzx_camera; + } + } +} + +bool CvCaptureCAM_TYZX::grabFrame() +{ + return isOpened() && g_tyzx_camera && g_tyzx_camera->grab(); +} + +bool CvCaptureCAM_TYZX::allocateImage() +{ + int depth, nch; + CvSize size; + + // assume we want to resize + cvReleaseImage(&image); + + // figure out size depending on index provided + switch(index){ + case CV_TYZX_RIGHT: + size = cvSize(g_tyzx_camera->intensityWidth(), g_tyzx_camera->intensityHeight()); + depth = 8; + nch = 1; + break; + case CV_TYZX_Z: + size = cvSize(g_tyzx_camera->zWidth(), g_tyzx_camera->zHeight()); + depth = IPL_DEPTH_16S; + nch = 1; + break; + case CV_TYZX_LEFT: + default: + size = cvSize(g_tyzx_camera->intensityWidth(), g_tyzx_camera->intensityHeight()); + depth = 8; + nch = 1; + break; + } + image = cvCreateImage(size, depth, nch); + return image != 0; +} + +/// Copy 'grabbed' image into capture buffer and return it. +IplImage * CvCaptureCAM_TYZX::retrieveFrame(int) +{ + if(!isOpened() || !g_tyzx_camera) return 0; + + if(!image && !alocateImage()) + return 0; + + // copy camera image into buffer. + // tempting to reference TYZX memory directly to avoid copying. + switch (index) + { + case CV_TYZX_RIGHT: + memcpy(image->imageData, g_tyzx_camera->getRImage(), image->imageSize); + break; + case CV_TYZX_Z: + memcpy(image->imageData, g_tyzx_camera->getZImage(), image->imageSize); + break; + case CV_TYZX_LEFT: + default: + memcpy(image->imageData, g_tyzx_camera->getLImage(), image->imageSize); + break; + } + + return image; +} + +double CvCaptureCAM_TYZX::getProperty(int property_id) +{ + CvSize size; + switch(capture->index) + { + case CV_TYZX_LEFT: + size = cvSize(g_tyzx_camera->intensityWidth(), g_tyzx_camera->intensityHeight()); + break; + case CV_TYZX_RIGHT: + size = cvSize(g_tyzx_camera->intensityWidth(), g_tyzx_camera->intensityHeight()); + break; + case CV_TYZX_Z: + size = cvSize(g_tyzx_camera->zWidth(), g_tyzx_camera->zHeight()); + break; + default: + size = cvSize(0,0); + } + + switch( property_id ) + { + case CV_CAP_PROP_FRAME_WIDTH: + return size.width; + case CV_CAP_PROP_FRAME_HEIGHT: + return size.height; + } + + return 0; +} + +bool CvCaptureCAM_TYZX::setProperty( int, double ) +{ + return false; +} + +CvCapture * cvCreateCameraCapture_TYZX (int index) +{ + CvCaptureCAM_TYZX * capture = new CvCaptureCAM_TYZX; + if( capture->open(index) ) + return capture; + + delete capture; + return 0; +} diff --git a/highgui/src/cap_unicap.cpp b/highgui/src/cap_unicap.cpp new file mode 100644 index 0000000..15d96e7 --- /dev/null +++ b/highgui/src/cap_unicap.cpp @@ -0,0 +1,331 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2008, Xavier Delacour, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +// 2008-04-27 Xavier Delacour + +#include "precomp.hpp" +#include +#include +extern "C" { +#include +} + +#ifdef NDEBUG +#define CV_WARN(message) +#else +#define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__) +#endif + +struct CvCapture_Unicap : public CvCapture +{ + CvCapture_Unicap() { init(); } + virtual ~CvCapture_Unicap() { close(); } + + virtual bool open( int index ); + virtual void close(); + + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual int getCaptureDomain() { return CV_CAP_UNICAP; } // Return the type of the capture object: CV_CAP_VFW, etc... + + bool shutdownDevice(); + bool initDevice(); + + void init() + { + device_initialized = false; + desired_format = 0; + desired_size = cvSize(0,0); + convert_rgb = false; + + handle = 0; + memset( &device, 0, sizeof(device) ); + memset( &format_spec, 0, sizeof(format_spec) ); + memset( &format, 0, sizeof(format) ); + memset( &raw_buffer, 0, sizeof(raw_buffer) ); + memset( &buffer, 0, sizeof(buffer) ); + + raw_frame = frame = 0; + } + + bool device_initialized; + + int desired_device; + int desired_format; + CvSize desired_size; + bool convert_rgb; + + unicap_handle_t handle; + unicap_device_t device; + unicap_format_t format_spec; + unicap_format_t format; + unicap_data_buffer_t raw_buffer; + unicap_data_buffer_t buffer; + + IplImage *raw_frame; + IplImage *frame; +}; + +bool CvCapture_Unicap::shutdownDevice() { + bool result = false; + CV_FUNCNAME("CvCapture_Unicap::shutdownDevice"); + __BEGIN__; + + if (!SUCCESS(unicap_stop_capture(handle))) + CV_ERROR(CV_StsError, "unicap: failed to stop capture on device\n"); + + if (!SUCCESS(unicap_close(handle))) + CV_ERROR(CV_StsError, "unicap: failed to close the device\n"); + + cvReleaseImage(&raw_frame); + cvReleaseImage(&frame); + + device_initialized = false; + + result = true; + __END__; + return result; +} + +bool CvCapture_Unicap::initDevice() { + bool result = false; + CV_FUNCNAME("CvCapture_Unicap::initDevice"); + __BEGIN__; + + if (device_initialized && !shutdownDevice()) + return false; + + if(!SUCCESS(unicap_enumerate_devices(NULL, &device, desired_device))) + CV_ERROR(CV_StsError, "unicap: failed to get info for device\n"); + + if(!SUCCESS(unicap_open( &handle, &device))) + CV_ERROR(CV_StsError, "unicap: failed to open device\n"); + + unicap_void_format(&format_spec); + + if (!SUCCESS(unicap_enumerate_formats(handle, &format_spec, &format, desired_format))) { + shutdownDevice(); + CV_ERROR(CV_StsError, "unicap: failed to get video format\n"); + } + + int i; + if (format.sizes) + { + for (i = format.size_count - 1; i > 0; i--) + if (format.sizes[i].width == desired_size.width && + format.sizes[i].height == desired_size.height) + break; + format.size.width = format.sizes[i].width; + format.size.height = format.sizes[i].height; + } + + if (!SUCCESS(unicap_set_format(handle, &format))) { + shutdownDevice(); + CV_ERROR(CV_StsError, "unicap: failed to set video format\n"); + } + + memset(&raw_buffer, 0x0, sizeof(unicap_data_buffer_t)); + raw_frame = cvCreateImage(cvSize(format.size.width, + format.size.height), + 8, format.bpp / 8); + memcpy(&raw_buffer.format, &format, sizeof(raw_buffer.format)); + raw_buffer.data = (unsigned char*)raw_frame->imageData; + raw_buffer.buffer_size = format.size.width * + format.size.height * format.bpp / 8; + + memset(&buffer, 0x0, sizeof(unicap_data_buffer_t)); + memcpy(&buffer.format, &format, sizeof(buffer.format)); + + buffer.format.fourcc = UCIL_FOURCC('B','G','R','3'); + buffer.format.bpp = 24; + // * todo support greyscale output + // buffer.format.fourcc = UCIL_FOURCC('G','R','E','Y'); + // buffer.format.bpp = 8; + + frame = cvCreateImage(cvSize(buffer.format.size.width, + buffer.format.size.height), + 8, buffer.format.bpp / 8); + buffer.data = (unsigned char*)frame->imageData; + buffer.buffer_size = buffer.format.size.width * + buffer.format.size.height * buffer.format.bpp / 8; + + if(!SUCCESS(unicap_start_capture(handle))) { + shutdownDevice(); + CV_ERROR(CV_StsError, "unicap: failed to start capture on device\n"); + } + + device_initialized = true; + result = true; + __END__; + return result; +} + +void CvCapture_Unicap::close() { + if(device_initialized) + shutdownDevice(); +} + +bool CvCapture_Unicap::grabFrame() { + bool result = false; + + CV_FUNCNAME("CvCapture_Unicap::grabFrame"); + __BEGIN__; + + unicap_data_buffer_t *returned_buffer; + + int retry_count = 100; + + while (retry_count--) { + if(!SUCCESS(unicap_queue_buffer(handle, &raw_buffer))) + CV_ERROR(CV_StsError, "unicap: failed to queue a buffer on device\n"); + + if(SUCCESS(unicap_wait_buffer(handle, &returned_buffer))) + { + result = true; + EXIT; + } + + CV_WARN("unicap: failed to wait for buffer on device\n"); + usleep(100 * 1000); + } + + __END__; + return result; +} + +IplImage * CvCapture_Unicap::retrieveFrame(int) { + if (convert_rgb) { + ucil_convert_buffer(&buffer, &raw_buffer); + return frame; + } + return raw_frame; +} + +double CvCapture_Unicap::getProperty(int id) { + switch (id) { + case CV_CAP_PROP_POS_MSEC: break; + case CV_CAP_PROP_POS_FRAMES: break; + case CV_CAP_PROP_POS_AVI_RATIO: break; + case CV_CAP_PROP_FRAME_WIDTH: + return desired_size.width; + case CV_CAP_PROP_FRAME_HEIGHT: + return desired_size.height; + case CV_CAP_PROP_FPS: break; + case CV_CAP_PROP_FOURCC: break; + case CV_CAP_PROP_FRAME_COUNT: break; + case CV_CAP_PROP_FORMAT: + return desired_format; + case CV_CAP_PROP_MODE: break; + case CV_CAP_PROP_BRIGHTNESS: break; + case CV_CAP_PROP_CONTRAST: break; + case CV_CAP_PROP_SATURATION: break; + case CV_CAP_PROP_HUE: break; + case CV_CAP_PROP_GAIN: break; + case CV_CAP_PROP_CONVERT_RGB: + return convert_rgb; + } + + return 0; +} + +bool CvCapture_Unicap::setProperty(int id, double value) { + bool reinit = false; + + switch (id) { + case CV_CAP_PROP_POS_MSEC: break; + case CV_CAP_PROP_POS_FRAMES: break; + case CV_CAP_PROP_POS_AVI_RATIO: break; + case CV_CAP_PROP_FRAME_WIDTH: + desired_size.width = (int)value; + reinit = true; + break; + case CV_CAP_PROP_FRAME_HEIGHT: + desired_size.height = (int)value; + reinit = true; + break; + case CV_CAP_PROP_FPS: break; + case CV_CAP_PROP_FOURCC: break; + case CV_CAP_PROP_FRAME_COUNT: break; + case CV_CAP_PROP_FORMAT: + desired_format = id; + reinit = true; + break; + case CV_CAP_PROP_MODE: break; + case CV_CAP_PROP_BRIGHTNESS: break; + case CV_CAP_PROP_CONTRAST: break; + case CV_CAP_PROP_SATURATION: break; + case CV_CAP_PROP_HUE: break; + case CV_CAP_PROP_GAIN: break; + case CV_CAP_PROP_CONVERT_RGB: + convert_rgb = value != 0; + break; + } + + if (reinit && !initDevice()) + return false; + + return true; +} + +bool CvCapture_Unicap::open(int index) +{ + close(); + device_initialized = false; + + desired_device = index < 0 ? 0 : index; + desired_format = 0; + desired_size = cvSize(320, 240); + convert_rgb = true; + + return initDevice(); +} + + +CvCapture * cvCreateCameraCapture_Unicap(const int index) +{ + CvCapture_Unicap *cap = new CvCapture_Unicap; + if( cap->open(index) ) + return cap; + delete cap; + return 0; +} diff --git a/highgui/src/cap_v4l.cpp b/highgui/src/cap_v4l.cpp new file mode 100644 index 0000000..b970fa0 --- /dev/null +++ b/highgui/src/cap_v4l.cpp @@ -0,0 +1,2861 @@ +/* This is the contributed code: + +File: cvcap_v4l.cpp +Current Location: ../opencv-0.9.6/otherlibs/highgui + +Original Version: 2003-03-12 Magnus Lundin lundin@mlu.mine.nu +Original Comments: + +ML:This set of files adds support for firevre and usb cameras. +First it tries to install a firewire camera, +if that fails it tries a v4l/USB camera +It has been tested with the motempl sample program + +First Patch: August 24, 2004 Travis Wood TravisOCV@tkwood.com +For Release: OpenCV-Linux Beta4 opencv-0.9.6 +Tested On: LMLBT44 with 8 video inputs +Problems? Post problems/fixes to OpenCV group on groups.yahoo.com +Patched Comments: + +TW: The cv cam utils that came with the initial release of OpenCV for LINUX Beta4 +were not working. I have rewritten them so they work for me. At the same time, trying +to keep the original code as ML wrote it as unchanged as possible. No one likes to debug +someone elses code, so I resisted changes as much as possible. I have tried to keep the +same "ideas" where applicable, that is, where I could figure out what the previous author +intended. Some areas I just could not help myself and had to "spiffy-it-up" my way. + +These drivers should work with other V4L frame capture cards other then my bttv +driven frame capture card. + +Re Written driver for standard V4L mode. Tested using LMLBT44 video capture card. +Standard bttv drivers are on the LMLBT44 with up to 8 Inputs. + +This utility was written with the help of the document: +http://pages.cpsc.ucalgary.ca/~sayles/VFL_HowTo +as a general guide for interfacing into the V4l standard. + +Made the index value passed for icvOpenCAM_V4L(index) be the number of the +video device source in the /dev tree. The -1 uses original /dev/video. + +Index Device + 0 /dev/video0 + 1 /dev/video1 + 2 /dev/video2 + 3 /dev/video3 + ... + 7 /dev/video7 +with + -1 /dev/video + +TW: You can select any video source, but this package was limited from the start to only +ONE camera opened at any ONE time. +This is an original program limitation. +If you are interested, I will make my version available to other OpenCV users. The big +difference in mine is you may pass the camera number as part of the cv argument, but this +convention is non standard for current OpenCV calls and the camera number is not currently +passed into the called routine. + +Second Patch: August 28, 2004 Sfuncia Fabio fiblan@yahoo.it +For Release: OpenCV-Linux Beta4 Opencv-0.9.6 + +FS: this patch fix not sequential index of device (unplugged device), and real numCameras. + for -1 index (icvOpenCAM_V4L) i dont use /dev/video but real device available, because + if /dev/video is a link to /dev/video0 and i unplugged device on /dev/video0, /dev/video + is a bad link. I search the first available device with indexList. + +Third Patch: December 9, 2004 Frederic Devernay Frederic.Devernay@inria.fr +For Release: OpenCV-Linux Beta4 Opencv-0.9.6 + +[FD] I modified the following: + - handle YUV420P, YUV420, and YUV411P palettes (for many webcams) without using floating-point + - cvGrabFrame should not wait for the end of the first frame, and should return quickly + (see highgui doc) + - cvRetrieveFrame should in turn wait for the end of frame capture, and should not + trigger the capture of the next frame (the user choses when to do it using GrabFrame) + To get the old behavior, re-call cvRetrieveFrame just after cvGrabFrame. + - having global bufferIndex and FirstCapture variables makes the code non-reentrant + (e.g. when using several cameras), put these in the CvCapture struct. + - according to V4L HowTo, incrementing the buffer index must be done before VIDIOCMCAPTURE. + - the VID_TYPE_SCALES stuff from V4L HowTo is wrong: image size can be changed + even if the hardware does not support scaling (e.g. webcams can have several + resolutions available). Just don't try to set the size at 640x480 if the hardware supports + scaling: open with the default (probably best) image size, and let the user scale it + using SetProperty. + - image size can be changed by two subsequent calls to SetProperty (for width and height) + - bug fix: if the image size changes, realloc the new image only when it is grabbed + - issue errors only when necessary, fix error message formatting. + +Fourth Patch: Sept 7, 2005 Csaba Kertesz sign@freemail.hu +For Release: OpenCV-Linux Beta5 OpenCV-0.9.7 + +I modified the following: + - Additional Video4Linux2 support :) + - Use mmap functions (v4l2) + - New methods are internal: + try_palette_v4l2 -> rewrite try_palette for v4l2 + mainloop_v4l2, read_image_v4l2 -> this methods are moved from official v4l2 capture.c example + try_init_v4l -> device v4l initialisation + try_init_v4l2 -> device v4l2 initialisation + autosetup_capture_mode_v4l -> autodetect capture modes for v4l + autosetup_capture_mode_v4l2 -> autodetect capture modes for v4l2 + - Modifications are according with Video4Linux old codes + - Video4Linux handling is automatically if it does not recognize a Video4Linux2 device + - Tested succesful with Logitech Quickcam Express (V4L), Creative Vista (V4L) and Genius VideoCam Notebook (V4L2) + - Correct source lines with compiler warning messages + - Information message from v4l/v4l2 detection + +Fifth Patch: Sept 7, 2005 Csaba Kertesz sign@freemail.hu +For Release: OpenCV-Linux Beta5 OpenCV-0.9.7 + +I modified the following: + - SN9C10x chip based webcams support + - New methods are internal: + bayer2rgb24, sonix_decompress -> decoder routines for SN9C10x decoding from Takafumi Mizuno with his pleasure :) + - Tested succesful with Genius VideoCam Notebook (V4L2) + +Sixth Patch: Sept 10, 2005 Csaba Kertesz sign@freemail.hu +For Release: OpenCV-Linux Beta5 OpenCV-0.9.7 + +I added the following: + - Add capture control support (hue, saturation, brightness, contrast, gain) + - Get and change V4L capture controls (hue, saturation, brightness, contrast) + - New method is internal: + icvSetControl -> set capture controls + - Tested succesful with Creative Vista (V4L) + +Seventh Patch: Sept 10, 2005 Csaba Kertesz sign@freemail.hu +For Release: OpenCV-Linux Beta5 OpenCV-0.9.7 + +I added the following: + - Detect, get and change V4L2 capture controls (hue, saturation, brightness, contrast, gain) + - New methods are internal: + v4l2_scan_controls_enumerate_menu, v4l2_scan_controls -> detect capture control intervals + - Tested succesful with Genius VideoCam Notebook (V4L2) + +8th patch: Jan 5, 2006, Olivier.Bornet@idiap.ch +Add support of V4L2_PIX_FMT_YUYV and V4L2_PIX_FMT_MJPEG. +With this patch, new webcams of Logitech, like QuickCam Fusion works. +Note: For use these webcams, look at the UVC driver at +http://linux-uvc.berlios.de/ + +9th patch: Mar 4, 2006, Olivier.Bornet@idiap.ch +- try V4L2 before V4L, because some devices are V4L2 by default, + but they try to implement the V4L compatibility layer. + So, I think this is better to support V4L2 before V4L. +- better separation between V4L2 and V4L initialization. (this was needed to support + some drivers working, but not fully with V4L2. (so, we do not know when we + need to switch from V4L2 to V4L. + +10th patch: July 02, 2008, Mikhail Afanasyev fopencv@theamk.com +Fix reliability problems with high-resolution UVC cameras on linux +the symptoms were damaged image and 'Corrupt JPEG data: premature end of data segment' on stderr +- V4L_ABORT_BADJPEG detects JPEG warnings and turns them into errors, so bad images + could be filtered out +- USE_TEMP_BUFFER fixes the main problem (improper buffer management) and + prevents bad images in the first place + + +make & enjoy! + +*/ + +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#if !defined WIN32 && defined HAVE_CAMV4L && defined HAVE_CAMV4L2 + +#define CLEAR(x) memset (&(x), 0, sizeof (x)) + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include /* for videodev2.h */ +#include +#include +#include + +#ifdef HAVE_CAMV4L2 +#include +#endif + +/* Defaults - If your board can do better, set it here. Set for the most common type inputs. */ +#define DEFAULT_V4L_WIDTH 640 +#define DEFAULT_V4L_HEIGHT 480 + +#define CHANNEL_NUMBER 1 +#define MAX_CAMERAS 8 + + +// default and maximum number of V4L buffers, not including last, 'special' buffer +#define MAX_V4L_BUFFERS 10 +#define DEFAULT_V4L_BUFFERS 4 + +// if enabled, then bad JPEG warnings become errors and cause NULL returned instead of image +#define V4L_ABORT_BADJPEG + +#define MAX_DEVICE_DRIVER_NAME 80 + +/* Device Capture Objects */ + +#ifdef HAVE_CAMV4L2 + +/* V4L2 structure */ +struct buffer +{ + void * start; + size_t length; +}; + +static unsigned int n_buffers = 0; + +/* Additional V4L2 pixelformats support for Sonix SN9C10x base webcams */ +#ifndef V4L2_PIX_FMT_SBGGR8 +#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */ +#endif +#ifndef V4L2_PIX_FMT_SN9C10X +#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S','9','1','0') /* SN9C10x cmpr. */ +#endif + +#ifndef V4L2_PIX_FMT_SGBRG +#define V4L2_PIX_FMT_SGBRG v4l2_fourcc('G','B','R','G') /* bayer GBRG GBGB.. RGRG.. */ +#endif + +#endif /* HAVE_CAMV4L2 */ + +enum PALETTE_TYPE { + PALETTE_BGR24 = 1, + PALETTE_YVU420, + PALETTE_YUV411P, + PALETTE_YUYV, + PALETTE_UYVY, + PALETTE_SBGGR8, + PALETTE_SN9C10X, + PALETTE_MJPEG, + PALETTE_SGBRG +}; + +typedef struct CvCaptureCAM_V4L +{ + int deviceHandle; + int bufferIndex; + int FirstCapture; + struct video_capability capability; + struct video_window captureWindow; + struct video_picture imageProperties; + struct video_mbuf memoryBuffer; + struct video_mmap *mmaps; + char *memoryMap; + IplImage frame; + +#ifdef HAVE_CAMV4L2 + enum PALETTE_TYPE palette; + /* V4L2 variables */ + buffer buffers[MAX_V4L_BUFFERS + 1]; + struct v4l2_capability cap; + struct v4l2_input inp; + struct v4l2_format form; + struct v4l2_crop crop; + struct v4l2_cropcap cropcap; + struct v4l2_requestbuffers req; + struct v4l2_control control; + enum v4l2_buf_type type; + struct v4l2_queryctrl queryctrl; + struct v4l2_querymenu querymenu; + + /* V4L2 control variables */ + int v4l2_brightness, v4l2_brightness_min, v4l2_brightness_max; + int v4l2_contrast, v4l2_contrast_min, v4l2_contrast_max; + int v4l2_saturation, v4l2_saturation_min, v4l2_saturation_max; + int v4l2_hue, v4l2_hue_min, v4l2_hue_max; + int v4l2_gain, v4l2_gain_min, v4l2_gain_max; + int v4l2_exposure, v4l2_exposure_min, v4l2_exposure_max; + +#endif /* HAVE_CAMV4L2 */ + +} +CvCaptureCAM_V4L; + +#ifdef HAVE_CAMV4L2 + +int V4L2_SUPPORT = 0; + +#endif /* HAVE_CAMV4L2 */ + +static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture ); + +static int icvGrabFrameCAM_V4L( CvCaptureCAM_V4L* capture ); +static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int ); + +static double icvGetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id ); +static int icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id, double value ); + +static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h); + +/*********************** Implementations ***************************************/ + +static int numCameras = 0; +static int indexList = 0; + +#ifdef HAVE_CAMV4L2 + +// IOCTL handling for V4L2 +static int xioctl( int fd, int request, void *arg) +{ + + int r; + + + do r = ioctl (fd, request, arg); + while (-1 == r && EINTR == errno); + + return r; + +} + +#endif /* HAVE_CAMV4L2 */ + +/* Simple test program: Find number of Video Sources available. + Start from 0 and go to MAX_CAMERAS while checking for the device with that name. + If it fails on the first attempt of /dev/video0, then check if /dev/video is valid. + Returns the global numCameras with the correct value (we hope) */ + +static void icvInitCapture_V4L() { + int deviceHandle; + int CameraNumber; + char deviceName[MAX_DEVICE_DRIVER_NAME]; + + CameraNumber = 0; + while(CameraNumber < MAX_CAMERAS) { + /* Print the CameraNumber at the end of the string with a width of one character */ + sprintf(deviceName, "/dev/video%1d", CameraNumber); + /* Test using an open to see if this new device name really does exists. */ + deviceHandle = open(deviceName, O_RDONLY); + if (deviceHandle != -1) { + /* This device does indeed exist - add it to the total so far */ + // add indexList + indexList|=(1 << CameraNumber); + numCameras++; + } + if (deviceHandle != -1) + close(deviceHandle); + /* Set up to test the next /dev/video source in line */ + CameraNumber++; + } /* End while */ + +}; /* End icvInitCapture_V4L */ + +static int +try_palette(int fd, + struct video_picture *cam_pic, + int pal, + int depth) +{ + cam_pic->palette = pal; + cam_pic->depth = depth; + if (ioctl(fd, VIDIOCSPICT, cam_pic) < 0) + return 0; + if (ioctl(fd, VIDIOCGPICT, cam_pic) < 0) + return 0; + if (cam_pic->palette == pal) + return 1; + return 0; +} + +#ifdef HAVE_CAMV4L2 + +static int try_palette_v4l2(CvCaptureCAM_V4L* capture, unsigned long colorspace) +{ + CLEAR (capture->form); + + capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + capture->form.fmt.pix.pixelformat = colorspace; + capture->form.fmt.pix.field = V4L2_FIELD_ANY; + capture->form.fmt.pix.width = DEFAULT_V4L_WIDTH; + capture->form.fmt.pix.height = DEFAULT_V4L_HEIGHT; + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form)) + return -1; + + + if (colorspace != capture->form.fmt.pix.pixelformat) + return -1; + else + return 0; +} + +#endif /* HAVE_CAMV4L2 */ + +static int try_init_v4l(CvCaptureCAM_V4L* capture, char *deviceName) +{ + + // if detect = -1 then unable to open device + // if detect = 0 then detected nothing + // if detect = 1 then V4L device + int detect = 0; + + + // Test device for V4L compability + + /* Test using an open to see if this new device name really does exists. */ + /* No matter what the name - it still must be opened! */ + capture->deviceHandle = open(deviceName, O_RDWR); + + + if (capture->deviceHandle == 0) + { + detect = -1; + + icvCloseCAM_V4L(capture); + } + + if (detect == 0) + { + /* Query the newly opened device for its capabilities */ + if (ioctl(capture->deviceHandle, VIDIOCGCAP, &capture->capability) < 0) + { + detect = 0; + + icvCloseCAM_V4L(capture); + } + else + { + detect = 1; + } + } + + return detect; + +} + +#ifdef HAVE_CAMV4L2 + +static int try_init_v4l2(CvCaptureCAM_V4L* capture, char *deviceName) +{ + + // if detect = -1 then unable to open device + // if detect = 0 then detected nothing + // if detect = 1 then V4L2 device + int detect = 0; + + + // Test device for V4L2 compability + + /* Open and test V4L2 device */ + capture->deviceHandle = open (deviceName, O_RDWR /* required */ | O_NONBLOCK, 0); + + + + if (capture->deviceHandle == 0) + { + detect = -1; + + icvCloseCAM_V4L(capture); + } + + if (detect == 0) + { + CLEAR (capture->cap); + if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYCAP, &capture->cap)) + { + detect = 0; + + icvCloseCAM_V4L(capture); + } + else + { + CLEAR (capture->capability); + capture->capability.type = capture->cap.capabilities; + + /* Query channels number */ + if (-1 != xioctl (capture->deviceHandle, VIDIOC_G_INPUT, &capture->capability.channels)) + { + detect = 1; + } + } + } + + return detect; + +} + +static int autosetup_capture_mode_v4l2(CvCaptureCAM_V4L* capture) +{ + if (try_palette_v4l2(capture, V4L2_PIX_FMT_BGR24) == 0) + { + capture->palette = PALETTE_BGR24; + } + else + if (try_palette_v4l2(capture, V4L2_PIX_FMT_YVU420) == 0) + { + capture->palette = PALETTE_YVU420; + } + else + if (try_palette_v4l2(capture, V4L2_PIX_FMT_YUV411P) == 0) + { + capture->palette = PALETTE_YUV411P; + } + else + +#ifdef HAVE_JPEG +#ifdef __USE_GNU + /* support for MJPEG is only available with libjpeg and gcc, + because it's use libjepg and fmemopen() + */ + if (try_palette_v4l2(capture, V4L2_PIX_FMT_MJPEG) == 0 || + try_palette_v4l2(capture, V4L2_PIX_FMT_JPEG) == 0) + { + capture->palette = PALETTE_MJPEG; + } + else +#endif +#endif + + if (try_palette_v4l2(capture, V4L2_PIX_FMT_YUYV) == 0) + { + capture->palette = PALETTE_YUYV; + } + else if (try_palette_v4l2(capture, V4L2_PIX_FMT_UYVY) == 0) + { + capture->palette = PALETTE_UYVY; + } + else + if (try_palette_v4l2(capture, V4L2_PIX_FMT_SN9C10X) == 0) + { + capture->palette = PALETTE_SN9C10X; + } else + if (try_palette_v4l2(capture, V4L2_PIX_FMT_SBGGR8) == 0) + { + capture->palette = PALETTE_SBGGR8; + } else + if (try_palette_v4l2(capture, V4L2_PIX_FMT_SGBRG) == 0) + { + capture->palette = PALETTE_SGBRG; + } + else + { + fprintf(stderr, "HIGHGUI ERROR: V4L2: Pixel format of incoming image is unsupported by OpenCV\n"); + icvCloseCAM_V4L(capture); + return -1; + } + + return 0; + +} + +#endif /* HAVE_CAMV4L2 */ + +static int autosetup_capture_mode_v4l(CvCaptureCAM_V4L* capture) +{ + + if(ioctl(capture->deviceHandle, VIDIOCGPICT, &capture->imageProperties) < 0) { + fprintf( stderr, "HIGHGUI ERROR: V4L: Unable to determine size of incoming image\n"); + icvCloseCAM_V4L(capture); + return -1; + } + + /* Yet MORE things that might have to be changes with your frame capture card */ + /* This sets the scale to the center of a 2^16 number */ + if (try_palette(capture->deviceHandle, &capture->imageProperties, VIDEO_PALETTE_RGB24, 24)) { + //printf("negotiated palette RGB24\n"); + } + else if (try_palette(capture->deviceHandle, &capture->imageProperties, VIDEO_PALETTE_YUV420P, 16)) { + //printf("negotiated palette YUV420P\n"); + } + else if (try_palette(capture->deviceHandle, &capture->imageProperties, VIDEO_PALETTE_YUV420, 16)) { + //printf("negotiated palette YUV420\n"); + } + else if (try_palette(capture->deviceHandle, &capture->imageProperties, VIDEO_PALETTE_YUV411P, 16)) { + //printf("negotiated palette YUV420P\n"); + } + else { + fprintf(stderr, "HIGHGUI ERROR: V4L: Pixel format of incoming image is unsupported by OpenCV\n"); + icvCloseCAM_V4L(capture); + return -1; + } + + return 0; + +} + +#ifdef HAVE_CAMV4L2 + +static void v4l2_scan_controls_enumerate_menu(CvCaptureCAM_V4L* capture) +{ +// printf (" Menu items:\n"); + CLEAR (capture->querymenu); + capture->querymenu.id = capture->queryctrl.id; + for (capture->querymenu.index = capture->queryctrl.minimum; + (int)capture->querymenu.index <= capture->queryctrl.maximum; + capture->querymenu.index++) + { + if (0 == xioctl (capture->deviceHandle, VIDIOC_QUERYMENU, + &capture->querymenu)) + { +// printf (" %s\n", capture->querymenu.name); + } else { + perror ("VIDIOC_QUERYMENU"); + } + } +} + +static void v4l2_scan_controls(CvCaptureCAM_V4L* capture) +{ + + __u32 ctrl_id; + + for (ctrl_id = V4L2_CID_BASE; + ctrl_id < V4L2_CID_LASTP1; + ctrl_id++) + { + + /* set the id we will query now */ + CLEAR (capture->queryctrl); + capture->queryctrl.id = ctrl_id; + + if (0 == xioctl (capture->deviceHandle, VIDIOC_QUERYCTRL, + &capture->queryctrl)) + { + + if (capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) + continue; + + if (capture->queryctrl.id == V4L2_CID_BRIGHTNESS) + { + capture->v4l2_brightness = 1; + capture->v4l2_brightness_min = capture->queryctrl.minimum; + capture->v4l2_brightness_max = capture->queryctrl.maximum; + } + + if (capture->queryctrl.id == V4L2_CID_CONTRAST) + { + capture->v4l2_contrast = 1; + capture->v4l2_contrast_min = capture->queryctrl.minimum; + capture->v4l2_contrast_max = capture->queryctrl.maximum; + } + + if (capture->queryctrl.id == V4L2_CID_SATURATION) + { + capture->v4l2_saturation = 1; + capture->v4l2_saturation_min = capture->queryctrl.minimum; + capture->v4l2_saturation_max = capture->queryctrl.maximum; + } + + if (capture->queryctrl.id == V4L2_CID_HUE) + { + capture->v4l2_hue = 1; + capture->v4l2_hue_min = capture->queryctrl.minimum; + capture->v4l2_hue_max = capture->queryctrl.maximum; + } + + if (capture->queryctrl.id == V4L2_CID_GAIN) + { + capture->v4l2_gain = 1; + capture->v4l2_gain_min = capture->queryctrl.minimum; + capture->v4l2_gain_max = capture->queryctrl.maximum; + } + + if (capture->queryctrl.id == V4L2_CID_EXPOSURE) + { + capture->v4l2_exposure = 1; + capture->v4l2_exposure_min = capture->queryctrl.minimum; + capture->v4l2_exposure_max = capture->queryctrl.maximum; + } + + if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU) + v4l2_scan_controls_enumerate_menu(capture); + + } else { + + if (errno == EINVAL) + continue; + + perror ("VIDIOC_QUERYCTRL"); + + } + + } + + for (ctrl_id = V4L2_CID_PRIVATE_BASE;;ctrl_id++) + { + + /* set the id we will query now */ + CLEAR (capture->queryctrl); + capture->queryctrl.id = ctrl_id; + + if (0 == xioctl (capture->deviceHandle, VIDIOC_QUERYCTRL, + &capture->queryctrl)) + { + + if (capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) + continue; + + if (capture->queryctrl.id == V4L2_CID_BRIGHTNESS) + { + capture->v4l2_brightness = 1; + capture->v4l2_brightness_min = capture->queryctrl.minimum; + capture->v4l2_brightness_max = capture->queryctrl.maximum; + } + + if (capture->queryctrl.id == V4L2_CID_CONTRAST) + { + capture->v4l2_contrast = 1; + capture->v4l2_contrast_min = capture->queryctrl.minimum; + capture->v4l2_contrast_max = capture->queryctrl.maximum; + } + + if (capture->queryctrl.id == V4L2_CID_SATURATION) + { + capture->v4l2_saturation = 1; + capture->v4l2_saturation_min = capture->queryctrl.minimum; + capture->v4l2_saturation_max = capture->queryctrl.maximum; + } + + if (capture->queryctrl.id == V4L2_CID_HUE) + { + capture->v4l2_hue = 1; + capture->v4l2_hue_min = capture->queryctrl.minimum; + capture->v4l2_hue_max = capture->queryctrl.maximum; + } + + if (capture->queryctrl.id == V4L2_CID_GAIN) + { + capture->v4l2_gain = 1; + capture->v4l2_gain_min = capture->queryctrl.minimum; + capture->v4l2_gain_max = capture->queryctrl.maximum; + } + + if (capture->queryctrl.id == V4L2_CID_EXPOSURE) + { + capture->v4l2_exposure = 1; + capture->v4l2_exposure_min = capture->queryctrl.minimum; + capture->v4l2_exposure_max = capture->queryctrl.maximum; + } + + if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU) + v4l2_scan_controls_enumerate_menu(capture); + + } else { + + if (errno == EINVAL) + break; + + perror ("VIDIOC_QUERYCTRL"); + + } + + } + +} + +static int _capture_V4L2 (CvCaptureCAM_V4L *capture, char *deviceName) +{ + int detect_v4l2 = 0; + + detect_v4l2 = try_init_v4l2(capture, deviceName); + + if (detect_v4l2 != 1) { + /* init of the v4l2 device is not OK */ + return -1; + } + + /* starting from here, we assume we are in V4L2 mode */ + V4L2_SUPPORT = 1; + + /* Init V4L2 control variables */ + capture->v4l2_brightness = 0; + capture->v4l2_contrast = 0; + capture->v4l2_saturation = 0; + capture->v4l2_hue = 0; + capture->v4l2_gain = 0; + capture->v4l2_exposure = 0; + + capture->v4l2_brightness_min = 0; + capture->v4l2_contrast_min = 0; + capture->v4l2_saturation_min = 0; + capture->v4l2_hue_min = 0; + capture->v4l2_gain_min = 0; + capture->v4l2_exposure_min = 0; + + capture->v4l2_brightness_max = 0; + capture->v4l2_contrast_max = 0; + capture->v4l2_saturation_max = 0; + capture->v4l2_hue_max = 0; + capture->v4l2_gain_max = 0; + capture->v4l2_exposure_max = 0; + + /* Scan V4L2 controls */ + v4l2_scan_controls(capture); + + if ((capture->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { + /* Nope. */ + fprintf( stderr, "HIGHGUI ERROR: V4L2: device %s is unable to capture video memory.\n",deviceName); + icvCloseCAM_V4L(capture); + return -1; + } + + /* The following code sets the CHANNEL_NUMBER of the video input. Some video sources + have sub "Channel Numbers". For a typical V4L TV capture card, this is usually 1. + I myself am using a simple NTSC video input capture card that uses the value of 1. + If you are not in North America or have a different video standard, you WILL have to change + the following settings and recompile/reinstall. This set of settings is based on + the most commonly encountered input video source types (like my bttv card) */ + + if(capture->inp.index > 0) { + CLEAR (capture->inp); + capture->inp.index = CHANNEL_NUMBER; + /* Set only channel number to CHANNEL_NUMBER */ + /* V4L2 have a status field from selected video mode */ + if (-1 == xioctl (capture->deviceHandle, VIDIOC_ENUMINPUT, &capture->inp)) + { + fprintf (stderr, "HIGHGUI ERROR: V4L2: Aren't able to set channel number\n"); + icvCloseCAM_V4L (capture); + return -1; + } + } /* End if */ + + /* Find Window info */ + CLEAR (capture->form); + capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) { + fprintf( stderr, "HIGHGUI ERROR: V4L2: Could not obtain specifics of capture window.\n\n"); + icvCloseCAM_V4L(capture); + return -1; + } + + if (V4L2_SUPPORT == 0) + { + } + + if (autosetup_capture_mode_v4l2(capture) == -1) + return -1; + + icvSetVideoSize(capture, DEFAULT_V4L_WIDTH, DEFAULT_V4L_HEIGHT); + + unsigned int min; + + /* Buggy driver paranoia. */ + min = capture->form.fmt.pix.width * 2; + + if (capture->form.fmt.pix.bytesperline < min) + capture->form.fmt.pix.bytesperline = min; + + min = capture->form.fmt.pix.bytesperline * capture->form.fmt.pix.height; + + if (capture->form.fmt.pix.sizeimage < min) + capture->form.fmt.pix.sizeimage = min; + + CLEAR (capture->req); + + unsigned int buffer_number = DEFAULT_V4L_BUFFERS; + + try_again: + + capture->req.count = buffer_number; + capture->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + capture->req.memory = V4L2_MEMORY_MMAP; + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_REQBUFS, &capture->req)) + { + if (EINVAL == errno) + { + fprintf (stderr, "%s does not support memory mapping\n", deviceName); + } else { + perror ("VIDIOC_REQBUFS"); + } + /* free capture, and returns an error code */ + icvCloseCAM_V4L (capture); + return -1; + } + + if (capture->req.count < buffer_number) + { + if (buffer_number == 1) + { + fprintf (stderr, "Insufficient buffer memory on %s\n", deviceName); + + /* free capture, and returns an error code */ + icvCloseCAM_V4L (capture); + return -1; + } else { + buffer_number--; + fprintf (stderr, "Insufficient buffer memory on %s -- decreaseing buffers\n", deviceName); + + goto try_again; + } + } + + for (n_buffers = 0; n_buffers < capture->req.count; ++n_buffers) + { + struct v4l2_buffer buf; + + CLEAR (buf); + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = n_buffers; + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYBUF, &buf)) { + perror ("VIDIOC_QUERYBUF"); + + /* free capture, and returns an error code */ + icvCloseCAM_V4L (capture); + return -1; + } + + capture->buffers[n_buffers].length = buf.length; + capture->buffers[n_buffers].start = + mmap (NULL /* start anywhere */, + buf.length, + PROT_READ | PROT_WRITE /* required */, + MAP_SHARED /* recommended */, + capture->deviceHandle, buf.m.offset); + + if (MAP_FAILED == capture->buffers[n_buffers].start) { + perror ("mmap"); + + /* free capture, and returns an error code */ + icvCloseCAM_V4L (capture); + return -1; + } + + if (n_buffers == 0) { + capture->buffers[MAX_V4L_BUFFERS].start = malloc( buf.length ); + capture->buffers[MAX_V4L_BUFFERS].length = buf.length; + } + } + + /* Set up Image data */ + cvInitImageHeader( &capture->frame, + cvSize( capture->captureWindow.width, + capture->captureWindow.height ), + IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 ); + /* Allocate space for RGBA data */ + capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize); + + return 1; +}; /* End _capture_V4L2 */ + +#endif /* HAVE_CAMV4L2 */ + +static int _capture_V4L (CvCaptureCAM_V4L *capture, char *deviceName) +{ + int detect_v4l = 0; + + detect_v4l = try_init_v4l(capture, deviceName); + + if ((detect_v4l == -1) + ) + { + fprintf (stderr, "HIGHGUI ERROR: V4L" + ": device %s: Unable to open for READ ONLY\n", deviceName); + + return -1; + } + + if ((detect_v4l <= 0) + ) + { + fprintf (stderr, "HIGHGUI ERROR: V4L" + ": device %s: Unable to query number of channels\n", deviceName); + + return -1; + } + + { + if ((capture->capability.type & VID_TYPE_CAPTURE) == 0) { + /* Nope. */ + fprintf( stderr, "HIGHGUI ERROR: V4L: " + "device %s is unable to capture video memory.\n",deviceName); + icvCloseCAM_V4L(capture); + return -1; + } + + } + + + /* The following code sets the CHANNEL_NUMBER of the video input. Some video sources + have sub "Channel Numbers". For a typical V4L TV capture card, this is usually 1. + I myself am using a simple NTSC video input capture card that uses the value of 1. + If you are not in North America or have a different video standard, you WILL have to change + the following settings and recompile/reinstall. This set of settings is based on + the most commonly encountered input video source types (like my bttv card) */ + + { + + if(capture->capability.channels>0) { + + struct video_channel selectedChannel; + memset(&selectedChannel, 0, sizeof(selectedChannel)); + + selectedChannel.channel=CHANNEL_NUMBER; + if (ioctl(capture->deviceHandle, VIDIOCGCHAN , &selectedChannel) != -1) { + /* set the video mode to ( VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM) */ +// selectedChannel.norm = VIDEO_MODE_NTSC; + if (ioctl(capture->deviceHandle, VIDIOCSCHAN , &selectedChannel) == -1) { + /* Could not set selected channel - Oh well */ + //printf("\n%d, %s not NTSC capable.\n",selectedChannel.channel, selectedChannel.name); + } /* End if */ + } /* End if */ + } /* End if */ + + } + + { + + if(ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) == -1) { + fprintf( stderr, "HIGHGUI ERROR: V4L: " + "Could not obtain specifics of capture window.\n\n"); + icvCloseCAM_V4L(capture); + return -1; + } + + } + + { + + if (autosetup_capture_mode_v4l(capture) == -1) + return -1; + + } + + { + + ioctl(capture->deviceHandle, VIDIOCGMBUF, &capture->memoryBuffer); + capture->memoryMap = (char *)mmap(0, + capture->memoryBuffer.size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + capture->deviceHandle, + 0); + if (capture->memoryMap == MAP_FAILED) { + fprintf( stderr, "HIGHGUI ERROR: V4L: Mapping Memmory from video source error: %s\n", strerror(errno)); + icvCloseCAM_V4L(capture); + } + + /* Set up video_mmap structure pointing to this memory mapped area so each image may be + retrieved from an index value */ + capture->mmaps = (struct video_mmap *) + (malloc(capture->memoryBuffer.frames * sizeof(struct video_mmap))); + if (!capture->mmaps) { + fprintf( stderr, "HIGHGUI ERROR: V4L: Could not memory map video frames.\n"); + icvCloseCAM_V4L(capture); + return -1; + } + + } + + /* Set up Image data */ + cvInitImageHeader( &capture->frame, + cvSize( capture->captureWindow.width, + capture->captureWindow.height ), + IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 ); + /* Allocate space for RGBA data */ + capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize); + + return 1; +}; /* End _capture_V4L */ + +static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (int index) +{ + static int autoindex; + autoindex = 0; + + char deviceName[MAX_DEVICE_DRIVER_NAME]; + + if (!numCameras) + icvInitCapture_V4L(); /* Havent called icvInitCapture yet - do it now! */ + if (!numCameras) + return NULL; /* Are there any /dev/video input sources? */ + + //search index in indexList + if ( (index>-1) && ! ((1 << index) & indexList) ) + { + fprintf( stderr, "HIGHGUI ERROR: V4L: index %d is not correct!\n",index); + return NULL; /* Did someone ask for not correct video source number? */ + } + /* Allocate memory for this humongus CvCaptureCAM_V4L structure that contains ALL + the handles for V4L processing */ + CvCaptureCAM_V4L * capture = (CvCaptureCAM_V4L*)cvAlloc(sizeof(CvCaptureCAM_V4L)); + if (!capture) { + fprintf( stderr, "HIGHGUI ERROR: V4L: Could not allocate memory for capture process.\n"); + return NULL; + } + /* Select camera, or rather, V4L video source */ + if (index<0) { // Asking for the first device available + for (; autoindexFirstCapture = 1; + +#ifdef HAVE_CAMV4L2 + if (_capture_V4L2 (capture, deviceName) == -1) { + icvCloseCAM_V4L(capture); + V4L2_SUPPORT = 0; +#endif /* HAVE_CAMV4L2 */ + if (_capture_V4L (capture, deviceName) == -1) { + icvCloseCAM_V4L(capture); + return NULL; + } +#ifdef HAVE_CAMV4L2 + } else { + V4L2_SUPPORT = 1; + } +#endif /* HAVE_CAMV4L2 */ + + return capture; +}; /* End icvOpenCAM_V4L */ + +#ifdef HAVE_CAMV4L2 + +static int read_frame_v4l2(CvCaptureCAM_V4L* capture) { + struct v4l2_buffer buf; + + CLEAR (buf); + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_DQBUF, &buf)) { + switch (errno) { + case EAGAIN: + return 0; + + case EIO: + if (!(buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) + { + if (xioctl(capture->deviceHandle, VIDIOC_QBUF, &buf) == -1) + { + return 0; + } + } + return 0; + + default: + /* display the error and stop processing */ + perror ("VIDIOC_DQBUF"); + return 1; + } + } + + assert(buf.index < capture->req.count); + + memcpy(capture->buffers[MAX_V4L_BUFFERS].start, + capture->buffers[buf.index].start, + capture->buffers[MAX_V4L_BUFFERS].length ); + capture->bufferIndex = MAX_V4L_BUFFERS; + //printf("got data in buff %d, len=%d, flags=0x%X, seq=%d, used=%d)\n", + // buf.index, buf.length, buf.flags, buf.sequence, buf.bytesused); + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf)) + perror ("VIDIOC_QBUF"); + + return 1; +} + +static void mainloop_v4l2(CvCaptureCAM_V4L* capture) { + unsigned int count; + + count = 1; + + while (count-- > 0) { + for (;;) { + fd_set fds; + struct timeval tv; + int r; + + FD_ZERO (&fds); + FD_SET (capture->deviceHandle, &fds); + + /* Timeout. */ + tv.tv_sec = 2; + tv.tv_usec = 0; + + r = select (capture->deviceHandle+1, &fds, NULL, NULL, &tv); + + if (-1 == r) { + if (EINTR == errno) + continue; + + perror ("select"); + } + + if (0 == r) { + fprintf (stderr, "select timeout\n"); + + /* end the infinite loop */ + break; + } + + if (read_frame_v4l2 (capture)) + break; + } + } +} + +#endif /* HAVE_CAMV4L2 */ + +static int icvGrabFrameCAM_V4L(CvCaptureCAM_V4L* capture) { + + if (capture->FirstCapture) { + /* Some general initialization must take place the first time through */ + + /* This is just a technicality, but all buffers must be filled up before any + staggered SYNC is applied. SO, filler up. (see V4L HowTo) */ + +#ifdef HAVE_CAMV4L2 + + if (V4L2_SUPPORT == 1) + { + + for (capture->bufferIndex = 0; + capture->bufferIndex < ((int)capture->req.count); + ++capture->bufferIndex) + { + + struct v4l2_buffer buf; + + CLEAR (buf); + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = (unsigned long)capture->bufferIndex; + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf)) { + perror ("VIDIOC_QBUF"); + return 0; + } + } + + /* enable the streaming */ + capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl (capture->deviceHandle, VIDIOC_STREAMON, + &capture->type)) { + /* error enabling the stream */ + perror ("VIDIOC_STREAMON"); + return 0; + } + } else +#endif /* HAVE_CAMV4L2 */ + { + + for (capture->bufferIndex = 0; + capture->bufferIndex < (capture->memoryBuffer.frames-1); + ++capture->bufferIndex) { + + capture->mmaps[capture->bufferIndex].frame = capture->bufferIndex; + capture->mmaps[capture->bufferIndex].width = capture->captureWindow.width; + capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height; + capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette; + + if (ioctl(capture->deviceHandle, VIDIOCMCAPTURE, &capture->mmaps[capture->bufferIndex]) == -1) { + fprintf( stderr, "HIGHGUI ERROR: V4L: Initial Capture Error: Unable to load initial memory buffers.\n"); + return 0; + } + } + + } + +#if defined(V4L_ABORT_BADJPEG) && defined(HAVE_CAMV4L2) + if (V4L2_SUPPORT == 1) + { + // skip first frame. it is often bad -- this is unnotied in traditional apps, + // but could be fatal if bad jpeg is enabled + mainloop_v4l2(capture); + } +#endif + + /* preparation is ok */ + capture->FirstCapture = 0; + } + +#ifdef HAVE_CAMV4L2 + + if (V4L2_SUPPORT == 1) + { + + mainloop_v4l2(capture); + + } else +#endif /* HAVE_CAMV4L2 */ + { + + capture->mmaps[capture->bufferIndex].frame = capture->bufferIndex; + capture->mmaps[capture->bufferIndex].width = capture->captureWindow.width; + capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height; + capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette; + + if (ioctl (capture->deviceHandle, VIDIOCMCAPTURE, + &capture->mmaps[capture->bufferIndex]) == -1) { + /* capture is on the way, so just exit */ + return 1; + } + + ++capture->bufferIndex; + if (capture->bufferIndex == capture->memoryBuffer.frames) { + capture->bufferIndex = 0; + } + + } + + return(1); +} + +/* + * Turn a YUV4:2:0 block into an RGB block + * + * Video4Linux seems to use the blue, green, red channel + * order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red. + * + * Color space conversion coefficients taken from the excellent + * http://www.inforamp.net/~poynton/ColorFAQ.html + * In his terminology, this is a CCIR 601.1 YCbCr -> RGB. + * Y values are given for all 4 pixels, but the U (Pb) + * and V (Pr) are assumed constant over the 2x2 block. + * + * To avoid floating point arithmetic, the color conversion + * coefficients are scaled into 16.16 fixed-point integers. + * They were determined as follows: + * + * double brightness = 1.0; (0->black; 1->full scale) + * double saturation = 1.0; (0->greyscale; 1->full color) + * double fixScale = brightness * 256 * 256; + * int rvScale = (int)(1.402 * saturation * fixScale); + * int guScale = (int)(-0.344136 * saturation * fixScale); + * int gvScale = (int)(-0.714136 * saturation * fixScale); + * int buScale = (int)(1.772 * saturation * fixScale); + * int yScale = (int)(fixScale); + */ + +/* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */ +#define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16))) + +static inline void +move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, + int rowPixels, unsigned char * rgb) +{ + const int rvScale = 91881; + const int guScale = -22553; + const int gvScale = -46801; + const int buScale = 116129; + const int yScale = 65536; + int r, g, b; + + g = guScale * u + gvScale * v; +// if (force_rgb) { +// r = buScale * u; +// b = rvScale * v; +// } else { + r = rvScale * v; + b = buScale * u; +// } + + yTL *= yScale; yTR *= yScale; + yBL *= yScale; yBR *= yScale; + + /* Write out top two pixels */ + rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); + rgb[2] = LIMIT(r+yTL); + + rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); + rgb[5] = LIMIT(r+yTR); + + /* Skip down to next line to write out bottom two pixels */ + rgb += 3 * rowPixels; + rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); + rgb[2] = LIMIT(r+yBL); + + rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); + rgb[5] = LIMIT(r+yBR); +} + +static inline void +move_411_block(int yTL, int yTR, int yBL, int yBR, int u, int v, + int rowPixels, unsigned char * rgb) +{ + const int rvScale = 91881; + const int guScale = -22553; + const int gvScale = -46801; + const int buScale = 116129; + const int yScale = 65536; + int r, g, b; + + g = guScale * u + gvScale * v; +// if (force_rgb) { +// r = buScale * u; +// b = rvScale * v; +// } else { + r = rvScale * v; + b = buScale * u; +// } + + yTL *= yScale; yTR *= yScale; + yBL *= yScale; yBR *= yScale; + + /* Write out top two first pixels */ + rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); + rgb[2] = LIMIT(r+yTL); + + rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); + rgb[5] = LIMIT(r+yTR); + + /* Write out top two last pixels */ + rgb += 6; + rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); + rgb[2] = LIMIT(r+yBL); + + rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); + rgb[5] = LIMIT(r+yBR); +} + +// Consider a YUV420P image of 8x2 pixels. +// +// A plane of Y values A B C D E F G H +// I J K L M N O P +// +// A plane of U values 1 2 3 4 +// A plane of V values 1 2 3 4 .... +// +// The U1/V1 samples correspond to the ABIJ pixels. +// U2/V2 samples correspond to the CDKL pixels. +// +/* Converts from planar YUV420P to RGB24. */ +static void +yuv420p_to_rgb24(int width, int height, + unsigned char *pIn0, unsigned char *pOut0) +{ + const int numpix = width * height; + const int bytes = 24 >> 3; + int i, j, y00, y01, y10, y11, u, v; + unsigned char *pY = pIn0; + unsigned char *pU = pY + numpix; + unsigned char *pV = pU + numpix / 4; + unsigned char *pOut = pOut0; + + for (j = 0; j <= height - 2; j += 2) { + for (i = 0; i <= width - 2; i += 2) { + y00 = *pY; + y01 = *(pY + 1); + y10 = *(pY + width); + y11 = *(pY + width + 1); + u = (*pU++) - 128; + v = (*pV++) - 128; + + move_420_block(y00, y01, y10, y11, u, v, + width, pOut); + + pY += 2; + pOut += 2 * bytes; + + } + pY += width; + pOut += width * bytes; + } +} + +// Consider a YUV420 image of 6x2 pixels. +// +// A B C D U1 U2 +// I J K L V1 V2 +// +// The U1/V1 samples correspond to the ABIJ pixels. +// U2/V2 samples correspond to the CDKL pixels. +// +/* Converts from interlaced YUV420 to RGB24. */ +/* [FD] untested... */ +static void +yuv420_to_rgb24(int width, int height, + unsigned char *pIn0, unsigned char *pOut0) +{ + const int bytes = 24 >> 3; + int i, j, y00, y01, y10, y11, u, v; + unsigned char *pY = pIn0; + unsigned char *pU = pY + 4; + unsigned char *pV = pU + width; + unsigned char *pOut = pOut0; + + for (j = 0; j <= height - 2; j += 2) { + for (i = 0; i <= width - 4; i += 4) { + y00 = *pY; + y01 = *(pY + 1); + y10 = *(pY + width); + y11 = *(pY + width + 1); + u = (*pU++) - 128; + v = (*pV++) - 128; + + move_420_block(y00, y01, y10, y11, u, v, + width, pOut); + + pY += 2; + pOut += 2 * bytes; + + y00 = *pY; + y01 = *(pY + 1); + y10 = *(pY + width); + y11 = *(pY + width + 1); + u = (*pU++) - 128; + v = (*pV++) - 128; + + move_420_block(y00, y01, y10, y11, u, v, + width, pOut); + + pY += 4; // skip UV + pOut += 2 * bytes; + + } + pY += width; + pOut += width * bytes; + } +} + +// Consider a YUV411P image of 8x2 pixels. +// +// A plane of Y values as before. +// +// A plane of U values 1 2 +// 3 4 +// +// A plane of V values 1 2 +// 3 4 +// +// The U1/V1 samples correspond to the ABCD pixels. +// U2/V2 samples correspond to the EFGH pixels. +// +/* Converts from planar YUV411P to RGB24. */ +/* [FD] untested... */ +static void +yuv411p_to_rgb24(int width, int height, + unsigned char *pIn0, unsigned char *pOut0) +{ + const int numpix = width * height; + const int bytes = 24 >> 3; + int i, j, y00, y01, y10, y11, u, v; + unsigned char *pY = pIn0; + unsigned char *pU = pY + numpix; + unsigned char *pV = pU + numpix / 4; + unsigned char *pOut = pOut0; + + for (j = 0; j <= height; j++) { + for (i = 0; i <= width - 4; i += 4) { + y00 = *pY; + y01 = *(pY + 1); + y10 = *(pY + 2); + y11 = *(pY + 3); + u = (*pU++) - 128; + v = (*pV++) - 128; + + move_411_block(y00, y01, y10, y11, u, v, + width, pOut); + + pY += 4; + pOut += 4 * bytes; + + } + } +} + +/* convert from 4:2:2 YUYV interlaced to RGB24 */ +/* based on ccvt_yuyv_bgr32() from camstream */ +#define SAT(c) \ + if (c & (~255)) { if (c < 0) c = 0; else c = 255; } +static void +yuyv_to_rgb24 (int width, int height, unsigned char *src, unsigned char *dst) +{ + unsigned char *s; + unsigned char *d; + int l, c; + int r, g, b, cr, cg, cb, y1, y2; + + l = height; + s = src; + d = dst; + while (l--) { + c = width >> 1; + while (c--) { + y1 = *s++; + cb = ((*s - 128) * 454) >> 8; + cg = (*s++ - 128) * 88; + y2 = *s++; + cr = ((*s - 128) * 359) >> 8; + cg = (cg + (*s++ - 128) * 183) >> 8; + + r = y1 + cr; + b = y1 + cb; + g = y1 - cg; + SAT(r); + SAT(g); + SAT(b); + + *d++ = b; + *d++ = g; + *d++ = r; + + r = y2 + cr; + b = y2 + cb; + g = y2 - cg; + SAT(r); + SAT(g); + SAT(b); + + *d++ = b; + *d++ = g; + *d++ = r; + } + } +} + +static void +uyvy_to_rgb24 (int width, int height, unsigned char *src, unsigned char *dst) +{ + unsigned char *s; + unsigned char *d; + int l, c; + int r, g, b, cr, cg, cb, y1, y2; + + l = height; + s = src; + d = dst; + while (l--) { + c = width >> 1; + while (c--) { + cb = ((*s - 128) * 454) >> 8; + cg = (*s++ - 128) * 88; + y1 = *s++; + cr = ((*s - 128) * 359) >> 8; + cg = (cg + (*s++ - 128) * 183) >> 8; + y2 = *s++; + + r = y1 + cr; + b = y1 + cb; + g = y1 - cg; + SAT(r); + SAT(g); + SAT(b); + + *d++ = b; + *d++ = g; + *d++ = r; + + r = y2 + cr; + b = y2 + cb; + g = y2 - cg; + SAT(r); + SAT(g); + SAT(b); + + *d++ = b; + *d++ = g; + *d++ = r; + } + } +} + +#ifdef HAVE_JPEG + +/* convert from mjpeg to rgb24 */ +static bool +mjpeg_to_rgb24 (int width, int height, + unsigned char *src, int length, + unsigned char *dst) +{ + cv::Mat temp=cv::imdecode(cv::Mat(std::vector(src, src + length)), 1); + if( !temp.data || temp.cols != width || temp.rows != height ) + return false; + memcpy(dst, temp.data, width*height*3); + return true; +} + +#endif + +/* + * BAYER2RGB24 ROUTINE TAKEN FROM: + * + * Sonix SN9C10x based webcam basic I/F routines + * Takafumi Mizuno + * + */ + +static void bayer2rgb24(long int WIDTH, long int HEIGHT, unsigned char *src, unsigned char *dst) +{ + long int i; + unsigned char *rawpt, *scanpt; + long int size; + + rawpt = src; + scanpt = dst; + size = WIDTH*HEIGHT; + + for ( i = 0; i < size; i++ ) { + if ( (i/WIDTH) % 2 == 0 ) { + if ( (i % 2) == 0 ) { + /* B */ + if ( (i > WIDTH) && ((i % WIDTH) > 0) ) { + *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+ + *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* R */ + *scanpt++ = (*(rawpt-1)+*(rawpt+1)+ + *(rawpt+WIDTH)+*(rawpt-WIDTH))/4; /* G */ + *scanpt++ = *rawpt; /* B */ + } else { + /* first line or left column */ + *scanpt++ = *(rawpt+WIDTH+1); /* R */ + *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2; /* G */ + *scanpt++ = *rawpt; /* B */ + } + } else { + /* (B)G */ + if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) { + *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* R */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* B */ + } else { + /* first line or right column */ + *scanpt++ = *(rawpt+WIDTH); /* R */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = *(rawpt-1); /* B */ + } + } + } else { + if ( (i % 2) == 0 ) { + /* G(R) */ + if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) { + *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* R */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* B */ + } else { + /* bottom line or left column */ + *scanpt++ = *(rawpt+1); /* R */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = *(rawpt-WIDTH); /* B */ + } + } else { + /* R */ + if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) { + *scanpt++ = *rawpt; /* R */ + *scanpt++ = (*(rawpt-1)+*(rawpt+1)+ + *(rawpt-WIDTH)+*(rawpt+WIDTH))/4; /* G */ + *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+ + *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* B */ + } else { + /* bottom line or right column */ + *scanpt++ = *rawpt; /* R */ + *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2; /* G */ + *scanpt++ = *(rawpt-WIDTH-1); /* B */ + } + } + } + rawpt++; + } + +} + +// SGBRG to RGB24 +// for some reason, red and blue needs to be swapped +// at least for 046d:092f Logitech, Inc. QuickCam Express Plus to work +//see: http://www.siliconimaging.com/RGB%20Bayer.htm +//and 4.6 at http://tldp.org/HOWTO/html_single/libdc1394-HOWTO/ +static void sgbrg2rgb24(long int WIDTH, long int HEIGHT, unsigned char *src, unsigned char *dst) +{ + long int i; + unsigned char *rawpt, *scanpt; + long int size; + + rawpt = src; + scanpt = dst; + size = WIDTH*HEIGHT; + + for ( i = 0; i < size; i++ ) + { + if ( (i/WIDTH) % 2 == 0 ) //even row + { + if ( (i % 2) == 0 ) //even pixel + { + if ( (i > WIDTH) && ((i % WIDTH) > 0) ) + { + *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* R */ + *scanpt++ = *(rawpt); /* G */ + *scanpt++ = (*(rawpt-WIDTH) + *(rawpt+WIDTH))/2; /* B */ + } else + { + /* first line or left column */ + + *scanpt++ = *(rawpt+1); /* R */ + *scanpt++ = *(rawpt); /* G */ + *scanpt++ = *(rawpt+WIDTH); /* B */ + } + } else //odd pixel + { + if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) + { + *scanpt++ = *(rawpt); /* R */ + *scanpt++ = (*(rawpt-1)+*(rawpt+1)+*(rawpt-WIDTH)+*(rawpt+WIDTH))/4; /* G */ + *scanpt++ = (*(rawpt-WIDTH-1) + *(rawpt-WIDTH+1) + *(rawpt+WIDTH-1) + *(rawpt+WIDTH+1))/4; /* B */ + } else + { + /* first line or right column */ + + *scanpt++ = *(rawpt); /* R */ + *scanpt++ = (*(rawpt-1)+*(rawpt+WIDTH))/2; /* G */ + *scanpt++ = *(rawpt+WIDTH-1); /* B */ + } + } + } else + { //odd row + if ( (i % 2) == 0 ) //even pixel + { + if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) + { + *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+*(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* R */ + *scanpt++ = (*(rawpt-1)+*(rawpt+1)+*(rawpt-WIDTH)+*(rawpt+WIDTH))/4; /* G */ + *scanpt++ = *(rawpt); /* B */ + } else + { + /* bottom line or left column */ + + *scanpt++ = *(rawpt-WIDTH+1); /* R */ + *scanpt++ = (*(rawpt+1)+*(rawpt-WIDTH))/2; /* G */ + *scanpt++ = *(rawpt); /* B */ + } + } else + { //odd pixel + if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) + { + *scanpt++ = (*(rawpt-WIDTH)+*(rawpt+WIDTH))/2; /* R */ + *scanpt++ = *(rawpt); /* G */ + *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* B */ + } else + { + /* bottom line or right column */ + + *scanpt++ = (*(rawpt-WIDTH)); /* R */ + *scanpt++ = *(rawpt); /* G */ + *scanpt++ = (*(rawpt-1)); /* B */ + } + } + } + rawpt++; + } +} + + +#define CLAMP(x) ((x)<0?0:((x)>255)?255:(x)) + +typedef struct { + int is_abs; + int len; + int val; +} code_table_t; + + +/* local storage */ +static code_table_t table[256]; +static int init_done = 0; + + +/* + sonix_decompress_init + ===================== + pre-calculates a locally stored table for efficient huffman-decoding. + + Each entry at index x in the table represents the codeword + present at the MSB of byte x. + +*/ +static void sonix_decompress_init(void) +{ + int i; + int is_abs, val, len; + + for (i = 0; i < 256; i++) { + is_abs = 0; + val = 0; + len = 0; + if ((i & 0x80) == 0) { + /* code 0 */ + val = 0; + len = 1; + } + else if ((i & 0xE0) == 0x80) { + /* code 100 */ + val = +4; + len = 3; + } + else if ((i & 0xE0) == 0xA0) { + /* code 101 */ + val = -4; + len = 3; + } + else if ((i & 0xF0) == 0xD0) { + /* code 1101 */ + val = +11; + len = 4; + } + else if ((i & 0xF0) == 0xF0) { + /* code 1111 */ + val = -11; + len = 4; + } + else if ((i & 0xF8) == 0xC8) { + /* code 11001 */ + val = +20; + len = 5; + } + else if ((i & 0xFC) == 0xC0) { + /* code 110000 */ + val = -20; + len = 6; + } + else if ((i & 0xFC) == 0xC4) { + /* code 110001xx: unknown */ + val = 0; + len = 8; + } + else if ((i & 0xF0) == 0xE0) { + /* code 1110xxxx */ + is_abs = 1; + val = (i & 0x0F) << 4; + len = 8; + } + table[i].is_abs = is_abs; + table[i].val = val; + table[i].len = len; + } + + init_done = 1; +} + + +/* + sonix_decompress + ================ + decompresses an image encoded by a SN9C101 camera controller chip. + + IN width + height + inp pointer to compressed frame (with header already stripped) + OUT outp pointer to decompressed frame + + Returns 0 if the operation was successful. + Returns <0 if operation failed. + +*/ +static int sonix_decompress(int width, int height, unsigned char *inp, unsigned char *outp) +{ + int row, col; + int val; + int bitpos; + unsigned char code; + unsigned char *addr; + + if (!init_done) { + /* do sonix_decompress_init first! */ + return -1; + } + + bitpos = 0; + for (row = 0; row < height; row++) { + + col = 0; + + + + /* first two pixels in first two rows are stored as raw 8-bit */ + if (row < 2) { + addr = inp + (bitpos >> 3); + code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7))); + bitpos += 8; + *outp++ = code; + + addr = inp + (bitpos >> 3); + code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7))); + bitpos += 8; + *outp++ = code; + + col += 2; + } + + while (col < width) { + /* get bitcode from bitstream */ + addr = inp + (bitpos >> 3); + code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7))); + + /* update bit position */ + bitpos += table[code].len; + + /* calculate pixel value */ + val = table[code].val; + if (!table[code].is_abs) { + /* value is relative to top and left pixel */ + if (col < 2) { + /* left column: relative to top pixel */ + val += outp[-2*width]; + } + else if (row < 2) { + /* top row: relative to left pixel */ + val += outp[-2]; + } + else { + /* main area: average of left pixel and top pixel */ + val += (outp[-2] + outp[-2*width]) / 2; + } + } + + /* store pixel */ + *outp++ = CLAMP(val); + col++; + } + } + + return 0; +} + + +static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int) { + +#ifdef HAVE_CAMV4L2 + if (V4L2_SUPPORT == 0) +#endif /* HAVE_CAMV4L2 */ + { + + /* [FD] this really belongs here */ + if (ioctl(capture->deviceHandle, VIDIOCSYNC, &capture->mmaps[capture->bufferIndex].frame) == -1) { + fprintf( stderr, "HIGHGUI ERROR: V4L: Could not SYNC to video stream. %s\n", strerror(errno)); + } + + } + + /* Now get what has already been captured as a IplImage return */ + + /* First, reallocate imageData if the frame size changed */ + +#ifdef HAVE_CAMV4L2 + + if (V4L2_SUPPORT == 1) + { + + if(((unsigned long)capture->frame.width != capture->form.fmt.pix.width) + || ((unsigned long)capture->frame.height != capture->form.fmt.pix.height)) { + cvFree(&capture->frame.imageData); + cvInitImageHeader( &capture->frame, + cvSize( capture->form.fmt.pix.width, + capture->form.fmt.pix.height ), + IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 ); + capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize); + } + + } else +#endif /* HAVE_CAMV4L2 */ + { + + if((capture->frame.width != capture->mmaps[capture->bufferIndex].width) + || (capture->frame.height != capture->mmaps[capture->bufferIndex].height)) { + cvFree(&capture->frame.imageData); + cvInitImageHeader( &capture->frame, + cvSize( capture->captureWindow.width, + capture->captureWindow.height ), + IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 ); + capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize); + } + + } + +#ifdef HAVE_CAMV4L2 + + if (V4L2_SUPPORT == 1) + { + switch (capture->palette) + { + case PALETTE_BGR24: + memcpy((char *)capture->frame.imageData, + (char *)capture->buffers[capture->bufferIndex].start, + capture->frame.imageSize); + break; + + case PALETTE_YVU420: + yuv420p_to_rgb24(capture->form.fmt.pix.width, + capture->form.fmt.pix.height, + (unsigned char*)(capture->buffers[capture->bufferIndex].start), + (unsigned char*)capture->frame.imageData); + break; + + case PALETTE_YUV411P: + yuv411p_to_rgb24(capture->form.fmt.pix.width, + capture->form.fmt.pix.height, + (unsigned char*)(capture->buffers[capture->bufferIndex].start), + (unsigned char*)capture->frame.imageData); + break; +#ifdef HAVE_JPEG +#ifdef __USE_GNU + /* support for MJPEG is only available with libjpeg and gcc, + because it's use libjepg and fmemopen() + */ + case PALETTE_MJPEG: + if (!mjpeg_to_rgb24(capture->form.fmt.pix.width, + capture->form.fmt.pix.height, + (unsigned char*)(capture->buffers[capture->bufferIndex] + .start), + capture->buffers[capture->bufferIndex].length, + (unsigned char*)capture->frame.imageData)) + return 0; + break; +#endif +#endif + + case PALETTE_YUYV: + yuyv_to_rgb24(capture->form.fmt.pix.width, + capture->form.fmt.pix.height, + (unsigned char*)(capture->buffers[capture->bufferIndex].start), + (unsigned char*)capture->frame.imageData); + break; + + case PALETTE_UYVY: + uyvy_to_rgb24(capture->form.fmt.pix.width, + capture->form.fmt.pix.height, + (unsigned char*)(capture->buffers[capture->bufferIndex].start), + (unsigned char*)capture->frame.imageData); + break; + case PALETTE_SBGGR8: + bayer2rgb24(capture->form.fmt.pix.width, + capture->form.fmt.pix.height, + (unsigned char*)capture->buffers[capture->bufferIndex].start, + (unsigned char*)capture->frame.imageData); + break; + + case PALETTE_SN9C10X: + sonix_decompress_init(); + sonix_decompress(capture->form.fmt.pix.width, + capture->form.fmt.pix.height, + (unsigned char*)capture->buffers[capture->bufferIndex].start, + (unsigned char*)capture->buffers[(capture->bufferIndex+1) % capture->req.count].start); + + bayer2rgb24(capture->form.fmt.pix.width, + capture->form.fmt.pix.height, + (unsigned char*)capture->buffers[(capture->bufferIndex+1) % capture->req.count].start, + (unsigned char*)capture->frame.imageData); + break; + + case PALETTE_SGBRG: + sgbrg2rgb24(capture->form.fmt.pix.width, + capture->form.fmt.pix.height, + (unsigned char*)capture->buffers[(capture->bufferIndex+1) % capture->req.count].start, + (unsigned char*)capture->frame.imageData); + break; + } + } else +#endif /* HAVE_CAMV4L2 */ + { + + switch(capture->imageProperties.palette) { + case VIDEO_PALETTE_RGB24: + memcpy((char *)capture->frame.imageData, + (char *)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]), + capture->frame.imageSize); + break; + case VIDEO_PALETTE_YUV420P: + yuv420p_to_rgb24(capture->captureWindow.width, + capture->captureWindow.height, + (unsigned char*)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]), + (unsigned char*)capture->frame.imageData); + break; + case VIDEO_PALETTE_YUV420: + yuv420_to_rgb24(capture->captureWindow.width, + capture->captureWindow.height, + (unsigned char*)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]), + (unsigned char*)capture->frame.imageData); + break; + case VIDEO_PALETTE_YUV411P: + yuv411p_to_rgb24(capture->captureWindow.width, + capture->captureWindow.height, + (unsigned char*)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]), + (unsigned char*)capture->frame.imageData); + break; + default: + fprintf( stderr, + "HIGHGUI ERROR: V4L: Cannot convert from palette %d to RGB\n", + capture->imageProperties.palette); + + return 0; + } + + } + + return(&capture->frame); +} + +static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture, + int property_id ) { + +#ifdef HAVE_CAMV4L2 + + if (V4L2_SUPPORT == 1) + { + + /* default value for min and max */ + int v4l2_min = 0; + int v4l2_max = 255; + + CLEAR (capture->form); + capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) { + /* display an error message, and return an error code */ + perror ("VIDIOC_G_FMT"); + return -1; + } + + switch (property_id) { + case CV_CAP_PROP_FRAME_WIDTH: + return capture->form.fmt.pix.width; + case CV_CAP_PROP_FRAME_HEIGHT: + return capture->form.fmt.pix.height; + } + + /* initialize the control structure */ + + switch (property_id) { + case CV_CAP_PROP_BRIGHTNESS: + capture->control.id = V4L2_CID_BRIGHTNESS; + break; + case CV_CAP_PROP_CONTRAST: + capture->control.id = V4L2_CID_CONTRAST; + break; + case CV_CAP_PROP_SATURATION: + capture->control.id = V4L2_CID_SATURATION; + break; + case CV_CAP_PROP_HUE: + capture->control.id = V4L2_CID_HUE; + break; + case CV_CAP_PROP_GAIN: + capture->control.id = V4L2_CID_GAIN; + break; + case CV_CAP_PROP_EXPOSURE: + capture->control.id = V4L2_CID_EXPOSURE; + break; + default: + fprintf(stderr, + "HIGHGUI ERROR: V4L2: getting property #%d is not supported\n", + property_id); + return -1; + } + + if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_CTRL, + &capture->control)) { + + fprintf( stderr, "HIGHGUI ERROR: V4L2: "); + switch (property_id) { + case CV_CAP_PROP_BRIGHTNESS: + fprintf (stderr, "Brightness"); + break; + case CV_CAP_PROP_CONTRAST: + fprintf (stderr, "Contrast"); + break; + case CV_CAP_PROP_SATURATION: + fprintf (stderr, "Saturation"); + break; + case CV_CAP_PROP_HUE: + fprintf (stderr, "Hue"); + break; + case CV_CAP_PROP_GAIN: + fprintf (stderr, "Gain"); + break; + case CV_CAP_PROP_EXPOSURE: + fprintf (stderr, "Exposure"); + break; + } + fprintf (stderr, " is not supported by your device\n"); + + return -1; + } + + /* get the min/max values */ + switch (property_id) { + + case CV_CAP_PROP_BRIGHTNESS: + v4l2_min = capture->v4l2_brightness_min; + v4l2_max = capture->v4l2_brightness_max; + break; + case CV_CAP_PROP_CONTRAST: + v4l2_min = capture->v4l2_contrast_min; + v4l2_max = capture->v4l2_contrast_max; + break; + case CV_CAP_PROP_SATURATION: + v4l2_min = capture->v4l2_saturation_min; + v4l2_max = capture->v4l2_saturation_max; + break; + case CV_CAP_PROP_HUE: + v4l2_min = capture->v4l2_hue_min; + v4l2_max = capture->v4l2_hue_max; + break; + case CV_CAP_PROP_GAIN: + v4l2_min = capture->v4l2_gain_min; + v4l2_max = capture->v4l2_gain_max; + break; + case CV_CAP_PROP_EXPOSURE: + v4l2_min = capture->v4l2_exposure_min; + v4l2_max = capture->v4l2_exposure_max; + break; + } + + /* all was OK, so convert to 0.0 - 1.0 range, and return the value */ + return ((float)capture->control.value - v4l2_min + 1) / (v4l2_max - v4l2_min); + + } else +#endif /* HAVE_CAMV4L2 */ + { + + int retval = -1; + + if (ioctl (capture->deviceHandle, + VIDIOCGWIN, &capture->captureWindow) < 0) { + fprintf (stderr, + "HIGHGUI ERROR: V4L: " + "Unable to determine size of incoming image\n"); + icvCloseCAM_V4L(capture); + return -1; + } + + switch (property_id) { + case CV_CAP_PROP_FRAME_WIDTH: + retval = capture->captureWindow.width; + break; + case CV_CAP_PROP_FRAME_HEIGHT: + retval = capture->captureWindow.height; + break; + case CV_CAP_PROP_BRIGHTNESS: + retval = capture->imageProperties.brightness; + break; + case CV_CAP_PROP_CONTRAST: + retval = capture->imageProperties.contrast; + break; + case CV_CAP_PROP_SATURATION: + retval = capture->imageProperties.colour; + break; + case CV_CAP_PROP_HUE: + retval = capture->imageProperties.hue; + break; + case CV_CAP_PROP_GAIN: + fprintf(stderr, + "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n"); + return -1; + break; + case CV_CAP_PROP_EXPOSURE: + fprintf(stderr, + "HIGHGUI ERROR: V4L: Exposure control in V4L is not supported\n"); + return -1; + break; + default: + fprintf(stderr, + "HIGHGUI ERROR: V4L: getting property #%d is not supported\n", + property_id); + } + + if (retval == -1) { + /* there was a problem */ + return -1; + } + + /* all was OK, so convert to 0.0 - 1.0 range, and return the value */ + return float (retval) / 0xFFFF; + + } + +}; + +static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h) { + +#ifdef HAVE_CAMV4L2 + + if (V4L2_SUPPORT == 1) + { + + CLEAR (capture->cropcap); + capture->cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (xioctl (capture->deviceHandle, VIDIOC_CROPCAP, &capture->cropcap) < 0) { + fprintf(stderr, "HIGHGUI ERROR: V4L/V4L2: VIDIOC_CROPCAP\n"); + } else { + + CLEAR (capture->crop); + capture->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + capture->crop.c= capture->cropcap.defrect; + + /* set the crop area, but don't exit if the device don't support croping */ + if (xioctl (capture->deviceHandle, VIDIOC_S_CROP, &capture->crop) < 0) { + fprintf(stderr, "HIGHGUI ERROR: V4L/V4L2: VIDIOC_S_CROP\n"); + } + } + + CLEAR (capture->form); + capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* read the current setting, mainly to retreive the pixelformat information */ + xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form); + + /* set the values we want to change */ + capture->form.fmt.pix.width = w; + capture->form.fmt.pix.height = h; + capture->form.fmt.win.chromakey = 0; + capture->form.fmt.win.field = V4L2_FIELD_ANY; + capture->form.fmt.win.clips = 0; + capture->form.fmt.win.clipcount = 0; + capture->form.fmt.pix.field = V4L2_FIELD_ANY; + + /* ask the device to change the size + * don't test if the set of the size is ok, because some device + * don't allow changing the size, and we will get the real size + * later */ + xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form); + + /* try to set framerate to 30 fps */ + struct v4l2_streamparm setfps; + memset (&setfps, 0, sizeof(struct v4l2_streamparm)); + setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + setfps.parm.capture.timeperframe.numerator = 1; + setfps.parm.capture.timeperframe.denominator = 30; + xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps); + + /* we need to re-initialize some things, like buffers, because the size has + * changed */ + capture->FirstCapture = 1; + + /* Get window info again, to get the real value */ + if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) + { + fprintf(stderr, "HIGHGUI ERROR: V4L/V4L2: Could not obtain specifics of capture window.\n\n"); + + icvCloseCAM_V4L(capture); + + return 0; + } + + return 0; + + } else +#endif /* HAVE_CAMV4L2 */ + { + + if (capture==0) return 0; + if (w>capture->capability.maxwidth) { + w=capture->capability.maxwidth; + } + if (h>capture->capability.maxheight) { + h=capture->capability.maxheight; + } + + capture->captureWindow.width=w; + capture->captureWindow.height=h; + + if (ioctl(capture->deviceHandle, VIDIOCSWIN, &capture->captureWindow) < 0) { + icvCloseCAM_V4L(capture); + return 0; + } + + if (ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) { + icvCloseCAM_V4L(capture); + return 0; + } + + capture->FirstCapture = 1; + + } + + return 0; + +} + +static int icvSetControl (CvCaptureCAM_V4L* capture, + int property_id, double value) { + + /* limitation of the input value */ + if (value < 0.0) { + value = 0.0; + } else if (value > 1.0) { + value = 1.0; + } + +#ifdef HAVE_CAMV4L2 + + if (V4L2_SUPPORT == 1) + { + + /* default value for min and max */ + int v4l2_min = 0; + int v4l2_max = 255; + + /* initialisations */ + CLEAR (capture->control); + + /* set which control we want to set */ + switch (property_id) { + + case CV_CAP_PROP_BRIGHTNESS: + capture->control.id = V4L2_CID_BRIGHTNESS; + break; + case CV_CAP_PROP_CONTRAST: + capture->control.id = V4L2_CID_CONTRAST; + break; + case CV_CAP_PROP_SATURATION: + capture->control.id = V4L2_CID_SATURATION; + break; + case CV_CAP_PROP_HUE: + capture->control.id = V4L2_CID_HUE; + break; + case CV_CAP_PROP_GAIN: + capture->control.id = V4L2_CID_GAIN; + break; + case CV_CAP_PROP_EXPOSURE: + capture->control.id = V4L2_CID_EXPOSURE; + break; + default: + fprintf(stderr, + "HIGHGUI ERROR: V4L2: setting property #%d is not supported\n", + property_id); + return -1; + } + + /* get the min and max values */ + if (-1 == xioctl (capture->deviceHandle, + VIDIOC_G_CTRL, &capture->control)) { +// perror ("VIDIOC_G_CTRL for getting min/max values"); + return -1; + } + + /* get the min/max values */ + switch (property_id) { + + case CV_CAP_PROP_BRIGHTNESS: + v4l2_min = capture->v4l2_brightness_min; + v4l2_max = capture->v4l2_brightness_max; + break; + case CV_CAP_PROP_CONTRAST: + v4l2_min = capture->v4l2_contrast_min; + v4l2_max = capture->v4l2_contrast_max; + break; + case CV_CAP_PROP_SATURATION: + v4l2_min = capture->v4l2_saturation_min; + v4l2_max = capture->v4l2_saturation_max; + break; + case CV_CAP_PROP_HUE: + v4l2_min = capture->v4l2_hue_min; + v4l2_max = capture->v4l2_hue_max; + break; + case CV_CAP_PROP_GAIN: + v4l2_min = capture->v4l2_gain_min; + v4l2_max = capture->v4l2_gain_max; + break; + case CV_CAP_PROP_EXPOSURE: + v4l2_min = capture->v4l2_exposure_min; + v4l2_max = capture->v4l2_exposure_max; + break; + } + + /* initialisations */ + CLEAR (capture->control); + + /* set which control we want to set */ + switch (property_id) { + + case CV_CAP_PROP_BRIGHTNESS: + capture->control.id = V4L2_CID_BRIGHTNESS; + break; + case CV_CAP_PROP_CONTRAST: + capture->control.id = V4L2_CID_CONTRAST; + break; + case CV_CAP_PROP_SATURATION: + capture->control.id = V4L2_CID_SATURATION; + break; + case CV_CAP_PROP_HUE: + capture->control.id = V4L2_CID_HUE; + break; + case CV_CAP_PROP_GAIN: + capture->control.id = V4L2_CID_GAIN; + break; + case CV_CAP_PROP_EXPOSURE: + capture->control.id = V4L2_CID_EXPOSURE; + break; + default: + fprintf(stderr, + "HIGHGUI ERROR: V4L2: setting property #%d is not supported\n", + property_id); + return -1; + } + + /* set the value we want to set to the scaled the value */ + capture->control.value = (int)(value * (v4l2_max - v4l2_min) + v4l2_min); + + /* The driver may clamp the value or return ERANGE, ignored here */ + if (-1 == xioctl (capture->deviceHandle, + VIDIOC_S_CTRL, &capture->control) && errno != ERANGE) { + perror ("VIDIOC_S_CTRL"); + return -1; + } + } else +#endif /* HAVE_CAMV4L2 */ + { + + int v4l_value; + + /* scale the value to the wanted integer one */ + v4l_value = (int)(0xFFFF * value); + + switch (property_id) { + case CV_CAP_PROP_BRIGHTNESS: + capture->imageProperties.brightness = v4l_value; + break; + case CV_CAP_PROP_CONTRAST: + capture->imageProperties.contrast = v4l_value; + break; + case CV_CAP_PROP_SATURATION: + capture->imageProperties.colour = v4l_value; + break; + case CV_CAP_PROP_HUE: + capture->imageProperties.hue = v4l_value; + break; + case CV_CAP_PROP_GAIN: + fprintf(stderr, + "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n"); + return -1; + case CV_CAP_PROP_EXPOSURE: + fprintf(stderr, + "HIGHGUI ERROR: V4L: Exposure control in V4L is not supported\n"); + return -1; + default: + fprintf(stderr, + "HIGHGUI ERROR: V4L: property #%d is not supported\n", + property_id); + return -1; + } + + if (ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties) + < 0) + { + fprintf(stderr, + "HIGHGUI ERROR: V4L: Unable to set video informations\n"); + icvCloseCAM_V4L(capture); + return -1; + } + } + + /* all was OK */ + return 0; + +} + +static int icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, + int property_id, double value ){ + static int width = 0, height = 0; + int retval; + + /* initialization */ + retval = 0; + + /* two subsequent calls setting WIDTH and HEIGHT will change + the video size */ + /* the first one will return an error, though. */ + + switch (property_id) { + case CV_CAP_PROP_FRAME_WIDTH: + width = cvRound(value); + if(width !=0 && height != 0) { + retval = icvSetVideoSize( capture, width, height); + width = height = 0; + } + break; + case CV_CAP_PROP_FRAME_HEIGHT: + height = cvRound(value); + if(width !=0 && height != 0) { + retval = icvSetVideoSize( capture, width, height); + width = height = 0; + } + break; + case CV_CAP_PROP_BRIGHTNESS: + case CV_CAP_PROP_CONTRAST: + case CV_CAP_PROP_SATURATION: + case CV_CAP_PROP_HUE: + case CV_CAP_PROP_GAIN: + case CV_CAP_PROP_EXPOSURE: + retval = icvSetControl(capture, property_id, value); + break; + default: + fprintf(stderr, + "HIGHGUI ERROR: V4L: setting property #%d is not supported\n", + property_id); + } + + /* return the the status */ + return retval; +} + +static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture ){ + /* Deallocate space - Hopefully, no leaks */ + + if (capture) + { + +#ifdef HAVE_CAMV4L2 + if (V4L2_SUPPORT == 0) +#endif /* HAVE_CAMV4L2 */ + { + + if (capture->mmaps) + free(capture->mmaps); + if (capture->memoryMap) + munmap(capture->memoryMap, capture->memoryBuffer.size); + + } +#ifdef HAVE_CAMV4L2 + else { + capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (ioctl(capture->deviceHandle, VIDIOC_STREAMOFF, &capture->type) < 0) { + perror ("Unable to stop the stream."); + } + + for (unsigned int n_buffers_ = 0; n_buffers_ < capture->req.count; ++n_buffers_) + { + if (-1 == munmap (capture->buffers[n_buffers_].start, capture->buffers[n_buffers_].length)) { + perror ("munmap"); + } + } + + if (capture->buffers[MAX_V4L_BUFFERS].start) + { + free(capture->buffers[MAX_V4L_BUFFERS].start); + capture->buffers[MAX_V4L_BUFFERS].start = 0; + } + } +#endif /* HAVE_CAMV4L2 */ + + if (capture->deviceHandle != -1) + close(capture->deviceHandle); + + if (capture->frame.imageData) cvFree(&capture->frame.imageData); + //cvFree((void **)capture); + } +}; + + +class CvCaptureCAM_V4L_CPP : CvCapture +{ +public: + CvCaptureCAM_V4L_CPP() { captureV4L = 0; } + virtual ~CvCaptureCAM_V4L_CPP() { close(); } + + virtual bool open( int index ); + virtual void close(); + + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); +protected: + + CvCaptureCAM_V4L* captureV4L; +}; + +bool CvCaptureCAM_V4L_CPP::open( int index ) +{ + close(); + captureV4L = icvCaptureFromCAM_V4L(index); + return captureV4L != 0; +} + +void CvCaptureCAM_V4L_CPP::close() +{ + if( captureV4L ) + { + icvCloseCAM_V4L( captureV4L ); + cvFree( &captureV4L ); + } +} + +bool CvCaptureCAM_V4L_CPP::grabFrame() +{ + return captureV4L ? icvGrabFrameCAM_V4L( captureV4L ) != 0 : false; +} + +IplImage* CvCaptureCAM_V4L_CPP::retrieveFrame(int) +{ + return captureV4L ? icvRetrieveFrameCAM_V4L( captureV4L, 0 ) : 0; +} + +double CvCaptureCAM_V4L_CPP::getProperty( int propId ) +{ + return captureV4L ? icvGetPropertyCAM_V4L( captureV4L, propId ) : 0.0; +} + +bool CvCaptureCAM_V4L_CPP::setProperty( int propId, double value ) +{ + return captureV4L ? icvSetPropertyCAM_V4L( captureV4L, propId, value ) != 0 : false; +} + +CvCapture* cvCreateCameraCapture_V4L( int index ) +{ + CvCaptureCAM_V4L_CPP* capture = new CvCaptureCAM_V4L_CPP; + + if( capture->open( index )) + return (CvCapture*)capture; + + delete capture; + return 0; +} + +#endif diff --git a/highgui/src/cap_vfw.cpp b/highgui/src/cap_vfw.cpp new file mode 100644 index 0000000..8e5b1e4 --- /dev/null +++ b/highgui/src/cap_vfw.cpp @@ -0,0 +1,721 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#include + +#ifdef __GNUC__ +#define WM_CAP_FIRSTA (WM_USER) +#define capSendMessage(hwnd,m,w,l) (IsWindow(hwnd)?SendMessage(hwnd,m,w,l):0) +#endif + +#if defined _M_X64 && defined _MSC_VER +#pragma optimize("",off) +#pragma warning(disable: 4748) +#endif + +/********************* Capturing video from AVI via VFW ************************/ + +static BITMAPINFOHEADER icvBitmapHeader( int width, int height, int bpp, int compression = BI_RGB ) +{ + BITMAPINFOHEADER bmih; + memset( &bmih, 0, sizeof(bmih)); + bmih.biSize = sizeof(bmih); + bmih.biWidth = width; + bmih.biHeight = height; + bmih.biBitCount = (WORD)bpp; + bmih.biCompression = compression; + bmih.biPlanes = 1; + + return bmih; +} + + +static void icvInitCapture_VFW() +{ + static int isInitialized = 0; + if( !isInitialized ) + { + AVIFileInit(); + isInitialized = 1; + } +} + + +class CvCaptureAVI_VFW : public CvCapture +{ +public: + CvCaptureAVI_VFW() + { + CoInitialize(NULL); + init(); + } + + virtual ~CvCaptureAVI_VFW() + { + close(); + CoUninitialize(); + } + + virtual bool open( const char* filename ); + virtual void close(); + + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual int getCaptureDomain() { return CV_CAP_VFW; } // Return the type of the capture object: CV_CAP_VFW, etc... + +protected: + void init(); + + PAVIFILE avifile; + PAVISTREAM avistream; + PGETFRAME getframe; + AVISTREAMINFO aviinfo; + BITMAPINFOHEADER * bmih; + CvSlice film_range; + double fps; + int pos; + IplImage* frame; + CvSize size; +}; + + +void CvCaptureAVI_VFW::init() +{ + avifile = 0; + avistream = 0; + getframe = 0; + memset( &aviinfo, 0, sizeof(aviinfo) ); + bmih = 0; + film_range = cvSlice(0,0); + fps = 0; + pos = 0; + frame = 0; + size = cvSize(0,0); +} + + +void CvCaptureAVI_VFW::close() +{ + if( getframe ) + AVIStreamGetFrameClose( getframe ); + + if( avistream ) + AVIStreamRelease( avistream ); + + if( avifile ) + AVIFileRelease( avifile ); + + if (frame) + cvReleaseImage( &frame ); + + init(); +} + + +bool CvCaptureAVI_VFW::open( const char* filename ) +{ + close(); + icvInitCapture_VFW(); + + if( !filename ) + return false; + + HRESULT hr = AVIFileOpen( &avifile, filename, OF_READ, NULL ); + if( SUCCEEDED(hr)) + { + hr = AVIFileGetStream( avifile, &avistream, streamtypeVIDEO, 0 ); + if( SUCCEEDED(hr)) + { + hr = AVIStreamInfo( avistream, &aviinfo, sizeof(aviinfo)); + if( SUCCEEDED(hr)) + { + size.width = aviinfo.rcFrame.right - aviinfo.rcFrame.left; + size.height = aviinfo.rcFrame.bottom - aviinfo.rcFrame.top; + BITMAPINFOHEADER bmihdr = icvBitmapHeader( size.width, size.height, 24 ); + + film_range.start_index = (int)aviinfo.dwStart; + film_range.end_index = film_range.start_index + (int)aviinfo.dwLength; + fps = (double)aviinfo.dwRate/aviinfo.dwScale; + pos = film_range.start_index; + getframe = AVIStreamGetFrameOpen( avistream, &bmihdr ); + if( getframe != 0 ) + return true; + + // Attempt to open as 8-bit AVI. + bmihdr = icvBitmapHeader( size.width, size.height, 8); + getframe = AVIStreamGetFrameOpen( avistream, &bmihdr ); + if( getframe != 0 ) + return true; + } + } + } + + close(); + return false; +} + +bool CvCaptureAVI_VFW::grabFrame() +{ + if( avistream ) + bmih = (BITMAPINFOHEADER*)AVIStreamGetFrame( getframe, pos++ ); + return bmih != 0; +} + +IplImage* CvCaptureAVI_VFW::retrieveFrame(int) +{ + if( avistream && bmih ) + { + bool isColor = bmih->biBitCount == 24; + int nChannels = (isColor) ? 3 : 1; + IplImage src; + cvInitImageHeader( &src, cvSize( bmih->biWidth, bmih->biHeight ), + IPL_DEPTH_8U, nChannels, IPL_ORIGIN_BL, 4 ); + + char* dataPtr = (char*)(bmih + 1); + + // Only account for the color map size if we are an 8-bit image and the color map is used + if (!isColor) + { + static int RGBQUAD_SIZE_PER_BYTE = sizeof(RGBQUAD)/sizeof(BYTE); + int offsetFromColormapToData = (int)bmih->biClrUsed*RGBQUAD_SIZE_PER_BYTE; + dataPtr += offsetFromColormapToData; + } + + cvSetData( &src, dataPtr, src.widthStep ); + + if( !frame || frame->width != src.width || frame->height != src.height ) + { + cvReleaseImage( &frame ); + frame = cvCreateImage( cvGetSize(&src), 8, nChannels ); + } + + cvFlip( &src, frame, 0 ); + return frame; + } + + return 0; +} + +double CvCaptureAVI_VFW::getProperty( int property_id ) +{ + switch( property_id ) + { + case CV_CAP_PROP_POS_MSEC: + return cvRound(pos*1000./fps); + case CV_CAP_PROP_POS_FRAMES: + return pos; + case CV_CAP_PROP_POS_AVI_RATIO: + return (pos - film_range.start_index)/ + (film_range.end_index - film_range.start_index + 1e-10); + case CV_CAP_PROP_FRAME_WIDTH: + return size.width; + case CV_CAP_PROP_FRAME_HEIGHT: + return size.height; + case CV_CAP_PROP_FPS: + return fps; + case CV_CAP_PROP_FOURCC: + return aviinfo.fccHandler; + case CV_CAP_PROP_FRAME_COUNT: + return film_range.end_index - film_range.start_index; + } + return 0; +} + +bool CvCaptureAVI_VFW::setProperty( int property_id, double value ) +{ + switch( property_id ) + { + case CV_CAP_PROP_POS_MSEC: + case CV_CAP_PROP_POS_FRAMES: + case CV_CAP_PROP_POS_AVI_RATIO: + { + switch( property_id ) + { + case CV_CAP_PROP_POS_MSEC: + pos = cvRound(value*fps*0.001); + break; + case CV_CAP_PROP_POS_AVI_RATIO: + pos = cvRound(value*(film_range.end_index - + film_range.start_index) + + film_range.start_index); + break; + default: + pos = cvRound(value); + } + if( pos < film_range.start_index ) + pos = film_range.start_index; + if( pos > film_range.end_index ) + pos = film_range.end_index; + } + break; + default: + return false; + } + + return true; +} + +CvCapture* cvCreateFileCapture_VFW (const char* filename) +{ + CvCaptureAVI_VFW* capture = new CvCaptureAVI_VFW; + if( capture->open(filename) ) + return capture; + delete capture; + return 0; +} + + +/********************* Capturing video from camera via VFW *********************/ + +class CvCaptureCAM_VFW : public CvCapture +{ +public: + CvCaptureCAM_VFW() { init(); } + virtual ~CvCaptureCAM_VFW() { close(); } + + virtual bool open( int index ); + virtual void close(); + virtual double getProperty(int); + virtual bool setProperty(int, double) { return false; } + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual int getCaptureDomain() { return CV_CAP_VFW; } // Return the type of the capture object: CV_CAP_VFW, etc... + +protected: + void init(); + void closeHIC(); + static LRESULT PASCAL frameCallback( HWND hWnd, VIDEOHDR* hdr ); + + CAPDRIVERCAPS caps; + HWND capWnd; + VIDEOHDR* hdr; + DWORD fourcc; + HIC hic; + IplImage* frame; +}; + + +void CvCaptureCAM_VFW::init() +{ + memset( &caps, 0, sizeof(caps) ); + capWnd = 0; + hdr = 0; + fourcc = 0; + hic = 0; + frame = 0; +} + +void CvCaptureCAM_VFW::closeHIC() +{ + if( hic ) + { + ICDecompressEnd( hic ); + ICClose( hic ); + hic = 0; + } +} + + +LRESULT PASCAL CvCaptureCAM_VFW::frameCallback( HWND hWnd, VIDEOHDR* hdr ) +{ + CvCaptureCAM_VFW* capture = 0; + + if (!hWnd) return FALSE; + + capture = (CvCaptureCAM_VFW*)capGetUserData(hWnd); + capture->hdr = hdr; + + return (LRESULT)TRUE; +} + + +// Initialize camera input +bool CvCaptureCAM_VFW::open( int wIndex ) +{ + char szDeviceName[80]; + char szDeviceVersion[80]; + HWND hWndC = 0; + + close(); + + if( (unsigned)wIndex >= 10 ) + wIndex = 0; + + for( ; wIndex < 10; wIndex++ ) + { + if( capGetDriverDescription( wIndex, szDeviceName, + sizeof (szDeviceName), szDeviceVersion, + sizeof (szDeviceVersion))) + { + hWndC = capCreateCaptureWindow ( "My Own Capture Window", + WS_POPUP | WS_CHILD, 0, 0, 320, 240, 0, 0); + if( capDriverConnect (hWndC, wIndex)) + break; + DestroyWindow( hWndC ); + hWndC = 0; + } + } + + if( hWndC ) + { + capWnd = hWndC; + hdr = 0; + hic = 0; + fourcc = (DWORD)-1; + + memset( &caps, 0, sizeof(caps)); + capDriverGetCaps( hWndC, &caps, sizeof(&caps)); + ::MoveWindow( hWndC, 0, 0, 320, 240, TRUE ); + capSetUserData( hWndC, (size_t)this ); + capSetCallbackOnFrame( hWndC, frameCallback ); + CAPTUREPARMS p; + capCaptureGetSetup(hWndC,&p,sizeof(CAPTUREPARMS)); + p.dwRequestMicroSecPerFrame = 66667/2; + capCaptureSetSetup(hWndC,&p,sizeof(CAPTUREPARMS)); + //capPreview( hWndC, 1 ); + capPreviewScale(hWndC,FALSE); + capPreviewRate(hWndC,1); + } + return capWnd != 0; +} + + +void CvCaptureCAM_VFW::close() +{ + if( capWnd ) + { + capSetCallbackOnFrame( capWnd, NULL ); + capDriverDisconnect( capWnd ); + DestroyWindow( capWnd ); + closeHIC(); + } + cvReleaseImage( &frame ); + init(); +} + + +bool CvCaptureCAM_VFW::grabFrame() +{ + if( capWnd ) + { + SendMessage( capWnd, WM_CAP_GRAB_FRAME_NOSTOP, 0, 0 ); + return true; + } + return false; +} + + +IplImage* CvCaptureCAM_VFW::retrieveFrame(int) +{ + BITMAPINFO vfmt; + memset( &vfmt, 0, sizeof(vfmt)); + BITMAPINFOHEADER& vfmt0 = vfmt.bmiHeader; + int sz, prevWidth, prevHeight; + + if( !capWnd ) + return 0; + + sz = capGetVideoFormat( capWnd, &vfmt, sizeof(vfmt)); + prevWidth = frame ? frame->width : 0; + prevHeight = frame ? frame->height : 0; + + if( !hdr || hdr->lpData == 0 || sz == 0 ) + return 0; + + if( !frame || frame->width != vfmt0.biWidth || frame->height != vfmt0.biHeight ) + { + cvReleaseImage( &frame ); + frame = cvCreateImage( cvSize( vfmt0.biWidth, vfmt0.biHeight ), 8, 3 ); + } + + if( vfmt.bmiHeader.biCompression != BI_RGB || + vfmt.bmiHeader.biBitCount != 24 ) + { + BITMAPINFOHEADER vfmt1 = icvBitmapHeader( vfmt0.biWidth, vfmt0.biHeight, 24 ); + + if( hic == 0 || fourcc != vfmt0.biCompression || + prevWidth != vfmt0.biWidth || prevHeight != vfmt0.biHeight ) + { + closeHIC(); + hic = ICOpen( MAKEFOURCC('V','I','D','C'), + vfmt0.biCompression, ICMODE_DECOMPRESS ); + if( hic ) + { + if( ICDecompressBegin( hic, &vfmt0, &vfmt1 ) != ICERR_OK ) + { + closeHIC(); + return 0; + } + } + } + + if( !hic || ICDecompress( hic, 0, &vfmt0, hdr->lpData, + &vfmt1, frame->imageData ) != ICERR_OK ) + { + closeHIC(); + return 0; + } + + cvFlip( frame, frame, 0 ); + } + else + { + IplImage src; + cvInitImageHeader( &src, cvSize(vfmt0.biWidth, vfmt0.biHeight), + IPL_DEPTH_8U, 3, IPL_ORIGIN_BL, 4 ); + cvSetData( &src, hdr->lpData, src.widthStep ); + cvFlip( &src, frame, 0 ); + } + + return frame; +} + + +double CvCaptureCAM_VFW::getProperty( int property_id ) +{ + switch( property_id ) + { + case CV_CAP_PROP_FRAME_WIDTH: + return frame ? frame->width : 0; + case CV_CAP_PROP_FRAME_HEIGHT: + return frame ? frame->height : 0; + case CV_CAP_PROP_FOURCC: + return fourcc; + } + return 0; +} + + +CvCapture* cvCreateCameraCapture_VFW( int index ) +{ + CvCaptureCAM_VFW* capture = new CvCaptureCAM_VFW; + + if( capture->open( index )) + return capture; + + delete capture; + return 0; +} + + +/*************************** writing AVIs ******************************/ + +class CvVideoWriter_VFW : public CvVideoWriter +{ +public: + CvVideoWriter_VFW() { init(); } + virtual ~CvVideoWriter_VFW() { close(); } + + virtual bool open( const char* filename, int fourcc, + double fps, CvSize frameSize, bool isColor ); + virtual void close(); + virtual bool writeFrame( const IplImage* ); + +protected: + void init(); + bool createStreams( CvSize frameSize, bool isColor ); + + PAVIFILE avifile; + PAVISTREAM compressed; + PAVISTREAM uncompressed; + double fps; + IplImage* tempFrame; + long pos; + int fourcc; +}; + + +void CvVideoWriter_VFW::init() +{ + avifile = 0; + compressed = uncompressed = 0; + fps = 0; + tempFrame = 0; + pos = 0; + fourcc = 0; +} + +void CvVideoWriter_VFW::close() +{ + if( uncompressed ) + AVIStreamRelease( uncompressed ); + if( compressed ) + AVIStreamRelease( compressed ); + if( avifile ) + AVIFileRelease( avifile ); + cvReleaseImage( &tempFrame ); + init(); +} + + +// philipg. Made this code capable of writing 8bpp gray scale bitmaps +struct BITMAPINFO_8Bit +{ + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[256]; +}; + + +bool CvVideoWriter_VFW::open( const char* filename, int _fourcc, double _fps, CvSize frameSize, bool isColor ) +{ + close(); + + icvInitCapture_VFW(); + if( AVIFileOpen( &avifile, filename, OF_CREATE | OF_WRITE, 0 ) == AVIERR_OK ) + { + fourcc = _fourcc; + fps = _fps; + if( frameSize.width > 0 && frameSize.height > 0 && + !createStreams( frameSize, isColor ) ) + { + close(); + return false; + } + } + return true; +} + + +bool CvVideoWriter_VFW::createStreams( CvSize frameSize, bool isColor ) +{ + if( !avifile ) + return false; + AVISTREAMINFO aviinfo; + + BITMAPINFO_8Bit bmih; + bmih.bmiHeader = icvBitmapHeader( frameSize.width, frameSize.height, isColor ? 24 : 8 ); + for( int i = 0; i < 256; i++ ) + { + bmih.bmiColors[i].rgbBlue = (BYTE)i; + bmih.bmiColors[i].rgbGreen = (BYTE)i; + bmih.bmiColors[i].rgbRed = (BYTE)i; + bmih.bmiColors[i].rgbReserved = 0; + } + + memset( &aviinfo, 0, sizeof(aviinfo)); + aviinfo.fccType = streamtypeVIDEO; + aviinfo.fccHandler = 0; + // use highest possible accuracy for dwRate/dwScale + aviinfo.dwScale = (DWORD)((double)0x7FFFFFFF / fps); + aviinfo.dwRate = cvRound(fps * aviinfo.dwScale); + aviinfo.rcFrame.top = aviinfo.rcFrame.left = 0; + aviinfo.rcFrame.right = frameSize.width; + aviinfo.rcFrame.bottom = frameSize.height; + + if( AVIFileCreateStream( avifile, &uncompressed, &aviinfo ) == AVIERR_OK ) + { + AVICOMPRESSOPTIONS copts, *pcopts = &copts; + copts.fccType = streamtypeVIDEO; + copts.fccHandler = fourcc != -1 ? fourcc : 0; + copts.dwKeyFrameEvery = 1; + copts.dwQuality = 10000; + copts.dwBytesPerSecond = 0; + copts.dwFlags = AVICOMPRESSF_VALID; + copts.lpFormat = &bmih; + copts.cbFormat = (isColor ? sizeof(BITMAPINFOHEADER) : sizeof(bmih)); + copts.lpParms = 0; + copts.cbParms = 0; + copts.dwInterleaveEvery = 0; + + if( fourcc != -1 || AVISaveOptions( 0, 0, 1, &uncompressed, &pcopts ) == TRUE ) + { + if( AVIMakeCompressedStream( &compressed, uncompressed, pcopts, 0 ) == AVIERR_OK && + AVIStreamSetFormat( compressed, 0, &bmih, sizeof(bmih)) == AVIERR_OK ) + { + fps = fps; + fourcc = (int)copts.fccHandler; + frameSize = frameSize; + tempFrame = cvCreateImage( frameSize, 8, (isColor ? 3 : 1) ); + return true; + } + } + } + return false; +} + + +bool CvVideoWriter_VFW::writeFrame( const IplImage* image ) +{ + bool result = false; + CV_FUNCNAME( "CvVideoWriter_VFW::writeFrame" ); + + __BEGIN__; + + if( !image ) + EXIT; + + if( !compressed && !createStreams( cvGetSize(image), image->nChannels > 1 )) + EXIT; + + if( image->width != tempFrame->width || image->height != tempFrame->height ) + CV_ERROR( CV_StsUnmatchedSizes, + "image size is different from the currently set frame size" ); + + if( image->nChannels != tempFrame->nChannels || + image->depth != tempFrame->depth || + image->origin == 0 || + image->widthStep != cvAlign(image->width*image->nChannels*((image->depth & 255)/8), 4)) + { + cvConvertImage( image, tempFrame, image->origin == 0 ? CV_CVTIMG_FLIP : 0 ); + image = (const IplImage*)tempFrame; + } + + result = AVIStreamWrite( compressed, pos++, 1, image->imageData, + image->imageSize, AVIIF_KEYFRAME, 0, 0 ) == AVIERR_OK; + + __END__; + + return result; +} + +CvVideoWriter* cvCreateVideoWriter_VFW( const char* filename, int fourcc, + double fps, CvSize frameSize, int isColor ) +{ + CvVideoWriter_VFW* writer = new CvVideoWriter_VFW; + if( writer->open( filename, fourcc, fps, frameSize, isColor != 0 )) + return writer; + delete writer; + return 0; +} diff --git a/highgui/src/cap_ximea.cpp b/highgui/src/cap_ximea.cpp new file mode 100644 index 0000000..dbb8f58 --- /dev/null +++ b/highgui/src/cap_ximea.cpp @@ -0,0 +1,299 @@ +#include "precomp.hpp" + +#include "xiApi.h" +#include "xiExt.h" +#include "m3Api.h" + +/**********************************************************************************/ + +class CvCaptureCAM_XIMEA : public CvCapture +{ +public: + CvCaptureCAM_XIMEA() { init(); } + virtual ~CvCaptureCAM_XIMEA() { close(); } + + virtual bool open( int index ); + virtual void close(); + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual int getCaptureDomain() { return CV_CAP_XIAPI; } // Return the type of the capture object: CV_CAP_VFW, etc... + +protected: + void init(); + void errMsg(const char* msg, int errNum); + IplImage* frame; + + HANDLE hmv; + DWORD numDevices; + XI_IMG image; + int width; + int height; + int format; + int timeout; +}; + +/**********************************************************************************/ + +CvCapture* cvCreateCameraCapture_XIMEA( int index ) +{ + CvCaptureCAM_XIMEA* capture = new CvCaptureCAM_XIMEA; + + if( capture->open( index )) + return capture; + + delete capture; + return 0; +} + +/**********************************************************************************/ +// Enumerate connected devices +void CvCaptureCAM_XIMEA::init() +{ + xiGetNumberDevices( &numDevices); + hmv = NULL; + memset(&image, 0, sizeof(XI_IMG)); +} + + +/**********************************************************************************/ +// Initialize camera input +bool CvCaptureCAM_XIMEA::open( int wIndex ) +{ + int mvret = XI_OK; + + if(numDevices == 0) + return false; + + if((mvret = xiOpenDevice( wIndex, &hmv)) != XI_OK) + { + errMsg("Open XI_DEVICE failed", mvret); + return false; + } + + // always use auto exposure/gain + mvret = xiSetParamInt( hmv, XI_PRM_AEAG, 1); + if(mvret != XI_OK) goto error; + + // always use auto white ballance + mvret = xiSetParamInt( hmv, XI_PRM_AUTO_WB, 1); + if(mvret != XI_OK) goto error; + + mvret = xiGetParamInt( hmv, XI_PRM_WIDTH, &width); + if(mvret != XI_OK) goto error; + + mvret = xiGetParamInt( hmv, XI_PRM_HEIGHT, &height); + if(mvret != XI_OK) goto error; + + // default image format RGB24 + format = XI_RGB24; + mvret = xiSetParamInt( hmv, XI_PRM_IMAGE_DATA_FORMAT, format); + if(mvret != XI_OK) goto error; + + // allocate frame buffer for RGB24 image + frame = cvCreateImage(cvSize( width, height), IPL_DEPTH_8U, 3); + + //default capture timeout 10s + timeout = 10000; + + mvret = xiStartAcquisition(hmv); + if(mvret != XI_OK) + { + errMsg("StartAcquisition XI_DEVICE failed", mvret); + goto error; + } + + return true; + +error: + xiCloseDevice(hmv); + hmv = NULL; + return false; +} + +/**********************************************************************************/ + +void CvCaptureCAM_XIMEA::close() +{ + if(hmv) + { + xiStopAcquisition(hmv); + xiCloseDevice(hmv); + hmv = NULL; + } +} + +/**********************************************************************************/ + +bool CvCaptureCAM_XIMEA::grabFrame() +{ + image.size = sizeof(XI_IMG); + int mvret = xiGetImage( hmv, timeout, &image); + + if(mvret == MM40_ACQUISITION_STOPED) + { + xiStartAcquisition(hmv); + mvret = xiGetImage(hmv, timeout, &image); + } + + if(mvret != XI_OK) + { + errMsg("Error during GetImage", mvret); + return false; + } + + return true; +} + +/**********************************************************************************/ + +IplImage* CvCaptureCAM_XIMEA::retrieveFrame(int) +{ + // update cvImage after format has changed + if( (int)image.width != width || (int)image.height != height || image.frm != (XI_IMG_FORMAT)format) + { + cvReleaseImage(&frame); + switch( image.frm) + { + case XI_MONO8 : frame = cvCreateImage(cvSize( image.width, image.height), IPL_DEPTH_8U, 1); break; + case XI_MONO16 : frame = cvCreateImage(cvSize( image.width, image.height), IPL_DEPTH_16U, 1); break; + case XI_RGB24 : frame = cvCreateImage(cvSize( image.width, image.height), IPL_DEPTH_8U, 3); break; + case XI_RGB32 : frame = cvCreateImage(cvSize( image.width, image.height), IPL_DEPTH_8U, 4); break; + default : + return frame; + } + // update global image format + format = image.frm; + width = image.width; + height = image.height; + } + + // copy pixel data + switch( image.frm) + { + case XI_MONO8 : memcpy( frame->imageData, image.bp, image.width*image.height); break; + case XI_MONO16 : memcpy( frame->imageData, image.bp, image.width*image.height*sizeof(WORD)); break; + case XI_RGB24 : memcpy( frame->imageData, image.bp, image.width*image.height*3); break; + case XI_RGB32 : memcpy( frame->imageData, image.bp, image.width*image.height*sizeof(DWORD)); break; + default: break; + } + return frame; +} + +/**********************************************************************************/ + +double CvCaptureCAM_XIMEA::getProperty( int property_id ) +{ + if(hmv == NULL) + return 0; + + int ival = 0; + float fval = 0; + + switch( property_id ) + { + // OCV parameters + case CV_CAP_PROP_POS_FRAMES : return (double) image.nframe; + case CV_CAP_PROP_FRAME_WIDTH : xiGetParamInt( hmv, XI_PRM_WIDTH, &ival); return ival; + case CV_CAP_PROP_FRAME_HEIGHT : xiGetParamInt( hmv, XI_PRM_HEIGHT, &ival); return ival; + case CV_CAP_PROP_FPS : xiGetParamFloat( hmv, XI_PRM_FRAMERATE, &fval); return fval; + case CV_CAP_PROP_GAIN : xiGetParamFloat( hmv, XI_PRM_GAIN, &fval); return fval; + case CV_CAP_PROP_EXPOSURE : xiGetParamInt( hmv, XI_PRM_EXPOSURE, &ival); return ival; + + // XIMEA camera properties + case CV_CAP_PROP_XI_DOWNSAMPLING : xiGetParamInt( hmv, XI_PRM_DOWNSAMPLING, &ival); return ival; + case CV_CAP_PROP_XI_DATA_FORMAT : xiGetParamInt( hmv, XI_PRM_IMAGE_DATA_FORMAT, &ival); return ival; + case CV_CAP_PROP_XI_OFFSET_X : xiGetParamInt( hmv, XI_PRM_OFFSET_X, &ival); return ival; + case CV_CAP_PROP_XI_OFFSET_Y : xiGetParamInt( hmv, XI_PRM_OFFSET_Y, &ival); return ival; + case CV_CAP_PROP_XI_TRG_SOURCE : xiGetParamInt( hmv, XI_PRM_TRG_SOURCE, &ival); return ival; + case CV_CAP_PROP_XI_GPI_SELECTOR : xiGetParamInt( hmv, XI_PRM_GPI_SELECTOR, &ival); return ival; + case CV_CAP_PROP_XI_GPI_MODE : xiGetParamInt( hmv, XI_PRM_GPI_MODE, &ival); return ival; + case CV_CAP_PROP_XI_GPI_LEVEL : xiGetParamInt( hmv, XI_PRM_GPI_LEVEL, &ival); return ival; + case CV_CAP_PROP_XI_GPO_SELECTOR : xiGetParamInt( hmv, XI_PRM_GPO_SELECTOR, &ival); return ival; + case CV_CAP_PROP_XI_GPO_MODE : xiGetParamInt( hmv, XI_PRM_GPO_MODE, &ival); return ival; + case CV_CAP_PROP_XI_LED_SELECTOR : xiGetParamInt( hmv, XI_PRM_LED_SELECTOR, &ival); return ival; + case CV_CAP_PROP_XI_LED_MODE : xiGetParamInt( hmv, XI_PRM_LED_MODE, &ival); return ival; + case CV_CAP_PROP_XI_AUTO_WB : xiGetParamInt( hmv, XI_PRM_AUTO_WB, &ival); return ival; + case CV_CAP_PROP_XI_AEAG : xiGetParamInt( hmv, XI_PRM_AEAG, &ival); return ival; + case CV_CAP_PROP_XI_EXP_PRIORITY : xiGetParamFloat( hmv, XI_PRM_EXP_PRIORITY, &fval); return fval; + case CV_CAP_PROP_XI_AE_MAX_LIMIT : xiGetParamInt( hmv, XI_PRM_EXP_PRIORITY, &ival); return ival; + case CV_CAP_PROP_XI_AG_MAX_LIMIT : xiGetParamFloat( hmv, XI_PRM_AG_MAX_LIMIT, &fval); return fval; + case CV_CAP_PROP_XI_AEAG_LEVEL : xiGetParamInt( hmv, XI_PRM_AEAG_LEVEL, &ival); return ival; + case CV_CAP_PROP_XI_TIMEOUT : return timeout; + + } + return 0; +} + +/**********************************************************************************/ + +bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) +{ + int ival = (int) value; + float fval = (float) value; + + int mvret = XI_OK; + + switch(property_id) + { + // OCV parameters + case CV_CAP_PROP_FRAME_WIDTH : mvret = xiSetParamInt( hmv, XI_PRM_WIDTH, ival); + if(mvret == XI_OK) width = ival; + break; + case CV_CAP_PROP_FRAME_HEIGHT : mvret = xiSetParamInt( hmv, XI_PRM_HEIGHT, ival); + if(mvret == XI_OK) height = ival; + break; + case CV_CAP_PROP_FPS : mvret = xiSetParamFloat( hmv, XI_PRM_FRAMERATE, fval); break; + case CV_CAP_PROP_GAIN : mvret = xiSetParamFloat( hmv, XI_PRM_GAIN, fval); break; + case CV_CAP_PROP_EXPOSURE : mvret = xiSetParamInt( hmv, XI_PRM_EXPOSURE, ival); break; + // XIMEA camera properties + case CV_CAP_PROP_XI_DOWNSAMPLING : mvret = xiSetParamInt( hmv, XI_PRM_DOWNSAMPLING, ival); break; + case CV_CAP_PROP_XI_DATA_FORMAT : mvret = xiSetParamInt( hmv, XI_PRM_IMAGE_DATA_FORMAT, ival); + if(mvret == XI_OK) format = ival; + break; + case CV_CAP_PROP_XI_OFFSET_X : mvret = xiSetParamInt( hmv, XI_PRM_OFFSET_X, ival); break; + case CV_CAP_PROP_XI_OFFSET_Y : mvret = xiSetParamInt( hmv, XI_PRM_OFFSET_Y, ival); break; + case CV_CAP_PROP_XI_TRG_SOURCE : mvret = xiSetParamInt( hmv, XI_PRM_TRG_SOURCE, ival); break; + case CV_CAP_PROP_XI_GPI_SELECTOR : mvret = xiSetParamInt( hmv, XI_PRM_GPI_SELECTOR, ival); break; + case CV_CAP_PROP_XI_TRG_SOFTWARE : mvret = xiSetParamInt( hmv, XI_PRM_TRG_SOURCE, 1); break; + case CV_CAP_PROP_XI_GPI_MODE : mvret = xiSetParamInt( hmv, XI_PRM_GPI_MODE, ival); break; + case CV_CAP_PROP_XI_GPI_LEVEL : mvret = xiSetParamInt( hmv, XI_PRM_GPI_LEVEL, ival); break; + case CV_CAP_PROP_XI_GPO_SELECTOR : mvret = xiSetParamInt( hmv, XI_PRM_GPO_SELECTOR, ival); break; + case CV_CAP_PROP_XI_GPO_MODE : mvret = xiSetParamInt( hmv, XI_PRM_GPO_MODE, ival); break; + case CV_CAP_PROP_XI_LED_SELECTOR : mvret = xiSetParamInt( hmv, XI_PRM_LED_SELECTOR, ival); break; + case CV_CAP_PROP_XI_LED_MODE : mvret = xiSetParamInt( hmv, XI_PRM_LED_MODE, ival); break; + case CV_CAP_PROP_XI_AUTO_WB : mvret = xiSetParamInt( hmv, XI_PRM_AUTO_WB, ival); break; + case CV_CAP_PROP_XI_MANUAL_WB : mvret = xiSetParamInt( hmv, XI_PRM_LED_MODE, ival); break; + case CV_CAP_PROP_XI_AEAG : mvret = xiSetParamInt( hmv, XI_PRM_AEAG, ival); break; + case CV_CAP_PROP_XI_EXP_PRIORITY : mvret = xiSetParamFloat( hmv, XI_PRM_EXP_PRIORITY, fval); break; + case CV_CAP_PROP_XI_AE_MAX_LIMIT : mvret = xiSetParamInt( hmv, XI_PRM_EXP_PRIORITY, ival); break; + case CV_CAP_PROP_XI_AG_MAX_LIMIT : mvret = xiSetParamFloat( hmv, XI_PRM_AG_MAX_LIMIT, fval); break; + case CV_CAP_PROP_XI_AEAG_LEVEL : mvret = xiSetParamInt( hmv, XI_PRM_AEAG_LEVEL, ival); break; + case CV_CAP_PROP_XI_TIMEOUT : timeout = ival; break; + } + + if(mvret != XI_OK) + { + errMsg("Set parameter error", mvret); + return false; + } + else + return true; + +} + +/**********************************************************************************/ + +void CvCaptureCAM_XIMEA::errMsg(const char* msg, int errNum) +{ +#if defined WIN32 || defined _WIN32 + char buf[512]; + sprintf( buf, "%s : %d\n", msg, errNum); + OutputDebugString(buf); +#else + fprintf(stderr, "%s : %d\n", msg, errNum); +#endif +} + +/**********************************************************************************/ \ No newline at end of file diff --git a/highgui/src/cap_xine.cpp b/highgui/src/cap_xine.cpp new file mode 100644 index 0000000..cdaf004 --- /dev/null +++ b/highgui/src/cap_xine.cpp @@ -0,0 +1,846 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +// Authors: Konstantin Dols +// Mark Asbach +// +// Institute of Communications Engineering +// RWTH Aachen University + + +#include "precomp.hpp" + +// required to enable some functions used here... +#define XINE_ENABLE_EXPERIMENTAL_FEATURES + +#include + +extern "C" +{ +#include + //#include + + // forward declaration from + const char *xine_get_homedir( void ); +} + +typedef struct CvCaptureAVI_XINE +{ + /// method call table + xine_t * xine; + xine_stream_t * stream; + xine_video_port_t * vo_port; + + /// frame returned by xine_get_next_video_frame() + xine_video_frame_t xine_frame; + + IplImage * yuv_frame; + IplImage * bgr_frame; + + /// image dimansions of the input stream. + CvSize size; + + /// framenumber of the last frame received from xine_get_next_video_frame(). + /// note: always keep this value updated !!!! + int frame_number; + + /// framerate of the opened stream + double frame_rate; + + /// duration of a frame in stream + double frame_duration; + + /// indicated if input is seekable + bool seekable; + +} +CvCaptureAVI_XINE; + + +// 4:2:2 interleaved -> BGR +static void icvYUY2toBGR( CvCaptureAVI_XINE * capture ) +{ + uint8_t * v = capture->xine_frame.data; + int offset; + for ( int y = 0; y < capture->yuv_frame->height; y++ ) + { + offset = y * capture->yuv_frame->widthStep; + + for ( int x = 0; x < capture->yuv_frame->width; x++, offset += 3 ) + { + capture->yuv_frame->imageData[ offset + 1 ] = v[ 3 ]; + capture->yuv_frame->imageData[ offset + 2 ] = v[ 1 ]; + if ( x & 1 ) + { + capture->yuv_frame->imageData[ offset ] = v[ 2 ]; + v += 4; + } + else + { + capture->yuv_frame->imageData[ offset ] = v[ 0 ]; + } + } + } + + // convert to BGR + cvCvtColor( capture->yuv_frame, capture->bgr_frame, CV_YCrCb2BGR ); +} + + +// 4:2:0 planary -> BGR +static void icvYV12toBGR( CvCaptureAVI_XINE * capture ) +{ + IplImage * yuv = capture->yuv_frame; + int w_Y = capture->size.width; + int h_Y = capture->size.height; + + int w_UV = w_Y >> 1; + + int size_Y = w_Y * h_Y; + int size_UV = size_Y / 4; + + int line = yuv->widthStep; + + uint8_t * addr_Y = capture->xine_frame.data; + uint8_t * addr_U = addr_Y + size_Y; + uint8_t * addr_V = addr_U + size_UV; + + // YYYY..UU.VV. -> BGRBGRBGR... + for ( int y = 0; y < h_Y; y++ ) + { + int offset = y * line; + for ( int x = 0; x < w_Y; x++, offset += 3 ) + { + /* + if ( x&1 ) + { + addr_U++; addr_V++; + } + */ + int one_zero = x & 1; + addr_U += one_zero; + addr_V += one_zero; + + yuv->imageData[ offset ] = *( addr_Y++ ); + yuv->imageData[ offset + 1 ] = *addr_U; + yuv->imageData[ offset + 2 ] = *addr_V; + } + + if ( y & 1 ) + { + addr_U -= w_UV; + addr_V -= w_UV; + } + } + + /* convert to BGR */ + cvCvtColor( capture->yuv_frame, capture->bgr_frame, CV_YCrCb2BGR ); +} + +static void icvCloseAVI_XINE( CvCaptureAVI_XINE* capture ) +{ + xine_free_video_frame( capture->vo_port, &capture->xine_frame ); + + if ( capture->yuv_frame ) cvReleaseImage( &capture->yuv_frame ); + if ( capture->bgr_frame ) cvReleaseImage( &capture->bgr_frame ); + + xine_close( capture->stream ); + // xine_dispose( capture->stream ); + + if ( capture->vo_port ) xine_close_video_driver( capture->xine, capture->vo_port ); + + xine_exit( capture->xine ); +} + + +/** + * CHECKS IF THE STREAM IN * capture IS SEEKABLE. +**/ +static void icvCheckSeekAVI_XINE( CvCaptureAVI_XINE * capture ) +{ + OPENCV_ASSERT ( capture, "icvCheckSeekAVI_XINE( CvCaptureAVI_XINE* )", "illegal capture"); + OPENCV_ASSERT ( capture->stream, + "icvCheckSeekAVI_XINE( CvCaptureAVI_XINE* )", "illegal capture->stream"); + OPENCV_ASSERT ( capture->vo_port, + "icvCheckSeekAVI_XINE( CvCaptureAVI_XINE* )", "illegal capture->vo_port"); + +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvCheckSeekAVI_XINE ... start\n" ); +#endif + + // temp. frame for testing. + xine_video_frame_t tmp; + // try to seek to a future frame... + xine_play( capture->stream, 0, 300 ); /* 300msec */ + // try to receive the frame... + xine_get_next_video_frame( capture->vo_port, &tmp ); + // if the framenumber is still 0, we can't use the xine seek functionality + capture->seekable = ( tmp.frame_number != 0 ); + // reset stream + xine_play( capture->stream, 0, 0 ); + // release xine_frame + xine_free_video_frame( capture->vo_port, &tmp ); + +#ifndef NDEBUG + if ( capture->seekable ) + fprintf( stderr, "(DEBUG) icvCheckSeekAVI_XINE: Input is seekable, using XINE seek implementation.\n" ); + else + fprintf( stderr, "(DEBUG) icvCheckSeekAVI_XINE: Input is NOT seekable, using fallback function.\n" ); + + fprintf( stderr, "(DEBUG) icvCheckSeekAVI_XINE ... end\n" ); +#endif +} + + +static int icvOpenAVI_XINE( CvCaptureAVI_XINE* capture, const char* filename ) +{ +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvOpenAVI_XINE ... start\n" ); +#endif + + char configfile[ 2048 ]; + + capture->xine = xine_new(); + sprintf( configfile, "%s%s", xine_get_homedir(), "/.xine/config" ); + + xine_config_load( capture->xine, configfile ); + xine_init( capture->xine ); + + xine_engine_set_param( capture->xine, 0, 0 ); + capture->vo_port = xine_new_framegrab_video_port( capture->xine ); + if ( capture->vo_port == NULL ) + { + printf( "(ERROR)icvOpenAVI_XINE(): Unable to initialize video driver.\n" ); + return 0; + } + + capture->stream = xine_stream_new( capture->xine, NULL, capture->vo_port ); + + if ( !xine_open( capture->stream, filename ) ) + { + printf( "(ERROR)icvOpenAVI_XINE(): Unable to open source '%s'\n", filename ); + return 0; + } + // reset stream... + xine_play( capture->stream, 0, 0 ); + + + // initialize some internals... + capture->frame_number = 0; + + if ( !xine_get_next_video_frame( capture->vo_port, &capture->xine_frame ) ) + { +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvOpenAVI_XINE ... failed!\n" ); +#endif + return 0; + } + + capture->size = cvSize( capture->xine_frame.width, capture->xine_frame.height ); + capture->yuv_frame = cvCreateImage( capture->size, IPL_DEPTH_8U, 3 ); + capture->bgr_frame = cvCreateImage( capture->size, IPL_DEPTH_8U, 3 ); + + xine_free_video_frame( capture->vo_port, &capture->xine_frame ); + capture->xine_frame.data[ 0 ] = 0; + + icvCheckSeekAVI_XINE( capture ); + + capture->frame_duration = xine_get_stream_info( capture->stream, XINE_STREAM_INFO_FRAME_DURATION ) / 90.; + capture->frame_rate = 1000 / capture->frame_duration; + +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) frame_duration = %f, framerate = %f\n", capture->frame_duration, capture->frame_rate ); +#endif + + OPENCV_ASSERT ( capture->yuv_frame, + "icvOpenAVI_XINE( CvCaptureAVI_XINE *, const char *)", "couldn't create yuv frame"); + + OPENCV_ASSERT ( capture->bgr_frame, + "icvOpenAVI_XINE( CvCaptureAVI_XINE *, const char *)", "couldn't create bgr frame"); + +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvOpenAVI_XINE ... end\n" ); +#endif + return 1; +} + + +static int icvGrabFrameAVI_XINE( CvCaptureAVI_XINE* capture ) +{ +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvGrabFrameAVI_XINE ... start\n" ); +#endif + + OPENCV_ASSERT ( capture, + "icvGrabFrameAVI_XINE( CvCaptureAVI_XINE * )", "illegal capture"); + OPENCV_ASSERT ( capture->vo_port, + "icvGrabFrameAVI_XINE( CvCaptureAVI_XINE * )", "illegal capture->vo_port"); + + int res = xine_get_next_video_frame( capture->vo_port, &capture->xine_frame ); + + /* always keep internal framenumber updated !!! */ + if ( res ) capture->frame_number++; + +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvGrabFrameAVI_XINE ... end\n" ); +#endif + return res; +} + + +static const IplImage* icvRetrieveFrameAVI_XINE( CvCaptureAVI_XINE* capture, int ) +{ +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvRetrieveFrameAVI_XINE ... start\n" ); +#endif + + OPENCV_ASSERT ( capture, + "icvRetrieveFrameAVI_XINE( CvCaptureAVI_XINE * )", "illegal capture"); + OPENCV_ASSERT ( capture->stream, + "icvRetrieveFrameAVI_XINE( CvCaptureAVI_XINE * )", "illegal capture->stream"); + OPENCV_ASSERT ( capture->vo_port, + "icvRetrieveFrameAVI_XINE( CvCaptureAVI_XINE * )", "illegal capture->vo_port"); + + /* no frame grabbed yet? so let's do it now! */ + int res = 0; + if ( capture->xine_frame.data == 0 ) + { + res = icvGrabFrameAVI_XINE( capture ); + } + else + { + res = 1; + } + + if ( res ) + { + switch ( capture->xine_frame.colorspace ) + { + case XINE_IMGFMT_YV12: icvYV12toBGR( capture ); +#ifndef NDEBUG + printf( "(DEBUG)icvRetrieveFrameAVI_XINE: converted YV12 to BGR.\n" ); +#endif + break; + + case XINE_IMGFMT_YUY2: icvYUY2toBGR( capture ); +#ifndef NDEBUG + printf( "(DEBUG)icvRetrieveFrameAVI_XINE: converted YUY2 to BGR.\n" ); +#endif + break; + case XINE_IMGFMT_XVMC: printf( "(ERROR)icvRetrieveFrameAVI_XINE: XVMC format not supported!\n" ); + break; + + case XINE_IMGFMT_XXMC: printf( "(ERROR)icvRetrieveFrameAVI_XINE: XXMC format not supported!\n" ); + break; + + default: printf( "(ERROR)icvRetrieveFrameAVI_XINE: unknown color/pixel format!\n" ); + } + + /* always release last xine_frame, not needed anymore, but store its frame_number in *capture ! */ + xine_free_video_frame( capture->vo_port, &capture->xine_frame ); + capture->xine_frame.data = 0; + +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvRetrieveFrameAVI_XINE ... end\n" ); +#endif + return capture->bgr_frame; + } + +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvRetrieveFrameAVI_XINE ... failed!\n" ); +#endif + return 0; +} + + +/** + * THIS FUNCTION IS A FALLBACK FUNCTION FOR THE CASE THAT THE XINE SEEK IMPLEMENTATION + * DOESN'T WORK WITH THE ACTUAL INPUT. THIS FUNCTION IS ONLY USED IN THE CASE OF AN EMERGENCY, + * BECAUSE IT IS VERY SLOW ! +**/ +static int icvOldSeekFrameAVI_XINE( CvCaptureAVI_XINE* capture, int f ) +{ +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvOldSeekFrameAVI_XINE ... start\n" ); +#endif + + OPENCV_ASSERT ( capture, + "icvRetricvOldSeekFrameAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture"); + OPENCV_ASSERT ( capture->stream, + "icvOldSeekFrameAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture->stream"); + OPENCV_ASSERT ( capture->vo_port, + "icvOldSeekFrameAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture->vo_port"); + +// not needed tnx to asserts... + // we need a valid capture context and it's stream to seek through +// if ( !capture || !capture->stream ) return 0; + + // no need to seek if we are already there... + if ( f == capture->frame_number ) + { +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvOldSeekFrameAVI_XINE ... end\n" ); +#endif + return 1; + } + // if the requested position is behind out actual position, + // we just need to read the remaining amount of frames until we are there. + else if ( f > capture->frame_number ) + { + for ( ;capture->frame_number < f;capture->frame_number++ ) + /// un-increment framenumber grabbing failed + if ( !xine_get_next_video_frame( capture->vo_port, &capture->xine_frame ) ) + { + capture->frame_number--; + break; + } + else + { + xine_free_video_frame( capture->vo_port, &capture->xine_frame ); + } + } + // otherwise we need to reset the stream and + // start reading frames from the beginning. + else // f < capture->frame_number + { + /// reset stream, should also work with non-seekable input + xine_play( capture->stream, 0, 0 ); + /// read frames until we are at the requested frame + for ( capture->frame_number = 0; capture->frame_number < f; capture->frame_number++ ) + /// un-increment last framenumber if grabbing failed + if ( !xine_get_next_video_frame( capture->vo_port, &capture->xine_frame ) ) + { + capture->frame_number--; + break; + } + else + { + xine_free_video_frame( capture->vo_port, &capture->xine_frame ); + } + } + + +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvOldSeekFrameAVI_XINE ... end\n" ); +#endif + return ( f == capture->frame_number ) ? 1 : 0; +} + + +static int icvSeekFrameAVI_XINE( CvCaptureAVI_XINE* capture, int f ) +{ +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSeekFrameAVI_XINE ... start\n" ); +#endif + + OPENCV_ASSERT ( capture, + "icvSeekFrameAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture"); + OPENCV_ASSERT ( capture->stream, + "icvSeekFrameAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture->stream"); + OPENCV_ASSERT ( capture->vo_port, + "icvSeekFrameAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture->vo_port"); + +// not needed tnx to asserts... + // we need a valid capture context and it's stream to seek through +// if ( !capture || !capture->stream ) return 0; + + if ( capture->seekable ) + { + + /// use xinelib's seek functionality + int new_time = ( int ) ( ( f + 1 ) * ( float ) capture->frame_duration ); + +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) calling xine_play()" ); +#endif + if ( xine_play( capture->stream, 0, new_time ) ) + { +#ifndef NDEBUG + fprintf( stderr, "ok\n" ); + fprintf( stderr, "(DEBUG) icvSeekFrameAVI_XINE ... end\n" ); +#endif + capture->frame_number = f; + return 1; + } + else + { +#ifndef NDEBUG + fprintf( stderr, "failed\n" ); + fprintf( stderr, "(DEBUG) icvSeekFrameAVI_XINE ... failed\n" ); +#endif + return 0; + } + } + else + { +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSeekFrameAVI_XINE ... end\n" ); +#endif + return icvOldSeekFrameAVI_XINE( capture, f ); + } +} + + +static int icvSeekTimeAVI_XINE( CvCaptureAVI_XINE* capture, int t ) +{ +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSeekTimeAVI_XINE ... start\n" ); +#endif + + OPENCV_ASSERT ( capture, + "icvSeekTimeAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture"); + OPENCV_ASSERT ( capture->stream, + "icvSeekTimeAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture->stream"); + OPENCV_ASSERT ( capture->vo_port, + "icvSeekTimeAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture->vo_port"); + +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSeekTimeAVI_XINE ... start\n" ); +#endif + +// not needed tnx to asserts... + // we need a valid capture context and it's stream to seek through +// if ( !capture || !capture->stream ) return 0; + + if ( capture->seekable ) + { + /// use xinelib's seek functionality + if ( xine_play( capture->stream, 0, t ) ) + { + capture->frame_number = ( int ) ( ( float ) t * capture->frame_rate / 1000 ); +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSeekFrameAVI_XINE ... end\n" ); +#endif + return 1; + } + else + { +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSeekFrameAVI_XINE ... failed!\n" ); +#endif + return 0; + } + } + else + { + int new_frame = ( int ) ( ( float ) t * capture->frame_rate / 1000 ); +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSeekFrameAVI_XINE ....end\n" ); +#endif + return icvOldSeekFrameAVI_XINE( capture, new_frame ); + } +} + + +static int icvSeekRatioAVI_XINE( CvCaptureAVI_XINE* capture, double ratio ) +{ +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSeekRatioAVI_XINE ... start\n" ); +#endif + + OPENCV_ASSERT ( capture, + "icvSeekRatioAVI_XINE( CvCaptureAVI_XINE *, double )", "illegal capture"); + OPENCV_ASSERT ( capture->stream, + "icvSeekRatioAVI_XINE( CvCaptureAVI_XINE *, double )", "illegal capture->stream"); + OPENCV_ASSERT ( capture->vo_port, + "icvSeekRatioAVI_XINE( CvCaptureAVI_XINE *, double )", "illegal capture->vo_port"); + +// not needed tnx to asserts... + // we need a valid capture context and it's stream to seek through +// if ( !capture || !capture->stream ) return 0; + + /// ratio must be [0..1] + if ( ratio > 1 || ratio < 0 ) return 0; + + if ( capture->seekable ) + { + // TODO: FIX IT, DOESN'T WORK PROPERLY, YET...! + int pos_t, pos_l, length; + xine_get_pos_length( capture->stream, &pos_l, &pos_t, &length ); + fprintf( stderr, "ratio on GetProperty(): %d\n", pos_l ); + + /// use xinelib's seek functionality + if ( xine_play( capture->stream, (int)(ratio*(float)length), 0 ) ) + { + capture->frame_number = ( int ) ( ratio*length / capture->frame_duration ); + } + else + { +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSeekRatioAVI_XINE ... failed!\n" ); +#endif + return 0; + } + } + else + { + /// TODO: fill it ! + fprintf( stderr, "icvSeekRatioAVI_XINE(): Seek not supported by stream !\n" ); + fprintf( stderr, "icvSeekRatioAVI_XINE(): (seek in stream with NO seek support NOT implemented...yet!)\n" ); +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSeekRatioAVI_XINE ... failed!\n" ); +#endif + return 0; + } + +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSeekRatioAVI_XINE ... end!\n" ); +#endif + return 1; +} + + +static double icvGetPropertyAVI_XINE( CvCaptureAVI_XINE* capture, int property_id ) +{ +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvGetPropertyAVI_XINE ... start\n" ); +#endif + + OPENCV_ASSERT ( capture, + "icvGetPropertyAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture"); + OPENCV_ASSERT ( capture->stream, + "icvGetPropertyAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture->stream"); + OPENCV_ASSERT ( capture->vo_port, + "icvGetPropertyAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture->vo_port"); + OPENCV_ASSERT ( capture->xine, + "icvGetPropertyAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture->xine"); + OPENCV_ASSERT ( capture->bgr_frame, + "icvGetPropertyAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture->bgr_frame"); + +// not needed tnx to asserts... + // we need a valid capture context and it's stream to seek through +// if ( !capture || !capture->stream || !capture->bgr_frame || !capture->xine || !capture->vo_port ) return 0 + + int pos_t, pos_l, length; + xine_get_pos_length( capture->stream, &pos_l, &pos_t, &length ); + fprintf( stderr, "ratio on GetProperty(): %i\n", pos_l ); + + switch ( property_id ) + { + /// return actual position in msec + case CV_CAP_PROP_POS_MSEC: + if ( !capture->seekable ) + { + fprintf( stderr, "(ERROR) GetPropertyAVI_XINE(CV_CAP_PROP_POS_MSEC:\n" ); + fprintf( stderr, " Stream is NOT seekable, so position info may NOT be valid !!\n" ); + } + return pos_t; + + /// return actual frame number + case CV_CAP_PROP_POS_FRAMES: + /// we insist the capture->frame_number to be remain updated !!!! + return capture->frame_number; + + /// return actual position ratio in the range [0..1] depending on + /// the total length of the stream and the actual position + case CV_CAP_PROP_POS_AVI_RATIO: + if ( !capture->seekable ) + { + fprintf( stderr, "(ERROR) GetPropertyAVI_XINE(CV_CAP_PROP_POS_AVI_RATIO:\n" ); + fprintf( stderr, " Stream is NOT seekable, so ratio info may NOT be valid !!\n" ); + } + if ( length == 0 ) break; + else return pos_l / 65535; + + + /// return width of image source + case CV_CAP_PROP_FRAME_WIDTH: + return capture->size.width; + + /// return height of image source + case CV_CAP_PROP_FRAME_HEIGHT: + return capture->size.height; + + /// return framerate of stream + case CV_CAP_PROP_FPS: + if ( !capture->seekable ) + { + fprintf( stderr, "(ERROR) GetPropertyAVI_XINE(CV_CAP_PROP_FPS:\n" ); + fprintf( stderr, " Stream is NOT seekable, so FPS info may NOT be valid !!\n" ); + } + return capture->frame_rate; + + /// return four-character-code (FOURCC) of source's codec + case CV_CAP_PROP_FOURCC: + return ( double ) xine_get_stream_info( capture->stream, XINE_STREAM_INFO_VIDEO_FOURCC ); + } + +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvGetPropertyAVI_XINE ... failed!\n" ); +#endif + + return 0; +} + + +static int icvSetPropertyAVI_XINE( CvCaptureAVI_XINE* capture, + int property_id, double value ) +{ +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSetPropertyAVI_XINE ... start\n" ); +#endif + + OPENCV_ASSERT ( capture, + "icvSetPropertyAVI_XINE( CvCaptureAVI_XINE *, int, double )", "illegal capture"); + OPENCV_ASSERT ( capture->stream, + "icvGetPropericvSetPropertyAVI_XINE( CvCaptureAVI_XINE *, int )", "illegal capture->stream"); + OPENCV_ASSERT ( capture->vo_port, + "icvSetPropertyAVI_XINE( CvCaptureAVI_XINE *, int, double )", "illegal capture->vo_port"); + +// not needed tnx to asserts... + // we need a valid capture context and it's stream to seek through +// if ( !capture || !capture->stream || !capture->bgr_frame || !capture->xine || !capture->vo_port ) return 0 + +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSetPropertyAVI_XINE: seeking to value %f ... ", value ); +#endif + + switch ( property_id ) + { + /// set (seek to) position in msec + case CV_CAP_PROP_POS_MSEC: + return icvSeekTimeAVI_XINE( capture, ( int ) value ); + + /// set (seek to) frame number + case CV_CAP_PROP_POS_FRAMES: + return icvSeekFrameAVI_XINE( capture, ( int ) value ); + + /// set (seek to) position ratio in the range [0..1] depending on + /// the total length of the stream and the actual position + case CV_CAP_PROP_POS_AVI_RATIO: + return icvSeekRatioAVI_XINE( capture, value ); + + default: +#ifndef NDEBUG + fprintf( stderr, "(DEBUG) icvSetPropertyAVI_XINE ... failed!\n" ); +#endif + + return 0; + } +} + + +static CvCaptureAVI_XINE* icvCaptureFromFile_XINE( const char* filename ) +{ + // construct capture struct + CvCaptureAVI_XINE * capture = ( CvCaptureAVI_XINE* ) cvAlloc ( sizeof ( CvCaptureAVI_XINE ) ); + memset( capture, 0, sizeof ( CvCaptureAVI_XINE ) ); + + // initialize XINE + if ( !icvOpenAVI_XINE( capture, filename ) ) + return 0; + + OPENCV_ASSERT ( capture, + "cvCaptureFromFile_XINE( const char * )", "couldn't create capture"); + + return capture; + +} + + + +class CvCaptureAVI_XINE_CPP : public CvCapture +{ +public: + CvCaptureAVI_XINE_CPP() { captureXINE = 0; } + virtual ~CvCaptureAVI_XINE_CPP() { close(); } + + virtual bool open( const char* filename ); + virtual void close(); + + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); +protected: + + CvCaptureAVI_XINE* captureXINE; +}; + +bool CvCaptureAVI_XINE_CPP::open( const char* filename ) +{ + close(); + captureXINE = icvCaptureFromFile_XINE(filename); + return captureXINE != 0; +} + +void CvCaptureAVI_XINE_CPP::close() +{ + if( captureXINE ) + { + icvCloseAVI_XINE( captureXINE ); + cvFree( &captureXINE ); + } +} + +bool CvCaptureAVI_XINE_CPP::grabFrame() +{ + return captureXINE ? icvGrabFrameAVI_XINE( captureXINE ) != 0 : false; +} + +IplImage* CvCaptureAVI_XINE_CPP::retrieveFrame(int) +{ + return captureXINE ? (IplImage*)icvRetrieveFrameAVI_XINE( captureXINE, 0 ) : 0; +} + +double CvCaptureAVI_XINE_CPP::getProperty( int propId ) +{ + return captureXINE ? icvGetPropertyAVI_XINE( captureXINE, propId ) : 0; +} + +bool CvCaptureAVI_XINE_CPP::setProperty( int propId, double value ) +{ + return captureXINE ? icvSetPropertyAVI_XINE( captureXINE, propId, value ) != 0 : false; +} + +CvCapture* cvCreateFileCapture_XINE(const char* filename) +{ + CvCaptureAVI_XINE_CPP* capture = new CvCaptureAVI_XINE_CPP; + + if( capture->open(filename)) + return capture; + + delete capture; + return 0; +} + + +#undef NDEBUG diff --git a/highgui/src/ffmpeg_codecs.hpp b/highgui/src/ffmpeg_codecs.hpp new file mode 100644 index 0000000..a9654ad --- /dev/null +++ b/highgui/src/ffmpeg_codecs.hpp @@ -0,0 +1,256 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(WIN32) || defined(__MINGW32__) +// some versions of FFMPEG assume a C99 compiler, and don't define INT64_C +#if !defined INT64_C || !defined UINT64_C +#define INT64_C +#define UINT64_C + #define __STDC_CONSTANT_MACROS +// force re-inclusion of stdint.h to get INT64_C macro +#undef _STDINT_H +#include +#endif +#include +#endif + +#ifdef WIN32 + #include +#else + +// if the header path is not specified explicitly, let's deduce it +#if !defined HAVE_FFMPEG_AVCODEC_H && !defined HAVE_LIBAVCODEC_AVCODEC_H + +#if defined(HAVE_GENTOO_FFMPEG) + #define HAVE_LIBAVFORMAT_AVFORMAT_H 1 +#elif defined HAVE_FFMPEG + #define HAVE_FFMPEG_AVFORMAT_H 1 +#endif + +#if defined(HAVE_FFMPEG_AVFORMAT_H) + #include +#endif + +#if defined(HAVE_LIBAVFORMAT_AVFORMAT_H) + #include +#endif + +#endif + +#endif + +#ifdef __cplusplus +} +#endif + +#ifndef MKTAG +#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24)) +#endif + +// required to look up the correct codec ID depending on the FOURCC code, +// this is just a snipped from the file riff.c from ffmpeg/libavformat +typedef struct AVCodecTag { + int id; + unsigned int tag; +} AVCodecTag; + +const AVCodecTag codec_bmp_tags[] = { + { CODEC_ID_H264, MKTAG('H', '2', '6', '4') }, + { CODEC_ID_H264, MKTAG('h', '2', '6', '4') }, + { CODEC_ID_H264, MKTAG('X', '2', '6', '4') }, + { CODEC_ID_H264, MKTAG('x', '2', '6', '4') }, + { CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') }, + { CODEC_ID_H264, MKTAG('V', 'S', 'S', 'H') }, + + { CODEC_ID_H263, MKTAG('H', '2', '6', '3') }, + { CODEC_ID_H263P, MKTAG('H', '2', '6', '3') }, + { CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* intel h263 */ + { CODEC_ID_H261, MKTAG('H', '2', '6', '1') }, + + /* added based on MPlayer */ + { CODEC_ID_H263P, MKTAG('U', '2', '6', '3') }, + { CODEC_ID_H263P, MKTAG('v', 'i', 'v', '1') }, + + { CODEC_ID_MPEG4, MKTAG('F', 'M', 'P', '4') }, + { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X') }, + { CODEC_ID_MPEG4, MKTAG('D', 'X', '5', '0') }, + { CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') }, + { CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') }, + { CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') }, + { CODEC_ID_MPEG4, MKTAG(0x04, 0, 0, 0) }, /* some broken avi use this */ + + /* added based on MPlayer */ + { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', '1') }, + { CODEC_ID_MPEG4, MKTAG('B', 'L', 'Z', '0') }, + { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') }, + { CODEC_ID_MPEG4, MKTAG('U', 'M', 'P', '4') }, + { CODEC_ID_MPEG4, MKTAG('W', 'V', '1', 'F') }, + { CODEC_ID_MPEG4, MKTAG('S', 'E', 'D', 'G') }, + + { CODEC_ID_MPEG4, MKTAG('R', 'M', 'P', '4') }, + + { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '3') }, /* default signature when using MSMPEG4 */ + { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') }, + + /* added based on MPlayer */ + { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', 'G', '3') }, + { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '5') }, + { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '6') }, + { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '4') }, + { CODEC_ID_MSMPEG4V3, MKTAG('A', 'P', '4', '1') }, + { CODEC_ID_MSMPEG4V3, MKTAG('C', 'O', 'L', '1') }, + { CODEC_ID_MSMPEG4V3, MKTAG('C', 'O', 'L', '0') }, + + { CODEC_ID_MSMPEG4V2, MKTAG('M', 'P', '4', '2') }, + + /* added based on MPlayer */ + { CODEC_ID_MSMPEG4V2, MKTAG('D', 'I', 'V', '2') }, + + { CODEC_ID_MSMPEG4V1, MKTAG('M', 'P', 'G', '4') }, + + { CODEC_ID_WMV1, MKTAG('W', 'M', 'V', '1') }, + + /* added based on MPlayer */ + { CODEC_ID_WMV2, MKTAG('W', 'M', 'V', '2') }, + { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'd') }, + { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', 'd') }, + { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'l') }, + { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '2', '5') }, + { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '1') }, + { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '2') }, + { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', 'g', '2') }, + { CODEC_ID_MPEG2VIDEO, MKTAG('M', 'P', 'E', 'G') }, + { CODEC_ID_MPEG1VIDEO, MKTAG('P', 'I', 'M', '1') }, + { CODEC_ID_MPEG1VIDEO, MKTAG('V', 'C', 'R', '2') }, + { CODEC_ID_MPEG1VIDEO, 0x10000001 }, + { CODEC_ID_MPEG2VIDEO, 0x10000002 }, + { CODEC_ID_MPEG2VIDEO, MKTAG('D', 'V', 'R', ' ') }, + { CODEC_ID_MPEG2VIDEO, MKTAG('M', 'M', 'E', 'S') }, + { CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') }, + { CODEC_ID_MJPEG, MKTAG('L', 'J', 'P', 'G') }, + { CODEC_ID_LJPEG, MKTAG('L', 'J', 'P', 'G') }, + { CODEC_ID_MJPEG, MKTAG('J', 'P', 'G', 'L') }, /* Pegasus lossless JPEG */ + { CODEC_ID_MJPEG, MKTAG('M', 'J', 'L', 'S') }, /* JPEG-LS custom FOURCC for avi - decoder */ + { CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') }, + { CODEC_ID_MJPEG, MKTAG('I', 'J', 'P', 'G') }, + { CODEC_ID_MJPEG, MKTAG('A', 'V', 'R', 'n') }, + { CODEC_ID_HUFFYUV, MKTAG('H', 'F', 'Y', 'U') }, + { CODEC_ID_FFVHUFF, MKTAG('F', 'F', 'V', 'H') }, + { CODEC_ID_CYUV, MKTAG('C', 'Y', 'U', 'V') }, + { CODEC_ID_RAWVIDEO, 0 }, + { CODEC_ID_RAWVIDEO, MKTAG('I', '4', '2', '0') }, + { CODEC_ID_RAWVIDEO, MKTAG('Y', 'U', 'Y', '2') }, + { CODEC_ID_RAWVIDEO, MKTAG('Y', '4', '2', '2') }, + { CODEC_ID_RAWVIDEO, MKTAG('Y', 'V', '1', '2') }, + { CODEC_ID_RAWVIDEO, MKTAG('U', 'Y', 'V', 'Y') }, + { CODEC_ID_RAWVIDEO, MKTAG('I', 'Y', 'U', 'V') }, + { CODEC_ID_RAWVIDEO, MKTAG('Y', '8', '0', '0') }, + { CODEC_ID_RAWVIDEO, MKTAG('H', 'D', 'Y', 'C') }, + { CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '1') }, + { CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '2') }, + { CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') }, + { CODEC_ID_VP3, MKTAG('V', 'P', '3', '0') }, + { CODEC_ID_ASV1, MKTAG('A', 'S', 'V', '1') }, + { CODEC_ID_ASV2, MKTAG('A', 'S', 'V', '2') }, + { CODEC_ID_VCR1, MKTAG('V', 'C', 'R', '1') }, + { CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') }, + { CODEC_ID_XAN_WC4, MKTAG('X', 'x', 'a', 'n') }, + { CODEC_ID_MSRLE, MKTAG('m', 'r', 'l', 'e') }, + { CODEC_ID_MSRLE, MKTAG(0x1, 0x0, 0x0, 0x0) }, + { CODEC_ID_MSVIDEO1, MKTAG('M', 'S', 'V', 'C') }, + { CODEC_ID_MSVIDEO1, MKTAG('m', 's', 'v', 'c') }, + { CODEC_ID_MSVIDEO1, MKTAG('C', 'R', 'A', 'M') }, + { CODEC_ID_MSVIDEO1, MKTAG('c', 'r', 'a', 'm') }, + { CODEC_ID_MSVIDEO1, MKTAG('W', 'H', 'A', 'M') }, + { CODEC_ID_MSVIDEO1, MKTAG('w', 'h', 'a', 'm') }, + { CODEC_ID_CINEPAK, MKTAG('c', 'v', 'i', 'd') }, + { CODEC_ID_TRUEMOTION1, MKTAG('D', 'U', 'C', 'K') }, + { CODEC_ID_MSZH, MKTAG('M', 'S', 'Z', 'H') }, + { CODEC_ID_ZLIB, MKTAG('Z', 'L', 'I', 'B') }, + { CODEC_ID_SNOW, MKTAG('S', 'N', 'O', 'W') }, + { CODEC_ID_4XM, MKTAG('4', 'X', 'M', 'V') }, + { CODEC_ID_FLV1, MKTAG('F', 'L', 'V', '1') }, + { CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', '1') }, + { CODEC_ID_TSCC, MKTAG('t', 's', 'c', 'c') }, + { CODEC_ID_ULTI, MKTAG('U', 'L', 'T', 'I') }, + { CODEC_ID_VIXL, MKTAG('V', 'I', 'X', 'L') }, + { CODEC_ID_QPEG, MKTAG('Q', 'P', 'E', 'G') }, + { CODEC_ID_QPEG, MKTAG('Q', '1', '.', '0') }, + { CODEC_ID_QPEG, MKTAG('Q', '1', '.', '1') }, + { CODEC_ID_WMV3, MKTAG('W', 'M', 'V', '3') }, + { CODEC_ID_LOCO, MKTAG('L', 'O', 'C', 'O') }, + { CODEC_ID_THEORA, MKTAG('t', 'h', 'e', 'o') }, +#if LIBAVCODEC_VERSION_INT>0x000409 + { CODEC_ID_WNV1, MKTAG('W', 'N', 'V', '1') }, + { CODEC_ID_AASC, MKTAG('A', 'A', 'S', 'C') }, + { CODEC_ID_INDEO2, MKTAG('R', 'T', '2', '1') }, + { CODEC_ID_FRAPS, MKTAG('F', 'P', 'S', '1') }, + { CODEC_ID_TRUEMOTION2, MKTAG('T', 'M', '2', '0') }, +#endif +#if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0) + { CODEC_ID_FLASHSV, MKTAG('F', 'S', 'V', '1') }, + { CODEC_ID_JPEGLS,MKTAG('M', 'J', 'L', 'S') }, /* JPEG-LS custom FOURCC for avi - encoder */ + { CODEC_ID_VC1, MKTAG('W', 'V', 'C', '1') }, + { CODEC_ID_VC1, MKTAG('W', 'M', 'V', 'A') }, + { CODEC_ID_CSCD, MKTAG('C', 'S', 'C', 'D') }, + { CODEC_ID_ZMBV, MKTAG('Z', 'M', 'B', 'V') }, + { CODEC_ID_KMVC, MKTAG('K', 'M', 'V', 'C') }, +#endif +#if LIBAVCODEC_VERSION_INT>((51<<16)+(11<<8)+0) + { CODEC_ID_VP5, MKTAG('V', 'P', '5', '0') }, + { CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') }, + { CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') }, + { CODEC_ID_VP6, MKTAG('V', 'P', '6', '2') }, + { CODEC_ID_VP6F, MKTAG('V', 'P', '6', 'F') }, + { CODEC_ID_JPEG2000, MKTAG('M', 'J', '2', 'C') }, + { CODEC_ID_VMNC, MKTAG('V', 'M', 'n', 'c') }, +#endif +#if LIBAVCODEC_VERSION_INT>=((51<<16)+(49<<8)+0) +// this tag seems not to exist in older versions of FFMPEG + { CODEC_ID_TARGA, MKTAG('t', 'g', 'a', ' ') }, +#endif + { CODEC_ID_NONE, 0 }, +}; diff --git a/highgui/src/files_Qt/Milky/48/1.png b/highgui/src/files_Qt/Milky/48/1.png new file mode 100644 index 0000000..af3dc13 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/1.png differ diff --git a/highgui/src/files_Qt/Milky/48/10.png b/highgui/src/files_Qt/Milky/48/10.png new file mode 100644 index 0000000..d016260 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/10.png differ diff --git a/highgui/src/files_Qt/Milky/48/100.png b/highgui/src/files_Qt/Milky/48/100.png new file mode 100644 index 0000000..a49d1da Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/100.png differ diff --git a/highgui/src/files_Qt/Milky/48/101.png b/highgui/src/files_Qt/Milky/48/101.png new file mode 100644 index 0000000..3a95d68 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/101.png differ diff --git a/highgui/src/files_Qt/Milky/48/102.png b/highgui/src/files_Qt/Milky/48/102.png new file mode 100644 index 0000000..cb6bb1d Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/102.png differ diff --git a/highgui/src/files_Qt/Milky/48/103.png b/highgui/src/files_Qt/Milky/48/103.png new file mode 100644 index 0000000..bf0c661 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/103.png differ diff --git a/highgui/src/files_Qt/Milky/48/104.png b/highgui/src/files_Qt/Milky/48/104.png new file mode 100644 index 0000000..530ffa1 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/104.png differ diff --git a/highgui/src/files_Qt/Milky/48/105.png b/highgui/src/files_Qt/Milky/48/105.png new file mode 100644 index 0000000..c0848cb Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/105.png differ diff --git a/highgui/src/files_Qt/Milky/48/106.png b/highgui/src/files_Qt/Milky/48/106.png new file mode 100644 index 0000000..e8d1f04 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/106.png differ diff --git a/highgui/src/files_Qt/Milky/48/107.png b/highgui/src/files_Qt/Milky/48/107.png new file mode 100644 index 0000000..7a5a022 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/107.png differ diff --git a/highgui/src/files_Qt/Milky/48/108.png b/highgui/src/files_Qt/Milky/48/108.png new file mode 100644 index 0000000..d7f27ab Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/108.png differ diff --git a/highgui/src/files_Qt/Milky/48/109.png b/highgui/src/files_Qt/Milky/48/109.png new file mode 100644 index 0000000..ffb93da Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/109.png differ diff --git a/highgui/src/files_Qt/Milky/48/11.png b/highgui/src/files_Qt/Milky/48/11.png new file mode 100644 index 0000000..ac23649 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/11.png differ diff --git a/highgui/src/files_Qt/Milky/48/110.png b/highgui/src/files_Qt/Milky/48/110.png new file mode 100644 index 0000000..82c6dd1 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/110.png differ diff --git a/highgui/src/files_Qt/Milky/48/111.png b/highgui/src/files_Qt/Milky/48/111.png new file mode 100644 index 0000000..5592dd8 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/111.png differ diff --git a/highgui/src/files_Qt/Milky/48/112.png b/highgui/src/files_Qt/Milky/48/112.png new file mode 100644 index 0000000..cc91c94 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/112.png differ diff --git a/highgui/src/files_Qt/Milky/48/113.png b/highgui/src/files_Qt/Milky/48/113.png new file mode 100644 index 0000000..143ea90 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/113.png differ diff --git a/highgui/src/files_Qt/Milky/48/114.png b/highgui/src/files_Qt/Milky/48/114.png new file mode 100644 index 0000000..a44368a Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/114.png differ diff --git a/highgui/src/files_Qt/Milky/48/115.png b/highgui/src/files_Qt/Milky/48/115.png new file mode 100644 index 0000000..f8226fb Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/115.png differ diff --git a/highgui/src/files_Qt/Milky/48/116.png b/highgui/src/files_Qt/Milky/48/116.png new file mode 100644 index 0000000..55e7b74 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/116.png differ diff --git a/highgui/src/files_Qt/Milky/48/117.png b/highgui/src/files_Qt/Milky/48/117.png new file mode 100644 index 0000000..54db487 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/117.png differ diff --git a/highgui/src/files_Qt/Milky/48/118.png b/highgui/src/files_Qt/Milky/48/118.png new file mode 100644 index 0000000..6693e84 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/118.png differ diff --git a/highgui/src/files_Qt/Milky/48/119.png b/highgui/src/files_Qt/Milky/48/119.png new file mode 100644 index 0000000..683f366 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/119.png differ diff --git a/highgui/src/files_Qt/Milky/48/12.png b/highgui/src/files_Qt/Milky/48/12.png new file mode 100644 index 0000000..e297afe Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/12.png differ diff --git a/highgui/src/files_Qt/Milky/48/120.png b/highgui/src/files_Qt/Milky/48/120.png new file mode 100644 index 0000000..fe0221b Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/120.png differ diff --git a/highgui/src/files_Qt/Milky/48/121.png b/highgui/src/files_Qt/Milky/48/121.png new file mode 100644 index 0000000..72fbc03 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/121.png differ diff --git a/highgui/src/files_Qt/Milky/48/122.png b/highgui/src/files_Qt/Milky/48/122.png new file mode 100644 index 0000000..6182b8f Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/122.png differ diff --git a/highgui/src/files_Qt/Milky/48/123.png b/highgui/src/files_Qt/Milky/48/123.png new file mode 100644 index 0000000..aaa02f5 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/123.png differ diff --git a/highgui/src/files_Qt/Milky/48/124.png b/highgui/src/files_Qt/Milky/48/124.png new file mode 100644 index 0000000..273400a Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/124.png differ diff --git a/highgui/src/files_Qt/Milky/48/125.png b/highgui/src/files_Qt/Milky/48/125.png new file mode 100644 index 0000000..4e0573c Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/125.png differ diff --git a/highgui/src/files_Qt/Milky/48/126.png b/highgui/src/files_Qt/Milky/48/126.png new file mode 100644 index 0000000..fc4f11d Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/126.png differ diff --git a/highgui/src/files_Qt/Milky/48/127.png b/highgui/src/files_Qt/Milky/48/127.png new file mode 100644 index 0000000..a2a7af2 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/127.png differ diff --git a/highgui/src/files_Qt/Milky/48/128.png b/highgui/src/files_Qt/Milky/48/128.png new file mode 100644 index 0000000..f811ee4 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/128.png differ diff --git a/highgui/src/files_Qt/Milky/48/129.png b/highgui/src/files_Qt/Milky/48/129.png new file mode 100644 index 0000000..77e7ebd Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/129.png differ diff --git a/highgui/src/files_Qt/Milky/48/13.png b/highgui/src/files_Qt/Milky/48/13.png new file mode 100644 index 0000000..691e73b Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/13.png differ diff --git a/highgui/src/files_Qt/Milky/48/130.png b/highgui/src/files_Qt/Milky/48/130.png new file mode 100644 index 0000000..c1fdd36 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/130.png differ diff --git a/highgui/src/files_Qt/Milky/48/131.png b/highgui/src/files_Qt/Milky/48/131.png new file mode 100644 index 0000000..858fde1 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/131.png differ diff --git a/highgui/src/files_Qt/Milky/48/14.png b/highgui/src/files_Qt/Milky/48/14.png new file mode 100644 index 0000000..ede537c Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/14.png differ diff --git a/highgui/src/files_Qt/Milky/48/15.png b/highgui/src/files_Qt/Milky/48/15.png new file mode 100644 index 0000000..b54b7d6 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/15.png differ diff --git a/highgui/src/files_Qt/Milky/48/16.png b/highgui/src/files_Qt/Milky/48/16.png new file mode 100644 index 0000000..3e675d4 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/16.png differ diff --git a/highgui/src/files_Qt/Milky/48/17.png b/highgui/src/files_Qt/Milky/48/17.png new file mode 100644 index 0000000..32ddc3e Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/17.png differ diff --git a/highgui/src/files_Qt/Milky/48/18.png b/highgui/src/files_Qt/Milky/48/18.png new file mode 100644 index 0000000..be8e3e7 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/18.png differ diff --git a/highgui/src/files_Qt/Milky/48/19.png b/highgui/src/files_Qt/Milky/48/19.png new file mode 100644 index 0000000..e5145d0 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/19.png differ diff --git a/highgui/src/files_Qt/Milky/48/2.png b/highgui/src/files_Qt/Milky/48/2.png new file mode 100644 index 0000000..d2ad4a4 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/2.png differ diff --git a/highgui/src/files_Qt/Milky/48/20.png b/highgui/src/files_Qt/Milky/48/20.png new file mode 100644 index 0000000..c53289a Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/20.png differ diff --git a/highgui/src/files_Qt/Milky/48/21.png b/highgui/src/files_Qt/Milky/48/21.png new file mode 100644 index 0000000..2df56ef Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/21.png differ diff --git a/highgui/src/files_Qt/Milky/48/22.png b/highgui/src/files_Qt/Milky/48/22.png new file mode 100644 index 0000000..36d41cc Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/22.png differ diff --git a/highgui/src/files_Qt/Milky/48/23.png b/highgui/src/files_Qt/Milky/48/23.png new file mode 100644 index 0000000..eb51b83 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/23.png differ diff --git a/highgui/src/files_Qt/Milky/48/24.png b/highgui/src/files_Qt/Milky/48/24.png new file mode 100644 index 0000000..b0033cf Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/24.png differ diff --git a/highgui/src/files_Qt/Milky/48/25.png b/highgui/src/files_Qt/Milky/48/25.png new file mode 100644 index 0000000..d41d792 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/25.png differ diff --git a/highgui/src/files_Qt/Milky/48/26.png b/highgui/src/files_Qt/Milky/48/26.png new file mode 100644 index 0000000..055c496 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/26.png differ diff --git a/highgui/src/files_Qt/Milky/48/27.png b/highgui/src/files_Qt/Milky/48/27.png new file mode 100644 index 0000000..34f5f0c Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/27.png differ diff --git a/highgui/src/files_Qt/Milky/48/28.png b/highgui/src/files_Qt/Milky/48/28.png new file mode 100644 index 0000000..9c94db1 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/28.png differ diff --git a/highgui/src/files_Qt/Milky/48/29.png b/highgui/src/files_Qt/Milky/48/29.png new file mode 100644 index 0000000..9ca7137 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/29.png differ diff --git a/highgui/src/files_Qt/Milky/48/3.png b/highgui/src/files_Qt/Milky/48/3.png new file mode 100644 index 0000000..5144bbf Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/3.png differ diff --git a/highgui/src/files_Qt/Milky/48/30.png b/highgui/src/files_Qt/Milky/48/30.png new file mode 100644 index 0000000..db76e78 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/30.png differ diff --git a/highgui/src/files_Qt/Milky/48/31.png b/highgui/src/files_Qt/Milky/48/31.png new file mode 100644 index 0000000..e79c0df Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/31.png differ diff --git a/highgui/src/files_Qt/Milky/48/32.png b/highgui/src/files_Qt/Milky/48/32.png new file mode 100644 index 0000000..414eecf Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/32.png differ diff --git a/highgui/src/files_Qt/Milky/48/33.png b/highgui/src/files_Qt/Milky/48/33.png new file mode 100644 index 0000000..2ec44d3 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/33.png differ diff --git a/highgui/src/files_Qt/Milky/48/34.png b/highgui/src/files_Qt/Milky/48/34.png new file mode 100644 index 0000000..63f3b04 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/34.png differ diff --git a/highgui/src/files_Qt/Milky/48/35.png b/highgui/src/files_Qt/Milky/48/35.png new file mode 100644 index 0000000..41a0415 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/35.png differ diff --git a/highgui/src/files_Qt/Milky/48/36.png b/highgui/src/files_Qt/Milky/48/36.png new file mode 100644 index 0000000..c6e17fd Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/36.png differ diff --git a/highgui/src/files_Qt/Milky/48/37.png b/highgui/src/files_Qt/Milky/48/37.png new file mode 100644 index 0000000..70be99d Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/37.png differ diff --git a/highgui/src/files_Qt/Milky/48/38.png b/highgui/src/files_Qt/Milky/48/38.png new file mode 100644 index 0000000..1faaa2e Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/38.png differ diff --git a/highgui/src/files_Qt/Milky/48/39.png b/highgui/src/files_Qt/Milky/48/39.png new file mode 100644 index 0000000..b5b7b98 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/39.png differ diff --git a/highgui/src/files_Qt/Milky/48/4.png b/highgui/src/files_Qt/Milky/48/4.png new file mode 100644 index 0000000..fe93c35 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/4.png differ diff --git a/highgui/src/files_Qt/Milky/48/40.png b/highgui/src/files_Qt/Milky/48/40.png new file mode 100644 index 0000000..1035906 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/40.png differ diff --git a/highgui/src/files_Qt/Milky/48/41.png b/highgui/src/files_Qt/Milky/48/41.png new file mode 100644 index 0000000..622e1d8 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/41.png differ diff --git a/highgui/src/files_Qt/Milky/48/42.png b/highgui/src/files_Qt/Milky/48/42.png new file mode 100644 index 0000000..2c20bf6 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/42.png differ diff --git a/highgui/src/files_Qt/Milky/48/43.png b/highgui/src/files_Qt/Milky/48/43.png new file mode 100644 index 0000000..b849f93 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/43.png differ diff --git a/highgui/src/files_Qt/Milky/48/44.png b/highgui/src/files_Qt/Milky/48/44.png new file mode 100644 index 0000000..3902ba1 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/44.png differ diff --git a/highgui/src/files_Qt/Milky/48/45.png b/highgui/src/files_Qt/Milky/48/45.png new file mode 100644 index 0000000..cd4d6de Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/45.png differ diff --git a/highgui/src/files_Qt/Milky/48/46.png b/highgui/src/files_Qt/Milky/48/46.png new file mode 100644 index 0000000..ead4d3e Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/46.png differ diff --git a/highgui/src/files_Qt/Milky/48/47.png b/highgui/src/files_Qt/Milky/48/47.png new file mode 100644 index 0000000..e5a07ce Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/47.png differ diff --git a/highgui/src/files_Qt/Milky/48/48.png b/highgui/src/files_Qt/Milky/48/48.png new file mode 100644 index 0000000..6092c0c Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/48.png differ diff --git a/highgui/src/files_Qt/Milky/48/49.png b/highgui/src/files_Qt/Milky/48/49.png new file mode 100644 index 0000000..120e40a Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/49.png differ diff --git a/highgui/src/files_Qt/Milky/48/5.png b/highgui/src/files_Qt/Milky/48/5.png new file mode 100644 index 0000000..60827ff Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/5.png differ diff --git a/highgui/src/files_Qt/Milky/48/50.png b/highgui/src/files_Qt/Milky/48/50.png new file mode 100644 index 0000000..39f6d90 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/50.png differ diff --git a/highgui/src/files_Qt/Milky/48/51.png b/highgui/src/files_Qt/Milky/48/51.png new file mode 100644 index 0000000..b5b77eb Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/51.png differ diff --git a/highgui/src/files_Qt/Milky/48/52.png b/highgui/src/files_Qt/Milky/48/52.png new file mode 100644 index 0000000..2467870 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/52.png differ diff --git a/highgui/src/files_Qt/Milky/48/53.png b/highgui/src/files_Qt/Milky/48/53.png new file mode 100644 index 0000000..a13b568 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/53.png differ diff --git a/highgui/src/files_Qt/Milky/48/54.png b/highgui/src/files_Qt/Milky/48/54.png new file mode 100644 index 0000000..55ad009 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/54.png differ diff --git a/highgui/src/files_Qt/Milky/48/55.png b/highgui/src/files_Qt/Milky/48/55.png new file mode 100644 index 0000000..2167215 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/55.png differ diff --git a/highgui/src/files_Qt/Milky/48/56.png b/highgui/src/files_Qt/Milky/48/56.png new file mode 100644 index 0000000..ef8920b Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/56.png differ diff --git a/highgui/src/files_Qt/Milky/48/57.png b/highgui/src/files_Qt/Milky/48/57.png new file mode 100644 index 0000000..10dd05f Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/57.png differ diff --git a/highgui/src/files_Qt/Milky/48/58.png b/highgui/src/files_Qt/Milky/48/58.png new file mode 100644 index 0000000..9bdf543 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/58.png differ diff --git a/highgui/src/files_Qt/Milky/48/59.png b/highgui/src/files_Qt/Milky/48/59.png new file mode 100644 index 0000000..287cd07 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/59.png differ diff --git a/highgui/src/files_Qt/Milky/48/6.png b/highgui/src/files_Qt/Milky/48/6.png new file mode 100644 index 0000000..ed04e55 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/6.png differ diff --git a/highgui/src/files_Qt/Milky/48/60.png b/highgui/src/files_Qt/Milky/48/60.png new file mode 100644 index 0000000..53250de Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/60.png differ diff --git a/highgui/src/files_Qt/Milky/48/61.png b/highgui/src/files_Qt/Milky/48/61.png new file mode 100644 index 0000000..5c4a464 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/61.png differ diff --git a/highgui/src/files_Qt/Milky/48/62.png b/highgui/src/files_Qt/Milky/48/62.png new file mode 100644 index 0000000..7434c49 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/62.png differ diff --git a/highgui/src/files_Qt/Milky/48/63.png b/highgui/src/files_Qt/Milky/48/63.png new file mode 100644 index 0000000..fa0383b Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/63.png differ diff --git a/highgui/src/files_Qt/Milky/48/64.png b/highgui/src/files_Qt/Milky/48/64.png new file mode 100644 index 0000000..df5cee0 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/64.png differ diff --git a/highgui/src/files_Qt/Milky/48/65.png b/highgui/src/files_Qt/Milky/48/65.png new file mode 100644 index 0000000..863bec1 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/65.png differ diff --git a/highgui/src/files_Qt/Milky/48/66.png b/highgui/src/files_Qt/Milky/48/66.png new file mode 100644 index 0000000..58fba6b Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/66.png differ diff --git a/highgui/src/files_Qt/Milky/48/67.png b/highgui/src/files_Qt/Milky/48/67.png new file mode 100644 index 0000000..de3fefa Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/67.png differ diff --git a/highgui/src/files_Qt/Milky/48/68.png b/highgui/src/files_Qt/Milky/48/68.png new file mode 100644 index 0000000..c9b8a72 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/68.png differ diff --git a/highgui/src/files_Qt/Milky/48/69.png b/highgui/src/files_Qt/Milky/48/69.png new file mode 100644 index 0000000..e0ce5b8 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/69.png differ diff --git a/highgui/src/files_Qt/Milky/48/7.png b/highgui/src/files_Qt/Milky/48/7.png new file mode 100644 index 0000000..6eca1fa Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/7.png differ diff --git a/highgui/src/files_Qt/Milky/48/70.png b/highgui/src/files_Qt/Milky/48/70.png new file mode 100644 index 0000000..3acf30c Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/70.png differ diff --git a/highgui/src/files_Qt/Milky/48/71.png b/highgui/src/files_Qt/Milky/48/71.png new file mode 100644 index 0000000..bf3c32a Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/71.png differ diff --git a/highgui/src/files_Qt/Milky/48/72.png b/highgui/src/files_Qt/Milky/48/72.png new file mode 100644 index 0000000..b821a98 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/72.png differ diff --git a/highgui/src/files_Qt/Milky/48/73.png b/highgui/src/files_Qt/Milky/48/73.png new file mode 100644 index 0000000..e5ca839 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/73.png differ diff --git a/highgui/src/files_Qt/Milky/48/74.png b/highgui/src/files_Qt/Milky/48/74.png new file mode 100644 index 0000000..c275e1d Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/74.png differ diff --git a/highgui/src/files_Qt/Milky/48/75.png b/highgui/src/files_Qt/Milky/48/75.png new file mode 100644 index 0000000..392792a Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/75.png differ diff --git a/highgui/src/files_Qt/Milky/48/76.png b/highgui/src/files_Qt/Milky/48/76.png new file mode 100644 index 0000000..cc2d75d Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/76.png differ diff --git a/highgui/src/files_Qt/Milky/48/77.png b/highgui/src/files_Qt/Milky/48/77.png new file mode 100644 index 0000000..80a0cac Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/77.png differ diff --git a/highgui/src/files_Qt/Milky/48/78.png b/highgui/src/files_Qt/Milky/48/78.png new file mode 100644 index 0000000..548115c Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/78.png differ diff --git a/highgui/src/files_Qt/Milky/48/79.png b/highgui/src/files_Qt/Milky/48/79.png new file mode 100644 index 0000000..9e311fc Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/79.png differ diff --git a/highgui/src/files_Qt/Milky/48/8.png b/highgui/src/files_Qt/Milky/48/8.png new file mode 100644 index 0000000..ab3280f Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/8.png differ diff --git a/highgui/src/files_Qt/Milky/48/80.png b/highgui/src/files_Qt/Milky/48/80.png new file mode 100644 index 0000000..44270bc Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/80.png differ diff --git a/highgui/src/files_Qt/Milky/48/81.png b/highgui/src/files_Qt/Milky/48/81.png new file mode 100644 index 0000000..d901825 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/81.png differ diff --git a/highgui/src/files_Qt/Milky/48/82.png b/highgui/src/files_Qt/Milky/48/82.png new file mode 100644 index 0000000..feb4ea2 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/82.png differ diff --git a/highgui/src/files_Qt/Milky/48/83.png b/highgui/src/files_Qt/Milky/48/83.png new file mode 100644 index 0000000..01abaad Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/83.png differ diff --git a/highgui/src/files_Qt/Milky/48/84.png b/highgui/src/files_Qt/Milky/48/84.png new file mode 100644 index 0000000..230c12f Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/84.png differ diff --git a/highgui/src/files_Qt/Milky/48/85.png b/highgui/src/files_Qt/Milky/48/85.png new file mode 100644 index 0000000..27a0be0 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/85.png differ diff --git a/highgui/src/files_Qt/Milky/48/86.png b/highgui/src/files_Qt/Milky/48/86.png new file mode 100644 index 0000000..915e31c Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/86.png differ diff --git a/highgui/src/files_Qt/Milky/48/87.png b/highgui/src/files_Qt/Milky/48/87.png new file mode 100644 index 0000000..b1bc27b Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/87.png differ diff --git a/highgui/src/files_Qt/Milky/48/88.png b/highgui/src/files_Qt/Milky/48/88.png new file mode 100644 index 0000000..cbdca6a Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/88.png differ diff --git a/highgui/src/files_Qt/Milky/48/89.png b/highgui/src/files_Qt/Milky/48/89.png new file mode 100644 index 0000000..afcbf38 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/89.png differ diff --git a/highgui/src/files_Qt/Milky/48/9.png b/highgui/src/files_Qt/Milky/48/9.png new file mode 100644 index 0000000..e6a9be1 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/9.png differ diff --git a/highgui/src/files_Qt/Milky/48/90.png b/highgui/src/files_Qt/Milky/48/90.png new file mode 100644 index 0000000..ae4acb3 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/90.png differ diff --git a/highgui/src/files_Qt/Milky/48/91.png b/highgui/src/files_Qt/Milky/48/91.png new file mode 100644 index 0000000..d83fe86 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/91.png differ diff --git a/highgui/src/files_Qt/Milky/48/92.png b/highgui/src/files_Qt/Milky/48/92.png new file mode 100644 index 0000000..48e5a94 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/92.png differ diff --git a/highgui/src/files_Qt/Milky/48/93.png b/highgui/src/files_Qt/Milky/48/93.png new file mode 100644 index 0000000..94eb7ac Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/93.png differ diff --git a/highgui/src/files_Qt/Milky/48/94.png b/highgui/src/files_Qt/Milky/48/94.png new file mode 100644 index 0000000..1e6999c Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/94.png differ diff --git a/highgui/src/files_Qt/Milky/48/95.png b/highgui/src/files_Qt/Milky/48/95.png new file mode 100644 index 0000000..c8c8f16 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/95.png differ diff --git a/highgui/src/files_Qt/Milky/48/96.png b/highgui/src/files_Qt/Milky/48/96.png new file mode 100644 index 0000000..daad4ea Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/96.png differ diff --git a/highgui/src/files_Qt/Milky/48/97.png b/highgui/src/files_Qt/Milky/48/97.png new file mode 100644 index 0000000..b76ec54 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/97.png differ diff --git a/highgui/src/files_Qt/Milky/48/98.png b/highgui/src/files_Qt/Milky/48/98.png new file mode 100644 index 0000000..5694611 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/98.png differ diff --git a/highgui/src/files_Qt/Milky/48/99.png b/highgui/src/files_Qt/Milky/48/99.png new file mode 100644 index 0000000..2cbc952 Binary files /dev/null and b/highgui/src/files_Qt/Milky/48/99.png differ diff --git a/highgui/src/files_Qt/Milky/64/1.png b/highgui/src/files_Qt/Milky/64/1.png new file mode 100644 index 0000000..9222f06 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/1.png differ diff --git a/highgui/src/files_Qt/Milky/64/10.png b/highgui/src/files_Qt/Milky/64/10.png new file mode 100644 index 0000000..e450e4a Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/10.png differ diff --git a/highgui/src/files_Qt/Milky/64/100.png b/highgui/src/files_Qt/Milky/64/100.png new file mode 100644 index 0000000..2920ba3 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/100.png differ diff --git a/highgui/src/files_Qt/Milky/64/101.png b/highgui/src/files_Qt/Milky/64/101.png new file mode 100644 index 0000000..03fe6ff Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/101.png differ diff --git a/highgui/src/files_Qt/Milky/64/102.png b/highgui/src/files_Qt/Milky/64/102.png new file mode 100644 index 0000000..22d7c0e Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/102.png differ diff --git a/highgui/src/files_Qt/Milky/64/103.png b/highgui/src/files_Qt/Milky/64/103.png new file mode 100644 index 0000000..cb66ba2 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/103.png differ diff --git a/highgui/src/files_Qt/Milky/64/104.png b/highgui/src/files_Qt/Milky/64/104.png new file mode 100644 index 0000000..a394b07 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/104.png differ diff --git a/highgui/src/files_Qt/Milky/64/105.png b/highgui/src/files_Qt/Milky/64/105.png new file mode 100644 index 0000000..ddbcc04 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/105.png differ diff --git a/highgui/src/files_Qt/Milky/64/106.png b/highgui/src/files_Qt/Milky/64/106.png new file mode 100644 index 0000000..4ac2b56 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/106.png differ diff --git a/highgui/src/files_Qt/Milky/64/107.png b/highgui/src/files_Qt/Milky/64/107.png new file mode 100644 index 0000000..dd8443c Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/107.png differ diff --git a/highgui/src/files_Qt/Milky/64/108.png b/highgui/src/files_Qt/Milky/64/108.png new file mode 100644 index 0000000..a87579a Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/108.png differ diff --git a/highgui/src/files_Qt/Milky/64/109.png b/highgui/src/files_Qt/Milky/64/109.png new file mode 100644 index 0000000..c42d2d5 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/109.png differ diff --git a/highgui/src/files_Qt/Milky/64/11.png b/highgui/src/files_Qt/Milky/64/11.png new file mode 100644 index 0000000..09e4252 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/11.png differ diff --git a/highgui/src/files_Qt/Milky/64/110.png b/highgui/src/files_Qt/Milky/64/110.png new file mode 100644 index 0000000..d75974a Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/110.png differ diff --git a/highgui/src/files_Qt/Milky/64/111.png b/highgui/src/files_Qt/Milky/64/111.png new file mode 100644 index 0000000..c61e685 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/111.png differ diff --git a/highgui/src/files_Qt/Milky/64/112.png b/highgui/src/files_Qt/Milky/64/112.png new file mode 100644 index 0000000..9dda7f9 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/112.png differ diff --git a/highgui/src/files_Qt/Milky/64/113.png b/highgui/src/files_Qt/Milky/64/113.png new file mode 100644 index 0000000..2aa9474 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/113.png differ diff --git a/highgui/src/files_Qt/Milky/64/114.png b/highgui/src/files_Qt/Milky/64/114.png new file mode 100644 index 0000000..e06723f Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/114.png differ diff --git a/highgui/src/files_Qt/Milky/64/115.png b/highgui/src/files_Qt/Milky/64/115.png new file mode 100644 index 0000000..fcb11c7 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/115.png differ diff --git a/highgui/src/files_Qt/Milky/64/116.png b/highgui/src/files_Qt/Milky/64/116.png new file mode 100644 index 0000000..a3227c7 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/116.png differ diff --git a/highgui/src/files_Qt/Milky/64/117.png b/highgui/src/files_Qt/Milky/64/117.png new file mode 100644 index 0000000..91991ab Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/117.png differ diff --git a/highgui/src/files_Qt/Milky/64/118.png b/highgui/src/files_Qt/Milky/64/118.png new file mode 100644 index 0000000..50c4cfc Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/118.png differ diff --git a/highgui/src/files_Qt/Milky/64/119.png b/highgui/src/files_Qt/Milky/64/119.png new file mode 100644 index 0000000..d8974f3 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/119.png differ diff --git a/highgui/src/files_Qt/Milky/64/12.png b/highgui/src/files_Qt/Milky/64/12.png new file mode 100644 index 0000000..42ddcf2 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/12.png differ diff --git a/highgui/src/files_Qt/Milky/64/120.png b/highgui/src/files_Qt/Milky/64/120.png new file mode 100644 index 0000000..feba57f Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/120.png differ diff --git a/highgui/src/files_Qt/Milky/64/121.png b/highgui/src/files_Qt/Milky/64/121.png new file mode 100644 index 0000000..01679ab Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/121.png differ diff --git a/highgui/src/files_Qt/Milky/64/122.png b/highgui/src/files_Qt/Milky/64/122.png new file mode 100644 index 0000000..4ee45a6 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/122.png differ diff --git a/highgui/src/files_Qt/Milky/64/123.png b/highgui/src/files_Qt/Milky/64/123.png new file mode 100644 index 0000000..eaeb829 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/123.png differ diff --git a/highgui/src/files_Qt/Milky/64/124.png b/highgui/src/files_Qt/Milky/64/124.png new file mode 100644 index 0000000..3babae1 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/124.png differ diff --git a/highgui/src/files_Qt/Milky/64/125.png b/highgui/src/files_Qt/Milky/64/125.png new file mode 100644 index 0000000..35d91e0 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/125.png differ diff --git a/highgui/src/files_Qt/Milky/64/126.png b/highgui/src/files_Qt/Milky/64/126.png new file mode 100644 index 0000000..4d34cfe Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/126.png differ diff --git a/highgui/src/files_Qt/Milky/64/127.png b/highgui/src/files_Qt/Milky/64/127.png new file mode 100644 index 0000000..bf1f773 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/127.png differ diff --git a/highgui/src/files_Qt/Milky/64/128.png b/highgui/src/files_Qt/Milky/64/128.png new file mode 100644 index 0000000..b9a903c Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/128.png differ diff --git a/highgui/src/files_Qt/Milky/64/129.png b/highgui/src/files_Qt/Milky/64/129.png new file mode 100644 index 0000000..000826f Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/129.png differ diff --git a/highgui/src/files_Qt/Milky/64/13.png b/highgui/src/files_Qt/Milky/64/13.png new file mode 100644 index 0000000..a5d1aff Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/13.png differ diff --git a/highgui/src/files_Qt/Milky/64/130.png b/highgui/src/files_Qt/Milky/64/130.png new file mode 100644 index 0000000..fbadb80 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/130.png differ diff --git a/highgui/src/files_Qt/Milky/64/131.png b/highgui/src/files_Qt/Milky/64/131.png new file mode 100644 index 0000000..636052f Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/131.png differ diff --git a/highgui/src/files_Qt/Milky/64/14.png b/highgui/src/files_Qt/Milky/64/14.png new file mode 100644 index 0000000..091cf58 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/14.png differ diff --git a/highgui/src/files_Qt/Milky/64/15.png b/highgui/src/files_Qt/Milky/64/15.png new file mode 100644 index 0000000..f55ea7d Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/15.png differ diff --git a/highgui/src/files_Qt/Milky/64/16.png b/highgui/src/files_Qt/Milky/64/16.png new file mode 100644 index 0000000..0088233 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/16.png differ diff --git a/highgui/src/files_Qt/Milky/64/17.png b/highgui/src/files_Qt/Milky/64/17.png new file mode 100644 index 0000000..7ab1b95 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/17.png differ diff --git a/highgui/src/files_Qt/Milky/64/18.png b/highgui/src/files_Qt/Milky/64/18.png new file mode 100644 index 0000000..c077263 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/18.png differ diff --git a/highgui/src/files_Qt/Milky/64/19.png b/highgui/src/files_Qt/Milky/64/19.png new file mode 100644 index 0000000..d167b9a Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/19.png differ diff --git a/highgui/src/files_Qt/Milky/64/2.png b/highgui/src/files_Qt/Milky/64/2.png new file mode 100644 index 0000000..f540987 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/2.png differ diff --git a/highgui/src/files_Qt/Milky/64/20.png b/highgui/src/files_Qt/Milky/64/20.png new file mode 100644 index 0000000..cb5cd37 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/20.png differ diff --git a/highgui/src/files_Qt/Milky/64/21.png b/highgui/src/files_Qt/Milky/64/21.png new file mode 100644 index 0000000..d1ae8e6 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/21.png differ diff --git a/highgui/src/files_Qt/Milky/64/22.png b/highgui/src/files_Qt/Milky/64/22.png new file mode 100644 index 0000000..ca026ec Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/22.png differ diff --git a/highgui/src/files_Qt/Milky/64/23.png b/highgui/src/files_Qt/Milky/64/23.png new file mode 100644 index 0000000..a374ea0 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/23.png differ diff --git a/highgui/src/files_Qt/Milky/64/24.png b/highgui/src/files_Qt/Milky/64/24.png new file mode 100644 index 0000000..5566ebd Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/24.png differ diff --git a/highgui/src/files_Qt/Milky/64/25.png b/highgui/src/files_Qt/Milky/64/25.png new file mode 100644 index 0000000..368f7a1 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/25.png differ diff --git a/highgui/src/files_Qt/Milky/64/26.png b/highgui/src/files_Qt/Milky/64/26.png new file mode 100644 index 0000000..10ecc3b Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/26.png differ diff --git a/highgui/src/files_Qt/Milky/64/27.png b/highgui/src/files_Qt/Milky/64/27.png new file mode 100644 index 0000000..9946afb Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/27.png differ diff --git a/highgui/src/files_Qt/Milky/64/28.png b/highgui/src/files_Qt/Milky/64/28.png new file mode 100644 index 0000000..9094ba1 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/28.png differ diff --git a/highgui/src/files_Qt/Milky/64/29.png b/highgui/src/files_Qt/Milky/64/29.png new file mode 100644 index 0000000..dc593df Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/29.png differ diff --git a/highgui/src/files_Qt/Milky/64/3.png b/highgui/src/files_Qt/Milky/64/3.png new file mode 100644 index 0000000..2b6cdca Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/3.png differ diff --git a/highgui/src/files_Qt/Milky/64/30.png b/highgui/src/files_Qt/Milky/64/30.png new file mode 100644 index 0000000..2430966 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/30.png differ diff --git a/highgui/src/files_Qt/Milky/64/31.png b/highgui/src/files_Qt/Milky/64/31.png new file mode 100644 index 0000000..1748d71 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/31.png differ diff --git a/highgui/src/files_Qt/Milky/64/32.png b/highgui/src/files_Qt/Milky/64/32.png new file mode 100644 index 0000000..d225fb3 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/32.png differ diff --git a/highgui/src/files_Qt/Milky/64/33.png b/highgui/src/files_Qt/Milky/64/33.png new file mode 100644 index 0000000..3fb4ac5 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/33.png differ diff --git a/highgui/src/files_Qt/Milky/64/34.png b/highgui/src/files_Qt/Milky/64/34.png new file mode 100644 index 0000000..0dd5f23 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/34.png differ diff --git a/highgui/src/files_Qt/Milky/64/35.png b/highgui/src/files_Qt/Milky/64/35.png new file mode 100644 index 0000000..5cdb35c Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/35.png differ diff --git a/highgui/src/files_Qt/Milky/64/36.png b/highgui/src/files_Qt/Milky/64/36.png new file mode 100644 index 0000000..d2b2444 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/36.png differ diff --git a/highgui/src/files_Qt/Milky/64/37.png b/highgui/src/files_Qt/Milky/64/37.png new file mode 100644 index 0000000..ef2b8a5 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/37.png differ diff --git a/highgui/src/files_Qt/Milky/64/38.png b/highgui/src/files_Qt/Milky/64/38.png new file mode 100644 index 0000000..f1a700c Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/38.png differ diff --git a/highgui/src/files_Qt/Milky/64/39.png b/highgui/src/files_Qt/Milky/64/39.png new file mode 100644 index 0000000..121a3f8 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/39.png differ diff --git a/highgui/src/files_Qt/Milky/64/4.png b/highgui/src/files_Qt/Milky/64/4.png new file mode 100644 index 0000000..264f8bd Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/4.png differ diff --git a/highgui/src/files_Qt/Milky/64/40.png b/highgui/src/files_Qt/Milky/64/40.png new file mode 100644 index 0000000..a04765d Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/40.png differ diff --git a/highgui/src/files_Qt/Milky/64/41.png b/highgui/src/files_Qt/Milky/64/41.png new file mode 100644 index 0000000..3bed0eb Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/41.png differ diff --git a/highgui/src/files_Qt/Milky/64/42.png b/highgui/src/files_Qt/Milky/64/42.png new file mode 100644 index 0000000..c176620 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/42.png differ diff --git a/highgui/src/files_Qt/Milky/64/43.png b/highgui/src/files_Qt/Milky/64/43.png new file mode 100644 index 0000000..295d288 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/43.png differ diff --git a/highgui/src/files_Qt/Milky/64/44.png b/highgui/src/files_Qt/Milky/64/44.png new file mode 100644 index 0000000..a8fba75 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/44.png differ diff --git a/highgui/src/files_Qt/Milky/64/45.png b/highgui/src/files_Qt/Milky/64/45.png new file mode 100644 index 0000000..d65e2bd Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/45.png differ diff --git a/highgui/src/files_Qt/Milky/64/46.png b/highgui/src/files_Qt/Milky/64/46.png new file mode 100644 index 0000000..4347e52 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/46.png differ diff --git a/highgui/src/files_Qt/Milky/64/47.png b/highgui/src/files_Qt/Milky/64/47.png new file mode 100644 index 0000000..87502ce Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/47.png differ diff --git a/highgui/src/files_Qt/Milky/64/48.png b/highgui/src/files_Qt/Milky/64/48.png new file mode 100644 index 0000000..6cc7164 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/48.png differ diff --git a/highgui/src/files_Qt/Milky/64/49.png b/highgui/src/files_Qt/Milky/64/49.png new file mode 100644 index 0000000..d6686e9 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/49.png differ diff --git a/highgui/src/files_Qt/Milky/64/5.png b/highgui/src/files_Qt/Milky/64/5.png new file mode 100644 index 0000000..185219d Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/5.png differ diff --git a/highgui/src/files_Qt/Milky/64/50.png b/highgui/src/files_Qt/Milky/64/50.png new file mode 100644 index 0000000..0bc5d92 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/50.png differ diff --git a/highgui/src/files_Qt/Milky/64/51.png b/highgui/src/files_Qt/Milky/64/51.png new file mode 100644 index 0000000..ea40b93 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/51.png differ diff --git a/highgui/src/files_Qt/Milky/64/52.png b/highgui/src/files_Qt/Milky/64/52.png new file mode 100644 index 0000000..27c41bd Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/52.png differ diff --git a/highgui/src/files_Qt/Milky/64/53.png b/highgui/src/files_Qt/Milky/64/53.png new file mode 100644 index 0000000..8c88aaa Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/53.png differ diff --git a/highgui/src/files_Qt/Milky/64/54.png b/highgui/src/files_Qt/Milky/64/54.png new file mode 100644 index 0000000..0f8c5cb Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/54.png differ diff --git a/highgui/src/files_Qt/Milky/64/55.png b/highgui/src/files_Qt/Milky/64/55.png new file mode 100644 index 0000000..533f2de Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/55.png differ diff --git a/highgui/src/files_Qt/Milky/64/56.png b/highgui/src/files_Qt/Milky/64/56.png new file mode 100644 index 0000000..28abf7a Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/56.png differ diff --git a/highgui/src/files_Qt/Milky/64/57.png b/highgui/src/files_Qt/Milky/64/57.png new file mode 100644 index 0000000..fd98c7e Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/57.png differ diff --git a/highgui/src/files_Qt/Milky/64/58.png b/highgui/src/files_Qt/Milky/64/58.png new file mode 100644 index 0000000..6142acc Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/58.png differ diff --git a/highgui/src/files_Qt/Milky/64/59.png b/highgui/src/files_Qt/Milky/64/59.png new file mode 100644 index 0000000..2ae78f3 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/59.png differ diff --git a/highgui/src/files_Qt/Milky/64/6.png b/highgui/src/files_Qt/Milky/64/6.png new file mode 100644 index 0000000..fa55cbc Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/6.png differ diff --git a/highgui/src/files_Qt/Milky/64/60.png b/highgui/src/files_Qt/Milky/64/60.png new file mode 100644 index 0000000..71adc81 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/60.png differ diff --git a/highgui/src/files_Qt/Milky/64/61.png b/highgui/src/files_Qt/Milky/64/61.png new file mode 100644 index 0000000..09b12bd Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/61.png differ diff --git a/highgui/src/files_Qt/Milky/64/62.png b/highgui/src/files_Qt/Milky/64/62.png new file mode 100644 index 0000000..374d4c5 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/62.png differ diff --git a/highgui/src/files_Qt/Milky/64/63.png b/highgui/src/files_Qt/Milky/64/63.png new file mode 100644 index 0000000..ac4f07a Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/63.png differ diff --git a/highgui/src/files_Qt/Milky/64/64.png b/highgui/src/files_Qt/Milky/64/64.png new file mode 100644 index 0000000..79e38d1 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/64.png differ diff --git a/highgui/src/files_Qt/Milky/64/65.png b/highgui/src/files_Qt/Milky/64/65.png new file mode 100644 index 0000000..46ca28e Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/65.png differ diff --git a/highgui/src/files_Qt/Milky/64/66.png b/highgui/src/files_Qt/Milky/64/66.png new file mode 100644 index 0000000..b98c32d Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/66.png differ diff --git a/highgui/src/files_Qt/Milky/64/67.png b/highgui/src/files_Qt/Milky/64/67.png new file mode 100644 index 0000000..7251a67 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/67.png differ diff --git a/highgui/src/files_Qt/Milky/64/68.png b/highgui/src/files_Qt/Milky/64/68.png new file mode 100644 index 0000000..894c9aa Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/68.png differ diff --git a/highgui/src/files_Qt/Milky/64/69.png b/highgui/src/files_Qt/Milky/64/69.png new file mode 100644 index 0000000..2312bc6 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/69.png differ diff --git a/highgui/src/files_Qt/Milky/64/7.png b/highgui/src/files_Qt/Milky/64/7.png new file mode 100644 index 0000000..98083e0 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/7.png differ diff --git a/highgui/src/files_Qt/Milky/64/70.png b/highgui/src/files_Qt/Milky/64/70.png new file mode 100644 index 0000000..d07791b Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/70.png differ diff --git a/highgui/src/files_Qt/Milky/64/71.png b/highgui/src/files_Qt/Milky/64/71.png new file mode 100644 index 0000000..fa32faa Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/71.png differ diff --git a/highgui/src/files_Qt/Milky/64/72.png b/highgui/src/files_Qt/Milky/64/72.png new file mode 100644 index 0000000..c5a01bf Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/72.png differ diff --git a/highgui/src/files_Qt/Milky/64/73.png b/highgui/src/files_Qt/Milky/64/73.png new file mode 100644 index 0000000..9e98cb0 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/73.png differ diff --git a/highgui/src/files_Qt/Milky/64/74.png b/highgui/src/files_Qt/Milky/64/74.png new file mode 100644 index 0000000..2c7ecf3 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/74.png differ diff --git a/highgui/src/files_Qt/Milky/64/75.png b/highgui/src/files_Qt/Milky/64/75.png new file mode 100644 index 0000000..eecf17e Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/75.png differ diff --git a/highgui/src/files_Qt/Milky/64/76.png b/highgui/src/files_Qt/Milky/64/76.png new file mode 100644 index 0000000..ac3e66b Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/76.png differ diff --git a/highgui/src/files_Qt/Milky/64/77.png b/highgui/src/files_Qt/Milky/64/77.png new file mode 100644 index 0000000..c56fcc8 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/77.png differ diff --git a/highgui/src/files_Qt/Milky/64/78.png b/highgui/src/files_Qt/Milky/64/78.png new file mode 100644 index 0000000..65a81a9 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/78.png differ diff --git a/highgui/src/files_Qt/Milky/64/79.png b/highgui/src/files_Qt/Milky/64/79.png new file mode 100644 index 0000000..073d726 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/79.png differ diff --git a/highgui/src/files_Qt/Milky/64/8.png b/highgui/src/files_Qt/Milky/64/8.png new file mode 100644 index 0000000..2daaaef Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/8.png differ diff --git a/highgui/src/files_Qt/Milky/64/80.png b/highgui/src/files_Qt/Milky/64/80.png new file mode 100644 index 0000000..6354dc4 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/80.png differ diff --git a/highgui/src/files_Qt/Milky/64/81.png b/highgui/src/files_Qt/Milky/64/81.png new file mode 100644 index 0000000..8ddba8b Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/81.png differ diff --git a/highgui/src/files_Qt/Milky/64/82.png b/highgui/src/files_Qt/Milky/64/82.png new file mode 100644 index 0000000..1145b3b Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/82.png differ diff --git a/highgui/src/files_Qt/Milky/64/83.png b/highgui/src/files_Qt/Milky/64/83.png new file mode 100644 index 0000000..ad2d75f Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/83.png differ diff --git a/highgui/src/files_Qt/Milky/64/84.png b/highgui/src/files_Qt/Milky/64/84.png new file mode 100644 index 0000000..9e1ba34 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/84.png differ diff --git a/highgui/src/files_Qt/Milky/64/85.png b/highgui/src/files_Qt/Milky/64/85.png new file mode 100644 index 0000000..baf7045 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/85.png differ diff --git a/highgui/src/files_Qt/Milky/64/86.png b/highgui/src/files_Qt/Milky/64/86.png new file mode 100644 index 0000000..bbbe97a Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/86.png differ diff --git a/highgui/src/files_Qt/Milky/64/87.png b/highgui/src/files_Qt/Milky/64/87.png new file mode 100644 index 0000000..39f26f1 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/87.png differ diff --git a/highgui/src/files_Qt/Milky/64/88.png b/highgui/src/files_Qt/Milky/64/88.png new file mode 100644 index 0000000..1cae0fc Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/88.png differ diff --git a/highgui/src/files_Qt/Milky/64/89.png b/highgui/src/files_Qt/Milky/64/89.png new file mode 100644 index 0000000..dfcf14d Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/89.png differ diff --git a/highgui/src/files_Qt/Milky/64/9.png b/highgui/src/files_Qt/Milky/64/9.png new file mode 100644 index 0000000..5eab48e Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/9.png differ diff --git a/highgui/src/files_Qt/Milky/64/90.png b/highgui/src/files_Qt/Milky/64/90.png new file mode 100644 index 0000000..3721677 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/90.png differ diff --git a/highgui/src/files_Qt/Milky/64/91.png b/highgui/src/files_Qt/Milky/64/91.png new file mode 100644 index 0000000..86e9d71 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/91.png differ diff --git a/highgui/src/files_Qt/Milky/64/92.png b/highgui/src/files_Qt/Milky/64/92.png new file mode 100644 index 0000000..b3a5a45 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/92.png differ diff --git a/highgui/src/files_Qt/Milky/64/93.png b/highgui/src/files_Qt/Milky/64/93.png new file mode 100644 index 0000000..f0b5818 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/93.png differ diff --git a/highgui/src/files_Qt/Milky/64/94.png b/highgui/src/files_Qt/Milky/64/94.png new file mode 100644 index 0000000..9be1178 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/94.png differ diff --git a/highgui/src/files_Qt/Milky/64/95.png b/highgui/src/files_Qt/Milky/64/95.png new file mode 100644 index 0000000..8f3e520 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/95.png differ diff --git a/highgui/src/files_Qt/Milky/64/96.png b/highgui/src/files_Qt/Milky/64/96.png new file mode 100644 index 0000000..6aeffcf Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/96.png differ diff --git a/highgui/src/files_Qt/Milky/64/97.png b/highgui/src/files_Qt/Milky/64/97.png new file mode 100644 index 0000000..3c66408 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/97.png differ diff --git a/highgui/src/files_Qt/Milky/64/98.png b/highgui/src/files_Qt/Milky/64/98.png new file mode 100644 index 0000000..a2e58c7 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/98.png differ diff --git a/highgui/src/files_Qt/Milky/64/99.png b/highgui/src/files_Qt/Milky/64/99.png new file mode 100644 index 0000000..5f952b8 Binary files /dev/null and b/highgui/src/files_Qt/Milky/64/99.png differ diff --git a/highgui/src/files_Qt/Milky/README.txt b/highgui/src/files_Qt/Milky/README.txt new file mode 100644 index 0000000..42f2d00 --- /dev/null +++ b/highgui/src/files_Qt/Milky/README.txt @@ -0,0 +1,19 @@ +From: +http://iconeden.com/icon/milky-a-free-vector-iconset.html + +License Agreement + +This is a legal agreement between you (the downloader) and IconEden.com. On download of any royalty-free icons from our website you agree to the following: + +All of the icons remain the property of IconEden.com. The icons can be used royalty-free by the license for any personal or commercial project including web application, web design, software application, mobile application, documentation, presentation, computer game, advertising, film, video. + +You may modify the icons in shape, color, and/or file format and use the modified icons royalty-free according to the license terms for any personal or commercial product. + +The license does not permit the following uses: + + 1. The icons may not be resold, sublicensed, rented, transferred or otherwise made available for use or detached from a product, software application or web page; + 2. The icons may not be placed on any electronic bulletin board or downloadable format; + +You may not use, or allow anyone else to use the icons to create pornographic, libelous, obscene, or defamatory material. + +All icon files are provided "as is". You agree not to hold IconEden.com liable for any damages that may occur due to use, or inability to use, icons or image data from IconEden.com. \ No newline at end of file diff --git a/highgui/src/files_Qt/stylesheet_trackbar.qss b/highgui/src/files_Qt/stylesheet_trackbar.qss new file mode 100644 index 0000000..9d5fd02 --- /dev/null +++ b/highgui/src/files_Qt/stylesheet_trackbar.qss @@ -0,0 +1,58 @@ +/* //from http://thesmithfam.org/blog/2010/03/10/fancy-qslider-stylesheet/ */ + +QSlider::groove:horizontal { +border: 1px solid #bbb; +background: white; +height: 10px; +border-radius: 4px; +} + +QSlider::sub-page:horizontal { +background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, +stop: 0 #66e, stop: 1 #bbf); +background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1, +stop: 0 #bbf, stop: 1 #55f); +border: 1px solid #777; +height: 10px; +border-radius: 4px; +} + +QSlider::add-page:horizontal { +background: #fff; +border: 1px solid #777; +height: 10px; +border-radius: 4px; +} + +QSlider::handle:horizontal { +background: qlineargradient(x1:0, y1:0, x2:1, y2:1, +stop:0 #eee, stop:1 #ccc); +border: 1px solid #777; +width: 13px; +margin-top: -2px; +margin-bottom: -2px; +border-radius: 4px; +} + +QSlider::handle:horizontal:hover { +background: qlineargradient(x1:0, y1:0, x2:1, y2:1, +stop:0 #fff, stop:1 #ddd); +border: 1px solid #444; +border-radius: 4px; +} + +QSlider::sub-page:horizontal:disabled { +background: #bbb; +border-color: #999; +} + +QSlider::add-page:horizontal:disabled { +background: #eee; +border-color: #999; +} + +QSlider::handle:horizontal:disabled { +background: #eee; +border: 1px solid #aaa; +border-radius: 4px; +} diff --git a/highgui/src/grfmt_base.cpp b/highgui/src/grfmt_base.cpp new file mode 100644 index 0000000..405cf8b --- /dev/null +++ b/highgui/src/grfmt_base.cpp @@ -0,0 +1,128 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#include "grfmt_base.hpp" +#include "bitstrm.hpp" + +namespace cv +{ + +BaseImageDecoder::BaseImageDecoder() +{ + m_width = m_height = 0; + m_type = -1; + m_buf_supported = false; +} + +bool BaseImageDecoder::setSource( const string& filename ) +{ + m_filename = filename; + m_buf.release(); + return true; +} + +bool BaseImageDecoder::setSource( const Mat& buf ) +{ + if( !m_buf_supported ) + return false; + m_filename = string(); + m_buf = buf; + return true; +} + +size_t BaseImageDecoder::signatureLength() const +{ + return m_signature.size(); +} + +bool BaseImageDecoder::checkSignature( const string& signature ) const +{ + size_t len = signatureLength(); + return signature.size() >= len && memcmp( signature.c_str(), m_signature.c_str(), len ) == 0; +} + +ImageDecoder BaseImageDecoder::newDecoder() const +{ + return ImageDecoder(); +} + +BaseImageEncoder::BaseImageEncoder() +{ + m_buf_supported = false; +} + +bool BaseImageEncoder::isFormatSupported( int depth ) const +{ + return depth == CV_8U; +} + +string BaseImageEncoder::getDescription() const +{ + return m_description; +} + +bool BaseImageEncoder::setDestination( const string& filename ) +{ + m_filename = filename; + m_buf = 0; + return true; +} + +bool BaseImageEncoder::setDestination( vector& buf ) +{ + if( !m_buf_supported ) + return false; + m_buf = &buf; + m_buf->clear(); + m_filename = string(); + return true; +} + +ImageEncoder BaseImageEncoder::newEncoder() const +{ + return ImageEncoder(); +} + +} + +/* End of file. */ diff --git a/highgui/src/grfmt_base.hpp b/highgui/src/grfmt_base.hpp new file mode 100644 index 0000000..ca19427 --- /dev/null +++ b/highgui/src/grfmt_base.hpp @@ -0,0 +1,113 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _GRFMT_BASE_H_ +#define _GRFMT_BASE_H_ + +#include "utils.hpp" +#include "bitstrm.hpp" + +namespace cv +{ + +class BaseImageDecoder; +class BaseImageEncoder; +typedef Ptr ImageEncoder; +typedef Ptr ImageDecoder; + +///////////////////////////////// base class for decoders //////////////////////// +class BaseImageDecoder +{ +public: + BaseImageDecoder(); + virtual ~BaseImageDecoder() {}; + + int width() const { return m_width; }; + int height() const { return m_height; }; + virtual int type() const { return m_type; }; + + virtual bool setSource( const string& filename ); + virtual bool setSource( const Mat& buf ); + virtual bool readHeader() = 0; + virtual bool readData( Mat& img ) = 0; + + virtual size_t signatureLength() const; + virtual bool checkSignature( const string& signature ) const; + virtual ImageDecoder newDecoder() const; + +protected: + int m_width; // width of the image ( filled by readHeader ) + int m_height; // height of the image ( filled by readHeader ) + int m_type; + string m_filename; + string m_signature; + Mat m_buf; + bool m_buf_supported; +}; + + +///////////////////////////// base class for encoders //////////////////////////// +class BaseImageEncoder +{ +public: + BaseImageEncoder(); + virtual ~BaseImageEncoder() {}; + virtual bool isFormatSupported( int depth ) const; + + virtual bool setDestination( const string& filename ); + virtual bool setDestination( vector& buf ); + virtual bool write( const Mat& img, const vector& params ) = 0; + + virtual string getDescription() const; + virtual ImageEncoder newEncoder() const; + +protected: + string m_description; + + string m_filename; + vector* m_buf; + bool m_buf_supported; +}; + +} + +#endif/*_GRFMT_BASE_H_*/ diff --git a/highgui/src/grfmt_bmp.cpp b/highgui/src/grfmt_bmp.cpp new file mode 100644 index 0000000..6d1c008 --- /dev/null +++ b/highgui/src/grfmt_bmp.cpp @@ -0,0 +1,566 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include "grfmt_bmp.hpp" + +namespace cv +{ + +static const char* fmtSignBmp = "BM"; + +/************************ BMP decoder *****************************/ + +BmpDecoder::BmpDecoder() +{ + m_signature = fmtSignBmp; + m_offset = -1; + m_buf_supported = true; +} + + +BmpDecoder::~BmpDecoder() +{ +} + + +void BmpDecoder::close() +{ + m_strm.close(); +} + +ImageDecoder BmpDecoder::newDecoder() const +{ + return new BmpDecoder; +} + +bool BmpDecoder::readHeader() +{ + bool result = false; + bool iscolor = false; + + if( !m_buf.empty() ) + { + if( !m_strm.open( m_buf ) ) + return false; + } + else if( !m_strm.open( m_filename )) + return false; + + try + { + m_strm.skip( 10 ); + m_offset = m_strm.getDWord(); + + int size = m_strm.getDWord(); + + if( size >= 36 ) + { + m_width = m_strm.getDWord(); + m_height = m_strm.getDWord(); + m_bpp = m_strm.getDWord() >> 16; + m_rle_code = (BmpCompression)m_strm.getDWord(); + m_strm.skip(12); + int clrused = m_strm.getDWord(); + m_strm.skip( size - 36 ); + + if( m_width > 0 && m_height != 0 && + (((m_bpp == 1 || m_bpp == 4 || m_bpp == 8 || + m_bpp == 24 || m_bpp == 32 ) && m_rle_code == BMP_RGB) || + (m_bpp == 16 && (m_rle_code == BMP_RGB || m_rle_code == BMP_BITFIELDS)) || + (m_bpp == 4 && m_rle_code == BMP_RLE4) || + (m_bpp == 8 && m_rle_code == BMP_RLE8))) + { + iscolor = true; + result = true; + + if( m_bpp <= 8 ) + { + memset( m_palette, 0, sizeof(m_palette)); + m_strm.getBytes( m_palette, (clrused == 0? 1<> 16; + m_rle_code = BMP_RGB; + + if( m_width > 0 && m_height != 0 && + (m_bpp == 1 || m_bpp == 4 || m_bpp == 8 || + m_bpp == 24 || m_bpp == 32 )) + { + if( m_bpp <= 8 ) + { + uchar buffer[256*3]; + int j, clrused = 1 << m_bpp; + m_strm.getBytes( buffer, clrused*3 ); + for( j = 0; j < clrused; j++ ) + { + m_palette[j].b = buffer[3*j+0]; + m_palette[j].g = buffer[3*j+1]; + m_palette[j].r = buffer[3*j+2]; + } + } + result = true; + } + } + } + catch(...) + { + } + + m_type = iscolor ? CV_8UC3 : CV_8UC1; + m_origin = m_height > 0 ? IPL_ORIGIN_BL : IPL_ORIGIN_TL; + m_height = std::abs(m_height); + + if( !result ) + { + m_offset = -1; + m_width = m_height = -1; + m_strm.close(); + } + return result; +} + + +bool BmpDecoder::readData( Mat& img ) +{ + uchar* data = img.data; + int step = (int)img.step; + bool color = img.channels() > 1; + uchar gray_palette[256]; + bool result = false; + int src_pitch = ((m_width*(m_bpp != 15 ? m_bpp : 16) + 7)/8 + 3) & -4; + int nch = color ? 3 : 1; + int y, width3 = m_width*nch; + + if( m_offset < 0 || !m_strm.isOpened()) + return false; + + if( m_origin == IPL_ORIGIN_BL ) + { + data += (m_height - 1)*step; + step = -step; + } + + AutoBuffer _src, _bgr; + _src.allocate(src_pitch + 32); + + if( !color ) + { + if( m_bpp <= 8 ) + { + CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp ); + } + _bgr.allocate(m_width*3 + 32); + } + uchar *src = _src, *bgr = _bgr; + + try + { + m_strm.setPos( m_offset ); + + switch( m_bpp ) + { + /************************* 1 BPP ************************/ + case 1: + for( y = 0; y < m_height; y++, data += step ) + { + m_strm.getBytes( src, src_pitch ); + FillColorRow1( color ? data : bgr, src, m_width, m_palette ); + if( !color ) + icvCvt_BGR2Gray_8u_C3C1R( bgr, 0, data, 0, cvSize(m_width,1) ); + } + result = true; + break; + + /************************* 4 BPP ************************/ + case 4: + if( m_rle_code == BMP_RGB ) + { + for( y = 0; y < m_height; y++, data += step ) + { + m_strm.getBytes( src, src_pitch ); + if( color ) + FillColorRow4( data, src, m_width, m_palette ); + else + FillGrayRow4( data, src, m_width, gray_palette ); + } + result = true; + } + else if( m_rle_code == BMP_RLE4 ) // rle4 compression + { + uchar* line_end = data + width3; + y = 0; + + for(;;) + { + int code = m_strm.getWord(); + int len = code & 255; + code >>= 8; + if( len != 0 ) // encoded mode + { + PaletteEntry clr[2]; + uchar gray_clr[2]; + int t = 0; + + clr[0] = m_palette[code >> 4]; + clr[1] = m_palette[code & 15]; + gray_clr[0] = gray_palette[code >> 4]; + gray_clr[1] = gray_palette[code & 15]; + + uchar* end = data + len*nch; + if( end > line_end ) goto decode_rle4_bad; + do + { + if( color ) + WRITE_PIX( data, clr[t] ); + else + *data = gray_clr[t]; + t ^= 1; + } + while( (data += nch) < end ); + } + else if( code > 2 ) // absolute mode + { + if( data + code*nch > line_end ) goto decode_rle4_bad; + m_strm.getBytes( src, (((code + 1)>>1) + 1) & -2 ); + if( color ) + data = FillColorRow4( data, src, code, m_palette ); + else + data = FillGrayRow4( data, src, code, gray_palette ); + } + else + { + int x_shift3 = (int)(line_end - data); + int y_shift = m_height - y; + + if( code == 2 ) + { + x_shift3 = m_strm.getByte()*nch; + y_shift = m_strm.getByte(); + } + + len = x_shift3 + ((y_shift * width3) & ((code == 0) - 1)); + + if( color ) + data = FillUniColor( data, line_end, step, width3, + y, m_height, x_shift3, + m_palette[0] ); + else + data = FillUniGray( data, line_end, step, width3, + y, m_height, x_shift3, + gray_palette[0] ); + + if( y >= m_height ) + break; + } + } + + result = true; +decode_rle4_bad: ; + } + break; + + /************************* 8 BPP ************************/ + case 8: + if( m_rle_code == BMP_RGB ) + { + for( y = 0; y < m_height; y++, data += step ) + { + m_strm.getBytes( src, src_pitch ); + if( color ) + FillColorRow8( data, src, m_width, m_palette ); + else + FillGrayRow8( data, src, m_width, gray_palette ); + } + result = true; + } + else if( m_rle_code == BMP_RLE8 ) // rle8 compression + { + uchar* line_end = data + width3; + int line_end_flag = 0; + y = 0; + + for(;;) + { + int code = m_strm.getWord(); + int len = code & 255; + code >>= 8; + if( len != 0 ) // encoded mode + { + int prev_y = y; + len *= nch; + + if( data + len > line_end ) + goto decode_rle8_bad; + + if( color ) + data = FillUniColor( data, line_end, step, width3, + y, m_height, len, + m_palette[code] ); + else + data = FillUniGray( data, line_end, step, width3, + y, m_height, len, + gray_palette[code] ); + + line_end_flag = y - prev_y; + } + else if( code > 2 ) // absolute mode + { + int prev_y = y; + int code3 = code*nch; + + if( data + code3 > line_end ) + goto decode_rle8_bad; + m_strm.getBytes( src, (code + 1) & -2 ); + if( color ) + data = FillColorRow8( data, src, code, m_palette ); + else + data = FillGrayRow8( data, src, code, gray_palette ); + + line_end_flag = y - prev_y; + } + else + { + int x_shift3 = (int)(line_end - data); + int y_shift = m_height - y; + + if( code || !line_end_flag || x_shift3 < width3 ) + { + if( code == 2 ) + { + x_shift3 = m_strm.getByte()*nch; + y_shift = m_strm.getByte(); + } + + x_shift3 += (y_shift * width3) & ((code == 0) - 1); + + if( y >= m_height ) + break; + + if( color ) + data = FillUniColor( data, line_end, step, width3, + y, m_height, x_shift3, + m_palette[0] ); + else + data = FillUniGray( data, line_end, step, width3, + y, m_height, x_shift3, + gray_palette[0] ); + + if( y >= m_height ) + break; + } + + line_end_flag = 0; + if( y >= m_height ) + break; + } + } + + result = true; +decode_rle8_bad: ; + } + break; + /************************* 15 BPP ************************/ + case 15: + for( y = 0; y < m_height; y++, data += step ) + { + m_strm.getBytes( src, src_pitch ); + if( !color ) + icvCvt_BGR5552Gray_8u_C2C1R( src, 0, data, 0, cvSize(m_width,1) ); + else + icvCvt_BGR5552BGR_8u_C2C3R( src, 0, data, 0, cvSize(m_width,1) ); + } + result = true; + break; + /************************* 16 BPP ************************/ + case 16: + for( y = 0; y < m_height; y++, data += step ) + { + m_strm.getBytes( src, src_pitch ); + if( !color ) + icvCvt_BGR5652Gray_8u_C2C1R( src, 0, data, 0, cvSize(m_width,1) ); + else + icvCvt_BGR5652BGR_8u_C2C3R( src, 0, data, 0, cvSize(m_width,1) ); + } + result = true; + break; + /************************* 24 BPP ************************/ + case 24: + for( y = 0; y < m_height; y++, data += step ) + { + m_strm.getBytes( src, src_pitch ); + if(!color) + icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1) ); + else + memcpy( data, src, m_width*3 ); + } + result = true; + break; + /************************* 32 BPP ************************/ + case 32: + for( y = 0; y < m_height; y++, data += step ) + { + m_strm.getBytes( src, src_pitch ); + + if( !color ) + icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, cvSize(m_width,1) ); + else + icvCvt_BGRA2BGR_8u_C4C3R( src, 0, data, 0, cvSize(m_width,1) ); + } + result = true; + break; + default: + assert(0); + } + } + catch(...) + { + } + + return result; +} + + +////////////////////////////////////////////////////////////////////////////////////////// + +BmpEncoder::BmpEncoder() +{ + m_description = "Windows bitmap (*.bmp;*.dib)"; + m_buf_supported = true; +} + + +BmpEncoder::~BmpEncoder() +{ +} + +ImageEncoder BmpEncoder::newEncoder() const +{ + return new BmpEncoder; +} + +bool BmpEncoder::write( const Mat& img, const vector& ) +{ + int width = img.cols, height = img.rows, channels = img.channels(); + int fileStep = (width*channels + 3) & -4; + uchar zeropad[] = "\0\0\0\0"; + WLByteStream strm; + + if( m_buf ) + { + if( !strm.open( *m_buf ) ) + return false; + } + else if( !strm.open( m_filename )) + return false; + + int bitmapHeaderSize = 40; + int paletteSize = channels > 1 ? 0 : 1024; + int headerSize = 14 /* fileheader */ + bitmapHeaderSize + paletteSize; + int fileSize = fileStep*height + headerSize; + PaletteEntry palette[256]; + + if( m_buf ) + m_buf->reserve( alignSize(fileSize + 16, 256) ); + + // write signature 'BM' + strm.putBytes( fmtSignBmp, (int)strlen(fmtSignBmp) ); + + // write file header + strm.putDWord( fileSize ); // file size + strm.putDWord( 0 ); + strm.putDWord( headerSize ); + + // write bitmap header + strm.putDWord( bitmapHeaderSize ); + strm.putDWord( width ); + strm.putDWord( height ); + strm.putWord( 1 ); + strm.putWord( channels << 3 ); + strm.putDWord( BMP_RGB ); + strm.putDWord( 0 ); + strm.putDWord( 0 ); + strm.putDWord( 0 ); + strm.putDWord( 0 ); + strm.putDWord( 0 ); + + if( channels == 1 ) + { + FillGrayPalette( palette, 8 ); + strm.putBytes( palette, sizeof(palette)); + } + + width *= channels; + for( int y = height - 1; y >= 0; y-- ) + { + strm.putBytes( img.data + img.step*y, width ); + if( fileStep > width ) + strm.putBytes( zeropad, fileStep - width ); + } + + strm.close(); + return true; +} + +} + diff --git a/highgui/src/grfmt_bmp.hpp b/highgui/src/grfmt_bmp.hpp new file mode 100644 index 0000000..f3841e8 --- /dev/null +++ b/highgui/src/grfmt_bmp.hpp @@ -0,0 +1,99 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _GRFMT_BMP_H_ +#define _GRFMT_BMP_H_ + +#include "grfmt_base.hpp" + +namespace cv +{ + +enum BmpCompression +{ + BMP_RGB = 0, + BMP_RLE8 = 1, + BMP_RLE4 = 2, + BMP_BITFIELDS = 3 +}; + + +// Windows Bitmap reader +class BmpDecoder : public BaseImageDecoder +{ +public: + + BmpDecoder(); + ~BmpDecoder(); + + bool readData( Mat& img ); + bool readHeader(); + void close(); + + ImageDecoder newDecoder() const; + +protected: + + RLByteStream m_strm; + PaletteEntry m_palette[256]; + int m_origin; + int m_bpp; + int m_offset; + BmpCompression m_rle_code; +}; + + +// ... writer +class BmpEncoder : public BaseImageEncoder +{ +public: + BmpEncoder(); + ~BmpEncoder(); + + bool write( const Mat& img, const vector& params ); + + ImageEncoder newEncoder() const; +}; + +} + +#endif/*_GRFMT_BMP_H_*/ diff --git a/highgui/src/grfmt_exr.cpp b/highgui/src/grfmt_exr.cpp new file mode 100644 index 0000000..ac874ae --- /dev/null +++ b/highgui/src/grfmt_exr.cpp @@ -0,0 +1,738 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#ifdef HAVE_OPENEXR + +#include +#include +#include +#include +#include +#include +#include "grfmt_exr.hpp" + +#if defined _MSC_VER && _MSC_VER >= 1200 +#pragma comment(lib, "Half.lib") +#pragma comment(lib, "Iex.lib") +#pragma comment(lib, "IlmImf.lib") +#pragma comment(lib, "IlmThread.lib") +#pragma comment(lib, "Imath.lib") + +#undef UINT +#define UINT ((Imf::PixelType)0) +#undef HALF +#define HALF ((Imf::PixelType)1) +#undef FLOAT +#define FLOAT ((Imf::PixelType)2) + +#endif + +namespace cv +{ + +/////////////////////// ExrDecoder /////////////////// + +ExrDecoder::ExrDecoder() +{ + m_signature = "\x76\x2f\x31\x01"; + m_file = 0; + m_red = m_green = m_blue = 0; +} + + +ExrDecoder::~ExrDecoder() +{ + close(); +} + + +void ExrDecoder::close() +{ + if( m_file ) + { + delete m_file; + m_file = 0; + } +} + + +int ExrDecoder::type() const +{ + return CV_MAKETYPE((m_isfloat ? CV_32F : CV_32S), m_iscolor ? 3 : 1); +} + + +bool ExrDecoder::readHeader() +{ + bool result = false; + + m_file = new InputFile( m_filename.c_str() ); + + if( !m_file ) // probably paranoid + return false; + + m_datawindow = m_file->header().dataWindow(); + m_width = m_datawindow.max.x - m_datawindow.min.x + 1; + m_height = m_datawindow.max.y - m_datawindow.min.y + 1; + + // the type HALF is converted to 32 bit float + // and the other types supported by OpenEXR are 32 bit anyway + m_bit_depth = 32; + + if( hasChromaticities( m_file->header() )) + m_chroma = chromaticities( m_file->header() ); + + const ChannelList &channels = m_file->header().channels(); + m_red = channels.findChannel( "R" ); + m_green = channels.findChannel( "G" ); + m_blue = channels.findChannel( "B" ); + if( m_red || m_green || m_blue ) + { + m_iscolor = true; + m_ischroma = false; + result = true; + } + else + { + m_green = channels.findChannel( "Y" ); + if( m_green ) + { + m_ischroma = true; + m_red = channels.findChannel( "RY" ); + m_blue = channels.findChannel( "BY" ); + m_iscolor = (m_blue || m_red); + result = true; + } + else + result = false; + } + + if( result ) + { + int uintcnt = 0; + int chcnt = 0; + if( m_red ) + { + chcnt++; + uintcnt += ( m_red->type == UINT ); + } + if( m_green ) + { + chcnt++; + uintcnt += ( m_green->type == UINT ); + } + if( m_blue ) + { + chcnt++; + uintcnt += ( m_blue->type == UINT ); + } + m_type = (chcnt == uintcnt) ? UINT : FLOAT; + + m_isfloat = (m_type == FLOAT); + } + + if( !result ) + close(); + + return result; +} + + +bool ExrDecoder::readData( Mat& img ) +{ + m_native_depth = CV_MAT_DEPTH(type()) == img.depth(); + bool color = img.channels() > 1; + + uchar* data = img.data; + int step = img.step; + bool justcopy = m_native_depth; + bool chromatorgb = false; + bool rgbtogray = false; + bool result = true; + FrameBuffer frame; + int xsample[3] = {1, 1, 1}; + char *buffer; + int xstep; + int ystep; + + xstep = m_native_depth ? 4 : 1; + + if( !m_native_depth || (!color && m_iscolor )) + { + buffer = (char *)new float[ m_width * 3 ]; + ystep = 0; + } + else + { + buffer = (char *)data; + ystep = step; + } + + if( m_ischroma ) + { + if( color ) + { + if( m_iscolor ) + { + if( m_blue ) + { + frame.insert( "BY", Slice( m_type, + buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep, + 12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 )); + xsample[0] = m_blue->ySampling; + } + if( m_green ) + { + frame.insert( "Y", Slice( m_type, + buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4, + 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); + xsample[1] = m_green->ySampling; + } + if( m_red ) + { + frame.insert( "RY", Slice( m_type, + buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8, + 12, ystep, m_red->xSampling, m_red->ySampling, 0.0 )); + xsample[2] = m_red->ySampling; + } + chromatorgb = true; + } + else + { + frame.insert( "Y", Slice( m_type, + buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep, + 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); + frame.insert( "Y", Slice( m_type, + buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4, + 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); + frame.insert( "Y", Slice( m_type, + buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8, + 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); + xsample[0] = m_green->ySampling; + xsample[1] = m_green->ySampling; + xsample[2] = m_green->ySampling; + } + } + else + { + frame.insert( "Y", Slice( m_type, + buffer - m_datawindow.min.x * 4 - m_datawindow.min.y * ystep, + 4, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); + xsample[0] = m_green->ySampling; + } + } + else + { + if( m_blue ) + { + frame.insert( "B", Slice( m_type, + buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep, + 12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 )); + xsample[0] = m_blue->ySampling; + } + if( m_green ) + { + frame.insert( "G", Slice( m_type, + buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4, + 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); + xsample[1] = m_green->ySampling; + } + if( m_red ) + { + frame.insert( "R", Slice( m_type, + buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8, + 12, ystep, m_red->xSampling, m_red->ySampling, 0.0 )); + xsample[2] = m_red->ySampling; + } + if(color == 0) + { + rgbtogray = true; + justcopy = false; + } + } + + m_file->setFrameBuffer( frame ); + if( justcopy ) + { + m_file->readPixels( m_datawindow.min.y, m_datawindow.max.y ); + + if( color ) + { + if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) ) + UpSample( data, 3, step / xstep, xsample[0], m_blue->ySampling ); + if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) ) + UpSample( data + xstep, 3, step / xstep, xsample[1], m_green->ySampling ); + if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) ) + UpSample( data + 2 * xstep, 3, step / xstep, xsample[2], m_red->ySampling ); + } + else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) ) + UpSample( data, 1, step / xstep, xsample[0], m_green->ySampling ); + } + else + { + uchar *out = data; + int x, y; + for( y = m_datawindow.min.y; y <= m_datawindow.max.y; y++ ) + { + m_file->readPixels( y, y ); + + if( rgbtogray ) + { + if( xsample[0] != 1 ) + UpSampleX( (float *)buffer, 3, xsample[0] ); + if( xsample[1] != 1 ) + UpSampleX( (float *)buffer + 4, 3, xsample[1] ); + if( xsample[2] != 1 ) + UpSampleX( (float *)buffer + 8, 3, xsample[2] ); + + RGBToGray( (float *)buffer, (float *)out ); + } + else + { + if( xsample[0] != 1 ) + UpSampleX( (float *)buffer, 3, xsample[0] ); + if( xsample[1] != 1 ) + UpSampleX( (float *)(buffer + 4), 3, xsample[1] ); + if( xsample[2] != 1 ) + UpSampleX( (float *)(buffer + 8), 3, xsample[2] ); + + if( chromatorgb ) + ChromaToBGR( (float *)buffer, 1, step ); + + if( m_type == FLOAT ) + { + float *fi = (float *)buffer; + for( x = 0; x < m_width * 3; x++) + { + int t = cvRound(fi[x]*5); + out[x] = CV_CAST_8U(t); + } + } + else + { + unsigned *ui = (unsigned *)buffer; + for( x = 0; x < m_width * 3; x++) + { + unsigned t = ui[x]; + out[x] = CV_CAST_8U(t); + } + } + } + + out += step; + } + if( color ) + { + if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) ) + UpSampleY( data, 3, step / xstep, m_blue->ySampling ); + if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) ) + UpSampleY( data + xstep, 3, step / xstep, m_green->ySampling ); + if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) ) + UpSampleY( data + 2 * xstep, 3, step / xstep, m_red->ySampling ); + } + else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) ) + UpSampleY( data, 1, step / xstep, m_green->ySampling ); + } + + if( chromatorgb ) + ChromaToBGR( (float *)data, m_height, step / xstep ); + + close(); + + return result; +} + +/** +// on entry pixel values are stored packed in the upper left corner of the image +// this functions expands them by duplication to cover the whole image + */ +void ExrDecoder::UpSample( uchar *data, int xstep, int ystep, int xsample, int ysample ) +{ + for( int y = (m_height - 1) / ysample, yre = m_height - ysample; y >= 0; y--, yre -= ysample ) + { + for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample ) + { + for( int i = 0; i < ysample; i++ ) + { + for( int n = 0; n < xsample; n++ ) + { + if( !m_native_depth ) + data[(yre + i) * ystep + (xre + n) * xstep] = data[y * ystep + x * xstep]; + else if( m_type == FLOAT ) + ((float *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((float *)data)[y * ystep + x * xstep]; + else + ((unsigned *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((unsigned *)data)[y * ystep + x * xstep]; + } + } + } + } +} + +/** +// on entry pixel values are stored packed in the upper left corner of the image +// this functions expands them by duplication to cover the whole image + */ +void ExrDecoder::UpSampleX( float *data, int xstep, int xsample ) +{ + for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample ) + { + for( int n = 0; n < xsample; n++ ) + { + if( m_type == FLOAT ) + ((float *)data)[(xre + n) * xstep] = ((float *)data)[x * xstep]; + else + ((unsigned *)data)[(xre + n) * xstep] = ((unsigned *)data)[x * xstep]; + } + } +} + +/** +// on entry pixel values are stored packed in the upper left corner of the image +// this functions expands them by duplication to cover the whole image + */ +void ExrDecoder::UpSampleY( uchar *data, int xstep, int ystep, int ysample ) +{ + for( int y = m_height - ysample, yre = m_height - ysample; y >= 0; y -= ysample, yre -= ysample ) + { + for( int x = 0; x < m_width; x++ ) + { + for( int i = 1; i < ysample; i++ ) + { + if( !m_native_depth ) + data[(yre + i) * ystep + x * xstep] = data[y * ystep + x * xstep]; + else if( m_type == FLOAT ) + ((float *)data)[(yre + i) * ystep + x * xstep] = ((float *)data)[y * ystep + x * xstep]; + else + ((unsigned *)data)[(yre + i) * ystep + x * xstep] = ((unsigned *)data)[y * ystep + x * xstep]; + } + } + } +} + +/** +// algorithm from ImfRgbaYca.cpp + */ +void ExrDecoder::ChromaToBGR( float *data, int numlines, int step ) +{ + for( int y = 0; y < numlines; y++ ) + { + for( int x = 0; x < m_width; x++ ) + { + double b, Y, r; + if( !m_native_depth ) + { + b = ((uchar *)data)[y * step + x * 3]; + Y = ((uchar *)data)[y * step + x * 3 + 1]; + r = ((uchar *)data)[y * step + x * 3 + 2]; + } + else if( m_type == FLOAT ) + { + b = data[y * step + x * 3]; + Y = data[y * step + x * 3 + 1]; + r = data[y * step + x * 3 + 2]; + } + else + { + b = ((unsigned *)data)[y * step + x * 3]; + Y = ((unsigned *)data)[y * step + x * 3 + 1]; + r = ((unsigned *)data)[y * step + x * 3 + 2]; + } + r = (r + 1) * Y; + b = (b + 1) * Y; + Y = (Y - b * m_chroma.blue[1] - r * m_chroma.red[1]) / m_chroma.green[1]; + + if( !m_native_depth ) + { + int t = cvRound(b); + ((uchar *)data)[y * step + x * 3] = CV_CAST_8U(t); + t = cvRound(Y); + ((uchar *)data)[y * step + x * 3 + 1] = CV_CAST_8U(t); + t = cvRound(r); + ((uchar *)data)[y * step + x * 3 + 2] = CV_CAST_8U(t); + } + else if( m_type == FLOAT ) + { + data[y * step + x * 3] = (float)b; + data[y * step + x * 3 + 1] = (float)Y; + data[y * step + x * 3 + 2] = (float)r; + } + else + { + int t = cvRound(b); + ((unsigned *)data)[y * step + x * 3] = (unsigned)MAX(t,0); + t = cvRound(Y); + ((unsigned *)data)[y * step + x * 3 + 1] = (unsigned)MAX(t,0); + t = cvRound(r); + ((unsigned *)data)[y * step + x * 3 + 2] = (unsigned)MAX(t,0); + } + } + } +} + + +/** +// convert one row to gray +*/ +void ExrDecoder::RGBToGray( float *in, float *out ) +{ + if( m_type == FLOAT ) + { + if( m_native_depth ) + { + for( int i = 0, n = 0; i < m_width; i++, n += 3 ) + out[i] = in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0]; + } + else + { + uchar *o = (uchar *)out; + for( int i = 0, n = 0; i < m_width; i++, n += 3 ) + o[i] = (uchar) (in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0]); + } + } + else // UINT + { + if( m_native_depth ) + { + unsigned *ui = (unsigned *)in; + for( int i = 0; i < m_width * 3; i++ ) + ui[i] -= 0x80000000; + int *si = (int *)in; + for( int i = 0, n = 0; i < m_width; i++, n += 3 ) + ((int *)out)[i] = int(si[n] * m_chroma.blue[0] + si[n + 1] * m_chroma.green[0] + si[n + 2] * m_chroma.red[0]); + } + else // how to best convert float to uchar? + { + unsigned *ui = (unsigned *)in; + for( int i = 0, n = 0; i < m_width; i++, n += 3 ) + ((uchar *)out)[i] = uchar((ui[n] * m_chroma.blue[0] + ui[n + 1] * m_chroma.green[0] + ui[n + 2] * m_chroma.red[0]) * (256.0 / 4294967296.0)); + } + } +} + + +ImageDecoder ExrDecoder::newDecoder() const +{ + return new ExrDecoder; +} + +/////////////////////// ExrEncoder /////////////////// + + +ExrEncoder::ExrEncoder() +{ + m_description = "OpenEXR Image files (*.exr)"; +} + + +ExrEncoder::~ExrEncoder() +{ +} + + +bool ExrEncoder::isFormatSupported( int depth ) const +{ + return CV_MAT_DEPTH(depth) >= CV_8U && CV_MAT_DEPTH(depth) < CV_64F; +} + + +// TODO scale appropriately +bool ExrEncoder::write( const Mat& img, const vector& ) +{ + int width = img.cols, height = img.rows; + int depth = img.depth(), channels = img.channels(); + bool result = false; + bool issigned = depth == CV_8S || depth == CV_16S || depth == CV_32S; + bool isfloat = depth == CV_32F || depth == CV_64F; + depth = CV_ELEM_SIZE1(depth)*8; + uchar* data = img.data; + int step = img.step; + + Header header( width, height ); + Imf::PixelType type; + + if(depth == 8) + type = HALF; + else if(isfloat) + type = FLOAT; + else + type = UINT; + + if( channels == 3 ) + { + header.channels().insert( "R", Channel( type )); + header.channels().insert( "G", Channel( type )); + header.channels().insert( "B", Channel( type )); + //printf("bunt\n"); + } + else + { + header.channels().insert( "Y", Channel( type )); + //printf("gray\n"); + } + + OutputFile file( m_filename.c_str(), header ); + + FrameBuffer frame; + + char *buffer; + int bufferstep; + int size; + if( type == FLOAT && depth == 32 ) + { + buffer = (char *)const_cast(data); + bufferstep = step; + size = 4; + } + else if( depth > 16 || type == UINT ) + { + buffer = (char *)new unsigned[width * channels]; + bufferstep = 0; + size = 4; + } + else + { + buffer = (char *)new half[width * channels]; + bufferstep = 0; + size = 2; + } + + //printf("depth %d %s\n", depth, types[type]); + + if( channels == 3 ) + { + frame.insert( "B", Slice( type, buffer, size * 3, bufferstep )); + frame.insert( "G", Slice( type, buffer + size, size * 3, bufferstep )); + frame.insert( "R", Slice( type, buffer + size * 2, size * 3, bufferstep )); + } + else + frame.insert( "Y", Slice( type, buffer, size, bufferstep )); + + file.setFrameBuffer( frame ); + + int offset = issigned ? 1 << (depth - 1) : 0; + + result = true; + if( type == FLOAT && depth == 32 ) + { + try + { + file.writePixels( height ); + } + catch(...) + { + result = false; + } + } + else + { + // int scale = 1 << (32 - depth); + // printf("scale %d\n", scale); + for(int line = 0; line < height; line++) + { + if(type == UINT) + { + unsigned *buf = (unsigned*)buffer; // FIXME 64-bit problems + + if( depth <= 8 ) + { + for(int i = 0; i < width * channels; i++) + buf[i] = data[i] + offset; + } + else if( depth <= 16 ) + { + unsigned short *sd = (unsigned short *)data; + for(int i = 0; i < width * channels; i++) + buf[i] = sd[i] + offset; + } + else + { + int *sd = (int *)data; // FIXME 64-bit problems + for(int i = 0; i < width * channels; i++) + buf[i] = (unsigned) sd[i] + offset; + } + } + else + { + half *buf = (half *)buffer; + + if( depth <= 8 ) + { + for(int i = 0; i < width * channels; i++) + buf[i] = data[i]; + } + else if( depth <= 16 ) + { + unsigned short *sd = (unsigned short *)data; + for(int i = 0; i < width * channels; i++) + buf[i] = sd[i]; + } + } + try + { + file.writePixels( 1 ); + } + catch(...) + { + result = false; + break; + } + data += step; + } + delete[] buffer; + } + + return result; +} + + +ImageEncoder ExrEncoder::newEncoder() const +{ + return new ExrEncoder; +} + +} + +#endif + +/* End of file. */ diff --git a/highgui/src/grfmt_exr.hpp b/highgui/src/grfmt_exr.hpp new file mode 100644 index 0000000..9c8c609 --- /dev/null +++ b/highgui/src/grfmt_exr.hpp @@ -0,0 +1,113 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _GRFMT_EXR_H_ +#define _GRFMT_EXR_H_ + +#ifdef HAVE_OPENEXR + +#include +#include +#include +#include +#include "grfmt_base.hpp" + +namespace cv +{ + +using namespace Imf; +using namespace Imath; + +/* libpng version only */ + +class ExrDecoder : public BaseImageDecoder +{ +public: + + ExrDecoder(); + ~ExrDecoder(); + + int type() const; + bool readData( Mat& img ); + bool readHeader(); + void close(); + + ImageDecoder newDecoder() const; + +protected: + void UpSample( uchar *data, int xstep, int ystep, int xsample, int ysample ); + void UpSampleX( float *data, int xstep, int xsample ); + void UpSampleY( uchar *data, int xstep, int ystep, int ysample ); + void ChromaToBGR( float *data, int numlines, int step ); + void RGBToGray( float *in, float *out ); + + InputFile *m_file; + Imf::PixelType m_type; + Box2i m_datawindow; + bool m_ischroma; + const Channel *m_red; + const Channel *m_green; + const Channel *m_blue; + Chromaticities m_chroma; + int m_bit_depth; + bool m_native_depth; + bool m_iscolor; + bool m_isfloat; +}; + + +class ExrEncoder : public BaseImageEncoder +{ +public: + ExrEncoder(); + ~ExrEncoder(); + + bool isFormatSupported( int depth ) const; + bool write( const Mat& img, const vector& params ); + ImageEncoder newEncoder() const; +}; + +} + +#endif + +#endif/*_GRFMT_EXR_H_*/ diff --git a/highgui/src/grfmt_imageio.cpp b/highgui/src/grfmt_imageio.cpp new file mode 100644 index 0000000..379d8b31 --- /dev/null +++ b/highgui/src/grfmt_imageio.cpp @@ -0,0 +1,396 @@ +/* + * grfmt_imageio.cpp + * + * + * Created by Morgan Conbere on 5/17/07. + * + */ + +#include "precomp.hpp" + +#ifdef HAVE_IMAGEIO + +#include "grfmt_imageio.hpp" + +namespace cv +{ + +/////////////////////// ImageIODecoder /////////////////// + +ImageIODecoder::ImageIODecoder() +{ + imageRef = NULL; +} + +ImageIODecoder::~ImageIODecoder() +{ + close(); +} + + +void ImageIODecoder::close() +{ + CGImageRelease( imageRef ); + imageRef = NULL; +} + + +size_t ImageIODecoder::signatureLength() const +{ + return 12; +} + +bool ImageIODecoder::checkSignature( const string& signature ) const +{ + // TODO: implement real signature check + return true; +} + +ImageDecoder ImageIODecoder::newDecoder() const +{ + return new ImageIODecoder; +} + +bool ImageIODecoder::readHeader() +{ + CFURLRef imageURLRef; + CGImageSourceRef sourceRef; + // diciu, if ReadHeader is called twice in a row make sure to release the previously allocated imageRef + if (imageRef != NULL) + CGImageRelease(imageRef); + imageRef = NULL; + + imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL, + (const UInt8*)m_filename.c_str(), m_filename.size(), false ); + + sourceRef = CGImageSourceCreateWithURL( imageURLRef, NULL ); + CFRelease( imageURLRef ); + if ( !sourceRef ) + return false; + + imageRef = CGImageSourceCreateImageAtIndex( sourceRef, 0, NULL ); + CFRelease( sourceRef ); + if( !imageRef ) + return false; + + m_width = CGImageGetWidth( imageRef ); + m_height = CGImageGetHeight( imageRef ); + + CGColorSpaceRef colorSpace = CGImageGetColorSpace( imageRef ); + if( !colorSpace ) + return false; + + m_type = CGColorSpaceGetNumberOfComponents( colorSpace ) > 1 ? CV_8UC3 : CV_8UC1; + + return true; +} + + +bool ImageIODecoder::readData( Mat& img ) +{ + uchar* data = img.data; + int step = img.step; + bool color = img.channels() > 1; + int bpp; // Bytes per pixel + int bit_depth = 8; + + // Get Height, Width, and color information + if( !readHeader() ) + return false; + + CGContextRef context = NULL; // The bitmap context + CGColorSpaceRef colorSpace = NULL; + uchar* bitmap = NULL; + CGImageAlphaInfo alphaInfo; + + // CoreGraphics will take care of converting to grayscale and back as long as the + // appropriate colorspace is set + if( color == CV_LOAD_IMAGE_GRAYSCALE ) + { + colorSpace = CGColorSpaceCreateDeviceGray(); + bpp = 1; + alphaInfo = kCGImageAlphaNone; + } + else if( color == CV_LOAD_IMAGE_COLOR ) + { +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + colorSpace = CGColorSpaceCreateDeviceRGB(); +#else + colorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericRGBLinear ); +#endif + bpp = 4; /* CG only has 8 and 32 bit color spaces, so we waste a byte */ + alphaInfo = kCGImageAlphaNoneSkipLast; + } + if( !colorSpace ) + return false; + + bitmap = (uchar*)malloc( bpp * m_height * m_width ); + if( !bitmap ) + { + CGColorSpaceRelease( colorSpace ); + return false; + } + + context = CGBitmapContextCreate( (void *)bitmap, + m_width, /* width */ + m_height, /* height */ + bit_depth, /* bit depth */ + bpp * m_width, /* bytes per row */ + colorSpace, /* color space */ + alphaInfo); + + CGColorSpaceRelease( colorSpace ); + if( !context ) + { + free( bitmap ); + return false; + } + + // Copy the image data into the bitmap region + CGRect rect = {{0,0},{m_width,m_height}}; + CGContextDrawImage( context, rect, imageRef ); + + uchar* bitdata = (uchar*)CGBitmapContextGetData( context ); + if( !bitdata ) + { + free( bitmap); + CGContextRelease( context ); + return false; + } + + // Move the bitmap (in RGB) into data (in BGR) + int bitmapIndex = 0; + + if( color == CV_LOAD_IMAGE_COLOR ) + { + uchar * base = data; + + for (int y = 0; y < m_height; y++) + { + uchar * line = base + y * step; + + for (int x = 0; x < m_width; x++) + { + // Blue channel + line[0] = bitdata[bitmapIndex + 2]; + // Green channel + line[1] = bitdata[bitmapIndex + 1]; + // Red channel + line[2] = bitdata[bitmapIndex + 0]; + + line += 3; + bitmapIndex += bpp; + } + } + } + else if( color == CV_LOAD_IMAGE_GRAYSCALE ) + { + for (int y = 0; y < m_height; y++) + memcpy (data + y * step, bitmap + y * m_width, m_width); + } + + free( bitmap ); + CGContextRelease( context ); + return true; +} + + +/////////////////////// ImageIOEncoder /////////////////// + +ImageIOEncoder::ImageIOEncoder() +{ + m_description = "Apple ImageIO (*.bmp;*.dib;*.exr;*.jpeg;*.jpg;*.jpe;*.jp2;*.pdf;*.png;*.tiff;*.tif)"; +} + + +ImageIOEncoder::~ImageIOEncoder() +{ +} + + +ImageEncoder ImageIOEncoder::newEncoder() const +{ + return new ImageIOEncoder; +} + +static +CFStringRef FilenameToUTI( const char* filename ) +{ + const char* ext = filename; + char* ext_buf; + int i; + CFStringRef imageUTI = NULL; + + for(;;) + { + const char* temp = strchr( ext + 1, '.' ); + if( !temp ) break; + ext = temp; + } + + if(!ext) + return NULL; + + ext_buf = (char*)malloc(strlen(ext)+1); + for(i = 0; ext[i] != '\0'; i++) + ext_buf[i] = (char)tolower(ext[i]); + ext_buf[i] = '\0'; + ext = ext_buf; + + if( !strcmp(ext, ".bmp") || !strcmp(ext, ".dib") ) + imageUTI = CFSTR( "com.microsoft.bmp" ); + else if( !strcmp(ext, ".exr") ) + imageUTI = CFSTR( "com.ilm.openexr-image" ); + else if( !strcmp(ext, ".jpeg") || !strcmp(ext, ".jpg") || !strcmp(ext, ".jpe") ) + imageUTI = CFSTR( "public.jpeg" ); + else if( !strcmp(ext, ".jp2") ) + imageUTI = CFSTR( "public.jpeg-2000" ); + else if( !strcmp(ext, ".pdf") ) + imageUTI = CFSTR( "com.adobe.pdf" ); + else if( !strcmp(ext, ".png") ) + imageUTI = CFSTR( "public.png" ); + else if( !strcmp(ext, ".tiff") || !strcmp(ext, ".tif") ) + imageUTI = CFSTR( "public.tiff" ); + + free(ext_buf); + + return imageUTI; +} + + +bool ImageIOEncoder::write( const Mat& img, const vector& params ) +{ + int width = img.cols, height = img.rows; + int _channels = img.channels(); + const uchar* data = img.data; + int step = img.step; + + // Determine the appropriate UTI based on the filename extension + CFStringRef imageUTI = FilenameToUTI( m_filename.c_str() ); + + // Determine the Bytes Per Pixel + int bpp = (_channels == 1) ? 1 : 4; + + // Write the data into a bitmap context + CGContextRef context; + CGColorSpaceRef colorSpace; + uchar* bitmapData = NULL; + + if( bpp == 1 ) { +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + colorSpace = CGColorSpaceCreateDeviceGray(); +#else + colorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericGray ); +#endif + } + else if( bpp == 4 ) { +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + colorSpace = CGColorSpaceCreateDeviceRGB(); +#else + colorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericRGBLinear ); +#endif + } + if( !colorSpace ) + return false; + + bitmapData = (uchar*)malloc( bpp * height * width ); + if( !bitmapData ) + { + CGColorSpaceRelease( colorSpace ); + return false; + } + + context = CGBitmapContextCreate( bitmapData, + width, + height, + 8, + bpp * width, + colorSpace, + (bpp == 1) ? kCGImageAlphaNone : + kCGImageAlphaNoneSkipLast ); + CGColorSpaceRelease( colorSpace ); + if( !context ) + { + free( bitmapData ); + return false; + } + + // Copy pixel information from data into bitmapData + if (bpp == 4) + { + int bitmapIndex = 0; + const uchar * base = data; + + for (int y = 0; y < height; y++) + { + const uchar * line = base + y * step; + + for (int x = 0; x < width; x++) + { + // Blue channel + bitmapData[bitmapIndex + 2] = line[0]; + // Green channel + bitmapData[bitmapIndex + 1] = line[1]; + // Red channel + bitmapData[bitmapIndex + 0] = line[2]; + + line += 3; + bitmapIndex += bpp; + } + } + } + else if (bpp == 1) + { + for (int y = 0; y < height; y++) + memcpy (bitmapData + y * width, data + y * step, width); + } + + // Turn the bitmap context into an imageRef + CGImageRef imageRef = CGBitmapContextCreateImage( context ); + CGContextRelease( context ); + if( !imageRef ) + { + free( bitmapData ); + return false; + } + + // Write the imageRef to a file based on the UTI + CFURLRef imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL, + (const UInt8*)m_filename.c_str(), m_filename.size(), false ); + if( !imageURLRef ) + { + CGImageRelease( imageRef ); + free( bitmapData ); + return false; + } + + CGImageDestinationRef destRef = CGImageDestinationCreateWithURL( imageURLRef, + imageUTI, + 1, + NULL); + CFRelease( imageURLRef ); + if( !destRef ) + { + CGImageRelease( imageRef ); + free( bitmapData ); + fprintf(stderr, "!destRef\n"); + return false; + } + + CGImageDestinationAddImage(destRef, imageRef, NULL); + if( !CGImageDestinationFinalize(destRef) ) + { + fprintf(stderr, "Finalize failed\n"); + return false; + } + + CFRelease( destRef ); + CGImageRelease( imageRef ); + free( bitmapData ); + + return true; +} + +} + +#endif /* HAVE_IMAGEIO */ diff --git a/highgui/src/grfmt_imageio.hpp b/highgui/src/grfmt_imageio.hpp new file mode 100644 index 0000000..00a919d --- /dev/null +++ b/highgui/src/grfmt_imageio.hpp @@ -0,0 +1,67 @@ +/* + * grfmt_imageio.h + * + * + * Created by Morgan Conbere on 5/17/07. + * + */ + +#ifndef _GRFMT_IMAGEIO_H_ +#define _GRFMT_IMAGEIO_H_ + +#ifdef HAVE_IMAGEIO + +#include "grfmt_base.hpp" +#include + +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + +#include +#include + +#else + +#include + +#endif + +namespace cv +{ + +class ImageIODecoder : public BaseImageDecoder +{ +public: + + ImageIODecoder(); + ~ImageIODecoder(); + + bool readData( Mat& img ); + bool readHeader(); + void close(); + + size_t signatureLength() const; + bool checkSignature( const string& signature ) const; + + ImageDecoder newDecoder() const; + +protected: + + CGImageRef imageRef; +}; + +class ImageIOEncoder : public BaseImageEncoder +{ +public: + ImageIOEncoder(); + ~ImageIOEncoder(); + + bool write( const Mat& img, const vector& params ); + + ImageEncoder newEncoder() const; +}; + +} + +#endif/*HAVE_IMAGEIO*/ + +#endif/*_GRFMT_IMAGEIO_H_*/ diff --git a/highgui/src/grfmt_jpeg.cpp b/highgui/src/grfmt_jpeg.cpp new file mode 100644 index 0000000..20421ce --- /dev/null +++ b/highgui/src/grfmt_jpeg.cpp @@ -0,0 +1,638 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include "grfmt_jpeg.hpp" + +#ifdef HAVE_JPEG + +#ifdef _MSC_VER +//interaction between '_setjmp' and C++ object destruction is non-portable +#pragma warning(disable: 4611) +#endif + +#include +#include + +#ifdef WIN32 + +#define XMD_H // prevent redefinition of INT32 +#undef FAR // prevent FAR redefinition + +#endif + +#if defined WIN32 && defined __GNUC__ +typedef unsigned char boolean; +#endif + +extern "C" { +#include "jpeglib.h" +} + +namespace cv +{ + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4324) //structure was padded due to __declspec(align()) +#endif +struct JpegErrorMgr +{ + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; +}; +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +struct JpegSource +{ + struct jpeg_source_mgr pub; + int skip; +}; + +struct JpegState +{ + jpeg_decompress_struct cinfo; // IJG JPEG codec structure + JpegErrorMgr jerr; // error processing manager state + JpegSource source; // memory buffer source +}; + +/////////////////////// Error processing ///////////////////// + +METHODDEF(void) +stub(j_decompress_ptr) +{ +} + +METHODDEF(boolean) +fill_input_buffer(j_decompress_ptr) +{ + return FALSE; +} + +// emulating memory input stream + +METHODDEF(void) +skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + JpegSource* source = (JpegSource*) cinfo->src; + + if( num_bytes > (long)source->pub.bytes_in_buffer ) + { + // We need to skip more data than we have in the buffer. + // This will force the JPEG library to suspend decoding. + source->skip = (int)(num_bytes - source->pub.bytes_in_buffer); + source->pub.next_input_byte += source->pub.bytes_in_buffer; + source->pub.bytes_in_buffer = 0; + } + else + { + // Skip portion of the buffer + source->pub.bytes_in_buffer -= num_bytes; + source->pub.next_input_byte += num_bytes; + source->skip = 0; + } +} + + +static void jpeg_buffer_src(j_decompress_ptr cinfo, JpegSource* source) +{ + cinfo->src = &source->pub; + + // Prepare for suspending reader + source->pub.init_source = stub; + source->pub.fill_input_buffer = fill_input_buffer; + source->pub.skip_input_data = skip_input_data; + source->pub.resync_to_restart = jpeg_resync_to_restart; + source->pub.term_source = stub; + source->pub.bytes_in_buffer = 0; // forces fill_input_buffer on first read + + source->skip = 0; +} + + +METHODDEF(void) +error_exit( j_common_ptr cinfo ) +{ + JpegErrorMgr* err_mgr = (JpegErrorMgr*)(cinfo->err); + + /* Return control to the setjmp point */ + longjmp( err_mgr->setjmp_buffer, 1 ); +} + + +/////////////////////// JpegDecoder /////////////////// + + +JpegDecoder::JpegDecoder() +{ + m_signature = "\xFF\xD8\xFF"; + m_state = 0; + m_f = 0; + m_buf_supported = true; +} + + +JpegDecoder::~JpegDecoder() +{ + close(); +} + + +void JpegDecoder::close() +{ + if( m_state ) + { + JpegState* state = (JpegState*)m_state; + jpeg_destroy_decompress( &state->cinfo ); + delete state; + m_state = 0; + } + + if( m_f ) + { + fclose( m_f ); + m_f = 0; + } + + m_width = m_height = 0; + m_type = -1; +} + +ImageDecoder JpegDecoder::newDecoder() const +{ + return new JpegDecoder; +} + +bool JpegDecoder::readHeader() +{ + bool result = false; + close(); + + JpegState* state = new JpegState; + m_state = state; + state->cinfo.err = jpeg_std_error(&state->jerr.pub); + state->jerr.pub.error_exit = error_exit; + + if( setjmp( state->jerr.setjmp_buffer ) == 0 ) + { + jpeg_create_decompress( &state->cinfo ); + + if( !m_buf.empty() ) + { + jpeg_buffer_src(&state->cinfo, &state->source); + state->source.pub.next_input_byte = m_buf.data; + state->source.pub.bytes_in_buffer = m_buf.cols*m_buf.rows*m_buf.elemSize(); + } + else + { + m_f = fopen( m_filename.c_str(), "rb" ); + if( m_f ) + jpeg_stdio_src( &state->cinfo, m_f ); + } + jpeg_read_header( &state->cinfo, TRUE ); + + m_width = state->cinfo.image_width; + m_height = state->cinfo.image_height; + m_type = state->cinfo.num_components > 1 ? CV_8UC3 : CV_8UC1; + result = true; + } + + if( !result ) + close(); + + return result; +} + +/*************************************************************************** + * following code is for supporting MJPEG image files + * based on a message of Laurent Pinchart on the video4linux mailing list + ***************************************************************************/ + +/* JPEG DHT Segment for YCrCb omitted from MJPEG data */ +static +unsigned char my_jpeg_odml_dht[0x1a4] = { + 0xff, 0xc4, 0x01, 0xa2, + + 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + + 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + + 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, + 0x04, 0x00, 0x00, 0x01, 0x7d, + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, + 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, + 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, + 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, + 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, + 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, + + 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, + 0x04, 0x00, 0x01, 0x02, 0x77, + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, + 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, + 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, + 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, + 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, + 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, + 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, + 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, + 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa +}; + +/* + * Parse the DHT table. + * This code comes from jpeg6b (jdmarker.c). + */ +static +int my_jpeg_load_dht (struct jpeg_decompress_struct *info, unsigned char *dht, + JHUFF_TBL *ac_tables[], JHUFF_TBL *dc_tables[]) +{ + unsigned int length = (dht[2] << 8) + dht[3] - 2; + unsigned int pos = 4; + unsigned int count, i; + int index; + + JHUFF_TBL **hufftbl; + unsigned char bits[17]; + unsigned char huffval[256]; + + while (length > 16) + { + bits[0] = 0; + index = dht[pos++]; + count = 0; + for (i = 1; i <= 16; ++i) + { + bits[i] = dht[pos++]; + count += bits[i]; + } + length -= 17; + + if (count > 256 || count > length) + return -1; + + for (i = 0; i < count; ++i) + huffval[i] = dht[pos++]; + length -= count; + + if (index & 0x10) + { + index -= 0x10; + hufftbl = &ac_tables[index]; + } + else + hufftbl = &dc_tables[index]; + + if (index < 0 || index >= NUM_HUFF_TBLS) + return -1; + + if (*hufftbl == NULL) + *hufftbl = jpeg_alloc_huff_table ((j_common_ptr)info); + if (*hufftbl == NULL) + return -1; + + memcpy ((*hufftbl)->bits, bits, sizeof (*hufftbl)->bits); + memcpy ((*hufftbl)->huffval, huffval, sizeof (*hufftbl)->huffval); + } + + if (length != 0) + return -1; + + return 0; +} + +/*************************************************************************** + * end of code for supportting MJPEG image files + * based on a message of Laurent Pinchart on the video4linux mailing list + ***************************************************************************/ + +bool JpegDecoder::readData( Mat& img ) +{ + bool result = false; + int step = (int)img.step; + bool color = img.channels() > 1; + + if( m_state && m_width && m_height ) + { + jpeg_decompress_struct* cinfo = &((JpegState*)m_state)->cinfo; + JpegErrorMgr* jerr = &((JpegState*)m_state)->jerr; + JSAMPARRAY buffer = 0; + + if( setjmp( jerr->setjmp_buffer ) == 0 ) + { + /* check if this is a mjpeg image format */ + if ( cinfo->ac_huff_tbl_ptrs[0] == NULL && + cinfo->ac_huff_tbl_ptrs[1] == NULL && + cinfo->dc_huff_tbl_ptrs[0] == NULL && + cinfo->dc_huff_tbl_ptrs[1] == NULL ) + { + /* yes, this is a mjpeg image format, so load the correct + huffman table */ + my_jpeg_load_dht( cinfo, + my_jpeg_odml_dht, + cinfo->ac_huff_tbl_ptrs, + cinfo->dc_huff_tbl_ptrs ); + } + + if( color ) + { + if( cinfo->num_components != 4 ) + { + cinfo->out_color_space = JCS_RGB; + cinfo->out_color_components = 3; + } + else + { + cinfo->out_color_space = JCS_CMYK; + cinfo->out_color_components = 4; + } + } + else + { + if( cinfo->num_components != 4 ) + { + cinfo->out_color_space = JCS_GRAYSCALE; + cinfo->out_color_components = 1; + } + else + { + cinfo->out_color_space = JCS_CMYK; + cinfo->out_color_components = 4; + } + } + + jpeg_start_decompress( cinfo ); + + buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo, + JPOOL_IMAGE, m_width*4, 1 ); + + uchar* data = img.data; + for( ; m_height--; data += step ) + { + jpeg_read_scanlines( cinfo, buffer, 1 ); + if( color ) + { + if( cinfo->out_color_components == 3 ) + icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, cvSize(m_width,1) ); + else + icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, cvSize(m_width,1) ); + } + else + { + if( cinfo->out_color_components == 1 ) + memcpy( data, buffer[0], m_width ); + else + icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, cvSize(m_width,1) ); + } + } + result = true; + jpeg_finish_decompress( cinfo ); + } + } + + close(); + return result; +} + + +/////////////////////// JpegEncoder /////////////////// + +struct JpegDestination +{ + struct jpeg_destination_mgr pub; + vector *buf, *dst; +}; + +METHODDEF(void) +stub(j_compress_ptr) +{ +} + +METHODDEF(void) +term_destination (j_compress_ptr cinfo) +{ + JpegDestination* dest = (JpegDestination*)cinfo->dest; + size_t sz = dest->dst->size(), bufsz = dest->buf->size() - dest->pub.free_in_buffer; + if( bufsz > 0 ) + { + dest->dst->resize(sz + bufsz); + memcpy( &(*dest->dst)[0] + sz, &(*dest->buf)[0], bufsz); + } +} + +METHODDEF(boolean) +empty_output_buffer (j_compress_ptr cinfo) +{ + JpegDestination* dest = (JpegDestination*)cinfo->dest; + size_t sz = dest->dst->size(), bufsz = dest->buf->size(); + dest->dst->resize(sz + bufsz); + memcpy( &(*dest->dst)[0] + sz, &(*dest->buf)[0], bufsz); + + dest->pub.next_output_byte = &(*dest->buf)[0]; + dest->pub.free_in_buffer = bufsz; + return TRUE; +} + +static void jpeg_buffer_dest(j_compress_ptr cinfo, JpegDestination* destination) +{ + cinfo->dest = &destination->pub; + + destination->pub.init_destination = stub; + destination->pub.empty_output_buffer = empty_output_buffer; + destination->pub.term_destination = term_destination; +} + + +JpegEncoder::JpegEncoder() +{ + m_description = "JPEG files (*.jpeg;*.jpg;*.jpe)"; + m_buf_supported = true; +} + + +JpegEncoder::~JpegEncoder() +{ +} + +ImageEncoder JpegEncoder::newEncoder() const +{ + return new JpegEncoder; +} + +bool JpegEncoder::write( const Mat& img, const vector& params ) +{ + struct fileWrapper + { + FILE* f; + + fileWrapper() : f(0) {} + ~fileWrapper() { if(f) fclose(f); } + }; + bool result = false; + fileWrapper fw; + int width = img.cols, height = img.rows; + + vector out_buf(1 << 12); + AutoBuffer _buffer; + uchar* buffer; + + struct jpeg_compress_struct cinfo; + JpegErrorMgr jerr; + JpegDestination dest; + + jpeg_create_compress(&cinfo); + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = error_exit; + + if( !m_buf ) + { + fw.f = fopen( m_filename.c_str(), "wb" ); + if( !fw.f ) + goto _exit_; + jpeg_stdio_dest( &cinfo, fw.f ); + } + else + { + dest.dst = m_buf; + dest.buf = &out_buf; + + jpeg_buffer_dest( &cinfo, &dest ); + + dest.pub.next_output_byte = &out_buf[0]; + dest.pub.free_in_buffer = out_buf.size(); + } + + if( setjmp( jerr.setjmp_buffer ) == 0 ) + { + cinfo.image_width = width; + cinfo.image_height = height; + + int _channels = img.channels(); + int channels = _channels > 1 ? 3 : 1; + cinfo.input_components = channels; + cinfo.in_color_space = channels > 1 ? JCS_RGB : JCS_GRAYSCALE; + + int quality = 95; + + for( size_t i = 0; i < params.size(); i += 2 ) + { + if( params[i] == CV_IMWRITE_JPEG_QUALITY ) + { + quality = params[i+1]; + quality = MIN(MAX(quality, 0), 100); + } + } + + jpeg_set_defaults( &cinfo ); + jpeg_set_quality( &cinfo, quality, + TRUE /* limit to baseline-JPEG values */ ); + jpeg_start_compress( &cinfo, TRUE ); + + if( channels > 1 ) + _buffer.allocate(width*channels); + buffer = _buffer; + + for( int y = 0; y < height; y++ ) + { + uchar *data = img.data + img.step*y, *ptr = data; + + if( _channels == 3 ) + { + icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) ); + ptr = buffer; + } + else if( _channels == 4 ) + { + icvCvt_BGRA2BGR_8u_C4C3R( data, 0, buffer, 0, cvSize(width,1), 2 ); + ptr = buffer; + } + + jpeg_write_scanlines( &cinfo, &ptr, 1 ); + } + + jpeg_finish_compress( &cinfo ); + result = true; + } + +_exit_: + jpeg_destroy_compress( &cinfo ); + + return result; +} + +} + +#endif + +/* End of file. */ diff --git a/highgui/src/grfmt_jpeg.hpp b/highgui/src/grfmt_jpeg.hpp new file mode 100644 index 0000000..1a6d1ab --- /dev/null +++ b/highgui/src/grfmt_jpeg.hpp @@ -0,0 +1,90 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _GRFMT_JPEG_H_ +#define _GRFMT_JPEG_H_ + +#include "grfmt_base.hpp" +#include "bitstrm.hpp" + +#ifdef HAVE_JPEG + +// IJG-based Jpeg codec + +namespace cv +{ + +class JpegDecoder : public BaseImageDecoder +{ +public: + + JpegDecoder(); + virtual ~JpegDecoder(); + + bool readData( Mat& img ); + bool readHeader(); + void close(); + + ImageDecoder newDecoder() const; + +protected: + + FILE* m_f; + void* m_state; +}; + + +class JpegEncoder : public BaseImageEncoder +{ +public: + JpegEncoder(); + virtual ~JpegEncoder(); + + bool write( const Mat& img, const vector& params ); + ImageEncoder newEncoder() const; +}; + +} + +#endif + +#endif/*_GRFMT_JPEG_H_*/ diff --git a/highgui/src/grfmt_jpeg2000.cpp b/highgui/src/grfmt_jpeg2000.cpp new file mode 100644 index 0000000..f190835 --- /dev/null +++ b/highgui/src/grfmt_jpeg2000.cpp @@ -0,0 +1,529 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#ifdef HAVE_JASPER + +#include "grfmt_jpeg2000.hpp" + +#ifdef WIN32 +#define JAS_WIN_MSVC_BUILD 1 +#ifdef __GNUC__ +#define HAVE_STDINT_H 1 +#endif +#endif + +#undef PACKAGE +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#undef VERSION + +#include +// FIXME bad hack +#undef uchar +#undef ulong + +namespace cv +{ + +struct JasperInitializer +{ + JasperInitializer() { jas_init(); } + ~JasperInitializer() { jas_cleanup(); } +}; + +static JasperInitializer initialize_jasper; + + +/////////////////////// Jpeg2KDecoder /////////////////// + +Jpeg2KDecoder::Jpeg2KDecoder() +{ + m_signature = '\0' + string() + '\0' + string() + '\0' + string("\x0cjP \r\n\x87\n"); + m_stream = 0; + m_image = 0; +} + + +Jpeg2KDecoder::~Jpeg2KDecoder() +{ +} + +ImageDecoder Jpeg2KDecoder::newDecoder() const +{ + return new Jpeg2KDecoder; +} + +void Jpeg2KDecoder::close() +{ + if( m_stream ) + { + jas_stream_close( (jas_stream_t*)m_stream ); + m_stream = 0; + } + + if( m_image ) + { + jas_image_destroy( (jas_image_t*)m_image ); + m_image = 0; + } +} + + +bool Jpeg2KDecoder::readHeader() +{ + bool result = false; + + close(); + jas_stream_t* stream = jas_stream_fopen( m_filename.c_str(), "rb" ); + m_stream = stream; + + if( stream ) + { + jas_image_t* image = jas_image_decode( stream, -1, 0 ); + m_image = image; + if( image ) { + m_width = jas_image_width( image ); + m_height = jas_image_height( image ); + + int cntcmpts = 0; // count the known components + int numcmpts = jas_image_numcmpts( image ); + int depth = 0; + for( int i = 0; i < numcmpts; i++ ) + { + int depth_i = jas_image_cmptprec( image, i ); + depth = MAX(depth, depth_i); + if( jas_image_cmpttype( image, i ) > 2 ) + continue; + cntcmpts++; + } + + if( cntcmpts ) + { + m_type = CV_MAKETYPE(depth <= 8 ? CV_8U : CV_16U, cntcmpts > 1 ? 3 : 1); + result = true; + } + } + } + + if( !result ) + close(); + + return result; +} + + +bool Jpeg2KDecoder::readData( Mat& img ) +{ + bool result = false; + int color = img.channels() > 1; + uchar* data = img.data; + int step = (int)img.step; + jas_stream_t* stream = (jas_stream_t*)m_stream; + jas_image_t* image = (jas_image_t*)m_image; + + if( stream && image ) + { + bool convert; + int colorspace; + if( color ) + { + convert = (jas_image_clrspc( image ) != JAS_CLRSPC_SRGB); + colorspace = JAS_CLRSPC_SRGB; + } + else + { + convert = (jas_clrspc_fam( jas_image_clrspc( image ) ) != JAS_CLRSPC_FAM_GRAY); + colorspace = JAS_CLRSPC_SGRAY; // TODO GENGRAY or SGRAY? + } + + // convert to the desired colorspace + if( convert ) + { + jas_cmprof_t *clrprof = jas_cmprof_createfromclrspc( colorspace ); + if( clrprof ) + { + jas_image_t *_img = jas_image_chclrspc( image, clrprof, JAS_CMXFORM_INTENT_RELCLR ); + if( _img ) + { + jas_image_destroy( image ); + m_image = image = _img; + result = true; + } + else + fprintf(stderr, "JPEG 2000 LOADER ERROR: cannot convert colorspace\n"); + jas_cmprof_destroy( clrprof ); + } + else + fprintf(stderr, "JPEG 2000 LOADER ERROR: unable to create colorspace\n"); + } + else + result = true; + + if( result ) + { + int ncmpts; + int cmptlut[3]; + if( color ) + { + cmptlut[0] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_RGB_B ); + cmptlut[1] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_RGB_G ); + cmptlut[2] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_RGB_R ); + if( cmptlut[0] < 0 || cmptlut[1] < 0 || cmptlut[0] < 0 ) + result = false; + ncmpts = 3; + } + else + { + cmptlut[0] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_GRAY_Y ); + if( cmptlut[0] < 0 ) + result = false; + ncmpts = 1; + } + + if( result ) + { + for( int i = 0; i < ncmpts; i++ ) + { + int maxval = 1 << jas_image_cmptprec( image, cmptlut[i] ); + int offset = jas_image_cmptsgnd( image, cmptlut[i] ) ? maxval / 2 : 0; + + int yend = jas_image_cmptbry( image, cmptlut[i] ); + int ystep = jas_image_cmptvstep( image, cmptlut[i] ); + int xend = jas_image_cmptbrx( image, cmptlut[i] ); + int xstep = jas_image_cmpthstep( image, cmptlut[i] ); + + jas_matrix_t *buffer = jas_matrix_create( yend / ystep, xend / xstep ); + if( buffer ) + { + if( !jas_image_readcmpt( image, cmptlut[i], 0, 0, xend / xstep, yend / ystep, buffer )) + { + if( img.depth() == CV_8U ) + result = readComponent8u( data + i, buffer, step, cmptlut[i], maxval, offset, ncmpts ); + else + result = readComponent16u( ((unsigned short *)data) + i, buffer, step / 2, cmptlut[i], maxval, offset, ncmpts ); + if( !result ) + { + i = ncmpts; + result = false; + } + } + jas_matrix_destroy( buffer ); + } + } + } + } + else + fprintf(stderr, "JPEG2000 LOADER ERROR: colorspace conversion failed\n" ); + } + + close(); + + return result; +} + + +bool Jpeg2KDecoder::readComponent8u( uchar *data, void *_buffer, + int step, int cmpt, + int maxval, int offset, int ncmpts ) +{ + jas_matrix_t* buffer = (jas_matrix_t*)_buffer; + jas_image_t* image = (jas_image_t*)m_image; + int xstart = jas_image_cmpttlx( image, cmpt ); + int xend = jas_image_cmptbrx( image, cmpt ); + int xstep = jas_image_cmpthstep( image, cmpt ); + int xoffset = jas_image_tlx( image ); + int ystart = jas_image_cmpttly( image, cmpt ); + int yend = jas_image_cmptbry( image, cmpt ); + int ystep = jas_image_cmptvstep( image, cmpt ); + int yoffset = jas_image_tly( image ); + int x, y, x1, y1, j; + int rshift = cvRound(std::log(maxval/256.)/std::log(2.)); + int lshift = MAX(0, -rshift); + rshift = MAX(0, rshift); + int delta = (rshift > 0 ? 1 << (rshift - 1) : 0) + offset; + + for( y = 0; y < yend - ystart; ) + { + jas_seqent_t* pix_row = &jas_matrix_get( buffer, y / ystep, 0 ); + uchar* dst = data + (y - yoffset) * step - xoffset; + + if( xstep == 1 ) + { + if( maxval == 256 && offset == 0 ) + for( x = 0; x < xend - xstart; x++ ) + { + int pix = pix_row[x]; + dst[x*ncmpts] = CV_CAST_8U(pix); + } + else + for( x = 0; x < xend - xstart; x++ ) + { + int pix = ((pix_row[x] + delta) >> rshift) << lshift; + dst[x*ncmpts] = CV_CAST_8U(pix); + } + } + else if( xstep == 2 && offset == 0 ) + for( x = 0, j = 0; x < xend - xstart; x += 2, j++ ) + { + int pix = ((pix_row[j] + delta) >> rshift) << lshift; + dst[x*ncmpts] = dst[(x+1)*ncmpts] = CV_CAST_8U(pix); + } + else + for( x = 0, j = 0; x < xend - xstart; j++ ) + { + int pix = ((pix_row[j] + delta) >> rshift) << lshift; + pix = CV_CAST_8U(pix); + for( x1 = x + xstep; x < x1; x++ ) + dst[x*ncmpts] = (uchar)pix; + } + y1 = y + ystep; + for( ++y; y < y1; y++, dst += step ) + for( x = 0; x < xend - xstart; x++ ) + dst[x*ncmpts + step] = dst[x*ncmpts]; + } + + return true; +} + + +bool Jpeg2KDecoder::readComponent16u( unsigned short *data, void *_buffer, + int step, int cmpt, + int maxval, int offset, int ncmpts ) +{ + jas_matrix_t* buffer = (jas_matrix_t*)_buffer; + jas_image_t* image = (jas_image_t*)m_image; + int xstart = jas_image_cmpttlx( image, cmpt ); + int xend = jas_image_cmptbrx( image, cmpt ); + int xstep = jas_image_cmpthstep( image, cmpt ); + int xoffset = jas_image_tlx( image ); + int ystart = jas_image_cmpttly( image, cmpt ); + int yend = jas_image_cmptbry( image, cmpt ); + int ystep = jas_image_cmptvstep( image, cmpt ); + int yoffset = jas_image_tly( image ); + int x, y, x1, y1, j; + int rshift = cvRound(std::log(maxval/65536.)/std::log(2.)); + int lshift = MAX(0, -rshift); + rshift = MAX(0, rshift); + int delta = (rshift > 0 ? 1 << (rshift - 1) : 0) + offset; + + for( y = 0; y < yend - ystart; ) + { + jas_seqent_t* pix_row = &jas_matrix_get( buffer, y / ystep, 0 ); + ushort* dst = data + (y - yoffset) * step - xoffset; + + if( xstep == 1 ) + { + if( maxval == 65536 && offset == 0 ) + for( x = 0; x < xend - xstart; x++ ) + { + int pix = pix_row[x]; + dst[x*ncmpts] = CV_CAST_16U(pix); + } + else + for( x = 0; x < xend - xstart; x++ ) + { + int pix = ((pix_row[x] + delta) >> rshift) << lshift; + dst[x*ncmpts] = CV_CAST_16U(pix); + } + } + else if( xstep == 2 && offset == 0 ) + for( x = 0, j = 0; x < xend - xstart; x += 2, j++ ) + { + int pix = ((pix_row[j] + delta) >> rshift) << lshift; + dst[x*ncmpts] = dst[(x+1)*ncmpts] = CV_CAST_16U(pix); + } + else + for( x = 0, j = 0; x < xend - xstart; j++ ) + { + int pix = ((pix_row[j] + delta) >> rshift) << lshift; + pix = CV_CAST_16U(pix); + for( x1 = x + xstep; x < x1; x++ ) + dst[x*ncmpts] = (ushort)pix; + } + y1 = y + ystep; + for( ++y; y < y1; y++, dst += step ) + for( x = 0; x < xend - xstart; x++ ) + dst[x*ncmpts + step] = dst[x*ncmpts]; + } + + return true; +} + + +/////////////////////// Jpeg2KEncoder /////////////////// + + +Jpeg2KEncoder::Jpeg2KEncoder() +{ + m_description = "JPEG-2000 files (*.jp2)"; +} + + +Jpeg2KEncoder::~Jpeg2KEncoder() +{ +} + +ImageEncoder Jpeg2KEncoder::newEncoder() const +{ + return new Jpeg2KEncoder; +} + +bool Jpeg2KEncoder::isFormatSupported( int depth ) const +{ + return depth == CV_8U || depth == CV_16U; +} + + +bool Jpeg2KEncoder::write( const Mat& _img, const vector& ) +{ + int width = _img.cols, height = _img.rows; + int depth = _img.depth(), channels = _img.channels(); + depth = depth == CV_8U ? 8 : 16; + + if( channels > 3 || channels < 1 ) + return false; + + jas_image_cmptparm_t component_info[3]; + for( int i = 0; i < channels; i++ ) + { + component_info[i].tlx = 0; + component_info[i].tly = 0; + component_info[i].hstep = 1; + component_info[i].vstep = 1; + component_info[i].width = width; + component_info[i].height = height; + component_info[i].prec = depth; + component_info[i].sgnd = 0; + } + jas_image_t *img = jas_image_create( channels, component_info, (channels == 1) ? JAS_CLRSPC_SGRAY : JAS_CLRSPC_SRGB ); + if( !img ) + return false; + + if(channels == 1) + jas_image_setcmpttype( img, 0, JAS_IMAGE_CT_GRAY_Y ); + else + { + jas_image_setcmpttype( img, 0, JAS_IMAGE_CT_RGB_B ); + jas_image_setcmpttype( img, 1, JAS_IMAGE_CT_RGB_G ); + jas_image_setcmpttype( img, 2, JAS_IMAGE_CT_RGB_R ); + } + + bool result; + if( depth == 8 ) + result = writeComponent8u( img, _img ); + else + result = writeComponent16u( img, _img ); + if( result ) + { + jas_stream_t *stream = jas_stream_fopen( m_filename.c_str(), "wb" ); + if( stream ) + { + result = !jas_image_encode( img, stream, jas_image_strtofmt( (char*)"jp2" ), (char*)"" ); + + jas_stream_close( stream ); + } + + } + jas_image_destroy( img ); + + return result; +} + + +bool Jpeg2KEncoder::writeComponent8u( void *__img, const Mat& _img ) +{ + jas_image_t* img = (jas_image_t*)__img; + int w = _img.cols, h = _img.rows, ncmpts = _img.channels(); + jas_matrix_t *row = jas_matrix_create( 1, w ); + if(!row) + return false; + + for( int y = 0; y < h; y++ ) + { + uchar* data = _img.data + _img.step*y; + for( int i = 0; i < ncmpts; i++ ) + { + for( int x = 0; x < w; x++) + jas_matrix_setv( row, x, data[x * ncmpts + i] ); + jas_image_writecmpt( img, i, 0, y, w, 1, row ); + } + } + + jas_matrix_destroy( row ); + return true; +} + + +bool Jpeg2KEncoder::writeComponent16u( void *__img, const Mat& _img ) +{ + jas_image_t* img = (jas_image_t*)__img; + int w = _img.cols, h = _img.rows, ncmpts = _img.channels(); + jas_matrix_t *row = jas_matrix_create( 1, w ); + if(!row) + return false; + + for( int y = 0; y < h; y++ ) + { + uchar* data = _img.data + _img.step*y; + for( int i = 0; i < ncmpts; i++ ) + { + for( int x = 0; x < w; x++) + jas_matrix_setv( row, x, data[x * ncmpts + i] ); + jas_image_writecmpt( img, i, 0, y, w, 1, row ); + } + } + + jas_matrix_destroy( row ); + + return true; +} + +} + +#endif + +/* End of file. */ diff --git a/highgui/src/grfmt_jpeg2000.hpp b/highgui/src/grfmt_jpeg2000.hpp new file mode 100644 index 0000000..636a8c1 --- /dev/null +++ b/highgui/src/grfmt_jpeg2000.hpp @@ -0,0 +1,95 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _GRFMT_JASPER_H_ +#define _GRFMT_JASPER_H_ + +#ifdef HAVE_JASPER + +#include "grfmt_base.hpp" + +namespace cv +{ + +class Jpeg2KDecoder : public BaseImageDecoder +{ +public: + + Jpeg2KDecoder(); + virtual ~Jpeg2KDecoder(); + + bool readData( Mat& img ); + bool readHeader(); + void close(); + ImageDecoder newDecoder() const; + +protected: + bool readComponent8u( uchar *data, void *buffer, int step, int cmpt, + int maxval, int offset, int ncmpts ); + bool readComponent16u( unsigned short *data, void *buffer, int step, int cmpt, + int maxval, int offset, int ncmpts ); + + void *m_stream; + void *m_image; +}; + + +class Jpeg2KEncoder : public BaseImageEncoder +{ +public: + Jpeg2KEncoder(); + virtual ~Jpeg2KEncoder(); + + bool isFormatSupported( int depth ) const; + bool write( const Mat& img, const vector& params ); + ImageEncoder newEncoder() const; + +protected: + bool writeComponent8u( void *img, const Mat& _img ); + bool writeComponent16u( void *img, const Mat& _img ); +}; + +} + +#endif + +#endif/*_GRFMT_JASPER_H_*/ diff --git a/highgui/src/grfmt_png.cpp b/highgui/src/grfmt_png.cpp new file mode 100644 index 0000000..8f9df83 --- /dev/null +++ b/highgui/src/grfmt_png.cpp @@ -0,0 +1,427 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#ifdef HAVE_PNG + +/****************************************************************************************\ + This part of the file implements PNG codec on base of libpng library, + in particular, this code is based on example.c from libpng + (see otherlibs/_graphics/readme.txt for copyright notice) + and png2bmp sample from libpng distribution (Copyright (C) 1999-2001 MIYASAKA Masaru) +\****************************************************************************************/ + +#undef HAVE_UNISTD_H //to avoid redefinition +#ifndef _LFS64_LARGEFILE +# define _LFS64_LARGEFILE 0 +#endif +#ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 0 +#endif + +#ifdef HAVE_LIBPNG_PNG_H +#include +#else +#include +#endif +#include + +#include "grfmt_png.hpp" + +#if defined _MSC_VER && _MSC_VER >= 1200 + // interaction between '_setjmp' and C++ object destruction is non-portable + #pragma warning( disable: 4611 ) +#endif + +namespace cv +{ + +/////////////////////// PngDecoder /////////////////// + +PngDecoder::PngDecoder() +{ + m_signature = "\x89\x50\x4e\x47\xd\xa\x1a\xa"; + m_color_type = 0; + m_png_ptr = 0; + m_info_ptr = m_end_info = 0; + m_f = 0; + m_buf_supported = true; + m_buf_pos = 0; +} + + +PngDecoder::~PngDecoder() +{ + close(); +} + +ImageDecoder PngDecoder::newDecoder() const +{ + return new PngDecoder; +} + +void PngDecoder::close() +{ + if( m_f ) + { + fclose( m_f ); + m_f = 0; + } + + if( m_png_ptr ) + { + png_structp png_ptr = (png_structp)m_png_ptr; + png_infop info_ptr = (png_infop)m_info_ptr; + png_infop end_info = (png_infop)m_end_info; + png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); + m_png_ptr = m_info_ptr = m_end_info = 0; + } +} + + +void PngDecoder::readDataFromBuf( void* _png_ptr, uchar* dst, size_t size ) +{ + png_structp png_ptr = (png_structp)_png_ptr; + PngDecoder* decoder = (PngDecoder*)(png_get_io_ptr(png_ptr)); + CV_Assert( decoder ); + const Mat& buf = decoder->m_buf; + if( decoder->m_buf_pos + size > buf.cols*buf.rows*buf.elemSize() ) + { + png_error(png_ptr, "PNG input buffer is incomplete"); + return; + } + memcpy( dst, &decoder->m_buf.data[decoder->m_buf_pos], size ); + decoder->m_buf_pos += size; +} + +bool PngDecoder::readHeader() +{ + bool result = false; + close(); + + png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); + + if( png_ptr ) + { + png_infop info_ptr = png_create_info_struct( png_ptr ); + png_infop end_info = png_create_info_struct( png_ptr ); + + m_png_ptr = png_ptr; + m_info_ptr = info_ptr; + m_end_info = end_info; + m_buf_pos = 0; + + if( info_ptr && end_info ) + { + if( setjmp( png_jmpbuf( png_ptr ) ) == 0 ) + { + if( !m_buf.empty() ) + png_set_read_fn(png_ptr, this, (png_rw_ptr)readDataFromBuf ); + else + { + m_f = fopen( m_filename.c_str(), "rb" ); + if( m_f ) + png_init_io( png_ptr, m_f ); + } + + if( !m_buf.empty() || m_f ) + { + png_uint_32 wdth, hght; + int bit_depth, color_type; + + png_read_info( png_ptr, info_ptr ); + + png_get_IHDR( png_ptr, info_ptr, &wdth, &hght, + &bit_depth, &color_type, 0, 0, 0 ); + + m_width = (int)wdth; + m_height = (int)hght; + m_color_type = color_type; + m_bit_depth = bit_depth; + + if( bit_depth <= 8 || bit_depth == 16 ) + { + switch(color_type) + { + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_PALETTE: + m_type = CV_8UC3; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + m_type = CV_8UC4; + break; + default: + m_type = CV_8UC1; + } + if( bit_depth == 16 ) + m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type)); + result = true; + } + } + } + } + } + + if( !result ) + close(); + + return result; +} + + +bool PngDecoder::readData( Mat& img ) +{ + bool result = false; + AutoBuffer _buffer(m_height); + uchar** buffer = _buffer; + int color = img.channels() > 1; + uchar* data = img.data; + int step = (int)img.step; + + if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height ) + { + png_structp png_ptr = (png_structp)m_png_ptr; + png_infop info_ptr = (png_infop)m_info_ptr; + png_infop end_info = (png_infop)m_end_info; + + if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 ) + { + int y; + + if( img.depth() == CV_8U && m_bit_depth == 16 ) + png_set_strip_16( png_ptr ); + else if( !isBigEndian() ) + png_set_swap( png_ptr ); + + if(img.channels() < 4) + { + /* observation: png_read_image() writes 400 bytes beyond + * end of data when reading a 400x118 color png + * "mpplus_sand.png". OpenCV crashes even with demo + * programs. Looking at the loaded image I'd say we get 4 + * bytes per pixel instead of 3 bytes per pixel. Test + * indicate that it is a good idea to always ask for + * stripping alpha.. 18.11.2004 Axel Walthelm + */ + png_set_strip_alpha( png_ptr ); + } + + if( m_color_type == PNG_COLOR_TYPE_PALETTE ) + png_set_palette_to_rgb( png_ptr ); + + if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 ) +#if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \ + (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18) + png_set_expand_gray_1_2_4_to_8( png_ptr ); +#else + png_set_gray_1_2_4_to_8( png_ptr ); +#endif + + if( CV_MAT_CN(m_type) > 1 && color ) + png_set_bgr( png_ptr ); // convert RGB to BGR + else if( color ) + png_set_gray_to_rgb( png_ptr ); // Gray->RGB + else + png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray + + png_read_update_info( png_ptr, info_ptr ); + + for( y = 0; y < m_height; y++ ) + buffer[y] = data + y*step; + + png_read_image( png_ptr, buffer ); + png_read_end( png_ptr, end_info ); + + result = true; + } + } + + close(); + return result; +} + + +/////////////////////// PngEncoder /////////////////// + + +PngEncoder::PngEncoder() +{ + m_description = "Portable Network Graphics files (*.png)"; + m_buf_supported = true; +} + + +PngEncoder::~PngEncoder() +{ +} + + +bool PngEncoder::isFormatSupported( int depth ) const +{ + return depth == CV_8U || depth == CV_16U; +} + +ImageEncoder PngEncoder::newEncoder() const +{ + return new PngEncoder; +} + + +void PngEncoder::writeDataToBuf(void* _png_ptr, uchar* src, size_t size) +{ + if( size == 0 ) + return; + png_structp png_ptr = (png_structp)_png_ptr; + PngEncoder* encoder = (PngEncoder*)(png_get_io_ptr(png_ptr)); + CV_Assert( encoder && encoder->m_buf ); + size_t cursz = encoder->m_buf->size(); + encoder->m_buf->resize(cursz + size); + memcpy( &(*encoder->m_buf)[cursz], src, size ); +} + + +void PngEncoder::flushBuf(void*) +{ +} + +bool PngEncoder::write( const Mat& img, const vector& params ) +{ + png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); + png_infop info_ptr = 0; + FILE* f = 0; + int y, width = img.cols, height = img.rows; + int depth = img.depth(), channels = img.channels(); + bool result = false; + AutoBuffer buffer; + + if( depth != CV_8U && depth != CV_16U ) + return false; + + if( png_ptr ) + { + info_ptr = png_create_info_struct( png_ptr ); + + if( info_ptr ) + { + if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 ) + { + if( m_buf ) + { + png_set_write_fn(png_ptr, this, + (png_rw_ptr)writeDataToBuf, (png_flush_ptr)flushBuf); + } + else + { + f = fopen( m_filename.c_str(), "wb" ); + if( f ) + png_init_io( png_ptr, f ); + } + + int compression_level = 0; + int compression_strategy = Z_RLE; + + for( size_t i = 0; i < params.size(); i += 2 ) + { + if( params[i] == CV_IMWRITE_PNG_COMPRESSION ) + { + compression_level = params[i+1]; + compression_level = MIN(MAX(compression_level, 0), MAX_MEM_LEVEL); + } + if( params[i] == CV_IMWRITE_PNG_STRATEGY ) + { + compression_strategy = params[i+1]; + compression_strategy = MIN(MAX(compression_strategy, 0), Z_FIXED); + } + } + + if( m_buf || f ) + { + if( compression_level > 0 ) + { + png_set_compression_mem_level( png_ptr, compression_level ); + } + else + { + // tune parameters for speed + // (see http://wiki.linuxquestions.org/wiki/Libpng) + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB); + png_set_compression_level(png_ptr, Z_BEST_SPEED); + } + png_set_compression_strategy(png_ptr, compression_strategy); + + png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? 8 : 16, + channels == 1 ? PNG_COLOR_TYPE_GRAY : + channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT ); + + png_write_info( png_ptr, info_ptr ); + + png_set_bgr( png_ptr ); + if( !isBigEndian() ) + png_set_swap( png_ptr ); + + buffer.allocate(height); + for( y = 0; y < height; y++ ) + buffer[y] = img.data + y*img.step; + + png_write_image( png_ptr, buffer ); + png_write_end( png_ptr, info_ptr ); + + result = true; + } + } + } + } + + png_destroy_write_struct( &png_ptr, &info_ptr ); + if(f) fclose( f ); + + return result; +} + +} + +#endif + +/* End of file. */ diff --git a/highgui/src/grfmt_png.hpp b/highgui/src/grfmt_png.hpp new file mode 100644 index 0000000..91d4496 --- /dev/null +++ b/highgui/src/grfmt_png.hpp @@ -0,0 +1,101 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _GRFMT_PNG_H_ +#define _GRFMT_PNG_H_ + +#ifdef HAVE_PNG + +#include "grfmt_base.hpp" +#include "bitstrm.hpp" + +namespace cv +{ + +class PngDecoder : public BaseImageDecoder +{ +public: + + PngDecoder(); + virtual ~PngDecoder(); + + bool readData( Mat& img ); + bool readHeader(); + void close(); + + ImageDecoder newDecoder() const; + +protected: + + static void readDataFromBuf(void* png_ptr, uchar* dst, size_t size); + + int m_bit_depth; + void* m_png_ptr; // pointer to decompression structure + void* m_info_ptr; // pointer to image information structure + void* m_end_info; // pointer to one more image information structure + FILE* m_f; + int m_color_type; + size_t m_buf_pos; +}; + + +class PngEncoder : public BaseImageEncoder +{ +public: + PngEncoder(); + virtual ~PngEncoder(); + + bool isFormatSupported( int depth ) const; + bool write( const Mat& img, const vector& params ); + + ImageEncoder newEncoder() const; + +protected: + static void writeDataToBuf(void* png_ptr, uchar* src, size_t size); + static void flushBuf(void* png_ptr); +}; + +} + +#endif + +#endif/*_GRFMT_PNG_H_*/ diff --git a/highgui/src/grfmt_pxm.cpp b/highgui/src/grfmt_pxm.cpp new file mode 100644 index 0000000..33837b1 --- /dev/null +++ b/highgui/src/grfmt_pxm.cpp @@ -0,0 +1,513 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include "utils.hpp" +#include "grfmt_pxm.hpp" + +namespace cv +{ + +///////////////////////// P?M reader ////////////////////////////// + +static int ReadNumber( RLByteStream& strm, int maxdigits ) +{ + int code; + int val = 0; + int digits = 0; + + code = strm.getByte(); + + if( !isdigit(code)) + { + do + { + if( code == '#' ) + { + do + { + code = strm.getByte(); + } + while( code != '\n' && code != '\r' ); + } + + code = strm.getByte(); + + while( isspace(code)) + code = strm.getByte(); + } + while( !isdigit( code )); + } + + do + { + val = val*10 + code - '0'; + if( ++digits >= maxdigits ) break; + code = strm.getByte(); + } + while( isdigit(code)); + + return val; +} + + +PxMDecoder::PxMDecoder() +{ + m_offset = -1; + m_buf_supported = true; +} + + +PxMDecoder::~PxMDecoder() +{ + close(); +} + +size_t PxMDecoder::signatureLength() const +{ + return 3; +} + +bool PxMDecoder::checkSignature( const string& signature ) const +{ + return signature.size() >= 3 && signature[0] == 'P' && + '1' <= signature[1] && signature[1] <= '6' && + isspace(signature[2]); +} + +ImageDecoder PxMDecoder::newDecoder() const +{ + return new PxMDecoder; +} + +void PxMDecoder::close() +{ + m_strm.close(); +} + + +bool PxMDecoder::readHeader() +{ + bool result = false; + + if( !m_buf.empty() ) + { + if( !m_strm.open(m_buf) ) + return false; + } + else if( !m_strm.open( m_filename )) + return false; + + try + { + int code = m_strm.getByte(); + if( code != 'P' ) + throw RBS_BAD_HEADER; + + code = m_strm.getByte(); + switch( code ) + { + case '1': case '4': m_bpp = 1; break; + case '2': case '5': m_bpp = 8; break; + case '3': case '6': m_bpp = 24; break; + default: throw RBS_BAD_HEADER; + } + + m_binary = code >= '4'; + m_type = m_bpp > 8 ? CV_8UC3 : CV_8UC1; + + m_width = ReadNumber( m_strm, INT_MAX ); + m_height = ReadNumber( m_strm, INT_MAX ); + + m_maxval = m_bpp == 1 ? 1 : ReadNumber( m_strm, INT_MAX ); + if( m_maxval > 65535 ) + throw RBS_BAD_HEADER; + + //if( m_maxval > 255 ) m_binary = false; nonsense + if( m_maxval > 255 ) + m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type)); + + if( m_width > 0 && m_height > 0 && m_maxval > 0 && m_maxval < (1 << 16)) + { + m_offset = m_strm.getPos(); + result = true; + } + } + catch(...) + { + } + + if( !result ) + { + m_offset = -1; + m_width = m_height = -1; + m_strm.close(); + } + return result; +} + + +bool PxMDecoder::readData( Mat& img ) +{ + int color = img.channels() > 1; + uchar* data = img.data; + int step = (int)img.step; + PaletteEntry palette[256]; + bool result = false; + int bit_depth = CV_ELEM_SIZE1(m_type)*8; + int src_pitch = (m_width*m_bpp*bit_depth/8 + 7)/8; + int nch = CV_MAT_CN(m_type); + int width3 = m_width*nch; + int i, x, y; + + if( m_offset < 0 || !m_strm.isOpened()) + return false; + + AutoBuffer _src(src_pitch + 32); + uchar* src = _src; + AutoBuffer _gray_palette; + uchar* gray_palette = _gray_palette; + + // create LUT for converting colors + if( bit_depth == 8 ) + { + _gray_palette.allocate(m_maxval + 1); + gray_palette = _gray_palette; + + for( i = 0; i <= m_maxval; i++ ) + gray_palette[i] = (uchar)((i*255/m_maxval)^(m_bpp == 1 ? 255 : 0)); + + FillGrayPalette( palette, m_bpp==1 ? 1 : 8 , m_bpp == 1 ); + } + + try + { + m_strm.setPos( m_offset ); + + switch( m_bpp ) + { + ////////////////////////// 1 BPP ///////////////////////// + case 1: + if( !m_binary ) + { + for( y = 0; y < m_height; y++, data += step ) + { + for( x = 0; x < m_width; x++ ) + src[x] = ReadNumber( m_strm, 1 ) != 0; + + if( color ) + FillColorRow8( data, src, m_width, palette ); + else + FillGrayRow8( data, src, m_width, gray_palette ); + } + } + else + { + for( y = 0; y < m_height; y++, data += step ) + { + m_strm.getBytes( src, src_pitch ); + + if( color ) + FillColorRow1( data, src, m_width, palette ); + else + FillGrayRow1( data, src, m_width, gray_palette ); + } + } + result = true; + break; + + ////////////////////////// 8 BPP ///////////////////////// + case 8: + case 24: + for( y = 0; y < m_height; y++, data += step ) + { + if( !m_binary ) + { + for( x = 0; x < width3; x++ ) + { + int code = ReadNumber( m_strm, INT_MAX ); + if( (unsigned)code > (unsigned)m_maxval ) code = m_maxval; + if( bit_depth == 8 ) + src[x] = gray_palette[code]; + else + ((ushort *)src)[x] = (ushort)code; + } + } + else + { + m_strm.getBytes( src, src_pitch ); + if( bit_depth == 16 && !isBigEndian() ) + { + for( x = 0; x < width3; x++ ) + { + uchar v = src[x * 2]; + src[x * 2] = src[x * 2 + 1]; + src[x * 2 + 1] = v; + } + } + } + + if( img.depth() == CV_8U && bit_depth == 16 ) + { + for( x = 0; x < width3; x++ ) + { + int v = ((ushort *)src)[x]; + src[x] = (uchar)(v >> 8); + } + } + + if( m_bpp == 8 ) // image has one channel + { + if( color ) + { + if( img.depth() == CV_8U ) { + uchar *d = data, *s = src, *end = src + m_width; + for( ; s < end; d += 3, s++) + d[0] = d[1] = d[2] = *s; + } else { + ushort *d = (ushort *)data, *s = (ushort *)src, *end = ((ushort *)src) + m_width; + for( ; s < end; s++, d += 3) + d[0] = d[1] = d[2] = *s; + } + } + else + memcpy( data, src, m_width*(bit_depth/8) ); + } + else + { + if( color ) + { + if( img.depth() == CV_8U ) + icvCvt_RGB2BGR_8u_C3R( src, 0, data, 0, cvSize(m_width,1) ); + else + icvCvt_RGB2BGR_16u_C3R( (ushort *)src, 0, (ushort *)data, 0, cvSize(m_width,1) ); + } + else if( img.depth() == CV_8U ) + icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1), 2 ); + else + icvCvt_BGRA2Gray_16u_CnC1R( (ushort *)src, 0, (ushort *)data, 0, cvSize(m_width,1), 3, 2 ); + } + } + result = true; + break; + default: + assert(0); + } + } + catch(...) + { + } + + return result; +} + + +////////////////////////////////////////////////////////////////////////////////////////// + +PxMEncoder::PxMEncoder() +{ + m_description = "Portable image format (*.pbm;*.pgm;*.ppm;*.pxm;*.pnm)"; + m_buf_supported = true; +} + + +PxMEncoder::~PxMEncoder() +{ +} + + +ImageEncoder PxMEncoder::newEncoder() const +{ + return new PxMEncoder; +} + + +bool PxMEncoder::isFormatSupported( int depth ) const +{ + return depth == CV_8U || depth == CV_16U; +} + + +bool PxMEncoder::write( const Mat& img, const vector& params ) +{ + bool isBinary = true; + + int width = img.cols, height = img.rows; + int _channels = img.channels(), depth = (int)img.elemSize1()*8; + int channels = _channels > 1 ? 3 : 1; + int fileStep = width*(int)img.elemSize(); + int x, y; + + for( size_t i = 0; i < params.size(); i += 2 ) + if( params[i] == CV_IMWRITE_PXM_BINARY ) + isBinary = params[i+1] != 0; + + WLByteStream strm; + + if( m_buf ) + { + if( !strm.open(*m_buf) ) + return false; + int t = CV_MAKETYPE(img.depth(), channels); + m_buf->reserve( alignSize(256 + (isBinary ? fileStep*height : + ((t == CV_8UC1 ? 4 : t == CV_8UC3 ? 4*3+2 : + t == CV_16UC1 ? 6 : 6*3+2)*width+1)*height), 256)); + } + else if( !strm.open(m_filename) ) + return false; + + int lineLength; + int bufferSize = 128; // buffer that should fit a header + + if( isBinary ) + lineLength = width * (int)img.elemSize(); + else + lineLength = (6 * channels + (channels > 1 ? 2 : 0)) * width + 32; + + if( bufferSize < lineLength ) + bufferSize = lineLength; + + AutoBuffer _buffer(bufferSize); + char* buffer = _buffer; + + // write header; + sprintf( buffer, "P%c\n%d %d\n%d\n", + '2' + (channels > 1 ? 1 : 0) + (isBinary ? 3 : 0), + width, height, (1 << depth) - 1 ); + + strm.putBytes( buffer, (int)strlen(buffer) ); + + for( y = 0; y < height; y++ ) + { + uchar* data = img.data + img.step*y; + if( isBinary ) + { + if( _channels == 3 ) + { + if( depth == 8 ) + icvCvt_BGR2RGB_8u_C3R( (uchar*)data, 0, + (uchar*)buffer, 0, cvSize(width,1) ); + else + icvCvt_BGR2RGB_16u_C3R( (ushort*)data, 0, + (ushort*)buffer, 0, cvSize(width,1) ); + } + + // swap endianness if necessary + if( depth == 16 && !isBigEndian() ) + { + if( _channels == 1 ) + memcpy( buffer, data, fileStep ); + for( x = 0; x < width*channels*2; x += 2 ) + { + uchar v = buffer[x]; + buffer[x] = buffer[x + 1]; + buffer[x + 1] = v; + } + } + strm.putBytes( (channels > 1 || depth > 8) ? buffer : (char*)data, fileStep ); + } + else + { + char* ptr = buffer; + + if( channels > 1 ) + { + if( depth == 8 ) + { + for( x = 0; x < width*channels; x += channels ) + { + sprintf( ptr, "% 4d", data[x + 2] ); + ptr += 4; + sprintf( ptr, "% 4d", data[x + 1] ); + ptr += 4; + sprintf( ptr, "% 4d", data[x] ); + ptr += 4; + *ptr++ = ' '; + *ptr++ = ' '; + } + } + else + { + for( x = 0; x < width*channels; x += channels ) + { + sprintf( ptr, "% 6d", ((ushort *)data)[x + 2] ); + ptr += 6; + sprintf( ptr, "% 6d", ((ushort *)data)[x + 1] ); + ptr += 6; + sprintf( ptr, "% 6d", ((ushort *)data)[x] ); + ptr += 6; + *ptr++ = ' '; + *ptr++ = ' '; + } + } + } + else + { + if( depth == 8 ) + { + for( x = 0; x < width; x++ ) + { + sprintf( ptr, "% 4d", data[x] ); + ptr += 4; + } + } + else + { + for( x = 0; x < width; x++ ) + { + sprintf( ptr, "% 6d", ((ushort *)data)[x] ); + ptr += 6; + } + } + } + + *ptr++ = '\n'; + + strm.putBytes( buffer, (int)(ptr - buffer) ); + } + } + + strm.close(); + return true; +} + +} diff --git a/highgui/src/grfmt_pxm.hpp b/highgui/src/grfmt_pxm.hpp new file mode 100644 index 0000000..07efa44 --- /dev/null +++ b/highgui/src/grfmt_pxm.hpp @@ -0,0 +1,92 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _GRFMT_PxM_H_ +#define _GRFMT_PxM_H_ + +#include "grfmt_base.hpp" +#include "bitstrm.hpp" + +namespace cv +{ + +class PxMDecoder : public BaseImageDecoder +{ +public: + + PxMDecoder(); + virtual ~PxMDecoder(); + + bool readData( Mat& img ); + bool readHeader(); + void close(); + + size_t signatureLength() const; + bool checkSignature( const string& signature ) const; + ImageDecoder newDecoder() const; + +protected: + + RLByteStream m_strm; + PaletteEntry m_palette[256]; + int m_bpp; + int m_offset; + bool m_binary; + int m_maxval; +}; + + +class PxMEncoder : public BaseImageEncoder +{ +public: + PxMEncoder(); + virtual ~PxMEncoder(); + + bool isFormatSupported( int depth ) const; + bool write( const Mat& img, const vector& params ); + + ImageEncoder newEncoder() const; +}; + +} + +#endif/*_GRFMT_PxM_H_*/ diff --git a/highgui/src/grfmt_sunras.cpp b/highgui/src/grfmt_sunras.cpp new file mode 100644 index 0000000..19f8db4 --- /dev/null +++ b/highgui/src/grfmt_sunras.cpp @@ -0,0 +1,425 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include "grfmt_sunras.hpp" + +namespace cv +{ + +static const char* fmtSignSunRas = "\x59\xA6\x6A\x95"; + +/************************ Sun Raster reader *****************************/ + +SunRasterDecoder::SunRasterDecoder() +{ + m_offset = -1; + m_signature = fmtSignSunRas; +} + + +SunRasterDecoder::~SunRasterDecoder() +{ +} + +ImageDecoder SunRasterDecoder::newDecoder() const +{ + return new SunRasterDecoder; +} + +void SunRasterDecoder::close() +{ + m_strm.close(); +} + + +bool SunRasterDecoder::readHeader() +{ + bool result = false; + + if( !m_strm.open( m_filename )) return false; + + try + { + m_strm.skip( 4 ); + m_width = m_strm.getDWord(); + m_height = m_strm.getDWord(); + m_bpp = m_strm.getDWord(); + int palSize = 3*(1 << m_bpp); + + m_strm.skip( 4 ); + m_encoding = (SunRasType)m_strm.getDWord(); + m_maptype = (SunRasMapType)m_strm.getDWord(); + m_maplength = m_strm.getDWord(); + + if( m_width > 0 && m_height > 0 && + (m_bpp == 1 || m_bpp == 8 || m_bpp == 24 || m_bpp == 32) && + (m_encoding == RAS_OLD || m_encoding == RAS_STANDARD || + (m_type == RAS_BYTE_ENCODED && m_bpp == 8) || m_type == RAS_FORMAT_RGB) && + ((m_maptype == RMT_NONE && m_maplength == 0) || + (m_maptype == RMT_EQUAL_RGB && m_maplength <= palSize && m_bpp <= 8))) + { + memset( m_palette, 0, sizeof(m_palette)); + + if( m_maplength != 0 ) + { + uchar buffer[256*3]; + + if( m_strm.getBytes( buffer, m_maplength ) == m_maplength ) + { + int i; + palSize = m_maplength/3; + + for( i = 0; i < palSize; i++ ) + { + m_palette[i].b = buffer[i + 2*palSize]; + m_palette[i].g = buffer[i + palSize]; + m_palette[i].r = buffer[i]; + m_palette[i].a = 0; + } + + m_type = IsColorPalette( m_palette, m_bpp ) ? CV_8UC3 : CV_8UC1; + m_offset = m_strm.getPos(); + + assert( m_offset == 32 + m_maplength ); + result = true; + } + } + else + { + m_type = m_bpp > 8 ? CV_8UC3 : CV_8UC1; + + if( CV_MAT_CN(m_type) == 1 ) + FillGrayPalette( m_palette, m_bpp ); + + m_offset = m_strm.getPos(); + + assert( m_offset == 32 + m_maplength ); + result = true; + } + } + } + catch(...) + { + } + + if( !result ) + { + m_offset = -1; + m_width = m_height = -1; + m_strm.close(); + } + return result; +} + + +bool SunRasterDecoder::readData( Mat& img ) +{ + int color = img.channels() > 1; + uchar* data = img.data; + int step = (int)img.step; + uchar gray_palette[256]; + bool result = false; + int src_pitch = ((m_width*m_bpp + 7)/8 + 1) & -2; + int nch = color ? 3 : 1; + int width3 = m_width*nch; + int y; + + if( m_offset < 0 || !m_strm.isOpened()) + return false; + + AutoBuffer _src(src_pitch + 32); + uchar* src = _src; + AutoBuffer _bgr(m_width*3 + 32); + uchar* bgr = _bgr; + + if( !color && m_maptype == RMT_EQUAL_RGB ) + CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp ); + + try + { + m_strm.setPos( m_offset ); + + switch( m_bpp ) + { + /************************* 1 BPP ************************/ + case 1: + if( m_type != RAS_BYTE_ENCODED ) + { + for( y = 0; y < m_height; y++, data += step ) + { + m_strm.getBytes( src, src_pitch ); + if( color ) + FillColorRow1( data, src, m_width, m_palette ); + else + FillGrayRow1( data, src, m_width, gray_palette ); + } + result = true; + } + else + { + uchar* line_end = src + (m_width*m_bpp + 7)/8; + uchar* tsrc = src; + y = 0; + + for(;;) + { + int max_count = (int)(line_end - tsrc); + int code = 0, len = 0, len1 = 0; + + do + { + code = m_strm.getByte(); + if( code == 0x80 ) + { + len = m_strm.getByte(); + if( len != 0 ) break; + } + tsrc[len1] = (uchar)code; + } + while( ++len1 < max_count ); + + tsrc += len1; + + if( len > 0 ) // encoded mode + { + ++len; + code = m_strm.getByte(); + if( len > line_end - tsrc ) + { + assert(0); + goto bad_decoding_1bpp; + } + + memset( tsrc, code, len ); + tsrc += len; + } + + if( tsrc >= line_end ) + { + tsrc = src; + if( color ) + FillColorRow1( data, src, m_width, m_palette ); + else + FillGrayRow1( data, src, m_width, gray_palette ); + data += step; + if( ++y >= m_height ) break; + } + } + result = true; +bad_decoding_1bpp: + ; + } + break; + /************************* 8 BPP ************************/ + case 8: + if( m_type != RAS_BYTE_ENCODED ) + { + for( y = 0; y < m_height; y++, data += step ) + { + m_strm.getBytes( src, src_pitch ); + if( color ) + FillColorRow8( data, src, m_width, m_palette ); + else + FillGrayRow8( data, src, m_width, gray_palette ); + } + result = true; + } + else // RLE-encoded + { + uchar* line_end = data + width3; + y = 0; + + for(;;) + { + int max_count = (int)(line_end - data); + int code = 0, len = 0, len1; + uchar* tsrc = src; + + do + { + code = m_strm.getByte(); + if( code == 0x80 ) + { + len = m_strm.getByte(); + if( len != 0 ) break; + } + *tsrc++ = (uchar)code; + } + while( (max_count -= nch) > 0 ); + + len1 = (int)(tsrc - src); + + if( len1 > 0 ) + { + if( color ) + FillColorRow8( data, src, len1, m_palette ); + else + FillGrayRow8( data, src, len1, gray_palette ); + data += len1*nch; + } + + if( len > 0 ) // encoded mode + { + len = (len + 1)*nch; + code = m_strm.getByte(); + + if( color ) + data = FillUniColor( data, line_end, step, width3, + y, m_height, len, + m_palette[code] ); + else + data = FillUniGray( data, line_end, step, width3, + y, m_height, len, + gray_palette[code] ); + if( y >= m_height ) + break; + } + + if( data == line_end ) + { + if( m_strm.getByte() != 0 ) + goto bad_decoding_end; + line_end += step; + data = line_end - width3; + if( ++y >= m_height ) break; + } + } + + result = true; +bad_decoding_end: + ; + } + break; + /************************* 24 BPP ************************/ + case 24: + for( y = 0; y < m_height; y++, data += step ) + { + m_strm.getBytes( color ? data : bgr, src_pitch ); + + if( color ) + { + if( m_type == RAS_FORMAT_RGB ) + icvCvt_RGB2BGR_8u_C3R( data, 0, data, 0, cvSize(m_width,1) ); + } + else + { + icvCvt_BGR2Gray_8u_C3C1R( bgr, 0, data, 0, cvSize(m_width,1), + m_type == RAS_FORMAT_RGB ? 2 : 0 ); + } + } + result = true; + break; + /************************* 32 BPP ************************/ + case 32: + for( y = 0; y < m_height; y++, data += step ) + { + /* hack: a0 b0 g0 r0 a1 b1 g1 r1 ... are written to src + 3, + so when we look at src + 4, we see b0 g0 r0 x b1 g1 g1 x ... */ + m_strm.getBytes( src + 3, src_pitch ); + + if( color ) + icvCvt_BGRA2BGR_8u_C4C3R( src + 4, 0, data, 0, cvSize(m_width,1), + m_type == RAS_FORMAT_RGB ? 2 : 0 ); + else + icvCvt_BGRA2Gray_8u_C4C1R( src + 4, 0, data, 0, cvSize(m_width,1), + m_type == RAS_FORMAT_RGB ? 2 : 0 ); + } + result = true; + break; + default: + assert(0); + } + } + catch( ... ) + { + } + + return result; +} + + +////////////////////////////////////////////////////////////////////////////////////////// + +SunRasterEncoder::SunRasterEncoder() +{ + m_description = "Sun raster files (*.sr;*.ras)"; +} + + +ImageEncoder SunRasterEncoder::newEncoder() const +{ + return new SunRasterEncoder; +} + +SunRasterEncoder::~SunRasterEncoder() +{ +} + +bool SunRasterEncoder::write( const Mat& img, const vector& ) +{ + bool result = false; + int y, width = img.cols, height = img.rows, channels = img.channels(); + int fileStep = (width*channels + 1) & -2; + WMByteStream strm; + + if( strm.open(m_filename) ) + { + strm.putBytes( fmtSignSunRas, (int)strlen(fmtSignSunRas) ); + strm.putDWord( width ); + strm.putDWord( height ); + strm.putDWord( channels*8 ); + strm.putDWord( fileStep*height ); + strm.putDWord( RAS_STANDARD ); + strm.putDWord( RMT_NONE ); + strm.putDWord( 0 ); + + for( y = 0; y < height; y++ ) + strm.putBytes( img.data + img.step*y, fileStep ); + + strm.close(); + result = true; + } + return result; +} + +} diff --git a/highgui/src/grfmt_sunras.hpp b/highgui/src/grfmt_sunras.hpp new file mode 100644 index 0000000..f9e6cc3 --- /dev/null +++ b/highgui/src/grfmt_sunras.hpp @@ -0,0 +1,105 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _GRFMT_SUNRAS_H_ +#define _GRFMT_SUNRAS_H_ + +#include "grfmt_base.hpp" + +namespace cv +{ + +enum SunRasType +{ + RAS_OLD = 0, + RAS_STANDARD = 1, + RAS_BYTE_ENCODED = 2, /* RLE encoded */ + RAS_FORMAT_RGB = 3 /* RGB instead of BGR */ +}; + +enum SunRasMapType +{ + RMT_NONE = 0, /* direct color encoding */ + RMT_EQUAL_RGB = 1 /* paletted image */ +}; + + +// Sun Raster Reader +class SunRasterDecoder : public BaseImageDecoder +{ +public: + + SunRasterDecoder(); + virtual ~SunRasterDecoder(); + + bool readData( Mat& img ); + bool readHeader(); + void close(); + + ImageDecoder newDecoder() const; + +protected: + + RMByteStream m_strm; + PaletteEntry m_palette[256]; + int m_bpp; + int m_offset; + SunRasType m_encoding; + SunRasMapType m_maptype; + int m_maplength; +}; + + +class SunRasterEncoder : public BaseImageEncoder +{ +public: + SunRasterEncoder(); + virtual ~SunRasterEncoder(); + + bool write( const Mat& img, const vector& params ); + + ImageEncoder newEncoder() const; +}; + +} + +#endif/*_GRFMT_SUNRAS_H_*/ diff --git a/highgui/src/grfmt_tiff.cpp b/highgui/src/grfmt_tiff.cpp new file mode 100644 index 0000000..eba54bc --- /dev/null +++ b/highgui/src/grfmt_tiff.cpp @@ -0,0 +1,718 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +/****************************************************************************************\ + A part of the file implements TIFF reader on base of libtiff library + (see otherlibs/_graphics/readme.txt for copyright notice) +\****************************************************************************************/ + +#include "precomp.hpp" +#include "grfmt_tiff.hpp" + +namespace cv +{ +static const char fmtSignTiffII[] = "II\x2a\x00"; +static const char fmtSignTiffMM[] = "MM\x00\x2a"; + +#ifdef HAVE_TIFF + +#include "tiff.h" +#include "tiffio.h" + +static int grfmt_tiff_err_handler_init = 0; +static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {} + +TiffDecoder::TiffDecoder() +{ + m_tif = 0; + if( !grfmt_tiff_err_handler_init ) + { + grfmt_tiff_err_handler_init = 1; + + TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler ); + TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler ); + } +} + + +void TiffDecoder::close() +{ + if( m_tif ) + { + TIFF* tif = (TIFF*)m_tif; + TIFFClose( tif ); + m_tif = 0; + } +} + +TiffDecoder::~TiffDecoder() +{ + close(); +} + +size_t TiffDecoder::signatureLength() const +{ + return 4; +} + +bool TiffDecoder::checkSignature( const string& signature ) const +{ + return signature.size() >= 4 && + (memcmp(signature.c_str(), fmtSignTiffII, 4) == 0 || + memcmp(signature.c_str(), fmtSignTiffMM, 4) == 0); +} + +ImageDecoder TiffDecoder::newDecoder() const +{ + return new TiffDecoder; +} + +bool TiffDecoder::readHeader() +{ + bool result = false; + + close(); + TIFF* tif = TIFFOpen( m_filename.c_str(), "rb" ); + + if( tif ) + { + int wdth = 0, hght = 0, photometric = 0; + m_tif = tif; + + if( TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &wdth ) && + TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &hght ) && + TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric )) + { + int bpp=8, ncn = photometric > 1 ? 3 : 1; + TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp ); + TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn ); + + m_width = wdth; + m_height = hght; + if( bpp > 8 && + ((photometric != 2 && photometric != 1) || + (ncn != 1 && ncn != 3 && ncn != 4))) + bpp = 8; + + switch(bpp) + { + case 8: + m_type = CV_MAKETYPE(CV_8U, photometric > 1 ? 3 : 1); + break; + case 16: + m_type = CV_MAKETYPE(CV_16U, photometric > 1 ? 3 : 1); + break; + + case 32: + m_type = CV_MAKETYPE(CV_32F, photometric > 1 ? 3 : 1); + break; + case 64: + m_type = CV_MAKETYPE(CV_64F, photometric > 1 ? 3 : 1); + break; + + default: + result = false; + } + result = true; + } + } + + if( !result ) + close(); + + return result; +} + + +bool TiffDecoder::readData( Mat& img ) +{ + bool result = false; + bool color = img.channels() > 1; + uchar* data = img.data; + int step = (int)img.step; + + if( img.depth() != CV_8U && img.depth() != CV_16U && img.depth() != CV_32F && img.depth() != CV_64F ) + return false; + + if( m_tif && m_width && m_height ) + { + TIFF* tif = (TIFF*)m_tif; + int tile_width0 = m_width, tile_height0 = 0; + int x, y, i; + int is_tiled = TIFFIsTiled(tif); + int photometric; + TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ); + int bpp = 8, ncn = photometric > 1 ? 3 : 1; + TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp ); + TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn ); + const int bitsPerByte = 8; + int dst_bpp = (int)(img.elemSize1() * bitsPerByte); + + if(dst_bpp == 8) + { + char errmsg[1024]; + if(!TIFFRGBAImageOK( tif, errmsg )) + { + close(); + return false; + } + } + + if( (!is_tiled && + TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 )) || + (is_tiled && + TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) && + TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 ))) + { + if( tile_width0 <= 0 ) + tile_width0 = m_width; + + if( tile_height0 <= 0 ) + tile_height0 = m_height; + + AutoBuffer _buffer(tile_height0*tile_width0*8); + uchar* buffer = _buffer; + ushort* buffer16 = (ushort*)buffer; + float* buffer32 = (float*)buffer; + double* buffer64 = (double*)buffer; + int tileidx = 0; + + for( y = 0; y < m_height; y += tile_height0, data += step*tile_height0 ) + { + int tile_height = tile_height0; + + if( y + tile_height > m_height ) + tile_height = m_height - y; + + for( x = 0; x < m_width; x += tile_width0, tileidx++ ) + { + int tile_width = tile_width0, ok; + + if( x + tile_width > m_width ) + tile_width = m_width - x; + + switch(dst_bpp) + { + case 8: + { + if( !is_tiled ) + ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer ); + else + ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer ); + + if( !ok ) + { + close(); + return false; + } + + for( i = 0; i < tile_height; i++ ) + if( color ) + icvCvt_BGRA2BGR_8u_C4C3R( buffer + i*tile_width*4, 0, + data + x*3 + step*(tile_height - i - 1), 0, + cvSize(tile_width,1), 2 ); + else + icvCvt_BGRA2Gray_8u_C4C1R( buffer + i*tile_width*4, 0, + data + x + step*(tile_height - i - 1), 0, + cvSize(tile_width,1), 2 ); + break; + } + + case 16: + { + if( !is_tiled ) + ok = (int)TIFFReadEncodedStrip( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0; + else + ok = (int)TIFFReadEncodedTile( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0; + + if( !ok ) + { + close(); + return false; + } + + for( i = 0; i < tile_height; i++ ) + { + if( color ) + { + if( ncn == 1 ) + { + icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width*ncn, 0, + (ushort*)(data + step*i) + x*3, 0, + cvSize(tile_width,1) ); + } + else if( ncn == 3 ) + { + icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width*ncn, 0, + (ushort*)(data + step*i) + x*3, 0, + cvSize(tile_width,1) ); + } + else + { + icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width*ncn, 0, + (ushort*)(data + step*i) + x*3, 0, + cvSize(tile_width,1), 2 ); + } + } + else + { + if( ncn == 1 ) + { + memcpy((ushort*)(data + step*i)+x, + buffer16 + i*tile_width*ncn, + tile_width*sizeof(buffer16[0])); + } + else + { + icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width*ncn, 0, + (ushort*)(data + step*i) + x, 0, + cvSize(tile_width,1), ncn, 2 ); + } + } + } + break; + } + + case 32: + case 64: + { + if( !is_tiled ) + ok = (int)TIFFReadEncodedStrip( tif, tileidx, buffer, (tsize_t)-1 ) >= 0; + else + ok = (int)TIFFReadEncodedTile( tif, tileidx, buffer, (tsize_t)-1 ) >= 0; + + if( !ok || ncn != 1 ) + { + close(); + return false; + } + + for( i = 0; i < tile_height; i++ ) + { + if(dst_bpp == 32) + { + memcpy((float*)(data + step*i)+x, + buffer32 + i*tile_width*ncn, + tile_width*sizeof(buffer32[0])); + } + else + { + memcpy((double*)(data + step*i)+x, + buffer64 + i*tile_width*ncn, + tile_width*sizeof(buffer64[0])); + } + } + + break; + } + default: + { + close(); + return false; + } + } + } + } + + result = true; + } + } + + close(); + return result; +} + +#endif + +////////////////////////////////////////////////////////////////////////////////////////// + +TiffEncoder::TiffEncoder() +{ + m_description = "TIFF Files (*.tiff;*.tif)"; +#ifdef HAVE_TIFF + m_buf_supported = false; +#else + m_buf_supported = true; +#endif +} + +TiffEncoder::~TiffEncoder() +{ +} + +ImageEncoder TiffEncoder::newEncoder() const +{ + return new TiffEncoder; +} + +bool TiffEncoder::isFormatSupported( int depth ) const +{ + return depth == CV_8U || depth == CV_16U; +} + +void TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag, + TiffFieldType fieldType, + int count, int value ) +{ + strm.putWord( tag ); + strm.putWord( fieldType ); + strm.putDWord( count ); + strm.putDWord( value ); +} + +#ifdef HAVE_TIFF +bool TiffEncoder::writeLibTiff( const Mat& img, const vector& /*params*/) +{ + int channels = img.channels(); + int width = img.cols, height = img.rows; + int depth = img.depth(); + + int bitsPerChannel = -1; + switch (depth) + { + case CV_8U: + { + bitsPerChannel = 8; + break; + } + case CV_16U: + { + bitsPerChannel = 16; + break; + } + default: + { + return false; + } + } + + const int bitsPerByte = 8; + size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte; + int rowsPerStrip = (int)((1 << 13)/fileStep); + + if( rowsPerStrip < 1 ) + rowsPerStrip = 1; + + if( rowsPerStrip > height ) + rowsPerStrip = height; + + + // do NOT put "wb" as the mode, because the b means "big endian" mode, not "binary" mode. + // http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html + TIFF* pTiffHandle = TIFFOpen(m_filename.c_str(), "w"); + if (!pTiffHandle) + { + return false; + } + + // defaults for now, maybe base them on params in the future + int compression = COMPRESSION_LZW; + int predictor = PREDICTOR_HORIZONTAL; + + int colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK; + + if ( !TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width) + || !TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height) + || !TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, bitsPerChannel) + || !TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression) + || !TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, colorspace) + || !TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, channels) + || !TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG) + || !TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, rowsPerStrip) + || !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor) + ) + { + TIFFClose(pTiffHandle); + return false; + } + + // row buffer, because TIFFWriteScanline modifies the original data! + size_t scanlineSize = TIFFScanlineSize(pTiffHandle); + AutoBuffer _buffer(scanlineSize+32); + uchar* buffer = _buffer; + if (!buffer) + { + TIFFClose(pTiffHandle); + return false; + } + + for (int y = 0; y < height; ++y) + { + switch(channels) + { + case 1: + { + memcpy(buffer, img.data + img.step * y, scanlineSize); + break; + } + + case 3: + { + if (depth == CV_8U) + icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) ); + else + icvCvt_BGR2RGB_16u_C3R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) ); + break; + } + + case 4: + { + if (depth == CV_8U) + icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) ); + else + icvCvt_BGRA2RGBA_16u_C4R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) ); + } + + default: + { + TIFFClose(pTiffHandle); + return false; + } + } + + int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0); + if (writeResult != 1) + { + TIFFClose(pTiffHandle); + return false; + } + } + + TIFFClose(pTiffHandle); + return true; +} + +#endif + +#ifdef HAVE_TIFF +bool TiffEncoder::write( const Mat& img, const vector& params) +#else +bool TiffEncoder::write( const Mat& img, const vector& /*params*/) +#endif +{ + int channels = img.channels(); + int width = img.cols, height = img.rows; + int depth = img.depth(); + + if (depth != CV_8U && depth != CV_16U) + return false; + + int bytesPerChannel = depth == CV_8U ? 1 : 2; + int fileStep = width * channels * bytesPerChannel; + + WLByteStream strm; + + if( m_buf ) + { + if( !strm.open(*m_buf) ) + return false; + } + else + { +#ifdef HAVE_TIFF + return writeLibTiff(img, params); +#else + if( !strm.open(m_filename) ) + return false; +#endif + } + + int rowsPerStrip = (1 << 13)/fileStep; + + if( rowsPerStrip < 1 ) + rowsPerStrip = 1; + + if( rowsPerStrip > height ) + rowsPerStrip = height; + + int i, stripCount = (height + rowsPerStrip - 1) / rowsPerStrip; + + if( m_buf ) + m_buf->reserve( alignSize(stripCount*8 + fileStep*height + 256, 256) ); + +/*#if defined _DEBUG || !defined WIN32 + int uncompressedRowSize = rowsPerStrip * fileStep; +#endif*/ + int directoryOffset = 0; + + AutoBuffer stripOffsets(stripCount); + AutoBuffer stripCounts(stripCount); + AutoBuffer _buffer(fileStep+32); + uchar* buffer = _buffer; + int stripOffsetsOffset = 0; + int stripCountsOffset = 0; + int bitsPerSample = 8 * bytesPerChannel; + int y = 0; + + strm.putBytes( fmtSignTiffII, 4 ); + strm.putDWord( directoryOffset ); + + // write an image data first (the most reasonable way + // for compressed images) + for( i = 0; i < stripCount; i++ ) + { + int limit = y + rowsPerStrip; + + if( limit > height ) + limit = height; + + stripOffsets[i] = strm.getPos(); + + for( ; y < limit; y++ ) + { + if( channels == 3 ) + { + if (depth == CV_8U) + icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) ); + else + icvCvt_BGR2RGB_16u_C3R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) ); + } + else + { + if( channels == 4 ) + { + if (depth == CV_8U) + icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) ); + else + icvCvt_BGRA2RGBA_16u_C4R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) ); + } + } + + strm.putBytes( channels > 1 ? buffer : img.data + img.step*y, fileStep ); + } + + stripCounts[i] = (short)(strm.getPos() - stripOffsets[i]); + /*assert( stripCounts[i] == uncompressedRowSize || + stripCounts[i] < uncompressedRowSize && + i == stripCount - 1);*/ + } + + if( stripCount > 2 ) + { + stripOffsetsOffset = strm.getPos(); + for( i = 0; i < stripCount; i++ ) + strm.putDWord( stripOffsets[i] ); + + stripCountsOffset = strm.getPos(); + for( i = 0; i < stripCount; i++ ) + strm.putWord( stripCounts[i] ); + } + else if(stripCount == 2) + { + stripOffsetsOffset = strm.getPos(); + for (i = 0; i < stripCount; i++) + { + strm.putDWord (stripOffsets [i]); + } + stripCountsOffset = stripCounts [0] + (stripCounts [1] << 16); + } + else + { + stripOffsetsOffset = stripOffsets[0]; + stripCountsOffset = stripCounts[0]; + } + + if( channels > 1 ) + { + int bitsPerSamplePos = strm.getPos(); + strm.putWord(bitsPerSample); + strm.putWord(bitsPerSample); + strm.putWord(bitsPerSample); + if( channels == 4 ) + strm.putWord(bitsPerSample); + bitsPerSample = bitsPerSamplePos; + } + + directoryOffset = strm.getPos(); + + // write header + strm.putWord( 9 ); + + /* warning: specification 5.0 of Tiff want to have tags in + ascending order. This is a non-fatal error, but this cause + warning with some tools. So, keep this in ascending order */ + + writeTag( strm, TIFF_TAG_WIDTH, TIFF_TYPE_LONG, 1, width ); + writeTag( strm, TIFF_TAG_HEIGHT, TIFF_TYPE_LONG, 1, height ); + writeTag( strm, TIFF_TAG_BITS_PER_SAMPLE, + TIFF_TYPE_SHORT, channels, bitsPerSample ); + writeTag( strm, TIFF_TAG_COMPRESSION, TIFF_TYPE_LONG, 1, TIFF_UNCOMP ); + writeTag( strm, TIFF_TAG_PHOTOMETRIC, TIFF_TYPE_SHORT, 1, channels > 1 ? 2 : 1 ); + + writeTag( strm, TIFF_TAG_STRIP_OFFSETS, TIFF_TYPE_LONG, + stripCount, stripOffsetsOffset ); + + writeTag( strm, TIFF_TAG_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, channels ); + writeTag( strm, TIFF_TAG_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, rowsPerStrip ); + + writeTag( strm, TIFF_TAG_STRIP_COUNTS, + stripCount > 1 ? TIFF_TYPE_SHORT : TIFF_TYPE_LONG, + stripCount, stripCountsOffset ); + + strm.putDWord(0); + strm.close(); + + if( m_buf ) + { + (*m_buf)[4] = (uchar)directoryOffset; + (*m_buf)[5] = (uchar)(directoryOffset >> 8); + (*m_buf)[6] = (uchar)(directoryOffset >> 16); + (*m_buf)[7] = (uchar)(directoryOffset >> 24); + } + else + { + // write directory offset + FILE* f = fopen( m_filename.c_str(), "r+b" ); + buffer[0] = (uchar)directoryOffset; + buffer[1] = (uchar)(directoryOffset >> 8); + buffer[2] = (uchar)(directoryOffset >> 16); + buffer[3] = (uchar)(directoryOffset >> 24); + + fseek( f, 4, SEEK_SET ); + fwrite( buffer, 1, 4, f ); + fclose(f); + } + + return true; +} + +} diff --git a/highgui/src/grfmt_tiff.hpp b/highgui/src/grfmt_tiff.hpp new file mode 100644 index 0000000..8318548 --- /dev/null +++ b/highgui/src/grfmt_tiff.hpp @@ -0,0 +1,136 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _GRFMT_TIFF_H_ +#define _GRFMT_TIFF_H_ + +#include "grfmt_base.hpp" + +namespace cv +{ + +// native simple TIFF codec +enum TiffCompression +{ + TIFF_UNCOMP = 1, + TIFF_HUFFMAN = 2, + TIFF_PACKBITS = 32773 +}; + +enum TiffByteOrder +{ + TIFF_ORDER_II = 0x4949, + TIFF_ORDER_MM = 0x4d4d +}; + + +enum TiffTag +{ + TIFF_TAG_WIDTH = 256, + TIFF_TAG_HEIGHT = 257, + TIFF_TAG_BITS_PER_SAMPLE = 258, + TIFF_TAG_COMPRESSION = 259, + TIFF_TAG_PHOTOMETRIC = 262, + TIFF_TAG_STRIP_OFFSETS = 273, + TIFF_TAG_STRIP_COUNTS = 279, + TIFF_TAG_SAMPLES_PER_PIXEL = 277, + TIFF_TAG_ROWS_PER_STRIP = 278, + TIFF_TAG_PLANAR_CONFIG = 284, + TIFF_TAG_COLOR_MAP = 320 +}; + + +enum TiffFieldType +{ + TIFF_TYPE_BYTE = 1, + TIFF_TYPE_SHORT = 3, + TIFF_TYPE_LONG = 4 +}; + + +#ifdef HAVE_TIFF + +// libtiff based TIFF codec + +class TiffDecoder : public BaseImageDecoder +{ +public: + TiffDecoder(); + virtual ~TiffDecoder(); + + bool readHeader(); + bool readData( Mat& img ); + void close(); + + size_t signatureLength() const; + bool checkSignature( const string& signature ) const; + ImageDecoder newDecoder() const; + +protected: + void* m_tif; +}; + +#endif + +// ... and writer +class TiffEncoder : public BaseImageEncoder +{ +public: + TiffEncoder(); + virtual ~TiffEncoder(); + + bool isFormatSupported( int depth ) const; + + bool write( const Mat& img, const vector& params ); + ImageEncoder newEncoder() const; + +protected: + void writeTag( WLByteStream& strm, TiffTag tag, + TiffFieldType fieldType, + int count, int value ); + + bool writeLibTiff( const Mat& img, const vector& params ); +}; + +} + +#endif/*_GRFMT_TIFF_H_*/ diff --git a/highgui/src/grfmts.hpp b/highgui/src/grfmts.hpp new file mode 100644 index 0000000..20acd4c --- /dev/null +++ b/highgui/src/grfmts.hpp @@ -0,0 +1,56 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _GRFMTS_H_ +#define _GRFMTS_H_ + +#include "grfmt_base.hpp" +#include "grfmt_imageio.hpp" +#include "grfmt_bmp.hpp" +#include "grfmt_sunras.hpp" +#include "grfmt_jpeg.hpp" +#include "grfmt_pxm.hpp" +#include "grfmt_tiff.hpp" +#include "grfmt_png.hpp" +#include "grfmt_jpeg2000.hpp" +#include "grfmt_exr.hpp" + +#endif/*_GRFMTS_H_*/ diff --git a/highgui/src/loadsave.cpp b/highgui/src/loadsave.cpp new file mode 100644 index 0000000..1fd20dc --- /dev/null +++ b/highgui/src/loadsave.cpp @@ -0,0 +1,534 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +// +// Loading and saving IPL images. +// + +#include "precomp.hpp" +#include "grfmts.hpp" +#undef min +#undef max + +/****************************************************************************************\ +* Image Codecs * +\****************************************************************************************/ +namespace cv +{ + +struct ImageCodecInitializer +{ + ImageCodecInitializer() + { + decoders.push_back( new BmpDecoder ); + encoders.push_back( new BmpEncoder ); + #ifdef HAVE_JPEG + decoders.push_back( new JpegDecoder ); + encoders.push_back( new JpegEncoder ); + #endif + decoders.push_back( new SunRasterDecoder ); + encoders.push_back( new SunRasterEncoder ); + decoders.push_back( new PxMDecoder ); + encoders.push_back( new PxMEncoder ); + #ifdef HAVE_TIFF + decoders.push_back( new TiffDecoder ); + #endif + encoders.push_back( new TiffEncoder ); + #ifdef HAVE_PNG + decoders.push_back( new PngDecoder ); + encoders.push_back( new PngEncoder ); + #endif + #ifdef HAVE_JASPER + decoders.push_back( new Jpeg2KDecoder ); + encoders.push_back( new Jpeg2KEncoder ); + #endif + #ifdef HAVE_OPENEXR + decoders.push_back( new ExrDecoder ); + encoders.push_back( new ExrEncoder ); + #endif + // because it is a generic image I/O API, supporting many formats, + // it should be last in the list. + #ifdef HAVE_IMAGEIO + decoders.push_back( new ImageIODecoder ); + encoders.push_back( new ImageIOEncoder ); + #endif + } + + vector decoders; + vector encoders; +}; + +static ImageCodecInitializer codecs; + +static ImageDecoder findDecoder( const string& filename ) +{ + size_t i, maxlen = 0; + for( i = 0; i < codecs.decoders.size(); i++ ) + { + size_t len = codecs.decoders[i]->signatureLength(); + maxlen = std::max(maxlen, len); + } + + FILE* f= fopen( filename.c_str(), "rb" ); + if( !f ) + return ImageDecoder(); + string signature(maxlen, ' '); + maxlen = fread( &signature[0], 1, maxlen, f ); + fclose(f); + signature = signature.substr(0, maxlen); + + for( i = 0; i < codecs.decoders.size(); i++ ) + { + if( codecs.decoders[i]->checkSignature(signature) ) + return codecs.decoders[i]->newDecoder(); + } + + return ImageDecoder(); +} + +static ImageDecoder findDecoder( const Mat& buf ) +{ + size_t i, maxlen = 0; + + if( buf.rows*buf.cols < 1 || !buf.isContinuous() ) + return ImageDecoder(); + + for( i = 0; i < codecs.decoders.size(); i++ ) + { + size_t len = codecs.decoders[i]->signatureLength(); + maxlen = std::max(maxlen, len); + } + + size_t bufSize = buf.rows*buf.cols*buf.elemSize(); + maxlen = std::min(maxlen, bufSize); + string signature(maxlen, ' '); + memcpy( &signature[0], buf.data, maxlen ); + + for( i = 0; i < codecs.decoders.size(); i++ ) + { + if( codecs.decoders[i]->checkSignature(signature) ) + return codecs.decoders[i]->newDecoder(); + } + + return ImageDecoder(); +} + +static ImageEncoder findEncoder( const string& _ext ) +{ + if( _ext.size() <= 1 ) + return ImageEncoder(); + + const char* ext = strrchr( _ext.c_str(), '.' ); + if( !ext ) + return ImageEncoder(); + int len = 0; + for( ext++; isalnum(ext[len]) && len < 128; len++ ) + ; + + for( size_t i = 0; i < codecs.encoders.size(); i++ ) + { + string description = codecs.encoders[i]->getDescription(); + const char* descr = strchr( description.c_str(), '(' ); + + while( descr ) + { + descr = strchr( descr + 1, '.' ); + if( !descr ) + break; + int j = 0; + for( descr++; isalnum(descr[j]) && j < len; j++ ) + { + int c1 = tolower(ext[j]); + int c2 = tolower(descr[j]); + if( c1 != c2 ) + break; + } + if( j == len && !isalnum(descr[j])) + return codecs.encoders[i]->newEncoder(); + descr += j; + } + } + + return ImageEncoder(); +} + +enum { LOAD_CVMAT=0, LOAD_IMAGE=1, LOAD_MAT=2 }; + +static void* +imread_( const string& filename, int flags, int hdrtype, Mat* mat=0 ) +{ + IplImage* image = 0; + CvMat *matrix = 0; + Mat temp, *data = &temp; + + ImageDecoder decoder = findDecoder(filename); + if( decoder.empty() ) + return 0; + decoder->setSource(filename); + if( !decoder->readHeader() ) + return 0; + + CvSize size; + size.width = decoder->width(); + size.height = decoder->height(); + + int type = decoder->type(); + if( flags != -1 ) + { + if( (flags & CV_LOAD_IMAGE_ANYDEPTH) == 0 ) + type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type)); + + if( (flags & CV_LOAD_IMAGE_COLOR) != 0 || + ((flags & CV_LOAD_IMAGE_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1) ) + type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3); + else + type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1); + } + + if( hdrtype == LOAD_CVMAT || hdrtype == LOAD_MAT ) + { + if( hdrtype == LOAD_CVMAT ) + { + matrix = cvCreateMat( size.height, size.width, type ); + temp = cvarrToMat(matrix); + } + else + { + mat->create( size.height, size.width, type ); + data = mat; + } + } + else + { + image = cvCreateImage( size, cvIplDepth(type), CV_MAT_CN(type) ); + temp = cvarrToMat(image); + } + + if( !decoder->readData( *data )) + { + cvReleaseImage( &image ); + cvReleaseMat( &matrix ); + if( mat ) + mat->release(); + return 0; + } + + return hdrtype == LOAD_CVMAT ? (void*)matrix : + hdrtype == LOAD_IMAGE ? (void*)image : (void*)mat; +} + +Mat imread( const string& filename, int flags ) +{ + Mat img; + imread_( filename, flags, LOAD_MAT, &img ); + return img; +} + +static bool imwrite_( const string& filename, const Mat& image, + const vector& params, bool flipv ) +{ + Mat temp; + const Mat* pimage = ℑ + + CV_Assert( image.channels() == 1 || image.channels() == 3 || image.channels() == 4 ); + + ImageEncoder encoder = findEncoder( filename ); + if( encoder.empty() ) + CV_Error( CV_StsError, "could not find a writer for the specified extension" ); + + if( !encoder->isFormatSupported(image.depth()) ) + { + CV_Assert( encoder->isFormatSupported(CV_8U) ); + image.convertTo( temp, CV_8U ); + pimage = &temp; + } + + if( flipv ) + { + flip(*pimage, temp, 0); + pimage = &temp; + } + + encoder->setDestination( filename ); + bool code = encoder->write( *pimage, params ); + + // CV_Assert( code ); + return code; +} + +bool imwrite( const string& filename, InputArray _img, + const vector& params ) +{ + Mat img = _img.getMat(); + return imwrite_(filename, img, params, false); +} + +static void* +imdecode_( const Mat& buf, int flags, int hdrtype, Mat* mat=0 ) +{ + CV_Assert(buf.data && buf.isContinuous()); + IplImage* image = 0; + CvMat *matrix = 0; + Mat temp, *data = &temp; + string filename = tempfile(); + bool removeTempFile = false; + + ImageDecoder decoder = findDecoder(buf); + if( decoder.empty() ) + return 0; + + if( !decoder->setSource(buf) ) + { + FILE* f = fopen( filename.c_str(), "wb" ); + if( !f ) + return 0; + removeTempFile = true; + size_t bufSize = buf.cols*buf.rows*buf.elemSize(); + fwrite( &buf.data[0], 1, bufSize, f ); + fclose(f); + decoder->setSource(filename); + } + + if( !decoder->readHeader() ) + { + if( removeTempFile ) + remove(filename.c_str()); + return 0; + } + + CvSize size; + size.width = decoder->width(); + size.height = decoder->height(); + + int type = decoder->type(); + if( flags != -1 ) + { + if( (flags & CV_LOAD_IMAGE_ANYDEPTH) == 0 ) + type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type)); + + if( (flags & CV_LOAD_IMAGE_COLOR) != 0 || + ((flags & CV_LOAD_IMAGE_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1) ) + type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3); + else + type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1); + } + + if( hdrtype == LOAD_CVMAT || hdrtype == LOAD_MAT ) + { + if( hdrtype == LOAD_CVMAT ) + { + matrix = cvCreateMat( size.height, size.width, type ); + temp = cvarrToMat(matrix); + } + else + { + mat->create( size.height, size.width, type ); + data = mat; + } + } + else + { + image = cvCreateImage( size, cvIplDepth(type), CV_MAT_CN(type) ); + temp = cvarrToMat(image); + } + + bool code = decoder->readData( *data ); + if( removeTempFile ) + remove(filename.c_str()); + + if( !code ) + { + cvReleaseImage( &image ); + cvReleaseMat( &matrix ); + if( mat ) + mat->release(); + return 0; + } + + return hdrtype == LOAD_CVMAT ? (void*)matrix : + hdrtype == LOAD_IMAGE ? (void*)image : (void*)mat; +} + + +Mat imdecode( InputArray _buf, int flags ) +{ + Mat buf = _buf.getMat(), img; + imdecode_( buf, flags, LOAD_MAT, &img ); + return img; +} + +bool imencode( const string& ext, InputArray _image, + vector& buf, const vector& params ) +{ + Mat image = _image.getMat(); + + int channels = image.channels(); + CV_Assert( channels == 1 || channels == 3 || channels == 4 ); + + ImageEncoder encoder = findEncoder( ext ); + if( encoder.empty() ) + CV_Error( CV_StsError, "could not find encoder for the specified extension" ); + + if( !encoder->isFormatSupported(image.depth()) ) + { + CV_Assert( encoder->isFormatSupported(CV_8U) ); + Mat temp; + image.convertTo(temp, CV_8U); + image = temp; + } + + bool code; + if( encoder->setDestination(buf) ) + { + code = encoder->write(image, params); + CV_Assert( code ); + } + else + { + string filename = tempfile(); + code = encoder->setDestination(filename); + CV_Assert( code ); + code = encoder->write(image, params); + CV_Assert( code ); + FILE* f = fopen( filename.c_str(), "rb" ); + CV_Assert(f != 0); + fseek( f, 0, SEEK_END ); + long pos = ftell(f); + buf.resize((size_t)pos); + fseek( f, 0, SEEK_SET ); + buf.resize(fread( &buf[0], 1, buf.size(), f )); + fclose(f); + remove(filename.c_str()); + } + return code; +} + +} + +/****************************************************************************************\ +* HighGUI loading & saving function implementation * +\****************************************************************************************/ + +CV_IMPL int +cvHaveImageReader( const char* filename ) +{ + cv::ImageDecoder decoder = cv::findDecoder(filename); + return !decoder.empty(); +} + +CV_IMPL int cvHaveImageWriter( const char* filename ) +{ + cv::ImageEncoder encoder = cv::findEncoder(filename); + return !encoder.empty(); +} + +CV_IMPL IplImage* +cvLoadImage( const char* filename, int iscolor ) +{ + return (IplImage*)cv::imread_(filename, iscolor, cv::LOAD_IMAGE ); +} + +CV_IMPL CvMat* +cvLoadImageM( const char* filename, int iscolor ) +{ + return (CvMat*)cv::imread_( filename, iscolor, cv::LOAD_CVMAT ); +} + +CV_IMPL int +cvSaveImage( const char* filename, const CvArr* arr, const int* _params ) +{ + int i = 0; + if( _params ) + { + for( ; _params[i] > 0; i += 2 ) + ; + } + return cv::imwrite_(filename, cv::cvarrToMat(arr), + i > 0 ? cv::vector(_params, _params+i) : cv::vector(), + CV_IS_IMAGE(arr) && ((const IplImage*)arr)->origin == IPL_ORIGIN_BL ); +} + +/* decode image stored in the buffer */ +CV_IMPL IplImage* +cvDecodeImage( const CvMat* _buf, int iscolor ) +{ + CV_Assert( _buf && CV_IS_MAT_CONT(_buf->type) ); + cv::Mat buf(1, _buf->rows*_buf->cols*CV_ELEM_SIZE(_buf->type), CV_8U, _buf->data.ptr); + return (IplImage*)cv::imdecode_(buf, iscolor, cv::LOAD_IMAGE ); +} + +CV_IMPL CvMat* +cvDecodeImageM( const CvMat* _buf, int iscolor ) +{ + CV_Assert( _buf && CV_IS_MAT_CONT(_buf->type) ); + cv::Mat buf(1, _buf->rows*_buf->cols*CV_ELEM_SIZE(_buf->type), CV_8U, _buf->data.ptr); + return (CvMat*)cv::imdecode_(buf, iscolor, cv::LOAD_CVMAT ); +} + +CV_IMPL CvMat* +cvEncodeImage( const char* ext, const CvArr* arr, const int* _params ) +{ + int i = 0; + if( _params ) + { + for( ; _params[i] > 0; i += 2 ) + ; + } + cv::Mat img = cv::cvarrToMat(arr); + if( CV_IS_IMAGE(arr) && ((const IplImage*)arr)->origin == IPL_ORIGIN_BL ) + { + cv::Mat temp; + cv::flip(img, temp, 0); + img = temp; + } + cv::vector buf; + + bool code = cv::imencode(ext, img, buf, + i > 0 ? std::vector(_params, _params+i) : std::vector() ); + if( !code ) + return 0; + CvMat* _buf = cvCreateMat(1, (int)buf.size(), CV_8U); + memcpy( _buf->data.ptr, &buf[0], buf.size() ); + + return _buf; +} + +/* End of file. */ diff --git a/highgui/src/makeswig.sh b/highgui/src/makeswig.sh new file mode 100644 index 0000000..06e88e1 --- /dev/null +++ b/highgui/src/makeswig.sh @@ -0,0 +1,2 @@ +swig -DSKIP_INCLUDES -python -small highgui.i +gcc -I/usr/include/python2.3/ -I../../cxcore/include -D CV_NO_BACKWARD_COMPATIBILITY -c highgui_wrap.c diff --git a/highgui/src/precomp.cpp b/highgui/src/precomp.cpp new file mode 100644 index 0000000..d6f6e18 --- /dev/null +++ b/highgui/src/precomp.cpp @@ -0,0 +1,43 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + diff --git a/highgui/src/precomp.hpp b/highgui/src/precomp.hpp new file mode 100644 index 0000000..334a097 --- /dev/null +++ b/highgui/src/precomp.hpp @@ -0,0 +1,245 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __HIGHGUI_H_ +#define __HIGHGUI_H_ + +#include "cvconfig.h" + +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/highgui/highgui_c.h" +#include "opencv2/imgproc/imgproc_c.h" +#include "opencv2/core/internal.hpp" + +#if defined WIN32 || defined _WIN32 +//required windows.h has to be included by the opencv2/core/internal.hpp +void FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin ); +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_TEGRA_OPTIMIZATION +#include "opencv2/highgui/highgui_tegra.hpp" +#endif + +/* Errors */ +#define HG_OK 0 /* Don't bet on it! */ +#define HG_BADNAME -1 /* Bad window or file name */ +#define HG_INITFAILED -2 /* Can't initialize HigHGUI */ +#define HG_WCFAILED -3 /* Can't create a window */ +#define HG_NULLPTR -4 /* The null pointer where it should not appear */ +#define HG_BADPARAM -5 + +#define __BEGIN__ __CV_BEGIN__ +#define __END__ __CV_END__ +#define EXIT __CV_EXIT__ + +#define CV_WINDOW_MAGIC_VAL 0x00420042 +#define CV_TRACKBAR_MAGIC_VAL 0x00420043 + +/***************************** CvCapture structure ******************************/ + +struct CvCapture +{ + virtual ~CvCapture() {} + virtual double getProperty(int) { return 0; } + virtual bool setProperty(int, double) { return 0; } + virtual bool grabFrame() { return true; } + virtual IplImage* retrieveFrame(int) { return 0; } + virtual int getCaptureDomain() { return CV_CAP_ANY; } // Return the type of the capture object: CV_CAP_VFW, etc... +}; + +/*************************** CvVideoWriter structure ****************************/ + +struct CvVideoWriter +{ + virtual ~CvVideoWriter() {} + virtual bool writeFrame(const IplImage*) { return false; } +}; + +#if defined WIN32 || defined _WIN32 +#define HAVE_VFW 1 + +/* uncomment to enable CMUCamera1394 fireware camera module */ +//#define HAVE_CMU1394 1 +#endif + + +CvCapture * cvCreateCameraCapture_V4L( int index ); +CvCapture * cvCreateCameraCapture_DC1394( int index ); +CvCapture * cvCreateCameraCapture_DC1394_2( int index ); +CvCapture* cvCreateCameraCapture_MIL( int index ); +CvCapture * cvCreateCameraCapture_CMU( int index ); +CV_IMPL CvCapture * cvCreateCameraCapture_TYZX( int index ); +CvCapture* cvCreateFileCapture_Win32( const char* filename ); +CvCapture* cvCreateCameraCapture_VFW( int index ); +CvCapture* cvCreateFileCapture_VFW( const char* filename ); +CvVideoWriter* cvCreateVideoWriter_Win32( const char* filename, int fourcc, + double fps, CvSize frameSize, int is_color ); +CvVideoWriter* cvCreateVideoWriter_VFW( const char* filename, int fourcc, + double fps, CvSize frameSize, int is_color ); +CvCapture* cvCreateCameraCapture_DShow( int index ); +CvCapture* cvCreateCameraCapture_OpenNI( int index ); +CvCapture* cvCreateFileCapture_OpenNI( const char* filename ); +CvCapture* cvCreateCameraCapture_Android( int index ); +CvCapture* cvCreateCameraCapture_XIMEA( int index ); +CvCapture* cvCreateCameraCapture_AVFoundation(int index); + + +CVAPI(int) cvHaveImageReader(const char* filename); +CVAPI(int) cvHaveImageWriter(const char* filename); + +CvCapture* cvCreateFileCapture_Images(const char* filename); +CvVideoWriter* cvCreateVideoWriter_Images(const char* filename); + +CvCapture* cvCreateFileCapture_XINE (const char* filename); + + + + +#define CV_CAP_GSTREAMER_1394 0 +#define CV_CAP_GSTREAMER_V4L 1 +#define CV_CAP_GSTREAMER_V4L2 2 +#define CV_CAP_GSTREAMER_FILE 3 + +CvCapture* cvCreateCapture_GStreamer(int type, const char *filename); +CvCapture* cvCreateFileCapture_FFMPEG_proxy(const char* filename); + + +CvVideoWriter* cvCreateVideoWriter_FFMPEG_proxy( const char* filename, int fourcc, + double fps, CvSize frameSize, int is_color ); + +CvCapture * cvCreateFileCapture_QT (const char * filename); +CvCapture * cvCreateCameraCapture_QT (const int index); + +CvVideoWriter* cvCreateVideoWriter_QT ( const char* filename, int fourcc, + double fps, CvSize frameSize, int is_color ); + +CvCapture* cvCreateFileCapture_AVFoundation (const char * filename); +CvVideoWriter* cvCreateVideoWriter_AVFoundation( const char* filename, int fourcc, + double fps, CvSize frameSize, int is_color ); + + +CvCapture * cvCreateCameraCapture_Unicap (const int index); +CvCapture * cvCreateCameraCapture_PvAPI (const int index); +CvVideoWriter* cvCreateVideoWriter_GStreamer( const char* filename, int fourcc, + double fps, CvSize frameSize, int is_color ); + +//Yannick Verdie 2010 +void cvSetModeWindow_W32(const char* name, double prop_value); +void cvSetModeWindow_GTK(const char* name, double prop_value); +void cvSetModeWindow_CARBON(const char* name, double prop_value); +void cvSetModeWindow_COCOA(const char* name, double prop_value); + +double cvGetModeWindow_W32(const char* name); +double cvGetModeWindow_GTK(const char* name); +double cvGetModeWindow_CARBON(const char* name); +double cvGetModeWindow_COCOA(const char* name); + +double cvGetPropWindowAutoSize_W32(const char* name); +double cvGetPropWindowAutoSize_GTK(const char* name); + +double cvGetRatioWindow_W32(const char* name); +double cvGetRatioWindow_GTK(const char* name); + +double cvGetOpenGlProp_W32(const char* name); +double cvGetOpenGlProp_GTK(const char* name); + +//for QT +#if defined (HAVE_QT) +double cvGetModeWindow_QT(const char* name); +void cvSetModeWindow_QT(const char* name, double prop_value); + +double cvGetPropWindow_QT(const char* name); +void cvSetPropWindow_QT(const char* name,double prop_value); + +double cvGetRatioWindow_QT(const char* name); +void cvSetRatioWindow_QT(const char* name,double prop_value); + +double cvGetOpenGlProp_QT(const char* name); +#endif + +// OpenGL +typedef void (CV_CDECL *CvOpenGlCleanCallback)(void* userdata); +void icvSetOpenGlCleanCallback(const char* window_name, CvOpenGlCleanCallback callback, void* userdata); + + +/*namespace cv +{ + +class CV_EXPORTS BaseWindow +{ +public: + BaseWindow(const String& name, int flags=0); + virtual ~BaseWindow(); + virtual void close(); + virtual void show(const Mat& mat); + virtual void resize(Size size); + virtual void move(Point topleft); + virtual Size size() const; + virtual Point topLeft() const; + virtual void setGeometry(Point topLeft, Size size); + virtual void getGeometry(Point& topLeft, Size& size) const; + virtual String getTitle() const; + virtual void setTitle(const String& str); + virtual String getName() const; + virtual void setScaleMode(int mode); + virtual int getScaleMode(); + virtual void setScrollPos(double pos); + virtual double getScrollPos() const; + virtual void setScale(double scale); + virtual double getScale() const; + virtual Point getImageCoords(Point pos) const; + virtual Scalar getPixelValue(Point pos, const String& colorspace=String()) const; + + virtual void addTrackbar( const String& trackbar, int low, int high, int step ); +}; + +typedef Ptr Window; + +}*/ + +#endif /* __HIGHGUI_H_ */ diff --git a/highgui/src/utils.cpp b/highgui/src/utils.cpp new file mode 100644 index 0000000..095a256 --- /dev/null +++ b/highgui/src/utils.cpp @@ -0,0 +1,689 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include "utils.hpp" + +#define SCALE 14 +#define cR (int)(0.299*(1 << SCALE) + 0.5) +#define cG (int)(0.587*(1 << SCALE) + 0.5) +#define cB ((1 << SCALE) - cR - cG) + +void icvCvt_BGR2Gray_8u_C3C1R( const uchar* rgb, int rgb_step, + uchar* gray, int gray_step, + CvSize size, int _swap_rb ) +{ + int i; + int swap_rb = _swap_rb ? 2 : 0; + for( ; size.height--; gray += gray_step ) + { + for( i = 0; i < size.width; i++, rgb += 3 ) + { + int t = descale( rgb[swap_rb]*cB + rgb[1]*cG + rgb[swap_rb^2]*cR, SCALE ); + gray[i] = (uchar)t; + } + + rgb += rgb_step - size.width*3; + } +} + + +void icvCvt_BGRA2Gray_16u_CnC1R( const ushort* rgb, int rgb_step, + ushort* gray, int gray_step, + CvSize size, int ncn, int _swap_rb ) +{ + int i; + int swap_rb = _swap_rb ? 2 : 0; + for( ; size.height--; gray += gray_step ) + { + for( i = 0; i < size.width; i++, rgb += ncn ) + { + int t = descale( rgb[swap_rb]*cB + rgb[1]*cG + rgb[swap_rb^2]*cR, SCALE ); + gray[i] = (ushort)t; + } + + rgb += rgb_step - size.width*ncn; + } +} + + +void icvCvt_BGRA2Gray_8u_C4C1R( const uchar* rgba, int rgba_step, + uchar* gray, int gray_step, + CvSize size, int _swap_rb ) +{ + int i; + int swap_rb = _swap_rb ? 2 : 0; + for( ; size.height--; gray += gray_step ) + { + for( i = 0; i < size.width; i++, rgba += 4 ) + { + int t = descale( rgba[swap_rb]*cB + rgba[1]*cG + rgba[swap_rb^2]*cR, SCALE ); + gray[i] = (uchar)t; + } + + rgba += rgba_step - size.width*4; + } +} + + +void icvCvt_Gray2BGR_8u_C1C3R( const uchar* gray, int gray_step, + uchar* bgr, int bgr_step, CvSize size ) +{ + int i; + for( ; size.height--; gray += gray_step ) + { + for( i = 0; i < size.width; i++, bgr += 3 ) + { + bgr[0] = bgr[1] = bgr[2] = gray[i]; + } + bgr += bgr_step - size.width*3; + } +} + + +void icvCvt_Gray2BGR_16u_C1C3R( const ushort* gray, int gray_step, + ushort* bgr, int bgr_step, CvSize size ) +{ + int i; + for( ; size.height--; gray += gray_step/sizeof(gray[0]) ) + { + for( i = 0; i < size.width; i++, bgr += 3 ) + { + bgr[0] = bgr[1] = bgr[2] = gray[i]; + } + bgr += bgr_step/sizeof(bgr[0]) - size.width*3; + } +} + + +void icvCvt_BGRA2BGR_8u_C4C3R( const uchar* bgra, int bgra_step, + uchar* bgr, int bgr_step, + CvSize size, int _swap_rb ) +{ + int i; + int swap_rb = _swap_rb ? 2 : 0; + for( ; size.height--; ) + { + for( i = 0; i < size.width; i++, bgr += 3, bgra += 4 ) + { + uchar t0 = bgra[swap_rb], t1 = bgra[1]; + bgr[0] = t0; bgr[1] = t1; + t0 = bgra[swap_rb^2]; bgr[2] = t0; + } + bgr += bgr_step - size.width*3; + bgra += bgra_step - size.width*4; + } +} + + +void icvCvt_BGRA2BGR_16u_C4C3R( const ushort* bgra, int bgra_step, + ushort* bgr, int bgr_step, + CvSize size, int _swap_rb ) +{ + int i; + int swap_rb = _swap_rb ? 2 : 0; + for( ; size.height--; ) + { + for( i = 0; i < size.width; i++, bgr += 3, bgra += 4 ) + { + ushort t0 = bgra[swap_rb], t1 = bgra[1]; + bgr[0] = t0; bgr[1] = t1; + t0 = bgra[swap_rb^2]; bgr[2] = t0; + } + bgr += bgr_step/sizeof(bgr[0]) - size.width*3; + bgra += bgra_step/sizeof(bgra[0]) - size.width*4; + } +} + + +void icvCvt_BGRA2RGBA_8u_C4R( const uchar* bgra, int bgra_step, + uchar* rgba, int rgba_step, CvSize size ) +{ + int i; + for( ; size.height--; ) + { + for( i = 0; i < size.width; i++, bgra += 4, rgba += 4 ) + { + uchar t0 = bgra[0], t1 = bgra[1]; + uchar t2 = bgra[2], t3 = bgra[3]; + rgba[0] = t2; rgba[1] = t1; + rgba[2] = t0; rgba[3] = t3; + } + bgra += bgra_step - size.width*4; + rgba += rgba_step - size.width*4; + } +} + +void icvCvt_BGRA2RGBA_16u_C4R( const ushort* bgra, int bgra_step, + ushort* rgba, int rgba_step, CvSize size ) +{ + int i; + for( ; size.height--; ) + { + for( i = 0; i < size.width; i++, bgra += 4, rgba += 4 ) + { + ushort t0 = bgra[0], t1 = bgra[1]; + ushort t2 = bgra[2], t3 = bgra[3]; + + rgba[0] = t2; rgba[1] = t1; + rgba[2] = t0; rgba[3] = t3; + } + bgra += bgra_step/sizeof(bgra[0]) - size.width*4; + rgba += rgba_step/sizeof(rgba[0]) - size.width*4; + } +} + + +void icvCvt_BGR2RGB_8u_C3R( const uchar* bgr, int bgr_step, + uchar* rgb, int rgb_step, CvSize size ) +{ + int i; + for( ; size.height--; ) + { + for( i = 0; i < size.width; i++, bgr += 3, rgb += 3 ) + { + uchar t0 = bgr[0], t1 = bgr[1], t2 = bgr[2]; + rgb[2] = t0; rgb[1] = t1; rgb[0] = t2; + } + bgr += bgr_step - size.width*3; + rgb += rgb_step - size.width*3; + } +} + + +void icvCvt_BGR2RGB_16u_C3R( const ushort* bgr, int bgr_step, + ushort* rgb, int rgb_step, CvSize size ) +{ + int i; + for( ; size.height--; ) + { + for( i = 0; i < size.width; i++, bgr += 3, rgb += 3 ) + { + ushort t0 = bgr[0], t1 = bgr[1], t2 = bgr[2]; + rgb[2] = t0; rgb[1] = t1; rgb[0] = t2; + } + bgr += bgr_step - size.width*3; + rgb += rgb_step - size.width*3; + } +} + + +typedef unsigned short ushort; + +void icvCvt_BGR5552Gray_8u_C2C1R( const uchar* bgr555, int bgr555_step, + uchar* gray, int gray_step, CvSize size ) +{ + int i; + for( ; size.height--; gray += gray_step, bgr555 += bgr555_step ) + { + for( i = 0; i < size.width; i++ ) + { + int t = descale( ((((ushort*)bgr555)[i] << 3) & 0xf8)*cB + + ((((ushort*)bgr555)[i] >> 2) & 0xf8)*cG + + ((((ushort*)bgr555)[i] >> 7) & 0xf8)*cR, SCALE ); + gray[i] = (uchar)t; + } + } +} + + +void icvCvt_BGR5652Gray_8u_C2C1R( const uchar* bgr565, int bgr565_step, + uchar* gray, int gray_step, CvSize size ) +{ + int i; + for( ; size.height--; gray += gray_step, bgr565 += bgr565_step ) + { + for( i = 0; i < size.width; i++ ) + { + int t = descale( ((((ushort*)bgr565)[i] << 3) & 0xf8)*cB + + ((((ushort*)bgr565)[i] >> 3) & 0xfc)*cG + + ((((ushort*)bgr565)[i] >> 8) & 0xf8)*cR, SCALE ); + gray[i] = (uchar)t; + } + } +} + + +void icvCvt_BGR5552BGR_8u_C2C3R( const uchar* bgr555, int bgr555_step, + uchar* bgr, int bgr_step, CvSize size ) +{ + int i; + for( ; size.height--; bgr555 += bgr555_step ) + { + for( i = 0; i < size.width; i++, bgr += 3 ) + { + int t0 = (((ushort*)bgr555)[i] << 3) & 0xf8; + int t1 = (((ushort*)bgr555)[i] >> 2) & 0xf8; + int t2 = (((ushort*)bgr555)[i] >> 7) & 0xf8; + bgr[0] = (uchar)t0; bgr[1] = (uchar)t1; bgr[2] = (uchar)t2; + } + bgr += bgr_step - size.width*3; + } +} + + +void icvCvt_BGR5652BGR_8u_C2C3R( const uchar* bgr565, int bgr565_step, + uchar* bgr, int bgr_step, CvSize size ) +{ + int i; + for( ; size.height--; bgr565 += bgr565_step ) + { + for( i = 0; i < size.width; i++, bgr += 3 ) + { + int t0 = (((ushort*)bgr565)[i] << 3) & 0xf8; + int t1 = (((ushort*)bgr565)[i] >> 3) & 0xfc; + int t2 = (((ushort*)bgr565)[i] >> 8) & 0xf8; + bgr[0] = (uchar)t0; bgr[1] = (uchar)t1; bgr[2] = (uchar)t2; + } + bgr += bgr_step - size.width*3; + } +} + + +void icvCvt_CMYK2BGR_8u_C4C3R( const uchar* cmyk, int cmyk_step, + uchar* bgr, int bgr_step, CvSize size ) +{ + int i; + for( ; size.height--; ) + { + for( i = 0; i < size.width; i++, bgr += 3, cmyk += 4 ) + { + int c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3]; + c = k - ((255 - c)*k>>8); + m = k - ((255 - m)*k>>8); + y = k - ((255 - y)*k>>8); + bgr[2] = (uchar)c; bgr[1] = (uchar)m; bgr[0] = (uchar)y; + } + bgr += bgr_step - size.width*3; + cmyk += cmyk_step - size.width*4; + } +} + + +void icvCvt_CMYK2Gray_8u_C4C1R( const uchar* cmyk, int cmyk_step, + uchar* gray, int gray_step, CvSize size ) +{ + int i; + for( ; size.height--; ) + { + for( i = 0; i < size.width; i++, cmyk += 4 ) + { + int c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3]; + c = k - ((255 - c)*k>>8); + m = k - ((255 - m)*k>>8); + y = k - ((255 - y)*k>>8); + int t = descale( y*cB + m*cG + c*cR, SCALE ); + gray[i] = (uchar)t; + } + gray += gray_step; + cmyk += cmyk_step - size.width*4; + } +} + + +void CvtPaletteToGray( const PaletteEntry* palette, uchar* grayPalette, int entries ) +{ + int i; + for( i = 0; i < entries; i++ ) + { + icvCvt_BGR2Gray_8u_C3C1R( (uchar*)(palette + i), 0, grayPalette + i, 0, cvSize(1,1) ); + } +} + + +void FillGrayPalette( PaletteEntry* palette, int bpp, bool negative ) +{ + int i, length = 1 << bpp; + int xor_mask = negative ? 255 : 0; + + for( i = 0; i < length; i++ ) + { + int val = (i * 255/(length - 1)) ^ xor_mask; + palette[i].b = palette[i].g = palette[i].r = (uchar)val; + palette[i].a = 0; + } +} + + +bool IsColorPalette( PaletteEntry* palette, int bpp ) +{ + int i, length = 1 << bpp; + + for( i = 0; i < length; i++ ) + { + if( palette[i].b != palette[i].g || + palette[i].b != palette[i].r ) + return true; + } + + return false; +} + + +uchar* FillUniColor( uchar* data, uchar*& line_end, + int step, int width3, + int& y, int height, + int count3, PaletteEntry clr ) +{ + do + { + uchar* end = data + count3; + + if( end > line_end ) + end = line_end; + + count3 -= (int)(end - data); + + for( ; data < end; data += 3 ) + { + WRITE_PIX( data, clr ); + } + + if( data >= line_end ) + { + line_end += step; + data = line_end - width3; + if( ++y >= height ) break; + } + } + while( count3 > 0 ); + + return data; +} + + +uchar* FillUniGray( uchar* data, uchar*& line_end, + int step, int width, + int& y, int height, + int count, uchar clr ) +{ + do + { + uchar* end = data + count; + + if( end > line_end ) + end = line_end; + + count -= (int)(end - data); + + for( ; data < end; data++ ) + { + *data = clr; + } + + if( data >= line_end ) + { + line_end += step; + data = line_end - width; + if( ++y >= height ) break; + } + } + while( count > 0 ); + + return data; +} + + +uchar* FillColorRow8( uchar* data, uchar* indices, int len, PaletteEntry* palette ) +{ + uchar* end = data + len*3; + while( (data += 3) < end ) + { + *((PaletteEntry*)(data-3)) = palette[*indices++]; + } + PaletteEntry clr = palette[indices[0]]; + WRITE_PIX( data - 3, clr ); + return data; +} + + +uchar* FillGrayRow8( uchar* data, uchar* indices, int len, uchar* palette ) +{ + int i; + for( i = 0; i < len; i++ ) + { + data[i] = palette[indices[i]]; + } + return data + len; +} + + +uchar* FillColorRow4( uchar* data, uchar* indices, int len, PaletteEntry* palette ) +{ + uchar* end = data + len*3; + + while( (data += 6) < end ) + { + int idx = *indices++; + *((PaletteEntry*)(data-6)) = palette[idx >> 4]; + *((PaletteEntry*)(data-3)) = palette[idx & 15]; + } + + int idx = indices[0]; + PaletteEntry clr = palette[idx >> 4]; + WRITE_PIX( data - 6, clr ); + + if( data == end ) + { + clr = palette[idx & 15]; + WRITE_PIX( data - 3, clr ); + } + return end; +} + + +uchar* FillGrayRow4( uchar* data, uchar* indices, int len, uchar* palette ) +{ + uchar* end = data + len; + while( (data += 2) < end ) + { + int idx = *indices++; + data[-2] = palette[idx >> 4]; + data[-1] = palette[idx & 15]; + } + + int idx = indices[0]; + uchar clr = palette[idx >> 4]; + data[-2] = clr; + + if( data == end ) + { + clr = palette[idx & 15]; + data[-1] = clr; + } + return end; +} + + +uchar* FillColorRow1( uchar* data, uchar* indices, int len, PaletteEntry* palette ) +{ + uchar* end = data + len*3; + + while( (data += 24) < end ) + { + int idx = *indices++; + *((PaletteEntry*)(data - 24)) = palette[(idx & 128) != 0]; + *((PaletteEntry*)(data - 21)) = palette[(idx & 64) != 0]; + *((PaletteEntry*)(data - 18)) = palette[(idx & 32) != 0]; + *((PaletteEntry*)(data - 15)) = palette[(idx & 16) != 0]; + *((PaletteEntry*)(data - 12)) = palette[(idx & 8) != 0]; + *((PaletteEntry*)(data - 9)) = palette[(idx & 4) != 0]; + *((PaletteEntry*)(data - 6)) = palette[(idx & 2) != 0]; + *((PaletteEntry*)(data - 3)) = palette[(idx & 1) != 0]; + } + + int idx = indices[0] << 24; + for( data -= 24; data < end; data += 3, idx += idx ) + { + PaletteEntry clr = palette[idx < 0]; + WRITE_PIX( data, clr ); + } + + return data; +} + + +uchar* FillGrayRow1( uchar* data, uchar* indices, int len, uchar* palette ) +{ + uchar* end = data + len; + + while( (data += 8) < end ) + { + int idx = *indices++; + *((uchar*)(data - 8)) = palette[(idx & 128) != 0]; + *((uchar*)(data - 7)) = palette[(idx & 64) != 0]; + *((uchar*)(data - 6)) = palette[(idx & 32) != 0]; + *((uchar*)(data - 5)) = palette[(idx & 16) != 0]; + *((uchar*)(data - 4)) = palette[(idx & 8) != 0]; + *((uchar*)(data - 3)) = palette[(idx & 4) != 0]; + *((uchar*)(data - 2)) = palette[(idx & 2) != 0]; + *((uchar*)(data - 1)) = palette[(idx & 1) != 0]; + } + + int idx = indices[0] << 24; + for( data -= 8; data < end; data++, idx += idx ) + { + data[0] = palette[idx < 0]; + } + + return data; +} + + +CV_IMPL void +cvConvertImage( const CvArr* srcarr, CvArr* dstarr, int flags ) +{ + CvMat* temp = 0; + + CV_FUNCNAME( "cvConvertImage" ); + + __BEGIN__; + + CvMat srcstub, *src; + CvMat dststub, *dst; + int src_cn, dst_cn, swap_rb = flags & CV_CVTIMG_SWAP_RB; + + CV_CALL( src = cvGetMat( srcarr, &srcstub )); + CV_CALL( dst = cvGetMat( dstarr, &dststub )); + + src_cn = CV_MAT_CN( src->type ); + dst_cn = CV_MAT_CN( dst->type ); + + if( src_cn != 1 && src_cn != 3 && src_cn != 4 ) + CV_ERROR( CV_BadNumChannels, "Source image must have 1, 3 or 4 channels" ); + + if( CV_MAT_DEPTH( dst->type ) != CV_8U ) + CV_ERROR( CV_BadDepth, "Destination image must be 8u" ); + + if( CV_MAT_CN(dst->type) != 1 && CV_MAT_CN(dst->type) != 3 ) + CV_ERROR( CV_BadNumChannels, "Destination image must have 1 or 3 channels" ); + + if( !CV_ARE_DEPTHS_EQ( src, dst )) + { + int src_depth = CV_MAT_DEPTH(src->type); + double scale = src_depth <= CV_8S ? 1 : src_depth <= CV_32S ? 1./256 : 255; + double shift = src_depth == CV_8S || src_depth == CV_16S ? 128 : 0; + + if( !CV_ARE_CNS_EQ( src, dst )) + { + temp = cvCreateMat( src->height, src->width, + (src->type & CV_MAT_CN_MASK)|(dst->type & CV_MAT_DEPTH_MASK)); + cvConvertScale( src, temp, scale, shift ); + src = temp; + } + else + { + cvConvertScale( src, dst, scale, shift ); + src = dst; + } + } + + if( src_cn != dst_cn || (src_cn == 3 && swap_rb) ) + { + uchar *s = src->data.ptr, *d = dst->data.ptr; + int s_step = src->step, d_step = dst->step; + int code = src_cn*10 + dst_cn; + CvSize size = { src->cols, src->rows }; + + if( CV_IS_MAT_CONT(src->type & dst->type) ) + { + size.width *= size.height; + size.height = 1; + s_step = d_step = CV_STUB_STEP; + } + + switch( code ) + { + case 13: + icvCvt_Gray2BGR_8u_C1C3R( s, s_step, d, d_step, size ); + break; + case 31: + icvCvt_BGR2Gray_8u_C3C1R( s, s_step, d, d_step, size, swap_rb ); + break; + case 33: + assert( swap_rb ); + icvCvt_RGB2BGR_8u_C3R( s, s_step, d, d_step, size ); + break; + case 41: + icvCvt_BGRA2Gray_8u_C4C1R( s, s_step, d, d_step, size, swap_rb ); + break; + case 43: + icvCvt_BGRA2BGR_8u_C4C3R( s, s_step, d, d_step, size, swap_rb ); + break; + default: + CV_ERROR( CV_StsUnsupportedFormat, "Unsupported combination of input/output formats" ); + } + src = dst; + } + + if( flags & CV_CVTIMG_FLIP ) + { + CV_CALL( cvFlip( src, dst, 0 )); + } + else if( src != dst ) + { + CV_CALL( cvCopy( src, dst )); + } + + __END__; + + cvReleaseMat( &temp ); +} diff --git a/highgui/src/utils.hpp b/highgui/src/utils.hpp new file mode 100644 index 0000000..d4b264e --- /dev/null +++ b/highgui/src/utils.hpp @@ -0,0 +1,128 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _UTILS_H_ +#define _UTILS_H_ + +struct PaletteEntry +{ + unsigned char b, g, r, a; +}; + +#define WRITE_PIX( ptr, clr ) \ + (((uchar*)(ptr))[0] = (clr).b, \ + ((uchar*)(ptr))[1] = (clr).g, \ + ((uchar*)(ptr))[2] = (clr).r) + +#define descale(x,n) (((x) + (1 << ((n)-1))) >> (n)) +#define saturate(x) (uchar)(((x) & ~255) == 0 ? (x) : ~((x)>>31)) + +void icvCvt_BGR2Gray_8u_C3C1R( const uchar* bgr, int bgr_step, + uchar* gray, int gray_step, + CvSize size, int swap_rb=0 ); +void icvCvt_BGRA2Gray_8u_C4C1R( const uchar* bgra, int bgra_step, + uchar* gray, int gray_step, + CvSize size, int swap_rb=0 ); +void icvCvt_BGRA2Gray_16u_CnC1R( const ushort* bgra, int bgra_step, + ushort* gray, int gray_step, + CvSize size, int ncn, int swap_rb=0 ); + +void icvCvt_Gray2BGR_8u_C1C3R( const uchar* gray, int gray_step, + uchar* bgr, int bgr_step, CvSize size ); +void icvCvt_Gray2BGR_16u_C1C3R( const ushort* gray, int gray_step, + ushort* bgr, int bgr_step, CvSize size ); + +void icvCvt_BGRA2BGR_8u_C4C3R( const uchar* bgra, int bgra_step, + uchar* bgr, int bgr_step, + CvSize size, int swap_rb=0 ); +void icvCvt_BGRA2BGR_16u_C4C3R( const ushort* bgra, int bgra_step, + ushort* bgr, int bgr_step, + CvSize size, int _swap_rb ); + +void icvCvt_BGR2RGB_8u_C3R( const uchar* bgr, int bgr_step, + uchar* rgb, int rgb_step, CvSize size ); +#define icvCvt_RGB2BGR_8u_C3R icvCvt_BGR2RGB_8u_C3R +void icvCvt_BGR2RGB_16u_C3R( const ushort* bgr, int bgr_step, + ushort* rgb, int rgb_step, CvSize size ); +#define icvCvt_RGB2BGR_16u_C3R icvCvt_BGR2RGB_16u_C3R + +void icvCvt_BGRA2RGBA_8u_C4R( const uchar* bgra, int bgra_step, + uchar* rgba, int rgba_step, CvSize size ); +#define icvCvt_RGBA2BGRA_8u_C4R icvCvt_BGRA2RGBA_8u_C4R + +void icvCvt_BGRA2RGBA_16u_C4R( const ushort* bgra, int bgra_step, + ushort* rgba, int rgba_step, CvSize size ); +#define icvCvt_RGBA2BGRA_16u_C4R icvCvt_BGRA2RGBA_16u_C4R + +void icvCvt_BGR5552Gray_8u_C2C1R( const uchar* bgr555, int bgr555_step, + uchar* gray, int gray_step, CvSize size ); +void icvCvt_BGR5652Gray_8u_C2C1R( const uchar* bgr565, int bgr565_step, + uchar* gray, int gray_step, CvSize size ); +void icvCvt_BGR5552BGR_8u_C2C3R( const uchar* bgr555, int bgr555_step, + uchar* bgr, int bgr_step, CvSize size ); +void icvCvt_BGR5652BGR_8u_C2C3R( const uchar* bgr565, int bgr565_step, + uchar* bgr, int bgr_step, CvSize size ); +void icvCvt_CMYK2BGR_8u_C4C3R( const uchar* cmyk, int cmyk_step, + uchar* bgr, int bgr_step, CvSize size ); +void icvCvt_CMYK2Gray_8u_C4C1R( const uchar* ycck, int ycck_step, + uchar* gray, int gray_step, CvSize size ); + +void FillGrayPalette( PaletteEntry* palette, int bpp, bool negative = false ); +bool IsColorPalette( PaletteEntry* palette, int bpp ); +void CvtPaletteToGray( const PaletteEntry* palette, uchar* grayPalette, int entries ); +uchar* FillUniColor( uchar* data, uchar*& line_end, int step, int width3, + int& y, int height, int count3, PaletteEntry clr ); +uchar* FillUniGray( uchar* data, uchar*& line_end, int step, int width3, + int& y, int height, int count3, uchar clr ); + +uchar* FillColorRow8( uchar* data, uchar* indices, int len, PaletteEntry* palette ); +uchar* FillGrayRow8( uchar* data, uchar* indices, int len, uchar* palette ); +uchar* FillColorRow4( uchar* data, uchar* indices, int len, PaletteEntry* palette ); +uchar* FillGrayRow4( uchar* data, uchar* indices, int len, uchar* palette ); +uchar* FillColorRow1( uchar* data, uchar* indices, int len, PaletteEntry* palette ); +uchar* FillGrayRow1( uchar* data, uchar* indices, int len, uchar* palette ); + +CV_INLINE bool isBigEndian( void ) +{ + return (((const int*)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0; +} + +#endif/*_UTILS_H_*/ diff --git a/highgui/src/window.cpp b/highgui/src/window.cpp new file mode 100644 index 0000000..4e94566 --- /dev/null +++ b/highgui/src/window.cpp @@ -0,0 +1,746 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include "opencv2/core/opengl_interop.hpp" + +// in later times, use this file as a dispatcher to implementations like cvcap.cpp + +CV_IMPL void cvSetWindowProperty(const char* name, int prop_id, double prop_value) +{ + switch(prop_id) + { + //change between fullscreen or not. + case CV_WND_PROP_FULLSCREEN: + + if (!name || (prop_value!=CV_WINDOW_NORMAL && prop_value!=CV_WINDOW_FULLSCREEN))//bad argument + break; + + #if defined (HAVE_QT) + cvSetModeWindow_QT(name,prop_value); + #elif defined WIN32 || defined _WIN32 + cvSetModeWindow_W32(name,prop_value); + #elif defined (HAVE_GTK) + cvSetModeWindow_GTK(name,prop_value); + #elif defined (HAVE_CARBON) + cvSetModeWindow_CARBON(name,prop_value); + #elif defined (HAVE_COCOA) + cvSetModeWindow_COCOA(name,prop_value); + #endif + break; + + case CV_WND_PROP_AUTOSIZE: + #if defined (HAVE_QT) + cvSetPropWindow_QT(name,prop_value); + #endif + break; + + case CV_WND_PROP_ASPECTRATIO: + #if defined (HAVE_QT) + cvSetRatioWindow_QT(name,prop_value); + #endif + break; + + default:; + } +} + +/* return -1 if error */ +CV_IMPL double cvGetWindowProperty(const char* name, int prop_id) +{ + if (!name) + return -1; + + switch(prop_id) + { + case CV_WND_PROP_FULLSCREEN: + + #if defined (HAVE_QT) + return cvGetModeWindow_QT(name); + #elif defined WIN32 || defined _WIN32 + return cvGetModeWindow_W32(name); + #elif defined (HAVE_GTK) + return cvGetModeWindow_GTK(name); + #elif defined (HAVE_CARBON) + return cvGetModeWindow_CARBON(name); + #elif defined (HAVE_COCOA) + return cvGetModeWindow_COCOA(name); + #else + return -1; + #endif + break; + + case CV_WND_PROP_AUTOSIZE: + + #if defined (HAVE_QT) + return cvGetPropWindow_QT(name); + #elif defined WIN32 || defined _WIN32 + return cvGetPropWindowAutoSize_W32(name); + #elif defined (HAVE_GTK) + return cvGetPropWindowAutoSize_GTK(name); + #else + return -1; + #endif + break; + + case CV_WND_PROP_ASPECTRATIO: + + #if defined (HAVE_QT) + return cvGetRatioWindow_QT(name); + #elif defined WIN32 || defined _WIN32 + return cvGetRatioWindow_W32(name); + #elif defined (HAVE_GTK) + return cvGetRatioWindow_GTK(name); + #else + return -1; + #endif + break; + + case CV_WND_PROP_OPENGL: + + #if defined (HAVE_QT) + return cvGetOpenGlProp_QT(name); + #elif defined WIN32 || defined _WIN32 + return cvGetOpenGlProp_W32(name); + #elif defined (HAVE_GTK) + return cvGetOpenGlProp_GTK(name); + #else + return -1; + #endif + break; + + default: + return -1; + } +} + +void cv::namedWindow( const string& winname, int flags ) +{ + cvNamedWindow( winname.c_str(), flags ); +} + +void cv::destroyWindow( const string& winname ) +{ + cvDestroyWindow( winname.c_str() ); +} + +void cv::destroyAllWindows() +{ + cvDestroyAllWindows(); +} + +void cv::resizeWindow( const string& winname, int width, int height ) +{ + cvResizeWindow( winname.c_str(), width, height ); +} + +void cv::moveWindow( const string& winname, int x, int y ) +{ + cvMoveWindow( winname.c_str(), x, y ); +} + +void cv::setWindowProperty(const string& winname, int prop_id, double prop_value) +{ + cvSetWindowProperty( winname.c_str(), prop_id, prop_value); +} + +double cv::getWindowProperty(const string& winname, int prop_id) +{ + return cvGetWindowProperty(winname.c_str(), prop_id); +} + +int cv::waitKey(int delay) +{ + return cvWaitKey(delay); +} + +int cv::createTrackbar(const string& trackbarName, const string& winName, + int* value, int count, TrackbarCallback callback, + void* userdata) +{ + return cvCreateTrackbar2(trackbarName.c_str(), winName.c_str(), + value, count, callback, userdata); +} + +void cv::setTrackbarPos( const string& trackbarName, const string& winName, int value ) +{ + cvSetTrackbarPos(trackbarName.c_str(), winName.c_str(), value ); +} + +int cv::getTrackbarPos( const string& trackbarName, const string& winName ) +{ + return cvGetTrackbarPos(trackbarName.c_str(), winName.c_str()); +} + +void cv::setMouseCallback( const string& windowName, MouseCallback onMouse, void* param) +{ + cvSetMouseCallback(windowName.c_str(), onMouse, param); +} + +int cv::startWindowThread() +{ + return cvStartWindowThread(); +} + +// OpenGL support + +void cv::setOpenGlDrawCallback(const string& name, OpenGlDrawCallback callback, void* userdata) +{ + cvSetOpenGlDrawCallback(name.c_str(), callback, userdata); +} + +void cv::setOpenGlContext(const string& windowName) +{ + cvSetOpenGlContext(windowName.c_str()); +} + +void cv::updateWindow(const string& windowName) +{ + cvUpdateWindow(windowName.c_str()); +} + +#ifdef HAVE_OPENGL +namespace +{ + const int CV_TEXTURE_MAGIC_VAL = 0x00287653; + const int CV_POINT_CLOUD_MAGIC_VAL = 0x00287654; + + struct GlObjBase + { + int flag; + GlObjBase* next; + GlObjBase* prev; + std::string winname; + + virtual ~GlObjBase() {} + }; + + GlObjBase* g_glObjs = 0; + + GlObjBase* findGlObjByName(const std::string& winname) + { + GlObjBase* obj = g_glObjs; + + while(obj && obj->winname != winname) + obj = obj->next; + + return obj; + } + + void addGlObj(GlObjBase* glObj) + { + glObj->next = g_glObjs; + glObj->prev = 0; + if (g_glObjs) + g_glObjs->prev = glObj; + g_glObjs = glObj; + } + + void removeGlObj(GlObjBase* glObj) + { + if (glObj->prev) + glObj->prev->next = glObj->next; + else + g_glObjs = glObj->next; + + if (glObj->next) + glObj->next->prev = glObj->prev; + + delete glObj; + } + + struct GlObjTex : GlObjBase + { + cv::GlTexture tex; + }; + + void CV_CDECL glDrawTextureCallback(void* userdata) + { + GlObjTex* texObj = static_cast(userdata); + + CV_DbgAssert(texObj->flag == CV_TEXTURE_MAGIC_VAL); + + static cv::GlCamera glCamera; + + glCamera.setupProjectionMatrix(); + + cv::render(texObj->tex); + } + + struct GlObjPointCloud : GlObjBase + { + cv::GlArrays arr; + cv::GlCamera camera; + }; + + void CV_CDECL glDrawPointCloudCallback(void* userdata) + { + GlObjPointCloud* pointCloudObj = static_cast(userdata); + + CV_DbgAssert(pointCloudObj->flag == CV_POINT_CLOUD_MAGIC_VAL); + + pointCloudObj->camera.setupProjectionMatrix(); + pointCloudObj->camera.setupModelViewMatrix(); + + cv::render(pointCloudObj->arr); + } + + void CV_CDECL glCleanCallback(void* userdata) + { + GlObjBase* glObj = static_cast(userdata); + + removeGlObj(glObj); + } +} +#endif // HAVE_OPENGL + +void cv::imshow( const string& winname, InputArray _img ) +{ +#ifndef HAVE_OPENGL + Mat img = _img.getMat(); + CvMat c_img = img; + cvShowImage(winname.c_str(), &c_img); +#else + double useGl = getWindowProperty(winname, WND_PROP_OPENGL); + if (useGl <= 0) + { + Mat img = _img.getMat(); + CvMat c_img = img; + cvShowImage(winname.c_str(), &c_img); + } + else + { + double autoSize = getWindowProperty(winname, WND_PROP_AUTOSIZE); + + if (autoSize > 0) + { + Size size = _img.size(); + resizeWindow(winname, size.width, size.height); + } + + setOpenGlContext(winname); + + GlObjBase* glObj = findGlObjByName(winname); + + if (glObj && glObj->flag != CV_TEXTURE_MAGIC_VAL) + { + icvSetOpenGlCleanCallback(winname.c_str(), 0, 0); + glObj = 0; + } + + if (glObj) + { + GlObjTex* texObj = static_cast(glObj); + texObj->tex.copyFrom(_img); + } + else + { + GlObjTex* texObj = new GlObjTex; + texObj->tex.copyFrom(_img); + + glObj = texObj; + glObj->flag = CV_TEXTURE_MAGIC_VAL; + glObj->winname = winname; + + addGlObj(glObj); + + icvSetOpenGlCleanCallback(winname.c_str(), glCleanCallback, glObj); + } + + setOpenGlDrawCallback(winname, glDrawTextureCallback, glObj); + + updateWindow(winname); + } +#endif +} + +void cv::pointCloudShow(const string& winname, const GlCamera& camera, const GlArrays& arr) +{ +#ifndef HAVE_OPENGL + CV_Error(CV_OpenGlNotSupported, "The library is compiled without OpenGL support"); + (void)winname; + (void)camera; + (void)arr; +#else + namedWindow(winname, WINDOW_OPENGL); + + setOpenGlContext(winname); + + GlObjBase* glObj = findGlObjByName(winname); + + if (glObj && glObj->flag != CV_POINT_CLOUD_MAGIC_VAL) + { + icvSetOpenGlCleanCallback(winname.c_str(), 0, 0); + glObj = 0; + } + + if (glObj) + { + GlObjPointCloud* pointCloudObj = static_cast(glObj); + pointCloudObj->arr = arr; + pointCloudObj->camera = camera; + } + else + { + GlObjPointCloud* pointCloudObj = new GlObjPointCloud; + pointCloudObj->arr = arr; + pointCloudObj->camera = camera; + + glObj = pointCloudObj; + glObj->flag = CV_POINT_CLOUD_MAGIC_VAL; + glObj->winname = winname; + + addGlObj(glObj); + + icvSetOpenGlCleanCallback(winname.c_str(), glCleanCallback, glObj); + } + + setOpenGlDrawCallback(winname, glDrawPointCloudCallback, glObj); + + updateWindow(winname); +#endif +} + +void cv::pointCloudShow(const std::string& winname, const cv::GlCamera& camera, InputArray points, InputArray colors) +{ +#ifndef HAVE_OPENGL + (void)winname; + (void)camera; + (void)points; + (void)colors; + CV_Error(CV_OpenGlNotSupported, "The library is compiled without OpenGL support"); +#else + namedWindow(winname, WINDOW_OPENGL); + + setOpenGlContext(winname); + + GlObjBase* glObj = findGlObjByName(winname); + + if (glObj && glObj->flag != CV_POINT_CLOUD_MAGIC_VAL) + { + icvSetOpenGlCleanCallback(winname.c_str(), 0, 0); + glObj = 0; + } + + if (glObj) + { + GlObjPointCloud* pointCloudObj = static_cast(glObj); + + pointCloudObj->arr.setVertexArray(points); + if (colors.empty()) + pointCloudObj->arr.resetColorArray(); + else + pointCloudObj->arr.setColorArray(colors); + + pointCloudObj->camera = camera; + } + else + { + GlObjPointCloud* pointCloudObj = new GlObjPointCloud; + + pointCloudObj->arr.setVertexArray(points); + if (!colors.empty()) + pointCloudObj->arr.setColorArray(colors); + + pointCloudObj->camera = camera; + + glObj = pointCloudObj; + glObj->flag = CV_POINT_CLOUD_MAGIC_VAL; + glObj->winname = winname; + + addGlObj(glObj); + + icvSetOpenGlCleanCallback(winname.c_str(), glCleanCallback, glObj); + } + + setOpenGlDrawCallback(winname, glDrawPointCloudCallback, glObj); + + updateWindow(winname); +#endif +} + +// Without OpenGL + +#ifndef HAVE_OPENGL + +CV_IMPL void cvSetOpenGlDrawCallback(const char*, CvOpenGlDrawCallback, void*) +{ + CV_Error(CV_OpenGlNotSupported, "The library is compiled without OpenGL support"); +} + +CV_IMPL void cvSetOpenGlContext(const char*) +{ + CV_Error(CV_OpenGlNotSupported, "The library is compiled without OpenGL support"); +} + +CV_IMPL void cvUpdateWindow(const char*) +{ + CV_Error(CV_OpenGlNotSupported, "The library is compiled without OpenGL support"); +} + +void icvSetOpenGlCleanCallback(const char*, CvOpenGlCleanCallback, void*) +{ + CV_Error(CV_OpenGlNotSupported, "The library is compiled without OpenGL support"); +} + +#endif // !HAVE_OPENGL + +#if defined (HAVE_QT) + +CvFont cv::fontQt(const string& nameFont, int pointSize, Scalar color, int weight, int style, int /*spacing*/) +{ +return cvFontQt(nameFont.c_str(), pointSize,color,weight, style); +} + +void cv::addText( const Mat& img, const string& text, Point org, CvFont font) +{ + CvMat _img = img; + cvAddText( &_img, text.c_str(), org,&font); +} + +void cv::displayStatusBar(const string& name, const string& text, int delayms) +{ + cvDisplayStatusBar(name.c_str(),text.c_str(), delayms); +} + +void cv::displayOverlay(const string& name, const string& text, int delayms) +{ + cvDisplayOverlay(name.c_str(),text.c_str(), delayms); +} + +int cv::startLoop(int (*pt2Func)(int argc, char *argv[]), int argc, char* argv[]) +{ + return cvStartLoop(pt2Func, argc, argv); +} + +void cv::stopLoop() +{ + cvStopLoop(); +} + +void cv::saveWindowParameters(const string& windowName) +{ + cvSaveWindowParameters(windowName.c_str()); +} + +void cv::loadWindowParameters(const string& windowName) +{ + cvLoadWindowParameters(windowName.c_str()); +} + +int cv::createButton(const string& button_name, ButtonCallback on_change, void* userdata, int button_type , bool initial_button_state ) +{ + return cvCreateButton(button_name.c_str(), on_change, userdata, button_type , initial_button_state ); +} + +#endif + +#if defined WIN32 || defined _WIN32 // see window_w32.cpp +#elif defined (HAVE_GTK) // see window_gtk.cpp +#elif defined (HAVE_COCOA) // see window_carbon.cpp +#elif defined (HAVE_CARBON) +#elif defined (HAVE_QT) //YV see window_QT.cpp + +#else + +// No windowing system present at compile time ;-( +// +// We will build place holders that don't break the API but give an error +// at runtime. This way people can choose to replace an installed HighGUI +// version with a more capable one without a need to recompile dependent +// applications or libraries. + + +#define CV_NO_GUI_ERROR(funcname) \ + cvError( CV_StsError, funcname, \ + "The function is not implemented. " \ + "Rebuild the library with Windows, GTK+ 2.x or Carbon support. "\ + "If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script", \ + __FILE__, __LINE__ ) + + +CV_IMPL int cvNamedWindow( const char*, int ) +{ + CV_NO_GUI_ERROR("cvNamedWindow"); + return -1; +} + +CV_IMPL void cvDestroyWindow( const char* ) +{ + CV_NO_GUI_ERROR( "cvDestroyWindow" ); +} + +CV_IMPL void +cvDestroyAllWindows( void ) +{ + CV_NO_GUI_ERROR( "cvDestroyAllWindows" ); +} + +CV_IMPL void +cvShowImage( const char*, const CvArr* ) +{ + CV_NO_GUI_ERROR( "cvShowImage" ); +} + +CV_IMPL void cvResizeWindow( const char*, int, int ) +{ + CV_NO_GUI_ERROR( "cvResizeWindow" ); +} + +CV_IMPL void cvMoveWindow( const char*, int, int ) +{ + CV_NO_GUI_ERROR( "cvMoveWindow" ); +} + +CV_IMPL int +cvCreateTrackbar( const char*, const char*, + int*, int, CvTrackbarCallback ) +{ + CV_NO_GUI_ERROR( "cvCreateTrackbar" ); + return -1; +} + +CV_IMPL int +cvCreateTrackbar2( const char* /*trackbar_name*/, const char* /*window_name*/, + int* /*val*/, int /*count*/, CvTrackbarCallback2 /*on_notify2*/, + void* /*userdata*/ ) +{ + CV_NO_GUI_ERROR( "cvCreateTrackbar2" ); + return -1; +} + +CV_IMPL void +cvSetMouseCallback( const char*, CvMouseCallback, void* ) +{ + CV_NO_GUI_ERROR( "cvSetMouseCallback" ); +} + +CV_IMPL int cvGetTrackbarPos( const char*, const char* ) +{ + CV_NO_GUI_ERROR( "cvGetTrackbarPos" ); + return -1; +} + +CV_IMPL void cvSetTrackbarPos( const char*, const char*, int ) +{ + CV_NO_GUI_ERROR( "cvSetTrackbarPos" ); +} + +CV_IMPL void* cvGetWindowHandle( const char* ) +{ + CV_NO_GUI_ERROR( "cvGetWindowHandle" ); + return 0; +} + +CV_IMPL const char* cvGetWindowName( void* ) +{ + CV_NO_GUI_ERROR( "cvGetWindowName" ); + return 0; +} + +CV_IMPL int cvWaitKey( int ) +{ + CV_NO_GUI_ERROR( "cvWaitKey" ); + return -1; +} + +CV_IMPL int cvInitSystem( int , char** ) +{ + + CV_NO_GUI_ERROR( "cvInitSystem" ); + return -1; +} + +CV_IMPL int cvStartWindowThread() +{ + + CV_NO_GUI_ERROR( "cvStartWindowThread" ); + return -1; +} + +//-------- Qt --------- +CV_IMPL void cvAddText( const CvArr*, const char*, CvPoint , CvFont* ) +{ + CV_NO_GUI_ERROR("cvAddText"); +} + +CV_IMPL void cvDisplayStatusBar(const char* , const char* , int ) +{ + CV_NO_GUI_ERROR("cvDisplayStatusBar"); +} + +CV_IMPL void cvDisplayOverlay(const char* , const char* , int ) +{ + CV_NO_GUI_ERROR("cvNamedWindow"); +} + +CV_IMPL int cvStartLoop(int (*)(int argc, char *argv[]), int , char* argv[]) +{ + (void)argv; + CV_NO_GUI_ERROR("cvStartLoop"); + return -1; +} + +CV_IMPL void cvStopLoop() +{ + CV_NO_GUI_ERROR("cvStopLoop"); +} + +CV_IMPL void cvSaveWindowParameters(const char* ) +{ + CV_NO_GUI_ERROR("cvSaveWindowParameters"); +} + +// CV_IMPL void cvLoadWindowParameterss(const char* name) +// { +// CV_NO_GUI_ERROR("cvLoadWindowParameters"); +// } + +CV_IMPL int cvCreateButton(const char*, void (*)(int, void*), void*, int, int) +{ + CV_NO_GUI_ERROR("cvCreateButton"); + return -1; +} + + +#endif + +/* End of file. */ diff --git a/highgui/src/window_QT.cpp b/highgui/src/window_QT.cpp new file mode 100644 index 0000000..fe063c9 --- /dev/null +++ b/highgui/src/window_QT.cpp @@ -0,0 +1,3540 @@ +//IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. + + +// License Agreement +// For Open Source Computer Vision Library + +//Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +//Copyright (C) 2008-2010, Willow Garage Inc., all rights reserved. +//Third party copyrights are property of their respective owners. + +//Redistribution and use in source and binary forms, with or without modification, +//are permitted provided that the following conditions are met: + +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. + +// * Redistribution's 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. + +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. + +//This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. + +//--------------------Google Code 2010 -- Yannick Verdie--------------------// + + +#if defined(HAVE_QT) + +#include + +#include + +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +#ifdef HAVE_QT_OPENGL + #ifdef Q_WS_X11 + #include + #endif +#endif + + +//Static and global first +static GuiReceiver *guiMainThread = NULL; +static int parameterSystemC = 1; +static char* parameterSystemV[] = {(char*)""}; +static bool multiThreads = false; +static int last_key = -1; +QWaitCondition key_pressed; +QMutex mutexKey; +static const unsigned int threshold_zoom_img_region = 30; +//the minimum zoom value to start displaying the values in the grid +//that is also the number of pixel per grid + +static CvWinProperties* global_control_panel = NULL; +//end static and global + + +CV_IMPL CvFont cvFontQt(const char* nameFont, int pointSize,CvScalar color,int weight,int style, int spacing) +{ + /* + //nameFont <- only Qt + //CvScalar color <- only Qt (blue_component, green_component, red\_component[, alpha_component]) + int font_face;//<- style in Qt + const int* ascii; + const int* greek; + const int* cyrillic; + float hscale, vscale; + float shear; + int thickness;//<- weight in Qt + float dx;//spacing letter in Qt (0 default) in pixel + int line_type;//<- pointSize in Qt + */ + CvFont f = {nameFont,color,style,NULL,NULL,NULL,0,0,0,weight,spacing,pointSize}; + return f; +} + + +CV_IMPL void cvAddText(const CvArr* img, const char* text, CvPoint org, CvFont* font) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "putText", + Qt::AutoConnection, + Q_ARG(void*, (void*) img), + Q_ARG(QString,QString(text)), + Q_ARG(QPoint, QPoint(org.x,org.y)), + Q_ARG(void*,(void*) font)); +} + + +double cvGetRatioWindow_QT(const char* name) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + double result = -1; + QMetaObject::invokeMethod(guiMainThread, + "getRatioWindow", + //Qt::DirectConnection, + Qt::AutoConnection, + Q_RETURN_ARG(double, result), + Q_ARG(QString, QString(name))); + + return result; +} + + +void cvSetRatioWindow_QT(const char* name,double prop_value) +{ + + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "setRatioWindow", + Qt::AutoConnection, + Q_ARG(QString, QString(name)), + Q_ARG(double, prop_value)); +} + + +double cvGetPropWindow_QT(const char* name) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + double result = -1; + QMetaObject::invokeMethod(guiMainThread, + "getPropWindow", + //Qt::DirectConnection, + Qt::AutoConnection, + Q_RETURN_ARG(double, result), + Q_ARG(QString, QString(name))); + + return result; +} + + +void cvSetPropWindow_QT(const char* name,double prop_value) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "setPropWindow", + Qt::AutoConnection, + Q_ARG(QString, QString(name)), + Q_ARG(double, prop_value)); +} + + +void cvSetModeWindow_QT(const char* name, double prop_value) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "toggleFullScreen", + Qt::AutoConnection, + Q_ARG(QString, QString(name)), + Q_ARG(double, prop_value)); +} + + +double cvGetModeWindow_QT(const char* name) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + double result = -1; + + QMetaObject::invokeMethod(guiMainThread, + "isFullScreen", + Qt::AutoConnection, + Q_RETURN_ARG(double, result), + Q_ARG(QString, QString(name))); + + return result; +} + + +CV_IMPL void cvDisplayOverlay(const char* name, const char* text, int delayms) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "displayInfo", + Qt::AutoConnection, + //Qt::DirectConnection, + Q_ARG(QString, QString(name)), + Q_ARG(QString, QString(text)), + Q_ARG(int, delayms)); +} + + +CV_IMPL void cvSaveWindowParameters(const char* name) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "saveWindowParameters", + Qt::AutoConnection, + Q_ARG(QString, QString(name))); +} + + +CV_IMPL void cvLoadWindowParameters(const char* name) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "loadWindowParameters", + Qt::AutoConnection, + Q_ARG(QString, QString(name))); +} + + +CV_IMPL void cvDisplayStatusBar(const char* name, const char* text, int delayms) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "displayStatusBar", + Qt::AutoConnection, + //Qt::DirectConnection, + Q_ARG(QString, QString(name)), + Q_ARG(QString, QString(text)), + Q_ARG(int, delayms)); +} + + +CV_IMPL int cvWaitKey(int delay) +{ + int result = -1; + + if (!guiMainThread) + return result; + + unsigned long delayms = delay <= 0 ? ULONG_MAX : delay; //in milliseconds + + if (multiThreads) + { + mutexKey.lock(); + if (key_pressed.wait(&mutexKey, delayms)) //false if timeout + { + result = last_key; + } + last_key = -1; + mutexKey.unlock(); + } + else + { + //cannot use wait here because events will not be distributed before processEvents (the main eventLoop is broken) + //so I create a Thread for the QTimer + + if (delay > 0) + guiMainThread->timer->start(delay); + + //QMutex dummy; + + while (!guiMainThread->bTimeOut) + { + qApp->processEvents(QEventLoop::AllEvents); + + if (!guiMainThread)//when all the windows are deleted + return result; + + mutexKey.lock(); + if (last_key != -1) + { + result = last_key; + last_key = -1; + guiMainThread->timer->stop(); + //printf("keypressed\n"); + } + mutexKey.unlock(); + + if (result!=-1) + { + break; + } + else + { + /* + * //will not work, I broke the event loop !!!! + dummy.lock(); + QWaitCondition waitCondition; + waitCondition.wait(&dummy, 2); + */ + + //to decrease CPU usage + //sleep 1 millisecond +#if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64 + Sleep(1); +#else + usleep(1000); +#endif + } + } + + guiMainThread->bTimeOut = false; + } + + return result; +} + + +//Yannick Verdie +//This function is experimental and some functions (such as cvSet/getWindowProperty will not work) +//We recommend not using this function for now +CV_IMPL int cvStartLoop(int (*pt2Func)(int argc, char *argv[]), int argc, char* argv[]) +{ + multiThreads = true; + QFuture future = QtConcurrent::run(pt2Func, argc, argv); + return guiMainThread->start(); +} + + +CV_IMPL void cvStopLoop() +{ + qApp->exit(); +} + + +static CvWindow* icvFindWindowByName(QString name) +{ + CvWindow* window = 0; + + //This is not a very clean way to do the stuff. Indeed, QAction automatically generate toolTil (QLabel) + //that can be grabbed here and crash the code at 'w->param_name==name'. + foreach (QWidget* widget, QApplication::topLevelWidgets()) + { + if (widget->isWindow() && !widget->parentWidget())//is a window without parent + { + CvWinModel* temp = (CvWinModel*) widget; + + if (temp->type == type_CvWindow) + { + CvWindow* w = (CvWindow*) temp; + if (w->windowTitle() == name) + { + window = w; + break; + } + } + } + } + + return window; +} + + +static CvBar* icvFindBarByName(QBoxLayout* layout, QString name_bar, typeBar type) +{ + if (!layout) + return NULL; + + int stop_index = layout->layout()->count(); + + for (int i = 0; i < stop_index; ++i) + { + CvBar* t = (CvBar*) layout->layout()->itemAt(i); + + if (t->type == type && t->name_bar == name_bar) + return t; + } + + return NULL; +} + + +static CvTrackbar* icvFindTrackBarByName(const char* name_trackbar, const char* name_window, QBoxLayout* layout = NULL) +{ + QString nameQt(name_trackbar); + + if (!name_window && global_control_panel) //window name is null and we have a control panel + layout = global_control_panel->myLayout; + + if (!layout) + { + QPointer w = icvFindWindowByName(QLatin1String(name_window)); + + if (!w) + CV_Error(CV_StsNullPtr, "NULL window handler"); + + if (w->param_gui_mode == CV_GUI_NORMAL) + return (CvTrackbar*) icvFindBarByName(w->myBarLayout, nameQt, type_CvTrackbar); + + if (w->param_gui_mode == CV_GUI_EXPANDED) + { + CvBar* result = icvFindBarByName(w->myBarLayout, nameQt, type_CvTrackbar); + + if (result) + return (CvTrackbar*) result; + + return (CvTrackbar*) icvFindBarByName(global_control_panel->myLayout, nameQt, type_CvTrackbar); + } + + return NULL; + } + else + { + //layout was specified + return (CvTrackbar*) icvFindBarByName(layout, nameQt, type_CvTrackbar); + } +} + +/* +static CvButtonbar* icvFindButtonBarByName(const char* button_name, QBoxLayout* layout) +{ + QString nameQt(button_name); + return (CvButtonbar*) icvFindBarByName(layout, nameQt, type_CvButtonbar); +} +*/ + +static int icvInitSystem(int* c, char** v) +{ + //"For any GUI application using Qt, there is precisely one QApplication object" + if (!QApplication::instance()) + { + new QApplication(*c, v); + + qDebug() << "init done"; + +#ifdef HAVE_QT_OPENGL + qDebug() << "opengl support available"; +#endif + } + + return 0; +} + + +CV_IMPL int cvInitSystem(int, char**) +{ + icvInitSystem(¶meterSystemC, parameterSystemV); + return 0; +} + + +CV_IMPL int cvNamedWindow(const char* name, int flags) +{ + if (!guiMainThread) + guiMainThread = new GuiReceiver; + + if (multiThreads) + QMetaObject::invokeMethod(guiMainThread, + "createWindow", + Qt::BlockingQueuedConnection, + Q_ARG(QString, QString(name)), + Q_ARG(int, flags)); + else + guiMainThread->createWindow(QString(name), flags); + + return 1; //Dummy value +} + + +CV_IMPL void cvDestroyWindow(const char* name) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "destroyWindow", + //Qt::BlockingQueuedConnection, + Qt::AutoConnection, + Q_ARG(QString, QString(name))); +} + + +CV_IMPL void cvDestroyAllWindows() +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "destroyAllWindow", + //Qt::BlockingQueuedConnection, + Qt::AutoConnection); +} + + +CV_IMPL void* cvGetWindowHandle(const char* name) +{ + if (!name) + CV_Error( CV_StsNullPtr, "NULL name string" ); + + return (void*) icvFindWindowByName(QLatin1String(name)); +} + + +CV_IMPL const char* cvGetWindowName(void* window_handle) +{ + if( !window_handle ) + CV_Error( CV_StsNullPtr, "NULL window handler" ); + + return ((CvWindow*)window_handle)->windowTitle().toLatin1().data(); +} + + +CV_IMPL void cvMoveWindow(const char* name, int x, int y) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "moveWindow", + //Qt::BlockingQueuedConnection, + Qt::AutoConnection, + Q_ARG(QString, QString(name)), + Q_ARG(int, x), + Q_ARG(int, y)); +} + + +CV_IMPL void cvResizeWindow(const char* name, int width, int height) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "resizeWindow", + //Qt::BlockingQueuedConnection, + Qt::AutoConnection, + Q_ARG(QString, QString(name)), + Q_ARG(int, width), + Q_ARG(int, height)); +} + + +CV_IMPL int cvCreateTrackbar2(const char* name_bar, const char* window_name, int* val, int count, CvTrackbarCallback2 on_notify, void* userdata) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "addSlider2", + Qt::AutoConnection, + Q_ARG(QString, QString(name_bar)), + Q_ARG(QString, QString(window_name)), + Q_ARG(void*, (void*)val), + Q_ARG(int, count), + Q_ARG(void*, (void*)on_notify), + Q_ARG(void*, (void*)userdata)); + + return 1; //dummy value +} + + +CV_IMPL int cvStartWindowThread() +{ + return 0; +} + + +CV_IMPL int cvCreateTrackbar(const char* name_bar, const char* window_name, int* value, int count, CvTrackbarCallback on_change) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "addSlider", + Qt::AutoConnection, + Q_ARG(QString, QString(name_bar)), + Q_ARG(QString, QString(window_name)), + Q_ARG(void*, (void*)value), + Q_ARG(int, count), + Q_ARG(void*, (void*)on_change)); + + return 1; //dummy value +} + + +CV_IMPL int cvCreateButton(const char* button_name, CvButtonCallback on_change, void* userdata, int button_type, int initial_button_state) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + if (initial_button_state < 0 || initial_button_state > 1) + return 0; + + QMetaObject::invokeMethod(guiMainThread, + "addButton", + Qt::AutoConnection, + Q_ARG(QString, QString(button_name)), + Q_ARG(int, button_type), + Q_ARG(int, initial_button_state), + Q_ARG(void*, (void*)on_change), + Q_ARG(void*, userdata)); + + return 1;//dummy value +} + + +CV_IMPL int cvGetTrackbarPos(const char* name_bar, const char* window_name) +{ + int result = -1; + + QPointer t = icvFindTrackBarByName(name_bar, window_name); + + if (t) + result = t->slider->value(); + + return result; +} + + +CV_IMPL void cvSetTrackbarPos(const char* name_bar, const char* window_name, int pos) +{ + QPointer t = icvFindTrackBarByName(name_bar, window_name); + + if (t) + t->slider->setValue(pos); +} + + +/* assign callback for mouse events */ +CV_IMPL void cvSetMouseCallback(const char* window_name, CvMouseCallback on_mouse, void* param) +{ + QPointer w = icvFindWindowByName(QLatin1String(window_name)); + + if (!w) + CV_Error(CV_StsNullPtr, "NULL window handler"); + + w->setMouseCallBack(on_mouse, param); + +} + + +CV_IMPL void cvShowImage(const char* name, const CvArr* arr) +{ + if (!guiMainThread) + guiMainThread = new GuiReceiver; + + QMetaObject::invokeMethod(guiMainThread, + "showImage", + //Qt::BlockingQueuedConnection, + Qt::DirectConnection, + Q_ARG(QString, QString(name)), + Q_ARG(void*, (void*)arr)); +} + + +#ifdef HAVE_QT_OPENGL + +CV_IMPL void cvSetOpenGlDrawCallback(const char* window_name, CvOpenGlDrawCallback callback, void* userdata) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "setOpenGlDrawCallback", + Qt::AutoConnection, + Q_ARG(QString, QString(window_name)), + Q_ARG(void*, (void*)callback), + Q_ARG(void*, userdata)); +} + + +void icvSetOpenGlCleanCallback(const char* window_name, CvOpenGlCleanCallback callback, void* userdata) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "setOpenGlCleanCallback", + Qt::AutoConnection, + Q_ARG(QString, QString(window_name)), + Q_ARG(void*, (void*)callback), + Q_ARG(void*, userdata)); +} + + +CV_IMPL void cvSetOpenGlContext(const char* window_name) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "setOpenGlContext", + Qt::AutoConnection, + Q_ARG(QString, QString(window_name))); +} + + +CV_IMPL void cvUpdateWindow(const char* window_name) +{ + if (!guiMainThread) + CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); + + QMetaObject::invokeMethod(guiMainThread, + "updateWindow", + Qt::AutoConnection, + Q_ARG(QString, QString(window_name))); +} + +#endif + + +double cvGetOpenGlProp_QT(const char* name) +{ + double result = -1; + + if (guiMainThread) + { + QMetaObject::invokeMethod(guiMainThread, + "isOpenGl", + Qt::AutoConnection, + Q_RETURN_ARG(double, result), + Q_ARG(QString, QString(name))); + } + + return result; +} + + +////////////////////////////////////////////////////// +// GuiReceiver + + +GuiReceiver::GuiReceiver() : bTimeOut(false), nb_windows(0) +{ + doesExternalQAppExist = (QApplication::instance() != 0); + icvInitSystem(¶meterSystemC, parameterSystemV); + + timer = new QTimer(this); + QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timeOut())); + timer->setSingleShot(true); +} + + +void GuiReceiver::isLastWindow() +{ + if (--nb_windows <= 0) + { + delete guiMainThread;//delete global_control_panel too + guiMainThread = NULL; + + if (!doesExternalQAppExist) + { + qApp->quit(); + } + } +} + + +GuiReceiver::~GuiReceiver() +{ + if (global_control_panel) + { + delete global_control_panel; + global_control_panel = NULL; + } +} + + +void GuiReceiver::putText(void* arr, QString text, QPoint org, void* arg2) +{ + CV_Assert(arr); + + CvMat* mat, stub; + mat = cvGetMat(arr, &stub); + + int nbChannelOriginImage = cvGetElemType(mat); + if (nbChannelOriginImage != CV_8UC3) return; //for now, font works only with 8UC3 + + QImage qimg(mat->data.ptr, mat->cols, mat->rows, mat->step, QImage::Format_RGB888); + + CvFont* font = (CvFont*)arg2; + + QPainter qp(&qimg); + if (font) + { + QFont f(font->nameFont, font->line_type/*PointSize*/, font->thickness/*weight*/); + f.setStyle((QFont::Style) font->font_face/*style*/); + f.setLetterSpacing(QFont::AbsoluteSpacing, font->dx/*spacing*/); + //cvScalar(blue_component, green_component, red_component[, alpha_component]) + //Qt map non-transparent to 0xFF and transparent to 0 + //OpenCV scalar is the reverse, so 255-font->color.val[3] + qp.setPen(QColor(font->color.val[2], font->color.val[1], font->color.val[0], 255 - font->color.val[3])); + qp.setFont(f); + } + qp.drawText(org, text); + qp.end(); +} + + +void GuiReceiver::saveWindowParameters(QString name) +{ + QPointer w = icvFindWindowByName(name); + + if (w) + w->writeSettings(); +} + + +void GuiReceiver::loadWindowParameters(QString name) +{ + QPointer w = icvFindWindowByName(name); + + if (w) + w->readSettings(); +} + + +double GuiReceiver::getRatioWindow(QString name) +{ + QPointer w = icvFindWindowByName(name); + + if (!w) + return -1; + + return w->getRatio(); +} + + +void GuiReceiver::setRatioWindow(QString name, double arg2) +{ + QPointer w = icvFindWindowByName( name.toLatin1().data() ); + + if (!w) + return; + + int flags = (int) arg2; + + w->setRatio(flags); +} + + +double GuiReceiver::getPropWindow(QString name) +{ + QPointer w = icvFindWindowByName(name); + + if (!w) + return -1; + + return (double) w->getPropWindow(); +} + + +void GuiReceiver::setPropWindow(QString name, double arg2) +{ + QPointer w = icvFindWindowByName(name); + + if (!w) + return; + + int flags = (int) arg2; + + w->setPropWindow(flags); +} + + +double GuiReceiver::isFullScreen(QString name) +{ + QPointer w = icvFindWindowByName(name); + + if (!w) + return -1; + + return w->isFullScreen() ? CV_WINDOW_FULLSCREEN : CV_WINDOW_NORMAL; +} + + +void GuiReceiver::toggleFullScreen(QString name, double arg2) +{ + QPointer w = icvFindWindowByName(name); + + if (!w) + return; + + int flags = (int) arg2; + + w->toggleFullScreen(flags); +} + + +void GuiReceiver::createWindow(QString name, int flags) +{ + if (!qApp) + CV_Error(CV_StsNullPtr, "NULL session handler" ); + + // Check the name in the storage + if (icvFindWindowByName(name.toLatin1().data())) + { + return; + } + + nb_windows++; + new CvWindow(name, flags); +} + + +void GuiReceiver::timeOut() +{ + bTimeOut = true; +} + + +void GuiReceiver::displayInfo(QString name, QString text, int delayms) +{ + QPointer w = icvFindWindowByName(name); + + if (w) + w->displayInfo(text, delayms); +} + + +void GuiReceiver::displayStatusBar(QString name, QString text, int delayms) +{ + QPointer w = icvFindWindowByName(name); + + if (w) + w->displayStatusBar(text, delayms); +} + + +void GuiReceiver::showImage(QString name, void* arr) +{ + QPointer w = icvFindWindowByName(name); + + if (!w) //as observed in the previous implementation (W32, GTK or Carbon), create a new window is the pointer returned is null + { + cvNamedWindow(name.toLatin1().data()); + w = icvFindWindowByName(name); + } + + if (!w || !arr) + return; // keep silence here. + + if (w->isOpenGl()) + { + CvMat* mat, stub; + + mat = cvGetMat(arr, &stub); + + cv::Mat im(mat); + cv::imshow(name.toStdString(), im); + } + else + { + w->updateImage(arr); + } + + if (w->isHidden()) + w->show(); +} + + +void GuiReceiver::destroyWindow(QString name) +{ + QPointer w = icvFindWindowByName(name); + + if (w) + { + w->close(); + + //in not-multiThreads mode, looks like the window is hidden but not deleted + //so I do it manually + //otherwise QApplication do it for me if the exec command was executed (in multiThread mode) + if (!multiThreads) + delete w; + } +} + + +void GuiReceiver::destroyAllWindow() +{ + if (!qApp) + CV_Error(CV_StsNullPtr, "NULL session handler" ); + + if (multiThreads) + { + // WARNING: this could even close windows from an external parent app + //#TODO check externalQAppExists and in case it does, close windows carefully, + // i.e. apply the className-check from below... + qApp->closeAllWindows(); + } + else + { + bool isWidgetDeleted = true; + while(isWidgetDeleted) + { + isWidgetDeleted = false; + QWidgetList list = QApplication::topLevelWidgets(); + for (int i = 0; i < list.count(); i++) + { + QObject *obj = list.at(i); + if (obj->metaObject()->className() == QString("CvWindow")) + { + delete obj; + isWidgetDeleted = true; + break; + } + } + } + } +} + + +void GuiReceiver::moveWindow(QString name, int x, int y) +{ + QPointer w = icvFindWindowByName(name); + + if (w) + w->move(x, y); +} + + +void GuiReceiver::resizeWindow(QString name, int width, int height) +{ + QPointer w = icvFindWindowByName(name); + + if (w) + { + w->showNormal(); + w->setViewportSize(QSize(width, height)); + } +} + + +void GuiReceiver::enablePropertiesButtonEachWindow() +{ + //For each window, enable window property button + foreach (QWidget* widget, QApplication::topLevelWidgets()) + { + if (widget->isWindow() && !widget->parentWidget()) //is a window without parent + { + CvWinModel* temp = (CvWinModel*) widget; + if (temp->type == type_CvWindow) + { + CvWindow* w = (CvWindow*) widget; + + //active window properties button + w->enablePropertiesButton(); + } + } + } +} + + +void GuiReceiver::addButton(QString button_name, int button_type, int initial_button_state, void* on_change, void* userdata) +{ + if (!global_control_panel) + return; + + QPointer b; + + if (global_control_panel->myLayout->count() == 0) //if that is the first button attach to the control panel, create a new button bar + { + b = CvWindow::createButtonBar(button_name); //the bar has the name of the first button attached to it + enablePropertiesButtonEachWindow(); + + } + else + { + CvBar* lastbar = (CvBar*) global_control_panel->myLayout->itemAt(global_control_panel->myLayout->count() - 1); + + if (lastbar->type == type_CvTrackbar) //if last bar is a trackbar, create a new buttonbar, else, attach to the current bar + b = CvWindow::createButtonBar(button_name); //the bar has the name of the first button attached to it + else + b = (CvButtonbar*) lastbar; + + } + + b->addButton(button_name, (CvButtonCallback) on_change, userdata, button_type, initial_button_state); +} + + +void GuiReceiver::addSlider2(QString bar_name, QString window_name, void* value, int count, void* on_change, void *userdata) +{ + QBoxLayout *layout = NULL; + QPointer w; + + if (!window_name.isEmpty()) + { + w = icvFindWindowByName(window_name); + + if (!w) + return; + } + else + { + if (global_control_panel) + layout = global_control_panel->myLayout; + } + + QPointer t = icvFindTrackBarByName(bar_name.toLatin1().data(), window_name.toLatin1().data(), layout); + + if (t) //trackbar exists + return; + + if (!value) + CV_Error(CV_StsNullPtr, "NULL value pointer" ); + + if (count <= 0) //count is the max value of the slider, so must be bigger than 0 + CV_Error(CV_StsNullPtr, "Max value of the slider must be bigger than 0" ); + + CvWindow::addSlider2(w, bar_name, (int*)value, count, (CvTrackbarCallback2) on_change, userdata); +} + + +void GuiReceiver::addSlider(QString bar_name, QString window_name, void* value, int count, void* on_change) +{ + QBoxLayout *layout = NULL; + QPointer w; + + if (!window_name.isEmpty()) + { + w = icvFindWindowByName(window_name); + + if (!w) + return; + } + else + { + if (global_control_panel) + layout = global_control_panel->myLayout; + } + + QPointer t = icvFindTrackBarByName(bar_name.toLatin1().data(), window_name.toLatin1().data(), layout); + + if (t) //trackbar exists + return; + + if (!value) + CV_Error(CV_StsNullPtr, "NULL value pointer" ); + + if (count <= 0) //count is the max value of the slider, so must be bigger than 0 + CV_Error(CV_StsNullPtr, "Max value of the slider must be bigger than 0" ); + + CvWindow::addSlider(w, bar_name, (int*)value, count, (CvTrackbarCallback) on_change); +} + + +int GuiReceiver::start() +{ + return qApp->exec(); +} + + +void GuiReceiver::setOpenGlDrawCallback(QString name, void* callback, void* userdata) +{ + QPointer w = icvFindWindowByName(name); + + if (w) + w->setOpenGlDrawCallback((CvOpenGlDrawCallback) callback, userdata); +} + +void GuiReceiver::setOpenGlCleanCallback(QString name, void* callback, void* userdata) +{ + QPointer w = icvFindWindowByName(name); + + if (w) + w->setOpenGlCleanCallback((CvOpenGlCleanCallback) callback, userdata); +} + +void GuiReceiver::setOpenGlContext(QString name) +{ + QPointer w = icvFindWindowByName(name); + + if (w) + w->makeCurrentOpenGlContext(); +} + +void GuiReceiver::updateWindow(QString name) +{ + QPointer w = icvFindWindowByName(name); + + if (w) + w->updateGl(); +} + +double GuiReceiver::isOpenGl(QString name) +{ + double result = -1; + + QPointer w = icvFindWindowByName(name); + + if (w) + result = (double) w->isOpenGl(); + + return result; +} + + +////////////////////////////////////////////////////// +// CvTrackbar + + +CvTrackbar::CvTrackbar(CvWindow* arg, QString name, int* value, int _count, CvTrackbarCallback2 on_change, void* data) +{ + callback = NULL; + callback2 = on_change; + userdata = data; + + create(arg, name, value, _count); +} + + +CvTrackbar::CvTrackbar(CvWindow* arg, QString name, int* value, int _count, CvTrackbarCallback on_change) +{ + callback = on_change; + callback2 = NULL; + userdata = NULL; + + create(arg, name, value, _count); +} + + +void CvTrackbar::create(CvWindow* arg, QString name, int* value, int _count) +{ + type = type_CvTrackbar; + myparent = arg; + name_bar = name; + setObjectName(name_bar); + dataSlider = value; + + slider = new QSlider(Qt::Horizontal); + slider->setFocusPolicy(Qt::StrongFocus); + slider->setMinimum(0); + slider->setMaximum(_count); + slider->setPageStep(5); + slider->setValue(*value); + slider->setTickPosition(QSlider::TicksBelow); + + + //Change style of the Slider + //slider->setStyleSheet(str_Trackbar_css); + + QFile qss(":/stylesheet-trackbar"); + if (qss.open(QFile::ReadOnly)) + { + slider->setStyleSheet(QLatin1String(qss.readAll())); + qss.close(); + } + + + //this next line does not work if we change the style with a stylesheet, why ? (bug in QT ?) + //slider->setTickPosition(QSlider::TicksBelow); + label = new QPushButton; + label->setFlat(true); + setLabel(slider->value()); + + + QObject::connect(slider, SIGNAL(valueChanged(int)), this, SLOT(update(int))); + + QObject::connect(label, SIGNAL(clicked()), this, SLOT(createDialog())); + + //label->setStyleSheet("QPushButton:disabled {color: black}"); + + addWidget(label, Qt::AlignLeft);//name + value + addWidget(slider, Qt::AlignCenter);//slider +} + + +void CvTrackbar::createDialog() +{ + bool ok = false; + + //crash if I access the values directly and give them to QInputDialog, so do a copy first. + int value = slider->value(); + int step = slider->singleStep(); + int min = slider->minimum(); + int max = slider->maximum(); + + int i = +#if QT_VERSION >= 0x040500 + QInputDialog::getInt +#else + QInputDialog::getInteger +#endif + (this->parentWidget(), + tr("Slider %1").arg(name_bar), + tr("New value:"), + value, + min, + max, + step, + &ok); + + if (ok) + slider->setValue(i); +} + + +void CvTrackbar::update(int myvalue) +{ + setLabel(myvalue); + + *dataSlider = myvalue; + if (callback) + { + callback(myvalue); + return; + } + + if (callback2) + { + callback2(myvalue, userdata); + return; + } +} + + +void CvTrackbar::setLabel(int myvalue) +{ + QString nameNormalized = name_bar.leftJustified( 10, ' ', true ); + QString valueMaximum = QString("%1").arg(slider->maximum()); + QString str = QString("%1 (%2/%3)").arg(nameNormalized).arg(myvalue,valueMaximum.length(),10,QChar('0')).arg(valueMaximum); + label->setText(str); +} + + +////////////////////////////////////////////////////// +// CvButtonbar + + +//here CvButtonbar class +CvButtonbar::CvButtonbar(QWidget* arg, QString arg2) +{ + type = type_CvButtonbar; + myparent = arg; + name_bar = arg2; + setObjectName(name_bar); + + group_button = new QButtonGroup(this); +} + + +void CvButtonbar::setLabel() +{ + QString nameNormalized = name_bar.leftJustified(10, ' ', true); + label->setText(nameNormalized); +} + + +void CvButtonbar::addButton(QString name, CvButtonCallback call, void* userdata, int button_type, int initial_button_state) +{ + QString button_name = name; + + if (button_name == "") + button_name = tr("button %1").arg(this->count()); + + QPointer button; + + if (button_type == CV_PUSH_BUTTON) + button = (QAbstractButton*) new CvPushButton(this, button_name,call, userdata); + + if (button_type == CV_CHECKBOX) + button = (QAbstractButton*) new CvCheckBox(this, button_name,call, userdata, initial_button_state); + + if (button_type == CV_RADIOBOX) + { + button = (QAbstractButton*) new CvRadioButton(this, button_name,call, userdata, initial_button_state); + group_button->addButton(button); + } + + if (button) + { + if (button_type == CV_PUSH_BUTTON) + QObject::connect(button, SIGNAL(clicked(bool)), button, SLOT(callCallBack(bool))); + else + QObject::connect(button, SIGNAL(toggled(bool)), button, SLOT(callCallBack(bool))); + + addWidget(button, Qt::AlignCenter); + } +} + + +////////////////////////////////////////////////////// +// Buttons + + +//buttons here +CvPushButton::CvPushButton(CvButtonbar* arg1, QString arg2, CvButtonCallback arg3, void* arg4) +{ + myparent = arg1; + button_name = arg2; + callback = arg3; + userdata = arg4; + + setObjectName(button_name); + setText(button_name); + + if (isChecked()) + callCallBack(true); +} + + +void CvPushButton::callCallBack(bool checked) +{ + if (callback) + callback(checked, userdata); +} + + +CvCheckBox::CvCheckBox(CvButtonbar* arg1, QString arg2, CvButtonCallback arg3, void* arg4, int initial_button_state) +{ + myparent = arg1; + button_name = arg2; + callback = arg3; + userdata = arg4; + + setObjectName(button_name); + setCheckState((initial_button_state == 1 ? Qt::Checked : Qt::Unchecked)); + setText(button_name); + + if (isChecked()) + callCallBack(true); +} + + +void CvCheckBox::callCallBack(bool checked) +{ + if (callback) + callback(checked, userdata); +} + + +CvRadioButton::CvRadioButton(CvButtonbar* arg1, QString arg2, CvButtonCallback arg3, void* arg4, int initial_button_state) +{ + myparent = arg1; + button_name = arg2; + callback = arg3; + userdata = arg4; + + setObjectName(button_name); + setChecked(initial_button_state); + setText(button_name); + + if (isChecked()) + callCallBack(true); +} + +void CvRadioButton::callCallBack(bool checked) +{ + if (callback) + callback(checked, userdata); +} + + +////////////////////////////////////////////////////// +// CvWinProperties + + +//here CvWinProperties class +CvWinProperties::CvWinProperties(QString name_paraWindow, QObject* /*parent*/) +{ + //setParent(parent); + type = type_CvWinProperties; + setWindowFlags(Qt::Tool); + setContentsMargins(0, 0, 0, 0); + setWindowTitle(name_paraWindow); + setObjectName(name_paraWindow); + resize(100, 50); + + myLayout = new QBoxLayout(QBoxLayout::TopToBottom); + myLayout->setObjectName(QString::fromUtf8("boxLayout")); + myLayout->setContentsMargins(0, 0, 0, 0); + myLayout->setSpacing(0); + myLayout->setMargin(0); + myLayout->setSizeConstraint(QLayout::SetFixedSize); + setLayout(myLayout); + + hide(); +} + + +void CvWinProperties::closeEvent(QCloseEvent* e) +{ + e->accept(); //intersept the close event (not sure I really need it) + //an hide event is also sent. I will intercept it and do some processing +} + + +void CvWinProperties::showEvent(QShowEvent* evnt) +{ + //why -1,-1 ?: do this trick because the first time the code is run, + //no value pos was saved so we let Qt move the window in the middle of its parent (event ignored). + //then hide will save the last position and thus, we want to retreive it (event accepted). + QPoint mypos(-1, -1); + QSettings settings("OpenCV2", windowTitle()); + mypos = settings.value("pos", mypos).toPoint(); + + if (mypos.x() >= 0) + { + move(mypos); + evnt->accept(); + } + else + { + evnt->ignore(); + } +} + + +void CvWinProperties::hideEvent(QHideEvent* evnt) +{ + QSettings settings("OpenCV2", windowTitle()); + settings.setValue("pos", pos()); //there is an offset of 6 pixels (so the window's position is wrong -- why ?) + evnt->accept(); +} + + +CvWinProperties::~CvWinProperties() +{ + //clear the setting pos + QSettings settings("OpenCV2", windowTitle()); + settings.remove("pos"); +} + + +////////////////////////////////////////////////////// +// CvWindow + + +CvWindow::CvWindow(QString name, int arg2) +{ + type = type_CvWindow; + moveToThread(qApp->instance()->thread()); + + param_flags = arg2 & 0x0000000F; + param_gui_mode = arg2 & 0x000000F0; + param_ratio_mode = arg2 & 0x00000F00; + + //setAttribute(Qt::WA_DeleteOnClose); //in other case, does not release memory + setContentsMargins(0, 0, 0, 0); + setWindowTitle(name); + setObjectName(name); + + setFocus( Qt::PopupFocusReason ); //#1695 arrow keys are not recieved without the explicit focus + + resize(400, 300); + setMinimumSize(1, 1); + + //1: create control panel + if (!global_control_panel) + global_control_panel = createParameterWindow(); + + //2: Layouts + createBarLayout(); + createGlobalLayout(); + + //3: my view +#ifndef HAVE_QT_OPENGL + if (arg2 & CV_WINDOW_OPENGL) + CV_Error( CV_OpenGlNotSupported, "Library was built without OpenGL support" ); + mode_display = CV_MODE_NORMAL; +#else + mode_display = arg2 & CV_WINDOW_OPENGL ? CV_MODE_OPENGL : CV_MODE_NORMAL; + if (mode_display == CV_MODE_OPENGL) + param_gui_mode = CV_GUI_NORMAL; +#endif + createView(); + + //4: shortcuts and actions + //5: toolBar and statusbar + if (param_gui_mode == CV_GUI_EXPANDED) + { + createActions(); + createShortcuts(); + + createToolBar(); + createStatusBar(); + } + + //Now attach everything + if (myToolBar) + myGlobalLayout->addWidget(myToolBar, Qt::AlignCenter); + + myGlobalLayout->addWidget(myView->getWidget(), Qt::AlignCenter); + + myGlobalLayout->addLayout(myBarLayout, Qt::AlignCenter); + + if (myStatusBar) + myGlobalLayout->addWidget(myStatusBar, Qt::AlignCenter); + + setLayout(myGlobalLayout); + show(); +} + + +CvWindow::~CvWindow() +{ + if (guiMainThread) + guiMainThread->isLastWindow(); +} + + +void CvWindow::setMouseCallBack(CvMouseCallback callback, void* param) +{ + myView->setMouseCallBack(callback, param); +} + + +void CvWindow::writeSettings() +{ + //organisation and application's name + QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName()); + + settings.setValue("pos", pos()); + settings.setValue("size", size()); + settings.setValue("mode_resize" ,param_flags); + settings.setValue("mode_gui", param_gui_mode); + + myView->writeSettings(settings); + + icvSaveTrackbars(&settings); + + if (global_control_panel) + { + icvSaveControlPanel(); + settings.setValue("posPanel", global_control_panel->pos()); + } +} + + + +//TODO: load CV_GUI flag (done) and act accordingly (create win property if needed and attach trackbars) +void CvWindow::readSettings() +{ + //organisation and application's name + QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName()); + + QPoint _pos = settings.value("pos", QPoint(200, 200)).toPoint(); + QSize _size = settings.value("size", QSize(400, 400)).toSize(); + + param_flags = settings.value("mode_resize", param_flags).toInt(); + param_gui_mode = settings.value("mode_gui", param_gui_mode).toInt(); + + param_flags = settings.value("mode_resize", param_flags).toInt(); + + myView->readSettings(settings); + + //trackbar here + icvLoadTrackbars(&settings); + + resize(_size); + move(_pos); + + if (global_control_panel) + { + icvLoadControlPanel(); + global_control_panel->move(settings.value("posPanel", global_control_panel->pos()).toPoint()); + } +} + + +double CvWindow::getRatio() +{ + return myView->getRatio(); +} + + +void CvWindow::setRatio(int flags) +{ + myView->setRatio(flags); +} + + +int CvWindow::getPropWindow() +{ + return param_flags; +} + + +void CvWindow::setPropWindow(int flags) +{ + if (param_flags == flags) //nothing to do + return; + + switch(flags) + { + case CV_WINDOW_NORMAL: + myGlobalLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); + param_flags = flags; + + break; + + case CV_WINDOW_AUTOSIZE: + myGlobalLayout->setSizeConstraint(QLayout::SetFixedSize); + param_flags = flags; + + break; + + default: + ; + } +} + + +void CvWindow::toggleFullScreen(int flags) +{ + if (isFullScreen() && flags == CV_WINDOW_NORMAL) + { + showTools(); + showNormal(); + return; + } + + if (!isFullScreen() && flags == CV_WINDOW_FULLSCREEN) + { + hideTools(); + showFullScreen(); + return; + } +} + + +void CvWindow::updateImage(void* arr) +{ + myView->updateImage(arr); +} + + +void CvWindow::displayInfo(QString text, int delayms) +{ + myView->startDisplayInfo(text, delayms); +} + + +void CvWindow::displayStatusBar(QString text, int delayms) +{ + if (myStatusBar) + myStatusBar->showMessage(text, delayms); +} + + +void CvWindow::enablePropertiesButton() +{ + vect_QActions[9]->setDisabled(false); +} + + +CvButtonbar* CvWindow::createButtonBar(QString name_bar) +{ + QPointer t = new CvButtonbar(global_control_panel, name_bar); + t->setAlignment(Qt::AlignHCenter); + + QPointer myLayout = global_control_panel->myLayout; + + myLayout->insertLayout(myLayout->count(), t); + + return t; +} + + +void CvWindow::addSlider(CvWindow* w, QString name, int* value, int count, CvTrackbarCallback on_change) +{ + QPointer t = new CvTrackbar(w, name, value, count, on_change); + t->setAlignment(Qt::AlignHCenter); + + QPointer myLayout; + + if (w) + { + myLayout = w->myBarLayout; + } + else + { + myLayout = global_control_panel->myLayout; + + //if first one, enable control panel + if (myLayout->count() == 0) + guiMainThread->enablePropertiesButtonEachWindow(); + } + + myLayout->insertLayout(myLayout->count(), t); +} + + +void CvWindow::addSlider2(CvWindow* w, QString name, int* value, int count, CvTrackbarCallback2 on_change, void* userdata) +{ + QPointer t = new CvTrackbar(w, name, value, count, on_change, userdata); + t->setAlignment(Qt::AlignHCenter); + + QPointer myLayout; + + if (w) + { + myLayout = w->myBarLayout; + } + else + { + myLayout = global_control_panel->myLayout; + + //if first one, enable control panel + if (myLayout->count() == 0) + guiMainThread->enablePropertiesButtonEachWindow(); + } + + myLayout->insertLayout(myLayout->count(), t); +} + + +void CvWindow::setOpenGlDrawCallback(CvOpenGlDrawCallback callback, void* userdata) +{ + myView->setOpenGlDrawCallback(callback, userdata); +} + + +void CvWindow::setOpenGlCleanCallback(CvOpenGlCleanCallback callback, void* userdata) +{ + myView->setOpenGlCleanCallback(callback, userdata); +} + + +void CvWindow::makeCurrentOpenGlContext() +{ + myView->makeCurrentOpenGlContext(); +} + + +void CvWindow::updateGl() +{ + myView->updateGl(); +} + + +bool CvWindow::isOpenGl() +{ + return mode_display == CV_MODE_OPENGL; +} + + +void CvWindow::setViewportSize(QSize _size) +{ + myView->getWidget()->resize(_size); + myView->setSize(_size); +} + + +void CvWindow::createBarLayout() +{ + myBarLayout = new QBoxLayout(QBoxLayout::TopToBottom); + myBarLayout->setObjectName(QString::fromUtf8("barLayout")); + myBarLayout->setContentsMargins(0, 0, 0, 0); + myBarLayout->setSpacing(0); + myBarLayout->setMargin(0); +} + + +void CvWindow::createGlobalLayout() +{ + myGlobalLayout = new QBoxLayout(QBoxLayout::TopToBottom); + myGlobalLayout->setObjectName(QString::fromUtf8("boxLayout")); + myGlobalLayout->setContentsMargins(0, 0, 0, 0); + myGlobalLayout->setSpacing(0); + myGlobalLayout->setMargin(0); + setMinimumSize(1, 1); + + if (param_flags == CV_WINDOW_AUTOSIZE) + myGlobalLayout->setSizeConstraint(QLayout::SetFixedSize); + else if (param_flags == CV_WINDOW_NORMAL) + myGlobalLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); +} + + +void CvWindow::createView() +{ +#ifdef HAVE_QT_OPENGL + if (isOpenGl()) + myView = new OpenGlViewPort(this); + else +#endif + myView = new DefaultViewPort(this, param_ratio_mode); +} + + +void CvWindow::createActions() +{ + vect_QActions.resize(10); + + QWidget* view = myView->getWidget(); + + //if the shortcuts are changed in window_QT.h, we need to update the tooltip manually + vect_QActions[0] = new QAction(QIcon(":/left-icon"), "Panning left (CTRL+arrowLEFT)", this); + vect_QActions[0]->setIconVisibleInMenu(true); + QObject::connect(vect_QActions[0], SIGNAL(triggered()), view, SLOT(siftWindowOnLeft())); + + vect_QActions[1] = new QAction(QIcon(":/right-icon"), "Panning right (CTRL+arrowRIGHT)", this); + vect_QActions[1]->setIconVisibleInMenu(true); + QObject::connect(vect_QActions[1], SIGNAL(triggered()), view, SLOT(siftWindowOnRight())); + + vect_QActions[2] = new QAction(QIcon(":/up-icon"), "Panning up (CTRL+arrowUP)", this); + vect_QActions[2]->setIconVisibleInMenu(true); + QObject::connect(vect_QActions[2], SIGNAL(triggered()), view, SLOT(siftWindowOnUp())); + + vect_QActions[3] = new QAction(QIcon(":/down-icon"), "Panning down (CTRL+arrowDOWN)", this); + vect_QActions[3]->setIconVisibleInMenu(true); + QObject::connect(vect_QActions[3], SIGNAL(triggered()), view, SLOT(siftWindowOnDown()) ); + + vect_QActions[4] = new QAction(QIcon(":/zoom_x1-icon"), "Zoom x1 (CTRL+P)", this); + vect_QActions[4]->setIconVisibleInMenu(true); + QObject::connect(vect_QActions[4], SIGNAL(triggered()), view, SLOT(resetZoom())); + + vect_QActions[5] = new QAction(QIcon(":/imgRegion-icon"), tr("Zoom x%1 (see label) (CTRL+X)").arg(threshold_zoom_img_region), this); + vect_QActions[5]->setIconVisibleInMenu(true); + QObject::connect(vect_QActions[5], SIGNAL(triggered()), view, SLOT(imgRegion())); + + vect_QActions[6] = new QAction(QIcon(":/zoom_in-icon"), "Zoom in (CTRL++)", this); + vect_QActions[6]->setIconVisibleInMenu(true); + QObject::connect(vect_QActions[6], SIGNAL(triggered()), view, SLOT(ZoomIn())); + + vect_QActions[7] = new QAction(QIcon(":/zoom_out-icon"), "Zoom out (CTRL+-)", this); + vect_QActions[7]->setIconVisibleInMenu(true); + QObject::connect(vect_QActions[7], SIGNAL(triggered()), view, SLOT(ZoomOut())); + + vect_QActions[8] = new QAction(QIcon(":/save-icon"), "Save current image (CTRL+S)", this); + vect_QActions[8]->setIconVisibleInMenu(true); + QObject::connect(vect_QActions[8], SIGNAL(triggered()), view, SLOT(saveView())); + + vect_QActions[9] = new QAction(QIcon(":/properties-icon"), "Display properties window (CTRL+P)", this); + vect_QActions[9]->setIconVisibleInMenu(true); + QObject::connect(vect_QActions[9], SIGNAL(triggered()), this, SLOT(displayPropertiesWin())); + + if (global_control_panel->myLayout->count() == 0) + vect_QActions[9]->setDisabled(true); +} + + +void CvWindow::createShortcuts() +{ + vect_QShortcuts.resize(10); + + QWidget* view = myView->getWidget(); + + vect_QShortcuts[0] = new QShortcut(shortcut_panning_left, this); + QObject::connect(vect_QShortcuts[0], SIGNAL(activated()), view, SLOT(siftWindowOnLeft())); + + vect_QShortcuts[1] = new QShortcut(shortcut_panning_right, this); + QObject::connect(vect_QShortcuts[1], SIGNAL(activated()), view, SLOT(siftWindowOnRight())); + + vect_QShortcuts[2] = new QShortcut(shortcut_panning_up, this); + QObject::connect(vect_QShortcuts[2], SIGNAL(activated()), view, SLOT(siftWindowOnUp())); + + vect_QShortcuts[3] = new QShortcut(shortcut_panning_down, this); + QObject::connect(vect_QShortcuts[3], SIGNAL(activated()), view, SLOT(siftWindowOnDown())); + + vect_QShortcuts[4] = new QShortcut(shortcut_zoom_normal, this); + QObject::connect(vect_QShortcuts[4], SIGNAL(activated()), view, SLOT(resetZoom())); + + vect_QShortcuts[5] = new QShortcut(shortcut_zoom_imgRegion, this); + QObject::connect(vect_QShortcuts[5], SIGNAL(activated()), view, SLOT(imgRegion())); + + vect_QShortcuts[6] = new QShortcut(shortcut_zoom_in, this); + QObject::connect(vect_QShortcuts[6], SIGNAL(activated()), view, SLOT(ZoomIn())); + + vect_QShortcuts[7] = new QShortcut(shortcut_zoom_out, this); + QObject::connect(vect_QShortcuts[7], SIGNAL(activated()), view, SLOT(ZoomOut())); + + vect_QShortcuts[8] = new QShortcut(shortcut_save_img, this); + QObject::connect(vect_QShortcuts[8], SIGNAL(activated()), view, SLOT(saveView())); + + vect_QShortcuts[9] = new QShortcut(shortcut_properties_win, this); + QObject::connect(vect_QShortcuts[9], SIGNAL(activated()), this, SLOT(displayPropertiesWin())); +} + + +void CvWindow::createToolBar() +{ + myToolBar = new QToolBar(this); + myToolBar->setFloatable(false); //is not a window + myToolBar->setFixedHeight(28); + myToolBar->setMinimumWidth(1); + + foreach (QAction *a, vect_QActions) + myToolBar->addAction(a); +} + + +void CvWindow::createStatusBar() +{ + myStatusBar = new QStatusBar(this); + myStatusBar->setSizeGripEnabled(false); + myStatusBar->setFixedHeight(20); + myStatusBar->setMinimumWidth(1); + myStatusBar_msg = new QLabel; + + //I comment this because if we change the style, myview (the picture) + //will not be the correct size anymore (will lost 2 pixel because of the borders) + + //myStatusBar_msg->setFrameStyle(QFrame::Raised); + + myStatusBar_msg->setAlignment(Qt::AlignHCenter); + myStatusBar->addWidget(myStatusBar_msg); +} + + +void CvWindow::hideTools() +{ + if (myToolBar) + myToolBar->hide(); + + if (myStatusBar) + myStatusBar->hide(); + + if (global_control_panel) + global_control_panel->hide(); +} + + +void CvWindow::showTools() +{ + if (myToolBar) + myToolBar->show(); + + if (myStatusBar) + myStatusBar->show(); +} + + +CvWinProperties* CvWindow::createParameterWindow() +{ + QString name_paraWindow = QFileInfo(QApplication::applicationFilePath()).fileName() + " settings"; + + CvWinProperties* result = new CvWinProperties(name_paraWindow, guiMainThread); + + return result; +} + + +void CvWindow::displayPropertiesWin() +{ + if (global_control_panel->isHidden()) + global_control_panel->show(); + else + global_control_panel->hide(); +} + + +//Need more test here ! +void CvWindow::keyPressEvent(QKeyEvent *evnt) +{ + //see http://doc.trolltech.com/4.6/qt.html#Key-enum + int key = evnt->key(); + + Qt::Key qtkey = static_cast(key); + char asciiCode = QTest::keyToAscii(qtkey); + if (asciiCode != 0) + key = static_cast(asciiCode); + else + key = evnt->nativeVirtualKey(); //same codes as returned by GTK-based backend + + //control plus (Z, +, -, up, down, left, right) are used for zoom/panning functions + if (evnt->modifiers() != Qt::ControlModifier) + { + mutexKey.lock(); + last_key = key; + mutexKey.unlock(); + key_pressed.wakeAll(); + //evnt->accept(); + } + + QWidget::keyPressEvent(evnt); +} + + +void CvWindow::icvLoadControlPanel() +{ + QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName() + " control panel"); + + int bsize = settings.beginReadArray("bars"); + + if (bsize == global_control_panel->myLayout->layout()->count()) + { + for (int i = 0; i < bsize; ++i) + { + CvBar* t = (CvBar*) global_control_panel->myLayout->layout()->itemAt(i); + settings.setArrayIndex(i); + if (t->type == type_CvTrackbar) + { + if (t->name_bar == settings.value("namebar").toString()) + { + ((CvTrackbar*)t)->slider->setValue(settings.value("valuebar").toInt()); + } + } + if (t->type == type_CvButtonbar) + { + int subsize = settings.beginReadArray(QString("buttonbar")+i); + + if ( subsize == ((CvButtonbar*)t)->layout()->count() ) + icvLoadButtonbar((CvButtonbar*)t,&settings); + + settings.endArray(); + } + } + } + + settings.endArray(); +} + + +void CvWindow::icvSaveControlPanel() +{ + QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName()+" control panel"); + + settings.beginWriteArray("bars"); + + for (int i = 0; i < global_control_panel->myLayout->layout()->count(); ++i) + { + CvBar* t = (CvBar*) global_control_panel->myLayout->layout()->itemAt(i); + settings.setArrayIndex(i); + if (t->type == type_CvTrackbar) + { + settings.setValue("namebar", QString(t->name_bar)); + settings.setValue("valuebar",((CvTrackbar*)t)->slider->value()); + } + if (t->type == type_CvButtonbar) + { + settings.beginWriteArray(QString("buttonbar")+i); + icvSaveButtonbar((CvButtonbar*)t,&settings); + settings.endArray(); + } + } + + settings.endArray(); +} + + +void CvWindow::icvSaveButtonbar(CvButtonbar* b, QSettings* settings) +{ + for (int i = 0, count = b->layout()->count(); i < count; ++i) + { + settings->setArrayIndex(i); + + QWidget* temp = (QWidget*) b->layout()->itemAt(i)->widget(); + QString myclass(QLatin1String(temp->metaObject()->className())); + + if (myclass == "CvPushButton") + { + CvPushButton* button = (CvPushButton*) temp; + settings->setValue("namebutton", button->text()); + settings->setValue("valuebutton", int(button->isChecked())); + } + else if (myclass == "CvCheckBox") + { + CvCheckBox* button = (CvCheckBox*) temp; + settings->setValue("namebutton", button->text()); + settings->setValue("valuebutton", int(button->isChecked())); + } + else if (myclass == "CvRadioButton") + { + CvRadioButton* button = (CvRadioButton*) temp; + settings->setValue("namebutton", button->text()); + settings->setValue("valuebutton", int(button->isChecked())); + } + } +} + + +void CvWindow::icvLoadButtonbar(CvButtonbar* b, QSettings* settings) +{ + for (int i = 0, count = b->layout()->count(); i < count; ++i) + { + settings->setArrayIndex(i); + + QWidget* temp = (QWidget*) b->layout()->itemAt(i)->widget(); + QString myclass(QLatin1String(temp->metaObject()->className())); + + if (myclass == "CvPushButton") + { + CvPushButton* button = (CvPushButton*) temp; + + if (button->text() == settings->value("namebutton").toString()) + button->setChecked(settings->value("valuebutton").toInt()); + } + else if (myclass == "CvCheckBox") + { + CvCheckBox* button = (CvCheckBox*) temp; + + if (button->text() == settings->value("namebutton").toString()) + button->setChecked(settings->value("valuebutton").toInt()); + } + else if (myclass == "CvRadioButton") + { + CvRadioButton* button = (CvRadioButton*) temp; + + if (button->text() == settings->value("namebutton").toString()) + button->setChecked(settings->value("valuebutton").toInt()); + } + + } +} + + +void CvWindow::icvLoadTrackbars(QSettings* settings) +{ + int bsize = settings->beginReadArray("trackbars"); + + //trackbar are saved in the same order, so no need to use icvFindTrackbarByName + + if (myBarLayout->layout()->count() == bsize) //if not the same number, the window saved and loaded is not the same (nb trackbar not equal) + { + for (int i = 0; i < bsize; ++i) + { + settings->setArrayIndex(i); + + CvTrackbar* t = (CvTrackbar*) myBarLayout->layout()->itemAt(i); + + if (t->name_bar == settings->value("name").toString()) + t->slider->setValue(settings->value("value").toInt()); + + } + } + + settings->endArray(); +} + + +void CvWindow::icvSaveTrackbars(QSettings* settings) +{ + settings->beginWriteArray("trackbars"); + + for (int i = 0; i < myBarLayout->layout()->count(); ++i) + { + settings->setArrayIndex(i); + + CvTrackbar* t = (CvTrackbar*) myBarLayout->layout()->itemAt(i); + + settings->setValue("name", t->name_bar); + settings->setValue("value", t->slider->value()); + } + + settings->endArray(); +} + + +////////////////////////////////////////////////////// +// DefaultViewPort + + +DefaultViewPort::DefaultViewPort(CvWindow* arg, int arg2) : QGraphicsView(arg), image2Draw_mat(0) +{ + centralWidget = arg; + param_keepRatio = arg2; + + setContentsMargins(0, 0, 0, 0); + setMinimumSize(1, 1); + setAlignment(Qt::AlignHCenter); + + setObjectName(QString::fromUtf8("graphicsView")); + + timerDisplay = new QTimer(this); + timerDisplay->setSingleShot(true); + connect(timerDisplay, SIGNAL(timeout()), this, SLOT(stopDisplayInfo())); + + drawInfo = false; + positionGrabbing = QPointF(0, 0); + positionCorners = QRect(0, 0, size().width(), size().height()); + + on_mouse = 0; + on_mouse_param = 0; + mouseCoordinate = QPoint(-1, -1); + + //no border + setStyleSheet( "QGraphicsView { border-style: none; }" ); + + image2Draw_mat = cvCreateMat(viewport()->height(), viewport()->width(), CV_8UC3); + cvZero(image2Draw_mat); + + nbChannelOriginImage = 0; + + setInteractive(false); + setMouseTracking(true); //receive mouse event everytime +} + + +DefaultViewPort::~DefaultViewPort() +{ + if (image2Draw_mat) + cvReleaseMat(&image2Draw_mat); +} + + +QWidget* DefaultViewPort::getWidget() +{ + return this; +} + + +void DefaultViewPort::setMouseCallBack(CvMouseCallback m, void* param) +{ + on_mouse = m; + + on_mouse_param = param; +} + +void DefaultViewPort::writeSettings(QSettings& settings) +{ + settings.setValue("matrix_view.m11", param_matrixWorld.m11()); + settings.setValue("matrix_view.m12", param_matrixWorld.m12()); + settings.setValue("matrix_view.m13", param_matrixWorld.m13()); + settings.setValue("matrix_view.m21", param_matrixWorld.m21()); + settings.setValue("matrix_view.m22", param_matrixWorld.m22()); + settings.setValue("matrix_view.m23", param_matrixWorld.m23()); + settings.setValue("matrix_view.m31", param_matrixWorld.m31()); + settings.setValue("matrix_view.m32", param_matrixWorld.m32()); + settings.setValue("matrix_view.m33", param_matrixWorld.m33()); +} + + +void DefaultViewPort::readSettings(QSettings& settings) +{ + qreal m11 = settings.value("matrix_view.m11", param_matrixWorld.m11()).toDouble(); + qreal m12 = settings.value("matrix_view.m12", param_matrixWorld.m12()).toDouble(); + qreal m13 = settings.value("matrix_view.m13", param_matrixWorld.m13()).toDouble(); + qreal m21 = settings.value("matrix_view.m21", param_matrixWorld.m21()).toDouble(); + qreal m22 = settings.value("matrix_view.m22", param_matrixWorld.m22()).toDouble(); + qreal m23 = settings.value("matrix_view.m23", param_matrixWorld.m23()).toDouble(); + qreal m31 = settings.value("matrix_view.m31", param_matrixWorld.m31()).toDouble(); + qreal m32 = settings.value("matrix_view.m32", param_matrixWorld.m32()).toDouble(); + qreal m33 = settings.value("matrix_view.m33", param_matrixWorld.m33()).toDouble(); + + param_matrixWorld = QTransform(m11, m12, m13, m21, m22, m23, m31, m32, m33); +} + + +double DefaultViewPort::getRatio() +{ + return param_keepRatio; +} + + +void DefaultViewPort::setRatio(int flags) +{ + if (getRatio() == flags) //nothing to do + return; + + //if valid flags + if (flags == CV_WINDOW_FREERATIO || flags == CV_WINDOW_KEEPRATIO) + { + centralWidget->param_ratio_mode = flags; + param_keepRatio = flags; + updateGeometry(); + viewport()->update(); + } +} + + +void DefaultViewPort::updateImage(const CvArr* arr) +{ + CV_Assert(arr); + + CvMat* mat, stub; + int origin = 0; + + if (CV_IS_IMAGE_HDR(arr)) + origin = ((IplImage*)arr)->origin; + + mat = cvGetMat(arr, &stub); + + if (!image2Draw_mat || !CV_ARE_SIZES_EQ(image2Draw_mat, mat)) + { + if (image2Draw_mat) + cvReleaseMat(&image2Draw_mat); + + //the image in ipl (to do a deep copy with cvCvtColor) + image2Draw_mat = cvCreateMat(mat->rows, mat->cols, CV_8UC3); + image2Draw_qt = QImage(image2Draw_mat->data.ptr, image2Draw_mat->cols, image2Draw_mat->rows, image2Draw_mat->step, QImage::Format_RGB888); + + //use to compute mouse coordinate, I need to update the ratio here and in resizeEvent + ratioX = width() / float(image2Draw_mat->cols); + ratioY = height() / float(image2Draw_mat->rows); + + updateGeometry(); + } + + nbChannelOriginImage = cvGetElemType(mat); + + cvConvertImage(mat, image2Draw_mat, (origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB); + + viewport()->update(); +} + + +void DefaultViewPort::startDisplayInfo(QString text, int delayms) +{ + if (timerDisplay->isActive()) + stopDisplayInfo(); + + infoText = text; + if (delayms > 0) timerDisplay->start(delayms); + drawInfo = true; +} + + +void DefaultViewPort::setOpenGlDrawCallback(CvOpenGlDrawCallback /*callback*/, void* /*userdata*/) +{ + CV_Error(CV_OpenGlNotSupported, "Window doesn't support OpenGL"); +} + + +void DefaultViewPort::setOpenGlCleanCallback(CvOpenGlCleanCallback /*callback*/, void* /*userdata*/) +{ + CV_Error(CV_OpenGlNotSupported, "Window doesn't support OpenGL"); +} + + +void DefaultViewPort::makeCurrentOpenGlContext() +{ + CV_Error(CV_OpenGlNotSupported, "Window doesn't support OpenGL"); +} + + +void DefaultViewPort::updateGl() +{ + CV_Error(CV_OpenGlNotSupported, "Window doesn't support OpenGL"); +} + + +//Note: move 2 percent of the window +void DefaultViewPort::siftWindowOnLeft() +{ + float delta = 2 * width() / (100.0 * param_matrixWorld.m11()); + moveView(QPointF(delta, 0)); +} + + +//Note: move 2 percent of the window +void DefaultViewPort::siftWindowOnRight() +{ + float delta = -2 * width() / (100.0 * param_matrixWorld.m11()); + moveView(QPointF(delta, 0)); +} + + +//Note: move 2 percent of the window +void DefaultViewPort::siftWindowOnUp() +{ + float delta = 2 * height() / (100.0 * param_matrixWorld.m11()); + moveView(QPointF(0, delta)); +} + + +//Note: move 2 percent of the window +void DefaultViewPort::siftWindowOnDown() +{ + float delta = -2 * height() / (100.0 * param_matrixWorld.m11()); + moveView(QPointF(0, delta)); +} + + +void DefaultViewPort::imgRegion() +{ + scaleView((threshold_zoom_img_region / param_matrixWorld.m11() - 1) * 5, QPointF(size().width() / 2, size().height() / 2)); +} + + +void DefaultViewPort::resetZoom() +{ + param_matrixWorld.reset(); + controlImagePosition(); +} + + +void DefaultViewPort::ZoomIn() +{ + scaleView(0.5, QPointF(size().width() / 2, size().height() / 2)); +} + + +void DefaultViewPort::ZoomOut() +{ + scaleView(-0.5, QPointF(size().width() / 2, size().height() / 2)); +} + + +//can save as JPG, JPEG, BMP, PNG +void DefaultViewPort::saveView() +{ + QDate date_d = QDate::currentDate(); + QString date_s = date_d.toString("dd.MM.yyyy"); + QString name_s = centralWidget->windowTitle() + "_screenshot_" + date_s; + + QString fileName = QFileDialog::getSaveFileName(this, tr("Save File %1").arg(name_s), name_s + ".png", tr("Images (*.png *.jpg *.bmp *.jpeg)")); + + if (!fileName.isEmpty()) //save the picture + { + QString extension = fileName.right(3); + + // (no need anymore) create the image resized to receive the 'screenshot' + // image2Draw_qt_resized = QImage(viewport()->width(), viewport()->height(),QImage::Format_RGB888); + + QPainter saveimage(&image2Draw_qt_resized); + this->render(&saveimage); + + // Save it.. + if (QString::compare(extension, "png", Qt::CaseInsensitive) == 0) + { + image2Draw_qt_resized.save(fileName, "PNG"); + return; + } + + if (QString::compare(extension, "jpg", Qt::CaseInsensitive) == 0) + { + image2Draw_qt_resized.save(fileName, "JPG"); + return; + } + + if (QString::compare(extension, "bmp", Qt::CaseInsensitive) == 0) + { + image2Draw_qt_resized.save(fileName, "BMP"); + return; + } + + if (QString::compare(extension, "jpeg", Qt::CaseInsensitive) == 0) + { + image2Draw_qt_resized.save(fileName, "JPEG"); + return; + } + + CV_Error(CV_StsNullPtr, "file extension not recognized, please choose between JPG, JPEG, BMP or PNG"); + } +} + + +void DefaultViewPort::contextMenuEvent(QContextMenuEvent* evnt) +{ + if (centralWidget->vect_QActions.size() > 0) + { + QMenu menu(this); + + foreach (QAction *a, centralWidget->vect_QActions) + menu.addAction(a); + + menu.exec(evnt->globalPos()); + } +} + + +void DefaultViewPort::resizeEvent(QResizeEvent* evnt) +{ + controlImagePosition(); + + //use to compute mouse coordinate, I need to update the ratio here and in resizeEvent + ratioX = width() / float(image2Draw_mat->cols); + ratioY = height() / float(image2Draw_mat->rows); + + if (param_keepRatio == CV_WINDOW_KEEPRATIO)//to keep the same aspect ratio + { + QSize newSize = QSize(image2Draw_mat->cols, image2Draw_mat->rows); + newSize.scale(evnt->size(), Qt::KeepAspectRatio); + + //imageWidth/imageHeight = newWidth/newHeight +/- epsilon + //ratioX = ratioY +/- epsilon + //||ratioX - ratioY|| = epsilon + if (fabs(ratioX - ratioY) * 100 > ratioX) //avoid infinity loop / epsilon = 1% of ratioX + { + resize(newSize); + + //move to the middle + //newSize get the delta offset to place the picture in the middle of its parent + newSize = (evnt->size() - newSize) / 2; + + //if the toolbar is displayed, avoid drawing myview on top of it + if (centralWidget->myToolBar) + if(!centralWidget->myToolBar->isHidden()) + newSize += QSize(0, centralWidget->myToolBar->height()); + + move(newSize.width(), newSize.height()); + } + } + + return QGraphicsView::resizeEvent(evnt); +} + + +void DefaultViewPort::wheelEvent(QWheelEvent* evnt) +{ + scaleView(evnt->delta() / 240.0, evnt->pos()); + viewport()->update(); +} + + +void DefaultViewPort::mousePressEvent(QMouseEvent* evnt) +{ + int cv_event = -1, flags = 0; + QPoint pt = evnt->pos(); + + //icvmouseHandler: pass parameters for cv_event, flags + icvmouseHandler(evnt, mouse_down, cv_event, flags); + icvmouseProcessing(QPointF(pt), cv_event, flags); + + if (param_matrixWorld.m11()>1) + { + setCursor(Qt::ClosedHandCursor); + positionGrabbing = evnt->pos(); + } + + QWidget::mousePressEvent(evnt); +} + + +void DefaultViewPort::mouseReleaseEvent(QMouseEvent* evnt) +{ + int cv_event = -1, flags = 0; + QPoint pt = evnt->pos(); + + //icvmouseHandler: pass parameters for cv_event, flags + icvmouseHandler(evnt, mouse_up, cv_event, flags); + icvmouseProcessing(QPointF(pt), cv_event, flags); + + if (param_matrixWorld.m11()>1) + setCursor(Qt::OpenHandCursor); + + QWidget::mouseReleaseEvent(evnt); +} + + +void DefaultViewPort::mouseDoubleClickEvent(QMouseEvent* evnt) +{ + int cv_event = -1, flags = 0; + QPoint pt = evnt->pos(); + + //icvmouseHandler: pass parameters for cv_event, flags + icvmouseHandler(evnt, mouse_dbclick, cv_event, flags); + icvmouseProcessing(QPointF(pt), cv_event, flags); + + QWidget::mouseDoubleClickEvent(evnt); +} + + +void DefaultViewPort::mouseMoveEvent(QMouseEvent* evnt) +{ + int cv_event = CV_EVENT_MOUSEMOVE, flags = 0; + QPoint pt = evnt->pos(); + + //icvmouseHandler: pass parameters for cv_event, flags + icvmouseHandler(evnt, mouse_move, cv_event, flags); + icvmouseProcessing(QPointF(pt), cv_event, flags); + + if (param_matrixWorld.m11() > 1 && evnt->buttons() == Qt::LeftButton) + { + QPointF dxy = (pt - positionGrabbing)/param_matrixWorld.m11(); + positionGrabbing = evnt->pos(); + moveView(dxy); + } + + //I update the statusbar here because if the user does a cvWaitkey(0) (like with inpaint.cpp) + //the status bar will only be repaint when a click occurs. + if (centralWidget->myStatusBar) + viewport()->update(); + + QWidget::mouseMoveEvent(evnt); +} + + +void DefaultViewPort::paintEvent(QPaintEvent* evnt) +{ + QPainter myPainter(viewport()); + myPainter.setWorldTransform(param_matrixWorld); + + draw2D(&myPainter); + + //Now disable matrixWorld for overlay display + myPainter.setWorldMatrixEnabled(false); + + //in mode zoom/panning + if (param_matrixWorld.m11() > 1) + { + if (param_matrixWorld.m11() >= threshold_zoom_img_region) + { + if (centralWidget->param_flags == CV_WINDOW_NORMAL) + startDisplayInfo("WARNING: The values displayed are the resized image's values. If you want the original image's values, use CV_WINDOW_AUTOSIZE", 1000); + + drawImgRegion(&myPainter); + } + + drawViewOverview(&myPainter); + } + + //for information overlay + if (drawInfo) + drawInstructions(&myPainter); + + //for statusbar + if (centralWidget->myStatusBar) + drawStatusBar(); + + QGraphicsView::paintEvent(evnt); +} + + +void DefaultViewPort::stopDisplayInfo() +{ + timerDisplay->stop(); + drawInfo = false; +} + + +inline bool DefaultViewPort::isSameSize(IplImage* img1, IplImage* img2) +{ + return img1->width == img2->width && img1->height == img2->height; +} + + +void DefaultViewPort::controlImagePosition() +{ + qreal left, top, right, bottom; + + //after check top-left, bottom right corner to avoid getting "out" during zoom/panning + param_matrixWorld.map(0,0,&left,&top); + + if (left > 0) + { + param_matrixWorld.translate(-left,0); + left = 0; + } + if (top > 0) + { + param_matrixWorld.translate(0,-top); + top = 0; + } + //------- + + QSize sizeImage = size(); + param_matrixWorld.map(sizeImage.width(),sizeImage.height(),&right,&bottom); + if (right < sizeImage.width()) + { + param_matrixWorld.translate(sizeImage.width()-right,0); + right = sizeImage.width(); + } + if (bottom < sizeImage.height()) + { + param_matrixWorld.translate(0,sizeImage.height()-bottom); + bottom = sizeImage.height(); + } + + //save corner position + positionCorners.setTopLeft(QPoint(left,top)); + positionCorners.setBottomRight(QPoint(right,bottom)); + //save also the inv matrix + matrixWorld_inv = param_matrixWorld.inverted(); + + //viewport()->update(); +} + +void DefaultViewPort::moveView(QPointF delta) +{ + param_matrixWorld.translate(delta.x(),delta.y()); + controlImagePosition(); + viewport()->update(); +} + +//factor is -0.5 (zoom out) or 0.5 (zoom in) +void DefaultViewPort::scaleView(qreal factor,QPointF center) +{ + factor/=5;//-0.1 <-> 0.1 + factor+=1;//0.9 <-> 1.1 + + //limit zoom out --- + if (param_matrixWorld.m11()==1 && factor < 1) + return; + + if (param_matrixWorld.m11()*factor<1) + factor = 1/param_matrixWorld.m11(); + + + //limit zoom int --- + if (param_matrixWorld.m11()>100 && factor > 1) + return; + + //inverse the transform + int a, b; + matrixWorld_inv.map(center.x(),center.y(),&a,&b); + + param_matrixWorld.translate(a-factor*a,b-factor*b); + param_matrixWorld.scale(factor,factor); + + controlImagePosition(); + + //display new zoom + if (centralWidget->myStatusBar) + centralWidget->displayStatusBar(tr("Zoom: %1%").arg(param_matrixWorld.m11()*100),1000); + + if (param_matrixWorld.m11()>1) + setCursor(Qt::OpenHandCursor); + else + unsetCursor(); +} + + +//up, down, dclick, move +void DefaultViewPort::icvmouseHandler(QMouseEvent *evnt, type_mouse_event category, int &cv_event, int &flags) +{ + Qt::KeyboardModifiers modifiers = evnt->modifiers(); + Qt::MouseButtons buttons = evnt->buttons(); + + flags = 0; + if(modifiers & Qt::ShiftModifier) + flags |= CV_EVENT_FLAG_SHIFTKEY; + if(modifiers & Qt::ControlModifier) + flags |= CV_EVENT_FLAG_CTRLKEY; + if(modifiers & Qt::AltModifier) + flags |= CV_EVENT_FLAG_ALTKEY; + + if(buttons & Qt::LeftButton) + flags |= CV_EVENT_FLAG_LBUTTON; + if(buttons & Qt::RightButton) + flags |= CV_EVENT_FLAG_RBUTTON; + if(buttons & Qt::MidButton) + flags |= CV_EVENT_FLAG_MBUTTON; + + cv_event = CV_EVENT_MOUSEMOVE; + switch(evnt->button()) + { + case Qt::LeftButton: + cv_event = tableMouseButtons[category][0]; + flags |= CV_EVENT_FLAG_LBUTTON; + break; + case Qt::RightButton: + cv_event = tableMouseButtons[category][1]; + flags |= CV_EVENT_FLAG_RBUTTON; + break; + case Qt::MidButton: + cv_event = tableMouseButtons[category][2]; + flags |= CV_EVENT_FLAG_MBUTTON; + break; + default:; + } +} + + +void DefaultViewPort::icvmouseProcessing(QPointF pt, int cv_event, int flags) +{ + //to convert mouse coordinate + qreal pfx, pfy; + matrixWorld_inv.map(pt.x(),pt.y(),&pfx,&pfy); + + mouseCoordinate.rx()=floor(pfx/ratioX); + mouseCoordinate.ry()=floor(pfy/ratioY); + + if (on_mouse) + on_mouse( cv_event, mouseCoordinate.x(), + mouseCoordinate.y(), flags, on_mouse_param ); +} + + +QSize DefaultViewPort::sizeHint() const +{ + if(image2Draw_mat) + return QSize(image2Draw_mat->cols, image2Draw_mat->rows); + else + return QGraphicsView::sizeHint(); +} + + +void DefaultViewPort::draw2D(QPainter *painter) +{ + image2Draw_qt = QImage(image2Draw_mat->data.ptr, image2Draw_mat->cols, image2Draw_mat->rows,image2Draw_mat->step,QImage::Format_RGB888); + image2Draw_qt_resized = image2Draw_qt.scaled(viewport()->width(),viewport()->height(),Qt::IgnoreAspectRatio,Qt::FastTransformation);//Qt::SmoothTransformation); + painter->drawImage(0,0,image2Draw_qt_resized); +} + +//only if CV_8UC1 or CV_8UC3 +void DefaultViewPort::drawStatusBar() +{ + if (nbChannelOriginImage!=CV_8UC1 && nbChannelOriginImage!=CV_8UC3) + return; + + if (mouseCoordinate.x()>=0 && + mouseCoordinate.y()>=0 && + mouseCoordinate.x()=0 && mouseCoordinate.y()>=0) + { + QRgb rgbValue = image2Draw_qt.pixel(mouseCoordinate); + + if (nbChannelOriginImage==CV_8UC3 ) + { + centralWidget->myStatusBar_msg->setText(tr("(x=%1, y=%2) ~ ") + .arg(mouseCoordinate.x()) + .arg(mouseCoordinate.y())+ + tr("R:%3 ").arg(qRed(rgbValue))+//.arg(value.val[0])+ + tr("G:%4 ").arg(qGreen(rgbValue))+//.arg(value.val[1])+ + tr("B:%5").arg(qBlue(rgbValue))//.arg(value.val[2]) + ); + } + + if (nbChannelOriginImage==CV_8UC1) + { + //all the channel have the same value (because of cvconvertimage), so only the r channel is dsplayed + centralWidget->myStatusBar_msg->setText(tr("(x=%1, y=%2) ~ ") + .arg(mouseCoordinate.x()) + .arg(mouseCoordinate.y())+ + tr("L:%3 ").arg(qRed(rgbValue)) + ); + } + } +} + +//accept only CV_8UC1 and CV_8UC8 image for now +void DefaultViewPort::drawImgRegion(QPainter *painter) +{ + + if (nbChannelOriginImage!=CV_8UC1 && nbChannelOriginImage!=CV_8UC3) + return; + + qreal offsetX = param_matrixWorld.dx()/param_matrixWorld.m11(); + offsetX = offsetX - floor(offsetX); + qreal offsetY = param_matrixWorld.dy()/param_matrixWorld.m11(); + offsetY = offsetY - floor(offsetY); + + QSize view = size(); + QVarLengthArray linesX; + for (qreal _x = offsetX*param_matrixWorld.m11(); _x < view.width(); _x += param_matrixWorld.m11() ) + linesX.append(QLineF(_x, 0, _x, view.height())); + + QVarLengthArray linesY; + for (qreal _y = offsetY*param_matrixWorld.m11(); _y < view.height(); _y += param_matrixWorld.m11() ) + linesY.append(QLineF(0, _y, view.width(), _y)); + + + QFont f = painter->font(); + int original_font_size = f.pointSize(); + //change font size + //f.setPointSize(4+(param_matrixWorld.m11()-threshold_zoom_img_region)/5); + f.setPixelSize(10+(param_matrixWorld.m11()-threshold_zoom_img_region)/5); + painter->setFont(f); + QString val; + QRgb rgbValue; + + QPointF point1;//sorry, I do not know how to name it + QPointF point2;//idem + + for (int j=-1;j= 0 && point2.y() >= 0) + rgbValue = image2Draw_qt_resized.pixel(QPoint(point2.x(),point2.y())); + else + rgbValue = qRgb(0,0,0); + + if (nbChannelOriginImage==CV_8UC3) + { + //for debug + /* + val = tr("%1 %2").arg(point2.x()).arg(point2.y()); + painter->setPen(QPen(Qt::black, 1)); + painter->drawText(QRect(point1.x(),point1.y(),param_matrixWorld.m11(),param_matrixWorld.m11()/2), + Qt::AlignCenter, val); + */ + + val = tr("%1").arg(qRed(rgbValue)); + painter->setPen(QPen(Qt::red, 1)); + painter->drawText(QRect(point1.x(),point1.y(),param_matrixWorld.m11(),param_matrixWorld.m11()/3), + Qt::AlignCenter, val); + + val = tr("%1").arg(qGreen(rgbValue)); + painter->setPen(QPen(Qt::green, 1)); + painter->drawText(QRect(point1.x(),point1.y()+param_matrixWorld.m11()/3,param_matrixWorld.m11(),param_matrixWorld.m11()/3), + Qt::AlignCenter, val); + + val = tr("%1").arg(qBlue(rgbValue)); + painter->setPen(QPen(Qt::blue, 1)); + painter->drawText(QRect(point1.x(),point1.y()+2*param_matrixWorld.m11()/3,param_matrixWorld.m11(),param_matrixWorld.m11()/3), + Qt::AlignCenter, val); + + } + + if (nbChannelOriginImage==CV_8UC1) + { + + val = tr("%1").arg(qRed(rgbValue)); + painter->drawText(QRect(point1.x(),point1.y(),param_matrixWorld.m11(),param_matrixWorld.m11()), + Qt::AlignCenter, val); + } + } + + painter->setPen(QPen(Qt::black, 1)); + painter->drawLines(linesX.data(), linesX.size()); + painter->drawLines(linesY.data(), linesY.size()); + + //restore font size + f.setPointSize(original_font_size); + painter->setFont(f); + +} + +void DefaultViewPort::drawViewOverview(QPainter *painter) +{ + QSize viewSize = size(); + viewSize.scale ( 100, 100,Qt::KeepAspectRatio ); + + const int margin = 5; + + //draw the image's location + painter->setBrush(QColor(0, 0, 0, 127)); + painter->setPen(Qt::darkGreen); + painter->drawRect(QRect(width()-viewSize.width()-margin, 0,viewSize.width(),viewSize.height())); + + //daw the view's location inside the image + qreal ratioSize = 1/param_matrixWorld.m11(); + qreal ratioWindow = (qreal)(viewSize.height())/(qreal)(size().height()); + painter->setPen(Qt::darkBlue); + painter->drawRect(QRectF(width()-viewSize.width()-positionCorners.left()*ratioSize*ratioWindow-margin, + -positionCorners.top()*ratioSize*ratioWindow, + (viewSize.width()-1)*ratioSize, + (viewSize.height()-1)*ratioSize) + ); +} + +void DefaultViewPort::drawInstructions(QPainter *painter) +{ + QFontMetrics metrics = QFontMetrics(font()); + int border = qMax(4, metrics.leading()); + + QRect qrect = metrics.boundingRect(0, 0, width() - 2*border, int(height()*0.125), + Qt::AlignCenter | Qt::TextWordWrap, infoText); + painter->setRenderHint(QPainter::TextAntialiasing); + painter->fillRect(QRect(0, 0, width(), qrect.height() + 2*border), + QColor(0, 0, 0, 127)); + painter->setPen(Qt::white); + painter->fillRect(QRect(0, 0, width(), qrect.height() + 2*border), + QColor(0, 0, 0, 127)); + + painter->drawText((width() - qrect.width())/2, border, + qrect.width(), qrect.height(), + Qt::AlignCenter | Qt::TextWordWrap, infoText); +} + + +void DefaultViewPort::setSize(QSize /*size_*/) +{ +} + + +////////////////////////////////////////////////////// +// OpenGlViewPort + +#ifdef HAVE_QT_OPENGL + +OpenGlViewPort::OpenGlViewPort(QWidget* _parent) : QGLWidget(_parent), size(-1, -1) +{ + mouseCallback = 0; + mouseData = 0; + + glDrawCallback = 0; + glDrawData = 0; + + glCleanCallback = 0; + glCleanData = 0; + + glFuncTab = 0; +} + +OpenGlViewPort::~OpenGlViewPort() +{ + if (glFuncTab) + delete glFuncTab; + + setOpenGlCleanCallback(0, 0); +} + +QWidget* OpenGlViewPort::getWidget() +{ + return this; +} + +void OpenGlViewPort::setMouseCallBack(CvMouseCallback callback, void* param) +{ + mouseCallback = callback; + mouseData = param; +} + +void OpenGlViewPort::writeSettings(QSettings& /*settings*/) +{ +} + +void OpenGlViewPort::readSettings(QSettings& /*settings*/) +{ +} + +double OpenGlViewPort::getRatio() +{ + return (double)width() / height(); +} + +void OpenGlViewPort::setRatio(int /*flags*/) +{ +} + +void OpenGlViewPort::updateImage(const CvArr* /*arr*/) +{ +} + +void OpenGlViewPort::startDisplayInfo(QString /*text*/, int /*delayms*/) +{ +} + +void OpenGlViewPort::setOpenGlDrawCallback(CvOpenGlDrawCallback callback, void* userdata) +{ + glDrawCallback = callback; + glDrawData = userdata; +} + +void OpenGlViewPort::setOpenGlCleanCallback(CvOpenGlCleanCallback callback, void* userdata) +{ + makeCurrentOpenGlContext(); + + if (glCleanCallback) + glCleanCallback(glCleanData); + + glCleanCallback = callback; + glCleanData = userdata; +} + +void OpenGlViewPort::makeCurrentOpenGlContext() +{ + makeCurrent(); + icvSetOpenGlFuncTab(glFuncTab); +} + +void OpenGlViewPort::updateGl() +{ + QGLWidget::updateGL(); +} + +#ifndef APIENTRY + #define APIENTRY +#endif + +#ifndef APIENTRYP + #define APIENTRYP APIENTRY * +#endif + +#ifndef GL_VERSION_1_5 + /* GL types for handling large vertex buffer objects */ + typedef ptrdiff_t GLintptr; + typedef ptrdiff_t GLsizeiptr; +#endif + +typedef void (APIENTRYP PFNGLGENBUFFERSPROC ) (GLsizei n, GLuint *buffers); +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); + +typedef void (APIENTRYP PFNGLBUFFERDATAPROC ) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data); + +typedef void (APIENTRYP PFNGLBINDBUFFERPROC ) (GLenum target, GLuint buffer); + +typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); + +class GlFuncTab_QT : public CvOpenGlFuncTab +{ +public: +#ifdef Q_WS_WIN + GlFuncTab_QT(HDC hDC); +#else + GlFuncTab_QT(); +#endif + + void genBuffers(int n, unsigned int* buffers) const; + void deleteBuffers(int n, const unsigned int* buffers) const; + + void bufferData(unsigned int target, ptrdiff_t size, const void* data, unsigned int usage) const; + void bufferSubData(unsigned int target, ptrdiff_t offset, ptrdiff_t size, const void* data) const; + + void bindBuffer(unsigned int target, unsigned int buffer) const; + + void* mapBuffer(unsigned int target, unsigned int access) const; + void unmapBuffer(unsigned int target) const; + + void generateBitmapFont(const std::string& family, int height, int weight, bool italic, bool underline, int start, int count, int base) const; + + bool isGlContextInitialized() const; + + PFNGLGENBUFFERSPROC glGenBuffersExt; + PFNGLDELETEBUFFERSPROC glDeleteBuffersExt; + + PFNGLBUFFERDATAPROC glBufferDataExt; + PFNGLBUFFERSUBDATAPROC glBufferSubDataExt; + + PFNGLBINDBUFFERPROC glBindBufferExt; + + PFNGLMAPBUFFERPROC glMapBufferExt; + PFNGLUNMAPBUFFERPROC glUnmapBufferExt; + + bool initialized; + +#ifdef Q_WS_WIN + HDC hDC; +#endif +}; + +#ifdef Q_WS_WIN + GlFuncTab_QT::GlFuncTab_QT(HDC hDC_) : hDC(hDC_) +#else + GlFuncTab_QT::GlFuncTab_QT() +#endif +{ + glGenBuffersExt = 0; + glDeleteBuffersExt = 0; + + glBufferDataExt = 0; + glBufferSubDataExt = 0; + + glBindBufferExt = 0; + + glMapBufferExt = 0; + glUnmapBufferExt = 0; + + initialized = false; +} + +void GlFuncTab_QT::genBuffers(int n, unsigned int* buffers) const +{ + CV_FUNCNAME( "GlFuncTab_QT::genBuffers" ); + + __BEGIN__; + + if (!glGenBuffersExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glGenBuffersExt(n, buffers); + CV_CheckGlError(); + + __END__; +} + +void GlFuncTab_QT::deleteBuffers(int n, const unsigned int* buffers) const +{ + CV_FUNCNAME( "GlFuncTab_QT::deleteBuffers" ); + + __BEGIN__; + + if (!glDeleteBuffersExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glDeleteBuffersExt(n, buffers); + CV_CheckGlError(); + + __END__; +} + +void GlFuncTab_QT::bufferData(unsigned int target, ptrdiff_t size, const void* data, unsigned int usage) const +{ + CV_FUNCNAME( "GlFuncTab_QT::bufferData" ); + + __BEGIN__; + + if (!glBufferDataExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glBufferDataExt(target, size, data, usage); + CV_CheckGlError(); + + __END__; +} + +void GlFuncTab_QT::bufferSubData(unsigned int target, ptrdiff_t offset, ptrdiff_t size, const void* data) const +{ + CV_FUNCNAME( "GlFuncTab_QT::bufferSubData" ); + + __BEGIN__; + + if (!glBufferSubDataExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glBufferSubDataExt(target, offset, size, data); + CV_CheckGlError(); + + __END__; +} + +void GlFuncTab_QT::bindBuffer(unsigned int target, unsigned int buffer) const +{ + CV_FUNCNAME( "GlFuncTab_QT::bindBuffer" ); + + __BEGIN__; + + if (!glBindBufferExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glBindBufferExt(target, buffer); + CV_CheckGlError(); + + __END__; +} + +void* GlFuncTab_QT::mapBuffer(unsigned int target, unsigned int access) const +{ + CV_FUNCNAME( "GlFuncTab_QT::mapBuffer" ); + + void* res = 0; + + __BEGIN__; + + if (!glMapBufferExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + res = glMapBufferExt(target, access); + CV_CheckGlError(); + + __END__; + + return res; +} + +void GlFuncTab_QT::unmapBuffer(unsigned int target) const +{ + CV_FUNCNAME( "GlFuncTab_QT::unmapBuffer" ); + + __BEGIN__; + + if (!glUnmapBufferExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glUnmapBufferExt(target); + CV_CheckGlError(); + + __END__; +} + +void GlFuncTab_QT::generateBitmapFont(const std::string& family, int height, int weight, bool italic, bool /*underline*/, int start, int count, int base) const +{ +#ifdef Q_WS_WIN + CV_FUNCNAME( "GlFuncTab_QT::generateBitmapFont" ); +#endif + + QFont font(QString(family.c_str()), height, weight, italic); + + __BEGIN__; + +#ifndef Q_WS_WIN + font.setStyleStrategy(QFont::OpenGLCompatible); + if (font.handle()) + glXUseXFont(font.handle(), start, count, base); +#else + SelectObject(hDC, font.handle()); + if (!wglUseFontBitmaps(hDC, start, count, base)) + CV_ERROR(CV_OpenGlApiCallError, "Can't create font"); +#endif + + __END__; +} + +bool GlFuncTab_QT::isGlContextInitialized() const +{ + return initialized; +} + +void OpenGlViewPort::initializeGL() +{ + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + +#ifdef Q_WS_WIN + std::auto_ptr qglFuncTab(new GlFuncTab_QT(getDC())); +#else + std::auto_ptr qglFuncTab(new GlFuncTab_QT); +#endif + + // Load extensions + + qglFuncTab->glGenBuffersExt = (PFNGLGENBUFFERSPROC)context()->getProcAddress("glGenBuffers"); + qglFuncTab->glDeleteBuffersExt = (PFNGLDELETEBUFFERSPROC)context()->getProcAddress("glDeleteBuffers"); + qglFuncTab->glBufferDataExt = (PFNGLBUFFERDATAPROC)context()->getProcAddress("glBufferData"); + qglFuncTab->glBufferSubDataExt = (PFNGLBUFFERSUBDATAPROC)context()->getProcAddress("glBufferSubData"); + qglFuncTab->glBindBufferExt = (PFNGLBINDBUFFERPROC)context()->getProcAddress("glBindBuffer"); + qglFuncTab->glMapBufferExt = (PFNGLMAPBUFFERPROC)context()->getProcAddress("glMapBuffer"); + qglFuncTab->glUnmapBufferExt = (PFNGLUNMAPBUFFERPROC)context()->getProcAddress("glUnmapBuffer"); + + qglFuncTab->initialized = true; + + glFuncTab = qglFuncTab.release(); + + icvSetOpenGlFuncTab(glFuncTab); +} + +void OpenGlViewPort::resizeGL(int w, int h) +{ + glViewport(0, 0, w, h); +} + +void OpenGlViewPort::paintGL() +{ + icvSetOpenGlFuncTab(glFuncTab); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (glDrawCallback) + glDrawCallback(glDrawData); + + CV_CheckGlError(); +} + +void OpenGlViewPort::mousePressEvent(QMouseEvent* evnt) +{ + int cv_event = -1, flags = 0; + QPoint pt = evnt->pos(); + + icvmouseHandler(evnt, mouse_down, cv_event, flags); + icvmouseProcessing(QPointF(pt), cv_event, flags); + + QGLWidget::mousePressEvent(evnt); +} + + +void OpenGlViewPort::mouseReleaseEvent(QMouseEvent* evnt) +{ + int cv_event = -1, flags = 0; + QPoint pt = evnt->pos(); + + icvmouseHandler(evnt, mouse_up, cv_event, flags); + icvmouseProcessing(QPointF(pt), cv_event, flags); + + QGLWidget::mouseReleaseEvent(evnt); +} + + +void OpenGlViewPort::mouseDoubleClickEvent(QMouseEvent* evnt) +{ + int cv_event = -1, flags = 0; + QPoint pt = evnt->pos(); + + icvmouseHandler(evnt, mouse_dbclick, cv_event, flags); + icvmouseProcessing(QPointF(pt), cv_event, flags); + + QGLWidget::mouseDoubleClickEvent(evnt); +} + + +void OpenGlViewPort::mouseMoveEvent(QMouseEvent* evnt) +{ + int cv_event = CV_EVENT_MOUSEMOVE, flags = 0; + QPoint pt = evnt->pos(); + + //icvmouseHandler: pass parameters for cv_event, flags + icvmouseHandler(evnt, mouse_move, cv_event, flags); + icvmouseProcessing(QPointF(pt), cv_event, flags); + + QGLWidget::mouseMoveEvent(evnt); +} + +void OpenGlViewPort::icvmouseHandler(QMouseEvent* evnt, type_mouse_event category, int& cv_event, int& flags) +{ + Qt::KeyboardModifiers modifiers = evnt->modifiers(); + Qt::MouseButtons buttons = evnt->buttons(); + + flags = 0; + if (modifiers & Qt::ShiftModifier) + flags |= CV_EVENT_FLAG_SHIFTKEY; + if (modifiers & Qt::ControlModifier) + flags |= CV_EVENT_FLAG_CTRLKEY; + if (modifiers & Qt::AltModifier) + flags |= CV_EVENT_FLAG_ALTKEY; + + if (buttons & Qt::LeftButton) + flags |= CV_EVENT_FLAG_LBUTTON; + if (buttons & Qt::RightButton) + flags |= CV_EVENT_FLAG_RBUTTON; + if (buttons & Qt::MidButton) + flags |= CV_EVENT_FLAG_MBUTTON; + + cv_event = CV_EVENT_MOUSEMOVE; + switch (evnt->button()) + { + case Qt::LeftButton: + cv_event = tableMouseButtons[category][0]; + flags |= CV_EVENT_FLAG_LBUTTON; + break; + + case Qt::RightButton: + cv_event = tableMouseButtons[category][1]; + flags |= CV_EVENT_FLAG_RBUTTON; + break; + + case Qt::MidButton: + cv_event = tableMouseButtons[category][2]; + flags |= CV_EVENT_FLAG_MBUTTON; + break; + + default: + ; + } +} + + +void OpenGlViewPort::icvmouseProcessing(QPointF pt, int cv_event, int flags) +{ + if (mouseCallback) + mouseCallback(cv_event, pt.x(), pt.y(), flags, mouseData); +} + + +QSize OpenGlViewPort::sizeHint() const +{ + if (size.width() > 0 && size.height() > 0) + return size; + + return QGLWidget::sizeHint(); +} + +void OpenGlViewPort::setSize(QSize size_) +{ + size = size_; + updateGeometry(); +} + +#endif + +#endif // HAVE_QT diff --git a/highgui/src/window_QT.h b/highgui/src/window_QT.h new file mode 100644 index 0000000..1553b91 --- /dev/null +++ b/highgui/src/window_QT.h @@ -0,0 +1,574 @@ +//IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. + + +// License Agreement +// For Open Source Computer Vision Library + +//Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +//Copyright (C) 2008-2010, Willow Garage Inc., all rights reserved. +//Third party copyrights are property of their respective owners. + +//Redistribution and use in source and binary forms, with or without modification, +//are permitted provided that the following conditions are met: + +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. + +// * Redistribution's 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. + +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. + +//This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. + +//--------------------Google Code 2010 -- Yannick Verdie--------------------// +#ifndef __OPENCV_HIGHGUI_QT_H__ +#define __OPENCV_HIGHGUI_QT_H__ + +#include "precomp.hpp" + +#if defined( HAVE_QT_OPENGL ) +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//start private enum +enum { CV_MODE_NORMAL = 0, CV_MODE_OPENGL = 1 }; + +//we can change the keyboard shortcuts from here ! +enum { shortcut_zoom_normal = Qt::CTRL + Qt::Key_Z, + shortcut_zoom_imgRegion = Qt::CTRL + Qt::Key_X, + shortcut_save_img = Qt::CTRL + Qt::Key_S, + shortcut_properties_win = Qt::CTRL + Qt::Key_P, + shortcut_zoom_in = Qt::CTRL + Qt::Key_Plus,//QKeySequence(QKeySequence::ZoomIn), + shortcut_zoom_out = Qt::CTRL + Qt::Key_Minus,//QKeySequence(QKeySequence::ZoomOut), + shortcut_panning_left = Qt::CTRL + Qt::Key_Left, + shortcut_panning_right = Qt::CTRL + Qt::Key_Right, + shortcut_panning_up = Qt::CTRL + Qt::Key_Up, + shortcut_panning_down = Qt::CTRL + Qt::Key_Down + }; + +//end enum + +class CvWindow; +class ViewPort; + + +class GuiReceiver : public QObject +{ + Q_OBJECT + +public: + GuiReceiver(); + ~GuiReceiver(); + + int start(); + void isLastWindow(); + + bool bTimeOut; + QTimer* timer; + +public slots: + void createWindow( QString name, int flags = 0 ); + void destroyWindow(QString name); + void destroyAllWindow(); + void addSlider(QString trackbar_name, QString window_name, void* value, int count, void* on_change); + void addSlider2(QString trackbar_name, QString window_name, void* value, int count, void* on_change, void *userdata); + void moveWindow(QString name, int x, int y); + void resizeWindow(QString name, int width, int height); + void showImage(QString name, void* arr); + void displayInfo( QString name, QString text, int delayms ); + void displayStatusBar( QString name, QString text, int delayms ); + void timeOut(); + void toggleFullScreen(QString name, double flags ); + double isFullScreen(QString name); + double getPropWindow(QString name); + void setPropWindow(QString name, double flags ); + double getRatioWindow(QString name); + void setRatioWindow(QString name, double arg2 ); + void saveWindowParameters(QString name); + void loadWindowParameters(QString name); + void putText(void* arg1, QString text, QPoint org, void* font); + void addButton(QString button_name, int button_type, int initial_button_state , void* on_change, void* userdata); + void enablePropertiesButtonEachWindow(); + + void setOpenGlDrawCallback(QString name, void* callback, void* userdata); + void setOpenGlCleanCallback(QString name, void* callback, void* userdata); + void setOpenGlContext(QString name); + void updateWindow(QString name); + double isOpenGl(QString name); + +private: + int nb_windows; + bool doesExternalQAppExist; +}; + + +enum typeBar { type_CvTrackbar = 0, type_CvButtonbar = 1 }; +class CvBar : public QHBoxLayout +{ +public: + typeBar type; + QString name_bar; + QPointer myparent; +}; + + +class CvButtonbar : public CvBar +{ + Q_OBJECT +public: + CvButtonbar(QWidget* arg, QString bar_name); + + void addButton(QString button_name, CvButtonCallback call, void* userdata, int button_type, int initial_button_state); + +private: + void setLabel(); + + QPointer label; + QPointer group_button; +}; + + +class CvPushButton : public QPushButton +{ + Q_OBJECT +public: + CvPushButton(CvButtonbar* par, QString button_name, CvButtonCallback call, void* userdata); + +private: + CvButtonbar* myparent; + QString button_name ; + CvButtonCallback callback; + void* userdata; + +private slots: + void callCallBack(bool); +}; + + +class CvCheckBox : public QCheckBox +{ + Q_OBJECT +public: + CvCheckBox(CvButtonbar* par, QString button_name, CvButtonCallback call, void* userdata, int initial_button_state); + +private: + CvButtonbar* myparent; + QString button_name ; + CvButtonCallback callback; + void* userdata; + +private slots: + void callCallBack(bool); +}; + + +class CvRadioButton : public QRadioButton +{ + Q_OBJECT +public: + CvRadioButton(CvButtonbar* par, QString button_name, CvButtonCallback call, void* userdata, int initial_button_state); + +private: + CvButtonbar* myparent; + QString button_name ; + CvButtonCallback callback; + void* userdata; + +private slots: + void callCallBack(bool); +}; + + +class CvTrackbar : public CvBar +{ + Q_OBJECT +public: + CvTrackbar(CvWindow* parent, QString name, int* value, int count, CvTrackbarCallback on_change); + CvTrackbar(CvWindow* parent, QString name, int* value, int count, CvTrackbarCallback2 on_change, void* data); + + QPointer slider; + +private slots: + void createDialog(); + void update(int myvalue); + +private: + void setLabel(int myvalue); + void create(CvWindow* arg, QString name, int* value, int count); + QString createLabel(); + QPointer label; + CvTrackbarCallback callback; + CvTrackbarCallback2 callback2;//look like it is use by python binding + int* dataSlider; + void* userdata; +}; + +//Both are top level window, so that a way to differenciate them. +//if (obj->metaObject ()->className () == "CvWindow") does not give me robust result + +enum typeWindow { type_CvWindow = 1, type_CvWinProperties = 2 }; +class CvWinModel : public QWidget +{ +public: +typeWindow type; +}; + + +class CvWinProperties : public CvWinModel +{ + Q_OBJECT +public: + CvWinProperties(QString name, QObject* parent); + ~CvWinProperties(); + QPointer myLayout; + +private: + void closeEvent ( QCloseEvent * e ); + void showEvent ( QShowEvent * event ) ; + void hideEvent ( QHideEvent * event ) ; +}; + + +class CvWindow : public CvWinModel +{ + Q_OBJECT +public: + CvWindow(QString arg2, int flag = CV_WINDOW_NORMAL); + ~CvWindow(); + + void setMouseCallBack(CvMouseCallback m, void* param); + + void writeSettings(); + void readSettings(); + + double getRatio(); + void setRatio(int flags); + + int getPropWindow(); + void setPropWindow(int flags); + + void toggleFullScreen(int flags); + + void updateImage(void* arr); + + void displayInfo(QString text, int delayms); + void displayStatusBar(QString text, int delayms); + + void enablePropertiesButton(); + + static CvButtonbar* createButtonBar(QString bar_name); + + static void addSlider(CvWindow* w, QString name, int* value, int count, CvTrackbarCallback on_change CV_DEFAULT(NULL)); + static void addSlider2(CvWindow* w, QString name, int* value, int count, CvTrackbarCallback2 on_change CV_DEFAULT(NULL), void* userdata CV_DEFAULT(0)); + + void setOpenGlDrawCallback(CvOpenGlDrawCallback callback, void* userdata); + void setOpenGlCleanCallback(CvOpenGlCleanCallback callback, void* userdata); + void makeCurrentOpenGlContext(); + void updateGl(); + bool isOpenGl(); + + void setViewportSize(QSize size); + + //parameters (will be save/load) + int param_flags; + int param_gui_mode; + int param_ratio_mode; + + QPointer myGlobalLayout; //All the widget (toolbar, view, LayoutBar, ...) are attached to it + QPointer myBarLayout; + + QVector vect_QActions; + + QPointer myStatusBar; + QPointer myToolBar; + QPointer myStatusBar_msg; + +protected: + virtual void keyPressEvent(QKeyEvent* event); + +private: + + int mode_display; //opengl or native + ViewPort* myView; + + QVector vect_QShortcuts; + + void icvLoadTrackbars(QSettings *settings); + void icvSaveTrackbars(QSettings *settings); + void icvLoadControlPanel(); + void icvSaveControlPanel(); + void icvLoadButtonbar(CvButtonbar* t,QSettings *settings); + void icvSaveButtonbar(CvButtonbar* t,QSettings *settings); + + void createActions(); + void createShortcuts(); + void createToolBar(); + void createView(); + void createStatusBar(); + void createGlobalLayout(); + void createBarLayout(); + CvWinProperties* createParameterWindow(); + + void hideTools(); + void showTools(); + QSize getAvailableSize(); + +private slots: + void displayPropertiesWin(); +}; + + +enum type_mouse_event { mouse_up = 0, mouse_down = 1, mouse_dbclick = 2, mouse_move = 3 }; +static const int tableMouseButtons[][3]={ + {CV_EVENT_LBUTTONUP, CV_EVENT_RBUTTONUP, CV_EVENT_MBUTTONUP}, //mouse_up + {CV_EVENT_LBUTTONDOWN, CV_EVENT_RBUTTONDOWN, CV_EVENT_MBUTTONDOWN}, //mouse_down + {CV_EVENT_LBUTTONDBLCLK, CV_EVENT_RBUTTONDBLCLK, CV_EVENT_MBUTTONDBLCLK}, //mouse_dbclick + {CV_EVENT_MOUSEMOVE, CV_EVENT_MOUSEMOVE, CV_EVENT_MOUSEMOVE} //mouse_move +}; + + +class ViewPort +{ +public: + virtual ~ViewPort() {} + + virtual QWidget* getWidget() = 0; + + virtual void setMouseCallBack(CvMouseCallback callback, void* param) = 0; + + virtual void writeSettings(QSettings& settings) = 0; + virtual void readSettings(QSettings& settings) = 0; + + virtual double getRatio() = 0; + virtual void setRatio(int flags) = 0; + + virtual void updateImage(const CvArr* arr) = 0; + + virtual void startDisplayInfo(QString text, int delayms) = 0; + + virtual void setOpenGlDrawCallback(CvOpenGlDrawCallback callback, void* userdata) = 0; + virtual void setOpenGlCleanCallback(CvOpenGlCleanCallback callback, void* userdata) = 0; + virtual void makeCurrentOpenGlContext() = 0; + virtual void updateGl() = 0; + + virtual void setSize(QSize size_) = 0; +}; + + + +#ifdef HAVE_QT_OPENGL + +class OpenGlViewPort : public QGLWidget, public ViewPort +{ +public: + explicit OpenGlViewPort(QWidget* parent); + ~OpenGlViewPort(); + + QWidget* getWidget(); + + void setMouseCallBack(CvMouseCallback callback, void* param); + + void writeSettings(QSettings& settings); + void readSettings(QSettings& settings); + + double getRatio(); + void setRatio(int flags); + + void updateImage(const CvArr* arr); + + void startDisplayInfo(QString text, int delayms); + + void setOpenGlDrawCallback(CvOpenGlDrawCallback callback, void* userdata); + void setOpenGlCleanCallback(CvOpenGlCleanCallback callback, void* userdata); + void makeCurrentOpenGlContext(); + void updateGl(); + + void setSize(QSize size_); + +protected: + void initializeGL(); + void resizeGL(int w, int h); + void paintGL(); + + void mouseMoveEvent(QMouseEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent* event); + void mouseDoubleClickEvent(QMouseEvent* event); + + QSize sizeHint() const; + +private: + QSize size; + + CvMouseCallback mouseCallback; + void* mouseData; + + CvOpenGlDrawCallback glDrawCallback; + void* glDrawData; + + CvOpenGlCleanCallback glCleanCallback; + void* glCleanData; + + CvOpenGlFuncTab* glFuncTab; + + void icvmouseHandler(QMouseEvent* event, type_mouse_event category, int& cv_event, int& flags); + void icvmouseProcessing(QPointF pt, int cv_event, int flags); +}; + +#endif // HAVE_QT_OPENGL + + +class DefaultViewPort : public QGraphicsView, public ViewPort +{ + Q_OBJECT + +public: + DefaultViewPort(CvWindow* centralWidget, int arg2); + ~DefaultViewPort(); + + QWidget* getWidget(); + + void setMouseCallBack(CvMouseCallback callback, void* param); + + void writeSettings(QSettings& settings); + void readSettings(QSettings& settings); + + double getRatio(); + void setRatio(int flags); + + void updateImage(const CvArr* arr); + + void startDisplayInfo(QString text, int delayms); + + void setOpenGlDrawCallback(CvOpenGlDrawCallback callback, void* userdata); + void setOpenGlCleanCallback(CvOpenGlCleanCallback callback, void* userdata); + void makeCurrentOpenGlContext(); + void updateGl(); + + void setSize(QSize size_); + +public slots: + //reference: + //http://www.qtcentre.org/wiki/index.php?title=QGraphicsView:_Smooth_Panning_and_Zooming + //http://doc.qt.nokia.com/4.6/gestures-imagegestures-imagewidget-cpp.html + + void siftWindowOnLeft(); + void siftWindowOnRight(); + void siftWindowOnUp() ; + void siftWindowOnDown(); + + void resetZoom(); + void imgRegion(); + void ZoomIn(); + void ZoomOut(); + + void saveView(); + +protected: + void contextMenuEvent(QContextMenuEvent* event); + void resizeEvent(QResizeEvent* event); + void paintEvent(QPaintEvent* paintEventInfo); + void wheelEvent(QWheelEvent* event); + void mouseMoveEvent(QMouseEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent* event); + void mouseDoubleClickEvent(QMouseEvent* event); + +private: + int param_keepRatio; + + //parameters (will be save/load) + QTransform param_matrixWorld; + + CvMat* image2Draw_mat; + QImage image2Draw_qt; + QImage image2Draw_qt_resized; + int nbChannelOriginImage; + + //for mouse callback + CvMouseCallback on_mouse; + void* on_mouse_param; + + + void scaleView(qreal scaleFactor, QPointF center); + void moveView(QPointF delta); + + QPoint mouseCoordinate; + QPointF positionGrabbing; + QRect positionCorners; + QTransform matrixWorld_inv; + float ratioX, ratioY; + + bool isSameSize(IplImage* img1,IplImage* img2); + + QSize sizeHint() const; + QPointer centralWidget; + QPointer timerDisplay; + bool drawInfo; + QString infoText; + QRectF target; + + void drawInstructions(QPainter *painter); + void drawViewOverview(QPainter *painter); + void drawImgRegion(QPainter *painter); + void draw2D(QPainter *painter); + void drawStatusBar(); + void controlImagePosition(); + void icvmouseHandler(QMouseEvent *event, type_mouse_event category, int &cv_event, int &flags); + void icvmouseProcessing(QPointF pt, int cv_event, int flags); + +private slots: + void stopDisplayInfo(); +}; + +#endif diff --git a/highgui/src/window_QT.qrc b/highgui/src/window_QT.qrc new file mode 100644 index 0000000..7bcdc24 --- /dev/null +++ b/highgui/src/window_QT.qrc @@ -0,0 +1,15 @@ + + + files_Qt/Milky/48/28.png + files_Qt/Milky/48/23.png + files_Qt/Milky/48/19.png + files_Qt/Milky/48/24.png + files_Qt/Milky/48/27.png + files_Qt/Milky/48/61.png + files_Qt/Milky/48/106.png + files_Qt/Milky/48/107.png + files_Qt/Milky/48/7.png + files_Qt/Milky/48/38.png + files_Qt/stylesheet_trackbar.qss + + diff --git a/highgui/src/window_carbon.cpp b/highgui/src/window_carbon.cpp new file mode 100644 index 0000000..68d2cd4 --- /dev/null +++ b/highgui/src/window_carbon.cpp @@ -0,0 +1,1100 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#include +#include //YV + +#include +#include +#include + +//#define MS_TO_TICKS(a) a*3/50 + +#define LABELWIDTH 64 +#define INTERWIDGETSPACE 16 +#define WIDGETHEIGHT 32 +#define NO_KEY -1 + +struct CvWindow; + +typedef struct CvTrackbar +{ + int signature; + + ControlRef trackbar; + ControlRef label; + + char* name; + CvTrackbar* next; + CvWindow* parent; + int* data; + int pos; + int maxval; + int labelSize;//Yannick Verdie + CvTrackbarCallback notify; + CvTrackbarCallback2 notify2; + void* userdata; +} +CvTrackbar; + + +typedef struct CvWindow +{ + int signature; + + char* name; + CvWindow* prev; + CvWindow* next; + + WindowRef window; + WindowRef oldwindow;//YV + CGImageRef imageRef; + int imageWidth;//FD + int imageHeight;//FD + + CvMat* image; + CvMat* dst_image; + int converted; + int last_key; + int flags; + int status;//YV + Ptr restoreState;//YV + + CvMouseCallback on_mouse; + void* on_mouse_param; + + struct { + int pos; + int rows; + CvTrackbar* first; + } + toolbar; + int trackbarheight; +} +CvWindow; + +static CvWindow* hg_windows = 0; + +#define Assert(exp) \ +if( !(exp) ) \ +{ \ + printf("Assertion: %s %s: %d\n", #exp, __FILE__, __LINE__);\ + assert(exp); \ +} + +static int wasInitialized = 0; +static char lastKey = NO_KEY; +OSStatus keyHandler(EventHandlerCallRef hcr, EventRef theEvent, void* inUserData); +static pascal OSStatus windowEventHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void *inUserData); + +static const EventTypeSpec applicationKeyboardEvents[] = +{ + { kEventClassKeyboard, kEventRawKeyDown }, +}; + +CV_IMPL int cvInitSystem( int argc, char** argv ) +{ + OSErr err = noErr; + if( !wasInitialized ) + { + + hg_windows = 0; + err = InstallApplicationEventHandler(NewEventHandlerUPP( keyHandler),GetEventTypeCount(applicationKeyboardEvents),applicationKeyboardEvents,NULL,NULL); + if (err != noErr) + { + fprintf(stderr,"InstallApplicationEventHandler was not ok\n"); + } + wasInitialized = 1; + } + + return 0; +} + +// TODO: implement missing functionality +CV_IMPL int cvStartWindowThread() +{ + return 0; +} + +static int icvCountTrackbarInWindow( const CvWindow* window) +{ + CvTrackbar* trackbar = window->toolbar.first; + int count = 0; + while (trackbar != 0) { + count++; + trackbar = trackbar->next; + } + return count; +} + +static CvTrackbar* icvTrackbarByHandle( void * handle ) +{ + CvWindow* window = hg_windows; + CvTrackbar* trackbar = NULL; + while( window != 0 && window->window != handle) { + trackbar = window->toolbar.first; + while (trackbar != 0 && trackbar->trackbar != handle) + trackbar = trackbar->next; + if (trackbar != 0 && trackbar->trackbar == handle) + break; + window = window->next; + } + return trackbar; +} + +static CvWindow* icvWindowByHandle( void * handle ) +{ + CvWindow* window = hg_windows; + + while( window != 0 && window->window != handle) + window = window->next; + + return window; +} + +CV_IMPL CvWindow * icvFindWindowByName( const char* name) +{ + CvWindow* window = hg_windows; + while( window != 0 && strcmp(name, window->name) != 0 ) + window = window->next; + + return window; +} + +static CvTrackbar* icvFindTrackbarByName( const CvWindow* window, const char* name ) +{ + CvTrackbar* trackbar = window->toolbar.first; + + while (trackbar != 0 && strcmp( trackbar->name, name ) != 0) + trackbar = trackbar->next; + + return trackbar; +} + +//FD +/* draw image to frame */ +static void icvDrawImage( CvWindow* window ) +{ + Assert( window != 0 ); + if( window->imageRef == 0 ) return; + + CGContextRef myContext; + CGRect rect; + Rect portrect; + int width = window->imageWidth; + int height = window->imageHeight; + + GetWindowPortBounds(window->window, &portrect); + + if(!( window->flags & CV_WINDOW_AUTOSIZE) ) //YV + { + CGPoint origin = {0,0}; + CGSize size = {portrect.right-portrect.left, portrect.bottom-portrect.top-window->trackbarheight}; + rect.origin = origin; rect.size = size; + } + else + { + CGPoint origin = {0, portrect.bottom - height - window->trackbarheight}; + CGSize size = {width, height}; + rect.origin = origin; rect.size = size; + } + + /* To be sybnchronous we are using this, better would be to susbcribe to the draw event and process whenever requested, we might save SOME CPU cycles*/ + SetPortWindowPort (window->window); + QDBeginCGContext (GetWindowPort (window->window), &myContext); + CGContextSetInterpolationQuality (myContext, kCGInterpolationLow); + CGContextDrawImage(myContext,rect,window->imageRef); + CGContextFlush(myContext);// 4 + QDEndCGContext (GetWindowPort(window->window), &myContext);// 5 +} + +//FD +/* update imageRef */ +static void icvPutImage( CvWindow* window ) +{ + Assert( window != 0 ); + if( window->image == 0 ) return; + + CGColorSpaceRef colorspace = NULL; + CGDataProviderRef provider = NULL; + int width = window->imageWidth = window->image->cols; + int height = window->imageHeight = window->image->rows; + + colorspace = CGColorSpaceCreateDeviceRGB(); + + int size = 8; + int nbChannels = 3; + + provider = CGDataProviderCreateWithData(NULL, window->image->data.ptr, width * height , NULL ); + + if (window->imageRef != NULL){ + CGImageRelease(window->imageRef); + window->imageRef = NULL; + } + + window->imageRef = CGImageCreate( width, height, size , size*nbChannels , window->image->step, colorspace, kCGImageAlphaNone , provider, NULL, true, kCGRenderingIntentDefault ); + icvDrawImage( window ); + + /* release the provider's memory */ + CGDataProviderRelease( provider ); +} + +static void icvUpdateWindowSize( const CvWindow* window ) +{ + int width = 0, height = 240; /* init à al taille de base de l'image*/ + Rect globalBounds; + + GetWindowBounds(window->window, kWindowContentRgn, &globalBounds); + + int minWidth = 320; + + if( window->image ) { + width = MAX(MAX(window->image->width, width), minWidth); + height = window->image->height; + } else + width = minWidth; + + height += window->trackbarheight; + + //height +=WIDGETHEIGHT; /* 32 pixels are spearating tracbars from the video display */ + + globalBounds.right = globalBounds.left + width; + globalBounds.bottom = globalBounds.top + height; + SetWindowBounds(window->window, kWindowContentRgn, &globalBounds); +} + +static void icvDeleteWindow( CvWindow* window ) +{ + CvTrackbar* trackbar; + + if( window->prev ) + window->prev->next = window->next; + else + hg_windows = window->next; + + if( window->next ) + window->next->prev = window->prev; + + window->prev = window->next = 0; + + cvReleaseMat( &window->image ); + cvReleaseMat( &window->dst_image ); + + for( trackbar = window->toolbar.first; trackbar != 0; ) + { + CvTrackbar* next = trackbar->next; + cvFree( (void**)&trackbar ); + trackbar = next; + } + + if (window->imageRef != NULL) + CGImageRelease(window->imageRef); + + DisposeWindow (window->window);//YV + + cvFree( (void**)&window ); +} + + +CV_IMPL void cvDestroyWindow( const char* name) +{ + CV_FUNCNAME( "cvDestroyWindow" ); + + __BEGIN__; + + CvWindow* window; + + if(!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if( !window ) + EXIT; + + icvDeleteWindow( window ); + + __END__; +} + + +CV_IMPL void cvDestroyAllWindows( void ) +{ + while( hg_windows ) + { + CvWindow* window = hg_windows; + icvDeleteWindow( window ); + } +} + + +CV_IMPL void cvShowImage( const char* name, const CvArr* arr) +{ + CV_FUNCNAME( "cvShowImage" ); + + __BEGIN__; + + CvWindow* window; + int origin = 0; + int resize = 0; + CvMat stub, *image; + + if( !name ) + CV_ERROR( CV_StsNullPtr, "NULL name" ); + + window = icvFindWindowByName(name); + if(!window) + { + cvNamedWindow(name, 1); + window = icvFindWindowByName(name); + } + + if( !window || !arr ) + EXIT; // keep silence here. + + if( CV_IS_IMAGE_HDR( arr )) + origin = ((IplImage*)arr)->origin; + + CV_CALL( image = cvGetMat( arr, &stub )); + + /* + if( !window->image ) + cvResizeWindow( name, image->cols, image->rows ); + */ + + if( window->image && + !CV_ARE_SIZES_EQ(window->image, image) ) { + if ( ! (window->flags & CV_WINDOW_AUTOSIZE) )//FD + resize = 1; + cvReleaseMat( &window->image ); + } + + if( !window->image ) { + resize = 1;//FD + window->image = cvCreateMat( image->rows, image->cols, CV_8UC3 ); + } + + cvConvertImage( image, window->image, (origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB ); + icvPutImage( window ); + if ( resize )//FD + icvUpdateWindowSize( window ); + + __END__; +} + +CV_IMPL void cvResizeWindow( const char* name, int width, int height) +{ + CV_FUNCNAME( "cvResizeWindow" ); + + __BEGIN__; + + CvWindow* window; + //CvTrackbar* trackbar; + + if( !name ) + CV_ERROR( CV_StsNullPtr, "NULL name" ); + + window = icvFindWindowByName(name); + if(!window) + EXIT; + + SizeWindow(window->window, width, height, true); + + __END__; +} + +CV_IMPL void cvMoveWindow( const char* name, int x, int y) +{ + CV_FUNCNAME( "cvMoveWindow" ); + + __BEGIN__; + + CvWindow* window; + //CvTrackbar* trackbar; + + if( !name ) + CV_ERROR( CV_StsNullPtr, "NULL name" ); + + window = icvFindWindowByName(name); + if(!window) + EXIT; + + MoveWindow(window->window, x, y, true); + + __END__; +} + +void TrackbarActionProcPtr (ControlRef theControl, ControlPartCode partCode) +{ + CvTrackbar * trackbar = icvTrackbarByHandle (theControl); + + if (trackbar == NULL) + { + fprintf(stderr,"Error getting trackbar\n"); + return; + } + else + { + int pos = GetControl32BitValue (theControl); + if ( trackbar->data ) + *trackbar->data = pos; + if ( trackbar->notify ) + trackbar->notify(pos); + else if ( trackbar->notify2 ) + trackbar->notify2(pos, trackbar->userdata); + + //--------YV--------------------------- + CFStringEncoding encoding = kCFStringEncodingASCII; + CFAllocatorRef alloc_default = kCFAllocatorDefault; // = NULL; + + char valueinchar[20]; + sprintf(valueinchar, " (%d)", *trackbar->data); + + // create an empty CFMutableString + CFIndex maxLength = 256; + CFMutableStringRef cfstring = CFStringCreateMutable(alloc_default,maxLength); + + // append some c strings into it. + CFStringAppendCString(cfstring,trackbar->name,encoding); + CFStringAppendCString(cfstring,valueinchar,encoding); + + SetControlData(trackbar->label, kControlEntireControl,kControlStaticTextCFStringTag, sizeof(cfstring), &cfstring); + DrawControls(trackbar->parent->window); + //----------------------------------------- + } +} + + +static int icvCreateTrackbar (const char* trackbar_name, + const char* window_name, + int* val, int count, + CvTrackbarCallback on_notify, + CvTrackbarCallback2 on_notify2, + void* userdata) +{ + int result = 0; + + CV_FUNCNAME( "icvCreateTrackbar" ); + __BEGIN__; + + /*char slider_name[32];*/ + CvWindow* window = 0; + CvTrackbar* trackbar = 0; + Rect stboundsRect; + ControlRef outControl; + ControlRef stoutControl; + Rect bounds; + + if( !window_name || !trackbar_name ) + CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" ); + + if( count <= 0 ) + CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" ); + + window = icvFindWindowByName(window_name); + if( !window ) + EXIT; + + trackbar = icvFindTrackbarByName(window,trackbar_name); + if( !trackbar ) + { + int len = strlen(trackbar_name); + trackbar = (CvTrackbar*)cvAlloc(sizeof(CvTrackbar) + len + 1); + memset( trackbar, 0, sizeof(*trackbar)); + trackbar->signature = CV_TRACKBAR_MAGIC_VAL; + trackbar->name = (char*)(trackbar+1); + memcpy( trackbar->name, trackbar_name, len + 1 ); + trackbar->parent = window; + trackbar->next = window->toolbar.first; + window->toolbar.first = trackbar; + + if( val ) + { + int value = *val; + if( value < 0 ) + value = 0; + if( value > count ) + value = count; + trackbar->pos = value; + trackbar->data = val; + } + + trackbar->maxval = count; + + //----------- YV ---------------------- + //get nb of digits + int nbDigit = 0; + while((count/=10)>10){ + nbDigit++; + } + + //pad size maxvalue in pixel + Point qdSize; + char valueinchar[strlen(trackbar_name)+1 +1 +1+nbDigit+1];//lenght+\n +space +(+nbDigit+) + sprintf(valueinchar, "%s (%d)",trackbar_name, trackbar->maxval); + SInt16 baseline; + CFStringRef text = CFStringCreateWithCString(NULL,valueinchar,kCFStringEncodingASCII); + GetThemeTextDimensions( text, kThemeCurrentPortFont, kThemeStateActive, false, &qdSize, &baseline ); + trackbar->labelSize = qdSize.h; + //-------------------------------------- + + int c = icvCountTrackbarInWindow(window); + + GetWindowBounds(window->window,kWindowContentRgn,&bounds); + + stboundsRect.top = (INTERWIDGETSPACE +WIDGETHEIGHT)* (c-1)+INTERWIDGETSPACE; + stboundsRect.left = INTERWIDGETSPACE; + stboundsRect.bottom = stboundsRect.top + WIDGETHEIGHT; + stboundsRect.right = stboundsRect.left+LABELWIDTH; + + //fprintf(stdout,"create trackabar bounds (%d %d %d %d)\n",stboundsRect.top,stboundsRect.left,stboundsRect.bottom,stboundsRect.right); + //----------- YV ---------------------- + sprintf(valueinchar, "%s (%d)",trackbar_name, trackbar->pos); + CreateStaticTextControl (window->window,&stboundsRect,CFStringCreateWithCString(NULL,valueinchar,kCFStringEncodingASCII),NULL,&stoutControl); + //-------------------------------------- + + stboundsRect.top = (INTERWIDGETSPACE +WIDGETHEIGHT)* (c-1)+INTERWIDGETSPACE; + stboundsRect.left = INTERWIDGETSPACE*2+LABELWIDTH; + stboundsRect.bottom = stboundsRect.top + WIDGETHEIGHT; + stboundsRect.right = bounds.right-INTERWIDGETSPACE; + + CreateSliderControl (window->window,&stboundsRect, trackbar->pos,0,trackbar->maxval,kControlSliderLiveFeedback,0,true,NewControlActionUPP(TrackbarActionProcPtr),&outControl); + + bounds.bottom += INTERWIDGETSPACE + WIDGETHEIGHT; + SetControlVisibility (outControl,true,true); + SetControlVisibility (stoutControl,true,true); + + trackbar->trackbar = outControl; + trackbar->label = stoutControl; + if (c == 1) + window->trackbarheight = INTERWIDGETSPACE*2 + WIDGETHEIGHT; + else + window->trackbarheight += INTERWIDGETSPACE + WIDGETHEIGHT; + icvUpdateWindowSize( window ); + } + + trackbar->notify = on_notify; + trackbar->notify2 = on_notify2; + trackbar->userdata = userdata; + + result = 1; + + __END__; + return result; +} + + +CV_IMPL int cvCreateTrackbar (const char* trackbar_name, + const char* window_name, + int* val, int count, + CvTrackbarCallback on_notify) +{ + return icvCreateTrackbar(trackbar_name, window_name, val, count, on_notify, 0, 0); +} + + +CV_IMPL int cvCreateTrackbar2(const char* trackbar_name, + const char* window_name, + int* val, int count, + CvTrackbarCallback2 on_notify2, + void* userdata) +{ + return icvCreateTrackbar(trackbar_name, window_name, val, + count, 0, on_notify2, userdata); +} + + +CV_IMPL void +cvSetMouseCallback( const char* name, CvMouseCallback function, void* info) +{ + CvWindow* window = icvFindWindowByName( name ); + if (window != NULL) + { + window->on_mouse = function; + window->on_mouse_param = info; + } + else + { + fprintf(stdout,"Error with cvSetMouseCallback. Window not found : %s\n",name); + } +} + + CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name ) +{ + int pos = -1; + + CV_FUNCNAME( "cvGetTrackbarPos" ); + + __BEGIN__; + + CvWindow* window; + CvTrackbar* trackbar = 0; + + if( trackbar_name == 0 || window_name == 0 ) + CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" ); + + window = icvFindWindowByName( window_name ); + if( window ) + trackbar = icvFindTrackbarByName( window, trackbar_name ); + + if( trackbar ) + pos = trackbar->pos; + + __END__; + + return pos; +} + +CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name, int pos) +{ + CV_FUNCNAME( "cvSetTrackbarPos" ); + + __BEGIN__; + + CvWindow* window; + CvTrackbar* trackbar = 0; + + if( trackbar_name == 0 || window_name == 0 ) + CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" ); + + window = icvFindWindowByName( window_name ); + if( window ) + trackbar = icvFindTrackbarByName( window, trackbar_name ); + + if( trackbar ) + { + if( pos < 0 ) + pos = 0; + + if( pos > trackbar->maxval ) + pos = trackbar->maxval; + + // Set new value and redraw the trackbar + SetControlValue( trackbar->trackbar, pos ); + Draw1Control( trackbar->trackbar ); + } + + __END__; + return ; +} + +CV_IMPL void* cvGetWindowHandle( const char* name ) +{ + WindowRef result = 0; + + __BEGIN__; + + CvWindow* window; + window = icvFindWindowByName( name ); + if (window != NULL) + result = window->window; + else + result = NULL; + + __END__; + + return result; +} + + +CV_IMPL const char* cvGetWindowName( void* window_handle ) +{ + const char* window_name = ""; + + CV_FUNCNAME( "cvGetWindowName" ); + + __BEGIN__; + + CvWindow* window; + + if( window_handle == 0 ) + CV_ERROR( CV_StsNullPtr, "NULL window" ); + window = icvWindowByHandle(window_handle ); + if( window ) + window_name = window->name; + + __END__; + + return window_name; +} + +double cvGetModeWindow_CARBON(const char* name)//YV +{ + double result = -1; + + CV_FUNCNAME( "cvGetModeWindow_QT" ); + + __BEGIN__; + + CvWindow* window; + + if(!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if( !window ) + CV_ERROR( CV_StsNullPtr, "NULL window" ); + + result = window->status; + + __END__; + return result; +} + +void cvSetModeWindow_CARBON( const char* name, double prop_value)//Yannick Verdie +{ + OSStatus err = noErr; + + + CV_FUNCNAME( "cvSetModeWindow_QT" ); + + __BEGIN__; + + CvWindow* window; + + if(!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if( !window ) + CV_ERROR( CV_StsNullPtr, "NULL window" ); + + if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set + EXIT; + + if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL) + { + err = EndFullScreen(window->restoreState,0); + if (err != noErr) + fprintf(stdout,"Error EndFullScreen\n"); + window->window = window->oldwindow; + ShowWindow( window->window ); + + window->status=CV_WINDOW_NORMAL; + EXIT; + } + + if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN) + { + GDHandle device; + err = GetWindowGreatestAreaDevice(window->window, kWindowTitleBarRgn, &device, NULL); + if (err != noErr) + fprintf(stdout,"Error GetWindowGreatestAreaDevice\n"); + + HideWindow(window->window); + window->oldwindow = window->window; + err = BeginFullScreen(&(window->restoreState), device, 0, 0, &window->window, 0, fullScreenAllowEvents | fullScreenDontSwitchMonitorResolution); + if (err != noErr) + fprintf(stdout,"Error BeginFullScreen\n"); + + window->status=CV_WINDOW_FULLSCREEN; + EXIT; + } + + __END__; +} + +CV_IMPL int cvNamedWindow( const char* name, int flags ) +{ + int result = 0; + CV_FUNCNAME( "cvNamedWindow" ); + if (!wasInitialized) + cvInitSystem(0, NULL); + + // to be able to display a window, we need to be a 'faceful' application + // http://lists.apple.com/archives/carbon-dev/2005/Jun/msg01414.html + static bool switched_to_faceful = false; + if (! switched_to_faceful) + { + ProcessSerialNumber psn = { 0, kCurrentProcess }; + OSStatus ret = TransformProcessType (&psn, kProcessTransformToForegroundApplication ); + + if (ret == noErr) + { + SetFrontProcess( &psn ); + switched_to_faceful = true; + } + else + { + fprintf(stderr, "Failed to tranform process type: %d\n", (int) ret); + fflush (stderr); + } + } + + __BEGIN__; + + WindowRef outWindow = NULL; + OSStatus err = noErr; + Rect contentBounds = {100,100,320,440}; + + CvWindow* window; + UInt wAttributes = 0; + + int len; + + const EventTypeSpec genericWindowEventHandler[] = { + { kEventClassMouse, kEventMouseMoved}, + { kEventClassMouse, kEventMouseDragged}, + { kEventClassMouse, kEventMouseUp}, + { kEventClassMouse, kEventMouseDown}, + { kEventClassWindow, kEventWindowClose }, + { kEventClassWindow, kEventWindowBoundsChanged }//FD + }; + + if( !name ) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + if( icvFindWindowByName( name ) != 0 ){ + result = 1; + EXIT; + } + len = strlen(name); + CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1)); + memset( window, 0, sizeof(*window)); + window->name = (char*)(window + 1); + memcpy( window->name, name, len + 1 ); + window->flags = flags; + window->status = CV_WINDOW_NORMAL;//YV + window->signature = CV_WINDOW_MAGIC_VAL; + window->image = 0; + window->last_key = 0; + window->on_mouse = 0; + window->on_mouse_param = 0; + + window->next = hg_windows; + window->prev = 0; + if( hg_windows ) + hg_windows->prev = window; + hg_windows = window; + wAttributes = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowLiveResizeAttribute; + + + if (window->flags & CV_WINDOW_AUTOSIZE)//Yannick verdie, remove the handler at the bottom-right position of the window in AUTORESIZE mode + { + wAttributes = 0; + wAttributes = kWindowCloseBoxAttribute | kWindowFullZoomAttribute | kWindowCollapseBoxAttribute | kWindowStandardHandlerAttribute | kWindowLiveResizeAttribute; + } + + err = CreateNewWindow ( kDocumentWindowClass,wAttributes,&contentBounds,&outWindow); + if (err != noErr) + fprintf(stderr,"Error while creating the window\n"); + + SetWindowTitleWithCFString(outWindow,CFStringCreateWithCString(NULL,name,kCFStringEncodingASCII)); + if (err != noErr) + fprintf(stdout,"Error SetWindowTitleWithCFString\n"); + + window->window = outWindow; + window->oldwindow = 0;//YV + + err = InstallWindowEventHandler(outWindow, NewEventHandlerUPP(windowEventHandler), GetEventTypeCount(genericWindowEventHandler), genericWindowEventHandler, outWindow, NULL); + + ShowWindow( outWindow ); + result = 1; + + __END__; + return result; +} + +static pascal OSStatus windowEventHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void *inUserData) +{ + CvWindow* window = NULL; + UInt32 eventKind, eventClass; + OSErr err = noErr; + int event = 0; + UInt32 count = 0; + HIPoint point = {0,0}; + EventMouseButton eventMouseButton = 0;//FD + UInt32 modifiers;//FD + + WindowRef theWindow = (WindowRef)inUserData; + if (theWindow == NULL) + return eventNotHandledErr; + window = icvWindowByHandle(theWindow); + if ( window == NULL) + return eventNotHandledErr; + + eventKind = GetEventKind(theEvent); + eventClass = GetEventClass(theEvent); + + switch (eventClass) { + case kEventClassMouse : { + switch (eventKind){ + case kEventMouseUp : + case kEventMouseDown : + case kEventMouseMoved : + case kEventMouseDragged : { + err = CallNextEventHandler(nextHandler, theEvent); + if (err != eventNotHandledErr) + return err; + err = GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(eventMouseButton), NULL, &eventMouseButton); + err = GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers); + err = GetEventParameter(theEvent,kEventParamClickCount,typeUInt32,NULL,sizeof(UInt32),NULL,&count); + if (err == noErr){ + if (count >1) event += 6; + } else { + event = CV_EVENT_MOUSEMOVE; + } + + if (eventKind == kEventMouseUp) + event +=4; + if (eventKind == kEventMouseDown) + event +=1; + + unsigned int flags = 0; + + err = GetEventParameter(theEvent, kEventParamWindowMouseLocation, typeHIPoint, NULL, sizeof(point), NULL, &point); + if (eventKind != kEventMouseMoved){ + switch(eventMouseButton){ + case kEventMouseButtonPrimary: + if (modifiers & controlKey){ + flags += CV_EVENT_FLAG_RBUTTON; + event += 1; + } else { + flags += CV_EVENT_FLAG_LBUTTON; + } + break; + case kEventMouseButtonSecondary: + flags += CV_EVENT_FLAG_RBUTTON; + event += 1; + break; + case kEventMouseButtonTertiary: + flags += CV_EVENT_FLAG_MBUTTON; + event += 2; + break; + } + } + + if (modifiers&controlKey) flags += CV_EVENT_FLAG_CTRLKEY; + if (modifiers&shiftKey) flags += CV_EVENT_FLAG_SHIFTKEY; + if (modifiers& cmdKey ) flags += CV_EVENT_FLAG_ALTKEY; + + if (window->on_mouse != NULL){ + int lx,ly; + Rect structure, content; + GetWindowBounds(theWindow, kWindowStructureRgn, &structure); + GetWindowBounds(theWindow, kWindowContentRgn, &content); + lx = (int)point.x - content.left + structure.left; + ly = (int)point.y - window->trackbarheight - content.top + structure.top; /* minus la taille des trackbars */ + if (window->flags & CV_WINDOW_AUTOSIZE) {//FD + //printf("was %d,%d\n", lx, ly); + /* scale the mouse coordinates */ + lx = lx * window->imageWidth / (content.right - content.left); + ly = ly * window->imageHeight / (content.bottom - content.top - window->trackbarheight); + } + + if (lx>0 && ly >0){ /* a remettre dans les coordonnées locale */ + window->on_mouse (event, lx, ly, flags, window->on_mouse_param); + return noErr; + } + } + } + default : return eventNotHandledErr; + } + } + case kEventClassWindow : {//FD + switch (eventKind){ + case kEventWindowBoundsChanged : + { + /* resize the trackbars */ + CvTrackbar *t; + Rect bounds; + GetWindowBounds(window->window,kWindowContentRgn,&bounds); + for ( t = window->toolbar.first; t != 0; t = t->next ) + SizeControl(t->trackbar,bounds.right - bounds.left - INTERWIDGETSPACE*3 - LABELWIDTH , WIDGETHEIGHT); + } + /* redraw the image */ + icvDrawImage(window); + break; + default : + return eventNotHandledErr; + } + } + default: + return eventNotHandledErr; + } + + return eventNotHandledErr; +} + +OSStatus keyHandler(EventHandlerCallRef hcr, EventRef theEvent, void* inUserData) +{ + UInt32 eventKind; + UInt32 eventClass; + OSErr err = noErr; + + eventKind = GetEventKind (theEvent); + eventClass = GetEventClass (theEvent); + err = GetEventParameter(theEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(lastKey), NULL, &lastKey); + if (err != noErr) + lastKey = NO_KEY; + + return noErr; +} + +CV_IMPL int cvWaitKey (int maxWait) +{ + EventRecord theEvent; + + // wait at least for one event (to allow mouse, etc. processing), exit if maxWait milliseconds passed (nullEvent) + UInt32 start = TickCount(); + int iters=0; + do + { + // remaining time until maxWait is over + UInt32 wait = EventTimeToTicks (maxWait / 1000.0) - (TickCount() - start); + if ((int)wait <= 0) + { + if( maxWait > 0 && iters > 0 ) + break; + wait = 1; + } + iters++; + WaitNextEvent (everyEvent, &theEvent, maxWait > 0 ? wait : kDurationForever, NULL); + } + while (lastKey == NO_KEY && theEvent.what != nullEvent); + + int key = lastKey; + lastKey = NO_KEY; + return key; +} + +/* End of file. */ diff --git a/highgui/src/window_cocoa.mm b/highgui/src/window_cocoa.mm new file mode 100644 index 0000000..20e0b1c --- /dev/null +++ b/highgui/src/window_cocoa.mm @@ -0,0 +1,940 @@ +/* The file is the modified version of window_cocoa.mm from opencv-cocoa project by Andre Cohen */ + +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +#import + +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR +/*** begin IPhone OS Stubs ***/ +// When highgui functions are referred to on iPhone OS, they will fail silently. +CV_IMPL int cvInitSystem( int argc, char** argv) { return 0;} +CV_IMPL int cvStartWindowThread(){ return 0; } +CV_IMPL void cvDestroyWindow( const char* name) {} +CV_IMPL void cvDestroyAllWindows( void ) {} +CV_IMPL void cvShowImage( const char* name, const CvArr* arr) {} +CV_IMPL void cvResizeWindow( const char* name, int width, int height) {} +CV_IMPL void cvMoveWindow( const char* name, int x, int y){} +CV_IMPL int cvCreateTrackbar (const char* trackbar_name,const char* window_name, + int* val, int count, CvTrackbarCallback on_notify) {return 0;} +CV_IMPL int cvCreateTrackbar2(const char* trackbar_name,const char* window_name, + int* val, int count, CvTrackbarCallback2 on_notify2, void* userdata) {return 0;} +CV_IMPL void cvSetMouseCallback( const char* name, CvMouseCallback function, void* info) {} +CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name ) {return 0;} +CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name, int pos) {} +CV_IMPL void* cvGetWindowHandle( const char* name ) {return NULL;} +CV_IMPL const char* cvGetWindowName( void* window_handle ) {return NULL;} +CV_IMPL int cvNamedWindow( const char* name, int flags ) {return 0; } +CV_IMPL int cvWaitKey (int maxWait) {return 0;} +//*** end IphoneOS Stubs ***/ +#else + +#import + +#include +using namespace std; + +const int TOP_BORDER = 7; +const int MIN_SLIDER_WIDTH=200; + +static NSApplication *application = nil; +static NSAutoreleasePool *pool = nil; +static NSMutableDictionary *windows = nil; +static bool wasInitialized = false; + +@interface CVView : NSView { + NSImage *image; +} +@property(retain) NSImage *image; +- (void)setImageData:(CvArr *)arr; +@end + +@interface CVSlider : NSView { + NSSlider *slider; + NSTextField *name; + int *value; + void *userData; + CvTrackbarCallback callback; + CvTrackbarCallback2 callback2; +} +@property(retain) NSSlider *slider; +@property(retain) NSTextField *name; +@property(assign) int *value; +@property(assign) void *userData; +@property(assign) CvTrackbarCallback callback; +@property(assign) CvTrackbarCallback2 callback2; +@end + +@interface CVWindow : NSWindow { + NSMutableDictionary *sliders; + CvMouseCallback mouseCallback; + void *mouseParam; + BOOL autosize; + BOOL firstContent; + int status; +} +@property(assign) CvMouseCallback mouseCallback; +@property(assign) void *mouseParam; +@property(assign) BOOL autosize; +@property(assign) BOOL firstContent; +@property(retain) NSMutableDictionary *sliders; +@property(readwrite) int status; +- (CVView *)contentView; +- (void)cvSendMouseEvent:(NSEvent *)event type:(int)type flags:(int)flags; +- (void)cvMouseEvent:(NSEvent *)event; +- (void)createSliderWithName:(const char *)name maxValue:(int)max value:(int *)value callback:(CvTrackbarCallback)callback; +@end + +/*static void icvCocoaCleanup(void) +{ + //cout << "icvCocoaCleanup" << endl; + if( application ) + { + cvDestroyAllWindows(); + //[application terminate:nil]; + application = 0; + [pool release]; + } +}*/ + +CV_IMPL int cvInitSystem( int argc, char** argv) +{ + //cout << "cvInitSystem" << endl; + wasInitialized = true; + + pool = [[NSAutoreleasePool alloc] init]; + application = [NSApplication sharedApplication]; + windows = [[NSMutableDictionary alloc] init]; + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + +#ifndef NSAppKitVersionNumber10_5 +#define NSAppKitVersionNumber10_5 949 +#endif + if( floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5 ) + [application setActivationPolicy:0/*NSApplicationActivationPolicyRegular*/]; +#endif + //[application finishLaunching]; + //atexit(icvCocoaCleanup); + + return 0; +} + +CVWindow *cvGetWindow(const char *name) { + //cout << "cvGetWindow" << endl; + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + NSString *cvname = [NSString stringWithFormat:@"%s", name]; + CVWindow* retval = (CVWindow*) [windows valueForKey:cvname] ; + //cout << "retain count: " << [retval retainCount] << endl; + //retval = [retval retain]; + //cout << "retain count: " << [retval retainCount] << endl; + [localpool drain]; + //cout << "retain count: " << [retval retainCount] << endl; + return retval; +} + +CV_IMPL int cvStartWindowThread() +{ + //cout << "cvStartWindowThread" << endl; + return 0; +} + +CV_IMPL void cvDestroyWindow( const char* name) +{ + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + //cout << "cvDestroyWindow" << endl; + CVWindow *window = cvGetWindow(name); + if(window) { + [window close]; + [windows removeObjectForKey:[NSString stringWithFormat:@"%s", name]]; + } + [localpool drain]; +} + + +CV_IMPL void cvDestroyAllWindows( void ) +{ + //cout << "cvDestroyAllWindows" << endl; + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + NSDictionary* list = [NSDictionary dictionaryWithDictionary:windows]; + for(NSString *key in list) { + cvDestroyWindow([key cStringUsingEncoding:NSASCIIStringEncoding]); + } + [localpool drain]; +} + + +CV_IMPL void cvShowImage( const char* name, const CvArr* arr) +{ + //cout << "cvShowImage" << endl; + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + CVWindow *window = cvGetWindow(name); + if(!window) + { + cvNamedWindow(name, CV_WINDOW_AUTOSIZE); + window = cvGetWindow(name); + } + + if(window) + { + bool empty = [[window contentView] image] == nil; + NSRect rect = [window frame]; + NSRect vrectOld = [[window contentView] frame]; + + [[window contentView] setImageData:(CvArr *)arr]; + if([window autosize] || [window firstContent] || empty) + { + //Set new view size considering sliders (reserve height and min width) + NSRect vrectNew = vrectOld; + int slider_height = 0; + for(NSString *key in [window sliders]) { + slider_height += [[[window sliders] valueForKey:key] frame].size.height; + } + vrectNew.size.height = [[[window contentView] image] size].height + slider_height; + vrectNew.size.width = std::max([[[window contentView] image] size].width, MIN_SLIDER_WIDTH); + [[window contentView] setFrameSize:vrectNew.size]; //adjust sliders to fit new window size + + rect.size.width += vrectNew.size.width - vrectOld.size.width; + rect.size.height += vrectNew.size.height - vrectOld.size.height; + rect.origin.y -= vrectNew.size.height - vrectOld.size.height; + + [window setFrame:rect display:YES]; + } + else + [window display]; + [window setFirstContent:NO]; + } + [localpool drain]; +} + +CV_IMPL void cvResizeWindow( const char* name, int width, int height) +{ + + //cout << "cvResizeWindow" << endl; + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + CVWindow *window = cvGetWindow(name); + if(window) { + NSRect frame = [window frame]; + frame.size.width = width; + frame.size.height = height; + [window setFrame:frame display:YES]; + } + [localpool drain]; +} + +CV_IMPL void cvMoveWindow( const char* name, int x, int y) +{ + + CV_FUNCNAME("cvMoveWindow"); + __BEGIN__; + + NSAutoreleasePool* localpool1 = [[NSAutoreleasePool alloc] init]; + CVWindow *window = nil; + + if(name == NULL) + CV_ERROR( CV_StsNullPtr, "NULL window name" ); + //cout << "cvMoveWindow"<< endl; + window = cvGetWindow(name); + if(window) { + y = [[window screen] frame].size.height - y; + [window setFrameTopLeftPoint:NSMakePoint(x, y)]; + } + [localpool1 drain]; + + __END__; +} + +CV_IMPL int cvCreateTrackbar (const char* trackbar_name, + const char* window_name, + int* val, int count, + CvTrackbarCallback on_notify) +{ + CV_FUNCNAME("cvCreateTrackbar"); + + + int result = 0; + CVWindow *window = nil; + NSAutoreleasePool* localpool2 = nil; + + __BEGIN__; + if (localpool2 != nil) [localpool2 drain]; + localpool2 = [[NSAutoreleasePool alloc] init]; + + if(window_name == NULL) + CV_ERROR( CV_StsNullPtr, "NULL window name" ); + + //cout << "cvCreateTrackbar" << endl ; + window = cvGetWindow(window_name); + if(window) { + [window createSliderWithName:trackbar_name + maxValue:count + value:val + callback:on_notify]; + result = 1; + } + [localpool2 drain]; + __END__; + return result; +} + + +CV_IMPL int cvCreateTrackbar2(const char* trackbar_name, + const char* window_name, + int* val, int count, + CvTrackbarCallback2 on_notify2, + void* userdata) +{ + //cout <<"cvCreateTrackbar2" << endl; + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + int res = cvCreateTrackbar(trackbar_name, window_name, val, count, NULL); + if(res) { + CVSlider *slider = [[cvGetWindow(window_name) sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; + [slider setCallback2:on_notify2]; + [slider setUserData:userdata]; + } + [localpool drain]; + return res; +} + + +CV_IMPL void +cvSetMouseCallback( const char* name, CvMouseCallback function, void* info) +{ + CV_FUNCNAME("cvSetMouseCallback"); + + CVWindow *window = nil; + NSAutoreleasePool* localpool3 = nil; + __BEGIN__; + //cout << "cvSetMouseCallback" << endl; + + if (localpool3 != nil) [localpool3 drain]; + localpool3 = [[NSAutoreleasePool alloc] init]; + + if(name == NULL) + CV_ERROR( CV_StsNullPtr, "NULL window name" ); + + window = cvGetWindow(name); + if(window) { + [window setMouseCallback:function]; + [window setMouseParam:info]; + } + [localpool3 drain]; + + __END__; +} + + CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name ) +{ + CV_FUNCNAME("cvGetTrackbarPos"); + + CVWindow *window = nil; + int pos = -1; + NSAutoreleasePool* localpool4 = nil; + __BEGIN__; + + //cout << "cvGetTrackbarPos" << endl; + if(trackbar_name == NULL || window_name == NULL) + CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" ); + + if (localpool4 != nil) [localpool4 drain]; + localpool4 = [[NSAutoreleasePool alloc] init]; + + window = cvGetWindow(window_name); + if(window) { + CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; + if(slider) { + pos = [[slider slider] intValue]; + } + } + [localpool4 drain]; + __END__; + return pos; +} + +CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name, int pos) +{ + CV_FUNCNAME("cvSetTrackbarPos"); + + CVWindow *window = nil; + CVSlider *slider = nil; + NSAutoreleasePool* localpool5 = nil; + + __BEGIN__; + //cout << "cvSetTrackbarPos" << endl; + if(trackbar_name == NULL || window_name == NULL) + CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" ); + + if(pos < 0) + CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" ); + + if (localpool5 != nil) [localpool5 drain]; + localpool5 = [[NSAutoreleasePool alloc] init]; + + window = cvGetWindow(window_name); + if(window) { + slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; + if(slider) { + [[slider slider] setIntValue:pos]; + } + } + [localpool5 drain]; + + __END__; +} + +CV_IMPL void* cvGetWindowHandle( const char* name ) +{ + //cout << "cvGetWindowHandle" << endl; + return cvGetWindow(name); +} + + +CV_IMPL const char* cvGetWindowName( void* window_handle ) +{ + //cout << "cvGetWindowName" << endl; + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + for(NSString *key in windows) { + if([windows valueForKey:key] == window_handle) { + [localpool drain]; + return [key UTF8String]; + } + } + [localpool drain]; + return 0; +} + +CV_IMPL int cvNamedWindow( const char* name, int flags ) +{ + if( !wasInitialized ) + cvInitSystem(0, 0); + + //cout << "cvNamedWindow" << endl; + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + CVWindow *window = cvGetWindow(name); + if( window ) + { + [window setAutosize:(flags == CV_WINDOW_AUTOSIZE)]; + [localpool drain]; + return 0; + } + + NSScreen* mainDisplay = [NSScreen mainScreen]; + + NSString *windowName = [NSString stringWithFormat:@"%s", name]; + NSUInteger showResize = (flags == CV_WINDOW_AUTOSIZE) ? 0: NSResizableWindowMask ; + NSUInteger styleMask = NSTitledWindowMask|NSMiniaturizableWindowMask|showResize; + CGFloat windowWidth = [NSWindow minFrameWidthWithTitle:windowName styleMask:styleMask]; + NSRect initContentRect = NSMakeRect(0, 0, windowWidth, 0); + if (mainDisplay) { + NSRect dispFrame = [mainDisplay visibleFrame]; + initContentRect.origin.y = dispFrame.size.height-20; + } + + + window = [[CVWindow alloc] initWithContentRect:initContentRect + styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|showResize + backing:NSBackingStoreBuffered + defer:YES + screen:mainDisplay]; + + [window setFrameTopLeftPoint:initContentRect.origin]; + + [window setFirstContent:YES]; + + [window setContentView:[[CVView alloc] init]]; + + [window setHasShadow:YES]; + [window setAcceptsMouseMovedEvents:YES]; + [window useOptimizedDrawing:YES]; + [window setTitle:windowName]; + [window makeKeyAndOrderFront:nil]; + + [window setAutosize:(flags == CV_WINDOW_AUTOSIZE)]; + + [windows setValue:window forKey:windowName]; + + [localpool drain]; + return [windows count]-1; +} + +CV_IMPL int cvWaitKey (int maxWait) +{ + //cout << "cvWaitKey" << endl; + int returnCode = -1; + NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init]; + double start = [[NSDate date] timeIntervalSince1970]; + + while(true) { + if(([[NSDate date] timeIntervalSince1970] - start) * 1000 >= maxWait && maxWait>0) + break; + + //event = [application currentEvent]; + [localpool drain]; + localpool = [[NSAutoreleasePool alloc] init]; + + NSEvent *event = + [application + nextEventMatchingMask:NSAnyEventMask + untilDate://[NSDate dateWithTimeIntervalSinceNow: 1./100] + [NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + + if([event type] == NSKeyDown) { + returnCode = [[event characters] characterAtIndex:0]; + break; + } + + [application sendEvent:event]; + [application updateWindows]; + + [NSThread sleepForTimeInterval:1/100.]; + } + [localpool drain]; + + return returnCode; +} + +double cvGetModeWindow_COCOA( const char* name ) +{ + double result = -1; + CVWindow *window = nil; + + CV_FUNCNAME( "cvGetModeWindow_COCOA" ); + + __BEGIN__; + if( name == NULL ) + { + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + } + + window = cvGetWindow( name ); + if ( window == NULL ) + { + CV_ERROR( CV_StsNullPtr, "NULL window" ); + } + + result = window.status; + + __END__; + return result; +} + +void cvSetModeWindow_COCOA( const char* name, double prop_value ) +{ + CVWindow *window = nil; + NSDictionary *fullscreenOptions = nil; + NSAutoreleasePool* localpool = nil; + + CV_FUNCNAME( "cvSetModeWindow_COCOA" ); + + __BEGIN__; + if( name == NULL ) + { + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + } + + window = cvGetWindow(name); + if ( window == NULL ) + { + CV_ERROR( CV_StsNullPtr, "NULL window" ); + } + + if ( [window autosize] ) + { + return; + } + + localpool = [[NSAutoreleasePool alloc] init]; + + fullscreenOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:NSFullScreenModeSetting]; + if ( [[window contentView] isInFullScreenMode] && prop_value==CV_WINDOW_NORMAL ) + { + [[window contentView] exitFullScreenModeWithOptions:fullscreenOptions]; + window.status=CV_WINDOW_NORMAL; + } + else if( ![[window contentView] isInFullScreenMode] && prop_value==CV_WINDOW_FULLSCREEN ) + { + [[window contentView] enterFullScreenMode:[NSScreen mainScreen] withOptions:fullscreenOptions]; + window.status=CV_WINDOW_FULLSCREEN; + } + + [localpool drain]; + + __END__; +} + +@implementation CVWindow + +@synthesize mouseCallback; +@synthesize mouseParam; +@synthesize autosize; +@synthesize firstContent; +@synthesize sliders; +@synthesize status; + +- (void)cvSendMouseEvent:(NSEvent *)event type:(int)type flags:(int)flags { + //cout << "cvSendMouseEvent" << endl; + NSPoint mp = [NSEvent mouseLocation]; + //NSRect visible = [[self contentView] frame]; + mp = [self convertScreenToBase: mp]; + double viewHeight = [self contentView].frame.size.height; + double viewWidth = [self contentView].frame.size.width; + CVWindow *window = (CVWindow *)[[self contentView] window]; + for(NSString *key in [window sliders]) { + NSSlider *slider = [[window sliders] valueForKey:key]; + viewHeight = std::min(viewHeight, (double)([slider frame].origin.y)); + } + viewHeight -= TOP_BORDER; + mp.y = viewHeight - mp.y; + + NSImage* image = ((CVView*)[self contentView]).image; + NSSize imageSize = [image size]; + mp.x = mp.x * imageSize.width / std::max(viewWidth, 1.); + mp.y = mp.y * imageSize.height / std::max(viewHeight, 1.); + + if( mp.x >= 0 && mp.y >= 0 && mp.x < imageSize.width && mp.y < imageSize.height ) + mouseCallback(type, mp.x, mp.y, flags, mouseParam); +} + +- (void)cvMouseEvent:(NSEvent *)event { + //cout << "cvMouseEvent" << endl; + if(!mouseCallback) + return; + + int flags = 0; + if([event modifierFlags] & NSShiftKeyMask) flags |= CV_EVENT_FLAG_SHIFTKEY; + if([event modifierFlags] & NSControlKeyMask) flags |= CV_EVENT_FLAG_CTRLKEY; + if([event modifierFlags] & NSAlternateKeyMask) flags |= CV_EVENT_FLAG_ALTKEY; + + if([event type] == NSLeftMouseDown) {[self cvSendMouseEvent:event type:CV_EVENT_LBUTTONDOWN flags:flags | CV_EVENT_FLAG_LBUTTON];} + if([event type] == NSLeftMouseUp) {[self cvSendMouseEvent:event type:CV_EVENT_LBUTTONUP flags:flags | CV_EVENT_FLAG_LBUTTON];} + if([event type] == NSRightMouseDown){[self cvSendMouseEvent:event type:CV_EVENT_RBUTTONDOWN flags:flags | CV_EVENT_FLAG_RBUTTON];} + if([event type] == NSRightMouseUp) {[self cvSendMouseEvent:event type:CV_EVENT_RBUTTONUP flags:flags | CV_EVENT_FLAG_RBUTTON];} + if([event type] == NSOtherMouseDown){[self cvSendMouseEvent:event type:CV_EVENT_MBUTTONDOWN flags:flags];} + if([event type] == NSOtherMouseUp) {[self cvSendMouseEvent:event type:CV_EVENT_MBUTTONUP flags:flags];} + if([event type] == NSMouseMoved) {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE flags:flags];} + if([event type] == NSLeftMouseDragged) {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE flags:flags | CV_EVENT_FLAG_LBUTTON];} + if([event type] == NSRightMouseDragged) {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE flags:flags | CV_EVENT_FLAG_RBUTTON];} + if([event type] == NSOtherMouseDragged) {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE flags:flags | CV_EVENT_FLAG_MBUTTON];} +} +- (void)keyDown:(NSEvent *)theEvent { + //cout << "keyDown" << endl; + [super keyDown:theEvent]; +} +- (void)rightMouseDragged:(NSEvent *)theEvent { + //cout << "rightMouseDragged" << endl ; + [self cvMouseEvent:theEvent]; +} +- (void)rightMouseUp:(NSEvent *)theEvent { + //cout << "rightMouseUp" << endl; + [self cvMouseEvent:theEvent]; +} +- (void)rightMouseDown:(NSEvent *)theEvent { + // Does not seem to work? + //cout << "rightMouseDown" << endl; + [self cvMouseEvent:theEvent]; +} +- (void)mouseMoved:(NSEvent *)theEvent { + [self cvMouseEvent:theEvent]; +} +- (void)otherMouseDragged:(NSEvent *)theEvent { + [self cvMouseEvent:theEvent]; +} +- (void)otherMouseUp:(NSEvent *)theEvent { + [self cvMouseEvent:theEvent]; +} +- (void)otherMouseDown:(NSEvent *)theEvent { + [self cvMouseEvent:theEvent]; +} +- (void)mouseDragged:(NSEvent *)theEvent { + [self cvMouseEvent:theEvent]; +} +- (void)mouseUp:(NSEvent *)theEvent { + [self cvMouseEvent:theEvent]; +} +- (void)mouseDown:(NSEvent *)theEvent { + [self cvMouseEvent:theEvent]; +} + +- (void)createSliderWithName:(const char *)name maxValue:(int)max value:(int *)value callback:(CvTrackbarCallback)callback { + //cout << "createSliderWithName" << endl; + if(sliders == nil) + sliders = [[NSMutableDictionary alloc] init]; + + NSString *cvname = [NSString stringWithFormat:@"%s", name]; + + // Avoid overwriting slider + if([sliders valueForKey:cvname]!=nil) + return; + + // Create slider + CVSlider *slider = [[CVSlider alloc] init]; + [[slider name] setStringValue:cvname]; + [[slider slider] setMaxValue:max]; + [[slider slider] setMinValue:0]; + [[slider slider] setNumberOfTickMarks:(max+1)]; + [[slider slider] setAllowsTickMarkValuesOnly:YES]; + if(value) + { + [[slider slider] setIntValue:*value]; + [slider setValue:value]; + } + if(callback) + [slider setCallback:callback]; + + // Save slider + [sliders setValue:slider forKey:cvname]; + [[self contentView] addSubview:slider]; + + + //update contentView size to contain sliders + NSSize viewSize=[[self contentView] frame].size, + sliderSize=[slider frame].size; + viewSize.height += sliderSize.height; + viewSize.width = std::max(viewSize.width, MIN_SLIDER_WIDTH); + + // Update slider sizes + [[self contentView] setFrameSize:viewSize]; + [[self contentView] setNeedsDisplay:YES]; + + //update window size to contain sliders + NSRect rect = [self frame]; + rect.size.height += [slider frame].size.height; + rect.size.width = std::max(rect.size.width, MIN_SLIDER_WIDTH); + [self setFrame:rect display:YES]; + + + +} + +- (CVView *)contentView { + return (CVView*)[super contentView]; +} + +@end + +@implementation CVView + +@synthesize image; + +- (id)init { + //cout << "CVView init" << endl; + [super init]; + image = [[NSImage alloc] init]; + return self; +} + +- (void)setImageData:(CvArr *)arr { + //cout << "setImageData" << endl; + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + CvMat *arrMat, *cvimage, stub; + + arrMat = cvGetMat(arr, &stub); + + cvimage = cvCreateMat(arrMat->rows, arrMat->cols, CV_8UC3); + cvConvertImage(arrMat, cvimage, CV_CVTIMG_SWAP_RB); + + /*CGColorSpaceRef colorspace = NULL; + CGDataProviderRef provider = NULL; + int width = cvimage->width; + int height = cvimage->height; + + colorspace = CGColorSpaceCreateDeviceRGB(); + + int size = 8; + int nbChannels = 3; + + provider = CGDataProviderCreateWithData(NULL, cvimage->data.ptr, width * height , NULL ); + + CGImageRef imageRef = CGImageCreate(width, height, size , size*nbChannels , cvimage->step, colorspace, kCGImageAlphaNone , provider, NULL, true, kCGRenderingIntentDefault); + + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCGImage:imageRef]; + if(image) { + [image release]; + }*/ + + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL + pixelsWide:cvimage->width + pixelsHigh:cvimage->height + bitsPerSample:8 + samplesPerPixel:3 + hasAlpha:NO + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:(cvimage->width * 4) + bitsPerPixel:32]; + + int pixelCount = cvimage->width * cvimage->height; + unsigned char *src = cvimage->data.ptr; + unsigned char *dst = [bitmap bitmapData]; + + for( int i = 0; i < pixelCount; i++ ) + { + dst[i * 4 + 0] = src[i * 3 + 0]; + dst[i * 4 + 1] = src[i * 3 + 1]; + dst[i * 4 + 2] = src[i * 3 + 2]; + } + + if( image ) + [image release]; + + image = [[NSImage alloc] init]; + [image addRepresentation:bitmap]; + [bitmap release]; + + /*CGColorSpaceRelease(colorspace); + CGDataProviderRelease(provider); + CGImageRelease(imageRef);*/ + cvReleaseMat(&cvimage); + [localpool drain]; + + [self setNeedsDisplay:YES]; + +} + +- (void)setFrameSize:(NSSize)size { + //cout << "setFrameSize" << endl; + [super setFrameSize:size]; + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + int height = size.height; + + CVWindow *cvwindow = (CVWindow *)[self window]; + for(NSString *key in [cvwindow sliders]) { + NSSlider *slider = [[cvwindow sliders] valueForKey:key]; + NSRect r = [slider frame]; + r.origin.y = height - r.size.height; + r.size.width = [[cvwindow contentView] frame].size.width; + [slider setFrame:r]; + height -= r.size.height; + } + [localpool drain]; +} + +- (void)drawRect:(NSRect)rect { + //cout << "drawRect" << endl; + [super drawRect:rect]; + + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + CVWindow *cvwindow = (CVWindow *)[self window]; + int height = 0; + if ([cvwindow respondsToSelector:@selector(sliders)]) { + for(NSString *key in [cvwindow sliders]) { + height += [[[cvwindow sliders] valueForKey:key] frame].size.height; + } + } + + + NSRect imageRect = {{0,0}, {[image size].width, [image size].height}}; + + if(image != nil) { + [image drawInRect: imageRect + fromRect: NSZeroRect + operation: NSCompositeSourceOver + fraction: 1.0]; + } + [localpool release]; + +} + +@end + +@implementation CVSlider + +@synthesize slider; +@synthesize name; +@synthesize value; +@synthesize userData; +@synthesize callback; +@synthesize callback2; + +- (id)init { + [super init]; + + callback = NULL; + value = NULL; + userData = NULL; + + [self setFrame:NSMakeRect(0,0,200,30)]; + + name = [[NSTextField alloc] initWithFrame:NSMakeRect(10, 0,110, 25)]; + [name setEditable:NO]; + [name setSelectable:NO]; + [name setBezeled:NO]; + [name setBordered:NO]; + [name setDrawsBackground:NO]; + [[name cell] setLineBreakMode:NSLineBreakByTruncatingTail]; + [self addSubview:name]; + + slider = [[NSSlider alloc] initWithFrame:NSMakeRect(120, 0, 70, 25)]; + [slider setAutoresizingMask:NSViewWidthSizable]; + [slider setMinValue:0]; + [slider setMaxValue:100]; + [slider setContinuous:YES]; + [slider setTarget:self]; + [slider setAction:@selector(sliderChanged:)]; + [self addSubview:slider]; + + [self setAutoresizingMask:NSViewWidthSizable]; + + //[self setFrame:NSMakeRect(12, 0, 100, 30)]; + + return self; +} + +- (void)sliderChanged:(NSNotification *)notification { + int pos = [slider intValue]; + if(value) + *value = pos; + if(callback) + callback(pos); + if(callback2) + callback2(pos, userData); +} + +@end + +#endif + +/* End of file. */ diff --git a/highgui/src/window_gtk.cpp b/highgui/src/window_gtk.cpp new file mode 100644 index 0000000..99b16d9 --- /dev/null +++ b/highgui/src/window_gtk.cpp @@ -0,0 +1,1949 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#ifndef WIN32 + +#ifdef HAVE_GTK + +#include "gtk/gtk.h" +#include "gdk/gdkkeysyms.h" +#include + +#ifdef HAVE_OPENGL + #include + #include + #include +#endif + +// TODO Fix the initial window size when flags=0. Right now the initial window is by default +// 320x240 size. A better default would be actual size of the image. Problem +// is determining desired window size with trackbars while still allowing resizing. +// +// Gnome Totem source may be of use here, see bacon_video_widget_set_scale_ratio +// in totem/src/backend/bacon-video-widget-xine.c + +//////////////////////////////////////////////////////////// +// CvImageWidget GTK Widget Public API +//////////////////////////////////////////////////////////// +typedef struct _CvImageWidget CvImageWidget; +typedef struct _CvImageWidgetClass CvImageWidgetClass; + +struct _CvImageWidget { + GtkWidget widget; + CvMat * original_image; + CvMat * scaled_image; + int flags; +}; + +struct _CvImageWidgetClass +{ + GtkWidgetClass parent_class; +}; + + +/** Allocate new image viewer widget */ +GtkWidget* cvImageWidgetNew (int flags); + +/** Set the image to display in the widget */ +void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr); + +// standard GTK object macros +#define CV_IMAGE_WIDGET(obj) GTK_CHECK_CAST (obj, cvImageWidget_get_type (), CvImageWidget) +#define CV_IMAGE_WIDGET_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, cvImageWidget_get_type (), CvImageWidgetClass) +#define CV_IS_IMAGE_WIDGET(obj) GTK_CHECK_TYPE (obj, cvImageWidget_get_type ()) + +///////////////////////////////////////////////////////////////////////////// +// Private API //////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +GtkType cvImageWidget_get_type (void); + +static GtkWidgetClass * parent_class = NULL; + +// flag to help size initial window +#define CV_WINDOW_NO_IMAGE 2 + +void cvImageWidgetSetImage(CvImageWidget * widget, const CvArr *arr){ + CvMat * mat, stub; + int origin=0; + + //printf("cvImageWidgetSetImage\n"); + + if( CV_IS_IMAGE_HDR( arr )) + origin = ((IplImage*)arr)->origin; + + mat = cvGetMat(arr, &stub); + + if(widget->original_image && !CV_ARE_SIZES_EQ(mat, widget->original_image)){ + cvReleaseMat( &widget->original_image ); + } + if(!widget->original_image){ + widget->original_image = cvCreateMat( mat->rows, mat->cols, CV_8UC3 ); + gtk_widget_queue_resize( GTK_WIDGET( widget ) ); + } + cvConvertImage( mat, widget->original_image, + (origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB ); + if(widget->scaled_image){ + cvResize( widget->original_image, widget->scaled_image, CV_INTER_AREA ); + } + + // window does not refresh without this + gtk_widget_queue_draw( GTK_WIDGET(widget) ); +} + +GtkWidget* +cvImageWidgetNew (int flags) +{ + CvImageWidget *image_widget; + + image_widget = CV_IMAGE_WIDGET( gtk_type_new (cvImageWidget_get_type ()) ); + image_widget->original_image = 0; + image_widget->scaled_image = 0; + image_widget->flags = flags | CV_WINDOW_NO_IMAGE; + + return GTK_WIDGET (image_widget); +} + +static void +cvImageWidget_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + + //printf("cvImageWidget_realize\n"); + g_return_if_fail (widget != NULL); + g_return_if_fail (CV_IS_IMAGE_WIDGET (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events (widget) | + GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gdk_window_set_user_data (widget->window, widget); + + gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE); +} + +static CvSize cvImageWidget_calc_size( int im_width, int im_height, int max_width, int max_height ){ + float aspect = (float)im_width/(float)im_height; + float max_aspect = (float)max_width/(float)max_height; + if(aspect > max_aspect){ + return cvSize( max_width, cvRound(max_width/aspect) ); + } + return cvSize( cvRound(max_height*aspect), max_height ); +} + +static void +cvImageWidget_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget ); + + //printf("cvImageWidget_size_request "); + // the case the first time cvShowImage called or when AUTOSIZE + if( image_widget->original_image && + ((image_widget->flags & CV_WINDOW_AUTOSIZE) || + (image_widget->flags & CV_WINDOW_NO_IMAGE))) + { + //printf("original "); + requisition->width = image_widget->original_image->cols; + requisition->height = image_widget->original_image->rows; + } + // default case + else if(image_widget->scaled_image){ + //printf("scaled "); + requisition->width = image_widget->scaled_image->cols; + requisition->height = image_widget->scaled_image->rows; + } + // the case before cvShowImage called + else{ + //printf("default "); + requisition->width = 320; + requisition->height = 240; + } + //printf("%d %d\n",requisition->width, requisition->height); +} + +static void cvImageWidget_set_size(GtkWidget * widget, int max_width, int max_height){ + CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget ); + + //printf("cvImageWidget_set_size %d %d\n", max_width, max_height); + + // don't allow to set the size + if(image_widget->flags & CV_WINDOW_AUTOSIZE) return; + if(!image_widget->original_image) return; + + CvSize scaled_image_size = cvImageWidget_calc_size( image_widget->original_image->cols, + image_widget->original_image->rows, max_width, max_height ); + + if( image_widget->scaled_image && + ( image_widget->scaled_image->cols != scaled_image_size.width || + image_widget->scaled_image->rows != scaled_image_size.height )) + { + cvReleaseMat( &image_widget->scaled_image ); + } + if( !image_widget->scaled_image ){ + image_widget->scaled_image = cvCreateMat( scaled_image_size.height, scaled_image_size.width, CV_8UC3 ); + + + } + assert( image_widget->scaled_image ); +} + +static void +cvImageWidget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + CvImageWidget *image_widget; + + //printf("cvImageWidget_size_allocate\n"); + g_return_if_fail (widget != NULL); + g_return_if_fail (CV_IS_IMAGE_WIDGET (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + image_widget = CV_IMAGE_WIDGET (widget); + + + if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 && image_widget->original_image ){ + // (re) allocated scaled image + if( image_widget->flags & CV_WINDOW_NO_IMAGE ){ + cvImageWidget_set_size( widget, image_widget->original_image->cols, + image_widget->original_image->rows); + } + else{ + cvImageWidget_set_size( widget, allocation->width, allocation->height ); + } + cvResize( image_widget->original_image, image_widget->scaled_image, CV_INTER_AREA ); + } + + if (GTK_WIDGET_REALIZED (widget)) + { + image_widget = CV_IMAGE_WIDGET (widget); + + if( image_widget->original_image && + ((image_widget->flags & CV_WINDOW_AUTOSIZE) || + (image_widget->flags & CV_WINDOW_NO_IMAGE)) ) + { + widget->allocation.width = image_widget->original_image->cols; + widget->allocation.height = image_widget->original_image->rows; + gdk_window_move_resize( widget->window, allocation->x, allocation->y, + image_widget->original_image->cols, image_widget->original_image->rows ); + if(image_widget->flags & CV_WINDOW_NO_IMAGE){ + image_widget->flags &= ~CV_WINDOW_NO_IMAGE; + gtk_widget_queue_resize( GTK_WIDGET(widget) ); + } + } + else{ + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height ); + + } + } +} + +static void +cvImageWidget_destroy (GtkObject *object) +{ + CvImageWidget *image_widget; + + g_return_if_fail (object != NULL); + g_return_if_fail (CV_IS_IMAGE_WIDGET (object)); + + image_widget = CV_IMAGE_WIDGET (object); + + cvReleaseMat( &image_widget->scaled_image ); + cvReleaseMat( &image_widget->original_image ); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void cvImageWidget_class_init (CvImageWidgetClass * klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + + parent_class = GTK_WIDGET_CLASS( gtk_type_class (gtk_widget_get_type ()) ); + + object_class->destroy = cvImageWidget_destroy; + + widget_class->realize = cvImageWidget_realize; + widget_class->size_request = cvImageWidget_size_request; + widget_class->size_allocate = cvImageWidget_size_allocate; + widget_class->button_press_event = NULL; + widget_class->button_release_event = NULL; + widget_class->motion_notify_event = NULL; +} + +static void +cvImageWidget_init (CvImageWidget *image_widget) +{ + image_widget->original_image=0; + image_widget->scaled_image=0; + image_widget->flags=0; +} + +GtkType cvImageWidget_get_type (void){ + static GtkType image_type = 0; + + if (!image_type) + { + static const GtkTypeInfo image_info = + { + (gchar*)"CvImageWidget", + sizeof (CvImageWidget), + sizeof (CvImageWidgetClass), + (GtkClassInitFunc) cvImageWidget_class_init, + (GtkObjectInitFunc) cvImageWidget_init, + /* reserved_1 */ NULL, + /* reserved_1 */ NULL, + (GtkClassInitFunc) NULL + }; + + image_type = gtk_type_unique (GTK_TYPE_WIDGET, &image_info); + } + + return image_type; +} +///////////////////////////////////////////////////////////////////////////// +// End CvImageWidget +///////////////////////////////////////////////////////////////////////////// + + +struct CvWindow; + +typedef struct CvTrackbar +{ + int signature; + GtkWidget* widget; + char* name; + CvTrackbar* next; + CvWindow* parent; + int* data; + int pos; + int maxval; + CvTrackbarCallback notify; + CvTrackbarCallback2 notify2; + void* userdata; +} +CvTrackbar; + + +typedef struct CvWindow +{ + int signature; + GtkWidget* widget; + GtkWidget* frame; + GtkWidget* paned; + char* name; + CvWindow* prev; + CvWindow* next; + + int last_key; + int flags; + int status;//0 normal, 1 fullscreen (YV) + + CvMouseCallback on_mouse; + void* on_mouse_param; + + struct + { + int pos; + int rows; + CvTrackbar* first; + } + toolbar; + +#ifdef HAVE_OPENGL + bool useGl; + + CvOpenGlDrawCallback glDrawCallback; + void* glDrawData; + + CvOpenGlCleanCallback glCleanCallback; + void* glCleanData; +#endif +} +CvWindow; + + +static gboolean icvOnClose( GtkWidget* widget, GdkEvent* event, gpointer user_data ); +static gboolean icvOnKeyPress( GtkWidget* widget, GdkEventKey* event, gpointer user_data ); +static void icvOnTrackbar( GtkWidget* widget, gpointer user_data ); +static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data ); + +#ifdef HAVE_GTHREAD +int thread_started=0; +static gpointer icvWindowThreadLoop(); +GMutex* last_key_mutex; +GCond* cond_have_key; +GMutex* window_mutex; +GThread* window_thread; +GtkWidget* cvTopLevelWidget = 0; +#endif + +static int last_key = -1; +static CvWindow* hg_windows = 0; + +CV_IMPL int cvInitSystem( int argc, char** argv ) +{ + static int wasInitialized = 0; + + // check initialization status + if( !wasInitialized ) + { + hg_windows = 0; + + gtk_disable_setlocale(); + gtk_init( &argc, &argv ); + + #ifdef HAVE_OPENGL + gtk_gl_init(&argc, &argv); + #endif + + wasInitialized = 1; + } + + return 0; +} + +CV_IMPL int cvStartWindowThread(){ +#ifdef HAVE_GTHREAD + cvInitSystem(0,NULL); + if (!thread_started) { + if (!g_thread_supported ()) { + /* the GThread system wasn't inited, so init it */ + g_thread_init(NULL); + } + + // this mutex protects the window resources + window_mutex = g_mutex_new(); + + // protects the 'last key pressed' variable + last_key_mutex = g_mutex_new(); + + // conditional that indicates a key has been pressed + cond_have_key = g_cond_new(); + + // this is the window update thread + window_thread = g_thread_create((GThreadFunc) icvWindowThreadLoop, + NULL, TRUE, NULL); + } + thread_started = window_thread!=NULL; + return thread_started; +#else + return 0; +#endif +} + +#ifdef HAVE_GTHREAD +gpointer icvWindowThreadLoop(){ + while(1){ + g_mutex_lock(window_mutex); + gtk_main_iteration_do(FALSE); + g_mutex_unlock(window_mutex); + + // little sleep + g_usleep(500); + + g_thread_yield(); + } + return NULL; +} + +#define CV_LOCK_MUTEX() \ +if(thread_started && g_thread_self()!=window_thread){ g_mutex_lock( window_mutex ); } else { } + +#define CV_UNLOCK_MUTEX() \ +if(thread_started && g_thread_self()!=window_thread){ g_mutex_unlock( window_mutex); } else { } + +#else +#define CV_LOCK_MUTEX() +#define CV_UNLOCK_MUTEX() +#endif + +static CvWindow* icvFindWindowByName( const char* name ) +{ + CvWindow* window = hg_windows; + while( window != 0 && strcmp(name, window->name) != 0 ) + window = window->next; + + return window; +} + +static CvWindow* icvWindowByWidget( GtkWidget* widget ) +{ + CvWindow* window = hg_windows; + + while( window != 0 && window->widget != widget && + window->frame != widget && window->paned != widget ) + window = window->next; + + return window; +} + +double cvGetModeWindow_GTK(const char* name)//YV +{ + double result = -1; + + CV_FUNCNAME( "cvGetModeWindow_GTK" ); + + __BEGIN__; + + CvWindow* window; + + if (!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + CV_ERROR( CV_StsNullPtr, "NULL window" ); + + CV_LOCK_MUTEX(); + result = window->status; + CV_UNLOCK_MUTEX(); + + __END__; + return result; +} + + +void cvSetModeWindow_GTK( const char* name, double prop_value)//Yannick Verdie +{ + + CV_FUNCNAME( "cvSetModeWindow_GTK" ); + + __BEGIN__; + + CvWindow* window; + + if(!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if( !window ) + CV_ERROR( CV_StsNullPtr, "NULL window" ); + + if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set + EXIT; + + //so easy to do fullscreen here, Linux rocks ! + + if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL) + { + CV_LOCK_MUTEX(); + gtk_window_unfullscreen(GTK_WINDOW(window->frame)); + window->status=CV_WINDOW_NORMAL; + CV_UNLOCK_MUTEX(); + EXIT; + } + + if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN) + { + CV_LOCK_MUTEX(); + gtk_window_fullscreen(GTK_WINDOW(window->frame)); + window->status=CV_WINDOW_FULLSCREEN; + CV_UNLOCK_MUTEX(); + EXIT; + } + + __END__; +} + + +double cvGetPropWindowAutoSize_GTK(const char* name) +{ + double result = -1; + + CV_FUNCNAME( "cvGetPropWindowAutoSize_GTK" ); + + __BEGIN__; + + CvWindow* window; + + if (!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + EXIT; // keep silence here + + result = window->flags & CV_WINDOW_AUTOSIZE; + + __END__; + + return result; +} + +double cvGetRatioWindow_GTK(const char* name) +{ + double result = -1; + + CV_FUNCNAME( "cvGetRatioWindow_GTK" ); + + __BEGIN__; + + CvWindow* window; + + if (!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + EXIT; // keep silence here + + result = static_cast(window->widget->allocation.width) / window->widget->allocation.height; + + __END__; + + return result; +} + +double cvGetOpenGlProp_GTK(const char* name) +{ + double result = -1; + +#ifdef HAVE_OPENGL + CV_FUNCNAME( "cvGetOpenGlProp_GTK" ); + + __BEGIN__; + + CvWindow* window; + + if (!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + EXIT; // keep silence here + + result = window->useGl; + + __END__; +#else + (void)name; +#endif + + return result; +} + + +// OpenGL support + +#ifdef HAVE_OPENGL + +namespace +{ + class GlFuncTab_GTK : public CvOpenGlFuncTab + { + public: + GlFuncTab_GTK(); + + void genBuffers(int n, unsigned int* buffers) const; + void deleteBuffers(int n, const unsigned int* buffers) const; + + void bufferData(unsigned int target, ptrdiff_t size, const void* data, unsigned int usage) const; + void bufferSubData(unsigned int target, ptrdiff_t offset, ptrdiff_t size, const void* data) const; + + void bindBuffer(unsigned int target, unsigned int buffer) const; + + void* mapBuffer(unsigned int target, unsigned int access) const; + void unmapBuffer(unsigned int target) const; + + void generateBitmapFont(const std::string& family, int height, int weight, bool italic, bool underline, int start, int count, int base) const; + + bool isGlContextInitialized() const; + + PFNGLGENBUFFERSPROC glGenBuffersExt; + PFNGLDELETEBUFFERSPROC glDeleteBuffersExt; + + PFNGLBUFFERDATAPROC glBufferDataExt; + PFNGLBUFFERSUBDATAPROC glBufferSubDataExt; + + PFNGLBINDBUFFERPROC glBindBufferExt; + + PFNGLMAPBUFFERPROC glMapBufferExt; + PFNGLUNMAPBUFFERPROC glUnmapBufferExt; + + bool initialized; + }; + + GlFuncTab_GTK::GlFuncTab_GTK() + { + glGenBuffersExt = 0; + glDeleteBuffersExt = 0; + + glBufferDataExt = 0; + glBufferSubDataExt = 0; + + glBindBufferExt = 0; + + glMapBufferExt = 0; + glUnmapBufferExt = 0; + + initialized = false; + } + + void GlFuncTab_GTK::genBuffers(int n, unsigned int* buffers) const + { + CV_FUNCNAME( "GlFuncTab_GTK::genBuffers" ); + + __BEGIN__; + + if (!glGenBuffersExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glGenBuffersExt(n, buffers); + CV_CheckGlError(); + + __END__; + } + + void GlFuncTab_GTK::deleteBuffers(int n, const unsigned int* buffers) const + { + CV_FUNCNAME( "GlFuncTab_GTK::deleteBuffers" ); + + __BEGIN__; + + if (!glDeleteBuffersExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glDeleteBuffersExt(n, buffers); + CV_CheckGlError(); + + __END__; + } + + void GlFuncTab_GTK::bufferData(unsigned int target, ptrdiff_t size, const void* data, unsigned int usage) const + { + CV_FUNCNAME( "GlFuncTab_GTK::bufferData" ); + + __BEGIN__; + + if (!glBufferDataExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glBufferDataExt(target, size, data, usage); + CV_CheckGlError(); + + __END__; + } + + void GlFuncTab_GTK::bufferSubData(unsigned int target, ptrdiff_t offset, ptrdiff_t size, const void* data) const + { + CV_FUNCNAME( "GlFuncTab_GTK::bufferSubData" ); + + __BEGIN__; + + if (!glBufferSubDataExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glBufferSubDataExt(target, offset, size, data); + CV_CheckGlError(); + + __END__; + } + + void GlFuncTab_GTK::bindBuffer(unsigned int target, unsigned int buffer) const + { + CV_FUNCNAME( "GlFuncTab_GTK::bindBuffer" ); + + __BEGIN__; + + if (!glBindBufferExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glBindBufferExt(target, buffer); + CV_CheckGlError(); + + __END__; + } + + void* GlFuncTab_GTK::mapBuffer(unsigned int target, unsigned int access) const + { + CV_FUNCNAME( "GlFuncTab_GTK::mapBuffer" ); + + void* res = 0; + + __BEGIN__; + + if (!glMapBufferExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + res = glMapBufferExt(target, access); + CV_CheckGlError(); + + __END__; + + return res; + } + + void GlFuncTab_GTK::unmapBuffer(unsigned int target) const + { + CV_FUNCNAME( "GlFuncTab_GTK::unmapBuffer" ); + + __BEGIN__; + + if (!glUnmapBufferExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glUnmapBufferExt(target); + CV_CheckGlError(); + + __END__; + } + + void GlFuncTab_GTK::generateBitmapFont(const std::string& family, int height, int weight, bool italic, bool /*underline*/, int start, int count, int base) const + { + PangoFontDescription* fontDecr; + PangoFont* pangoFont; + + CV_FUNCNAME( "GlFuncTab_GTK::generateBitmapFont" ); + + __BEGIN__; + + fontDecr = pango_font_description_new(); + + pango_font_description_set_size(fontDecr, height); + + pango_font_description_set_family_static(fontDecr, family.c_str()); + + pango_font_description_set_weight(fontDecr, static_cast(weight)); + + pango_font_description_set_style(fontDecr, italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); + + pangoFont = gdk_gl_font_use_pango_font(fontDecr, start, count, base); + + pango_font_description_free(fontDecr); + + if (!pangoFont) + CV_ERROR(CV_OpenGlApiCallError, "Can't create font"); + + __END__; + } + + bool GlFuncTab_GTK::isGlContextInitialized() const + { + return initialized; + } + + void initGl() + { + static GlFuncTab_GTK glFuncTab; + static bool first = true; + + if (first) + { + // Load extensions + GdkGLProc func; + + func = gdk_gl_get_proc_address("glGenBuffers"); + glFuncTab.glGenBuffersExt = (PFNGLGENBUFFERSPROC)func; + + func = gdk_gl_get_proc_address("glDeleteBuffers"); + glFuncTab.glDeleteBuffersExt = (PFNGLDELETEBUFFERSPROC)func; + + func = gdk_gl_get_proc_address("glBufferData"); + glFuncTab.glBufferDataExt = (PFNGLBUFFERDATAPROC)func; + + func = gdk_gl_get_proc_address("glBufferSubData"); + glFuncTab.glBufferSubDataExt = (PFNGLBUFFERSUBDATAPROC)func; + + func = gdk_gl_get_proc_address("glBindBuffer"); + glFuncTab.glBindBufferExt = (PFNGLBINDBUFFERPROC)func; + + func = gdk_gl_get_proc_address("glMapBuffer"); + glFuncTab.glMapBufferExt = (PFNGLMAPBUFFERPROC)func; + + func = gdk_gl_get_proc_address("glUnmapBuffer"); + glFuncTab.glUnmapBufferExt = (PFNGLUNMAPBUFFERPROC)func; + + glFuncTab.initialized = true; + + icvSetOpenGlFuncTab(&glFuncTab); + + first = false; + } + } + + void createGlContext(CvWindow* window) + { + GdkGLConfig* glconfig; + + CV_FUNCNAME( "createGlContext" ); + + __BEGIN__; + + window->useGl = false; + + // Try double-buffered visual + glconfig = gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE)); + if (!glconfig) + CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" ); + + // Set OpenGL-capability to the widget + if (!gtk_widget_set_gl_capability(window->widget, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE)) + CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" ); + + initGl(); + + window->useGl = true; + + __END__; + } + + void releaseGlContext(CvWindow* window) + { + //CV_FUNCNAME( "releaseGlContext" ); + + //__BEGIN__; + + window->useGl = false; + + //__END__; + } + + void drawGl(CvWindow* window) + { + CV_FUNCNAME( "drawGl" ); + + __BEGIN__; + + GdkGLContext* glcontext = gtk_widget_get_gl_context(window->widget); + GdkGLDrawable* gldrawable = gtk_widget_get_gl_drawable(window->widget); + + if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) + CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" ); + + glViewport(0, 0, window->widget->allocation.width, window->widget->allocation.height); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (window->glDrawCallback) + window->glDrawCallback(window->glDrawData); + + CV_CheckGlError(); + + if (gdk_gl_drawable_is_double_buffered (gldrawable)) + gdk_gl_drawable_swap_buffers(gldrawable); + else + glFlush(); + + gdk_gl_drawable_gl_end(gldrawable); + + __END__; + } +} + +#endif // HAVE_OPENGL + + +static gboolean cvImageWidget_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data) +{ +#ifdef HAVE_OPENGL + CvWindow* window = (CvWindow*)data; + + if (window->useGl) + { + drawGl(window); + return TRUE; + } +#else + (void)data; +#endif + + CvImageWidget *image_widget; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->count > 0) + return FALSE; + + image_widget = CV_IMAGE_WIDGET (widget); + + gdk_window_clear_area (widget->window, + 0, 0, + widget->allocation.width, + widget->allocation.height); + if( image_widget->scaled_image ){ + // center image in available region + int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2; + int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2; + + gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL], + x0, y0, MIN(image_widget->scaled_image->cols, widget->allocation.width), + MIN(image_widget->scaled_image->rows, widget->allocation.height), + GDK_RGB_DITHER_MAX, image_widget->scaled_image->data.ptr, image_widget->scaled_image->step ); + } + else if( image_widget->original_image ){ + gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL], + 0, 0, + MIN(image_widget->original_image->cols, widget->allocation.width), + MIN(image_widget->original_image->rows, widget->allocation.height), + GDK_RGB_DITHER_MAX, image_widget->original_image->data.ptr, image_widget->original_image->step ); + } + return TRUE; +} + +CV_IMPL int cvNamedWindow( const char* name, int flags ) +{ + int result = 0; + CV_FUNCNAME( "cvNamedWindow" ); + + __BEGIN__; + + CvWindow* window; + int len; + + cvInitSystem(1,(char**)&name); + if( !name ) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + // Check the name in the storage + if( icvFindWindowByName( name ) != 0 ) + { + result = 1; + EXIT; + } + + len = strlen(name); + CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1)); + memset( window, 0, sizeof(*window)); + window->name = (char*)(window + 1); + memcpy( window->name, name, len + 1 ); + window->flags = flags; + window->signature = CV_WINDOW_MAGIC_VAL; + window->last_key = 0; + window->on_mouse = 0; + window->on_mouse_param = 0; + memset( &window->toolbar, 0, sizeof(window->toolbar)); + window->next = hg_windows; + window->prev = 0; + window->status = CV_WINDOW_NORMAL;//YV + + CV_LOCK_MUTEX(); + + window->frame = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + + window->paned = gtk_vbox_new( FALSE, 0 ); + window->widget = cvImageWidgetNew( flags ); + gtk_box_pack_end( GTK_BOX(window->paned), window->widget, TRUE, TRUE, 0 ); + gtk_widget_show( window->widget ); + gtk_container_add( GTK_CONTAINER(window->frame), window->paned ); + gtk_widget_show( window->paned ); + +#ifndef HAVE_OPENGL + if (flags & CV_WINDOW_OPENGL) + CV_ERROR( CV_OpenGlNotSupported, "Library was built without OpenGL support" ); +#else + if (flags & CV_WINDOW_OPENGL) + createGlContext(window); + + window->glDrawCallback = 0; + window->glDrawData = 0; + + window->glCleanCallback = 0; + window->glCleanData = 0; +#endif + + // + // configure event handlers + // TODO -- move this to CvImageWidget ? + gtk_signal_connect( GTK_OBJECT(window->frame), "key-press-event", + GTK_SIGNAL_FUNC(icvOnKeyPress), window ); + gtk_signal_connect( GTK_OBJECT(window->widget), "button-press-event", + GTK_SIGNAL_FUNC(icvOnMouse), window ); + gtk_signal_connect( GTK_OBJECT(window->widget), "button-release-event", + GTK_SIGNAL_FUNC(icvOnMouse), window ); + gtk_signal_connect( GTK_OBJECT(window->widget), "motion-notify-event", + GTK_SIGNAL_FUNC(icvOnMouse), window ); + gtk_signal_connect( GTK_OBJECT(window->frame), "delete-event", + GTK_SIGNAL_FUNC(icvOnClose), window ); + gtk_signal_connect( GTK_OBJECT(window->widget), "expose-event", + GTK_SIGNAL_FUNC(cvImageWidget_expose), window ); + + gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK) ; + + gtk_widget_show( window->frame ); + gtk_window_set_title( GTK_WINDOW(window->frame), name ); + + if( hg_windows ) + hg_windows->prev = window; + hg_windows = window; + + gtk_window_set_resizable( GTK_WINDOW(window->frame), (flags & CV_WINDOW_AUTOSIZE) == 0 ); + + + // allow window to be resized + if( (flags & CV_WINDOW_AUTOSIZE)==0 ){ + GdkGeometry geometry; + geometry.min_width = 50; + geometry.min_height = 50; + gtk_window_set_geometry_hints( GTK_WINDOW( window->frame ), GTK_WIDGET( window->widget ), + &geometry, (GdkWindowHints) (GDK_HINT_MIN_SIZE)); + } + + CV_UNLOCK_MUTEX(); + +#ifdef HAVE_OPENGL + if (window->useGl) + cvSetOpenGlContext(name); +#endif + + result = 1; + __END__; + + return result; +} + + +#ifdef HAVE_OPENGL + +CV_IMPL void cvSetOpenGlContext(const char* name) +{ + CvWindow* window; + GdkGLContext* glcontext; + GdkGLDrawable* gldrawable; + + CV_FUNCNAME( "cvSetOpenGlContext" ); + + __BEGIN__; + + if(!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + CV_ERROR( CV_StsNullPtr, "NULL window" ); + + if (!window->useGl) + CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" ); + + glcontext = gtk_widget_get_gl_context(window->widget); + gldrawable = gtk_widget_get_gl_drawable(window->widget); + + if (!gdk_gl_drawable_make_current(gldrawable, glcontext)) + CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" ); + + __END__; +} + +CV_IMPL void cvUpdateWindow(const char* name) +{ + CV_FUNCNAME( "cvUpdateWindow" ); + + __BEGIN__; + + CvWindow* window; + + if (!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + EXIT; + + // window does not refresh without this + gtk_widget_queue_draw( GTK_WIDGET(window->widget) ); + + __END__; +} + +CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata) +{ + CvWindow* window; + + CV_FUNCNAME( "cvCreateOpenGLCallback" ); + + __BEGIN__; + + if(!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if( !window ) + EXIT; + + if (!window->useGl) + CV_ERROR( CV_OpenGlNotSupported, "Window was created without OpenGL context" ); + + window->glDrawCallback = callback; + window->glDrawData = userdata; + + __END__; +} + +void icvSetOpenGlCleanCallback(const char* name, CvOpenGlCleanCallback callback, void* userdata) +{ + CvWindow* window; + GdkGLContext* glcontext; + GdkGLDrawable* gldrawable; + + CV_FUNCNAME( "icvSetOpenGlCleanCallback" ); + + __BEGIN__; + + if (!name) + CV_ERROR(CV_StsNullPtr, "NULL name string"); + + window = icvFindWindowByName(name); + if (!window) + EXIT; + + if (!window->useGl) + CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" ); + + glcontext = gtk_widget_get_gl_context(window->widget); + gldrawable = gtk_widget_get_gl_drawable(window->widget); + + gdk_gl_drawable_make_current(gldrawable, glcontext); + + if (window->glCleanCallback) + window->glCleanCallback(window->glCleanData); + + window->glCleanCallback = callback; + window->glCleanData = userdata; + + __END__; +} + +#endif // HAVE_OPENGL + + + + +static void icvDeleteWindow( CvWindow* window ) +{ + CvTrackbar* trackbar; + +#ifdef HAVE_OPENGL + if (window->useGl) + { + GdkGLContext* glcontext = gtk_widget_get_gl_context(window->widget); + GdkGLDrawable* gldrawable = gtk_widget_get_gl_drawable(window->widget); + + gdk_gl_drawable_make_current(gldrawable, glcontext); + + if (window->glCleanCallback) + { + window->glCleanCallback(window->glCleanData); + window->glCleanCallback = 0; + window->glCleanData = 0; + } + + releaseGlContext(window); + } +#endif + + if( window->prev ) + window->prev->next = window->next; + else + hg_windows = window->next; + + if( window->next ) + window->next->prev = window->prev; + + window->prev = window->next = 0; + + gtk_widget_destroy( window->frame ); + + for( trackbar = window->toolbar.first; trackbar != 0; ) + { + CvTrackbar* next = trackbar->next; + cvFree( &trackbar ); + trackbar = next; + } + + cvFree( &window ); +#ifdef HAVE_GTHREAD + // if last window, send key press signal + // to jump out of any waiting cvWaitKey's + if(hg_windows==0 && thread_started){ + g_cond_broadcast(cond_have_key); + } +#endif +} + + +CV_IMPL void cvDestroyWindow( const char* name ) +{ + CV_FUNCNAME( "cvDestroyWindow" ); + + __BEGIN__; + + CvWindow* window; + + if(!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if( !window ) + EXIT; + + // note that it is possible for the update thread to run this function + // if there is a call to cvShowImage in a mouse callback + // (this would produce a deadlock on window_mutex) + CV_LOCK_MUTEX(); + + icvDeleteWindow( window ); + + CV_UNLOCK_MUTEX(); + + __END__; +} + + +CV_IMPL void +cvDestroyAllWindows( void ) +{ + CV_LOCK_MUTEX(); + + while( hg_windows ) + { + CvWindow* window = hg_windows; + icvDeleteWindow( window ); + } + CV_UNLOCK_MUTEX(); +} + +// CvSize icvCalcOptimalWindowSize( CvWindow * window, CvSize new_image_size){ +// CvSize window_size; +// GtkWidget * toplevel = gtk_widget_get_toplevel( window->frame ); +// gdk_drawable_get_size( GDK_DRAWABLE(toplevel->window), +// &window_size.width, &window_size.height ); + +// window_size.width = window_size.width + new_image_size.width - window->widget->allocation.width; +// window_size.height = window_size.height + new_image_size.height - window->widget->allocation.height; + +// return window_size; +// } + +CV_IMPL void +cvShowImage( const char* name, const CvArr* arr ) +{ + CV_FUNCNAME( "cvShowImage" ); + + __BEGIN__; + + CvWindow* window; + + if( !name ) + CV_ERROR( CV_StsNullPtr, "NULL name" ); + + CV_LOCK_MUTEX(); + + window = icvFindWindowByName(name); + if(!window) + { + cvNamedWindow(name, 1); + window = icvFindWindowByName(name); + } + + if( window && arr ) + { + #ifdef HAVE_OPENGL + if (window->useGl) + { + CvMat stub; + CvMat* mat = cvGetMat(arr, &stub); + cv::Mat im(mat); + cv::imshow(name, im); + return; + } + #endif + + CvImageWidget * image_widget = CV_IMAGE_WIDGET( window->widget ); + cvImageWidgetSetImage( image_widget, arr ); + } + + CV_UNLOCK_MUTEX(); + + __END__; +} + +CV_IMPL void cvResizeWindow(const char* name, int width, int height ) +{ + CV_FUNCNAME( "cvResizeWindow" ); + + __BEGIN__; + + CvWindow* window; + CvImageWidget * image_widget; + + if( !name ) + CV_ERROR( CV_StsNullPtr, "NULL name" ); + + window = icvFindWindowByName(name); + if(!window) + EXIT; + + image_widget = CV_IMAGE_WIDGET( window->widget ); + //if(image_widget->flags & CV_WINDOW_AUTOSIZE) + //EXIT; + + CV_LOCK_MUTEX(); + + gtk_window_set_resizable( GTK_WINDOW(window->frame), 1 ); + gtk_window_resize( GTK_WINDOW(window->frame), width, height ); + + // disable initial resize since presumably user wants to keep + // this window size + image_widget->flags &= ~CV_WINDOW_NO_IMAGE; + + CV_UNLOCK_MUTEX(); + + __END__; +} + + +CV_IMPL void cvMoveWindow( const char* name, int x, int y ) +{ + CV_FUNCNAME( "cvMoveWindow" ); + + __BEGIN__; + + CvWindow* window; + + if( !name ) + CV_ERROR( CV_StsNullPtr, "NULL name" ); + + window = icvFindWindowByName(name); + if(!window) + EXIT; + + CV_LOCK_MUTEX(); + + gtk_window_move( GTK_WINDOW(window->frame), x, y ); + + CV_UNLOCK_MUTEX(); + + __END__; +} + + +static CvTrackbar* +icvFindTrackbarByName( const CvWindow* window, const char* name ) +{ + CvTrackbar* trackbar = window->toolbar.first; + + for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next ) + ; + + return trackbar; +} + +static int +icvCreateTrackbar( const char* trackbar_name, const char* window_name, + int* val, int count, CvTrackbarCallback on_notify, + CvTrackbarCallback2 on_notify2, void* userdata ) +{ + int result = 0; + + CV_FUNCNAME( "icvCreateTrackbar" ); + + __BEGIN__; + + /*char slider_name[32];*/ + CvWindow* window = 0; + CvTrackbar* trackbar = 0; + + if( !window_name || !trackbar_name ) + CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" ); + + if( count <= 0 ) + CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" ); + + window = icvFindWindowByName(window_name); + if( !window ) + EXIT; + + trackbar = icvFindTrackbarByName(window,trackbar_name); + + CV_LOCK_MUTEX(); + + if( !trackbar ) + { + int len = strlen(trackbar_name); + trackbar = (CvTrackbar*)cvAlloc(sizeof(CvTrackbar) + len + 1); + memset( trackbar, 0, sizeof(*trackbar)); + trackbar->signature = CV_TRACKBAR_MAGIC_VAL; + trackbar->name = (char*)(trackbar+1); + memcpy( trackbar->name, trackbar_name, len + 1 ); + trackbar->parent = window; + trackbar->next = window->toolbar.first; + window->toolbar.first = trackbar; + + GtkWidget* hscale_box = gtk_hbox_new( FALSE, 10 ); + GtkWidget* hscale_label = gtk_label_new( trackbar_name ); + GtkWidget* hscale = gtk_hscale_new_with_range( 0, count, 1 ); + gtk_range_set_update_policy( GTK_RANGE(hscale), GTK_UPDATE_CONTINUOUS ); + gtk_scale_set_digits( GTK_SCALE(hscale), 0 ); + //gtk_scale_set_value_pos( hscale, GTK_POS_TOP ); + gtk_scale_set_draw_value( GTK_SCALE(hscale), TRUE ); + + trackbar->widget = hscale; + gtk_box_pack_start( GTK_BOX(hscale_box), hscale_label, FALSE, FALSE, 5 ); + gtk_widget_show( hscale_label ); + gtk_box_pack_start( GTK_BOX(hscale_box), hscale, TRUE, TRUE, 5 ); + gtk_widget_show( hscale ); + gtk_box_pack_start( GTK_BOX(window->paned), hscale_box, FALSE, FALSE, 5 ); + gtk_widget_show( hscale_box ); + + } + + if( val ) + { + int value = *val; + if( value < 0 ) + value = 0; + if( value > count ) + value = count; + gtk_range_set_value( GTK_RANGE(trackbar->widget), value ); + trackbar->pos = value; + trackbar->data = val; + } + + trackbar->maxval = count; + trackbar->notify = on_notify; + trackbar->notify2 = on_notify2; + trackbar->userdata = userdata; + gtk_signal_connect( GTK_OBJECT(trackbar->widget), "value-changed", + GTK_SIGNAL_FUNC(icvOnTrackbar), trackbar ); + + // queue a widget resize to trigger a window resize to + // compensate for the addition of trackbars + gtk_widget_queue_resize( GTK_WIDGET(window->widget) ); + + + CV_UNLOCK_MUTEX(); + + result = 1; + + __END__; + + return result; +} + + +CV_IMPL int +cvCreateTrackbar( const char* trackbar_name, const char* window_name, + int* val, int count, CvTrackbarCallback on_notify ) +{ + return icvCreateTrackbar(trackbar_name, window_name, val, count, + on_notify, 0, 0); +} + + +CV_IMPL int +cvCreateTrackbar2( const char* trackbar_name, const char* window_name, + int* val, int count, CvTrackbarCallback2 on_notify2, + void* userdata ) +{ + return icvCreateTrackbar(trackbar_name, window_name, val, count, + 0, on_notify2, userdata); +} + + +CV_IMPL void +cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param ) +{ + CV_FUNCNAME( "cvSetMouseCallback" ); + + __BEGIN__; + + CvWindow* window = 0; + + if( !window_name ) + CV_ERROR( CV_StsNullPtr, "NULL window name" ); + + window = icvFindWindowByName(window_name); + if( !window ) + EXIT; + + window->on_mouse = on_mouse; + window->on_mouse_param = param; + + __END__; +} + + +CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name ) +{ + int pos = -1; + + CV_FUNCNAME( "cvGetTrackbarPos" ); + + __BEGIN__; + + CvWindow* window; + CvTrackbar* trackbar = 0; + + if( trackbar_name == 0 || window_name == 0 ) + CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" ); + + window = icvFindWindowByName( window_name ); + if( window ) + trackbar = icvFindTrackbarByName( window, trackbar_name ); + + if( trackbar ) + pos = trackbar->pos; + + __END__; + + return pos; +} + + +CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos ) +{ + CV_FUNCNAME( "cvSetTrackbarPos" ); + + __BEGIN__; + + CvWindow* window; + CvTrackbar* trackbar = 0; + + if( trackbar_name == 0 || window_name == 0 ) + CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" ); + + window = icvFindWindowByName( window_name ); + if( window ) + trackbar = icvFindTrackbarByName( window, trackbar_name ); + + if( trackbar ) + { + if( pos < 0 ) + pos = 0; + + if( pos > trackbar->maxval ) + pos = trackbar->maxval; + } + + CV_LOCK_MUTEX(); + + gtk_range_set_value( GTK_RANGE(trackbar->widget), pos ); + + CV_UNLOCK_MUTEX(); + + __END__; +} + + +CV_IMPL void* cvGetWindowHandle( const char* window_name ) +{ + void* widget = 0; + + CV_FUNCNAME( "cvGetWindowHandle" ); + + __BEGIN__; + + CvWindow* window; + + if( window_name == 0 ) + CV_ERROR( CV_StsNullPtr, "NULL window name" ); + + window = icvFindWindowByName( window_name ); + if( window ) + widget = (void*)window->widget; + + __END__; + + return widget; +} + + +CV_IMPL const char* cvGetWindowName( void* window_handle ) +{ + const char* window_name = ""; + + CV_FUNCNAME( "cvGetWindowName" ); + + __BEGIN__; + + CvWindow* window; + + if( window_handle == 0 ) + CV_ERROR( CV_StsNullPtr, "NULL window" ); + + window = icvWindowByWidget( (GtkWidget*)window_handle ); + if( window ) + window_name = window->name; + + __END__; + + return window_name; +} + +static gboolean icvOnKeyPress( GtkWidget * /*widget*/, + GdkEventKey* event, gpointer /*user_data*/ ) +{ + int code = 0; + + switch( event->keyval ) + { + case GDK_Escape: + code = 27; + break; + case GDK_Return: + case GDK_Linefeed: + code = '\n'; + break; + case GDK_Tab: + code = '\t'; + break; + default: + code = event->keyval; + } + + code |= event->state << 16; + +#ifdef HAVE_GTHREAD + if(thread_started) g_mutex_lock(last_key_mutex); +#endif + + last_key = code; + +#ifdef HAVE_GTHREAD + if(thread_started){ + // signal any waiting threads + g_cond_broadcast(cond_have_key); + g_mutex_unlock(last_key_mutex); + } +#endif + + return FALSE; +} + + +static void icvOnTrackbar( GtkWidget* widget, gpointer user_data ) +{ + int pos = cvRound( gtk_range_get_value(GTK_RANGE(widget))); + CvTrackbar* trackbar = (CvTrackbar*)user_data; + + if( trackbar && trackbar->signature == CV_TRACKBAR_MAGIC_VAL && + trackbar->widget == widget ) + { + trackbar->pos = pos; + if( trackbar->data ) + *trackbar->data = pos; + if( trackbar->notify2 ) + trackbar->notify2(pos, trackbar->userdata); + else if( trackbar->notify ) + trackbar->notify(pos); + } +} + +static gboolean icvOnClose( GtkWidget* widget, GdkEvent* /*event*/, gpointer user_data ) +{ + CvWindow* window = (CvWindow*)user_data; + if( window->signature == CV_WINDOW_MAGIC_VAL && + window->frame == widget ) + { + icvDeleteWindow(window); + } + return TRUE; +} + + +static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_data ) +{ + // TODO move this logic to CvImageWidget + CvWindow* window = (CvWindow*)user_data; + CvPoint2D32f pt32f = {-1., -1.}; + CvPoint pt = {-1,-1}; + int cv_event = -1, state = 0; + CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget ); + + if( window->signature != CV_WINDOW_MAGIC_VAL || + window->widget != widget || !window->widget || + !window->on_mouse /*|| !image_widget->original_image*/) + return FALSE; + + if( event->type == GDK_MOTION_NOTIFY ) + { + GdkEventMotion* event_motion = (GdkEventMotion*)event; + + cv_event = CV_EVENT_MOUSEMOVE; + pt32f.x = cvRound(event_motion->x); + pt32f.y = cvRound(event_motion->y); + state = event_motion->state; + } + else if( event->type == GDK_BUTTON_PRESS || + event->type == GDK_BUTTON_RELEASE || + event->type == GDK_2BUTTON_PRESS ) + { + GdkEventButton* event_button = (GdkEventButton*)event; + pt32f.x = cvRound(event_button->x); + pt32f.y = cvRound(event_button->y); + + + if( event_button->type == GDK_BUTTON_PRESS ) + { + cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDOWN : + event_button->button == 2 ? CV_EVENT_MBUTTONDOWN : + event_button->button == 3 ? CV_EVENT_RBUTTONDOWN : 0; + } + else if( event_button->type == GDK_BUTTON_RELEASE ) + { + cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONUP : + event_button->button == 2 ? CV_EVENT_MBUTTONUP : + event_button->button == 3 ? CV_EVENT_RBUTTONUP : 0; + } + else if( event_button->type == GDK_2BUTTON_PRESS ) + { + cv_event = event_button->button == 1 ? CV_EVENT_LBUTTONDBLCLK : + event_button->button == 2 ? CV_EVENT_MBUTTONDBLCLK : + event_button->button == 3 ? CV_EVENT_RBUTTONDBLCLK : 0; + } + state = event_button->state; + } + + if( cv_event >= 0 ){ + // scale point if image is scaled + if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 && + image_widget->original_image && + image_widget->scaled_image ){ + // image origin is not necessarily at (0,0) + int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2; + int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2; + pt.x = cvRound( ((pt32f.x-x0)*image_widget->original_image->cols)/ + image_widget->scaled_image->cols ); + pt.y = cvRound( ((pt32f.y-y0)*image_widget->original_image->rows)/ + image_widget->scaled_image->rows ); + } + else{ + pt = cvPointFrom32f( pt32f ); + } + +// if((unsigned)pt.x < (unsigned)(image_widget->original_image->width) && +// (unsigned)pt.y < (unsigned)(image_widget->original_image->height) ) + { + int flags = (state & GDK_SHIFT_MASK ? CV_EVENT_FLAG_SHIFTKEY : 0) | + (state & GDK_CONTROL_MASK ? CV_EVENT_FLAG_CTRLKEY : 0) | + (state & (GDK_MOD1_MASK|GDK_MOD2_MASK) ? CV_EVENT_FLAG_ALTKEY : 0) | + (state & GDK_BUTTON1_MASK ? CV_EVENT_FLAG_LBUTTON : 0) | + (state & GDK_BUTTON2_MASK ? CV_EVENT_FLAG_MBUTTON : 0) | + (state & GDK_BUTTON3_MASK ? CV_EVENT_FLAG_RBUTTON : 0); + window->on_mouse( cv_event, pt.x, pt.y, flags, window->on_mouse_param ); + } + } + + return FALSE; + } + + +static gboolean icvAlarm( gpointer user_data ) +{ + *(int*)user_data = 1; + return FALSE; +} + + +CV_IMPL int cvWaitKey( int delay ) +{ +#ifdef HAVE_GTHREAD + if(thread_started && g_thread_self()!=window_thread){ + gboolean expired; + int my_last_key; + + // wait for signal or timeout if delay > 0 + if(delay>0){ + GTimeVal timer; + g_get_current_time(&timer); + g_time_val_add(&timer, delay*1000); + expired = !g_cond_timed_wait(cond_have_key, last_key_mutex, &timer); + } + else{ + g_cond_wait(cond_have_key, last_key_mutex); + expired=false; + } + my_last_key = last_key; + g_mutex_unlock(last_key_mutex); + if(expired || hg_windows==0){ + return -1; + } + return my_last_key; + } + else{ +#endif + int expired = 0; + guint timer = 0; + if( delay > 0 ) + timer = g_timeout_add( delay, icvAlarm, &expired ); + last_key = -1; + while( gtk_main_iteration_do(TRUE) && last_key < 0 && !expired && hg_windows != 0 ) + ; + + if( delay > 0 && !expired ) + g_source_remove(timer); +#ifdef HAVE_GTHREAD + } +#endif + return last_key; +} + + +#endif // HAVE_GTK +#endif // WIN32 + +/* End of file. */ diff --git a/highgui/src/window_w32.cpp b/highgui/src/window_w32.cpp new file mode 100644 index 0000000..29cdda8 --- /dev/null +++ b/highgui/src/window_w32.cpp @@ -0,0 +1,2484 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +#if defined WIN32 || defined _WIN32 + +#define COMPILE_MULTIMON_STUBS // Required for multi-monitor support +#ifndef _MULTIMON_USE_SECURE_CRT +# define _MULTIMON_USE_SECURE_CRT 0 // some MinGW platforms have no strncpy_s +#endif + +#if defined SM_CMONITORS && !defined MONITOR_DEFAULTTONEAREST +# define MONITOR_DEFAULTTONULL 0x00000000 +# define MONITOR_DEFAULTTOPRIMARY 0x00000001 +# define MONITOR_DEFAULTTONEAREST 0x00000002 +# define MONITORINFOF_PRIMARY 0x00000001 +#endif +#ifndef __inout +# define __inout +#endif + +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wmissing-declarations" +#endif +#include + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_OPENGL +#include +#include +#include +#include +#include "opencv2/highgui/highgui.hpp" +#include +#endif + +static const char* trackbar_text = +" "; + +#if defined _M_X64 || defined __x86_64 + +#define icvGetWindowLongPtr GetWindowLongPtr +#define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLongPtr( hwnd, id, (LONG_PTR)(ptr) ) +#define icvGetClassLongPtr GetClassLongPtr + +#define CV_USERDATA GWLP_USERDATA +#define CV_WNDPROC GWLP_WNDPROC +#define CV_HCURSOR GCLP_HCURSOR +#define CV_HBRBACKGROUND GCLP_HBRBACKGROUND + +#else + +#define icvGetWindowLongPtr GetWindowLong +#define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLong( hwnd, id, (size_t)ptr ) +#define icvGetClassLongPtr GetClassLong + +#define CV_USERDATA GWL_USERDATA +#define CV_WNDPROC GWL_WNDPROC +#define CV_HCURSOR GCL_HCURSOR +#define CV_HBRBACKGROUND GCL_HBRBACKGROUND + +#endif + +void FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin ) +{ + assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32)); + + BITMAPINFOHEADER* bmih = &(bmi->bmiHeader); + + memset( bmih, 0, sizeof(*bmih)); + bmih->biSize = sizeof(BITMAPINFOHEADER); + bmih->biWidth = width; + bmih->biHeight = origin ? abs(height) : -abs(height); + bmih->biPlanes = 1; + bmih->biBitCount = (unsigned short)bpp; + bmih->biCompression = BI_RGB; + + if( bpp == 8 ) + { + RGBQUAD* palette = bmi->bmiColors; + int i; + for( i = 0; i < 256; i++ ) + { + palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i; + palette[i].rgbReserved = 0; + } + } +} + +struct CvWindow; + +typedef struct CvTrackbar +{ + int signature; + HWND hwnd; + char* name; + CvTrackbar* next; + CvWindow* parent; + HWND buddy; + int* data; + int pos; + int maxval; + void (*notify)(int); + void (*notify2)(int, void*); + void* userdata; + int id; +} +CvTrackbar; + + +typedef struct CvWindow +{ + int signature; + HWND hwnd; + char* name; + CvWindow* prev; + CvWindow* next; + HWND frame; + + HDC dc; + HGDIOBJ image; + int last_key; + int flags; + int status;//0 normal, 1 fullscreen (YV) + + CvMouseCallback on_mouse; + void* on_mouse_param; + + struct + { + HWND toolbar; + int pos; + int rows; + WNDPROC toolBarProc; + CvTrackbar* first; + } + toolbar; + + int width; + int height; + + // OpenGL support + +#ifdef HAVE_OPENGL + bool useGl; + HGLRC hGLRC; + + CvOpenGlDrawCallback glDrawCallback; + void* glDrawData; + + CvOpenGlCleanCallback glCleanCallback; + void* glCleanData; + + CvOpenGlFuncTab* glFuncTab; +#endif +} +CvWindow; + +#define HG_BUDDY_WIDTH 130 + +#ifndef TBIF_SIZE + #define TBIF_SIZE 0x40 +#endif + +#ifndef TB_SETBUTTONINFO + #define TB_SETBUTTONINFO (WM_USER + 66) +#endif + +#ifndef TBM_GETTOOLTIPS + #define TBM_GETTOOLTIPS (WM_USER + 30) +#endif + +static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static LRESULT CALLBACK MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static void icvUpdateWindowPos( CvWindow* window ); + +static CvWindow* hg_windows = 0; + +typedef int (CV_CDECL * CvWin32WindowCallback)(HWND, UINT, WPARAM, LPARAM, int*); +static CvWin32WindowCallback hg_on_preprocess = 0, hg_on_postprocess = 0; +static HINSTANCE hg_hinstance = 0; + +static const char* highGUIclassName = "HighGUI class"; +static const char* mainHighGUIclassName = "Main HighGUI class"; + +static void icvCleanupHighgui() +{ + cvDestroyAllWindows(); + UnregisterClass(highGUIclassName, hg_hinstance); + UnregisterClass(mainHighGUIclassName, hg_hinstance); +} + +CV_IMPL int cvInitSystem( int, char** ) +{ + static int wasInitialized = 0; + + // check initialization status + if( !wasInitialized ) + { + // Initialize the stogare + hg_windows = 0; + + // Register the class + WNDCLASS wndc; + wndc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS; + wndc.lpfnWndProc = WindowProc; + wndc.cbClsExtra = 0; + wndc.cbWndExtra = 0; + wndc.hInstance = hg_hinstance; + wndc.lpszClassName = highGUIclassName; + wndc.lpszMenuName = highGUIclassName; + wndc.hIcon = LoadIcon(0, IDI_APPLICATION); + wndc.hCursor = (HCURSOR)LoadCursor(0, (LPSTR)(size_t)IDC_CROSS ); + wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH); + + RegisterClass(&wndc); + + wndc.lpszClassName = mainHighGUIclassName; + wndc.lpszMenuName = mainHighGUIclassName; + wndc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH); + wndc.lpfnWndProc = MainWindowProc; + + RegisterClass(&wndc); + atexit( icvCleanupHighgui ); + + wasInitialized = 1; + } + + return 0; +} + +CV_IMPL int cvStartWindowThread(){ + return 0; +} + +static CvWindow* icvFindWindowByName( const char* name ) +{ + CvWindow* window = hg_windows; + + for( ; window != 0 && strcmp( name, window->name) != 0; window = window->next ) + ; + + return window; +} + + +static CvWindow* icvWindowByHWND( HWND hwnd ) +{ + CvWindow* window = (CvWindow*)icvGetWindowLongPtr( hwnd, CV_USERDATA ); + return window != 0 && hg_windows != 0 && + window->signature == CV_WINDOW_MAGIC_VAL ? window : 0; +} + + +static CvTrackbar* icvTrackbarByHWND( HWND hwnd ) +{ + CvTrackbar* trackbar = (CvTrackbar*)icvGetWindowLongPtr( hwnd, CV_USERDATA ); + return trackbar != 0 && trackbar->signature == CV_TRACKBAR_MAGIC_VAL && + trackbar->hwnd == hwnd ? trackbar : 0; +} + + +static const char* icvWindowPosRootKey = "Software\\OpenCV\\HighGUI\\Windows\\"; + +// Window positions saving/loading added by Philip Gruebele. +//pgruebele@cox.net +// Restores the window position from the registry saved position. +static void +icvLoadWindowPos( const char* name, CvRect& rect ) +{ + HKEY hkey; + char szKey[1024]; + strcpy( szKey, icvWindowPosRootKey ); + strcat( szKey, name ); + + rect.x = rect.y = CW_USEDEFAULT; + rect.width = rect.height = 320; + + if( RegOpenKeyEx(HKEY_CURRENT_USER,szKey,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS ) + { + // Yes we are installed. + DWORD dwType = 0; + DWORD dwSize = sizeof(int); + + RegQueryValueEx(hkey, "Left", NULL, &dwType, (BYTE*)&rect.x, &dwSize); + RegQueryValueEx(hkey, "Top", NULL, &dwType, (BYTE*)&rect.y, &dwSize); + RegQueryValueEx(hkey, "Width", NULL, &dwType, (BYTE*)&rect.width, &dwSize); + RegQueryValueEx(hkey, "Height", NULL, &dwType, (BYTE*)&rect.height, &dwSize); + + if( rect.x != (int)CW_USEDEFAULT && (rect.x < -200 || rect.x > 3000) ) + rect.x = 100; + if( rect.y != (int)CW_USEDEFAULT && (rect.y < -200 || rect.y > 3000) ) + rect.y = 100; + + if( rect.width != (int)CW_USEDEFAULT && (rect.width < 0 || rect.width > 3000) ) + rect.width = 100; + if( rect.height != (int)CW_USEDEFAULT && (rect.height < 0 || rect.height > 3000) ) + rect.height = 100; + + RegCloseKey(hkey); + } +} + + +// Window positions saving/loading added by Philip Gruebele. +//pgruebele@cox.net +// philipg. Saves the window position in the registry +static void +icvSaveWindowPos( const char* name, CvRect rect ) +{ + static const DWORD MAX_RECORD_COUNT = 100; + HKEY hkey; + char szKey[1024]; + char rootKey[1024]; + strcpy( szKey, icvWindowPosRootKey ); + strcat( szKey, name ); + + if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_READ,&hkey) != ERROR_SUCCESS ) + { + HKEY hroot; + DWORD count = 0; + FILETIME oldestTime = { UINT_MAX, UINT_MAX }; + char oldestKey[1024]; + char currentKey[1024]; + + strcpy( rootKey, icvWindowPosRootKey ); + rootKey[strlen(rootKey)-1] = '\0'; + if( RegCreateKeyEx(HKEY_CURRENT_USER, rootKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ+KEY_WRITE, 0, &hroot, NULL) != ERROR_SUCCESS ) + //RegOpenKeyEx( HKEY_CURRENT_USER,rootKey,0,KEY_READ,&hroot) != ERROR_SUCCESS ) + return; + + for(;;) + { + DWORD csize = sizeof(currentKey); + FILETIME accesstime = { 0, 0 }; + LONG code = RegEnumKeyEx( hroot, count, currentKey, &csize, NULL, NULL, NULL, &accesstime ); + if( code != ERROR_SUCCESS && code != ERROR_MORE_DATA ) + break; + count++; + if( oldestTime.dwHighDateTime > accesstime.dwHighDateTime || + (oldestTime.dwHighDateTime == accesstime.dwHighDateTime && + oldestTime.dwLowDateTime > accesstime.dwLowDateTime) ) + { + oldestTime = accesstime; + strcpy( oldestKey, currentKey ); + } + } + + if( count >= MAX_RECORD_COUNT ) + RegDeleteKey( hroot, oldestKey ); + RegCloseKey( hroot ); + + if( RegCreateKeyEx(HKEY_CURRENT_USER,szKey,0,NULL,REG_OPTION_NON_VOLATILE, KEY_WRITE, 0, &hkey, NULL) != ERROR_SUCCESS ) + return; + } + else + { + RegCloseKey( hkey ); + if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_WRITE,&hkey) != ERROR_SUCCESS ) + return; + } + + RegSetValueEx(hkey, "Left", 0, REG_DWORD, (BYTE*)&rect.x, sizeof(rect.x)); + RegSetValueEx(hkey, "Top", 0, REG_DWORD, (BYTE*)&rect.y, sizeof(rect.y)); + RegSetValueEx(hkey, "Width", 0, REG_DWORD, (BYTE*)&rect.width, sizeof(rect.width)); + RegSetValueEx(hkey, "Height", 0, REG_DWORD, (BYTE*)&rect.height, sizeof(rect.height)); + RegCloseKey(hkey); +} + +double cvGetModeWindow_W32(const char* name)//YV +{ + double result = -1; + + CV_FUNCNAME( "cvGetModeWindow_W32" ); + + __BEGIN__; + + CvWindow* window; + + if (!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + EXIT; // keep silence here + + result = window->status; + + __END__; + return result; +} + +void cvSetModeWindow_W32( const char* name, double prop_value)//Yannick Verdie +{ + CV_FUNCNAME( "cvSetModeWindow_W32" ); + + __BEGIN__; + + CvWindow* window; + + if(!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if( !window ) + CV_ERROR( CV_StsNullPtr, "NULL window" ); + + if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set + EXIT; + + { + DWORD dwStyle = (DWORD)GetWindowLongPtr(window->frame, GWL_STYLE); + CvRect position; + + if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL) + { + icvLoadWindowPos(window->name,position ); + SetWindowLongPtr(window->frame, GWL_STYLE, dwStyle | WS_CAPTION | WS_THICKFRAME); + + SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED); + window->status=CV_WINDOW_NORMAL; + + EXIT; + } + + if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN) + { + //save dimension + RECT rect; + GetWindowRect(window->frame, &rect); + CvRect RectCV = cvRect(rect.left, rect.top,rect.right - rect.left, rect.bottom - rect.top); + icvSaveWindowPos(window->name,RectCV ); + + //Look at coordinate for fullscreen + HMONITOR hMonitor; + MONITORINFO mi; + hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST); + + mi.cbSize = sizeof(mi); + GetMonitorInfo(hMonitor, &mi); + + //fullscreen + position.x=mi.rcMonitor.left;position.y=mi.rcMonitor.top; + position.width=mi.rcMonitor.right - mi.rcMonitor.left;position.height=mi.rcMonitor.bottom - mi.rcMonitor.top; + SetWindowLongPtr(window->frame, GWL_STYLE, dwStyle & ~WS_CAPTION & ~WS_THICKFRAME); + + SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED); + window->status=CV_WINDOW_FULLSCREEN; + + EXIT; + } + } + + __END__; +} + +double cvGetPropWindowAutoSize_W32(const char* name) +{ + double result = -1; + + CV_FUNCNAME( "cvSetCloseCallback" ); + + __BEGIN__; + + CvWindow* window; + + if (!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + EXIT; // keep silence here + + result = window->flags & CV_WINDOW_AUTOSIZE; + + __END__; + + return result; +} + +double cvGetRatioWindow_W32(const char* name) +{ + double result = -1; + + CV_FUNCNAME( "cvGetRatioWindow_W32" ); + + __BEGIN__; + + CvWindow* window; + + if (!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + EXIT; // keep silence here + + result = static_cast(window->width) / window->height; + + __END__; + + return result; +} + +double cvGetOpenGlProp_W32(const char* name) +{ + double result = -1; + +#ifdef HAVE_OPENGL + CV_FUNCNAME( "cvGetOpenGlProp_W32" ); + + __BEGIN__; + + CvWindow* window; + + if (!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + EXIT; // keep silence here + + result = window->useGl; + + __END__; +#endif + (void)name; + + return result; +} + + +// OpenGL support + +#ifdef HAVE_OPENGL + +#ifndef APIENTRY + #define APIENTRY +#endif + +#ifndef APIENTRYP + #define APIENTRYP APIENTRY * +#endif + +#ifndef GL_VERSION_1_5 + /* GL types for handling large vertex buffer objects */ + typedef ptrdiff_t GLintptr; + typedef ptrdiff_t GLsizeiptr; +#endif + +namespace +{ + typedef void (APIENTRYP PFNGLGENBUFFERSPROC ) (GLsizei n, GLuint *buffers); + typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); + + typedef void (APIENTRYP PFNGLBUFFERDATAPROC ) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); + typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data); + + typedef void (APIENTRYP PFNGLBINDBUFFERPROC ) (GLenum target, GLuint buffer); + + typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); + typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); + + class GlFuncTab_W32 : public CvOpenGlFuncTab + { + public: + GlFuncTab_W32(HDC hDC); + + void genBuffers(int n, unsigned int* buffers) const; + void deleteBuffers(int n, const unsigned int* buffers) const; + + void bufferData(unsigned int target, ptrdiff_t size, const void* data, unsigned int usage) const; + void bufferSubData(unsigned int target, ptrdiff_t offset, ptrdiff_t size, const void* data) const; + + void bindBuffer(unsigned int target, unsigned int buffer) const; + + void* mapBuffer(unsigned int target, unsigned int access) const; + void unmapBuffer(unsigned int target) const; + + void generateBitmapFont(const std::string& family, int height, int weight, bool italic, bool underline, int start, int count, int base) const; + + bool isGlContextInitialized() const; + + PFNGLGENBUFFERSPROC glGenBuffersExt; + PFNGLDELETEBUFFERSPROC glDeleteBuffersExt; + + PFNGLBUFFERDATAPROC glBufferDataExt; + PFNGLBUFFERSUBDATAPROC glBufferSubDataExt; + + PFNGLBINDBUFFERPROC glBindBufferExt; + + PFNGLMAPBUFFERPROC glMapBufferExt; + PFNGLUNMAPBUFFERPROC glUnmapBufferExt; + + bool initialized; + + HDC hDC; + }; + + GlFuncTab_W32::GlFuncTab_W32(HDC hDC_) + { + glGenBuffersExt = 0; + glDeleteBuffersExt = 0; + + glBufferDataExt = 0; + glBufferSubDataExt = 0; + + glBindBufferExt = 0; + + glMapBufferExt = 0; + glUnmapBufferExt = 0; + + initialized = false; + + hDC = hDC_; + } + + void GlFuncTab_W32::genBuffers(int n, unsigned int* buffers) const + { + CV_FUNCNAME( "GlFuncTab_W32::genBuffers" ); + + __BEGIN__; + + if (!glGenBuffersExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glGenBuffersExt(n, buffers); + CV_CheckGlError(); + + __END__; + } + + void GlFuncTab_W32::deleteBuffers(int n, const unsigned int* buffers) const + { + CV_FUNCNAME( "GlFuncTab_W32::deleteBuffers" ); + + __BEGIN__; + + if (!glDeleteBuffersExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glDeleteBuffersExt(n, buffers); + CV_CheckGlError(); + + __END__; + } + + void GlFuncTab_W32::bufferData(unsigned int target, ptrdiff_t size, const void* data, unsigned int usage) const + { + CV_FUNCNAME( "GlFuncTab_W32::bufferData" ); + + __BEGIN__; + + if (!glBufferDataExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glBufferDataExt(target, size, data, usage); + CV_CheckGlError(); + + __END__; + } + + void GlFuncTab_W32::bufferSubData(unsigned int target, ptrdiff_t offset, ptrdiff_t size, const void* data) const + { + CV_FUNCNAME( "GlFuncTab_W32::bufferSubData" ); + + __BEGIN__; + + if (!glBufferSubDataExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glBufferSubDataExt(target, offset, size, data); + CV_CheckGlError(); + + __END__; + } + + void GlFuncTab_W32::bindBuffer(unsigned int target, unsigned int buffer) const + { + CV_FUNCNAME( "GlFuncTab_W32::bindBuffer" ); + + __BEGIN__; + + if (!glBindBufferExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glBindBufferExt(target, buffer); + CV_CheckGlError(); + + __END__; + } + + void* GlFuncTab_W32::mapBuffer(unsigned int target, unsigned int access) const + { + CV_FUNCNAME( "GlFuncTab_W32::mapBuffer" ); + + void* res = 0; + + __BEGIN__; + + if (!glMapBufferExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + res = glMapBufferExt(target, access); + CV_CheckGlError(); + + __END__; + + return res; + } + + void GlFuncTab_W32::unmapBuffer(unsigned int target) const + { + CV_FUNCNAME( "GlFuncTab_W32::unmapBuffer" ); + + __BEGIN__; + + if (!glUnmapBufferExt) + CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension"); + + glUnmapBufferExt(target); + CV_CheckGlError(); + + __END__; + } + + void GlFuncTab_W32::generateBitmapFont(const std::string& family, int height, int weight, bool italic, bool underline, int start, int count, int base) const + { + HFONT font; + + CV_FUNCNAME( "GlFuncTab_W32::generateBitmapFont" ); + + __BEGIN__; + + font = CreateFont + ( + -height, // height + 0, // cell width + 0, // Angle of Escapement + 0, // Orientation Angle + weight, // font weight + italic ? TRUE : FALSE, // Italic + underline ? TRUE : FALSE, // Underline + FALSE, // StrikeOut + ANSI_CHARSET, // CharSet + OUT_TT_PRECIS, // OutPrecision + CLIP_DEFAULT_PRECIS, // ClipPrecision + ANTIALIASED_QUALITY, // Quality + FF_DONTCARE | DEFAULT_PITCH, // PitchAndFamily + family.c_str() // FaceName + ); + + SelectObject(hDC, font); + + if (!wglUseFontBitmaps(hDC, start, count, base)) + CV_ERROR(CV_OpenGlApiCallError, "Can't create font"); + + __END__; + } + + bool GlFuncTab_W32::isGlContextInitialized() const + { + return initialized; + } + + void initGl(CvWindow* window) + { + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + + std::auto_ptr glFuncTab(new GlFuncTab_W32(window->dc)); + + // Load extensions + PROC func; + + func = wglGetProcAddress("glGenBuffers"); + glFuncTab->glGenBuffersExt = (PFNGLGENBUFFERSPROC)func; + + func = wglGetProcAddress("glDeleteBuffers"); + glFuncTab->glDeleteBuffersExt = (PFNGLDELETEBUFFERSPROC)func; + + func = wglGetProcAddress("glBufferData"); + glFuncTab->glBufferDataExt = (PFNGLBUFFERDATAPROC)func; + + func = wglGetProcAddress("glBufferSubData"); + glFuncTab->glBufferSubDataExt = (PFNGLBUFFERSUBDATAPROC)func; + + func = wglGetProcAddress("glBindBuffer"); + glFuncTab->glBindBufferExt = (PFNGLBINDBUFFERPROC)func; + + func = wglGetProcAddress("glMapBuffer"); + glFuncTab->glMapBufferExt = (PFNGLMAPBUFFERPROC)func; + + func = wglGetProcAddress("glUnmapBuffer"); + glFuncTab->glUnmapBufferExt = (PFNGLUNMAPBUFFERPROC)func; + + glFuncTab->initialized = true; + + window->glFuncTab = glFuncTab.release(); + + icvSetOpenGlFuncTab(window->glFuncTab); + } + + void createGlContext(HWND hWnd, HDC& hGLDC, HGLRC& hGLRC, bool& useGl) + { + CV_FUNCNAME( "createGlContext" ); + + __BEGIN__; + + useGl = false; + + int PixelFormat; + + static PIXELFORMATDESCRIPTOR pfd = + { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, // Must Support Double Buffering + PFD_TYPE_RGBA, // Request An RGBA Format + 32, // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // No Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 32, // 32 Bit Z-Buffer (Depth Buffer) + 0, // No Stencil Buffer + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + hGLDC = GetDC(hWnd); + if (!hGLDC) + CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" ); + + PixelFormat = ChoosePixelFormat(hGLDC, &pfd); + if (!PixelFormat) + CV_ERROR( CV_OpenGlApiCallError, "Can't Find A Suitable PixelFormat" ); + + if (!SetPixelFormat(hGLDC, PixelFormat, &pfd)) + CV_ERROR( CV_OpenGlApiCallError, "Can't Set The PixelFormat" ); + + hGLRC = wglCreateContext(hGLDC); + if (!hGLRC) + CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Rendering Context" ); + + if (!wglMakeCurrent(hGLDC, hGLRC)) + CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" ); + + useGl = true; + + __END__; + } + + void releaseGlContext(CvWindow* window) + { + //CV_FUNCNAME( "releaseGlContext" ); + + __BEGIN__; + + delete window->glFuncTab; + + if (window->hGLRC) + { + wglDeleteContext(window->hGLRC); + window->hGLRC = NULL; + } + + if (window->dc) + { + ReleaseDC(window->hwnd, window->dc); + window->dc = NULL; + } + + window->useGl = false; + + __END__; + } + + void drawGl(CvWindow* window) + { + CV_FUNCNAME( "drawGl" ); + + __BEGIN__; + + if (!wglMakeCurrent(window->dc, window->hGLRC)) + CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" ); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (window->glDrawCallback) + window->glDrawCallback(window->glDrawData); + + CV_CheckGlError(); + + if (!SwapBuffers(window->dc)) + CV_ERROR( CV_OpenGlApiCallError, "Can't swap OpenGL buffers" ); + + __END__; + } + + void resizeGl(CvWindow* window) + { + CV_FUNCNAME( "resizeGl" ); + + __BEGIN__; + + if (!wglMakeCurrent(window->dc, window->hGLRC)) + CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" ); + + glViewport(0, 0, window->width, window->height); + + __END__; + } +} + +#endif // HAVE_OPENGL + + +CV_IMPL int cvNamedWindow( const char* name, int flags ) +{ + int result = 0; + CV_FUNCNAME( "cvNamedWindow" ); + + __BEGIN__; + + HWND hWnd, mainhWnd; + CvWindow* window; + DWORD defStyle = WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU; + int len; + CvRect rect; +#ifdef HAVE_OPENGL + bool useGl; + HDC hGLDC; + HGLRC hGLRC; +#endif + + cvInitSystem(0,0); + + if( !name ) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + // Check the name in the storage + window = icvFindWindowByName( name ); + if (window != 0) + { + result = 1; + EXIT; + } + + if( !(flags & CV_WINDOW_AUTOSIZE))//YV add border in order to resize the window + defStyle |= WS_SIZEBOX; + + icvLoadWindowPos( name, rect ); + + mainhWnd = CreateWindow( "Main HighGUI class", name, defStyle | WS_OVERLAPPED, + rect.x, rect.y, rect.width, rect.height, 0, 0, hg_hinstance, 0 ); + if( !mainhWnd ) + CV_ERROR( CV_StsError, "Frame window can not be created" ); + + ShowWindow(mainhWnd, SW_SHOW); + + //YV- remove one border by changing the style + hWnd = CreateWindow("HighGUI class", "", (defStyle & ~WS_SIZEBOX) | WS_CHILD, CW_USEDEFAULT, 0, rect.width, rect.height, mainhWnd, 0, hg_hinstance, 0); + if( !hWnd ) + CV_ERROR( CV_StsError, "Frame window can not be created" ); + +#ifndef HAVE_OPENGL + if (flags & CV_WINDOW_OPENGL) + CV_ERROR( CV_OpenGlNotSupported, "Library was built without OpenGL support" ); +#else + useGl = false; + hGLDC = 0; + hGLRC = 0; + + if (flags & CV_WINDOW_OPENGL) + createGlContext(hWnd, hGLDC, hGLRC, useGl); +#endif + + ShowWindow(hWnd, SW_SHOW); + + len = (int)strlen(name); + CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1)); + + window->signature = CV_WINDOW_MAGIC_VAL; + window->hwnd = hWnd; + window->frame = mainhWnd; + window->name = (char*)(window + 1); + memcpy( window->name, name, len + 1 ); + window->flags = flags; + window->image = 0; + +#ifndef HAVE_OPENGL + window->dc = CreateCompatibleDC(0); +#else + window->glFuncTab = 0; + if (!useGl) + { + window->dc = CreateCompatibleDC(0); + window->hGLRC = 0; + window->useGl = false; + } + else + { + window->dc = hGLDC; + window->hGLRC = hGLRC; + window->useGl = true; + initGl(window); + } + + window->glDrawCallback = 0; + window->glDrawData = 0; + + window->glCleanCallback = 0; + window->glCleanData = 0; +#endif + + window->last_key = 0; + window->status = CV_WINDOW_NORMAL;//YV + + window->on_mouse = 0; + window->on_mouse_param = 0; + + memset( &window->toolbar, 0, sizeof(window->toolbar)); + + window->next = hg_windows; + window->prev = 0; + if( hg_windows ) + hg_windows->prev = window; + hg_windows = window; + icvSetWindowLongPtr( hWnd, CV_USERDATA, window ); + icvSetWindowLongPtr( mainhWnd, CV_USERDATA, window ); + + // Recalculate window pos + icvUpdateWindowPos( window ); + + result = 1; + __END__; + + return result; +} + +#ifdef HAVE_OPENGL + +CV_IMPL void cvSetOpenGlContext(const char* name) +{ + CV_FUNCNAME( "cvSetOpenGlContext" ); + + __BEGIN__; + + CvWindow* window; + + if(!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + CV_ERROR( CV_StsNullPtr, "NULL window" ); + + if (!window->useGl) + CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" ); + + if (!wglMakeCurrent(window->dc, window->hGLRC)) + CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" ); + + icvSetOpenGlFuncTab(window->glFuncTab); + + __END__; +} + +CV_IMPL void cvUpdateWindow(const char* name) +{ + CV_FUNCNAME( "cvUpdateWindow" ); + + __BEGIN__; + + CvWindow* window; + + if (!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + EXIT; + + InvalidateRect(window->hwnd, 0, 0); + + __END__; +} + +CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata) +{ + CV_FUNCNAME( "cvCreateOpenGLCallback" ); + + __BEGIN__; + + CvWindow* window; + + if(!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if( !window ) + EXIT; + + if (!window->useGl) + CV_ERROR( CV_OpenGlNotSupported, "Window was created without OpenGL context" ); + + window->glDrawCallback = callback; + window->glDrawData = userdata; + + __END__; +} + +void icvSetOpenGlCleanCallback(const char* name, CvOpenGlCleanCallback callback, void* userdata) +{ + CV_FUNCNAME( "icvSetOpenGlCleanCallback" ); + + __BEGIN__; + + CvWindow* window; + + if (!name) + CV_ERROR(CV_StsNullPtr, "NULL name string"); + + window = icvFindWindowByName(name); + if (!window) + EXIT; + + if (window->glCleanCallback) + window->glCleanCallback(window->glCleanData); + + window->glCleanCallback = callback; + window->glCleanData = userdata; + + __END__; +} + +#endif // HAVE_OPENGL + +static void icvRemoveWindow( CvWindow* window ) +{ + CvTrackbar* trackbar = NULL; + RECT wrect={0,0,0,0}; + +#ifdef HAVE_OPENGL + if (window->useGl) + { + wglMakeCurrent(window->dc, window->hGLRC); + + if (window->glCleanCallback) + { + window->glCleanCallback(window->glCleanData); + window->glCleanCallback = 0; + window->glCleanData = 0; + } + + releaseGlContext(window); + } +#endif + + if( window->frame ) + GetWindowRect( window->frame, &wrect ); + if( window->name ) + icvSaveWindowPos( window->name, cvRect(wrect.left, wrect.top, + wrect.right-wrect.left, wrect.bottom-wrect.top) ); + + if( window->hwnd ) + icvSetWindowLongPtr( window->hwnd, CV_USERDATA, 0 ); + if( window->frame ) + icvSetWindowLongPtr( window->frame, CV_USERDATA, 0 ); + + if( window->toolbar.toolbar ) + icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, 0); + + if( window->prev ) + window->prev->next = window->next; + else + hg_windows = window->next; + + if( window->next ) + window->next->prev = window->prev; + + window->prev = window->next = 0; + + if( window->dc && window->image ) + DeleteObject(SelectObject(window->dc,window->image)); + + if( window->dc ) + DeleteDC(window->dc); + + for( trackbar = window->toolbar.first; trackbar != 0; ) + { + CvTrackbar* next = trackbar->next; + if( trackbar->hwnd ) + { + icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, 0 ); + cvFree( &trackbar ); + } + trackbar = next; + } + + cvFree( &window ); +} + + +CV_IMPL void cvDestroyWindow( const char* name ) +{ + CV_FUNCNAME( "cvDestroyWindow" ); + + __BEGIN__; + + CvWindow* window; + HWND mainhWnd; + + if(!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if( !window ) + EXIT; + + mainhWnd = window->frame; + + SendMessage(window->hwnd, WM_CLOSE, 0, 0); + SendMessage( mainhWnd, WM_CLOSE, 0, 0); + // Do NOT call _remove_window -- CvWindow list will be updated automatically ... + + __END__; +} + + +static void icvScreenToClient( HWND hwnd, RECT* rect ) +{ + POINT p; + p.x = rect->left; + p.y = rect->top; + ScreenToClient(hwnd, &p); + OffsetRect( rect, p.x - rect->left, p.y - rect->top ); +} + + +/* Calculatess the window coordinates relative to the upper left corner of the mainhWnd window */ +static RECT icvCalcWindowRect( CvWindow* window ) +{ + const int gutter = 1; + RECT crect, trect, rect; + + assert(window); + + GetClientRect(window->frame, &crect); + if(window->toolbar.toolbar) + { + GetWindowRect(window->toolbar.toolbar, &trect); + icvScreenToClient(window->frame, &trect); + SubtractRect( &rect, &crect, &trect); + } + else + rect = crect; + + rect.top += gutter; + rect.left += gutter; + rect.bottom -= gutter; + rect.right -= gutter; + + return rect; +} + +// returns TRUE if there is a problem such as ERROR_IO_PENDING. +static bool icvGetBitmapData( CvWindow* window, SIZE* size, int* channels, void** data ) +{ + BITMAP bmp; + GdiFlush(); + HGDIOBJ h = GetCurrentObject( window->dc, OBJ_BITMAP ); + if( size ) + size->cx = size->cy = 0; + if( data ) + *data = 0; + + if (h == NULL) + return true; + if (GetObject(h, sizeof(bmp), &bmp) == 0) + return true; + + if( size ) + { + size->cx = abs(bmp.bmWidth); + size->cy = abs(bmp.bmHeight); + } + + if( channels ) + *channels = bmp.bmBitsPixel/8; + + if( data ) + *data = bmp.bmBits; + + return false; +} + + +static void icvUpdateWindowPos( CvWindow* window ) +{ + RECT rect; + assert(window); + + if( (window->flags & CV_WINDOW_AUTOSIZE) && window->image ) + { + int i; + SIZE size = {0,0}; + icvGetBitmapData( window, &size, 0, 0 ); + + // Repeat two times because after the first resizing of the mainhWnd window + // toolbar may resize too + for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++) + { + RECT rmw, rw = icvCalcWindowRect(window ); + MoveWindow(window->hwnd, rw.left, rw.top, + rw.right - rw.left + 1, rw.bottom - rw.top + 1, FALSE); + GetClientRect(window->hwnd, &rw); + GetWindowRect(window->frame, &rmw); + // Resize the mainhWnd window in order to make the bitmap fit into the child window + MoveWindow(window->frame, rmw.left, rmw.top, + rmw.right - rmw.left + size.cx - rw.right + rw.left, + rmw.bottom - rmw.top + size.cy - rw.bottom + rw.top, TRUE ); + } + } + + rect = icvCalcWindowRect(window); + MoveWindow(window->hwnd, rect.left, rect.top, + rect.right - rect.left + 1, + rect.bottom - rect.top + 1, TRUE ); +} + +CV_IMPL void +cvShowImage( const char* name, const CvArr* arr ) +{ + CV_FUNCNAME( "cvShowImage" ); + + __BEGIN__; + + CvWindow* window; + SIZE size = { 0, 0 }; + int channels = 0; + void* dst_ptr = 0; + const int channels0 = 3; + int origin = 0; + CvMat stub, dst, *image; + bool changed_size = false; // philipg + + if( !name ) + CV_ERROR( CV_StsNullPtr, "NULL name" ); + + window = icvFindWindowByName(name); + if(!window) + { + #ifndef HAVE_OPENGL + cvNamedWindow(name, CV_WINDOW_AUTOSIZE); + #else + cvNamedWindow(name, CV_WINDOW_AUTOSIZE | CV_WINDOW_OPENGL); + #endif + + window = icvFindWindowByName(name); + } + + if( !window || !arr ) + EXIT; // keep silence here. + + if( CV_IS_IMAGE_HDR( arr )) + origin = ((IplImage*)arr)->origin; + + CV_CALL( image = cvGetMat( arr, &stub )); + +#ifdef HAVE_OPENGL + if (window->useGl) + { + cv::Mat im(image); + cv::imshow(name, im); + return; + } +#endif + + if (window->image) + // if there is something wrong with these system calls, we cannot display image... + if (icvGetBitmapData( window, &size, &channels, &dst_ptr )) + return; + + if( size.cx != image->width || size.cy != image->height || channels != channels0 ) + { + changed_size = true; + + uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)]; + BITMAPINFO* binfo = (BITMAPINFO*)buffer; + + DeleteObject( SelectObject( window->dc, window->image )); + window->image = 0; + + size.cx = image->width; + size.cy = image->height; + channels = channels0; + + FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 ); + + window->image = SelectObject( window->dc, CreateDIBSection(window->dc, binfo, + DIB_RGB_COLORS, &dst_ptr, 0, 0)); + } + + cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3, + dst_ptr, (size.cx * channels + 3) & -4 ); + cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 ); + + // ony resize window if needed + if (changed_size) + icvUpdateWindowPos(window); + InvalidateRect(window->hwnd, 0, 0); + // philipg: this is not needed and just slows things down +// UpdateWindow(window->hwnd); + + __END__; +} + +#if 0 +CV_IMPL void +cvShowImageHWND(HWND w_hWnd, const CvArr* arr) +{ + CV_FUNCNAME( "cvShowImageHWND" ); + + __BEGIN__; + + SIZE size = { 0, 0 }; + int channels = 0; + void* dst_ptr = 0; + const int channels0 = 3; + int origin = 0; + CvMat stub, dst, *image; + bool changed_size = false; + BITMAPINFO tempbinfo; + HDC hdc = NULL; + + if( !arr ) + EXIT; + if( !w_hWnd ) + EXIT; + + hdc = GetDC(w_hWnd); + + if( CV_IS_IMAGE_HDR( arr ) ) + origin = ((IplImage*)arr)->origin; + + CV_CALL( image = cvGetMat( arr, &stub ) ); + + if ( hdc ) + { + //GetBitmapData + BITMAP bmp; + GdiFlush(); + HGDIOBJ h = GetCurrentObject( hdc, OBJ_BITMAP ); + + if (h == NULL) + EXIT; + if (GetObject(h, sizeof(bmp), &bmp) == 0) //GetObject(): returns size of object, 0 if error + EXIT; + + channels = bmp.bmBitsPixel/8; + dst_ptr = bmp.bmBits; + } + + if( size.cx != image->width || size.cy != image->height || channels != channels0 ) + { + changed_size = true; + + uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)]; + BITMAPINFO* binfo = (BITMAPINFO*)buffer; + + BOOL bDeleteObj = DeleteObject(GetCurrentObject(hdc, OBJ_BITMAP)); + CV_Assert( FALSE != bDeleteObj ); + + size.cx = image->width; + size.cy = image->height; + channels = channels0; + + FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 ); + + SelectObject( hdc, CreateDIBSection( hdc, binfo, DIB_RGB_COLORS, &dst_ptr, 0, 0)); + } + + cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3, dst_ptr, (size.cx * channels + 3) & -4 ); + cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 ); + + // Image stretching to fit the window + RECT rect; + GetClientRect(w_hWnd, &rect); + StretchDIBits( hdc, 0, 0, rect.right, rect.bottom, 0, 0, image->width, image->height, dst_ptr, &tempbinfo, DIB_RGB_COLORS, SRCCOPY ); + + // ony resize window if needed + InvalidateRect(w_hWnd, 0, 0); + + __END__; +} +#endif + +CV_IMPL void cvResizeWindow(const char* name, int width, int height ) +{ + CV_FUNCNAME( "cvResizeWindow" ); + + __BEGIN__; + + int i; + CvWindow* window; + RECT rmw, rw, rect; + + if( !name ) + CV_ERROR( CV_StsNullPtr, "NULL name" ); + + window = icvFindWindowByName(name); + if(!window) + EXIT; + + // Repeat two times because after the first resizing of the mainhWnd window + // toolbar may resize too + for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++) + { + rw = icvCalcWindowRect(window); + MoveWindow(window->hwnd, rw.left, rw.top, + rw.right - rw.left + 1, rw.bottom - rw.top + 1, FALSE); + GetClientRect(window->hwnd, &rw); + GetWindowRect(window->frame, &rmw); + // Resize the mainhWnd window in order to make the bitmap fit into the child window + MoveWindow(window->frame, rmw.left, rmw.top, + rmw.right - rmw.left + width - rw.right + rw.left, + rmw.bottom - rmw.top + height - rw.bottom + rw.top, TRUE); + } + + rect = icvCalcWindowRect(window); + MoveWindow(window->hwnd, rect.left, rect.top, + rect.right - rect.left + 1, rect.bottom - rect.top + 1, TRUE); + + __END__; +} + + +CV_IMPL void cvMoveWindow( const char* name, int x, int y ) +{ + CV_FUNCNAME( "cvMoveWindow" ); + + __BEGIN__; + + CvWindow* window; + RECT rect; + + if( !name ) + CV_ERROR( CV_StsNullPtr, "NULL name" ); + + window = icvFindWindowByName(name); + if(!window) + EXIT; + + GetWindowRect( window->frame, &rect ); + MoveWindow( window->frame, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE); + + __END__; +} + + +static LRESULT CALLBACK +MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + CvWindow* window = icvWindowByHWND( hwnd ); + if( !window ) + return DefWindowProc(hwnd, uMsg, wParam, lParam); + + switch(uMsg) + { + case WM_DESTROY: + + icvRemoveWindow(window); + // Do nothing!!! + //PostQuitMessage(0); + break; + + case WM_GETMINMAXINFO: + if( !(window->flags & CV_WINDOW_AUTOSIZE) ) + { + MINMAXINFO* minmax = (MINMAXINFO*)lParam; + RECT rect; + LRESULT retval = DefWindowProc(hwnd, uMsg, wParam, lParam); + + minmax->ptMinTrackSize.y = 100; + minmax->ptMinTrackSize.x = 100; + + if( window->toolbar.first ) + { + GetWindowRect( window->toolbar.first->hwnd, &rect ); + minmax->ptMinTrackSize.y += window->toolbar.rows*(rect.bottom - rect.top); + minmax->ptMinTrackSize.x = MAX(rect.right - rect.left + HG_BUDDY_WIDTH, HG_BUDDY_WIDTH*2); + } + return retval; + } + break; + + case WM_WINDOWPOSCHANGED: + { + WINDOWPOS* pos = (WINDOWPOS*)lParam; + + // Update the toolbar pos/size + if(window->toolbar.toolbar) + { + RECT rect; + GetWindowRect(window->toolbar.toolbar, &rect); + MoveWindow(window->toolbar.toolbar, 0, 0, pos->cx, rect.bottom - rect.top, TRUE); + } + + if(!(window->flags & CV_WINDOW_AUTOSIZE)) + icvUpdateWindowPos(window); + + break; + } + + case WM_WINDOWPOSCHANGING: + { + // Snap window to screen edges with multi-monitor support. // Adi Shavit + LPWINDOWPOS pos = (LPWINDOWPOS)lParam; + + RECT rect; + GetWindowRect(window->frame, &rect); + + HMONITOR hMonitor; + hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST); + + MONITORINFO mi; + mi.cbSize = sizeof(mi); + GetMonitorInfo(hMonitor, &mi); + + const int SNAP_DISTANCE = 15; + + if (abs(pos->x - mi.rcMonitor.left) <= SNAP_DISTANCE) + pos->x = mi.rcMonitor.left; // snap to left edge + else + if (abs(pos->x + pos->cx - mi.rcMonitor.right) <= SNAP_DISTANCE) + pos->x = mi.rcMonitor.right - pos->cx; // snap to right edge + + if (abs(pos->y - mi.rcMonitor.top) <= SNAP_DISTANCE) + pos->y = mi.rcMonitor.top; // snap to top edge + else + if (abs(pos->y + pos->cy - mi.rcMonitor.bottom) <= SNAP_DISTANCE) + pos->y = mi.rcMonitor.bottom - pos->cy; // snap to bottom edge + } + + case WM_ACTIVATE: + if(LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) + SetFocus(window->hwnd); + break; + + case WM_ERASEBKGND: + { + RECT cr, tr, wrc; + HRGN rgn, rgn1, rgn2; + int ret; + HDC hdc = (HDC)wParam; + GetWindowRect(window->hwnd, &cr); + icvScreenToClient(window->frame, &cr); + if(window->toolbar.toolbar) + { + GetWindowRect(window->toolbar.toolbar, &tr); + icvScreenToClient(window->frame, &tr); + } + else + tr.left = tr.top = tr.right = tr.bottom = 0; + + GetClientRect(window->frame, &wrc); + + rgn = CreateRectRgn(0, 0, wrc.right, wrc.bottom); + rgn1 = CreateRectRgn(cr.left, cr.top, cr.right, cr.bottom); + rgn2 = CreateRectRgn(tr.left, tr.top, tr.right, tr.bottom); + ret = CombineRgn(rgn, rgn, rgn1, RGN_DIFF); + ret = CombineRgn(rgn, rgn, rgn2, RGN_DIFF); + + if(ret != NULLREGION && ret != ERROR) + FillRgn(hdc, rgn, (HBRUSH)icvGetClassLongPtr(hwnd, CV_HBRBACKGROUND)); + + DeleteObject(rgn); + DeleteObject(rgn1); + DeleteObject(rgn2); + } + return 1; + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + + +static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + CvWindow* window = icvWindowByHWND(hwnd); + if( !window ) + // This window is not mentioned in HighGUI storage + // Actually, this should be error except for the case of calls to CreateWindow + return DefWindowProc(hwnd, uMsg, wParam, lParam); + + // Process the message + switch(uMsg) + { + case WM_WINDOWPOSCHANGING: + { + LPWINDOWPOS pos = (LPWINDOWPOS)lParam; + RECT rect = icvCalcWindowRect(window); + pos->x = rect.left; + pos->y = rect.top; + pos->cx = rect.right - rect.left + 1; + pos->cy = rect.bottom - rect.top + 1; + } + break; + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_MOUSEMOVE: + if( window->on_mouse ) + { + POINT pt; + RECT rect; + SIZE size = {0,0}; + + int flags = (wParam & MK_LBUTTON ? CV_EVENT_FLAG_LBUTTON : 0)| + (wParam & MK_RBUTTON ? CV_EVENT_FLAG_RBUTTON : 0)| + (wParam & MK_MBUTTON ? CV_EVENT_FLAG_MBUTTON : 0)| + (wParam & MK_CONTROL ? CV_EVENT_FLAG_CTRLKEY : 0)| + (wParam & MK_SHIFT ? CV_EVENT_FLAG_SHIFTKEY : 0)| + (GetKeyState(VK_MENU) < 0 ? CV_EVENT_FLAG_ALTKEY : 0); + int event = uMsg == WM_LBUTTONDOWN ? CV_EVENT_LBUTTONDOWN : + uMsg == WM_RBUTTONDOWN ? CV_EVENT_RBUTTONDOWN : + uMsg == WM_MBUTTONDOWN ? CV_EVENT_MBUTTONDOWN : + uMsg == WM_LBUTTONUP ? CV_EVENT_LBUTTONUP : + uMsg == WM_RBUTTONUP ? CV_EVENT_RBUTTONUP : + uMsg == WM_MBUTTONUP ? CV_EVENT_MBUTTONUP : + uMsg == WM_LBUTTONDBLCLK ? CV_EVENT_LBUTTONDBLCLK : + uMsg == WM_RBUTTONDBLCLK ? CV_EVENT_RBUTTONDBLCLK : + uMsg == WM_MBUTTONDBLCLK ? CV_EVENT_MBUTTONDBLCLK : + CV_EVENT_MOUSEMOVE; + if( uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN ) + SetCapture( hwnd ); + if( uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP || uMsg == WM_MBUTTONUP ) + ReleaseCapture(); + + pt.x = LOWORD( lParam ); + pt.y = HIWORD( lParam ); + + GetClientRect( window->hwnd, &rect ); + icvGetBitmapData( window, &size, 0, 0 ); + + window->on_mouse( event, pt.x*size.cx/MAX(rect.right - rect.left,1), + pt.y*size.cy/MAX(rect.bottom - rect.top,1), flags, + window->on_mouse_param ); + } + break; + + case WM_PAINT: + if(window->image != 0) + { + int nchannels = 3; + SIZE size = {0,0}; + PAINTSTRUCT paint; + HDC hdc; + RGBQUAD table[256]; + + // Determine the bitmap's dimensions + icvGetBitmapData( window, &size, &nchannels, 0 ); + + hdc = BeginPaint(hwnd, &paint); + SetStretchBltMode(hdc, COLORONCOLOR); + + if( nchannels == 1 ) + { + int i; + for(i = 0; i < 256; i++) + { + table[i].rgbBlue = (unsigned char)i; + table[i].rgbGreen = (unsigned char)i; + table[i].rgbRed = (unsigned char)i; + } + SetDIBColorTable(window->dc, 0, 255, table); + } + + if(window->flags & CV_WINDOW_AUTOSIZE) + { + BitBlt( hdc, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY ); + } + else + { + RECT rect; + GetClientRect(window->hwnd, &rect); + StretchBlt( hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, + window->dc, 0, 0, size.cx, size.cy, SRCCOPY ); + } + //DeleteDC(hdc); + EndPaint(hwnd, &paint); + } +#ifdef HAVE_OPENGL + else if(window->useGl) + { + drawGl(window); + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } +#endif + else + { + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + return 0; + + case WM_ERASEBKGND: + if(window->image) + return 0; + break; + + case WM_DESTROY: + + icvRemoveWindow(window); + // Do nothing!!! + //PostQuitMessage(0); + break; + + case WM_SETCURSOR: + SetCursor((HCURSOR)icvGetClassLongPtr(hwnd, CV_HCURSOR)); + return 0; + + case WM_KEYDOWN: + window->last_key = (int)wParam; + return 0; + + case WM_SIZE: + window->width = LOWORD(lParam); + window->height = HIWORD(lParam); + +#ifdef HAVE_OPENGL + if (window->useGl) + resizeGl(window); +#endif + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + + +static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + LRESULT ret; + + if( hg_on_preprocess ) + { + int was_processed = 0; + int rethg = hg_on_preprocess(hwnd, uMsg, wParam, lParam, &was_processed); + if( was_processed ) + return rethg; + } + ret = HighGUIProc(hwnd, uMsg, wParam, lParam); + + if(hg_on_postprocess) + { + int was_processed = 0; + int rethg = hg_on_postprocess(hwnd, uMsg, wParam, lParam, &was_processed); + if( was_processed ) + return rethg; + } + + return ret; +} + + +static void icvUpdateTrackbar( CvTrackbar* trackbar, int pos ) +{ + const int max_name_len = 10; + const char* suffix = ""; + char pos_text[32]; + int name_len; + + if( trackbar->data ) + *trackbar->data = pos; + + if( trackbar->pos != pos ) + { + trackbar->pos = pos; + if( trackbar->notify2 ) + trackbar->notify2(pos, trackbar->userdata); + if( trackbar->notify ) + trackbar->notify(pos); + + name_len = (int)strlen(trackbar->name); + + if( name_len > max_name_len ) + { + int start_len = max_name_len*2/3; + int end_len = max_name_len - start_len - 2; + memcpy( pos_text, trackbar->name, start_len ); + memcpy( pos_text + start_len, "...", 3 ); + memcpy( pos_text + start_len + 3, trackbar->name + name_len - end_len, end_len + 1 ); + } + else + { + memcpy( pos_text, trackbar->name, name_len + 1); + } + + sprintf( pos_text + strlen(pos_text), "%s: %d\n", suffix, pos ); + SetWindowText( trackbar->buddy, pos_text ); + } +} + + +static LRESULT CALLBACK HGToolbarProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + CvWindow* window = icvWindowByHWND( hwnd ); + if(!window) + return DefWindowProc(hwnd, uMsg, wParam, lParam); + + // Control messages processing + switch(uMsg) + { + // Slider processing + case WM_HSCROLL: + { + HWND slider = (HWND)lParam; + int pos = (int)SendMessage(slider, TBM_GETPOS, 0, 0); + CvTrackbar* trackbar = icvTrackbarByHWND( slider ); + + if( trackbar ) + { + if( trackbar->pos != pos ) + icvUpdateTrackbar( trackbar, pos ); + } + + SetFocus( window->hwnd ); + return 0; + } + + case WM_NCCALCSIZE: + { + LRESULT ret = CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam); + int rows = (int)SendMessage(hwnd, TB_GETROWS, 0, 0); + + if(window->toolbar.rows != rows) + { + SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0); + CvTrackbar* trackbar = window->toolbar.first; + + for( ; trackbar != 0; trackbar = trackbar->next ) + { + RECT rect; + SendMessage(window->toolbar.toolbar, TB_GETITEMRECT, + (WPARAM)trackbar->id, (LPARAM)&rect); + MoveWindow(trackbar->hwnd, rect.left + HG_BUDDY_WIDTH, rect.top, + rect.right - rect.left - HG_BUDDY_WIDTH, + rect.bottom - rect.top, FALSE); + MoveWindow(trackbar->buddy, rect.left, rect.top, + HG_BUDDY_WIDTH, rect.bottom - rect.top, FALSE); + } + window->toolbar.rows = rows; + } + return ret; + } + } + + return CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam); +} + + +CV_IMPL void +cvDestroyAllWindows(void) +{ + CvWindow* window = hg_windows; + + while( window ) + { + HWND mainhWnd = window->frame; + HWND hwnd = window->hwnd; + window = window->next; + + SendMessage( hwnd, WM_CLOSE, 0, 0 ); + SendMessage( mainhWnd, WM_CLOSE, 0, 0 ); + } +} + + +CV_IMPL int +cvWaitKey( int delay ) +{ + int time0 = GetTickCount(); + + for(;;) + { + CvWindow* window; + MSG message; + int is_processed = 0; + + if( (delay > 0 && abs((int)(GetTickCount() - time0)) >= delay) || hg_windows == 0 ) + return -1; + + if( delay <= 0 ) + GetMessage(&message, 0, 0, 0); + else if( PeekMessage(&message, 0, 0, 0, PM_REMOVE) == FALSE ) + { + Sleep(1); + continue; + } + + for( window = hg_windows; window != 0 && is_processed == 0; window = window->next ) + { + if( window->hwnd == message.hwnd || window->frame == message.hwnd ) + { + is_processed = 1; + switch(message.message) + { + case WM_DESTROY: + case WM_CHAR: + DispatchMessage(&message); + return (int)message.wParam; + + case WM_SYSKEYDOWN: + if( message.wParam == VK_F10 ) + { + is_processed = 1; + return (int)(message.wParam << 16); + } + break; + + case WM_KEYDOWN: + TranslateMessage(&message); + if( (message.wParam >= VK_F1 && message.wParam <= VK_F24) || + message.wParam == VK_HOME || message.wParam == VK_END || + message.wParam == VK_UP || message.wParam == VK_DOWN || + message.wParam == VK_LEFT || message.wParam == VK_RIGHT || + message.wParam == VK_INSERT || message.wParam == VK_DELETE || + message.wParam == VK_PRIOR || message.wParam == VK_NEXT ) + { + DispatchMessage(&message); + is_processed = 1; + return (int)(message.wParam << 16); + } + default: + DispatchMessage(&message); + is_processed = 1; + break; + } + } + } + + if( !is_processed ) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + } +} + + +static CvTrackbar* +icvFindTrackbarByName( const CvWindow* window, const char* name ) +{ + CvTrackbar* trackbar = window->toolbar.first; + + for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next ) + ; + + return trackbar; +} + + +typedef struct +{ + UINT cbSize; + DWORD dwMask; + int idCommand; + int iImage; + BYTE fsState; + BYTE fsStyle; + WORD cx; + DWORD lParam; + LPSTR pszText; + int cchText; +} +ButtonInfo; + + +static int +icvCreateTrackbar( const char* trackbar_name, const char* window_name, + int* val, int count, CvTrackbarCallback on_notify, + CvTrackbarCallback2 on_notify2, void* userdata ) +{ + int result = 0; + + CV_FUNCNAME( "icvCreateTrackbar" ); + + __BEGIN__; + + char slider_name[32]; + CvWindow* window = 0; + CvTrackbar* trackbar = 0; + int pos = 0; + + if( !window_name || !trackbar_name ) + CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" ); + + if( count <= 0 ) + CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" ); + + window = icvFindWindowByName(window_name); + if( !window ) + EXIT; + + trackbar = icvFindTrackbarByName(window,trackbar_name); + if( !trackbar ) + { + TBBUTTON tbs; + ButtonInfo tbis; + RECT rect; + int bcount; + int len = (int)strlen( trackbar_name ); + + // create toolbar if it is not created yet + if( !window->toolbar.toolbar ) + { + const int default_height = 30; + + window->toolbar.toolbar = CreateToolbarEx( + window->frame, WS_CHILD | CCS_TOP | TBSTYLE_WRAPABLE, + 1, 0, 0, 0, 0, 0, 16, 20, 16, 16, sizeof(TBBUTTON)); + GetClientRect(window->frame, &rect); + MoveWindow( window->toolbar.toolbar, 0, 0, + rect.right - rect.left, default_height, TRUE); + SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0); + ShowWindow(window->toolbar.toolbar, SW_SHOW); + + window->toolbar.first = 0; + window->toolbar.pos = 0; + window->toolbar.rows = 0; + window->toolbar.toolBarProc = + (WNDPROC)icvGetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC); + + icvUpdateWindowPos(window); + + // Subclassing from toolbar + icvSetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC, HGToolbarProc); + icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, window); + } + + /* Retrieve current buttons count */ + bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0); + + if(bcount > 1) + { + /* If this is not the first button then we need to + separate it from the previous one */ + tbs.iBitmap = 0; + tbs.idCommand = bcount; // Set button id to it's number + tbs.iString = 0; + tbs.fsStyle = TBSTYLE_SEP; + tbs.fsState = TBSTATE_ENABLED; + SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs); + + // Retrieve current buttons count + bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0); + } + + /* Add a button which we're going to cover with the slider */ + tbs.iBitmap = 0; + tbs.idCommand = bcount; // Set button id to it's number + tbs.fsState = TBSTATE_ENABLED; +#if 0/*!defined WIN64 && !defined EM64T*/ + tbs.fsStyle = 0; + tbs.iString = 0; +#else + +#ifndef TBSTYLE_AUTOSIZE +#define TBSTYLE_AUTOSIZE 0x0010 +#endif + +#ifndef TBSTYLE_GROUP +#define TBSTYLE_GROUP 0x0004 +#endif + //tbs.fsStyle = TBSTYLE_AUTOSIZE; + tbs.fsStyle = TBSTYLE_GROUP; + tbs.iString = (INT_PTR)trackbar_text; +#endif + SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs); + + /* Adjust button size to the slider */ + tbis.cbSize = sizeof(tbis); + tbis.dwMask = TBIF_SIZE; + + GetClientRect(window->hwnd, &rect); + tbis.cx = (unsigned short)(rect.right - rect.left); + + SendMessage(window->toolbar.toolbar, TB_SETBUTTONINFO, + (WPARAM)tbs.idCommand, (LPARAM)&tbis); + + /* Get button pos */ + SendMessage(window->toolbar.toolbar, TB_GETITEMRECT, + (WPARAM)tbs.idCommand, (LPARAM)&rect); + + /* Create a slider */ + trackbar = (CvTrackbar*)cvAlloc( sizeof(CvTrackbar) + len + 1 ); + trackbar->signature = CV_TRACKBAR_MAGIC_VAL; + trackbar->notify = 0; + trackbar->notify2 = 0; + trackbar->parent = window; + trackbar->pos = 0; + trackbar->data = 0; + trackbar->id = bcount; + trackbar->next = window->toolbar.first; + trackbar->name = (char*)(trackbar + 1); + memcpy( trackbar->name, trackbar_name, len + 1 ); + window->toolbar.first = trackbar; + + sprintf(slider_name, "Trackbar%p", val); + trackbar->hwnd = CreateWindowEx(0, TRACKBAR_CLASS, slider_name, + WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS | + TBS_FIXEDLENGTH | TBS_HORZ | TBS_BOTTOM, + rect.left + HG_BUDDY_WIDTH, rect.top, + rect.right - rect.left - HG_BUDDY_WIDTH, + rect.bottom - rect.top, window->toolbar.toolbar, + (HMENU)(size_t)bcount, hg_hinstance, 0); + + sprintf(slider_name,"Buddy%p", val); + trackbar->buddy = CreateWindowEx(0, "STATIC", slider_name, + WS_CHILD | SS_RIGHT, + rect.left, rect.top, + HG_BUDDY_WIDTH, rect.bottom - rect.top, + window->toolbar.toolbar, 0, hg_hinstance, 0); + + icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, trackbar ); + + /* Minimize the number of rows */ + SendMessage( window->toolbar.toolbar, TB_SETROWS, + MAKEWPARAM(1, FALSE), (LPARAM)&rect ); + } + else + { + trackbar->data = 0; + trackbar->notify = 0; + trackbar->notify2 = 0; + } + + trackbar->maxval = count; + + /* Adjust slider parameters */ + SendMessage(trackbar->hwnd, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, count)); + SendMessage(trackbar->hwnd, TBM_SETTICFREQ, (WPARAM)1, (LPARAM)0 ); + if( val ) + pos = *val; + + SendMessage(trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos ); + SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0); + + trackbar->pos = -1; + icvUpdateTrackbar( trackbar, pos ); + ShowWindow( trackbar->buddy, SW_SHOW ); + ShowWindow( trackbar->hwnd, SW_SHOW ); + + trackbar->notify = on_notify; + trackbar->notify2 = on_notify2; + trackbar->userdata = userdata; + trackbar->data = val; + + /* Resize the window to reflect the toolbar resizing*/ + icvUpdateWindowPos(window); + + result = 1; + + __END__; + + return result; +} + +CV_IMPL int +cvCreateTrackbar( const char* trackbar_name, const char* window_name, + int* val, int count, CvTrackbarCallback on_notify ) +{ + return icvCreateTrackbar( trackbar_name, window_name, val, count, + on_notify, 0, 0 ); +} + +CV_IMPL int +cvCreateTrackbar2( const char* trackbar_name, const char* window_name, + int* val, int count, CvTrackbarCallback2 on_notify2, + void* userdata ) +{ + return icvCreateTrackbar( trackbar_name, window_name, val, count, + 0, on_notify2, userdata ); +} + +CV_IMPL void +cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param ) +{ + CV_FUNCNAME( "cvSetMouseCallback" ); + + __BEGIN__; + + CvWindow* window = 0; + + if( !window_name ) + CV_ERROR( CV_StsNullPtr, "NULL window name" ); + + window = icvFindWindowByName(window_name); + if( !window ) + EXIT; + + window->on_mouse = on_mouse; + window->on_mouse_param = param; + + __END__; +} + + +CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name ) +{ + int pos = -1; + + CV_FUNCNAME( "cvGetTrackbarPos" ); + + __BEGIN__; + + CvWindow* window; + CvTrackbar* trackbar = 0; + + if( trackbar_name == 0 || window_name == 0 ) + CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" ); + + window = icvFindWindowByName( window_name ); + if( window ) + trackbar = icvFindTrackbarByName( window, trackbar_name ); + + if( trackbar ) + pos = trackbar->pos; + + __END__; + + return pos; +} + + +CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos ) +{ + CV_FUNCNAME( "cvSetTrackbarPos" ); + + __BEGIN__; + + CvWindow* window; + CvTrackbar* trackbar = 0; + + if( trackbar_name == 0 || window_name == 0 ) + CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" ); + + window = icvFindWindowByName( window_name ); + if( window ) + trackbar = icvFindTrackbarByName( window, trackbar_name ); + + if( trackbar ) + { + if( pos < 0 ) + pos = 0; + + if( pos > trackbar->maxval ) + pos = trackbar->maxval; + + SendMessage( trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos ); + icvUpdateTrackbar( trackbar, pos ); + } + + __END__; +} + + +CV_IMPL void* cvGetWindowHandle( const char* window_name ) +{ + void* hwnd = 0; + + CV_FUNCNAME( "cvGetWindowHandle" ); + + __BEGIN__; + + CvWindow* window; + + if( window_name == 0 ) + CV_ERROR( CV_StsNullPtr, "NULL window name" ); + + window = icvFindWindowByName( window_name ); + if( window ) + hwnd = (void*)window->hwnd; + + __END__; + + return hwnd; +} + + +CV_IMPL const char* cvGetWindowName( void* window_handle ) +{ + const char* window_name = ""; + + CV_FUNCNAME( "cvGetWindowName" ); + + __BEGIN__; + + CvWindow* window; + + if( window_handle == 0 ) + CV_ERROR( CV_StsNullPtr, "NULL window" ); + + window = icvWindowByHWND( (HWND)window_handle ); + if( window ) + window_name = window->name; + + __END__; + + return window_name; +} + + +CV_IMPL void +cvSetPreprocessFuncWin32_(const void* callback) +{ + hg_on_preprocess = (CvWin32WindowCallback)callback; +} + +CV_IMPL void +cvSetPostprocessFuncWin32_(const void* callback) +{ + hg_on_postprocess = (CvWin32WindowCallback)callback; +} + +#endif //WIN32 diff --git a/highgui/test/test_drawing.cpp b/highgui/test/test_drawing.cpp new file mode 100644 index 0000000..09590b3 --- /dev/null +++ b/highgui/test/test_drawing.cpp @@ -0,0 +1,446 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" +#include "opencv2/highgui/highgui.hpp" + +using namespace cv; + +//#define DRAW_TEST_IMAGE + +class CV_DrawingTest : public cvtest::BaseTest +{ +public: + CV_DrawingTest(){} +protected: + void run( int ); + virtual void draw( Mat& img ) = 0; + virtual int checkLineIterator( Mat& img) = 0; +}; + +void CV_DrawingTest::run( int ) +{ + Mat testImg, valImg; + const string fname = "drawing/image.jpg"; + string path = ts->get_data_path(), filename; + filename = path + fname; + + draw( testImg ); + + valImg = imread( filename ); + if( valImg.empty() ) + { + imwrite( filename, testImg ); + //ts->printf( ts->LOG, "test image can not be read"); + //ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); + } + else + { + float err = (float)norm( testImg, valImg, CV_RELATIVE_L1 ); + float Eps = 0.9f; + if( err > Eps) + { + ts->printf( ts->LOG, "CV_RELATIVE_L1 between testImg and valImg is equal %f (larger than %f)\n", err, Eps ); + ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); + } + else + { + ts->set_failed_test_info(checkLineIterator( testImg )); + } + } + ts->set_failed_test_info(cvtest::TS::OK); +} + +class CV_DrawingTest_CPP : public CV_DrawingTest +{ +public: + CV_DrawingTest_CPP() {} +protected: + virtual void draw( Mat& img ); + virtual int checkLineIterator( Mat& img); +}; + +void CV_DrawingTest_CPP::draw( Mat& img ) +{ + Size imgSize( 600, 400 ); + img.create( imgSize, CV_8UC3 ); + + vector polyline(4); + polyline[0] = Point(0, 0); + polyline[1] = Point(imgSize.width, 0); + polyline[2] = Point(imgSize.width, imgSize.height); + polyline[3] = Point(0, imgSize.height); + const Point* pts = &polyline[0]; + int n = (int)polyline.size(); + fillPoly( img, &pts, &n, 1, Scalar::all(255) ); + + Point p1(1,1), p2(3,3); + if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) ) + circle( img, Point(300,100), 40, Scalar(0,0,255), 3 ); // draw + + p2 = Point(3,imgSize.height+1000); + if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) ) + circle( img, Point(500,300), 50, cvColorToScalar(255,CV_8UC3), 5, 8, 1 ); // draw + + p1 = Point(imgSize.width,1), p2 = Point(imgSize.width,3); + if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) ) + circle( img, Point(390,100), 10, Scalar(0,0,255), 3 ); // not draw + + p1 = Point(imgSize.width-1,1), p2 = Point(imgSize.width,3); + if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) ) + ellipse( img, Point(390,100), Size(20,30), 60, 0, 220.0, Scalar(0,200,0), 4 ); //draw + + ellipse( img, RotatedRect(Point(100,200),Size(200,100),160), Scalar(200,200,255), 5 ); + + polyline.clear(); + ellipse2Poly( Point(430,180), Size(100,150), 30, 0, 150, 20, polyline ); + pts = &polyline[0]; + n = (int)polyline.size(); + polylines( img, &pts, &n, 1, false, Scalar(0,0,150), 4, CV_AA ); + n = 0; + for( vector::const_iterator it = polyline.begin(); n < (int)polyline.size()-1; ++it, n++ ) + { + line( img, *it, *(it+1), Scalar(50,250,100)); + } + + polyline.clear(); + ellipse2Poly( Point(500,300), Size(50,80), 0, 0, 180, 10, polyline ); + pts = &polyline[0]; + n = (int)polyline.size(); + polylines( img, &pts, &n, 1, true, Scalar(100,200,100), 20 ); + fillConvexPoly( img, pts, n, Scalar(0, 80, 0) ); + + polyline.resize(8); + // external rectengular + polyline[0] = Point(0, 0); + polyline[1] = Point(80, 0); + polyline[2] = Point(80, 80); + polyline[3] = Point(0, 80); + // internal rectangular + polyline[4] = Point(20, 20); + polyline[5] = Point(60, 20); + polyline[6] = Point(60, 60); + polyline[7] = Point(20, 60); + const Point* ppts[] = {&polyline[0], &polyline[0]+4}; + int pn[] = {4, 4}; + fillPoly( img, ppts, pn, 2, Scalar(100, 100, 0), 8, 0, Point(500, 20) ); + + rectangle( img, Point(0, 300), Point(50, 398), Scalar(0,0,255) ); + + string text1 = "OpenCV"; + int baseline = 0, thickness = 3, fontFace = FONT_HERSHEY_SCRIPT_SIMPLEX; + float fontScale = 2; + Size textSize = getTextSize( text1, fontFace, fontScale, thickness, &baseline); + baseline += thickness; + Point textOrg((img.cols - textSize.width)/2, (img.rows + textSize.height)/2); + rectangle(img, textOrg + Point(0, baseline), textOrg + Point(textSize.width, -textSize.height), Scalar(0,0,255)); + line(img, textOrg + Point(0, thickness), textOrg + Point(textSize.width, thickness), Scalar(0, 0, 255)); + putText(img, text1, textOrg, fontFace, fontScale, Scalar(150,0,150), thickness, 8); + + string text2 = "abcdefghijklmnopqrstuvwxyz1234567890"; + Scalar color(200,0,0); + fontScale = 0.5, thickness = 1; + int dist = 5; + + textSize = getTextSize( text2, FONT_HERSHEY_SIMPLEX, fontScale, thickness, &baseline); + textOrg = Point(5,5)+Point(0,textSize.height+dist); + putText(img, text2, textOrg, FONT_HERSHEY_SIMPLEX, fontScale, color, thickness, CV_AA); + + fontScale = 1; + textSize = getTextSize( text2, FONT_HERSHEY_PLAIN, fontScale, thickness, &baseline); + textOrg += Point(0,textSize.height+dist); + putText(img, text2, textOrg, FONT_HERSHEY_PLAIN, fontScale, color, thickness, CV_AA); + + fontScale = 0.5; + textSize = getTextSize( text2, FONT_HERSHEY_DUPLEX, fontScale, thickness, &baseline); + textOrg += Point(0,textSize.height+dist); + putText(img, text2, textOrg, FONT_HERSHEY_DUPLEX, fontScale, color, thickness, CV_AA); + + textSize = getTextSize( text2, FONT_HERSHEY_COMPLEX, fontScale, thickness, &baseline); + textOrg += Point(0,textSize.height+dist); + putText(img, text2, textOrg, FONT_HERSHEY_COMPLEX, fontScale, color, thickness, CV_AA); + + textSize = getTextSize( text2, FONT_HERSHEY_TRIPLEX, fontScale, thickness, &baseline); + textOrg += Point(0,textSize.height+dist); + putText(img, text2, textOrg, FONT_HERSHEY_TRIPLEX, fontScale, color, thickness, CV_AA); + + fontScale = 1; + textSize = getTextSize( text2, FONT_HERSHEY_COMPLEX_SMALL, fontScale, thickness, &baseline); + textOrg += Point(0,180) + Point(0,textSize.height+dist); + putText(img, text2, textOrg, FONT_HERSHEY_COMPLEX_SMALL, fontScale, color, thickness, CV_AA); + + textSize = getTextSize( text2, FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, thickness, &baseline); + textOrg += Point(0,textSize.height+dist); + putText(img, text2, textOrg, FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, color, thickness, CV_AA); + + textSize = getTextSize( text2, FONT_HERSHEY_SCRIPT_COMPLEX, fontScale, thickness, &baseline); + textOrg += Point(0,textSize.height+dist); + putText(img, text2, textOrg, FONT_HERSHEY_SCRIPT_COMPLEX, fontScale, color, thickness, CV_AA); + + dist = 15, fontScale = 0.5; + textSize = getTextSize( text2, FONT_ITALIC, fontScale, thickness, &baseline); + textOrg += Point(0,textSize.height+dist); + putText(img, text2, textOrg, FONT_ITALIC, fontScale, color, thickness, CV_AA); +} + +int CV_DrawingTest_CPP::checkLineIterator( Mat& img ) +{ + LineIterator it( img, Point(0,300), Point(1000, 300) ); + for(int i = 0; i < it.count; ++it, i++ ) + { + Vec3b v = (Vec3b)(*(*it)) - img.at(300,i); + float err = (float)norm( v ); + if( err != 0 ) + { + ts->printf( ts->LOG, "LineIterator works incorrect" ); + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); + } + } + ts->set_failed_test_info(cvtest::TS::OK); + return 0; +} + +class CV_DrawingTest_C : public CV_DrawingTest +{ +public: + CV_DrawingTest_C() {} +protected: + virtual void draw( Mat& img ); + virtual int checkLineIterator( Mat& img); +}; + +void CV_DrawingTest_C::draw( Mat& _img ) +{ + CvSize imgSize = cvSize(600, 400); + _img.create( imgSize, CV_8UC3 ); + CvMat img = _img; + + vector polyline(4); + polyline[0] = cvPoint(0, 0); + polyline[1] = cvPoint(imgSize.width, 0); + polyline[2] = cvPoint(imgSize.width, imgSize.height); + polyline[3] = cvPoint(0, imgSize.height); + CvPoint* pts = &polyline[0]; + int n = (int)polyline.size(); + cvFillPoly( &img, &pts, &n, 1, cvScalar(255,255,255) ); + + CvPoint p1 = cvPoint(1,1), p2 = cvPoint(3,3); + if( cvClipLine(imgSize, &p1, &p2) ) + cvCircle( &img, cvPoint(300,100), 40, cvScalar(0,0,255), 3 ); // draw + + p1 = cvPoint(1,1), p2 = cvPoint(3,imgSize.height+1000); + if( cvClipLine(imgSize, &p1, &p2) ) + cvCircle( &img, cvPoint(500,300), 50, cvScalar(255,0,0), 5, 8, 1 ); // draw + + p1 = cvPoint(imgSize.width,1), p2 = cvPoint(imgSize.width,3); + if( cvClipLine(imgSize, &p1, &p2) ) + cvCircle( &img, cvPoint(390,100), 10, cvScalar(0,0,255), 3 ); // not draw + + p1 = Point(imgSize.width-1,1), p2 = Point(imgSize.width,3); + if( cvClipLine(imgSize, &p1, &p2) ) + cvEllipse( &img, cvPoint(390,100), cvSize(20,30), 60, 0, 220.0, cvScalar(0,200,0), 4 ); //draw + + CvBox2D box; + box.center.x = 100; + box.center.y = 200; + box.size.width = 200; + box.size.height = 100; + box.angle = 160; + cvEllipseBox( &img, box, Scalar(200,200,255), 5 ); + + polyline.resize(9); + pts = &polyline[0]; + n = (int)polyline.size(); + assert( cvEllipse2Poly( cvPoint(430,180), cvSize(100,150), 30, 0, 150, &polyline[0], 20 ) == n ); + cvPolyLine( &img, &pts, &n, 1, false, cvScalar(0,0,150), 4, CV_AA ); + n = 0; + for( vector::const_iterator it = polyline.begin(); n < (int)polyline.size()-1; ++it, n++ ) + { + cvLine( &img, *it, *(it+1), cvScalar(50,250,100) ); + } + + polyline.resize(19); + pts = &polyline[0]; + n = (int)polyline.size(); + assert( cvEllipse2Poly( cvPoint(500,300), cvSize(50,80), 0, 0, 180, &polyline[0], 10 ) == n ); + cvPolyLine( &img, &pts, &n, 1, true, Scalar(100,200,100), 20 ); + cvFillConvexPoly( &img, pts, n, cvScalar(0, 80, 0) ); + + polyline.resize(8); + // external rectengular + polyline[0] = cvPoint(500, 20); + polyline[1] = cvPoint(580, 20); + polyline[2] = cvPoint(580, 100); + polyline[3] = cvPoint(500, 100); + // internal rectangular + polyline[4] = cvPoint(520, 40); + polyline[5] = cvPoint(560, 40); + polyline[6] = cvPoint(560, 80); + polyline[7] = cvPoint(520, 80); + CvPoint* ppts[] = {&polyline[0], &polyline[0]+4}; + int pn[] = {4, 4}; + cvFillPoly( &img, ppts, pn, 2, cvScalar(100, 100, 0), 8, 0 ); + + cvRectangle( &img, cvPoint(0, 300), cvPoint(50, 398), cvScalar(0,0,255) ); + + string text1 = "OpenCV"; + CvFont font; + cvInitFont( &font, FONT_HERSHEY_SCRIPT_SIMPLEX, 2, 2, 0, 3 ); + int baseline = 0; + CvSize textSize; + cvGetTextSize( text1.c_str(), &font, &textSize, &baseline ); + baseline += font.thickness; + CvPoint textOrg = cvPoint((imgSize.width - textSize.width)/2, (imgSize.height + textSize.height)/2); + cvRectangle( &img, cvPoint( textOrg.x, textOrg.y + baseline), + cvPoint(textOrg.x + textSize.width, textOrg.y - textSize.height), cvScalar(0,0,255)); + cvLine( &img, cvPoint(textOrg.x, textOrg.y + font.thickness), + cvPoint(textOrg.x + textSize.width, textOrg.y + font.thickness), cvScalar(0, 0, 255)); + cvPutText( &img, text1.c_str(), textOrg, &font, cvScalar(150,0,150) ); + + int dist = 5; + string text2 = "abcdefghijklmnopqrstuvwxyz1234567890"; + CvScalar color = cvScalar(200,0,0); + cvInitFont( &font, FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 1, CV_AA ); + cvGetTextSize( text2.c_str(), &font, &textSize, &baseline ); + textOrg = cvPoint(5, 5+textSize.height+dist); + cvPutText(&img, text2.c_str(), textOrg, &font, color ); + + cvInitFont( &font, FONT_HERSHEY_PLAIN, 1, 1, 0, 1, CV_AA ); + cvGetTextSize( text2.c_str(), &font, &textSize, &baseline ); + textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist); + cvPutText(&img, text2.c_str(), textOrg, &font, color ); + + cvInitFont( &font, FONT_HERSHEY_DUPLEX, 0.5, 0.5, 0, 1, CV_AA ); + cvGetTextSize( text2.c_str(), &font, &textSize, &baseline ); + textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist); + cvPutText(&img, text2.c_str(), textOrg, &font, color ); + + cvInitFont( &font, FONT_HERSHEY_COMPLEX, 0.5, 0.5, 0, 1, CV_AA ); + cvGetTextSize( text2.c_str(), &font, &textSize, &baseline ); + textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist); + cvPutText(&img, text2.c_str(), textOrg, &font, color ); + + cvInitFont( &font, FONT_HERSHEY_TRIPLEX, 0.5, 0.5, 0, 1, CV_AA ); + cvGetTextSize( text2.c_str(), &font, &textSize, &baseline ); + textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist); + cvPutText(&img, text2.c_str(), textOrg, &font, color ); + + cvInitFont( &font, FONT_HERSHEY_COMPLEX_SMALL, 1, 1, 0, 1, CV_AA ); + cvGetTextSize( text2.c_str(), &font, &textSize, &baseline ); + textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist + 180); + cvPutText(&img, text2.c_str(), textOrg, &font, color ); + + cvInitFont( &font, FONT_HERSHEY_SCRIPT_SIMPLEX, 1, 1, 0, 1, CV_AA ); + cvGetTextSize( text2.c_str(), &font, &textSize, &baseline ); + textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist); + cvPutText(&img, text2.c_str(), textOrg, &font, color ); + + cvInitFont( &font, FONT_HERSHEY_SCRIPT_COMPLEX, 1, 1, 0, 1, CV_AA ); + cvGetTextSize( text2.c_str(), &font, &textSize, &baseline ); + textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist); + cvPutText(&img, text2.c_str(), textOrg, &font, color ); + + dist = 15; + cvInitFont( &font, FONT_ITALIC, 0.5, 0.5, 0, 1, CV_AA ); + cvGetTextSize( text2.c_str(), &font, &textSize, &baseline ); + textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist); + cvPutText(&img, text2.c_str(), textOrg, &font, color ); +} + +int CV_DrawingTest_C::checkLineIterator( Mat& _img ) +{ + CvLineIterator it; + CvMat img = _img; + int count = cvInitLineIterator( &img, cvPoint(0,300), cvPoint(1000, 300), &it ); + for(int i = 0; i < count; i++ ) + { + Vec3b v = (Vec3b)(*(it.ptr)) - _img.at(300,i); + float err = (float)norm( v ); + if( err != 0 ) + { + ts->printf( ts->LOG, "CvLineIterator works incorrect" ); + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); + } + CV_NEXT_LINE_POINT(it); + } + ts->set_failed_test_info(cvtest::TS::OK); + return 0; +} + +#ifdef HAVE_JPEG +TEST(Highgui_Drawing, cpp_regression) { CV_DrawingTest_CPP test; test.safe_run(); } +TEST(Highgui_Drawing, c_regression) { CV_DrawingTest_C test; test.safe_run(); } +#endif + +class CV_FillConvexPolyTest : public cvtest::BaseTest +{ +public: + CV_FillConvexPolyTest() {} + ~CV_FillConvexPolyTest() {} +protected: + void run(int) + { + vector line1; + vector line2; + + line1.push_back(Point(1, 1)); + line1.push_back(Point(5, 1)); + line1.push_back(Point(5, 8)); + line1.push_back(Point(1, 8)); + + line2.push_back(Point(2, 2)); + line2.push_back(Point(10, 2)); + line2.push_back(Point(10, 16)); + line2.push_back(Point(2, 16)); + + Mat gray0(10,10,CV_8U, Scalar(0)); + fillConvexPoly(gray0, line1, Scalar(255), 8, 0); + int nz1 = countNonZero(gray0); + + fillConvexPoly(gray0, line2, Scalar(0), 8, 1); + int nz2 = countNonZero(gray0)/255; + + CV_Assert( nz1 == 40 && nz2 == 0 ); + } +}; + +TEST(Highgui_Drawing, fillconvexpoly_clipping) { CV_FillConvexPolyTest test; test.safe_run(); } diff --git a/highgui/test/test_ffmpeg.cpp b/highgui/test/test_ffmpeg.cpp new file mode 100644 index 0000000..fb32e01 --- /dev/null +++ b/highgui/test/test_ffmpeg.cpp @@ -0,0 +1,176 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" +#include "opencv2/highgui/highgui.hpp" + +#ifdef HAVE_FFMPEG + +#include "ffmpeg_codecs.hpp" + +using namespace cv; +using namespace std; + +class CV_FFmpegWriteBigVideoTest : public cvtest::BaseTest +{ +public: + void run(int) + { + const int img_r = 4096; + const int img_c = 4096; + const double fps0 = 15; + const double time_sec = 1; + + const size_t n = sizeof(codec_bmp_tags)/sizeof(codec_bmp_tags[0]); + + bool created = false; + + for (size_t j = 0; j < n; ++j) + { + stringstream s; s << codec_bmp_tags[j].tag; + int tag = codec_bmp_tags[j].tag; + + if( tag != MKTAG('H', '2', '6', '3') && + tag != MKTAG('H', '2', '6', '1') && + //tag != MKTAG('D', 'I', 'V', 'X') && + tag != MKTAG('D', 'X', '5', '0') && + tag != MKTAG('X', 'V', 'I', 'D') && + tag != MKTAG('m', 'p', '4', 'v') && + //tag != MKTAG('D', 'I', 'V', '3') && + //tag != MKTAG('W', 'M', 'V', '1') && + //tag != MKTAG('W', 'M', 'V', '2') && + tag != MKTAG('M', 'P', 'E', 'G') && + tag != MKTAG('M', 'J', 'P', 'G') && + //tag != MKTAG('j', 'p', 'e', 'g') && + tag != 0 && + tag != MKTAG('I', '4', '2', '0') && + //tag != MKTAG('Y', 'U', 'Y', '2') && + tag != MKTAG('F', 'L', 'V', '1') ) + continue; + + const string filename = "output_"+s.str()+".avi"; + + try + { + double fps = fps0; + Size frame_s = Size(img_c, img_r); + + if( tag == CV_FOURCC('H', '2', '6', '1') ) + frame_s = Size(352, 288); + else if( tag == CV_FOURCC('H', '2', '6', '3') ) + frame_s = Size(704, 576); + /*else if( tag == CV_FOURCC('M', 'J', 'P', 'G') || + tag == CV_FOURCC('j', 'p', 'e', 'g') ) + frame_s = Size(1920, 1080);*/ + + if( tag == CV_FOURCC('M', 'P', 'E', 'G') ) + fps = 25; + + VideoWriter writer(filename, tag, fps, frame_s); + + if (writer.isOpened() == false) + { + ts->printf(ts->LOG, "\n\nFile name: %s\n", filename.c_str()); + ts->printf(ts->LOG, "Codec id: %d Codec tag: %c%c%c%c\n", j, + tag & 255, (tag >> 8) & 255, (tag >> 16) & 255, (tag >> 24) & 255); + ts->printf(ts->LOG, "Error: cannot create video file."); + ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); + } + else + { + Mat img(frame_s, CV_8UC3, Scalar::all(0)); + const int coeff = cvRound(cv::min(frame_s.width, frame_s.height)/(fps0 * time_sec)); + + for (int i = 0 ; i < static_cast(fps * time_sec); i++ ) + { + //circle(img, Point2i(img_c / 2, img_r / 2), cv::min(img_r, img_c) / 2 * (i + 1), Scalar(255, 0, 0, 0), 2); + rectangle(img, Point2i(coeff * i, coeff * i), Point2i(coeff * (i + 1), coeff * (i + 1)), + Scalar::all(255 * (1.0 - static_cast(i) / (fps * time_sec * 2) )), -1); + writer << img; + } + + if (!created) created = true; + else remove(filename.c_str()); + } + } + catch(...) + { + ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); + } + ts->set_failed_test_info(cvtest::TS::OK); + + } + } +}; + +TEST(Highgui_Video, ffmpeg_writebig) { CV_FFmpegWriteBigVideoTest test; test.safe_run(); } + +class CV_FFmpegReadImageTest : public cvtest::BaseTest +{ +public: + void run(int) + { + try + { + string filename = ts->get_data_path() + "../cv/features2d/tsukuba.png"; + VideoCapture cap(filename); + Mat img0 = imread(filename, 1); + Mat img, img_next; + cap >> img; + cap >> img_next; + + CV_Assert( !img0.empty() && !img.empty() && img_next.empty() ); + + double diff = norm(img0, img, CV_C); + CV_Assert( diff == 0 ); + } + catch(...) + { + ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); + } + ts->set_failed_test_info(cvtest::TS::OK); + } +}; + +TEST(Highgui_Video, ffmpeg_image) { CV_FFmpegReadImageTest test; test.safe_run(); } + +#endif diff --git a/highgui/test/test_framecount.cpp b/highgui/test/test_framecount.cpp new file mode 100644 index 0000000..e4d8c30 --- /dev/null +++ b/highgui/test/test_framecount.cpp @@ -0,0 +1,114 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" +#include "opencv2/highgui/highgui.hpp" +#include + +using namespace cv; +using namespace std; + +class CV_FramecountTest: public cvtest::BaseTest +{ +public: + void run(int); +}; + +void CV_FramecountTest::run(int) +{ + const int time_sec = 5, fps = 25; + + const string ext[] = {"avi", "mov", "mp4"}; + + const size_t n = sizeof(ext)/sizeof(ext[0]); + + const string src_dir = ts->get_data_path(); + + ts->printf(cvtest::TS::LOG, "\n\nSource files directory: %s\n", (src_dir+"video/").c_str()); + + Ptr cap; + + for (size_t i = 0; i < n; ++i) + { + string file_path = src_dir+"video/big_buck_bunny."+ext[i]; + + cap = cvCreateFileCapture(file_path.c_str()); + if (cap.empty()) + { + ts->printf(cvtest::TS::LOG, "\nFile information (video %d): \n\nName: big_buck_bunny.%s\nFAILED\n\n", i+1, ext[i].c_str()); + ts->printf(cvtest::TS::LOG, "Error: cannot read source video file.\n"); + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); + return; + } + + //cvSetCaptureProperty(cap, CV_CAP_PROP_POS_FRAMES, 0); + IplImage* frame; int FrameCount = 0; + + for(;;) + { + frame = cvQueryFrame(cap); + if( !frame ) + break; + FrameCount++; + } + + int framecount = (int)cvGetCaptureProperty(cap, CV_CAP_PROP_FRAME_COUNT); + + ts->printf(cvtest::TS::LOG, "\nFile information (video %d): \n"\ + "\nName: big_buck_bunny.%s\nActual frame count: %d\n"\ + "Frame count computed in the cycle of queries of frames: %d\n"\ + "Frame count returned by cvGetCaptureProperty function: %d\n", + i+1, ext[i].c_str(), time_sec*fps, FrameCount, framecount); + + if( (FrameCount != cvRound(time_sec*fps) || + FrameCount != framecount) && ext[i] != "mpg" ) + { + ts->printf(cvtest::TS::LOG, "FAILED\n"); + ts->printf(cvtest::TS::LOG, "\nError: actual frame count and returned frame count are not matched.\n"); + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); + return; + } + } +} +#if BUILD_WITH_VIDEO_INPUT_SUPPORT +TEST(Highgui_Video, framecount) {CV_FramecountTest test; test.safe_run();} +#endif diff --git a/highgui/test/test_grfmt.cpp b/highgui/test/test_grfmt.cpp new file mode 100644 index 0000000..f590c63 --- /dev/null +++ b/highgui/test/test_grfmt.cpp @@ -0,0 +1,227 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" +#include "opencv2/highgui/highgui.hpp" + +using namespace cv; +using namespace std; + + +class CV_GrfmtWriteBigImageTest : public cvtest::BaseTest +{ +public: + void run(int) + { + try + { + ts->printf(cvtest::TS::LOG, "start reading big image\n"); + Mat img = imread(string(ts->get_data_path()) + "readwrite/read.png"); + ts->printf(cvtest::TS::LOG, "finish reading big image\n"); + if (img.empty()) ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); + ts->printf(cvtest::TS::LOG, "start writing big image\n"); + imwrite(cv::tempfile(".png"), img); + ts->printf(cvtest::TS::LOG, "finish writing big image\n"); + } + catch(...) + { + ts->set_failed_test_info(cvtest::TS::FAIL_EXCEPTION); + } + ts->set_failed_test_info(cvtest::TS::OK); + } +}; + +string ext_from_int(int ext) +{ +#ifdef HAVE_PNG + if (ext == 0) return ".png"; +#endif + if (ext == 1) return ".bmp"; + if (ext == 2) return ".pgm"; +#ifdef HAVE_TIFF + if (ext == 3) return ".tiff"; +#endif + return ""; +} + +class CV_GrfmtWriteSequenceImageTest : public cvtest::BaseTest +{ +public: + void run(int) + { + try + { + const int img_r = 640; + const int img_c = 480; + + for (int k = 1; k <= 5; ++k) + { + for (int ext = 0; ext < 4; ++ext) // 0 - png, 1 - bmp, 2 - pgm, 3 - tiff + { + if(ext_from_int(ext).empty()) + continue; + for (int num_channels = 1; num_channels <= 3; num_channels+=2) + { + ts->printf(ts->LOG, "image type depth:%d channels:%d ext: %s\n", CV_8U, num_channels, ext_from_int(ext).c_str()); + Mat img(img_r * k, img_c * k, CV_MAKETYPE(CV_8U, num_channels), Scalar::all(0)); + circle(img, Point2i((img_c * k) / 2, (img_r * k) / 2), cv::min((img_r * k), (img_c * k)) / 4 , Scalar::all(255)); + + string img_path = cv::tempfile(ext_from_int(ext).c_str()); + ts->printf(ts->LOG, "writing image : %s\n", img_path.c_str()); + imwrite(img_path, img); + + ts->printf(ts->LOG, "reading test image : %s\n", img_path.c_str()); + Mat img_test = imread(img_path, CV_LOAD_IMAGE_UNCHANGED); + + if (img_test.empty()) ts->set_failed_test_info(ts->FAIL_MISMATCH); + + CV_Assert(img.size() == img_test.size()); + CV_Assert(img.type() == img_test.type()); + + double n = norm(img, img_test); + if ( n > 1.0) + { + ts->printf(ts->LOG, "norm = %f \n", n); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + } + } + } + +#ifdef HAVE_JPEG + for (int num_channels = 1; num_channels <= 3; num_channels+=2) + { + // jpeg + ts->printf(ts->LOG, "image type depth:%d channels:%d ext: %s\n", CV_8U, num_channels, ".jpg"); + Mat img(img_r * k, img_c * k, CV_MAKETYPE(CV_8U, num_channels), Scalar::all(0)); + circle(img, Point2i((img_c * k) / 2, (img_r * k) / 2), cv::min((img_r * k), (img_c * k)) / 4 , Scalar::all(255)); + + string filename = cv::tempfile(".jpg"); + imwrite(filename, img); + img = imread(filename, CV_LOAD_IMAGE_UNCHANGED); + + filename = string(ts->get_data_path() + "readwrite/test_" + char(k + 48) + "_c" + char(num_channels + 48) + ".jpg"); + ts->printf(ts->LOG, "reading test image : %s\n", filename.c_str()); + Mat img_test = imread(filename, CV_LOAD_IMAGE_UNCHANGED); + + if (img_test.empty()) ts->set_failed_test_info(ts->FAIL_MISMATCH); + + CV_Assert(img.size() == img_test.size()); + CV_Assert(img.type() == img_test.type()); + + double n = norm(img, img_test); + if ( n > 1.0) + { + ts->printf(ts->LOG, "norm = %f \n", n); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + } + } +#endif + +#ifdef HAVE_TIFF + for (int num_channels = 1; num_channels <= 3; num_channels+=2) + { + // tiff + ts->printf(ts->LOG, "image type depth:%d channels:%d ext: %s\n", CV_16U, num_channels, ".tiff"); + Mat img(img_r * k, img_c * k, CV_MAKETYPE(CV_16U, num_channels), Scalar::all(0)); + circle(img, Point2i((img_c * k) / 2, (img_r * k) / 2), cv::min((img_r * k), (img_c * k)) / 4 , Scalar::all(255)); + + string filename = cv::tempfile(".tiff"); + imwrite(filename, img); + ts->printf(ts->LOG, "reading test image : %s\n", filename.c_str()); + Mat img_test = imread(filename, CV_LOAD_IMAGE_UNCHANGED); + + if (img_test.empty()) ts->set_failed_test_info(ts->FAIL_MISMATCH); + + CV_Assert(img.size() == img_test.size()); + + ts->printf(ts->LOG, "img : %d ; %d \n", img.channels(), img.depth()); + ts->printf(ts->LOG, "img_test : %d ; %d \n", img_test.channels(), img_test.depth()); + + CV_Assert(img.type() == img_test.type()); + + + double n = norm(img, img_test); + if ( n > 1.0) + { + ts->printf(ts->LOG, "norm = %f \n", n); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + } + } +#endif + } + } + catch(const cv::Exception & e) + { + ts->printf(ts->LOG, "Exception: %s\n" , e.what()); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + } + } +}; + +class CV_GrfmtReadBMPRLE8Test : public cvtest::BaseTest +{ +public: + void run(int) + { + try + { + Mat rle = imread(string(ts->get_data_path()) + "readwrite/rle8.bmp"); + Mat bmp = imread(string(ts->get_data_path()) + "readwrite/ordinary.bmp"); + if (norm(rle-bmp)>1.e-10) + ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); + } + catch(...) + { + ts->set_failed_test_info(cvtest::TS::FAIL_EXCEPTION); + } + ts->set_failed_test_info(cvtest::TS::OK); + } +}; + +#ifdef HAVE_PNG +TEST(Highgui_Image, write_big) { CV_GrfmtWriteBigImageTest test; test.safe_run(); } +#endif + +TEST(Highgui_Image, write_imageseq) { CV_GrfmtWriteSequenceImageTest test; test.safe_run(); } + +TEST(Highgui_Image, read_bmp_rle8) { CV_GrfmtReadBMPRLE8Test test; test.safe_run(); } + diff --git a/highgui/test/test_gui.cpp b/highgui/test/test_gui.cpp new file mode 100644 index 0000000..11aa3f9 --- /dev/null +++ b/highgui/test/test_gui.cpp @@ -0,0 +1,90 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" +#include "opencv2/highgui/highgui.hpp" + +#if defined HAVE_GTK || defined HAVE_QT || defined WIN32 || defined _WIN32 || defined HAVE_CARBON || defined HAVE_COCOA + +using namespace cv; +using namespace std; + +class CV_HighGuiOnlyGuiTest : public cvtest::BaseTest +{ +protected: + void run(int); +}; + +void Foo(int /*k*/, void* /*z*/) {} + +void CV_HighGuiOnlyGuiTest::run( int /*start_from */) +{ + ts->printf(ts->LOG, "GUI 1\n"); + namedWindow("Win"); + + ts->printf(ts->LOG, "GUI 2\n"); + Mat m(256, 256, CV_8U); + m = Scalar(128); + + ts->printf(ts->LOG, "GUI 3\n"); + imshow("Win", m); + + ts->printf(ts->LOG, "GUI 4\n"); + int value = 50; + + ts->printf(ts->LOG, "GUI 5\n"); + createTrackbar( "trackbar", "Win", &value, 100, Foo, &value); + + ts->printf(ts->LOG, "GUI 6\n"); + getTrackbarPos( "trackbar", "Win" ); + + ts->printf(ts->LOG, "GUI 7\n"); + waitKey(500); + + ts->printf(ts->LOG, "GUI 8\n"); + cvDestroyAllWindows(); + ts->set_failed_test_info(cvtest::TS::OK); +} + +TEST(Highgui_GUI, regression) { CV_HighGuiOnlyGuiTest test; test.safe_run(); } + +#endif diff --git a/highgui/test/test_main.cpp b/highgui/test/test_main.cpp new file mode 100644 index 0000000..363b541 --- /dev/null +++ b/highgui/test/test_main.cpp @@ -0,0 +1,4 @@ +#include "test_precomp.hpp" + +CV_TEST_MAIN("highgui") + diff --git a/highgui/test/test_positioning.cpp b/highgui/test/test_positioning.cpp new file mode 100644 index 0000000..0cbfec4 --- /dev/null +++ b/highgui/test/test_positioning.cpp @@ -0,0 +1,223 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" +#include "opencv2/highgui/highgui.hpp" +#include + +using namespace cv; +using namespace std; + +class CV_VideoPositioningTest: public cvtest::BaseTest +{ +public: + enum {PROGRESSIVE, RANDOM}; + + CV_VideoPositioningTest(); + ~CV_VideoPositioningTest(); + virtual void run(int) = 0; + +protected: + vector idx; + void run_test(int method); + +private: + void generate_idx_seq(CvCapture *cap, int method); +}; + +class CV_VideoProgressivePositioningTest: public CV_VideoPositioningTest +{ +public: + CV_VideoProgressivePositioningTest() : CV_VideoPositioningTest() {}; + ~CV_VideoProgressivePositioningTest(); + void run(int); +}; + +class CV_VideoRandomPositioningTest: public CV_VideoPositioningTest +{ +public: + CV_VideoRandomPositioningTest(): CV_VideoPositioningTest() {}; + ~CV_VideoRandomPositioningTest(); + void run(int); +}; + +CV_VideoPositioningTest::CV_VideoPositioningTest() {} +CV_VideoPositioningTest::~CV_VideoPositioningTest() {} +CV_VideoProgressivePositioningTest::~CV_VideoProgressivePositioningTest() {} +CV_VideoRandomPositioningTest::~CV_VideoRandomPositioningTest() {} + +void CV_VideoPositioningTest::generate_idx_seq(CvCapture* cap, int method) +{ + idx.clear(); + int N = (int)cvGetCaptureProperty(cap, CV_CAP_PROP_FRAME_COUNT); + switch(method) + { + case PROGRESSIVE: + { + int pos = 1, step = 20; + do + { + idx.push_back(pos); + pos += step; + } + while (pos <= N); + break; + } + case RANDOM: + { + RNG rng(N); + idx.clear(); + for( int i = 0; i < N-1; i++ ) + idx.push_back(rng.uniform(0, N)); + idx.push_back(N-1); + std::swap(idx.at(rng.uniform(0, N-1)), idx.at(N-1)); + break; + } + default:break; + } +} + +void CV_VideoPositioningTest::run_test(int method) +{ + const string& src_dir = ts->get_data_path(); + + ts->printf(cvtest::TS::LOG, "\n\nSource files directory: %s\n", (src_dir+"video/").c_str()); + + const string ext[] = {"avi", "mov", "mp4", "mpg"}; + + int n = (int)(sizeof(ext)/sizeof(ext[0])); + + int failed_videos = 0; + + for (int i = 0; i < n; ++i) + { + // skip random positioning test in plain mpegs + if( method == RANDOM && ext[i] == "mpg" ) + continue; + string file_path = src_dir + "video/big_buck_bunny." + ext[i]; + + ts->printf(cvtest::TS::LOG, "\nReading video file in %s...\n", file_path.c_str()); + + CvCapture* cap = cvCreateFileCapture(file_path.c_str()); + + if (!cap) + { + ts->printf(cvtest::TS::LOG, "\nFile information (video %d): \n\nName: big_buck_bunny.%s\nFAILED\n\n", i+1, ext[i].c_str()); + ts->printf(cvtest::TS::LOG, "Error: cannot read source video file.\n"); + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); + failed_videos++; continue; + } + + cvSetCaptureProperty(cap, CV_CAP_PROP_POS_FRAMES, 0); + + generate_idx_seq(cap, method); + + int N = (int)idx.size(), failed_frames = 0, failed_positions = 0, failed_iterations = 0; + + for (int j = 0; j < N; ++j) + { + bool flag = false; + + cvSetCaptureProperty(cap, CV_CAP_PROP_POS_FRAMES, idx.at(j)); + + /* IplImage* frame = cvRetrieveFrame(cap); + + if (!frame) + { + if (!failed_frames) + { + ts->printf(cvtest::TS::LOG, "\nFile information (video %d): \n\nName: big_buck_bunny.%s\n", i+1, ext[i].c_str()); + } + failed_frames++; + ts->printf(cvtest::TS::LOG, "\nIteration: %d\n\nError: cannot read a frame with index %d.\n", j, idx.at(j)); + ts->set_failed_test_info(cvtest::TS::FAIL_EXCEPTION); + flag = !flag; + } */ + + int val = (int)cvGetCaptureProperty(cap, CV_CAP_PROP_POS_FRAMES); + + if (idx.at(j) != val) + { + if (!(failed_frames||failed_positions)) + { + ts->printf(cvtest::TS::LOG, "\nFile information (video %d): \n\nName: big_buck_bunny.%s\n", i+1, ext[i].c_str()); + } + failed_positions++; + if (!failed_frames) + { + ts->printf(cvtest::TS::LOG, "\nIteration: %d\n", j); + } + ts->printf(cvtest::TS::LOG, "Required pos: %d\nReturned pos: %d\n", idx.at(j), val); + ts->printf(cvtest::TS::LOG, "Error: required and returned positions are not matched.\n"); + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); + flag = true; + } + + if (flag) + { + failed_iterations++; + failed_videos++; + break; + } + } + + cvReleaseCapture(&cap); + } + + ts->printf(cvtest::TS::LOG, "\nSuccessfull experiments: %d (%d%%)\n", n-failed_videos, 100*(n-failed_videos)/n); + ts->printf(cvtest::TS::LOG, "Failed experiments: %d (%d%%)\n", failed_videos, 100*failed_videos/n); +} + +void CV_VideoProgressivePositioningTest::run(int) +{ + run_test(PROGRESSIVE); +} + +void CV_VideoRandomPositioningTest::run(int) +{ + run_test(RANDOM); +} + +#if BUILD_WITH_VIDEO_INPUT_SUPPORT +TEST (Highgui_Video, seek_progressive) { CV_VideoProgressivePositioningTest test; test.safe_run(); } +TEST (Highgui_Video, seek_random) { CV_VideoRandomPositioningTest test; test.safe_run(); } +#endif \ No newline at end of file diff --git a/highgui/test/test_precomp.cpp b/highgui/test/test_precomp.cpp new file mode 100644 index 0000000..5956e13 --- /dev/null +++ b/highgui/test/test_precomp.cpp @@ -0,0 +1 @@ +#include "test_precomp.hpp" diff --git a/highgui/test/test_precomp.hpp b/highgui/test/test_precomp.hpp new file mode 100644 index 0000000..676b80b --- /dev/null +++ b/highgui/test/test_precomp.hpp @@ -0,0 +1,84 @@ +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wmissing-declarations" +# pragma GCC diagnostic ignored "-Wmissing-prototypes" //OSX +#endif + +#ifndef __OPENCV_TEST_PRECOMP_HPP__ +#define __OPENCV_TEST_PRECOMP_HPP__ + +#ifdef HAVE_CVCONFIG_H +# include "cvconfig.h" +#endif + +#include "opencv2/ts/ts.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/imgproc/imgproc_c.h" +#include + +#if defined(HAVE_VIDEOINPUT) || \ + defined(HAVE_TYZX) || \ + defined(HAVE_VFW) || \ + defined(HAVE_LIBV4L) || \ + (defined(HAVE_CAMV4L) && defined(HAVE_CAMV4L2)) || \ + defined(HAVE_GSTREAMER) || \ + defined(HAVE_DC1394_2) || \ + defined(HAVE_DC1394) || \ + defined(HAVE_CMU1394) || \ + defined(HAVE_MIL) || \ + defined(HAVE_QUICKTIME) || \ + defined(HAVE_UNICAP) || \ + defined(HAVE_PVAPI) || \ + defined(HAVE_OPENNI) || \ + defined(HAVE_XIMEA) || \ + defined(HAVE_AVFOUNDATION) || \ + (0) + //defined(HAVE_ANDROID_NATIVE_CAMERA) || - enable after #1193 +# define BUILD_WITH_CAMERA_SUPPORT 1 +#else +# define BUILD_WITH_CAMERA_SUPPORT 0 +#endif + +#if defined(HAVE_XINE) || \ + defined(HAVE_GSTREAMER) || \ + defined(HAVE_QUICKTIME) || \ + defined(HAVE_AVFOUNDATION) || \ + /*defined(HAVE_OPENNI) || too specialized */ \ + defined(HAVE_FFMPEG) || \ + defined(WIN32) /* assume that we have ffmpeg */ + +# define BUILD_WITH_VIDEO_INPUT_SUPPORT 1 +#else +# define BUILD_WITH_VIDEO_INPUT_SUPPORT 0 +#endif + +#if /*defined(HAVE_XINE) || */\ + defined(HAVE_GSTREAMER) || \ + defined(HAVE_QUICKTIME) || \ + defined(HAVE_AVFOUNDATION) || \ + defined(HAVE_FFMPEG) || \ + defined(WIN32) /* assume that we have ffmpeg */ +# define BUILD_WITH_VIDEO_OUTPUT_SUPPORT 1 +#else +# define BUILD_WITH_VIDEO_OUTPUT_SUPPORT 0 +#endif + +namespace cvtest +{ + +string fourccToString(int fourcc); + +struct VideoFormat +{ + VideoFormat() { fourcc = -1; } + VideoFormat(const string& _ext, int _fourcc) : ext(_ext), fourcc(_fourcc) {} + bool empty() const { return ext.empty(); } + + string ext; + int fourcc; +}; + +extern const VideoFormat g_specific_fmt_list[]; + +} + +#endif diff --git a/highgui/test/test_video_io.cpp b/highgui/test/test_video_io.cpp new file mode 100644 index 0000000..e85fa5e --- /dev/null +++ b/highgui/test/test_video_io.cpp @@ -0,0 +1,529 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" +#include "opencv2/highgui/highgui.hpp" + +using namespace cv; +using namespace std; + +namespace cvtest +{ + +string fourccToString(int fourcc) +{ + return format("%c%c%c%c", fourcc & 255, (fourcc >> 8) & 255, (fourcc >> 16) & 255, (fourcc >> 24) & 255); +} + +const VideoFormat g_specific_fmt_list[] = +{ + VideoFormat("avi", CV_FOURCC('X', 'V', 'I', 'D')), + VideoFormat("avi", CV_FOURCC('M', 'P', 'E', 'G')), + VideoFormat("avi", CV_FOURCC('M', 'J', 'P', 'G')), + //VideoFormat("avi", CV_FOURCC('I', 'Y', 'U', 'V')), + VideoFormat("mkv", CV_FOURCC('X', 'V', 'I', 'D')), + VideoFormat("mkv", CV_FOURCC('M', 'P', 'E', 'G')), + VideoFormat("mkv", CV_FOURCC('M', 'J', 'P', 'G')), + + VideoFormat("mov", CV_FOURCC('m', 'p', '4', 'v')), + VideoFormat() +}; + +} + +class CV_HighGuiTest : public cvtest::BaseTest +{ +protected: + void ImageTest(const string& dir); + void VideoTest (const string& dir, const cvtest::VideoFormat& fmt); + void SpecificImageTest (const string& dir); + void SpecificVideoTest (const string& dir, const cvtest::VideoFormat& fmt); + + CV_HighGuiTest() {} + ~CV_HighGuiTest() {} + virtual void run(int) = 0; +}; + +class CV_ImageTest : public CV_HighGuiTest +{ +public: + CV_ImageTest() {} + ~CV_ImageTest() {} + void run(int); +}; + +class CV_SpecificImageTest : public CV_HighGuiTest +{ +public: + CV_SpecificImageTest() {} + ~CV_SpecificImageTest() {} + void run(int); +}; + +class CV_VideoTest : public CV_HighGuiTest +{ +public: + CV_VideoTest() {} + ~CV_VideoTest() {} + void run(int); +}; + +class CV_SpecificVideoTest : public CV_HighGuiTest +{ +public: + CV_SpecificVideoTest() {} + ~CV_SpecificVideoTest() {} + void run(int); +}; + + +void CV_HighGuiTest::ImageTest(const string& dir) +{ + string _name = dir + string("../cv/shared/baboon.jpg"); + ts->printf(ts->LOG, "reading image : %s\n", _name.c_str()); + + Mat image = imread(_name); + image.convertTo(image, CV_8UC3); + + if (image.empty()) + { + ts->set_failed_test_info(ts->FAIL_MISSING_TEST_DATA); + return; + } + + const string exts[] = { +#ifdef HAVE_PNG + "png", +#endif +#ifdef HAVE_TIFF + "tiff", +#endif +#ifdef HAVE_JPEG + "jpg", +#endif +#ifdef HAVE_JASPER + "jp2", +#endif +#ifdef HAVE_OPENEXR + "exr", +#endif + "bmp", + "ppm", + "ras" + }; + const size_t ext_num = sizeof(exts)/sizeof(exts[0]); + + for(size_t i = 0; i < ext_num; ++i) + { + string ext = exts[i]; + string full_name = cv::tempfile(ext.c_str()); + ts->printf(ts->LOG, " full_name : %s\n", full_name.c_str()); + + imwrite(full_name, image); + + Mat loaded = imread(full_name); + if (loaded.empty()) + { + ts->printf(ts->LOG, "Reading failed at fmt=%s\n", ext.c_str()); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + continue; + } + + const double thresDbell = 20; + double psnr = PSNR(loaded, image); + if (psnr < thresDbell) + { + ts->printf(ts->LOG, "Reading image from file: too big difference (=%g) with fmt=%s\n", psnr, ext.c_str()); + ts->set_failed_test_info(ts->FAIL_BAD_ACCURACY); + continue; + } + + vector from_file; + + FILE *f = fopen(full_name.c_str(), "rb"); + fseek(f, 0, SEEK_END); + long len = ftell(f); + from_file.resize((size_t)len); + fseek(f, 0, SEEK_SET); + from_file.resize(fread(&from_file[0], 1, from_file.size(), f)); + fclose(f); + + vector buf; + imencode("." + exts[i], image, buf); + + if (buf != from_file) + { + ts->printf(ts->LOG, "Encoding failed with fmt=%s\n", ext.c_str()); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + continue; + } + + Mat buf_loaded = imdecode(Mat(buf), 1); + + if (buf_loaded.empty()) + { + ts->printf(ts->LOG, "Decoding failed with fmt=%s\n", ext.c_str()); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + continue; + } + + psnr = PSNR(buf_loaded, image); + + if (psnr < thresDbell) + { + ts->printf(ts->LOG, "Decoding image from memory: too small PSNR (=%gdb) with fmt=%s\n", psnr, ext.c_str()); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + continue; + } + + } + + ts->printf(ts->LOG, "end test function : ImagesTest \n"); + ts->set_failed_test_info(ts->OK); +} + + +void CV_HighGuiTest::VideoTest(const string& dir, const cvtest::VideoFormat& fmt) +{ + string src_file = dir + "../cv/shared/video_for_test.avi"; + string tmp_name = cv::tempfile((cvtest::fourccToString(fmt.fourcc) + "." + fmt.ext).c_str()); + + ts->printf(ts->LOG, "reading video : %s and converting it to %s\n", src_file.c_str(), tmp_name.c_str()); + + CvCapture* cap = cvCaptureFromFile(src_file.c_str()); + + if (!cap) + { + ts->set_failed_test_info(ts->FAIL_MISMATCH); + return; + } + + CvVideoWriter* writer = 0; + vector frames; + + for(;;) + { + IplImage * img = cvQueryFrame( cap ); + + if (!img) + break; + + frames.push_back(Mat(img).clone()); + + if (writer == 0) + { + writer = cvCreateVideoWriter(tmp_name.c_str(), fmt.fourcc, 24, cvGetSize(img)); + if (writer == 0) + { + ts->printf(ts->LOG, "can't create writer (with fourcc : %d)\n", + cvtest::fourccToString(fmt.fourcc).c_str()); + cvReleaseCapture( &cap ); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + return; + } + } + + cvWriteFrame(writer, img); + } + + cvReleaseVideoWriter( &writer ); + cvReleaseCapture( &cap ); + + CvCapture *saved = cvCaptureFromFile(tmp_name.c_str()); + if (!saved) + { + ts->set_failed_test_info(ts->FAIL_MISMATCH); + return; + } + + const double thresDbell = 20; + + for(int i = 0;; i++) + { + IplImage* ipl1 = cvQueryFrame( saved ); + + if (!ipl1) + break; + + Mat img = frames[i]; + Mat img1(ipl1); + + double psnr = PSNR(img1, img); + if (psnr < thresDbell) + { + printf("Too low psnr = %gdb\n", psnr); + // imwrite("img.png", img); + // imwrite("img1.png", img1); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + break; + } + } + + cvReleaseCapture( &saved ); + + ts->printf(ts->LOG, "end test function : ImagesVideo \n"); +} + +void CV_HighGuiTest::SpecificImageTest(const string& dir) +{ + const size_t IMAGE_COUNT = 10; + + for (size_t i = 0; i < IMAGE_COUNT; ++i) + { + stringstream s; s << i; + string file_path = dir+"../python/images/QCIF_0"+s.str()+".bmp"; + Mat image = imread(file_path); + + if (image.empty()) + { + ts->set_failed_test_info(ts->FAIL_MISSING_TEST_DATA); + return; + } + + resize(image, image, Size(968, 757), 0.0, 0.0, INTER_CUBIC); + + stringstream s_digit; s_digit << i; + + string full_name = cv::tempfile((s_digit.str() + ".bmp").c_str()); + ts->printf(ts->LOG, " full_name : %s\n", full_name.c_str()); + + imwrite(full_name, image); + + Mat loaded = imread(full_name); + if (loaded.empty()) + { + ts->printf(ts->LOG, "Reading failed at fmt=bmp\n"); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + continue; + } + + const double thresDbell = 20; + double psnr = PSNR(loaded, image); + if (psnr < thresDbell) + { + ts->printf(ts->LOG, "Reading image from file: too big difference (=%g) with fmt=bmp\n", psnr); + ts->set_failed_test_info(ts->FAIL_BAD_ACCURACY); + continue; + } + + vector from_file; + + FILE *f = fopen(full_name.c_str(), "rb"); + fseek(f, 0, SEEK_END); + long len = ftell(f); + from_file.resize((size_t)len); + fseek(f, 0, SEEK_SET); + from_file.resize(fread(&from_file[0], 1, from_file.size(), f)); + fclose(f); + + vector buf; + imencode(".bmp", image, buf); + + if (buf != from_file) + { + ts->printf(ts->LOG, "Encoding failed with fmt=bmp\n"); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + continue; + } + + Mat buf_loaded = imdecode(Mat(buf), 1); + + if (buf_loaded.empty()) + { + ts->printf(ts->LOG, "Decoding failed with fmt=bmp\n"); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + continue; + } + + psnr = PSNR(buf_loaded, image); + + if (psnr < thresDbell) + { + ts->printf(ts->LOG, "Decoding image from memory: too small PSNR (=%gdb) with fmt=bmp\n", psnr); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + continue; + } + } + + ts->printf(ts->LOG, "end test function : SpecificImageTest \n"); + ts->set_failed_test_info(ts->OK); +} + + +void CV_HighGuiTest::SpecificVideoTest(const string& dir, const cvtest::VideoFormat& fmt) +{ + string ext = fmt.ext; + int fourcc = fmt.fourcc; + + string fourcc_str = cvtest::fourccToString(fourcc); + const string video_file = cv::tempfile((fourcc_str + "." + ext).c_str()); + + Size frame_size(968 & -2, 757 & -2); + VideoWriter writer(video_file, fourcc, 25, frame_size, true); + + if (!writer.isOpened()) + { + // call it repeatedly for easier debugging + VideoWriter writer2(video_file, fourcc, 25, frame_size, true); + ts->printf(ts->LOG, "Creating a video in %s...\n", video_file.c_str()); + ts->printf(ts->LOG, "Cannot create VideoWriter object with codec %s.\n", fourcc_str.c_str()); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + return; + } + + const size_t IMAGE_COUNT = 30; + vector images; + + for( size_t i = 0; i < IMAGE_COUNT; ++i ) + { + string file_path = format("%s../python/images/QCIF_%02d.bmp", dir.c_str(), i); + Mat img = imread(file_path, CV_LOAD_IMAGE_COLOR); + + if (img.empty()) + { + ts->printf(ts->LOG, "Creating a video in %s...\n", video_file.c_str()); + ts->printf(ts->LOG, "Error: cannot read frame from %s.\n", file_path.c_str()); + ts->printf(ts->LOG, "Continue creating the video file...\n"); + ts->set_failed_test_info(ts->FAIL_INVALID_TEST_DATA); + break; + } + + for (int k = 0; k < img.rows; ++k) + for (int l = 0; l < img.cols; ++l) + if (img.at(k, l) == Vec3b::all(0)) + img.at(k, l) = Vec3b(0, 255, 0); + else img.at(k, l) = Vec3b(0, 0, 255); + + resize(img, img, frame_size, 0.0, 0.0, INTER_CUBIC); + + images.push_back(img); + writer << img; + } + + writer.release(); + VideoCapture cap(video_file); + + size_t FRAME_COUNT = (size_t)cap.get(CV_CAP_PROP_FRAME_COUNT); + + if (FRAME_COUNT != IMAGE_COUNT ) + { + ts->printf(ts->LOG, "\nFrame count checking for video_%s.%s...\n", fourcc_str.c_str(), ext.c_str()); + ts->printf(ts->LOG, "Video codec: %s\n", fourcc_str.c_str()); + ts->printf(ts->LOG, "Required frame count: %d; Returned frame count: %d\n", IMAGE_COUNT, FRAME_COUNT); + ts->printf(ts->LOG, "Error: Incorrect frame count in the video.\n"); + ts->printf(ts->LOG, "Continue checking...\n"); + ts->set_failed_test_info(ts->FAIL_BAD_ACCURACY); + return; + } + + for (int i = 0; (size_t)i < FRAME_COUNT; i++) + { + Mat frame; cap >> frame; + if (frame.empty()) + { + ts->printf(ts->LOG, "\nVideo file directory: %s\n", "."); + ts->printf(ts->LOG, "File name: video_%s.%s\n", fourcc_str.c_str(), ext.c_str()); + ts->printf(ts->LOG, "Video codec: %s\n", fourcc_str.c_str()); + ts->printf(ts->LOG, "Error: cannot read the next frame with index %d.\n", i+1); + ts->set_failed_test_info(ts->FAIL_MISSING_TEST_DATA); + break; + } + + Mat img = images[i]; + + const double thresDbell = 40; + double psnr = PSNR(img, frame); + + if (psnr > thresDbell) + { + ts->printf(ts->LOG, "\nReading frame from the file video_%s.%s...\n", fourcc_str.c_str(), ext.c_str()); + ts->printf(ts->LOG, "Frame index: %d\n", i+1); + ts->printf(ts->LOG, "Difference between saved and original images: %g\n", psnr); + ts->printf(ts->LOG, "Maximum allowed difference: %g\n", thresDbell); + ts->printf(ts->LOG, "Error: too big difference between saved and original images.\n"); + break; + } + } +} + +void CV_ImageTest::run(int) +{ + ImageTest(ts->get_data_path()); +} + +void CV_SpecificImageTest::run(int) +{ + SpecificImageTest(ts->get_data_path()); +} + +void CV_VideoTest::run(int) +{ + for (int i = 0; ; ++i) + { + const cvtest::VideoFormat& fmt = cvtest::g_specific_fmt_list[i]; + if( fmt.empty() ) + break; + VideoTest(ts->get_data_path(), fmt); + } +} + +void CV_SpecificVideoTest::run(int) +{ + for (int i = 0; ; ++i) + { + const cvtest::VideoFormat& fmt = cvtest::g_specific_fmt_list[i]; + if( fmt.empty() ) + break; + SpecificVideoTest(ts->get_data_path(), fmt); + } +} + +#ifdef HAVE_JPEG +TEST(Highgui_Image, regression) { CV_ImageTest test; test.safe_run(); } +#endif + +#if BUILD_WITH_VIDEO_INPUT_SUPPORT && BUILD_WITH_VIDEO_OUTPUT_SUPPORT && !defined(__APPLE__) +TEST(Highgui_Video, regression) { CV_VideoTest test; test.safe_run(); } +TEST(Highgui_Video, write_read) { CV_SpecificVideoTest test; test.safe_run(); } +#endif + +TEST(Highgui_Image, write_read) { CV_SpecificImageTest test; test.safe_run(); } diff --git a/highgui/test/test_video_pos.cpp b/highgui/test/test_video_pos.cpp new file mode 100644 index 0000000..92904f5 --- /dev/null +++ b/highgui/test/test_video_pos.cpp @@ -0,0 +1,178 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// + // + // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + // + // By downloading, copying, installing or using the software you agree to this license. + // If you do not agree to this license, do not download, install, + // copy or use the software. + // + // + // License Agreement + // For Open Source Computer Vision Library + // + // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. + // Copyright (C) 2009, Willow Garage Inc., all rights reserved. + // Third party copyrights are property of their respective owners. + // + // Redistribution and use in source and binary forms, with or without modification, + // are permitted provided that the following conditions are met: + // + // * Redistribution's of source code must retain the above copyright notice, + // this list of conditions and the following disclaimer. + // + // * Redistribution's 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. + // + // * The name of the copyright holders may not be used to endorse or promote products + // derived from this software without specific prior written permission. + // + // This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. + // + //M*/ + +#include "test_precomp.hpp" +#include "opencv2/highgui/highgui.hpp" + +using namespace cv; +using namespace std; + +class CV_PositioningTest : public cvtest::BaseTest +{ +public: + CV_PositioningTest() + { + framesize = Size(640, 480); + } + + Mat drawFrame(int i) + { + Mat mat = Mat::zeros(framesize, CV_8UC3); + + mat = Scalar(fabs(cos(i*0.08)*255), fabs(sin(i*0.05)*255), i); + putText(mat, format("%03d", i), Point(10, 350), 0, 10, Scalar(128, 255, 255), 15); + return mat; + } + + string getFilename(const cvtest::VideoFormat& fmt) + { + return cv::tempfile((cvtest::fourccToString(fmt.fourcc) + "." + fmt.ext).c_str()); + } + + bool CreateTestVideo(const cvtest::VideoFormat& fmt, int framecount, string filename) + { + VideoWriter writer(filename, fmt.fourcc, 25, framesize, true); + if( !writer.isOpened() ) + return false; + + for (int i = 0; i < framecount; ++i) + { + Mat img = drawFrame(i); + writer << img; + } + return true; + } + + void run(int) + { + int n_frames = 100; + + for( int testcase = 0; ; testcase++ ) + { + const cvtest::VideoFormat& fmt = cvtest::g_specific_fmt_list[testcase]; + if( fmt.empty() ) + break; + string filename = getFilename(fmt); + ts->printf(ts->LOG, "\nFile: %s\n", filename.c_str()); + + if( !CreateTestVideo(fmt, n_frames, filename) ) + { + ts->printf(ts->LOG, "\nError: cannot create video file"); + ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); + return; + } + + VideoCapture cap(filename); + + if (!cap.isOpened()) + { + ts->printf(ts->LOG, "\nError: cannot read video file."); + ts->set_failed_test_info(ts->FAIL_INVALID_TEST_DATA); + return; + } + + int N0 = (int)cap.get(CV_CAP_PROP_FRAME_COUNT); + cap.set(CV_CAP_PROP_POS_FRAMES, 0); + int N = (int)cap.get(CV_CAP_PROP_FRAME_COUNT); + + if (N != n_frames || N != N0) + { + ts->printf(ts->LOG, "\nError: returned frame count (N0=%d, N=%d) is different from the reference number %d\n", N0, N, n_frames); + ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); + return; + } + + for (int k = 0; k < N; ++k) + { + int idx = theRNG().uniform(0, N); + + if( !cap.set(CV_CAP_PROP_POS_FRAMES, idx) ) + { + ts->printf(ts->LOG, "\nError: cannot seek to frame %d.\n", idx); + ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); + return; + } + + int idx1 = (int)cap.get(CV_CAP_PROP_POS_FRAMES); + + Mat img; cap >> img; + Mat img0 = drawFrame(idx); + + if( idx != idx1 ) + { + ts->printf(ts->LOG, "\nError: the current position (%d) after seek is different from specified (%d)\n", + idx1, idx); + ts->printf(ts->LOG, "Saving both frames ...\n"); + ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); + // imwrite("opencv_test_highgui_postest_actual.png", img); + // imwrite("opencv_test_highgui_postest_expected.png", img0); + return; + } + + if (img.empty()) + { + ts->printf(ts->LOG, "\nError: cannot read a frame at position %d.\n", idx); + ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); + return; + } + + double err = PSNR(img, img0); + + if( err < 20 ) + { + ts->printf(ts->LOG, "The frame read after positioning to %d is incorrect (PSNR=%g)\n", idx, err); + ts->printf(ts->LOG, "Saving both frames ...\n"); + ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); + // imwrite("opencv_test_highgui_postest_actual.png", img); + // imwrite("opencv_test_highgui_postest_expected.png", img0); + return; + } + } + } + } + + Size framesize; +}; + +#if BUILD_WITH_VIDEO_INPUT_SUPPORT && BUILD_WITH_VIDEO_OUTPUT_SUPPORT +TEST(Highgui_Video, seek_random_synthetic) { CV_PositioningTest test; test.safe_run(); } +#endif diff --git a/imgproc/.DS_Store b/imgproc/.DS_Store new file mode 100644 index 0000000..38f9a42 Binary files /dev/null and b/imgproc/.DS_Store differ diff --git a/imgproc/.imgproc/CMakeFiles/CMakeDirectoryInformation.cmake b/imgproc/.imgproc/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000..18abf29 --- /dev/null +++ b/imgproc/.imgproc/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Relative path conversion top directories. +SET(CMAKE_RELATIVE_PATH_TOP_SOURCE "/Users/beau/Documents/workspace/OpenCV/opencv") +SET(CMAKE_RELATIVE_PATH_TOP_BINARY "/Users/beau/Documents/workspace/OpenCV/opencv") + +# Force unix paths in dependencies. +SET(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +SET(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +SET(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +SET(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +SET(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/imgproc/.imgproc/CMakeFiles/progress.marks b/imgproc/.imgproc/CMakeFiles/progress.marks new file mode 100644 index 0000000..573541a --- /dev/null +++ b/imgproc/.imgproc/CMakeFiles/progress.marks @@ -0,0 +1 @@ +0 diff --git a/imgproc/.imgproc/Makefile b/imgproc/.imgproc/Makefile new file mode 100644 index 0000000..d047a7c --- /dev/null +++ b/imgproc/.imgproc/Makefile @@ -0,0 +1,167 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." + /opt/local/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /opt/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: install/local +.PHONY : install/local/fast + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /opt/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: install/strip +.PHONY : install/strip/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\" \"main\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /opt/local/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_progress_start /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/.imgproc/CMakeFiles/progress.marks + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/imgproc/.imgproc/all + $(CMAKE_COMMAND) -E cmake_progress_start /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/imgproc/.imgproc/clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/imgproc/.imgproc/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/imgproc/.imgproc/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... rebuild_cache" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/imgproc/.imgproc/cmake_install.cmake b/imgproc/.imgproc/cmake_install.cmake new file mode 100644 index 0000000..e563347 --- /dev/null +++ b/imgproc/.imgproc/cmake_install.cmake @@ -0,0 +1,29 @@ +# Install script for directory: /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc + +# Set the install prefix +IF(NOT DEFINED CMAKE_INSTALL_PREFIX) + SET(CMAKE_INSTALL_PREFIX "/usr/local") +ENDIF(NOT DEFINED CMAKE_INSTALL_PREFIX) +STRING(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +IF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + IF(BUILD_TYPE) + STRING(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + ELSE(BUILD_TYPE) + SET(CMAKE_INSTALL_CONFIG_NAME "Release") + ENDIF(BUILD_TYPE) + MESSAGE(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +ENDIF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + +# Set the component getting installed. +IF(NOT CMAKE_INSTALL_COMPONENT) + IF(COMPONENT) + MESSAGE(STATUS "Install component: \"${COMPONENT}\"") + SET(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + ELSE(COMPONENT) + SET(CMAKE_INSTALL_COMPONENT) + ENDIF(COMPONENT) +ENDIF(NOT CMAKE_INSTALL_COMPONENT) + diff --git a/imgproc/CMakeFiles/CMakeDirectoryInformation.cmake b/imgproc/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000..18abf29 --- /dev/null +++ b/imgproc/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Relative path conversion top directories. +SET(CMAKE_RELATIVE_PATH_TOP_SOURCE "/Users/beau/Documents/workspace/OpenCV/opencv") +SET(CMAKE_RELATIVE_PATH_TOP_BINARY "/Users/beau/Documents/workspace/OpenCV/opencv") + +# Force unix paths in dependencies. +SET(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +SET(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +SET(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +SET(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +SET(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/imgproc/CMakeFiles/opencv_imgproc.dir/DependInfo.cmake b/imgproc/CMakeFiles/opencv_imgproc.dir/DependInfo.cmake new file mode 100644 index 0000000..cf279fa --- /dev/null +++ b/imgproc/CMakeFiles/opencv_imgproc.dir/DependInfo.cmake @@ -0,0 +1,88 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/accum.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/approx.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/canny.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/color.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/contours.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/convhull.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/corner.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/cornersubpix.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/deriv.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/distransform.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/emd.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/featureselect.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/filter.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/floodfill.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/gabor.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/geometry.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/grabcut.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/histogram.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/hough.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/imgwarp.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/linefit.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/matchcontours.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/moments.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/morph.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/phasecorr.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/precomp.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/pyramids.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/rotcalipers.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/samplers.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/segmentation.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/shapedescr.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/smooth.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/subdivision2d.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/sumpixels.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/tables.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/templmatch.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/thresh.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/undistort.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/utils.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "Clang") + +# Preprocessor definitions for this target. +SET(CMAKE_TARGET_DEFINITIONS + "HAVE_CVCONFIG_H" + "HAVE_ALLOCA" + "HAVE_ALLOCA_H" + "HAVE_LIBPTHREAD" + "HAVE_UNISTD_H" + "CVAPI_EXPORTS" + ) + +# Pairs of files generated by the same build rule. +SET(CMAKE_MULTIPLE_OUTPUT_PAIRS + "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_imgproc.2.4.dylib" "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_imgproc.2.4.9.dylib" + "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_imgproc.dylib" "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_imgproc.2.4.9.dylib" + ) + + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib/CMakeFiles/zlib.dir/DependInfo.cmake" + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "modules/imgproc/perf" + "modules/highgui/include" + "modules/ts/include" + "modules/imgproc/include" + "modules/core/include" + "modules/imgproc" + "modules/imgproc/src" + "modules/imgproc/test" + "." + "/opt/local/include" + "/opt/local/include/eigen3" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/imgproc/CMakeFiles/opencv_imgproc.dir/build.make b/imgproc/CMakeFiles/opencv_imgproc.dir/build.make new file mode 100644 index 0000000..a1b41ad --- /dev/null +++ b/imgproc/CMakeFiles/opencv_imgproc.dir/build.make @@ -0,0 +1,1097 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# Include any dependencies generated for this target. +include modules/imgproc/CMakeFiles/opencv_imgproc.dir/depend.make + +# Include the progress variables for this target. +include modules/imgproc/CMakeFiles/opencv_imgproc.dir/progress.make + +# Include the compile flags for this target's objects. +include modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o: modules/imgproc/src/accum.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/accum.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/accum.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/accum.cpp > CMakeFiles/opencv_imgproc.dir/src/accum.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/accum.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/accum.cpp -o CMakeFiles/opencv_imgproc.dir/src/accum.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o: modules/imgproc/src/approx.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_2) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/approx.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/approx.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/approx.cpp > CMakeFiles/opencv_imgproc.dir/src/approx.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/approx.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/approx.cpp -o CMakeFiles/opencv_imgproc.dir/src/approx.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o: modules/imgproc/src/canny.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_3) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/canny.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/canny.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/canny.cpp > CMakeFiles/opencv_imgproc.dir/src/canny.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/canny.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/canny.cpp -o CMakeFiles/opencv_imgproc.dir/src/canny.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o: modules/imgproc/src/color.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_4) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/color.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/color.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/color.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/color.cpp > CMakeFiles/opencv_imgproc.dir/src/color.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/color.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/color.cpp -o CMakeFiles/opencv_imgproc.dir/src/color.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o: modules/imgproc/src/contours.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_5) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/contours.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/contours.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/contours.cpp > CMakeFiles/opencv_imgproc.dir/src/contours.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/contours.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/contours.cpp -o CMakeFiles/opencv_imgproc.dir/src/contours.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o: modules/imgproc/src/convhull.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_6) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/convhull.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/convhull.cpp > CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/convhull.cpp -o CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o: modules/imgproc/src/corner.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_7) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/corner.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/corner.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/corner.cpp > CMakeFiles/opencv_imgproc.dir/src/corner.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/corner.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/corner.cpp -o CMakeFiles/opencv_imgproc.dir/src/corner.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o: modules/imgproc/src/cornersubpix.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_8) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/cornersubpix.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/cornersubpix.cpp > CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/cornersubpix.cpp -o CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o: modules/imgproc/src/deriv.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_9) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/deriv.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/deriv.cpp > CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/deriv.cpp -o CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o: modules/imgproc/src/distransform.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_10) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/distransform.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/distransform.cpp > CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/distransform.cpp -o CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o: modules/imgproc/src/emd.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_11) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/emd.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/emd.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/emd.cpp > CMakeFiles/opencv_imgproc.dir/src/emd.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/emd.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/emd.cpp -o CMakeFiles/opencv_imgproc.dir/src/emd.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o: modules/imgproc/src/featureselect.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_12) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/featureselect.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/featureselect.cpp > CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/featureselect.cpp -o CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o: modules/imgproc/src/filter.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_13) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/filter.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/filter.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/filter.cpp > CMakeFiles/opencv_imgproc.dir/src/filter.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/filter.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/filter.cpp -o CMakeFiles/opencv_imgproc.dir/src/filter.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o: modules/imgproc/src/floodfill.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_14) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/floodfill.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/floodfill.cpp > CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/floodfill.cpp -o CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o: modules/imgproc/src/gabor.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_15) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/gabor.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/gabor.cpp > CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/gabor.cpp -o CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o: modules/imgproc/src/geometry.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_16) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/geometry.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/geometry.cpp > CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/geometry.cpp -o CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o: modules/imgproc/src/grabcut.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_17) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/grabcut.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/grabcut.cpp > CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/grabcut.cpp -o CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o: modules/imgproc/src/histogram.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_18) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/histogram.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/histogram.cpp > CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/histogram.cpp -o CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o: modules/imgproc/src/hough.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_19) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/hough.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/hough.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/hough.cpp > CMakeFiles/opencv_imgproc.dir/src/hough.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/hough.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/hough.cpp -o CMakeFiles/opencv_imgproc.dir/src/hough.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o: modules/imgproc/src/imgwarp.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_20) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/imgwarp.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/imgwarp.cpp > CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/imgwarp.cpp -o CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o: modules/imgproc/src/linefit.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_21) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/linefit.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/linefit.cpp > CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/linefit.cpp -o CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o: modules/imgproc/src/matchcontours.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_22) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/matchcontours.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/matchcontours.cpp > CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/matchcontours.cpp -o CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o: modules/imgproc/src/moments.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_23) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/moments.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/moments.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/moments.cpp > CMakeFiles/opencv_imgproc.dir/src/moments.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/moments.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/moments.cpp -o CMakeFiles/opencv_imgproc.dir/src/moments.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o: modules/imgproc/src/morph.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_24) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/morph.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/morph.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/morph.cpp > CMakeFiles/opencv_imgproc.dir/src/morph.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/morph.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/morph.cpp -o CMakeFiles/opencv_imgproc.dir/src/morph.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o: modules/imgproc/src/phasecorr.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_25) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/phasecorr.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/phasecorr.cpp > CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/phasecorr.cpp -o CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o: modules/imgproc/src/precomp.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_26) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/precomp.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/precomp.cpp > CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/precomp.cpp -o CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o: modules/imgproc/src/pyramids.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_27) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/pyramids.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/pyramids.cpp > CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/pyramids.cpp -o CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o: modules/imgproc/src/rotcalipers.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_28) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/rotcalipers.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/rotcalipers.cpp > CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/rotcalipers.cpp -o CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o: modules/imgproc/src/samplers.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_29) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/samplers.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/samplers.cpp > CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/samplers.cpp -o CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o: modules/imgproc/src/segmentation.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_30) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/segmentation.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/segmentation.cpp > CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/segmentation.cpp -o CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o: modules/imgproc/src/shapedescr.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_31) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/shapedescr.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/shapedescr.cpp > CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/shapedescr.cpp -o CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o: modules/imgproc/src/smooth.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_32) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/smooth.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/smooth.cpp > CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/smooth.cpp -o CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o: modules/imgproc/src/subdivision2d.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_33) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/subdivision2d.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/subdivision2d.cpp > CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/subdivision2d.cpp -o CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o: modules/imgproc/src/sumpixels.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_34) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/sumpixels.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/sumpixels.cpp > CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/sumpixels.cpp -o CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o: modules/imgproc/src/tables.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_35) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/tables.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/tables.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/tables.cpp > CMakeFiles/opencv_imgproc.dir/src/tables.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/tables.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/tables.cpp -o CMakeFiles/opencv_imgproc.dir/src/tables.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o: modules/imgproc/src/templmatch.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_36) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/templmatch.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/templmatch.cpp > CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/templmatch.cpp -o CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o: modules/imgproc/src/thresh.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_37) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/thresh.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/thresh.cpp > CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/thresh.cpp -o CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o: modules/imgproc/src/undistort.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_38) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/undistort.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/undistort.cpp > CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/undistort.cpp -o CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o: modules/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o: modules/imgproc/src/utils.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_39) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/utils.cpp + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_imgproc.dir/src/utils.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/utils.cpp > CMakeFiles/opencv_imgproc.dir/src/utils.cpp.i + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_imgproc.dir/src/utils.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src/utils.cpp -o CMakeFiles/opencv_imgproc.dir/src/utils.cpp.s + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o + +# Object files for target opencv_imgproc +opencv_imgproc_OBJECTS = \ +"CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/color.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o" \ +"CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o" + +# External object files for target opencv_imgproc +opencv_imgproc_EXTERNAL_OBJECTS = + +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make +lib/libopencv_imgproc.2.4.9.dylib: lib/libopencv_core.2.4.9.dylib +lib/libopencv_imgproc.2.4.9.dylib: 3rdparty/lib/libzlib.a +lib/libopencv_imgproc.2.4.9.dylib: modules/imgproc/CMakeFiles/opencv_imgproc.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX shared library ../../lib/libopencv_imgproc.dylib" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/opencv_imgproc.dir/link.txt --verbose=$(VERBOSE) + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && $(CMAKE_COMMAND) -E cmake_symlink_library ../../lib/libopencv_imgproc.2.4.9.dylib ../../lib/libopencv_imgproc.2.4.dylib ../../lib/libopencv_imgproc.dylib + +lib/libopencv_imgproc.2.4.dylib: lib/libopencv_imgproc.2.4.9.dylib + +lib/libopencv_imgproc.dylib: lib/libopencv_imgproc.2.4.9.dylib + +# Rule to build all files generated by this target. +modules/imgproc/CMakeFiles/opencv_imgproc.dir/build: lib/libopencv_imgproc.dylib +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/build + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o.requires +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/requires + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && $(CMAKE_COMMAND) -P CMakeFiles/opencv_imgproc.dir/cmake_clean.cmake +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/clean + +modules/imgproc/CMakeFiles/opencv_imgproc.dir/depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/depend + diff --git a/imgproc/CMakeFiles/opencv_imgproc.dir/cmake_clean.cmake b/imgproc/CMakeFiles/opencv_imgproc.dir/cmake_clean.cmake new file mode 100644 index 0000000..f3bd6bd --- /dev/null +++ b/imgproc/CMakeFiles/opencv_imgproc.dir/cmake_clean.cmake @@ -0,0 +1,50 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/color.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o" + "CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o" + "../../lib/libopencv_imgproc.pdb" + "../../lib/libopencv_imgproc.dylib" + "../../lib/libopencv_imgproc.2.4.9.dylib" + "../../lib/libopencv_imgproc.2.4.dylib" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/opencv_imgproc.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/imgproc/CMakeFiles/opencv_imgproc.dir/depend.make b/imgproc/CMakeFiles/opencv_imgproc.dir/depend.make new file mode 100644 index 0000000..3c7b48b --- /dev/null +++ b/imgproc/CMakeFiles/opencv_imgproc.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for opencv_imgproc. +# This may be replaced when dependencies are built. diff --git a/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make b/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make new file mode 100644 index 0000000..ea478a1 --- /dev/null +++ b/imgproc/CMakeFiles/opencv_imgproc.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -O3 -DNDEBUG -fPIC -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test -I/Users/beau/Documents/workspace/OpenCV/opencv -I/opt/local/include -I/opt/local/include/eigen3 + +CXX_DEFINES = -Dopencv_imgproc_EXPORTS -DHAVE_CVCONFIG_H -DHAVE_ALLOCA -DHAVE_ALLOCA_H -DHAVE_LIBPTHREAD -DHAVE_UNISTD_H -DCVAPI_EXPORTS + diff --git a/imgproc/CMakeFiles/opencv_imgproc.dir/link.txt b/imgproc/CMakeFiles/opencv_imgproc.dir/link.txt new file mode 100644 index 0000000..3880c8f --- /dev/null +++ b/imgproc/CMakeFiles/opencv_imgproc.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -O3 -DNDEBUG -shared -compatibility_version 2.4.0 -current_version 2.4.9 -o ../../lib/libopencv_imgproc.2.4.9.dylib -install_name /Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_imgproc.2.4.dylib CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o CMakeFiles/opencv_imgproc.dir/src/color.cpp.o CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib/gcc -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib ../../lib/libopencv_core.2.4.9.dylib ../../3rdparty/lib/libzlib.a diff --git a/imgproc/CMakeFiles/opencv_imgproc.dir/progress.make b/imgproc/CMakeFiles/opencv_imgproc.dir/progress.make new file mode 100644 index 0000000..1b16177 --- /dev/null +++ b/imgproc/CMakeFiles/opencv_imgproc.dir/progress.make @@ -0,0 +1,40 @@ +CMAKE_PROGRESS_1 = +CMAKE_PROGRESS_2 = +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = +CMAKE_PROGRESS_5 = +CMAKE_PROGRESS_6 = +CMAKE_PROGRESS_7 = +CMAKE_PROGRESS_8 = 41 +CMAKE_PROGRESS_9 = +CMAKE_PROGRESS_10 = +CMAKE_PROGRESS_11 = +CMAKE_PROGRESS_12 = +CMAKE_PROGRESS_13 = +CMAKE_PROGRESS_14 = +CMAKE_PROGRESS_15 = +CMAKE_PROGRESS_16 = 42 +CMAKE_PROGRESS_17 = +CMAKE_PROGRESS_18 = +CMAKE_PROGRESS_19 = +CMAKE_PROGRESS_20 = +CMAKE_PROGRESS_21 = +CMAKE_PROGRESS_22 = +CMAKE_PROGRESS_23 = 43 +CMAKE_PROGRESS_24 = +CMAKE_PROGRESS_25 = +CMAKE_PROGRESS_26 = +CMAKE_PROGRESS_27 = +CMAKE_PROGRESS_28 = +CMAKE_PROGRESS_29 = +CMAKE_PROGRESS_30 = +CMAKE_PROGRESS_31 = 44 +CMAKE_PROGRESS_32 = +CMAKE_PROGRESS_33 = +CMAKE_PROGRESS_34 = +CMAKE_PROGRESS_35 = +CMAKE_PROGRESS_36 = +CMAKE_PROGRESS_37 = +CMAKE_PROGRESS_38 = +CMAKE_PROGRESS_39 = 45 + diff --git a/imgproc/CMakeFiles/opencv_perf_imgproc.dir/DependInfo.cmake b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/DependInfo.cmake new file mode 100644 index 0000000..afce65a --- /dev/null +++ b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/DependInfo.cmake @@ -0,0 +1,66 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_bilateral.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_blur.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_canny.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_cornerEigenValsAndVecs.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_cornerHarris.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_cvt_color.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_distanceTransform.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_filter2d.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_goodFeaturesToTrack.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_histogram.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_houghLines.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_integral.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_main.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_morph.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_precomp.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_pyramids.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_remap.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_resize.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_sepfilters.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_threshold.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_warp.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "Clang") + +# Preprocessor definitions for this target. +SET(CMAKE_TARGET_DEFINITIONS + "HAVE_CVCONFIG_H" + "HAVE_ALLOCA" + "HAVE_ALLOCA_H" + "HAVE_LIBPTHREAD" + "HAVE_UNISTD_H" + "CVAPI_EXPORTS" + ) + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/CMakeFiles/opencv_ts.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib/CMakeFiles/zlib.dir/DependInfo.cmake" + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "modules/imgproc/perf" + "modules/highgui/include" + "modules/ts/include" + "modules/imgproc/include" + "modules/core/include" + "modules/imgproc" + "modules/imgproc/src" + "modules/imgproc/test" + "." + "/opt/local/include" + "/opt/local/include/eigen3" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make new file mode 100644 index 0000000..0db44e3 --- /dev/null +++ b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make @@ -0,0 +1,629 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# Include any dependencies generated for this target. +include modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/depend.make + +# Include the progress variables for this target. +include modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/progress.make + +# Include the compile flags for this target's objects. +include modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o: modules/imgproc/perf/perf_bilateral.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_bilateral.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_bilateral.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_bilateral.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o: modules/imgproc/perf/perf_blur.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_2) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_blur.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_blur.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_blur.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o: modules/imgproc/perf/perf_canny.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_3) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_canny.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_canny.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_canny.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o: modules/imgproc/perf/perf_cornerEigenValsAndVecs.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_4) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_cornerEigenValsAndVecs.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_cornerEigenValsAndVecs.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_cornerEigenValsAndVecs.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o: modules/imgproc/perf/perf_cornerHarris.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_5) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_cornerHarris.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_cornerHarris.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_cornerHarris.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o: modules/imgproc/perf/perf_cvt_color.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_6) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_cvt_color.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_cvt_color.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_cvt_color.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o: modules/imgproc/perf/perf_distanceTransform.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_7) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_distanceTransform.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_distanceTransform.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_distanceTransform.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o: modules/imgproc/perf/perf_filter2d.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_8) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_filter2d.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_filter2d.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_filter2d.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o: modules/imgproc/perf/perf_goodFeaturesToTrack.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_9) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_goodFeaturesToTrack.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_goodFeaturesToTrack.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_goodFeaturesToTrack.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o: modules/imgproc/perf/perf_histogram.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_10) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_histogram.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_histogram.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_histogram.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o: modules/imgproc/perf/perf_houghLines.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_11) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_houghLines.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_houghLines.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_houghLines.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o: modules/imgproc/perf/perf_integral.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_12) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_integral.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_integral.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_integral.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o: modules/imgproc/perf/perf_main.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_13) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_main.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_main.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_main.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o: modules/imgproc/perf/perf_morph.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_14) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_morph.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_morph.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_morph.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o: modules/imgproc/perf/perf_precomp.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_15) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_precomp.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_precomp.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_precomp.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o: modules/imgproc/perf/perf_pyramids.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_16) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_pyramids.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_pyramids.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_pyramids.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o: modules/imgproc/perf/perf_remap.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_17) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_remap.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_remap.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_remap.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o: modules/imgproc/perf/perf_resize.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_18) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_resize.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_resize.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_resize.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o: modules/imgproc/perf/perf_sepfilters.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_19) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_sepfilters.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_sepfilters.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_sepfilters.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o: modules/imgproc/perf/perf_threshold.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_20) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_threshold.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_threshold.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_threshold.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o: modules/imgproc/perf/perf_warp.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_21) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_warp.cpp + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_warp.cpp > CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.i + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf/perf_warp.cpp -o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.s + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o + +# Object files for target opencv_perf_imgproc +opencv_perf_imgproc_OBJECTS = \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o" \ +"CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o" + +# External object files for target opencv_perf_imgproc +opencv_perf_imgproc_EXTERNAL_OBJECTS = + +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make +bin/opencv_perf_imgproc: lib/libopencv_core.2.4.9.dylib +bin/opencv_perf_imgproc: lib/libopencv_imgproc.2.4.9.dylib +bin/opencv_perf_imgproc: lib/libopencv_ts.2.4.9.dylib +bin/opencv_perf_imgproc: lib/libopencv_highgui.2.4.9.dylib +bin/opencv_perf_imgproc: lib/libopencv_imgproc.2.4.9.dylib +bin/opencv_perf_imgproc: lib/libopencv_core.2.4.9.dylib +bin/opencv_perf_imgproc: 3rdparty/lib/libzlib.a +bin/opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX executable ../../bin/opencv_perf_imgproc" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/opencv_perf_imgproc.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build: bin/opencv_perf_imgproc +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o.requires +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/requires + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && $(CMAKE_COMMAND) -P CMakeFiles/opencv_perf_imgproc.dir/cmake_clean.cmake +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/clean + +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/depend + diff --git a/imgproc/CMakeFiles/opencv_perf_imgproc.dir/cmake_clean.cmake b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/cmake_clean.cmake new file mode 100644 index 0000000..2ce09c4 --- /dev/null +++ b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/cmake_clean.cmake @@ -0,0 +1,30 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o" + "CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o" + "../../bin/opencv_perf_imgproc.pdb" + "../../bin/opencv_perf_imgproc" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/opencv_perf_imgproc.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/imgproc/CMakeFiles/opencv_perf_imgproc.dir/depend.make b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/depend.make new file mode 100644 index 0000000..8b620d3 --- /dev/null +++ b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for opencv_perf_imgproc. +# This may be replaced when dependencies are built. diff --git a/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make new file mode 100644 index 0000000..5a6ef99 --- /dev/null +++ b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -O3 -DNDEBUG -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test -I/Users/beau/Documents/workspace/OpenCV/opencv -I/opt/local/include -I/opt/local/include/eigen3 + +CXX_DEFINES = -DHAVE_CVCONFIG_H -DHAVE_ALLOCA -DHAVE_ALLOCA_H -DHAVE_LIBPTHREAD -DHAVE_UNISTD_H -DCVAPI_EXPORTS + diff --git a/imgproc/CMakeFiles/opencv_perf_imgproc.dir/link.txt b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/link.txt new file mode 100644 index 0000000..81a7fa6 --- /dev/null +++ b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -O3 -DNDEBUG -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o -o ../../bin/opencv_perf_imgproc -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib/gcc -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib ../../lib/libopencv_core.2.4.9.dylib ../../lib/libopencv_imgproc.2.4.9.dylib ../../lib/libopencv_ts.2.4.9.dylib ../../lib/libopencv_highgui.2.4.9.dylib ../../lib/libopencv_imgproc.2.4.9.dylib ../../lib/libopencv_core.2.4.9.dylib ../../3rdparty/lib/libzlib.a diff --git a/imgproc/CMakeFiles/opencv_perf_imgproc.dir/progress.make b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/progress.make new file mode 100644 index 0000000..93fdf1d --- /dev/null +++ b/imgproc/CMakeFiles/opencv_perf_imgproc.dir/progress.make @@ -0,0 +1,22 @@ +CMAKE_PROGRESS_1 = +CMAKE_PROGRESS_2 = +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = +CMAKE_PROGRESS_5 = +CMAKE_PROGRESS_6 = 68 +CMAKE_PROGRESS_7 = +CMAKE_PROGRESS_8 = +CMAKE_PROGRESS_9 = +CMAKE_PROGRESS_10 = +CMAKE_PROGRESS_11 = +CMAKE_PROGRESS_12 = +CMAKE_PROGRESS_13 = +CMAKE_PROGRESS_14 = 69 +CMAKE_PROGRESS_15 = +CMAKE_PROGRESS_16 = +CMAKE_PROGRESS_17 = +CMAKE_PROGRESS_18 = +CMAKE_PROGRESS_19 = +CMAKE_PROGRESS_20 = +CMAKE_PROGRESS_21 = 70 + diff --git a/imgproc/CMakeFiles/opencv_test_imgproc.dir/DependInfo.cmake b/imgproc/CMakeFiles/opencv_test_imgproc.dir/DependInfo.cmake new file mode 100644 index 0000000..0d15fd4 --- /dev/null +++ b/imgproc/CMakeFiles/opencv_test_imgproc.dir/DependInfo.cmake @@ -0,0 +1,67 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_approxpoly.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_bilateral_filter.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_boundingrect.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_canny.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_color.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_contours.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_convhull.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_cvtyuv.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_distancetransform.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_emd.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_filter.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_floodfill.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_grabcut.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_histograms.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_imgwarp.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_main.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_moments.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_pc.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_precomp.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_templmatch.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_thresh.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_watershed.cpp" "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "Clang") + +# Preprocessor definitions for this target. +SET(CMAKE_TARGET_DEFINITIONS + "HAVE_CVCONFIG_H" + "HAVE_ALLOCA" + "HAVE_ALLOCA_H" + "HAVE_LIBPTHREAD" + "HAVE_UNISTD_H" + "CVAPI_EXPORTS" + ) + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/CMakeFiles/opencv_core.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_imgproc.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/CMakeFiles/opencv_ts.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/CMakeFiles/opencv_highgui.dir/DependInfo.cmake" + "/Users/beau/Documents/workspace/OpenCV/opencv/3rdparty/zlib/CMakeFiles/zlib.dir/DependInfo.cmake" + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "modules/imgproc/perf" + "modules/highgui/include" + "modules/ts/include" + "modules/imgproc/include" + "modules/core/include" + "modules/imgproc" + "modules/imgproc/src" + "modules/imgproc/test" + "." + "/opt/local/include" + "/opt/local/include/eigen3" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make b/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make new file mode 100644 index 0000000..1997503 --- /dev/null +++ b/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make @@ -0,0 +1,655 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# Include any dependencies generated for this target. +include modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/depend.make + +# Include the progress variables for this target. +include modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/progress.make + +# Include the compile flags for this target's objects. +include modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o: modules/imgproc/test/test_approxpoly.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_approxpoly.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_approxpoly.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_approxpoly.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o: modules/imgproc/test/test_bilateral_filter.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_2) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_bilateral_filter.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_bilateral_filter.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_bilateral_filter.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o: modules/imgproc/test/test_boundingrect.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_3) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_boundingrect.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_boundingrect.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_boundingrect.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o: modules/imgproc/test/test_canny.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_4) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_canny.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_canny.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_canny.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o: modules/imgproc/test/test_color.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_5) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_color.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_color.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_color.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o: modules/imgproc/test/test_contours.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_6) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_contours.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_contours.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_contours.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o: modules/imgproc/test/test_convhull.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_7) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_convhull.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_convhull.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_convhull.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o: modules/imgproc/test/test_cvtyuv.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_8) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_cvtyuv.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_cvtyuv.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_cvtyuv.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o: modules/imgproc/test/test_distancetransform.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_9) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_distancetransform.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_distancetransform.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_distancetransform.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o: modules/imgproc/test/test_emd.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_10) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_emd.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_emd.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_emd.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o: modules/imgproc/test/test_filter.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_11) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_filter.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_filter.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_filter.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o: modules/imgproc/test/test_floodfill.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_12) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_floodfill.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_floodfill.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_floodfill.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o: modules/imgproc/test/test_grabcut.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_13) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_grabcut.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_grabcut.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_grabcut.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o: modules/imgproc/test/test_histograms.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_14) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_histograms.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_histograms.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_histograms.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o: modules/imgproc/test/test_imgwarp.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_15) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_imgwarp.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_imgwarp.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_imgwarp.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o: modules/imgproc/test/test_main.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_16) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_main.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_main.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_main.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o: modules/imgproc/test/test_moments.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_17) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_moments.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_moments.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_moments.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o: modules/imgproc/test/test_pc.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_18) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_pc.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_pc.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_pc.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o: modules/imgproc/test/test_precomp.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_19) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_precomp.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_precomp.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_precomp.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o: modules/imgproc/test/test_templmatch.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_20) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_templmatch.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_templmatch.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_templmatch.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o: modules/imgproc/test/test_thresh.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_21) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_thresh.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_thresh.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_thresh.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o: modules/imgproc/test/test_watershed.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles $(CMAKE_PROGRESS_22) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o -c /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_watershed.cpp + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.i" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_watershed.cpp > CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.i + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.s" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test/test_watershed.cpp -o CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.s + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o.requires: +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o.requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o.provides: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o.requires + $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o.provides.build +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o.provides + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o.provides.build: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o + +# Object files for target opencv_test_imgproc +opencv_test_imgproc_OBJECTS = \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o" \ +"CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o" + +# External object files for target opencv_test_imgproc +opencv_test_imgproc_EXTERNAL_OBJECTS = + +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make +bin/opencv_test_imgproc: lib/libopencv_core.2.4.9.dylib +bin/opencv_test_imgproc: lib/libopencv_imgproc.2.4.9.dylib +bin/opencv_test_imgproc: lib/libopencv_ts.2.4.9.dylib +bin/opencv_test_imgproc: lib/libopencv_highgui.2.4.9.dylib +bin/opencv_test_imgproc: lib/libopencv_imgproc.2.4.9.dylib +bin/opencv_test_imgproc: lib/libopencv_core.2.4.9.dylib +bin/opencv_test_imgproc: 3rdparty/lib/libzlib.a +bin/opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX executable ../../bin/opencv_test_imgproc" + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/opencv_test_imgproc.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build: bin/opencv_test_imgproc +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o.requires +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o.requires +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/requires + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc && $(CMAKE_COMMAND) -P CMakeFiles/opencv_test_imgproc.dir/cmake_clean.cmake +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/clean + +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc /Users/beau/Documents/workspace/OpenCV/opencv /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/depend + diff --git a/imgproc/CMakeFiles/opencv_test_imgproc.dir/cmake_clean.cmake b/imgproc/CMakeFiles/opencv_test_imgproc.dir/cmake_clean.cmake new file mode 100644 index 0000000..9ce2ad6 --- /dev/null +++ b/imgproc/CMakeFiles/opencv_test_imgproc.dir/cmake_clean.cmake @@ -0,0 +1,31 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o" + "CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o" + "../../bin/opencv_test_imgproc.pdb" + "../../bin/opencv_test_imgproc" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/opencv_test_imgproc.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/imgproc/CMakeFiles/opencv_test_imgproc.dir/depend.make b/imgproc/CMakeFiles/opencv_test_imgproc.dir/depend.make new file mode 100644 index 0000000..659e22e --- /dev/null +++ b/imgproc/CMakeFiles/opencv_test_imgproc.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for opencv_test_imgproc. +# This may be replaced when dependencies are built. diff --git a/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make b/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make new file mode 100644 index 0000000..5a6ef99 --- /dev/null +++ b/imgproc/CMakeFiles/opencv_test_imgproc.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -O3 -DNDEBUG -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/perf -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/highgui/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/ts/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/core/include -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/src -I/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/test -I/Users/beau/Documents/workspace/OpenCV/opencv -I/opt/local/include -I/opt/local/include/eigen3 + +CXX_DEFINES = -DHAVE_CVCONFIG_H -DHAVE_ALLOCA -DHAVE_ALLOCA_H -DHAVE_LIBPTHREAD -DHAVE_UNISTD_H -DCVAPI_EXPORTS + diff --git a/imgproc/CMakeFiles/opencv_test_imgproc.dir/link.txt b/imgproc/CMakeFiles/opencv_test_imgproc.dir/link.txt new file mode 100644 index 0000000..9f41aff --- /dev/null +++ b/imgproc/CMakeFiles/opencv_test_imgproc.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -O3 -DNDEBUG -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o -o ../../bin/opencv_test_imgproc -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib/gcc -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 -L/usr/llvm-gcc-4.2/lib -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib ../../lib/libopencv_core.2.4.9.dylib ../../lib/libopencv_imgproc.2.4.9.dylib ../../lib/libopencv_ts.2.4.9.dylib ../../lib/libopencv_highgui.2.4.9.dylib ../../lib/libopencv_imgproc.2.4.9.dylib ../../lib/libopencv_core.2.4.9.dylib ../../3rdparty/lib/libzlib.a diff --git a/imgproc/CMakeFiles/opencv_test_imgproc.dir/progress.make b/imgproc/CMakeFiles/opencv_test_imgproc.dir/progress.make new file mode 100644 index 0000000..c620eee --- /dev/null +++ b/imgproc/CMakeFiles/opencv_test_imgproc.dir/progress.make @@ -0,0 +1,23 @@ +CMAKE_PROGRESS_1 = 85 +CMAKE_PROGRESS_2 = +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = +CMAKE_PROGRESS_5 = +CMAKE_PROGRESS_6 = +CMAKE_PROGRESS_7 = +CMAKE_PROGRESS_8 = +CMAKE_PROGRESS_9 = 86 +CMAKE_PROGRESS_10 = +CMAKE_PROGRESS_11 = +CMAKE_PROGRESS_12 = +CMAKE_PROGRESS_13 = +CMAKE_PROGRESS_14 = +CMAKE_PROGRESS_15 = +CMAKE_PROGRESS_16 = +CMAKE_PROGRESS_17 = 87 +CMAKE_PROGRESS_18 = +CMAKE_PROGRESS_19 = +CMAKE_PROGRESS_20 = +CMAKE_PROGRESS_21 = +CMAKE_PROGRESS_22 = + diff --git a/imgproc/CMakeFiles/progress.marks b/imgproc/CMakeFiles/progress.marks new file mode 100644 index 0000000..81b5c5d --- /dev/null +++ b/imgproc/CMakeFiles/progress.marks @@ -0,0 +1 @@ +37 diff --git a/imgproc/CMakeLists.txt b/imgproc/CMakeLists.txt new file mode 100644 index 0000000..652d6e1 --- /dev/null +++ b/imgproc/CMakeLists.txt @@ -0,0 +1,2 @@ +set(the_description "Image Processing") +ocv_define_module(imgproc opencv_core) diff --git a/imgproc/Makefile b/imgproc/Makefile new file mode 100644 index 0000000..f748615 --- /dev/null +++ b/imgproc/Makefile @@ -0,0 +1,2426 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/beau/Documents/workspace/OpenCV/opencv + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." + /opt/local/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /opt/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: install/local +.PHONY : install/local/fast + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /opt/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: install/strip +.PHONY : install/strip/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\" \"main\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /opt/local/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -E cmake_progress_start /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/CMakeFiles/progress.marks + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/imgproc/all + $(CMAKE_COMMAND) -E cmake_progress_start /Users/beau/Documents/workspace/OpenCV/opencv/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/imgproc/clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/imgproc/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/imgproc/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Convenience name for target. +modules/imgproc/CMakeFiles/opencv_imgproc.dir/rule: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/imgproc/CMakeFiles/opencv_imgproc.dir/rule +.PHONY : modules/imgproc/CMakeFiles/opencv_imgproc.dir/rule + +# Convenience name for target. +opencv_imgproc: modules/imgproc/CMakeFiles/opencv_imgproc.dir/rule +.PHONY : opencv_imgproc + +# fast build rule for target. +opencv_imgproc/fast: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/build +.PHONY : opencv_imgproc/fast + +# Convenience name for target. +modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/rule: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/rule +.PHONY : modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/rule + +# Convenience name for target. +opencv_perf_imgproc: modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/rule +.PHONY : opencv_perf_imgproc + +# fast build rule for target. +opencv_perf_imgproc/fast: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build +.PHONY : opencv_perf_imgproc/fast + +# Convenience name for target. +modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/rule: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f CMakeFiles/Makefile2 modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/rule +.PHONY : modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/rule + +# Convenience name for target. +opencv_test_imgproc: modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/rule +.PHONY : opencv_test_imgproc + +# fast build rule for target. +opencv_test_imgproc/fast: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build +.PHONY : opencv_test_imgproc/fast + +perf/perf_bilateral.o: perf/perf_bilateral.cpp.o +.PHONY : perf/perf_bilateral.o + +# target to build an object file +perf/perf_bilateral.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.o +.PHONY : perf/perf_bilateral.cpp.o + +perf/perf_bilateral.i: perf/perf_bilateral.cpp.i +.PHONY : perf/perf_bilateral.i + +# target to preprocess a source file +perf/perf_bilateral.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.i +.PHONY : perf/perf_bilateral.cpp.i + +perf/perf_bilateral.s: perf/perf_bilateral.cpp.s +.PHONY : perf/perf_bilateral.s + +# target to generate assembly for a file +perf/perf_bilateral.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_bilateral.cpp.s +.PHONY : perf/perf_bilateral.cpp.s + +perf/perf_blur.o: perf/perf_blur.cpp.o +.PHONY : perf/perf_blur.o + +# target to build an object file +perf/perf_blur.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.o +.PHONY : perf/perf_blur.cpp.o + +perf/perf_blur.i: perf/perf_blur.cpp.i +.PHONY : perf/perf_blur.i + +# target to preprocess a source file +perf/perf_blur.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.i +.PHONY : perf/perf_blur.cpp.i + +perf/perf_blur.s: perf/perf_blur.cpp.s +.PHONY : perf/perf_blur.s + +# target to generate assembly for a file +perf/perf_blur.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_blur.cpp.s +.PHONY : perf/perf_blur.cpp.s + +perf/perf_canny.o: perf/perf_canny.cpp.o +.PHONY : perf/perf_canny.o + +# target to build an object file +perf/perf_canny.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.o +.PHONY : perf/perf_canny.cpp.o + +perf/perf_canny.i: perf/perf_canny.cpp.i +.PHONY : perf/perf_canny.i + +# target to preprocess a source file +perf/perf_canny.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.i +.PHONY : perf/perf_canny.cpp.i + +perf/perf_canny.s: perf/perf_canny.cpp.s +.PHONY : perf/perf_canny.s + +# target to generate assembly for a file +perf/perf_canny.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_canny.cpp.s +.PHONY : perf/perf_canny.cpp.s + +perf/perf_cornerEigenValsAndVecs.o: perf/perf_cornerEigenValsAndVecs.cpp.o +.PHONY : perf/perf_cornerEigenValsAndVecs.o + +# target to build an object file +perf/perf_cornerEigenValsAndVecs.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.o +.PHONY : perf/perf_cornerEigenValsAndVecs.cpp.o + +perf/perf_cornerEigenValsAndVecs.i: perf/perf_cornerEigenValsAndVecs.cpp.i +.PHONY : perf/perf_cornerEigenValsAndVecs.i + +# target to preprocess a source file +perf/perf_cornerEigenValsAndVecs.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.i +.PHONY : perf/perf_cornerEigenValsAndVecs.cpp.i + +perf/perf_cornerEigenValsAndVecs.s: perf/perf_cornerEigenValsAndVecs.cpp.s +.PHONY : perf/perf_cornerEigenValsAndVecs.s + +# target to generate assembly for a file +perf/perf_cornerEigenValsAndVecs.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerEigenValsAndVecs.cpp.s +.PHONY : perf/perf_cornerEigenValsAndVecs.cpp.s + +perf/perf_cornerHarris.o: perf/perf_cornerHarris.cpp.o +.PHONY : perf/perf_cornerHarris.o + +# target to build an object file +perf/perf_cornerHarris.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.o +.PHONY : perf/perf_cornerHarris.cpp.o + +perf/perf_cornerHarris.i: perf/perf_cornerHarris.cpp.i +.PHONY : perf/perf_cornerHarris.i + +# target to preprocess a source file +perf/perf_cornerHarris.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.i +.PHONY : perf/perf_cornerHarris.cpp.i + +perf/perf_cornerHarris.s: perf/perf_cornerHarris.cpp.s +.PHONY : perf/perf_cornerHarris.s + +# target to generate assembly for a file +perf/perf_cornerHarris.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cornerHarris.cpp.s +.PHONY : perf/perf_cornerHarris.cpp.s + +perf/perf_cvt_color.o: perf/perf_cvt_color.cpp.o +.PHONY : perf/perf_cvt_color.o + +# target to build an object file +perf/perf_cvt_color.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.o +.PHONY : perf/perf_cvt_color.cpp.o + +perf/perf_cvt_color.i: perf/perf_cvt_color.cpp.i +.PHONY : perf/perf_cvt_color.i + +# target to preprocess a source file +perf/perf_cvt_color.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.i +.PHONY : perf/perf_cvt_color.cpp.i + +perf/perf_cvt_color.s: perf/perf_cvt_color.cpp.s +.PHONY : perf/perf_cvt_color.s + +# target to generate assembly for a file +perf/perf_cvt_color.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_cvt_color.cpp.s +.PHONY : perf/perf_cvt_color.cpp.s + +perf/perf_distanceTransform.o: perf/perf_distanceTransform.cpp.o +.PHONY : perf/perf_distanceTransform.o + +# target to build an object file +perf/perf_distanceTransform.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.o +.PHONY : perf/perf_distanceTransform.cpp.o + +perf/perf_distanceTransform.i: perf/perf_distanceTransform.cpp.i +.PHONY : perf/perf_distanceTransform.i + +# target to preprocess a source file +perf/perf_distanceTransform.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.i +.PHONY : perf/perf_distanceTransform.cpp.i + +perf/perf_distanceTransform.s: perf/perf_distanceTransform.cpp.s +.PHONY : perf/perf_distanceTransform.s + +# target to generate assembly for a file +perf/perf_distanceTransform.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_distanceTransform.cpp.s +.PHONY : perf/perf_distanceTransform.cpp.s + +perf/perf_filter2d.o: perf/perf_filter2d.cpp.o +.PHONY : perf/perf_filter2d.o + +# target to build an object file +perf/perf_filter2d.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.o +.PHONY : perf/perf_filter2d.cpp.o + +perf/perf_filter2d.i: perf/perf_filter2d.cpp.i +.PHONY : perf/perf_filter2d.i + +# target to preprocess a source file +perf/perf_filter2d.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.i +.PHONY : perf/perf_filter2d.cpp.i + +perf/perf_filter2d.s: perf/perf_filter2d.cpp.s +.PHONY : perf/perf_filter2d.s + +# target to generate assembly for a file +perf/perf_filter2d.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_filter2d.cpp.s +.PHONY : perf/perf_filter2d.cpp.s + +perf/perf_goodFeaturesToTrack.o: perf/perf_goodFeaturesToTrack.cpp.o +.PHONY : perf/perf_goodFeaturesToTrack.o + +# target to build an object file +perf/perf_goodFeaturesToTrack.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.o +.PHONY : perf/perf_goodFeaturesToTrack.cpp.o + +perf/perf_goodFeaturesToTrack.i: perf/perf_goodFeaturesToTrack.cpp.i +.PHONY : perf/perf_goodFeaturesToTrack.i + +# target to preprocess a source file +perf/perf_goodFeaturesToTrack.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.i +.PHONY : perf/perf_goodFeaturesToTrack.cpp.i + +perf/perf_goodFeaturesToTrack.s: perf/perf_goodFeaturesToTrack.cpp.s +.PHONY : perf/perf_goodFeaturesToTrack.s + +# target to generate assembly for a file +perf/perf_goodFeaturesToTrack.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_goodFeaturesToTrack.cpp.s +.PHONY : perf/perf_goodFeaturesToTrack.cpp.s + +perf/perf_histogram.o: perf/perf_histogram.cpp.o +.PHONY : perf/perf_histogram.o + +# target to build an object file +perf/perf_histogram.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.o +.PHONY : perf/perf_histogram.cpp.o + +perf/perf_histogram.i: perf/perf_histogram.cpp.i +.PHONY : perf/perf_histogram.i + +# target to preprocess a source file +perf/perf_histogram.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.i +.PHONY : perf/perf_histogram.cpp.i + +perf/perf_histogram.s: perf/perf_histogram.cpp.s +.PHONY : perf/perf_histogram.s + +# target to generate assembly for a file +perf/perf_histogram.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_histogram.cpp.s +.PHONY : perf/perf_histogram.cpp.s + +perf/perf_houghLines.o: perf/perf_houghLines.cpp.o +.PHONY : perf/perf_houghLines.o + +# target to build an object file +perf/perf_houghLines.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.o +.PHONY : perf/perf_houghLines.cpp.o + +perf/perf_houghLines.i: perf/perf_houghLines.cpp.i +.PHONY : perf/perf_houghLines.i + +# target to preprocess a source file +perf/perf_houghLines.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.i +.PHONY : perf/perf_houghLines.cpp.i + +perf/perf_houghLines.s: perf/perf_houghLines.cpp.s +.PHONY : perf/perf_houghLines.s + +# target to generate assembly for a file +perf/perf_houghLines.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_houghLines.cpp.s +.PHONY : perf/perf_houghLines.cpp.s + +perf/perf_integral.o: perf/perf_integral.cpp.o +.PHONY : perf/perf_integral.o + +# target to build an object file +perf/perf_integral.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.o +.PHONY : perf/perf_integral.cpp.o + +perf/perf_integral.i: perf/perf_integral.cpp.i +.PHONY : perf/perf_integral.i + +# target to preprocess a source file +perf/perf_integral.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.i +.PHONY : perf/perf_integral.cpp.i + +perf/perf_integral.s: perf/perf_integral.cpp.s +.PHONY : perf/perf_integral.s + +# target to generate assembly for a file +perf/perf_integral.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_integral.cpp.s +.PHONY : perf/perf_integral.cpp.s + +perf/perf_main.o: perf/perf_main.cpp.o +.PHONY : perf/perf_main.o + +# target to build an object file +perf/perf_main.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.o +.PHONY : perf/perf_main.cpp.o + +perf/perf_main.i: perf/perf_main.cpp.i +.PHONY : perf/perf_main.i + +# target to preprocess a source file +perf/perf_main.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.i +.PHONY : perf/perf_main.cpp.i + +perf/perf_main.s: perf/perf_main.cpp.s +.PHONY : perf/perf_main.s + +# target to generate assembly for a file +perf/perf_main.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_main.cpp.s +.PHONY : perf/perf_main.cpp.s + +perf/perf_morph.o: perf/perf_morph.cpp.o +.PHONY : perf/perf_morph.o + +# target to build an object file +perf/perf_morph.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.o +.PHONY : perf/perf_morph.cpp.o + +perf/perf_morph.i: perf/perf_morph.cpp.i +.PHONY : perf/perf_morph.i + +# target to preprocess a source file +perf/perf_morph.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.i +.PHONY : perf/perf_morph.cpp.i + +perf/perf_morph.s: perf/perf_morph.cpp.s +.PHONY : perf/perf_morph.s + +# target to generate assembly for a file +perf/perf_morph.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_morph.cpp.s +.PHONY : perf/perf_morph.cpp.s + +perf/perf_precomp.o: perf/perf_precomp.cpp.o +.PHONY : perf/perf_precomp.o + +# target to build an object file +perf/perf_precomp.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.o +.PHONY : perf/perf_precomp.cpp.o + +perf/perf_precomp.i: perf/perf_precomp.cpp.i +.PHONY : perf/perf_precomp.i + +# target to preprocess a source file +perf/perf_precomp.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.i +.PHONY : perf/perf_precomp.cpp.i + +perf/perf_precomp.s: perf/perf_precomp.cpp.s +.PHONY : perf/perf_precomp.s + +# target to generate assembly for a file +perf/perf_precomp.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_precomp.cpp.s +.PHONY : perf/perf_precomp.cpp.s + +perf/perf_pyramids.o: perf/perf_pyramids.cpp.o +.PHONY : perf/perf_pyramids.o + +# target to build an object file +perf/perf_pyramids.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.o +.PHONY : perf/perf_pyramids.cpp.o + +perf/perf_pyramids.i: perf/perf_pyramids.cpp.i +.PHONY : perf/perf_pyramids.i + +# target to preprocess a source file +perf/perf_pyramids.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.i +.PHONY : perf/perf_pyramids.cpp.i + +perf/perf_pyramids.s: perf/perf_pyramids.cpp.s +.PHONY : perf/perf_pyramids.s + +# target to generate assembly for a file +perf/perf_pyramids.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_pyramids.cpp.s +.PHONY : perf/perf_pyramids.cpp.s + +perf/perf_remap.o: perf/perf_remap.cpp.o +.PHONY : perf/perf_remap.o + +# target to build an object file +perf/perf_remap.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.o +.PHONY : perf/perf_remap.cpp.o + +perf/perf_remap.i: perf/perf_remap.cpp.i +.PHONY : perf/perf_remap.i + +# target to preprocess a source file +perf/perf_remap.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.i +.PHONY : perf/perf_remap.cpp.i + +perf/perf_remap.s: perf/perf_remap.cpp.s +.PHONY : perf/perf_remap.s + +# target to generate assembly for a file +perf/perf_remap.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_remap.cpp.s +.PHONY : perf/perf_remap.cpp.s + +perf/perf_resize.o: perf/perf_resize.cpp.o +.PHONY : perf/perf_resize.o + +# target to build an object file +perf/perf_resize.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.o +.PHONY : perf/perf_resize.cpp.o + +perf/perf_resize.i: perf/perf_resize.cpp.i +.PHONY : perf/perf_resize.i + +# target to preprocess a source file +perf/perf_resize.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.i +.PHONY : perf/perf_resize.cpp.i + +perf/perf_resize.s: perf/perf_resize.cpp.s +.PHONY : perf/perf_resize.s + +# target to generate assembly for a file +perf/perf_resize.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_resize.cpp.s +.PHONY : perf/perf_resize.cpp.s + +perf/perf_sepfilters.o: perf/perf_sepfilters.cpp.o +.PHONY : perf/perf_sepfilters.o + +# target to build an object file +perf/perf_sepfilters.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.o +.PHONY : perf/perf_sepfilters.cpp.o + +perf/perf_sepfilters.i: perf/perf_sepfilters.cpp.i +.PHONY : perf/perf_sepfilters.i + +# target to preprocess a source file +perf/perf_sepfilters.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.i +.PHONY : perf/perf_sepfilters.cpp.i + +perf/perf_sepfilters.s: perf/perf_sepfilters.cpp.s +.PHONY : perf/perf_sepfilters.s + +# target to generate assembly for a file +perf/perf_sepfilters.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_sepfilters.cpp.s +.PHONY : perf/perf_sepfilters.cpp.s + +perf/perf_threshold.o: perf/perf_threshold.cpp.o +.PHONY : perf/perf_threshold.o + +# target to build an object file +perf/perf_threshold.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.o +.PHONY : perf/perf_threshold.cpp.o + +perf/perf_threshold.i: perf/perf_threshold.cpp.i +.PHONY : perf/perf_threshold.i + +# target to preprocess a source file +perf/perf_threshold.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.i +.PHONY : perf/perf_threshold.cpp.i + +perf/perf_threshold.s: perf/perf_threshold.cpp.s +.PHONY : perf/perf_threshold.s + +# target to generate assembly for a file +perf/perf_threshold.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_threshold.cpp.s +.PHONY : perf/perf_threshold.cpp.s + +perf/perf_warp.o: perf/perf_warp.cpp.o +.PHONY : perf/perf_warp.o + +# target to build an object file +perf/perf_warp.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.o +.PHONY : perf/perf_warp.cpp.o + +perf/perf_warp.i: perf/perf_warp.cpp.i +.PHONY : perf/perf_warp.i + +# target to preprocess a source file +perf/perf_warp.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.i +.PHONY : perf/perf_warp.cpp.i + +perf/perf_warp.s: perf/perf_warp.cpp.s +.PHONY : perf/perf_warp.s + +# target to generate assembly for a file +perf/perf_warp.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_perf_imgproc.dir/perf/perf_warp.cpp.s +.PHONY : perf/perf_warp.cpp.s + +src/accum.o: src/accum.cpp.o +.PHONY : src/accum.o + +# target to build an object file +src/accum.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.o +.PHONY : src/accum.cpp.o + +src/accum.i: src/accum.cpp.i +.PHONY : src/accum.i + +# target to preprocess a source file +src/accum.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.i +.PHONY : src/accum.cpp.i + +src/accum.s: src/accum.cpp.s +.PHONY : src/accum.s + +# target to generate assembly for a file +src/accum.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/accum.cpp.s +.PHONY : src/accum.cpp.s + +src/approx.o: src/approx.cpp.o +.PHONY : src/approx.o + +# target to build an object file +src/approx.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.o +.PHONY : src/approx.cpp.o + +src/approx.i: src/approx.cpp.i +.PHONY : src/approx.i + +# target to preprocess a source file +src/approx.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.i +.PHONY : src/approx.cpp.i + +src/approx.s: src/approx.cpp.s +.PHONY : src/approx.s + +# target to generate assembly for a file +src/approx.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/approx.cpp.s +.PHONY : src/approx.cpp.s + +src/canny.o: src/canny.cpp.o +.PHONY : src/canny.o + +# target to build an object file +src/canny.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.o +.PHONY : src/canny.cpp.o + +src/canny.i: src/canny.cpp.i +.PHONY : src/canny.i + +# target to preprocess a source file +src/canny.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.i +.PHONY : src/canny.cpp.i + +src/canny.s: src/canny.cpp.s +.PHONY : src/canny.s + +# target to generate assembly for a file +src/canny.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/canny.cpp.s +.PHONY : src/canny.cpp.s + +src/color.o: src/color.cpp.o +.PHONY : src/color.o + +# target to build an object file +src/color.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.o +.PHONY : src/color.cpp.o + +src/color.i: src/color.cpp.i +.PHONY : src/color.i + +# target to preprocess a source file +src/color.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.i +.PHONY : src/color.cpp.i + +src/color.s: src/color.cpp.s +.PHONY : src/color.s + +# target to generate assembly for a file +src/color.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/color.cpp.s +.PHONY : src/color.cpp.s + +src/contours.o: src/contours.cpp.o +.PHONY : src/contours.o + +# target to build an object file +src/contours.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.o +.PHONY : src/contours.cpp.o + +src/contours.i: src/contours.cpp.i +.PHONY : src/contours.i + +# target to preprocess a source file +src/contours.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.i +.PHONY : src/contours.cpp.i + +src/contours.s: src/contours.cpp.s +.PHONY : src/contours.s + +# target to generate assembly for a file +src/contours.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/contours.cpp.s +.PHONY : src/contours.cpp.s + +src/convhull.o: src/convhull.cpp.o +.PHONY : src/convhull.o + +# target to build an object file +src/convhull.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.o +.PHONY : src/convhull.cpp.o + +src/convhull.i: src/convhull.cpp.i +.PHONY : src/convhull.i + +# target to preprocess a source file +src/convhull.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.i +.PHONY : src/convhull.cpp.i + +src/convhull.s: src/convhull.cpp.s +.PHONY : src/convhull.s + +# target to generate assembly for a file +src/convhull.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/convhull.cpp.s +.PHONY : src/convhull.cpp.s + +src/corner.o: src/corner.cpp.o +.PHONY : src/corner.o + +# target to build an object file +src/corner.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.o +.PHONY : src/corner.cpp.o + +src/corner.i: src/corner.cpp.i +.PHONY : src/corner.i + +# target to preprocess a source file +src/corner.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.i +.PHONY : src/corner.cpp.i + +src/corner.s: src/corner.cpp.s +.PHONY : src/corner.s + +# target to generate assembly for a file +src/corner.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/corner.cpp.s +.PHONY : src/corner.cpp.s + +src/cornersubpix.o: src/cornersubpix.cpp.o +.PHONY : src/cornersubpix.o + +# target to build an object file +src/cornersubpix.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.o +.PHONY : src/cornersubpix.cpp.o + +src/cornersubpix.i: src/cornersubpix.cpp.i +.PHONY : src/cornersubpix.i + +# target to preprocess a source file +src/cornersubpix.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.i +.PHONY : src/cornersubpix.cpp.i + +src/cornersubpix.s: src/cornersubpix.cpp.s +.PHONY : src/cornersubpix.s + +# target to generate assembly for a file +src/cornersubpix.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/cornersubpix.cpp.s +.PHONY : src/cornersubpix.cpp.s + +src/deriv.o: src/deriv.cpp.o +.PHONY : src/deriv.o + +# target to build an object file +src/deriv.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.o +.PHONY : src/deriv.cpp.o + +src/deriv.i: src/deriv.cpp.i +.PHONY : src/deriv.i + +# target to preprocess a source file +src/deriv.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.i +.PHONY : src/deriv.cpp.i + +src/deriv.s: src/deriv.cpp.s +.PHONY : src/deriv.s + +# target to generate assembly for a file +src/deriv.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/deriv.cpp.s +.PHONY : src/deriv.cpp.s + +src/distransform.o: src/distransform.cpp.o +.PHONY : src/distransform.o + +# target to build an object file +src/distransform.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.o +.PHONY : src/distransform.cpp.o + +src/distransform.i: src/distransform.cpp.i +.PHONY : src/distransform.i + +# target to preprocess a source file +src/distransform.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.i +.PHONY : src/distransform.cpp.i + +src/distransform.s: src/distransform.cpp.s +.PHONY : src/distransform.s + +# target to generate assembly for a file +src/distransform.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/distransform.cpp.s +.PHONY : src/distransform.cpp.s + +src/emd.o: src/emd.cpp.o +.PHONY : src/emd.o + +# target to build an object file +src/emd.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.o +.PHONY : src/emd.cpp.o + +src/emd.i: src/emd.cpp.i +.PHONY : src/emd.i + +# target to preprocess a source file +src/emd.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.i +.PHONY : src/emd.cpp.i + +src/emd.s: src/emd.cpp.s +.PHONY : src/emd.s + +# target to generate assembly for a file +src/emd.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/emd.cpp.s +.PHONY : src/emd.cpp.s + +src/featureselect.o: src/featureselect.cpp.o +.PHONY : src/featureselect.o + +# target to build an object file +src/featureselect.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.o +.PHONY : src/featureselect.cpp.o + +src/featureselect.i: src/featureselect.cpp.i +.PHONY : src/featureselect.i + +# target to preprocess a source file +src/featureselect.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.i +.PHONY : src/featureselect.cpp.i + +src/featureselect.s: src/featureselect.cpp.s +.PHONY : src/featureselect.s + +# target to generate assembly for a file +src/featureselect.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/featureselect.cpp.s +.PHONY : src/featureselect.cpp.s + +src/filter.o: src/filter.cpp.o +.PHONY : src/filter.o + +# target to build an object file +src/filter.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.o +.PHONY : src/filter.cpp.o + +src/filter.i: src/filter.cpp.i +.PHONY : src/filter.i + +# target to preprocess a source file +src/filter.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.i +.PHONY : src/filter.cpp.i + +src/filter.s: src/filter.cpp.s +.PHONY : src/filter.s + +# target to generate assembly for a file +src/filter.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/filter.cpp.s +.PHONY : src/filter.cpp.s + +src/floodfill.o: src/floodfill.cpp.o +.PHONY : src/floodfill.o + +# target to build an object file +src/floodfill.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.o +.PHONY : src/floodfill.cpp.o + +src/floodfill.i: src/floodfill.cpp.i +.PHONY : src/floodfill.i + +# target to preprocess a source file +src/floodfill.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.i +.PHONY : src/floodfill.cpp.i + +src/floodfill.s: src/floodfill.cpp.s +.PHONY : src/floodfill.s + +# target to generate assembly for a file +src/floodfill.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/floodfill.cpp.s +.PHONY : src/floodfill.cpp.s + +src/gabor.o: src/gabor.cpp.o +.PHONY : src/gabor.o + +# target to build an object file +src/gabor.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.o +.PHONY : src/gabor.cpp.o + +src/gabor.i: src/gabor.cpp.i +.PHONY : src/gabor.i + +# target to preprocess a source file +src/gabor.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.i +.PHONY : src/gabor.cpp.i + +src/gabor.s: src/gabor.cpp.s +.PHONY : src/gabor.s + +# target to generate assembly for a file +src/gabor.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/gabor.cpp.s +.PHONY : src/gabor.cpp.s + +src/geometry.o: src/geometry.cpp.o +.PHONY : src/geometry.o + +# target to build an object file +src/geometry.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.o +.PHONY : src/geometry.cpp.o + +src/geometry.i: src/geometry.cpp.i +.PHONY : src/geometry.i + +# target to preprocess a source file +src/geometry.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.i +.PHONY : src/geometry.cpp.i + +src/geometry.s: src/geometry.cpp.s +.PHONY : src/geometry.s + +# target to generate assembly for a file +src/geometry.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/geometry.cpp.s +.PHONY : src/geometry.cpp.s + +src/grabcut.o: src/grabcut.cpp.o +.PHONY : src/grabcut.o + +# target to build an object file +src/grabcut.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.o +.PHONY : src/grabcut.cpp.o + +src/grabcut.i: src/grabcut.cpp.i +.PHONY : src/grabcut.i + +# target to preprocess a source file +src/grabcut.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.i +.PHONY : src/grabcut.cpp.i + +src/grabcut.s: src/grabcut.cpp.s +.PHONY : src/grabcut.s + +# target to generate assembly for a file +src/grabcut.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/grabcut.cpp.s +.PHONY : src/grabcut.cpp.s + +src/histogram.o: src/histogram.cpp.o +.PHONY : src/histogram.o + +# target to build an object file +src/histogram.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.o +.PHONY : src/histogram.cpp.o + +src/histogram.i: src/histogram.cpp.i +.PHONY : src/histogram.i + +# target to preprocess a source file +src/histogram.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.i +.PHONY : src/histogram.cpp.i + +src/histogram.s: src/histogram.cpp.s +.PHONY : src/histogram.s + +# target to generate assembly for a file +src/histogram.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/histogram.cpp.s +.PHONY : src/histogram.cpp.s + +src/hough.o: src/hough.cpp.o +.PHONY : src/hough.o + +# target to build an object file +src/hough.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.o +.PHONY : src/hough.cpp.o + +src/hough.i: src/hough.cpp.i +.PHONY : src/hough.i + +# target to preprocess a source file +src/hough.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.i +.PHONY : src/hough.cpp.i + +src/hough.s: src/hough.cpp.s +.PHONY : src/hough.s + +# target to generate assembly for a file +src/hough.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/hough.cpp.s +.PHONY : src/hough.cpp.s + +src/imgwarp.o: src/imgwarp.cpp.o +.PHONY : src/imgwarp.o + +# target to build an object file +src/imgwarp.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.o +.PHONY : src/imgwarp.cpp.o + +src/imgwarp.i: src/imgwarp.cpp.i +.PHONY : src/imgwarp.i + +# target to preprocess a source file +src/imgwarp.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.i +.PHONY : src/imgwarp.cpp.i + +src/imgwarp.s: src/imgwarp.cpp.s +.PHONY : src/imgwarp.s + +# target to generate assembly for a file +src/imgwarp.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/imgwarp.cpp.s +.PHONY : src/imgwarp.cpp.s + +src/linefit.o: src/linefit.cpp.o +.PHONY : src/linefit.o + +# target to build an object file +src/linefit.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.o +.PHONY : src/linefit.cpp.o + +src/linefit.i: src/linefit.cpp.i +.PHONY : src/linefit.i + +# target to preprocess a source file +src/linefit.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.i +.PHONY : src/linefit.cpp.i + +src/linefit.s: src/linefit.cpp.s +.PHONY : src/linefit.s + +# target to generate assembly for a file +src/linefit.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/linefit.cpp.s +.PHONY : src/linefit.cpp.s + +src/matchcontours.o: src/matchcontours.cpp.o +.PHONY : src/matchcontours.o + +# target to build an object file +src/matchcontours.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.o +.PHONY : src/matchcontours.cpp.o + +src/matchcontours.i: src/matchcontours.cpp.i +.PHONY : src/matchcontours.i + +# target to preprocess a source file +src/matchcontours.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.i +.PHONY : src/matchcontours.cpp.i + +src/matchcontours.s: src/matchcontours.cpp.s +.PHONY : src/matchcontours.s + +# target to generate assembly for a file +src/matchcontours.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/matchcontours.cpp.s +.PHONY : src/matchcontours.cpp.s + +src/moments.o: src/moments.cpp.o +.PHONY : src/moments.o + +# target to build an object file +src/moments.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.o +.PHONY : src/moments.cpp.o + +src/moments.i: src/moments.cpp.i +.PHONY : src/moments.i + +# target to preprocess a source file +src/moments.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.i +.PHONY : src/moments.cpp.i + +src/moments.s: src/moments.cpp.s +.PHONY : src/moments.s + +# target to generate assembly for a file +src/moments.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/moments.cpp.s +.PHONY : src/moments.cpp.s + +src/morph.o: src/morph.cpp.o +.PHONY : src/morph.o + +# target to build an object file +src/morph.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.o +.PHONY : src/morph.cpp.o + +src/morph.i: src/morph.cpp.i +.PHONY : src/morph.i + +# target to preprocess a source file +src/morph.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.i +.PHONY : src/morph.cpp.i + +src/morph.s: src/morph.cpp.s +.PHONY : src/morph.s + +# target to generate assembly for a file +src/morph.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/morph.cpp.s +.PHONY : src/morph.cpp.s + +src/phasecorr.o: src/phasecorr.cpp.o +.PHONY : src/phasecorr.o + +# target to build an object file +src/phasecorr.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.o +.PHONY : src/phasecorr.cpp.o + +src/phasecorr.i: src/phasecorr.cpp.i +.PHONY : src/phasecorr.i + +# target to preprocess a source file +src/phasecorr.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.i +.PHONY : src/phasecorr.cpp.i + +src/phasecorr.s: src/phasecorr.cpp.s +.PHONY : src/phasecorr.s + +# target to generate assembly for a file +src/phasecorr.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/phasecorr.cpp.s +.PHONY : src/phasecorr.cpp.s + +src/precomp.o: src/precomp.cpp.o +.PHONY : src/precomp.o + +# target to build an object file +src/precomp.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.o +.PHONY : src/precomp.cpp.o + +src/precomp.i: src/precomp.cpp.i +.PHONY : src/precomp.i + +# target to preprocess a source file +src/precomp.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.i +.PHONY : src/precomp.cpp.i + +src/precomp.s: src/precomp.cpp.s +.PHONY : src/precomp.s + +# target to generate assembly for a file +src/precomp.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/precomp.cpp.s +.PHONY : src/precomp.cpp.s + +src/pyramids.o: src/pyramids.cpp.o +.PHONY : src/pyramids.o + +# target to build an object file +src/pyramids.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.o +.PHONY : src/pyramids.cpp.o + +src/pyramids.i: src/pyramids.cpp.i +.PHONY : src/pyramids.i + +# target to preprocess a source file +src/pyramids.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.i +.PHONY : src/pyramids.cpp.i + +src/pyramids.s: src/pyramids.cpp.s +.PHONY : src/pyramids.s + +# target to generate assembly for a file +src/pyramids.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/pyramids.cpp.s +.PHONY : src/pyramids.cpp.s + +src/rotcalipers.o: src/rotcalipers.cpp.o +.PHONY : src/rotcalipers.o + +# target to build an object file +src/rotcalipers.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.o +.PHONY : src/rotcalipers.cpp.o + +src/rotcalipers.i: src/rotcalipers.cpp.i +.PHONY : src/rotcalipers.i + +# target to preprocess a source file +src/rotcalipers.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.i +.PHONY : src/rotcalipers.cpp.i + +src/rotcalipers.s: src/rotcalipers.cpp.s +.PHONY : src/rotcalipers.s + +# target to generate assembly for a file +src/rotcalipers.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/rotcalipers.cpp.s +.PHONY : src/rotcalipers.cpp.s + +src/samplers.o: src/samplers.cpp.o +.PHONY : src/samplers.o + +# target to build an object file +src/samplers.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.o +.PHONY : src/samplers.cpp.o + +src/samplers.i: src/samplers.cpp.i +.PHONY : src/samplers.i + +# target to preprocess a source file +src/samplers.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.i +.PHONY : src/samplers.cpp.i + +src/samplers.s: src/samplers.cpp.s +.PHONY : src/samplers.s + +# target to generate assembly for a file +src/samplers.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/samplers.cpp.s +.PHONY : src/samplers.cpp.s + +src/segmentation.o: src/segmentation.cpp.o +.PHONY : src/segmentation.o + +# target to build an object file +src/segmentation.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.o +.PHONY : src/segmentation.cpp.o + +src/segmentation.i: src/segmentation.cpp.i +.PHONY : src/segmentation.i + +# target to preprocess a source file +src/segmentation.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.i +.PHONY : src/segmentation.cpp.i + +src/segmentation.s: src/segmentation.cpp.s +.PHONY : src/segmentation.s + +# target to generate assembly for a file +src/segmentation.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/segmentation.cpp.s +.PHONY : src/segmentation.cpp.s + +src/shapedescr.o: src/shapedescr.cpp.o +.PHONY : src/shapedescr.o + +# target to build an object file +src/shapedescr.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.o +.PHONY : src/shapedescr.cpp.o + +src/shapedescr.i: src/shapedescr.cpp.i +.PHONY : src/shapedescr.i + +# target to preprocess a source file +src/shapedescr.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.i +.PHONY : src/shapedescr.cpp.i + +src/shapedescr.s: src/shapedescr.cpp.s +.PHONY : src/shapedescr.s + +# target to generate assembly for a file +src/shapedescr.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/shapedescr.cpp.s +.PHONY : src/shapedescr.cpp.s + +src/smooth.o: src/smooth.cpp.o +.PHONY : src/smooth.o + +# target to build an object file +src/smooth.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.o +.PHONY : src/smooth.cpp.o + +src/smooth.i: src/smooth.cpp.i +.PHONY : src/smooth.i + +# target to preprocess a source file +src/smooth.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.i +.PHONY : src/smooth.cpp.i + +src/smooth.s: src/smooth.cpp.s +.PHONY : src/smooth.s + +# target to generate assembly for a file +src/smooth.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/smooth.cpp.s +.PHONY : src/smooth.cpp.s + +src/subdivision2d.o: src/subdivision2d.cpp.o +.PHONY : src/subdivision2d.o + +# target to build an object file +src/subdivision2d.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.o +.PHONY : src/subdivision2d.cpp.o + +src/subdivision2d.i: src/subdivision2d.cpp.i +.PHONY : src/subdivision2d.i + +# target to preprocess a source file +src/subdivision2d.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.i +.PHONY : src/subdivision2d.cpp.i + +src/subdivision2d.s: src/subdivision2d.cpp.s +.PHONY : src/subdivision2d.s + +# target to generate assembly for a file +src/subdivision2d.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/subdivision2d.cpp.s +.PHONY : src/subdivision2d.cpp.s + +src/sumpixels.o: src/sumpixels.cpp.o +.PHONY : src/sumpixels.o + +# target to build an object file +src/sumpixels.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.o +.PHONY : src/sumpixels.cpp.o + +src/sumpixels.i: src/sumpixels.cpp.i +.PHONY : src/sumpixels.i + +# target to preprocess a source file +src/sumpixels.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.i +.PHONY : src/sumpixels.cpp.i + +src/sumpixels.s: src/sumpixels.cpp.s +.PHONY : src/sumpixels.s + +# target to generate assembly for a file +src/sumpixels.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/sumpixels.cpp.s +.PHONY : src/sumpixels.cpp.s + +src/tables.o: src/tables.cpp.o +.PHONY : src/tables.o + +# target to build an object file +src/tables.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.o +.PHONY : src/tables.cpp.o + +src/tables.i: src/tables.cpp.i +.PHONY : src/tables.i + +# target to preprocess a source file +src/tables.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.i +.PHONY : src/tables.cpp.i + +src/tables.s: src/tables.cpp.s +.PHONY : src/tables.s + +# target to generate assembly for a file +src/tables.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/tables.cpp.s +.PHONY : src/tables.cpp.s + +src/templmatch.o: src/templmatch.cpp.o +.PHONY : src/templmatch.o + +# target to build an object file +src/templmatch.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.o +.PHONY : src/templmatch.cpp.o + +src/templmatch.i: src/templmatch.cpp.i +.PHONY : src/templmatch.i + +# target to preprocess a source file +src/templmatch.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.i +.PHONY : src/templmatch.cpp.i + +src/templmatch.s: src/templmatch.cpp.s +.PHONY : src/templmatch.s + +# target to generate assembly for a file +src/templmatch.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/templmatch.cpp.s +.PHONY : src/templmatch.cpp.s + +src/thresh.o: src/thresh.cpp.o +.PHONY : src/thresh.o + +# target to build an object file +src/thresh.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.o +.PHONY : src/thresh.cpp.o + +src/thresh.i: src/thresh.cpp.i +.PHONY : src/thresh.i + +# target to preprocess a source file +src/thresh.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.i +.PHONY : src/thresh.cpp.i + +src/thresh.s: src/thresh.cpp.s +.PHONY : src/thresh.s + +# target to generate assembly for a file +src/thresh.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/thresh.cpp.s +.PHONY : src/thresh.cpp.s + +src/undistort.o: src/undistort.cpp.o +.PHONY : src/undistort.o + +# target to build an object file +src/undistort.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.o +.PHONY : src/undistort.cpp.o + +src/undistort.i: src/undistort.cpp.i +.PHONY : src/undistort.i + +# target to preprocess a source file +src/undistort.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.i +.PHONY : src/undistort.cpp.i + +src/undistort.s: src/undistort.cpp.s +.PHONY : src/undistort.s + +# target to generate assembly for a file +src/undistort.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/undistort.cpp.s +.PHONY : src/undistort.cpp.s + +src/utils.o: src/utils.cpp.o +.PHONY : src/utils.o + +# target to build an object file +src/utils.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.o +.PHONY : src/utils.cpp.o + +src/utils.i: src/utils.cpp.i +.PHONY : src/utils.i + +# target to preprocess a source file +src/utils.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.i +.PHONY : src/utils.cpp.i + +src/utils.s: src/utils.cpp.s +.PHONY : src/utils.s + +# target to generate assembly for a file +src/utils.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_imgproc.dir/src/utils.cpp.s +.PHONY : src/utils.cpp.s + +test/test_approxpoly.o: test/test_approxpoly.cpp.o +.PHONY : test/test_approxpoly.o + +# target to build an object file +test/test_approxpoly.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.o +.PHONY : test/test_approxpoly.cpp.o + +test/test_approxpoly.i: test/test_approxpoly.cpp.i +.PHONY : test/test_approxpoly.i + +# target to preprocess a source file +test/test_approxpoly.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.i +.PHONY : test/test_approxpoly.cpp.i + +test/test_approxpoly.s: test/test_approxpoly.cpp.s +.PHONY : test/test_approxpoly.s + +# target to generate assembly for a file +test/test_approxpoly.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_approxpoly.cpp.s +.PHONY : test/test_approxpoly.cpp.s + +test/test_bilateral_filter.o: test/test_bilateral_filter.cpp.o +.PHONY : test/test_bilateral_filter.o + +# target to build an object file +test/test_bilateral_filter.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.o +.PHONY : test/test_bilateral_filter.cpp.o + +test/test_bilateral_filter.i: test/test_bilateral_filter.cpp.i +.PHONY : test/test_bilateral_filter.i + +# target to preprocess a source file +test/test_bilateral_filter.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.i +.PHONY : test/test_bilateral_filter.cpp.i + +test/test_bilateral_filter.s: test/test_bilateral_filter.cpp.s +.PHONY : test/test_bilateral_filter.s + +# target to generate assembly for a file +test/test_bilateral_filter.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_bilateral_filter.cpp.s +.PHONY : test/test_bilateral_filter.cpp.s + +test/test_boundingrect.o: test/test_boundingrect.cpp.o +.PHONY : test/test_boundingrect.o + +# target to build an object file +test/test_boundingrect.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.o +.PHONY : test/test_boundingrect.cpp.o + +test/test_boundingrect.i: test/test_boundingrect.cpp.i +.PHONY : test/test_boundingrect.i + +# target to preprocess a source file +test/test_boundingrect.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.i +.PHONY : test/test_boundingrect.cpp.i + +test/test_boundingrect.s: test/test_boundingrect.cpp.s +.PHONY : test/test_boundingrect.s + +# target to generate assembly for a file +test/test_boundingrect.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_boundingrect.cpp.s +.PHONY : test/test_boundingrect.cpp.s + +test/test_canny.o: test/test_canny.cpp.o +.PHONY : test/test_canny.o + +# target to build an object file +test/test_canny.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.o +.PHONY : test/test_canny.cpp.o + +test/test_canny.i: test/test_canny.cpp.i +.PHONY : test/test_canny.i + +# target to preprocess a source file +test/test_canny.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.i +.PHONY : test/test_canny.cpp.i + +test/test_canny.s: test/test_canny.cpp.s +.PHONY : test/test_canny.s + +# target to generate assembly for a file +test/test_canny.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_canny.cpp.s +.PHONY : test/test_canny.cpp.s + +test/test_color.o: test/test_color.cpp.o +.PHONY : test/test_color.o + +# target to build an object file +test/test_color.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.o +.PHONY : test/test_color.cpp.o + +test/test_color.i: test/test_color.cpp.i +.PHONY : test/test_color.i + +# target to preprocess a source file +test/test_color.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.i +.PHONY : test/test_color.cpp.i + +test/test_color.s: test/test_color.cpp.s +.PHONY : test/test_color.s + +# target to generate assembly for a file +test/test_color.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_color.cpp.s +.PHONY : test/test_color.cpp.s + +test/test_contours.o: test/test_contours.cpp.o +.PHONY : test/test_contours.o + +# target to build an object file +test/test_contours.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.o +.PHONY : test/test_contours.cpp.o + +test/test_contours.i: test/test_contours.cpp.i +.PHONY : test/test_contours.i + +# target to preprocess a source file +test/test_contours.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.i +.PHONY : test/test_contours.cpp.i + +test/test_contours.s: test/test_contours.cpp.s +.PHONY : test/test_contours.s + +# target to generate assembly for a file +test/test_contours.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_contours.cpp.s +.PHONY : test/test_contours.cpp.s + +test/test_convhull.o: test/test_convhull.cpp.o +.PHONY : test/test_convhull.o + +# target to build an object file +test/test_convhull.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.o +.PHONY : test/test_convhull.cpp.o + +test/test_convhull.i: test/test_convhull.cpp.i +.PHONY : test/test_convhull.i + +# target to preprocess a source file +test/test_convhull.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.i +.PHONY : test/test_convhull.cpp.i + +test/test_convhull.s: test/test_convhull.cpp.s +.PHONY : test/test_convhull.s + +# target to generate assembly for a file +test/test_convhull.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_convhull.cpp.s +.PHONY : test/test_convhull.cpp.s + +test/test_cvtyuv.o: test/test_cvtyuv.cpp.o +.PHONY : test/test_cvtyuv.o + +# target to build an object file +test/test_cvtyuv.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.o +.PHONY : test/test_cvtyuv.cpp.o + +test/test_cvtyuv.i: test/test_cvtyuv.cpp.i +.PHONY : test/test_cvtyuv.i + +# target to preprocess a source file +test/test_cvtyuv.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.i +.PHONY : test/test_cvtyuv.cpp.i + +test/test_cvtyuv.s: test/test_cvtyuv.cpp.s +.PHONY : test/test_cvtyuv.s + +# target to generate assembly for a file +test/test_cvtyuv.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_cvtyuv.cpp.s +.PHONY : test/test_cvtyuv.cpp.s + +test/test_distancetransform.o: test/test_distancetransform.cpp.o +.PHONY : test/test_distancetransform.o + +# target to build an object file +test/test_distancetransform.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.o +.PHONY : test/test_distancetransform.cpp.o + +test/test_distancetransform.i: test/test_distancetransform.cpp.i +.PHONY : test/test_distancetransform.i + +# target to preprocess a source file +test/test_distancetransform.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.i +.PHONY : test/test_distancetransform.cpp.i + +test/test_distancetransform.s: test/test_distancetransform.cpp.s +.PHONY : test/test_distancetransform.s + +# target to generate assembly for a file +test/test_distancetransform.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_distancetransform.cpp.s +.PHONY : test/test_distancetransform.cpp.s + +test/test_emd.o: test/test_emd.cpp.o +.PHONY : test/test_emd.o + +# target to build an object file +test/test_emd.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.o +.PHONY : test/test_emd.cpp.o + +test/test_emd.i: test/test_emd.cpp.i +.PHONY : test/test_emd.i + +# target to preprocess a source file +test/test_emd.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.i +.PHONY : test/test_emd.cpp.i + +test/test_emd.s: test/test_emd.cpp.s +.PHONY : test/test_emd.s + +# target to generate assembly for a file +test/test_emd.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_emd.cpp.s +.PHONY : test/test_emd.cpp.s + +test/test_filter.o: test/test_filter.cpp.o +.PHONY : test/test_filter.o + +# target to build an object file +test/test_filter.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.o +.PHONY : test/test_filter.cpp.o + +test/test_filter.i: test/test_filter.cpp.i +.PHONY : test/test_filter.i + +# target to preprocess a source file +test/test_filter.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.i +.PHONY : test/test_filter.cpp.i + +test/test_filter.s: test/test_filter.cpp.s +.PHONY : test/test_filter.s + +# target to generate assembly for a file +test/test_filter.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_filter.cpp.s +.PHONY : test/test_filter.cpp.s + +test/test_floodfill.o: test/test_floodfill.cpp.o +.PHONY : test/test_floodfill.o + +# target to build an object file +test/test_floodfill.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.o +.PHONY : test/test_floodfill.cpp.o + +test/test_floodfill.i: test/test_floodfill.cpp.i +.PHONY : test/test_floodfill.i + +# target to preprocess a source file +test/test_floodfill.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.i +.PHONY : test/test_floodfill.cpp.i + +test/test_floodfill.s: test/test_floodfill.cpp.s +.PHONY : test/test_floodfill.s + +# target to generate assembly for a file +test/test_floodfill.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_floodfill.cpp.s +.PHONY : test/test_floodfill.cpp.s + +test/test_grabcut.o: test/test_grabcut.cpp.o +.PHONY : test/test_grabcut.o + +# target to build an object file +test/test_grabcut.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.o +.PHONY : test/test_grabcut.cpp.o + +test/test_grabcut.i: test/test_grabcut.cpp.i +.PHONY : test/test_grabcut.i + +# target to preprocess a source file +test/test_grabcut.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.i +.PHONY : test/test_grabcut.cpp.i + +test/test_grabcut.s: test/test_grabcut.cpp.s +.PHONY : test/test_grabcut.s + +# target to generate assembly for a file +test/test_grabcut.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_grabcut.cpp.s +.PHONY : test/test_grabcut.cpp.s + +test/test_histograms.o: test/test_histograms.cpp.o +.PHONY : test/test_histograms.o + +# target to build an object file +test/test_histograms.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.o +.PHONY : test/test_histograms.cpp.o + +test/test_histograms.i: test/test_histograms.cpp.i +.PHONY : test/test_histograms.i + +# target to preprocess a source file +test/test_histograms.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.i +.PHONY : test/test_histograms.cpp.i + +test/test_histograms.s: test/test_histograms.cpp.s +.PHONY : test/test_histograms.s + +# target to generate assembly for a file +test/test_histograms.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_histograms.cpp.s +.PHONY : test/test_histograms.cpp.s + +test/test_imgwarp.o: test/test_imgwarp.cpp.o +.PHONY : test/test_imgwarp.o + +# target to build an object file +test/test_imgwarp.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.o +.PHONY : test/test_imgwarp.cpp.o + +test/test_imgwarp.i: test/test_imgwarp.cpp.i +.PHONY : test/test_imgwarp.i + +# target to preprocess a source file +test/test_imgwarp.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.i +.PHONY : test/test_imgwarp.cpp.i + +test/test_imgwarp.s: test/test_imgwarp.cpp.s +.PHONY : test/test_imgwarp.s + +# target to generate assembly for a file +test/test_imgwarp.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_imgwarp.cpp.s +.PHONY : test/test_imgwarp.cpp.s + +test/test_main.o: test/test_main.cpp.o +.PHONY : test/test_main.o + +# target to build an object file +test/test_main.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.o +.PHONY : test/test_main.cpp.o + +test/test_main.i: test/test_main.cpp.i +.PHONY : test/test_main.i + +# target to preprocess a source file +test/test_main.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.i +.PHONY : test/test_main.cpp.i + +test/test_main.s: test/test_main.cpp.s +.PHONY : test/test_main.s + +# target to generate assembly for a file +test/test_main.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_main.cpp.s +.PHONY : test/test_main.cpp.s + +test/test_moments.o: test/test_moments.cpp.o +.PHONY : test/test_moments.o + +# target to build an object file +test/test_moments.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.o +.PHONY : test/test_moments.cpp.o + +test/test_moments.i: test/test_moments.cpp.i +.PHONY : test/test_moments.i + +# target to preprocess a source file +test/test_moments.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.i +.PHONY : test/test_moments.cpp.i + +test/test_moments.s: test/test_moments.cpp.s +.PHONY : test/test_moments.s + +# target to generate assembly for a file +test/test_moments.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_moments.cpp.s +.PHONY : test/test_moments.cpp.s + +test/test_pc.o: test/test_pc.cpp.o +.PHONY : test/test_pc.o + +# target to build an object file +test/test_pc.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.o +.PHONY : test/test_pc.cpp.o + +test/test_pc.i: test/test_pc.cpp.i +.PHONY : test/test_pc.i + +# target to preprocess a source file +test/test_pc.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.i +.PHONY : test/test_pc.cpp.i + +test/test_pc.s: test/test_pc.cpp.s +.PHONY : test/test_pc.s + +# target to generate assembly for a file +test/test_pc.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_pc.cpp.s +.PHONY : test/test_pc.cpp.s + +test/test_precomp.o: test/test_precomp.cpp.o +.PHONY : test/test_precomp.o + +# target to build an object file +test/test_precomp.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.o +.PHONY : test/test_precomp.cpp.o + +test/test_precomp.i: test/test_precomp.cpp.i +.PHONY : test/test_precomp.i + +# target to preprocess a source file +test/test_precomp.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.i +.PHONY : test/test_precomp.cpp.i + +test/test_precomp.s: test/test_precomp.cpp.s +.PHONY : test/test_precomp.s + +# target to generate assembly for a file +test/test_precomp.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_precomp.cpp.s +.PHONY : test/test_precomp.cpp.s + +test/test_templmatch.o: test/test_templmatch.cpp.o +.PHONY : test/test_templmatch.o + +# target to build an object file +test/test_templmatch.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.o +.PHONY : test/test_templmatch.cpp.o + +test/test_templmatch.i: test/test_templmatch.cpp.i +.PHONY : test/test_templmatch.i + +# target to preprocess a source file +test/test_templmatch.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.i +.PHONY : test/test_templmatch.cpp.i + +test/test_templmatch.s: test/test_templmatch.cpp.s +.PHONY : test/test_templmatch.s + +# target to generate assembly for a file +test/test_templmatch.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_templmatch.cpp.s +.PHONY : test/test_templmatch.cpp.s + +test/test_thresh.o: test/test_thresh.cpp.o +.PHONY : test/test_thresh.o + +# target to build an object file +test/test_thresh.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.o +.PHONY : test/test_thresh.cpp.o + +test/test_thresh.i: test/test_thresh.cpp.i +.PHONY : test/test_thresh.i + +# target to preprocess a source file +test/test_thresh.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.i +.PHONY : test/test_thresh.cpp.i + +test/test_thresh.s: test/test_thresh.cpp.s +.PHONY : test/test_thresh.s + +# target to generate assembly for a file +test/test_thresh.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_thresh.cpp.s +.PHONY : test/test_thresh.cpp.s + +test/test_watershed.o: test/test_watershed.cpp.o +.PHONY : test/test_watershed.o + +# target to build an object file +test/test_watershed.cpp.o: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.o +.PHONY : test/test_watershed.cpp.o + +test/test_watershed.i: test/test_watershed.cpp.i +.PHONY : test/test_watershed.i + +# target to preprocess a source file +test/test_watershed.cpp.i: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.i +.PHONY : test/test_watershed.cpp.i + +test/test_watershed.s: test/test_watershed.cpp.s +.PHONY : test/test_watershed.s + +# target to generate assembly for a file +test/test_watershed.cpp.s: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(MAKE) -f modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/build.make modules/imgproc/CMakeFiles/opencv_test_imgproc.dir/test/test_watershed.cpp.s +.PHONY : test/test_watershed.cpp.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... opencv_imgproc" + @echo "... opencv_perf_imgproc" + @echo "... opencv_test_imgproc" + @echo "... rebuild_cache" + @echo "... perf/perf_bilateral.o" + @echo "... perf/perf_bilateral.i" + @echo "... perf/perf_bilateral.s" + @echo "... perf/perf_blur.o" + @echo "... perf/perf_blur.i" + @echo "... perf/perf_blur.s" + @echo "... perf/perf_canny.o" + @echo "... perf/perf_canny.i" + @echo "... perf/perf_canny.s" + @echo "... perf/perf_cornerEigenValsAndVecs.o" + @echo "... perf/perf_cornerEigenValsAndVecs.i" + @echo "... perf/perf_cornerEigenValsAndVecs.s" + @echo "... perf/perf_cornerHarris.o" + @echo "... perf/perf_cornerHarris.i" + @echo "... perf/perf_cornerHarris.s" + @echo "... perf/perf_cvt_color.o" + @echo "... perf/perf_cvt_color.i" + @echo "... perf/perf_cvt_color.s" + @echo "... perf/perf_distanceTransform.o" + @echo "... perf/perf_distanceTransform.i" + @echo "... perf/perf_distanceTransform.s" + @echo "... perf/perf_filter2d.o" + @echo "... perf/perf_filter2d.i" + @echo "... perf/perf_filter2d.s" + @echo "... perf/perf_goodFeaturesToTrack.o" + @echo "... perf/perf_goodFeaturesToTrack.i" + @echo "... perf/perf_goodFeaturesToTrack.s" + @echo "... perf/perf_histogram.o" + @echo "... perf/perf_histogram.i" + @echo "... perf/perf_histogram.s" + @echo "... perf/perf_houghLines.o" + @echo "... perf/perf_houghLines.i" + @echo "... perf/perf_houghLines.s" + @echo "... perf/perf_integral.o" + @echo "... perf/perf_integral.i" + @echo "... perf/perf_integral.s" + @echo "... perf/perf_main.o" + @echo "... perf/perf_main.i" + @echo "... perf/perf_main.s" + @echo "... perf/perf_morph.o" + @echo "... perf/perf_morph.i" + @echo "... perf/perf_morph.s" + @echo "... perf/perf_precomp.o" + @echo "... perf/perf_precomp.i" + @echo "... perf/perf_precomp.s" + @echo "... perf/perf_pyramids.o" + @echo "... perf/perf_pyramids.i" + @echo "... perf/perf_pyramids.s" + @echo "... perf/perf_remap.o" + @echo "... perf/perf_remap.i" + @echo "... perf/perf_remap.s" + @echo "... perf/perf_resize.o" + @echo "... perf/perf_resize.i" + @echo "... perf/perf_resize.s" + @echo "... perf/perf_sepfilters.o" + @echo "... perf/perf_sepfilters.i" + @echo "... perf/perf_sepfilters.s" + @echo "... perf/perf_threshold.o" + @echo "... perf/perf_threshold.i" + @echo "... perf/perf_threshold.s" + @echo "... perf/perf_warp.o" + @echo "... perf/perf_warp.i" + @echo "... perf/perf_warp.s" + @echo "... src/accum.o" + @echo "... src/accum.i" + @echo "... src/accum.s" + @echo "... src/approx.o" + @echo "... src/approx.i" + @echo "... src/approx.s" + @echo "... src/canny.o" + @echo "... src/canny.i" + @echo "... src/canny.s" + @echo "... src/color.o" + @echo "... src/color.i" + @echo "... src/color.s" + @echo "... src/contours.o" + @echo "... src/contours.i" + @echo "... src/contours.s" + @echo "... src/convhull.o" + @echo "... src/convhull.i" + @echo "... src/convhull.s" + @echo "... src/corner.o" + @echo "... src/corner.i" + @echo "... src/corner.s" + @echo "... src/cornersubpix.o" + @echo "... src/cornersubpix.i" + @echo "... src/cornersubpix.s" + @echo "... src/deriv.o" + @echo "... src/deriv.i" + @echo "... src/deriv.s" + @echo "... src/distransform.o" + @echo "... src/distransform.i" + @echo "... src/distransform.s" + @echo "... src/emd.o" + @echo "... src/emd.i" + @echo "... src/emd.s" + @echo "... src/featureselect.o" + @echo "... src/featureselect.i" + @echo "... src/featureselect.s" + @echo "... src/filter.o" + @echo "... src/filter.i" + @echo "... src/filter.s" + @echo "... src/floodfill.o" + @echo "... src/floodfill.i" + @echo "... src/floodfill.s" + @echo "... src/gabor.o" + @echo "... src/gabor.i" + @echo "... src/gabor.s" + @echo "... src/geometry.o" + @echo "... src/geometry.i" + @echo "... src/geometry.s" + @echo "... src/grabcut.o" + @echo "... src/grabcut.i" + @echo "... src/grabcut.s" + @echo "... src/histogram.o" + @echo "... src/histogram.i" + @echo "... src/histogram.s" + @echo "... src/hough.o" + @echo "... src/hough.i" + @echo "... src/hough.s" + @echo "... src/imgwarp.o" + @echo "... src/imgwarp.i" + @echo "... src/imgwarp.s" + @echo "... src/linefit.o" + @echo "... src/linefit.i" + @echo "... src/linefit.s" + @echo "... src/matchcontours.o" + @echo "... src/matchcontours.i" + @echo "... src/matchcontours.s" + @echo "... src/moments.o" + @echo "... src/moments.i" + @echo "... src/moments.s" + @echo "... src/morph.o" + @echo "... src/morph.i" + @echo "... src/morph.s" + @echo "... src/phasecorr.o" + @echo "... src/phasecorr.i" + @echo "... src/phasecorr.s" + @echo "... src/precomp.o" + @echo "... src/precomp.i" + @echo "... src/precomp.s" + @echo "... src/pyramids.o" + @echo "... src/pyramids.i" + @echo "... src/pyramids.s" + @echo "... src/rotcalipers.o" + @echo "... src/rotcalipers.i" + @echo "... src/rotcalipers.s" + @echo "... src/samplers.o" + @echo "... src/samplers.i" + @echo "... src/samplers.s" + @echo "... src/segmentation.o" + @echo "... src/segmentation.i" + @echo "... src/segmentation.s" + @echo "... src/shapedescr.o" + @echo "... src/shapedescr.i" + @echo "... src/shapedescr.s" + @echo "... src/smooth.o" + @echo "... src/smooth.i" + @echo "... src/smooth.s" + @echo "... src/subdivision2d.o" + @echo "... src/subdivision2d.i" + @echo "... src/subdivision2d.s" + @echo "... src/sumpixels.o" + @echo "... src/sumpixels.i" + @echo "... src/sumpixels.s" + @echo "... src/tables.o" + @echo "... src/tables.i" + @echo "... src/tables.s" + @echo "... src/templmatch.o" + @echo "... src/templmatch.i" + @echo "... src/templmatch.s" + @echo "... src/thresh.o" + @echo "... src/thresh.i" + @echo "... src/thresh.s" + @echo "... src/undistort.o" + @echo "... src/undistort.i" + @echo "... src/undistort.s" + @echo "... src/utils.o" + @echo "... src/utils.i" + @echo "... src/utils.s" + @echo "... test/test_approxpoly.o" + @echo "... test/test_approxpoly.i" + @echo "... test/test_approxpoly.s" + @echo "... test/test_bilateral_filter.o" + @echo "... test/test_bilateral_filter.i" + @echo "... test/test_bilateral_filter.s" + @echo "... test/test_boundingrect.o" + @echo "... test/test_boundingrect.i" + @echo "... test/test_boundingrect.s" + @echo "... test/test_canny.o" + @echo "... test/test_canny.i" + @echo "... test/test_canny.s" + @echo "... test/test_color.o" + @echo "... test/test_color.i" + @echo "... test/test_color.s" + @echo "... test/test_contours.o" + @echo "... test/test_contours.i" + @echo "... test/test_contours.s" + @echo "... test/test_convhull.o" + @echo "... test/test_convhull.i" + @echo "... test/test_convhull.s" + @echo "... test/test_cvtyuv.o" + @echo "... test/test_cvtyuv.i" + @echo "... test/test_cvtyuv.s" + @echo "... test/test_distancetransform.o" + @echo "... test/test_distancetransform.i" + @echo "... test/test_distancetransform.s" + @echo "... test/test_emd.o" + @echo "... test/test_emd.i" + @echo "... test/test_emd.s" + @echo "... test/test_filter.o" + @echo "... test/test_filter.i" + @echo "... test/test_filter.s" + @echo "... test/test_floodfill.o" + @echo "... test/test_floodfill.i" + @echo "... test/test_floodfill.s" + @echo "... test/test_grabcut.o" + @echo "... test/test_grabcut.i" + @echo "... test/test_grabcut.s" + @echo "... test/test_histograms.o" + @echo "... test/test_histograms.i" + @echo "... test/test_histograms.s" + @echo "... test/test_imgwarp.o" + @echo "... test/test_imgwarp.i" + @echo "... test/test_imgwarp.s" + @echo "... test/test_main.o" + @echo "... test/test_main.i" + @echo "... test/test_main.s" + @echo "... test/test_moments.o" + @echo "... test/test_moments.i" + @echo "... test/test_moments.s" + @echo "... test/test_pc.o" + @echo "... test/test_pc.i" + @echo "... test/test_pc.s" + @echo "... test/test_precomp.o" + @echo "... test/test_precomp.i" + @echo "... test/test_precomp.s" + @echo "... test/test_templmatch.o" + @echo "... test/test_templmatch.i" + @echo "... test/test_templmatch.s" + @echo "... test/test_thresh.o" + @echo "... test/test_thresh.i" + @echo "... test/test_thresh.s" + @echo "... test/test_watershed.o" + @echo "... test/test_watershed.i" + @echo "... test/test_watershed.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /Users/beau/Documents/workspace/OpenCV/opencv && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/imgproc/cmake_install.cmake b/imgproc/cmake_install.cmake new file mode 100644 index 0000000..68af3bc --- /dev/null +++ b/imgproc/cmake_install.cmake @@ -0,0 +1,65 @@ +# Install script for directory: /Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc + +# Set the install prefix +IF(NOT DEFINED CMAKE_INSTALL_PREFIX) + SET(CMAKE_INSTALL_PREFIX "/usr/local") +ENDIF(NOT DEFINED CMAKE_INSTALL_PREFIX) +STRING(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +IF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + IF(BUILD_TYPE) + STRING(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + ELSE(BUILD_TYPE) + SET(CMAKE_INSTALL_CONFIG_NAME "Release") + ENDIF(BUILD_TYPE) + MESSAGE(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +ENDIF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + +# Set the component getting installed. +IF(NOT CMAKE_INSTALL_COMPONENT) + IF(COMPONENT) + MESSAGE(STATUS "Install component: \"${COMPONENT}\"") + SET(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + ELSE(COMPONENT) + SET(CMAKE_INSTALL_COMPONENT) + ENDIF(COMPONENT) +ENDIF(NOT CMAKE_INSTALL_COMPONENT) + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE SHARED_LIBRARY FILES + "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_imgproc.2.4.9.dylib" + "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_imgproc.2.4.dylib" + "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_imgproc.dylib" + ) + FOREACH(file + "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libopencv_imgproc.2.4.9.dylib" + "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libopencv_imgproc.2.4.dylib" + "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libopencv_imgproc.dylib" + ) + IF(EXISTS "${file}" AND + NOT IS_SYMLINK "${file}") + EXECUTE_PROCESS(COMMAND "/usr/bin/install_name_tool" + -id "lib/libopencv_imgproc.2.4.dylib" + -change "/Users/beau/Documents/workspace/OpenCV/opencv/lib/libopencv_core.2.4.dylib" "lib/libopencv_core.2.4.dylib" + "${file}") + IF(CMAKE_INSTALL_DO_STRIP) + EXECUTE_PROCESS(COMMAND "/usr/bin/strip" "${file}") + ENDIF(CMAKE_INSTALL_DO_STRIP) + ENDIF() + ENDFOREACH() +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/include/opencv2/imgproc" TYPE FILE FILES "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/include/opencv2/imgproc/imgproc.hpp") +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/include/opencv2/imgproc" TYPE FILE FILES "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/include/opencv2/imgproc/imgproc_c.h") +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/include/opencv2/imgproc" TYPE FILE FILES "/Users/beau/Documents/workspace/OpenCV/opencv/modules/imgproc/include/opencv2/imgproc/types_c.h") +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + diff --git a/imgproc/doc/feature_detection.rst b/imgproc/doc/feature_detection.rst new file mode 100644 index 0000000..df1a193 --- /dev/null +++ b/imgproc/doc/feature_detection.rst @@ -0,0 +1,548 @@ +Feature Detection +================= + +.. highlight:: cpp + + + +Canny +--------- +Finds edges in an image using the [Canny86]_ algorithm. + +.. ocv:function:: void Canny( InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize=3, bool L2gradient=false ) + +.. ocv:pyfunction:: cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]]) -> edges + +.. ocv:cfunction:: void cvCanny( const CvArr* image, CvArr* edges, double threshold1, double threshold2, int aperture_size=3 ) + +.. ocv:pyoldfunction:: cv.Canny(image, edges, threshold1, threshold2, aperture_size=3) -> None + + :param image: single-channel 8-bit input image. + + :param edges: output edge map; it has the same size and type as ``image`` . + + :param threshold1: first threshold for the hysteresis procedure. + + :param threshold2: second threshold for the hysteresis procedure. + + :param apertureSize: aperture size for the :ocv:func:`Sobel` operator. + + :param L2gradient: a flag, indicating whether a more accurate :math:`L_2` norm :math:`=\sqrt{(dI/dx)^2 + (dI/dy)^2}` should be used to calculate the image gradient magnitude ( ``L2gradient=true`` ), or whether the default :math:`L_1` norm :math:`=|dI/dx|+|dI/dy|` is enough ( ``L2gradient=false`` ). + +The function finds edges in the input image ``image`` and marks them in the output map ``edges`` using the Canny algorithm. The smallest value between ``threshold1`` and ``threshold2`` is used for edge linking. The largest value is used to find initial segments of strong edges. See +http://en.wikipedia.org/wiki/Canny_edge_detector + + + +cornerEigenValsAndVecs +---------------------- +Calculates eigenvalues and eigenvectors of image blocks for corner detection. + +.. ocv:function:: void cornerEigenValsAndVecs( InputArray src, OutputArray dst, int blockSize, int ksize, int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.cornerEigenValsAndVecs(src, blockSize, ksize[, dst[, borderType]]) -> dst + +.. ocv:cfunction:: void cvCornerEigenValsAndVecs( const CvArr* image, CvArr* eigenvv, int block_size, int aperture_size=3 ) + +.. ocv:pyoldfunction:: cv.CornerEigenValsAndVecs(image, eigenvv, blockSize, aperture_size=3) -> None + + :param src: Input single-channel 8-bit or floating-point image. + + :param dst: Image to store the results. It has the same size as ``src`` and the type ``CV_32FC(6)`` . + + :param blockSize: Neighborhood size (see details below). + + :param ksize: Aperture parameter for the :ocv:func:`Sobel` operator. + + :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` . + +For every pixel +:math:`p` , the function ``cornerEigenValsAndVecs`` considers a ``blockSize`` :math:`\times` ``blockSize`` neighborhood +:math:`S(p)` . It calculates the covariation matrix of derivatives over the neighborhood as: + +.. math:: + + M = \begin{bmatrix} \sum _{S(p)}(dI/dx)^2 & \sum _{S(p)}(dI/dx dI/dy)^2 \\ \sum _{S(p)}(dI/dx dI/dy)^2 & \sum _{S(p)}(dI/dy)^2 \end{bmatrix} + +where the derivatives are computed using the +:ocv:func:`Sobel` operator. + +After that, it finds eigenvectors and eigenvalues of +:math:`M` and stores them in the destination image as +:math:`(\lambda_1, \lambda_2, x_1, y_1, x_2, y_2)` where + +* :math:`\lambda_1, \lambda_2` are the non-sorted eigenvalues of :math:`M` + +* :math:`x_1, y_1` are the eigenvectors corresponding to :math:`\lambda_1` + +* :math:`x_2, y_2` are the eigenvectors corresponding to :math:`\lambda_2` + +The output of the function can be used for robust edge or corner detection. + +.. seealso:: + + :ocv:func:`cornerMinEigenVal`, + :ocv:func:`cornerHarris`, + :ocv:func:`preCornerDetect` + + + +cornerHarris +------------ +Harris edge detector. + +.. ocv:function:: void cornerHarris( InputArray src, OutputArray dst, int blockSize, int ksize, double k, int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.cornerHarris(src, blockSize, ksize, k[, dst[, borderType]]) -> dst + +.. ocv:cfunction:: void cvCornerHarris( const CvArr* image, CvArr* harris_responce, int block_size, int aperture_size=3, double k=0.04 ) + +.. ocv:pyoldfunction:: cv.CornerHarris(image, harris_dst, blockSize, aperture_size=3, k=0.04) -> None + + :param src: Input single-channel 8-bit or floating-point image. + + :param dst: Image to store the Harris detector responses. It has the type ``CV_32FC1`` and the same size as ``src`` . + + :param blockSize: Neighborhood size (see the details on :ocv:func:`cornerEigenValsAndVecs` ). + + :param ksize: Aperture parameter for the :ocv:func:`Sobel` operator. + + :param k: Harris detector free parameter. See the formula below. + + :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` . + +The function runs the Harris edge detector on the image. Similarly to +:ocv:func:`cornerMinEigenVal` and +:ocv:func:`cornerEigenValsAndVecs` , for each pixel +:math:`(x, y)` it calculates a +:math:`2\times2` gradient covariance matrix +:math:`M^{(x,y)}` over a +:math:`\texttt{blockSize} \times \texttt{blockSize}` neighborhood. Then, it computes the following characteristic: + +.. math:: + + \texttt{dst} (x,y) = \mathrm{det} M^{(x,y)} - k \cdot \left ( \mathrm{tr} M^{(x,y)} \right )^2 + +Corners in the image can be found as the local maxima of this response map. + + + +cornerMinEigenVal +----------------- +Calculates the minimal eigenvalue of gradient matrices for corner detection. + +.. ocv:function:: void cornerMinEigenVal( InputArray src, OutputArray dst, int blockSize, int ksize=3, int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.cornerMinEigenVal(src, blockSize[, dst[, ksize[, borderType]]]) -> dst + +.. ocv:cfunction:: void cvCornerMinEigenVal( const CvArr* image, CvArr* eigenval, int block_size, int aperture_size=3 ) + +.. ocv:pyoldfunction:: cv.CornerMinEigenVal(image, eigenval, blockSize, aperture_size=3) -> None + + :param src: Input single-channel 8-bit or floating-point image. + + :param dst: Image to store the minimal eigenvalues. It has the type ``CV_32FC1`` and the same size as ``src`` . + + :param blockSize: Neighborhood size (see the details on :ocv:func:`cornerEigenValsAndVecs` ). + + :param ksize: Aperture parameter for the :ocv:func:`Sobel` operator. + + :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` . + +The function is similar to +:ocv:func:`cornerEigenValsAndVecs` but it calculates and stores only the minimal eigenvalue of the covariance matrix of derivatives, that is, +:math:`\min(\lambda_1, \lambda_2)` in terms of the formulae in the +:ocv:func:`cornerEigenValsAndVecs` description. + + + +cornerSubPix +---------------- +Refines the corner locations. + +.. ocv:function:: void cornerSubPix( InputArray image, InputOutputArray corners, Size winSize, Size zeroZone, TermCriteria criteria ) + +.. ocv:pyfunction:: cv2.cornerSubPix(image, corners, winSize, zeroZone, criteria) -> None + +.. ocv:cfunction:: void cvFindCornerSubPix( const CvArr* image, CvPoint2D32f* corners, int count, CvSize win, CvSize zero_zone, CvTermCriteria criteria ) + +.. ocv:pyoldfunction:: cv.FindCornerSubPix(image, corners, win, zero_zone, criteria) -> corners + + :param image: Input image. + + :param corners: Initial coordinates of the input corners and refined coordinates provided for output. + + :param winSize: Half of the side length of the search window. For example, if ``winSize=Size(5,5)`` , then a :math:`5*2+1 \times 5*2+1 = 11 \times 11` search window is used. + + :param zeroZone: Half of the size of the dead region in the middle of the search zone over which the summation in the formula below is not done. It is used sometimes to avoid possible singularities of the autocorrelation matrix. The value of (-1,-1) indicates that there is no such a size. + + :param criteria: Criteria for termination of the iterative process of corner refinement. That is, the process of corner position refinement stops either after ``criteria.maxCount`` iterations or when the corner position moves by less than ``criteria.epsilon`` on some iteration. + +The function iterates to find the sub-pixel accurate location of corners or radial saddle points, as shown on the figure below. + +.. image:: pics/cornersubpix.png + +Sub-pixel accurate corner locator is based on the observation that every vector from the center +:math:`q` to a point +:math:`p` located within a neighborhood of +:math:`q` is orthogonal to the image gradient at +:math:`p` subject to image and measurement noise. Consider the expression: + +.. math:: + + \epsilon _i = {DI_{p_i}}^T \cdot (q - p_i) + +where +:math:`{DI_{p_i}}` is an image gradient at one of the points +:math:`p_i` in a neighborhood of +:math:`q` . The value of +:math:`q` is to be found so that +:math:`\epsilon_i` is minimized. A system of equations may be set up with +:math:`\epsilon_i` set to zero: + +.. math:: + + \sum _i(DI_{p_i} \cdot {DI_{p_i}}^T) - \sum _i(DI_{p_i} \cdot {DI_{p_i}}^T \cdot p_i) + +where the gradients are summed within a neighborhood ("search window") of +:math:`q` . Calling the first gradient term +:math:`G` and the second gradient term +:math:`b` gives: + +.. math:: + + q = G^{-1} \cdot b + +The algorithm sets the center of the neighborhood window at this new center +:math:`q` and then iterates until the center stays within a set threshold. + + + +goodFeaturesToTrack +------------------- +Determines strong corners on an image. + +.. ocv:function:: void goodFeaturesToTrack( InputArray image, OutputArray corners, int maxCorners, double qualityLevel, double minDistance, InputArray mask=noArray(), int blockSize=3, bool useHarrisDetector=false, double k=0.04 ) + +.. ocv:pyfunction:: cv2.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance[, corners[, mask[, blockSize[, useHarrisDetector[, k]]]]]) -> corners + +.. ocv:cfunction:: void cvGoodFeaturesToTrack( const CvArr* image, CvArr* eig_image, CvArr* temp_image, CvPoint2D32f* corners, int* corner_count, double quality_level, double min_distance, const CvArr* mask=NULL, int block_size=3, int use_harris=0, double k=0.04 ) + +.. ocv:pyoldfunction:: cv.GoodFeaturesToTrack(image, eigImage, tempImage, cornerCount, qualityLevel, minDistance, mask=None, blockSize=3, useHarris=0, k=0.04) -> cornerCount + + :param image: Input 8-bit or floating-point 32-bit, single-channel image. + + :param eig_image: The parameter is ignored. + + :param temp_image: The parameter is ignored. + + :param corners: Output vector of detected corners. + + :param maxCorners: Maximum number of corners to return. If there are more corners than are found, the strongest of them is returned. + + :param qualityLevel: Parameter characterizing the minimal accepted quality of image corners. The parameter value is multiplied by the best corner quality measure, which is the minimal eigenvalue (see :ocv:func:`cornerMinEigenVal` ) or the Harris function response (see :ocv:func:`cornerHarris` ). The corners with the quality measure less than the product are rejected. For example, if the best corner has the quality measure = 1500, and the ``qualityLevel=0.01`` , then all the corners with the quality measure less than 15 are rejected. + + :param minDistance: Minimum possible Euclidean distance between the returned corners. + + :param mask: Optional region of interest. If the image is not empty (it needs to have the type ``CV_8UC1`` and the same size as ``image`` ), it specifies the region in which the corners are detected. + + :param blockSize: Size of an average block for computing a derivative covariation matrix over each pixel neighborhood. See :ocv:func:`cornerEigenValsAndVecs` . + + :param useHarrisDetector: Parameter indicating whether to use a Harris detector (see :ocv:func:`cornerHarris`) or :ocv:func:`cornerMinEigenVal`. + + :param k: Free parameter of the Harris detector. + +The function finds the most prominent corners in the image or in the specified image region, as described in [Shi94]_: + +#. + Function calculates the corner quality measure at every source image pixel using the + :ocv:func:`cornerMinEigenVal` or + :ocv:func:`cornerHarris` . + +#. + Function performs a non-maximum suppression (the local maximums in *3 x 3* neighborhood are retained). + +#. + The corners with the minimal eigenvalue less than + :math:`\texttt{qualityLevel} \cdot \max_{x,y} qualityMeasureMap(x,y)` are rejected. + +#. + The remaining corners are sorted by the quality measure in the descending order. + +#. + Function throws away each corner for which there is a stronger corner at a distance less than ``maxDistance``. + +The function can be used to initialize a point-based tracker of an object. + +.. note:: If the function is called with different values ``A`` and ``B`` of the parameter ``qualityLevel`` , and ``A`` > {B}, the vector of returned corners with ``qualityLevel=A`` will be the prefix of the output vector with ``qualityLevel=B`` . + +.. seealso:: + + :ocv:func:`cornerMinEigenVal`, + :ocv:func:`cornerHarris`, + :ocv:func:`calcOpticalFlowPyrLK`, + :ocv:func:`estimateRigidTransform`, + + +HoughCircles +------------ +Finds circles in a grayscale image using the Hough transform. + +.. ocv:function:: void HoughCircles( InputArray image, OutputArray circles, int method, double dp, double minDist, double param1=100, double param2=100, int minRadius=0, int maxRadius=0 ) + +.. ocv:cfunction:: CvSeq* cvHoughCircles( CvArr* image, void* circle_storage, int method, double dp, double min_dist, double param1=100, double param2=100, int min_radius=0, int max_radius=0 ) + +.. ocv:pyfunction:: cv2.HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]]) -> circles + + :param image: 8-bit, single-channel, grayscale input image. + + :param circles: Output vector of found circles. Each vector is encoded as a 3-element floating-point vector :math:`(x, y, radius)` . + + :param circle_storage: In C function this is a memory storage that will contain the output sequence of found circles. + + :param method: Detection method to use. Currently, the only implemented method is ``CV_HOUGH_GRADIENT`` , which is basically *21HT* , described in [Yuen90]_. + + :param dp: Inverse ratio of the accumulator resolution to the image resolution. For example, if ``dp=1`` , the accumulator has the same resolution as the input image. If ``dp=2`` , the accumulator has half as big width and height. + + :param minDist: Minimum distance between the centers of the detected circles. If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed. + + :param param1: First method-specific parameter. In case of ``CV_HOUGH_GRADIENT`` , it is the higher threshold of the two passed to the :ocv:func:`Canny` edge detector (the lower one is twice smaller). + + :param param2: Second method-specific parameter. In case of ``CV_HOUGH_GRADIENT`` , it is the accumulator threshold for the circle centers at the detection stage. The smaller it is, the more false circles may be detected. Circles, corresponding to the larger accumulator values, will be returned first. + + :param minRadius: Minimum circle radius. + + :param maxRadius: Maximum circle radius. + +The function finds circles in a grayscale image using a modification of the Hough transform. + +Example: :: + + #include + #include + #include + + using namespace cv; + + int main(int argc, char** argv) + { + Mat img, gray; + if( argc != 2 && !(img=imread(argv[1], 1)).data) + return -1; + cvtColor(img, gray, CV_BGR2GRAY); + // smooth it, otherwise a lot of false circles may be detected + GaussianBlur( gray, gray, Size(9, 9), 2, 2 ); + vector circles; + HoughCircles(gray, circles, CV_HOUGH_GRADIENT, + 2, gray->rows/4, 200, 100 ); + for( size_t i = 0; i < circles.size(); i++ ) + { + Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); + int radius = cvRound(circles[i][2]); + // draw the circle center + circle( img, center, 3, Scalar(0,255,0), -1, 8, 0 ); + // draw the circle outline + circle( img, center, radius, Scalar(0,0,255), 3, 8, 0 ); + } + namedWindow( "circles", 1 ); + imshow( "circles", img ); + return 0; + } + +.. note:: Usually the function detects the centers of circles well. However, it may fail to find correct radii. You can assist to the function by specifying the radius range ( ``minRadius`` and ``maxRadius`` ) if you know it. Or, you may ignore the returned radius, use only the center, and find the correct radius using an additional procedure. + +.. seealso:: + + :ocv:func:`fitEllipse`, + :ocv:func:`minEnclosingCircle` + + +HoughLines +---------- +Finds lines in a binary image using the standard Hough transform. + +.. ocv:function:: void HoughLines( InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 ) + +.. ocv:pyfunction:: cv2.HoughLines(image, rho, theta, threshold[, lines[, srn[, stn]]]) -> lines + +.. ocv:cfunction:: CvSeq* cvHoughLines2( CvArr* image, void* line_storage, int method, double rho, double theta, int threshold, double param1=0, double param2=0 ) + +.. ocv:pyoldfunction:: cv.HoughLines2(image, storage, method, rho, theta, threshold, param1=0, param2=0)-> lines + + :param image: 8-bit, single-channel binary source image. The image may be modified by the function. + + :param lines: Output vector of lines. Each line is represented by a two-element vector :math:`(\rho, \theta)` . :math:`\rho` is the distance from the coordinate origin :math:`(0,0)` (top-left corner of the image). :math:`\theta` is the line rotation angle in radians ( :math:`0 \sim \textrm{vertical line}, \pi/2 \sim \textrm{horizontal line}` ). + + :param rho: Distance resolution of the accumulator in pixels. + + :param theta: Angle resolution of the accumulator in radians. + + :param threshold: Accumulator threshold parameter. Only those lines are returned that get enough votes ( :math:`>\texttt{threshold}` ). + + :param srn: For the multi-scale Hough transform, it is a divisor for the distance resolution ``rho`` . The coarse accumulator distance resolution is ``rho`` and the accurate accumulator resolution is ``rho/srn`` . If both ``srn=0`` and ``stn=0`` , the classical Hough transform is used. Otherwise, both these parameters should be positive. + + :param stn: For the multi-scale Hough transform, it is a divisor for the distance resolution ``theta``. + + :param method: One of the following Hough transform variants: + + * **CV_HOUGH_STANDARD** classical or standard Hough transform. Every line is represented by two floating-point numbers :math:`(\rho, \theta)` , where :math:`\rho` is a distance between (0,0) point and the line, and :math:`\theta` is the angle between x-axis and the normal to the line. Thus, the matrix must be (the created sequence will be) of ``CV_32FC2`` type + + + * **CV_HOUGH_PROBABILISTIC** probabilistic Hough transform (more efficient in case if the picture contains a few long linear segments). It returns line segments rather than the whole line. Each segment is represented by starting and ending points, and the matrix must be (the created sequence will be) of the ``CV_32SC4`` type. + + * **CV_HOUGH_MULTI_SCALE** multi-scale variant of the classical Hough transform. The lines are encoded the same way as ``CV_HOUGH_STANDARD``. + + + :param param1: First method-dependent parameter: + + * For the classical Hough transform, it is not used (0). + + * For the probabilistic Hough transform, it is the minimum line length. + + * For the multi-scale Hough transform, it is ``srn``. + + :param param2: Second method-dependent parameter: + + * For the classical Hough transform, it is not used (0). + + * For the probabilistic Hough transform, it is the maximum gap between line segments lying on the same line to treat them as a single line segment (that is, to join them). + + * For the multi-scale Hough transform, it is ``stn``. + +The function implements the standard or standard multi-scale Hough transform algorithm for line detection. See http://homepages.inf.ed.ac.uk/rbf/HIPR2/hough.htm for a good explanation of Hough transform. +See also the example in :ocv:func:`HoughLinesP` description. + +HoughLinesP +----------- +Finds line segments in a binary image using the probabilistic Hough transform. + +.. ocv:function:: void HoughLinesP( InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength=0, double maxLineGap=0 ) + +.. ocv:pyfunction:: cv2.HoughLinesP(image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]]) -> lines + + :param image: 8-bit, single-channel binary source image. The image may be modified by the function. + + :param lines: Output vector of lines. Each line is represented by a 4-element vector :math:`(x_1, y_1, x_2, y_2)` , where :math:`(x_1,y_1)` and :math:`(x_2, y_2)` are the ending points of each detected line segment. + + :param rho: Distance resolution of the accumulator in pixels. + + :param theta: Angle resolution of the accumulator in radians. + + :param threshold: Accumulator threshold parameter. Only those lines are returned that get enough votes ( :math:`>\texttt{threshold}` ). + + :param minLineLength: Minimum line length. Line segments shorter than that are rejected. + + :param maxLineGap: Maximum allowed gap between points on the same line to link them. + +The function implements the probabilistic Hough transform algorithm for line detection, described in +[Matas00]_. See the line detection example below: :: + + /* This is a standalone program. Pass an image name as the first parameter + of the program. Switch between standard and probabilistic Hough transform + by changing "#if 1" to "#if 0" and back */ + #include + #include + #include + + using namespace cv; + + int main(int argc, char** argv) + { + Mat src, dst, color_dst; + if( argc != 2 || !(src=imread(argv[1], 0)).data) + return -1; + + Canny( src, dst, 50, 200, 3 ); + cvtColor( dst, color_dst, CV_GRAY2BGR ); + + #if 0 + vector lines; + HoughLines( dst, lines, 1, CV_PI/180, 100 ); + + for( size_t i = 0; i < lines.size(); i++ ) + { + float rho = lines[i][0]; + float theta = lines[i][1]; + double a = cos(theta), b = sin(theta); + double x0 = a*rho, y0 = b*rho; + Point pt1(cvRound(x0 + 1000*(-b)), + cvRound(y0 + 1000*(a))); + Point pt2(cvRound(x0 - 1000*(-b)), + cvRound(y0 - 1000*(a))); + line( color_dst, pt1, pt2, Scalar(0,0,255), 3, 8 ); + } + #else + vector lines; + HoughLinesP( dst, lines, 1, CV_PI/180, 80, 30, 10 ); + for( size_t i = 0; i < lines.size(); i++ ) + { + line( color_dst, Point(lines[i][0], lines[i][1]), + Point(lines[i][2], lines[i][3]), Scalar(0,0,255), 3, 8 ); + } + #endif + namedWindow( "Source", 1 ); + imshow( "Source", src ); + + namedWindow( "Detected Lines", 1 ); + imshow( "Detected Lines", color_dst ); + + waitKey(0); + return 0; + } + +This is a sample picture the function parameters have been tuned for: + +.. image:: pics/building.jpg + +And this is the output of the above program in case of the probabilistic Hough transform: + +.. image:: pics/houghp.png + + + +preCornerDetect +--------------- +Calculates a feature map for corner detection. + +.. ocv:function:: void preCornerDetect( InputArray src, OutputArray dst, int ksize, int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.preCornerDetect(src, ksize[, dst[, borderType]]) -> dst + +.. ocv:cfunction:: void cvPreCornerDetect( const CvArr* image, CvArr* corners, int aperture_size=3 ) + +.. ocv:pyoldfunction:: cv.PreCornerDetect(image, corners, apertureSize=3)-> None + + :param src: Source single-channel 8-bit of floating-point image. + + :param dst: Output image that has the type ``CV_32F`` and the same size as ``src`` . + + :param ksize: Aperture size of the :ocv:func:`Sobel` . + + :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` . + +The function calculates the complex spatial derivative-based function of the source image + +.. math:: + + \texttt{dst} = (D_x \texttt{src} )^2 \cdot D_{yy} \texttt{src} + (D_y \texttt{src} )^2 \cdot D_{xx} \texttt{src} - 2 D_x \texttt{src} \cdot D_y \texttt{src} \cdot D_{xy} \texttt{src} + +where +:math:`D_x`,:math:`D_y` are the first image derivatives, +:math:`D_{xx}`,:math:`D_{yy}` are the second image derivatives, and +:math:`D_{xy}` is the mixed derivative. + +The corners can be found as local maximums of the functions, as shown below: :: + + Mat corners, dilated_corners; + preCornerDetect(image, corners, 3); + // dilation with 3x3 rectangular structuring element + dilate(corners, dilated_corners, Mat(), 1); + Mat corner_mask = corners == dilated_corners; + +.. [Canny86] J. Canny. *A Computational Approach to Edge Detection*, IEEE Trans. on Pattern Analysis and Machine Intelligence, 8(6), pp. 679-698 (1986). + +.. [Matas00] Matas, J. and Galambos, C. and Kittler, J.V., *Robust Detection of Lines Using the Progressive Probabilistic Hough Transform*. CVIU 78 1, pp 119-137 (2000) + +.. [Shi94] J. Shi and C. Tomasi. *Good Features to Track*. Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, pages 593-600, June 1994. + +.. [Yuen90] Yuen, H. K. and Princen, J. and Illingworth, J. and Kittler, J., *Comparative study of Hough transform methods for circle finding*. Image Vision Comput. 8 1, pp 71–77 (1990) diff --git a/imgproc/doc/filtering.rst b/imgproc/doc/filtering.rst new file mode 100644 index 0000000..5f4e043 --- /dev/null +++ b/imgproc/doc/filtering.rst @@ -0,0 +1,1622 @@ +Image Filtering +=============== + +.. highlight:: cpp + +Functions and classes described in this section are used to perform various linear or non-linear filtering operations on 2D images (represented as +:ocv:func:`Mat`'s). It means that for each pixel location +:math:`(x,y)` in the source image (normally, rectangular), its neighborhood is considered and used to compute the response. In case of a linear filter, it is a weighted sum of pixel values. In case of morphological operations, it is the minimum or maximum values, and so on. The computed response is stored in the destination image at the same location +:math:`(x,y)` . It means that the output image will be of the same size as the input image. Normally, the functions support multi-channel arrays, in which case every channel is processed independently. Therefore, the output image will also have the same number of channels as the input one. + +Another common feature of the functions and classes described in this section is that, unlike simple arithmetic functions, they need to extrapolate values of some non-existing pixels. For example, if you want to smooth an image using a Gaussian +:math:`3 \times 3` filter, then, when processing the left-most pixels in each row, you need pixels to the left of them, that is, outside of the image. You can let these pixels be the same as the left-most image pixels ("replicated border" extrapolation method), or assume that all the non-existing pixels are zeros ("constant border" extrapolation method), and so on. +OpenCV enables you to specify the extrapolation method. For details, see the function :ocv:func:`borderInterpolate` and discussion of the ``borderType`` parameter in the section and various functions below. :: + + /* + Various border types, image boundaries are denoted with '|' + + * BORDER_REPLICATE: aaaaaa|abcdefgh|hhhhhhh + * BORDER_REFLECT: fedcba|abcdefgh|hgfedcb + * BORDER_REFLECT_101: gfedcb|abcdefgh|gfedcba + * BORDER_WRAP: cdefgh|abcdefgh|abcdefg + * BORDER_CONSTANT: iiiiii|abcdefgh|iiiiiii with some specified 'i' + */ + +BaseColumnFilter +---------------- +.. ocv:class:: BaseColumnFilter + +Base class for filters with single-column kernels. :: + + class BaseColumnFilter + { + public: + virtual ~BaseColumnFilter(); + + // To be overriden by the user. + // + // runs a filtering operation on the set of rows, + // "dstcount + ksize - 1" rows on input, + // "dstcount" rows on output, + // each input and output row has "width" elements + // the filtered rows are written into "dst" buffer. + virtual void operator()(const uchar** src, uchar* dst, int dststep, + int dstcount, int width) = 0; + // resets the filter state (may be needed for IIR filters) + virtual void reset(); + + int ksize; // the aperture size + int anchor; // position of the anchor point, + // normally not used during the processing + }; + + +The class ``BaseColumnFilter`` is a base class for filtering data using single-column kernels. Filtering does not have to be a linear operation. In general, it could be written as follows: + +.. math:: + + \texttt{dst} (x,y) = F( \texttt{src} [y](x), \; \texttt{src} [y+1](x), \; ..., \; \texttt{src} [y+ \texttt{ksize} -1](x) + +where +:math:`F` is a filtering function but, as it is represented as a class, it can produce any side effects, memorize previously processed data, and so on. The class only defines an interface and is not used directly. Instead, there are several functions in OpenCV (and you can add more) that return pointers to the derived classes that implement specific filtering operations. Those pointers are then passed to the +:ocv:class:`FilterEngine` constructor. While the filtering operation interface uses the ``uchar`` type, a particular implementation is not limited to 8-bit data. + +.. seealso:: + + :ocv:class:`BaseRowFilter`, + :ocv:class:`BaseFilter`, + :ocv:class:`FilterEngine`, + :ocv:func:`getColumnSumFilter`, + :ocv:func:`getLinearColumnFilter`, + :ocv:func:`getMorphologyColumnFilter` + + +BaseFilter +---------- +.. ocv:class:: BaseFilter + +Base class for 2D image filters. :: + + class BaseFilter + { + public: + virtual ~BaseFilter(); + + // To be overriden by the user. + // + // runs a filtering operation on the set of rows, + // "dstcount + ksize.height - 1" rows on input, + // "dstcount" rows on output, + // each input row has "(width + ksize.width-1)*cn" elements + // each output row has "width*cn" elements. + // the filtered rows are written into "dst" buffer. + virtual void operator()(const uchar** src, uchar* dst, int dststep, + int dstcount, int width, int cn) = 0; + // resets the filter state (may be needed for IIR filters) + virtual void reset(); + Size ksize; + Point anchor; + }; + + +The class ``BaseFilter`` is a base class for filtering data using 2D kernels. Filtering does not have to be a linear operation. In general, it could be written as follows: + +.. math:: + + \begin{array}{l} \texttt{dst} (x,y) = F( \texttt{src} [y](x), \; \texttt{src} [y](x+1), \; ..., \; \texttt{src} [y](x+ \texttt{ksize.width} -1), \\ \texttt{src} [y+1](x), \; \texttt{src} [y+1](x+1), \; ..., \; \texttt{src} [y+1](x+ \texttt{ksize.width} -1), \\ ......................................................................................... \\ \texttt{src} [y+ \texttt{ksize.height-1} ](x), \\ \texttt{src} [y+ \texttt{ksize.height-1} ](x+1), \\ ... + \texttt{src} [y+ \texttt{ksize.height-1} ](x+ \texttt{ksize.width} -1)) + \end{array} + +where +:math:`F` is a filtering function. The class only defines an interface and is not used directly. Instead, there are several functions in OpenCV (and you can add more) that return pointers to the derived classes that implement specific filtering operations. Those pointers are then passed to the +:ocv:class:`FilterEngine` constructor. While the filtering operation interface uses the ``uchar`` type, a particular implementation is not limited to 8-bit data. + +.. seealso:: + + :ocv:class:`BaseColumnFilter`, + :ocv:class:`BaseRowFilter`, + :ocv:class:`FilterEngine`, + :ocv:func:`getLinearFilter`, + :ocv:func:`getMorphologyFilter` + + + +BaseRowFilter +------------- +.. ocv:class:: BaseRowFilter + +Base class for filters with single-row kernels. :: + + class BaseRowFilter + { + public: + virtual ~BaseRowFilter(); + + // To be overriden by the user. + // + // runs filtering operation on the single input row + // of "width" element, each element is has "cn" channels. + // the filtered row is written into "dst" buffer. + virtual void operator()(const uchar* src, uchar* dst, + int width, int cn) = 0; + int ksize, anchor; + }; + + +The class ``BaseRowFilter`` is a base class for filtering data using single-row kernels. Filtering does not have to be a linear operation. In general, it could be written as follows: + +.. math:: + + \texttt{dst} (x,y) = F( \texttt{src} [y](x), \; \texttt{src} [y](x+1), \; ..., \; \texttt{src} [y](x+ \texttt{ksize.width} -1)) + +where +:math:`F` is a filtering function. The class only defines an interface and is not used directly. Instead, there are several functions in OpenCV (and you can add more) that return pointers to the derived classes that implement specific filtering operations. Those pointers are then passed to the +:ocv:class:`FilterEngine` constructor. While the filtering operation interface uses the ``uchar`` type, a particular implementation is not limited to 8-bit data. + +.. seealso:: + + :ocv:class:`BaseColumnFilter`, + :ocv:class:`BaseFilter`, + :ocv:class:`FilterEngine`, + :ocv:func:`getLinearRowFilter`, + :ocv:func:`getMorphologyRowFilter`, + :ocv:func:`getRowSumFilter` + + + +FilterEngine +------------ +.. ocv:class:: FilterEngine + +Generic image filtering class. :: + + class FilterEngine + { + public: + // empty constructor + FilterEngine(); + // builds a 2D non-separable filter (!_filter2D.empty()) or + // a separable filter (!_rowFilter.empty() && !_columnFilter.empty()) + // the input data type will be "srcType", the output data type will be "dstType", + // the intermediate data type is "bufType". + // _rowBorderType and _columnBorderType determine how the image + // will be extrapolated beyond the image boundaries. + // _borderValue is only used when _rowBorderType and/or _columnBorderType + // == BORDER_CONSTANT + FilterEngine(const Ptr& _filter2D, + const Ptr& _rowFilter, + const Ptr& _columnFilter, + int srcType, int dstType, int bufType, + int _rowBorderType=BORDER_REPLICATE, + int _columnBorderType=-1, // use _rowBorderType by default + const Scalar& _borderValue=Scalar()); + virtual ~FilterEngine(); + // separate function for the engine initialization + void init(const Ptr& _filter2D, + const Ptr& _rowFilter, + const Ptr& _columnFilter, + int srcType, int dstType, int bufType, + int _rowBorderType=BORDER_REPLICATE, int _columnBorderType=-1, + const Scalar& _borderValue=Scalar()); + // starts filtering of the ROI in an image of size "wholeSize". + // returns the starting y-position in the source image. + virtual int start(Size wholeSize, Rect roi, int maxBufRows=-1); + // alternative form of start that takes the image + // itself instead of "wholeSize". Set isolated to true to pretend that + // there are no real pixels outside of the ROI + // (so that the pixels are extrapolated using the specified border modes) + virtual int start(const Mat& src, const Rect& srcRoi=Rect(0,0,-1,-1), + bool isolated=false, int maxBufRows=-1); + // processes the next portion of the source image, + // "srcCount" rows starting from "src" and + // stores the results in "dst". + // returns the number of produced rows + virtual int proceed(const uchar* src, int srcStep, int srcCount, + uchar* dst, int dstStep); + // higher-level function that processes the whole + // ROI or the whole image with a single call + virtual void apply( const Mat& src, Mat& dst, + const Rect& srcRoi=Rect(0,0,-1,-1), + Point dstOfs=Point(0,0), + bool isolated=false); + bool isSeparable() const { return filter2D.empty(); } + // how many rows from the input image are not yet processed + int remainingInputRows() const; + // how many output rows are not yet produced + int remainingOutputRows() const; + ... + // the starting and the ending rows in the source image + int startY, endY; + + // pointers to the filters + Ptr filter2D; + Ptr rowFilter; + Ptr columnFilter; + }; + + +The class ``FilterEngine`` can be used to apply an arbitrary filtering operation to an image. +It contains all the necessary intermediate buffers, computes extrapolated values +of the "virtual" pixels outside of the image, and so on. Pointers to the initialized ``FilterEngine`` instances +are returned by various ``create*Filter`` functions (see below) and they are used inside high-level functions such as +:ocv:func:`filter2D`, +:ocv:func:`erode`, +:ocv:func:`dilate`, and others. Thus, the class plays a key role in many of OpenCV filtering functions. + +This class makes it easier to combine filtering operations with other operations, such as color space conversions, thresholding, arithmetic operations, and others. By combining several operations together you can get much better performance because your data will stay in cache. For example, see below the implementation of the Laplace operator for floating-point images, which is a simplified implementation of +:ocv:func:`Laplacian` : :: + + void laplace_f(const Mat& src, Mat& dst) + { + CV_Assert( src.type() == CV_32F ); + dst.create(src.size(), src.type()); + + // get the derivative and smooth kernels for d2I/dx2. + // for d2I/dy2 consider using the same kernels, just swapped + Mat kd, ks; + getSobelKernels( kd, ks, 2, 0, ksize, false, ktype ); + + // process 10 source rows at once + int DELTA = std::min(10, src.rows); + Ptr Fxx = createSeparableLinearFilter(src.type(), + dst.type(), kd, ks, Point(-1,-1), 0, borderType, borderType, Scalar() ); + Ptr Fyy = createSeparableLinearFilter(src.type(), + dst.type(), ks, kd, Point(-1,-1), 0, borderType, borderType, Scalar() ); + + int y = Fxx->start(src), dsty = 0, dy = 0; + Fyy->start(src); + const uchar* sptr = src.data + y*src.step; + + // allocate the buffers for the spatial image derivatives; + // the buffers need to have more than DELTA rows, because at the + // last iteration the output may take max(kd.rows-1,ks.rows-1) + // rows more than the input. + Mat Ixx( DELTA + kd.rows - 1, src.cols, dst.type() ); + Mat Iyy( DELTA + kd.rows - 1, src.cols, dst.type() ); + + // inside the loop always pass DELTA rows to the filter + // (note that the "proceed" method takes care of possibe overflow, since + // it was given the actual image height in the "start" method) + // on output you can get: + // * < DELTA rows (initial buffer accumulation stage) + // * = DELTA rows (settled state in the middle) + // * > DELTA rows (when the input image is over, generate + // "virtual" rows using the border mode and filter them) + // this variable number of output rows is dy. + // dsty is the current output row. + // sptr is the pointer to the first input row in the portion to process + for( ; dsty < dst.rows; sptr += DELTA*src.step, dsty += dy ) + { + Fxx->proceed( sptr, (int)src.step, DELTA, Ixx.data, (int)Ixx.step ); + dy = Fyy->proceed( sptr, (int)src.step, DELTA, d2y.data, (int)Iyy.step ); + if( dy > 0 ) + { + Mat dstripe = dst.rowRange(dsty, dsty + dy); + add(Ixx.rowRange(0, dy), Iyy.rowRange(0, dy), dstripe); + } + } + } + + +If you do not need that much control of the filtering process, you can simply use the ``FilterEngine::apply`` method. The method is implemented as follows: :: + + void FilterEngine::apply(const Mat& src, Mat& dst, + const Rect& srcRoi, Point dstOfs, bool isolated) + { + // check matrix types + CV_Assert( src.type() == srcType && dst.type() == dstType ); + + // handle the "whole image" case + Rect _srcRoi = srcRoi; + if( _srcRoi == Rect(0,0,-1,-1) ) + _srcRoi = Rect(0,0,src.cols,src.rows); + + // check if the destination ROI is inside dst. + // and FilterEngine::start will check if the source ROI is inside src. + CV_Assert( dstOfs.x >= 0 && dstOfs.y >= 0 && + dstOfs.x + _srcRoi.width <= dst.cols && + dstOfs.y + _srcRoi.height <= dst.rows ); + + // start filtering + int y = start(src, _srcRoi, isolated); + + // process the whole ROI. Note that "endY - startY" is the total number + // of the source rows to process + // (including the possible rows outside of srcRoi but inside the source image) + proceed( src.data + y*src.step, + (int)src.step, endY - startY, + dst.data + dstOfs.y*dst.step + + dstOfs.x*dst.elemSize(), (int)dst.step ); + } + + +Unlike the earlier versions of OpenCV, now the filtering operations fully support the notion of image ROI, that is, pixels outside of the ROI but inside the image can be used in the filtering operations. For example, you can take a ROI of a single pixel and filter it. This will be a filter response at that particular pixel. However, it is possible to emulate the old behavior by passing ``isolated=false`` to ``FilterEngine::start`` or ``FilterEngine::apply`` . You can pass the ROI explicitly to ``FilterEngine::apply`` or construct new matrix headers: :: + + // compute dI/dx derivative at src(x,y) + + // method 1: + // form a matrix header for a single value + float val1 = 0; + Mat dst1(1,1,CV_32F,&val1); + + Ptr Fx = createDerivFilter(CV_32F, CV_32F, + 1, 0, 3, BORDER_REFLECT_101); + Fx->apply(src, Rect(x,y,1,1), Point(), dst1); + + // method 2: + // form a matrix header for a single value + float val2 = 0; + Mat dst2(1,1,CV_32F,&val2); + + Mat pix_roi(src, Rect(x,y,1,1)); + Sobel(pix_roi, dst2, dst2.type(), 1, 0, 3, 1, 0, BORDER_REFLECT_101); + + printf("method1 = + + +Explore the data types. As it was mentioned in the +:ocv:class:`BaseFilter` description, the specific filters can process data of any type, despite that ``Base*Filter::operator()`` only takes ``uchar`` pointers and no information about the actual types. To make it all work, the following rules are used: + +* + In case of separable filtering, ``FilterEngine::rowFilter`` is applied first. It transforms the input image data (of type ``srcType`` ) to the intermediate results stored in the internal buffers (of type ``bufType`` ). Then, these intermediate results are processed as + *single-channel data* + with ``FilterEngine::columnFilter`` and stored in the output image (of type ``dstType`` ). Thus, the input type for ``rowFilter`` is ``srcType`` and the output type is ``bufType`` . The input type for ``columnFilter`` is ``CV_MAT_DEPTH(bufType)`` and the output type is ``CV_MAT_DEPTH(dstType)`` . + +* + In case of non-separable filtering, ``bufType`` must be the same as ``srcType`` . The source data is copied to the temporary buffer, if needed, and then just passed to ``FilterEngine::filter2D`` . That is, the input type for ``filter2D`` is ``srcType`` (= ``bufType`` ) and the output type is ``dstType`` . + +.. seealso:: + + :ocv:class:`BaseColumnFilter`, + :ocv:class:`BaseFilter`, + :ocv:class:`BaseRowFilter`, + :ocv:func:`createBoxFilter`, + :ocv:func:`createDerivFilter`, + :ocv:func:`createGaussianFilter`, + :ocv:func:`createLinearFilter`, + :ocv:func:`createMorphologyFilter`, + :ocv:func:`createSeparableLinearFilter` + + + +bilateralFilter +------------------- +Applies the bilateral filter to an image. + +.. ocv:function:: void bilateralFilter( InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]]) -> dst + + :param src: Source 8-bit or floating-point, 1-channel or 3-channel image. + + :param dst: Destination image of the same size and type as ``src`` . + + :param d: Diameter of each pixel neighborhood that is used during filtering. If it is non-positive, it is computed from ``sigmaSpace`` . + + :param sigmaColor: Filter sigma in the color space. A larger value of the parameter means that farther colors within the pixel neighborhood (see ``sigmaSpace`` ) will be mixed together, resulting in larger areas of semi-equal color. + + :param sigmaSpace: Filter sigma in the coordinate space. A larger value of the parameter means that farther pixels will influence each other as long as their colors are close enough (see ``sigmaColor`` ). When ``d>0`` , it specifies the neighborhood size regardless of ``sigmaSpace`` . Otherwise, ``d`` is proportional to ``sigmaSpace`` . + +The function applies bilateral filtering to the input image, as described in +http://www.dai.ed.ac.uk/CVonline/LOCAL\_COPIES/MANDUCHI1/Bilateral\_Filtering.html +``bilateralFilter`` can reduce unwanted noise very well while keeping edges fairly sharp. However, it is very slow compared to most filters. + +*Sigma values*: For simplicity, you can set the 2 sigma values to be the same. If they are small (< 10), the filter will not have much effect, whereas if they are large (> 150), they will have a very strong effect, making the image look "cartoonish". + +*Filter size*: Large filters (d > 5) are very slow, so it is recommended to use d=5 for real-time applications, and perhaps d=9 for offline applications that need heavy noise filtering. + +This filter does not work inplace. + + + + +blur +---- +Blurs an image using the normalized box filter. + +.. ocv:function:: void blur( InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.blur(src, ksize[, dst[, anchor[, borderType]]]) -> dst + + :param src: input image; it can have any number of channels, which are processed independently, but the depth should be ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F`` or ``CV_64F``. + + :param dst: output image of the same size and type as ``src``. + + :param ksize: blurring kernel size. + + :param anchor: anchor point; default value ``Point(-1,-1)`` means that the anchor is at the kernel center. + + :param borderType: border mode used to extrapolate pixels outside of the image. + +The function smoothes an image using the kernel: + +.. math:: + + \texttt{K} = \frac{1}{\texttt{ksize.width*ksize.height}} \begin{bmatrix} 1 & 1 & 1 & \cdots & 1 & 1 \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \hdotsfor{6} \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \end{bmatrix} + +The call ``blur(src, dst, ksize, anchor, borderType)`` is equivalent to ``boxFilter(src, dst, src.type(), anchor, true, borderType)`` . + +.. seealso:: + + :ocv:func:`boxFilter`, + :ocv:func:`bilateralFilter`, + :ocv:func:`GaussianBlur`, + :ocv:func:`medianBlur` + + +borderInterpolate +----------------- +Computes the source location of an extrapolated pixel. + +.. ocv:function:: int borderInterpolate( int p, int len, int borderType ) + +.. ocv:pyfunction:: cv2.borderInterpolate(p, len, borderType) -> retval + + :param p: 0-based coordinate of the extrapolated pixel along one of the axes, likely <0 or >= ``len`` . + + :param len: Length of the array along the corresponding axis. + + :param borderType: Border type, one of the ``BORDER_*`` , except for ``BORDER_TRANSPARENT`` and ``BORDER_ISOLATED`` . When ``borderType==BORDER_CONSTANT`` , the function always returns -1, regardless of ``p`` and ``len`` . + +The function computes and returns the coordinate of a donor pixel corresponding to the specified extrapolated pixel when using the specified extrapolation border mode. For example, if you use ``BORDER_WRAP`` mode in the horizontal direction, ``BORDER_REFLECT_101`` in the vertical direction and want to compute value of the "virtual" pixel ``Point(-5, 100)`` in a floating-point image ``img`` , it looks like: :: + + float val = img.at(borderInterpolate(100, img.rows, BORDER_REFLECT_101), + borderInterpolate(-5, img.cols, BORDER_WRAP)); + + +Normally, the function is not called directly. It is used inside +:ocv:class:`FilterEngine` and +:ocv:func:`copyMakeBorder` to compute tables for quick extrapolation. + +.. seealso:: + + :ocv:class:`FilterEngine`, + :ocv:func:`copyMakeBorder` + + + +boxFilter +--------- +Blurs an image using the box filter. + +.. ocv:function:: void boxFilter( InputArray src, OutputArray dst, int ddepth, Size ksize, Point anchor=Point(-1,-1), bool normalize=true, int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.boxFilter(src, ddepth, ksize[, dst[, anchor[, normalize[, borderType]]]]) -> dst + + :param src: input image. + + :param dst: output image of the same size and type as ``src``. + + :param ksize: blurring kernel size. + + :param anchor: anchor point; default value ``Point(-1,-1)`` means that the anchor is at the kernel center. + + :param normalize: flag, specifying whether the kernel is normalized by its area or not. + + :param borderType: border mode used to extrapolate pixels outside of the image. + +The function smoothes an image using the kernel: + +.. math:: + + \texttt{K} = \alpha \begin{bmatrix} 1 & 1 & 1 & \cdots & 1 & 1 \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \hdotsfor{6} \\ 1 & 1 & 1 & \cdots & 1 & 1 \end{bmatrix} + +where + +.. math:: + + \alpha = \fork{\frac{1}{\texttt{ksize.width*ksize.height}}}{when \texttt{normalize=true}}{1}{otherwise} + +Unnormalized box filter is useful for computing various integral characteristics over each pixel neighborhood, such as covariance matrices of image derivatives (used in dense optical flow algorithms, and so on). If you need to compute pixel sums over variable-size windows, use :ocv:func:`integral` . + +.. seealso:: + + :ocv:func:`blur`, + :ocv:func:`bilateralFilter`, + :ocv:func:`GaussianBlur`, + :ocv:func:`medianBlur`, + :ocv:func:`integral` + + + +buildPyramid +------------ +Constructs the Gaussian pyramid for an image. + +.. ocv:function:: void buildPyramid( InputArray src, OutputArrayOfArrays dst, int maxlevel, int borderType=BORDER_DEFAULT ) + + :param src: Source image. Check :ocv:func:`pyrDown` for the list of supported types. + + :param dst: Destination vector of ``maxlevel+1`` images of the same type as ``src`` . ``dst[0]`` will be the same as ``src`` . ``dst[1]`` is the next pyramid layer, a smoothed and down-sized ``src`` , and so on. + + :param maxlevel: 0-based index of the last (the smallest) pyramid layer. It must be non-negative. + +The function constructs a vector of images and builds the Gaussian pyramid by recursively applying +:ocv:func:`pyrDown` to the previously built pyramid layers, starting from ``dst[0]==src`` . + + + +copyMakeBorder +-------------- +Forms a border around an image. + +.. ocv:function:: void copyMakeBorder( InputArray src, OutputArray dst, int top, int bottom, int left, int right, int borderType, const Scalar& value=Scalar() ) + +.. ocv:pyfunction:: cv2.copyMakeBorder(src, top, bottom, left, right, borderType[, dst[, value]]) -> dst + +.. ocv:cfunction:: void cvCopyMakeBorder( const CvArr* src, CvArr* dst, CvPoint offset, int bordertype, CvScalar value=cvScalarAll(0) ) +.. ocv:pyoldfunction:: cv.CopyMakeBorder(src, dst, offset, bordertype, value=(0, 0, 0, 0))-> None + + :param src: Source image. + + :param dst: Destination image of the same type as ``src`` and the size ``Size(src.cols+left+right, src.rows+top+bottom)`` . + + :param top: + + :param bottom: + + :param left: + + :param right: Parameter specifying how many pixels in each direction from the source image rectangle to extrapolate. For example, ``top=1, bottom=1, left=1, right=1`` mean that 1 pixel-wide border needs to be built. + + :param borderType: Border type. See :ocv:func:`borderInterpolate` for details. + + :param value: Border value if ``borderType==BORDER_CONSTANT`` . + +The function copies the source image into the middle of the destination image. The areas to the left, to the right, above and below the copied source image will be filled with extrapolated pixels. This is not what +:ocv:class:`FilterEngine` or filtering functions based on it do (they extrapolate pixels on-fly), but what other more complex functions, including your own, may do to simplify image boundary handling. + +The function supports the mode when ``src`` is already in the middle of ``dst`` . In this case, the function does not copy ``src`` itself but simply constructs the border, for example: :: + + // let border be the same in all directions + int border=2; + // constructs a larger image to fit both the image and the border + Mat gray_buf(rgb.rows + border*2, rgb.cols + border*2, rgb.depth()); + // select the middle part of it w/o copying data + Mat gray(gray_canvas, Rect(border, border, rgb.cols, rgb.rows)); + // convert image from RGB to grayscale + cvtColor(rgb, gray, CV_RGB2GRAY); + // form a border in-place + copyMakeBorder(gray, gray_buf, border, border, + border, border, BORDER_REPLICATE); + // now do some custom filtering ... + ... + + +.. note:: + + When the source image is a part (ROI) of a bigger image, the function will try to use the pixels outside of the ROI to form a border. To disable this feature and always do extrapolation, as if ``src`` was not a ROI, use ``borderType | BORDER_ISOLATED``. + +.. seealso:: + + :ocv:func:`borderInterpolate` + + +createBoxFilter +------------------- +Returns a box filter engine. + +.. ocv:function:: Ptr createBoxFilter( int srcType, int dstType, Size ksize, Point anchor=Point(-1,-1), bool normalize=true, int borderType=BORDER_DEFAULT) + +.. ocv:function:: Ptr getRowSumFilter(int srcType, int sumType, int ksize, int anchor=-1) + +.. ocv:function:: Ptr getColumnSumFilter(int sumType, int dstType, int ksize, int anchor=-1, double scale=1) + + :param srcType: Source image type. + + :param sumType: Intermediate horizontal sum type that must have as many channels as ``srcType`` . + + :param dstType: Destination image type that must have as many channels as ``srcType`` . + + :param ksize: Aperture size. + + :param anchor: Anchor position with the kernel. Negative values mean that the anchor is at the kernel center. + + :param normalize: Flag specifying whether the sums are normalized or not. See :ocv:func:`boxFilter` for details. + + :param scale: Another way to specify normalization in lower-level ``getColumnSumFilter`` . + + :param borderType: Border type to use. See :ocv:func:`borderInterpolate` . + +The function is a convenience function that retrieves the horizontal sum primitive filter with +:ocv:func:`getRowSumFilter` , vertical sum filter with +:ocv:func:`getColumnSumFilter` , constructs new +:ocv:class:`FilterEngine` , and passes both of the primitive filters there. The constructed filter engine can be used for image filtering with normalized or unnormalized box filter. + +The function itself is used by +:ocv:func:`blur` and +:ocv:func:`boxFilter` . + +.. seealso:: + + :ocv:class:`FilterEngine`, + :ocv:func:`blur`, + :ocv:func:`boxFilter` + + + +createDerivFilter +--------------------- +Returns an engine for computing image derivatives. + +.. ocv:function:: Ptr createDerivFilter( int srcType, int dstType, int dx, int dy, int ksize, int borderType=BORDER_DEFAULT ) + + :param srcType: Source image type. + + :param dstType: Destination image type that must have as many channels as ``srcType`` . + + :param dx: Derivative order in respect of x. + + :param dy: Derivative order in respect of y. + + :param ksize: Aperture size See :ocv:func:`getDerivKernels` . + + :param borderType: Border type to use. See :ocv:func:`borderInterpolate` . + +The function :ocv:func:`createDerivFilter` is a small convenience function that retrieves linear filter coefficients for computing image derivatives using +:ocv:func:`getDerivKernels` and then creates a separable linear filter with +:ocv:func:`createSeparableLinearFilter` . The function is used by +:ocv:func:`Sobel` and +:ocv:func:`Scharr` . + +.. seealso:: + + :ocv:func:`createSeparableLinearFilter`, + :ocv:func:`getDerivKernels`, + :ocv:func:`Scharr`, + :ocv:func:`Sobel` + + + +createGaussianFilter +------------------------ +Returns an engine for smoothing images with the Gaussian filter. + +.. ocv:function:: Ptr createGaussianFilter( int type, Size ksize, double sigma1, double sigma2=0, int borderType=BORDER_DEFAULT ) + + :param type: Source and destination image type. + + :param ksize: Aperture size. See :ocv:func:`getGaussianKernel` . + + :param sigma1: Gaussian sigma in the horizontal direction. See :ocv:func:`getGaussianKernel` . + + :param sigma2: Gaussian sigma in the vertical direction. If 0, then :math:`\texttt{sigma2}\leftarrow\texttt{sigma1}` . + + :param borderType: Border type to use. See :ocv:func:`borderInterpolate` . + +The function :ocv:func:`createGaussianFilter` computes Gaussian kernel coefficients and then returns a separable linear filter for that kernel. The function is used by +:ocv:func:`GaussianBlur` . Note that while the function takes just one data type, both for input and output, you can pass this limitation by calling +:ocv:func:`getGaussianKernel` and then +:ocv:func:`createSeparableLinearFilter` directly. + +.. seealso:: + + :ocv:func:`createSeparableLinearFilter`, + :ocv:func:`getGaussianKernel`, + :ocv:func:`GaussianBlur` + + + +createLinearFilter +---------------------- +Creates a non-separable linear filter engine. + +.. ocv:function:: Ptr createLinearFilter( int srcType, int dstType, InputArray kernel, Point _anchor=Point(-1,-1), double delta=0, int rowBorderType=BORDER_DEFAULT, int columnBorderType=-1, const Scalar& borderValue=Scalar() ) + +.. ocv:function:: Ptr getLinearFilter(int srcType, int dstType, InputArray kernel, Point anchor=Point(-1,-1), double delta=0, int bits=0) + + :param srcType: Source image type. + + :param dstType: Destination image type that must have as many channels as ``srcType`` . + + :param kernel: 2D array of filter coefficients. + + :param anchor: Anchor point within the kernel. Special value ``Point(-1,-1)`` means that the anchor is at the kernel center. + + :param delta: Value added to the filtered results before storing them. + + :param bits: Number of the fractional bits. The parameter is used when the kernel is an integer matrix representing fixed-point filter coefficients. + + :param rowBorderType: Pixel extrapolation method in the vertical direction. For details, see :ocv:func:`borderInterpolate`. + + :param columnBorderType: Pixel extrapolation method in the horizontal direction. + + :param borderValue: Border value used in case of a constant border. + +The function returns a pointer to a 2D linear filter for the specified kernel, the source array type, and the destination array type. The function is a higher-level function that calls ``getLinearFilter`` and passes the retrieved 2D filter to the +:ocv:class:`FilterEngine` constructor. + +.. seealso:: + + :ocv:func:`createSeparableLinearFilter`, + :ocv:class:`FilterEngine`, + :ocv:func:`filter2D` + + +createMorphologyFilter +-------------------------- +Creates an engine for non-separable morphological operations. + +.. ocv:function:: Ptr createMorphologyFilter( int op, int type, InputArray kernel, Point anchor=Point(-1,-1), int rowBorderType=BORDER_CONSTANT, int columnBorderType=-1, const Scalar& borderValue=morphologyDefaultBorderValue() ) + +.. ocv:function:: Ptr getMorphologyFilter( int op, int type, InputArray kernel, Point anchor=Point(-1,-1) ) + +.. ocv:function:: Ptr getMorphologyRowFilter( int op, int type, int ksize, int anchor=-1 ) + +.. ocv:function:: Ptr getMorphologyColumnFilter( int op, int type, int ksize, int anchor=-1 ) + +.. ocv:function:: Scalar morphologyDefaultBorderValue() + + :param op: Morphology operation ID, ``MORPH_ERODE`` or ``MORPH_DILATE`` . + + :param type: Input/output image type. The number of channels can be arbitrary. The depth should be one of ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F` or ``CV_64F``. + + :param kernel: 2D 8-bit structuring element for a morphological operation. Non-zero elements indicate the pixels that belong to the element. + + :param ksize: Horizontal or vertical structuring element size for separable morphological operations. + + :param anchor: Anchor position within the structuring element. Negative values mean that the anchor is at the kernel center. + + :param rowBorderType: Pixel extrapolation method in the vertical direction. For details, see :ocv:func:`borderInterpolate`. + + :param columnBorderType: Pixel extrapolation method in the horizontal direction. + + :param borderValue: Border value in case of a constant border. The default value, \ ``morphologyDefaultBorderValue`` , has a special meaning. It is transformed :math:`+\inf` for the erosion and to :math:`-\inf` for the dilation, which means that the minimum (maximum) is effectively computed only over the pixels that are inside the image. + +The functions construct primitive morphological filtering operations or a filter engine based on them. Normally it is enough to use +:ocv:func:`createMorphologyFilter` or even higher-level +:ocv:func:`erode`, +:ocv:func:`dilate` , or +:ocv:func:`morphologyEx` . +Note that +:ocv:func:`createMorphologyFilter` analyzes the structuring element shape and builds a separable morphological filter engine when the structuring element is square. + +.. seealso:: + + :ocv:func:`erode`, + :ocv:func:`dilate`, + :ocv:func:`morphologyEx`, + :ocv:class:`FilterEngine` + + +createSeparableLinearFilter +------------------------------- +Creates an engine for a separable linear filter. + +.. ocv:function:: Ptr createSeparableLinearFilter( int srcType, int dstType, InputArray rowKernel, InputArray columnKernel, Point anchor=Point(-1,-1), double delta=0, int rowBorderType=BORDER_DEFAULT, int columnBorderType=-1, const Scalar& borderValue=Scalar() ) + +.. ocv:function:: Ptr getLinearColumnFilter( int bufType, int dstType, InputArray kernel, int anchor, int symmetryType, double delta=0, int bits=0 ) + +.. ocv:function:: Ptr getLinearRowFilter( int srcType, int bufType, InputArray kernel, int anchor, int symmetryType ) + + :param srcType: Source array type. + + :param dstType: Destination image type that must have as many channels as ``srcType`` . + + :param bufType: Intermediate buffer type that must have as many channels as ``srcType`` . + + :param rowKernel: Coefficients for filtering each row. + + :param columnKernel: Coefficients for filtering each column. + + :param anchor: Anchor position within the kernel. Negative values mean that anchor is positioned at the aperture center. + + :param delta: Value added to the filtered results before storing them. + + :param bits: Number of the fractional bits. The parameter is used when the kernel is an integer matrix representing fixed-point filter coefficients. + + :param rowBorderType: Pixel extrapolation method in the vertical direction. For details, see :ocv:func:`borderInterpolate`. + + :param columnBorderType: Pixel extrapolation method in the horizontal direction. + + :param borderValue: Border value used in case of a constant border. + + :param symmetryType: Type of each row and column kernel. See :ocv:func:`getKernelType` . + +The functions construct primitive separable linear filtering operations or a filter engine based on them. Normally it is enough to use +:ocv:func:`createSeparableLinearFilter` or even higher-level +:ocv:func:`sepFilter2D` . The function +:ocv:func:`createMorphologyFilter` is smart enough to figure out the ``symmetryType`` for each of the two kernels, the intermediate ``bufType`` and, if filtering can be done in integer arithmetics, the number of ``bits`` to encode the filter coefficients. If it does not work for you, it is possible to call ``getLinearColumnFilter``,``getLinearRowFilter`` directly and then pass them to the +:ocv:class:`FilterEngine` constructor. + +.. seealso:: + + :ocv:func:`sepFilter2D`, + :ocv:func:`createLinearFilter`, + :ocv:class:`FilterEngine`, + :ocv:func:`getKernelType` + + +dilate +------ +Dilates an image by using a specific structuring element. + +.. ocv:function:: void dilate( InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() ) + +.. ocv:pyfunction:: cv2.dilate(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]) -> dst + +.. ocv:cfunction:: void cvDilate( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 ) +.. ocv:pyoldfunction:: cv.Dilate(src, dst, element=None, iterations=1)-> None + + :param src: input image; the number of channels can be arbitrary, but the depth should be one of ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F` or ``CV_64F``. + + :param dst: output image of the same size and type as ``src``. + + :param element: structuring element used for dilation; if ``element=Mat()`` , a ``3 x 3`` rectangular structuring element is used. + + :param anchor: position of the anchor within the element; default value ``(-1, -1)`` means that the anchor is at the element center. + + :param iterations: number of times dilation is applied. + + :param borderType: pixel extrapolation method (see :ocv:func:`borderInterpolate` for details). + + :param borderValue: border value in case of a constant border (see :ocv:func:`createMorphologyFilter` for details). + +The function dilates the source image using the specified structuring element that determines the shape of a pixel neighborhood over which the maximum is taken: + +.. math:: + + \texttt{dst} (x,y) = \max _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y') + +The function supports the in-place mode. Dilation can be applied several ( ``iterations`` ) times. In case of multi-channel images, each channel is processed independently. + +.. seealso:: + + :ocv:func:`erode`, + :ocv:func:`morphologyEx`, + :ocv:func:`createMorphologyFilter` + + +erode +----- +Erodes an image by using a specific structuring element. + +.. ocv:function:: void erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() ) + +.. ocv:pyfunction:: cv2.erode(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]) -> dst + +.. ocv:cfunction:: void cvErode( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1) +.. ocv:pyoldfunction:: cv.Erode(src, dst, element=None, iterations=1)-> None + + :param src: input image; the number of channels can be arbitrary, but the depth should be one of ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F` or ``CV_64F``. + + :param dst: output image of the same size and type as ``src``. + + :param element: structuring element used for erosion; if ``element=Mat()`` , a ``3 x 3`` rectangular structuring element is used. + + :param anchor: position of the anchor within the element; default value ``(-1, -1)`` means that the anchor is at the element center. + + :param iterations: number of times erosion is applied. + + :param borderType: pixel extrapolation method (see :ocv:func:`borderInterpolate` for details). + + :param borderValue: border value in case of a constant border (see :ocv:func:`createMorphologyFilter` for details). + +The function erodes the source image using the specified structuring element that determines the shape of a pixel neighborhood over which the minimum is taken: + +.. math:: + + \texttt{dst} (x,y) = \min _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y') + +The function supports the in-place mode. Erosion can be applied several ( ``iterations`` ) times. In case of multi-channel images, each channel is processed independently. + +.. seealso:: + + :ocv:func:`dilate`, + :ocv:func:`morphologyEx`, + :ocv:func:`createMorphologyFilter` + + + +filter2D +-------- +Convolves an image with the kernel. + +.. ocv:function:: void filter2D( InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]]) -> dst + +.. ocv:cfunction:: void cvFilter2D( const CvArr* src, CvArr* dst, const CvMat* kernel, CvPoint anchor=cvPoint(-1,-1) ) + +.. ocv:pyoldfunction:: cv.Filter2D(src, dst, kernel, anchor=(-1, -1))-> None + + :param src: input image. + + :param dst: output image of the same size and the same number of channels as ``src``. + + + :param ddepth: desired depth of the destination image; if it is negative, it will be the same as ``src.depth()``; the following combinations of ``src.depth()`` and ``ddepth`` are supported: + * ``src.depth()`` = ``CV_8U``, ``ddepth`` = -1/``CV_16S``/``CV_32F``/``CV_64F`` + * ``src.depth()`` = ``CV_16U``/``CV_16S``, ``ddepth`` = -1/``CV_32F``/``CV_64F`` + * ``src.depth()`` = ``CV_32F``, ``ddepth`` = -1/``CV_32F``/``CV_64F`` + * ``src.depth()`` = ``CV_64F``, ``ddepth`` = -1/``CV_64F`` + + when ``ddepth=-1``, the output image will have the same depth as the source. + + :param kernel: convolution kernel (or rather a correlation kernel), a single-channel floating point matrix; if you want to apply different kernels to different channels, split the image into separate color planes using :ocv:func:`split` and process them individually. + + :param anchor: anchor of the kernel that indicates the relative position of a filtered point within the kernel; the anchor should lie within the kernel; default value (-1,-1) means that the anchor is at the kernel center. + + :param delta: optional value added to the filtered pixels before storing them in ``dst``. + + :param borderType: pixel extrapolation method (see :ocv:func:`borderInterpolate` for details). + +The function applies an arbitrary linear filter to an image. In-place operation is supported. When the aperture is partially outside the image, the function interpolates outlier pixel values according to the specified border mode. + +The function does actually compute correlation, not the convolution: + +.. math:: + + \texttt{dst} (x,y) = \sum _{ \stackrel{0\leq x' < \texttt{kernel.cols},}{0\leq y' < \texttt{kernel.rows}} } \texttt{kernel} (x',y')* \texttt{src} (x+x'- \texttt{anchor.x} ,y+y'- \texttt{anchor.y} ) + +That is, the kernel is not mirrored around the anchor point. If you need a real convolution, flip the kernel using +:ocv:func:`flip` and set the new anchor to ``(kernel.cols - anchor.x - 1, kernel.rows - anchor.y - 1)`` . + +The function uses the DFT-based algorithm in case of sufficiently large kernels (~``11 x 11`` or larger) and the direct algorithm (that uses the engine retrieved by :ocv:func:`createLinearFilter` ) for small kernels. + +.. seealso:: + + :ocv:func:`sepFilter2D`, + :ocv:func:`createLinearFilter`, + :ocv:func:`dft`, + :ocv:func:`matchTemplate` + + + +GaussianBlur +------------ +Blurs an image using a Gaussian filter. + +.. ocv:function:: void GaussianBlur( InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]]) -> dst + + :param src: input image; the image can have any number of channels, which are processed independently, but the depth should be ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F`` or ``CV_64F``. + + :param dst: output image of the same size and type as ``src``. + + :param ksize: Gaussian kernel size. ``ksize.width`` and ``ksize.height`` can differ but they both must be positive and odd. Or, they can be zero's and then they are computed from ``sigma*`` . + + :param sigmaX: Gaussian kernel standard deviation in X direction. + + :param sigmaY: Gaussian kernel standard deviation in Y direction; if ``sigmaY`` is zero, it is set to be equal to ``sigmaX``, if both sigmas are zeros, they are computed from ``ksize.width`` and ``ksize.height`` , respectively (see :ocv:func:`getGaussianKernel` for details); to fully control the result regardless of possible future modifications of all this semantics, it is recommended to specify all of ``ksize``, ``sigmaX``, and ``sigmaY``. + + :param borderType: pixel extrapolation method (see :ocv:func:`borderInterpolate` for details). + +The function convolves the source image with the specified Gaussian kernel. In-place filtering is supported. + +.. seealso:: + + :ocv:func:`sepFilter2D`, + :ocv:func:`filter2D`, + :ocv:func:`blur`, + :ocv:func:`boxFilter`, + :ocv:func:`bilateralFilter`, + :ocv:func:`medianBlur` + + +getDerivKernels +--------------- +Returns filter coefficients for computing spatial image derivatives. + +.. ocv:function:: void getDerivKernels( OutputArray kx, OutputArray ky, int dx, int dy, int ksize, bool normalize=false, int ktype=CV_32F ) + +.. ocv:pyfunction:: cv2.getDerivKernels(dx, dy, ksize[, kx[, ky[, normalize[, ktype]]]]) -> kx, ky + + :param kx: Output matrix of row filter coefficients. It has the type ``ktype`` . + + :param ky: Output matrix of column filter coefficients. It has the type ``ktype`` . + + :param dx: Derivative order in respect of x. + + :param dy: Derivative order in respect of y. + + :param ksize: Aperture size. It can be ``CV_SCHARR`` , 1, 3, 5, or 7. + + :param normalize: Flag indicating whether to normalize (scale down) the filter coefficients or not. Theoretically, the coefficients should have the denominator :math:`=2^{ksize*2-dx-dy-2}` . If you are going to filter floating-point images, you are likely to use the normalized kernels. But if you compute derivatives of an 8-bit image, store the results in a 16-bit image, and wish to preserve all the fractional bits, you may want to set ``normalize=false`` . + + :param ktype: Type of filter coefficients. It can be ``CV_32f`` or ``CV_64F`` . + +The function computes and returns the filter coefficients for spatial image derivatives. When ``ksize=CV_SCHARR`` , the Scharr +:math:`3 \times 3` kernels are generated (see +:ocv:func:`Scharr` ). Otherwise, Sobel kernels are generated (see +:ocv:func:`Sobel` ). The filters are normally passed to +:ocv:func:`sepFilter2D` or to +:ocv:func:`createSeparableLinearFilter` . + + + +getGaussianKernel +----------------- +Returns Gaussian filter coefficients. + +.. ocv:function:: Mat getGaussianKernel( int ksize, double sigma, int ktype=CV_64F ) + +.. ocv:pyfunction:: cv2.getGaussianKernel(ksize, sigma[, ktype]) -> retval + + :param ksize: Aperture size. It should be odd ( :math:`\texttt{ksize} \mod 2 = 1` ) and positive. + + :param sigma: Gaussian standard deviation. If it is non-positive, it is computed from ``ksize`` as \ ``sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8`` . + :param ktype: Type of filter coefficients. It can be ``CV_32f`` or ``CV_64F`` . + +The function computes and returns the +:math:`\texttt{ksize} \times 1` matrix of Gaussian filter coefficients: + +.. math:: + + G_i= \alpha *e^{-(i-( \texttt{ksize} -1)/2)^2/(2* \texttt{sigma} )^2}, + +where +:math:`i=0..\texttt{ksize}-1` and +:math:`\alpha` is the scale factor chosen so that +:math:`\sum_i G_i=1`. + +Two of such generated kernels can be passed to +:ocv:func:`sepFilter2D` or to +:ocv:func:`createSeparableLinearFilter`. Those functions automatically recognize smoothing kernels (a symmetrical kernel with sum of weights equal to 1) and handle them accordingly. You may also use the higher-level +:ocv:func:`GaussianBlur`. + +.. seealso:: + + :ocv:func:`sepFilter2D`, + :ocv:func:`createSeparableLinearFilter`, + :ocv:func:`getDerivKernels`, + :ocv:func:`getStructuringElement`, + :ocv:func:`GaussianBlur` + + + +getKernelType +------------- +Returns the kernel type. + +.. ocv:function:: int getKernelType(InputArray kernel, Point anchor) + + :param kernel: 1D array of the kernel coefficients to analyze. + + :param anchor: Anchor position within the kernel. + +The function analyzes the kernel coefficients and returns the corresponding kernel type: + + * **KERNEL_GENERAL** The kernel is generic. It is used when there is no any type of symmetry or other properties. + + * **KERNEL_SYMMETRICAL** The kernel is symmetrical: :math:`\texttt{kernel}_i == \texttt{kernel}_{ksize-i-1}` , and the anchor is at the center. + + * **KERNEL_ASYMMETRICAL** The kernel is asymmetrical: :math:`\texttt{kernel}_i == -\texttt{kernel}_{ksize-i-1}` , and the anchor is at the center. + + * **KERNEL_SMOOTH** All the kernel elements are non-negative and summed to 1. For example, the Gaussian kernel is both smooth kernel and symmetrical, so the function returns ``KERNEL_SMOOTH | KERNEL_SYMMETRICAL`` . + * **KERNEL_INTEGER** All the kernel coefficients are integer numbers. This flag can be combined with ``KERNEL_SYMMETRICAL`` or ``KERNEL_ASYMMETRICAL`` . + + + +getStructuringElement +--------------------- +Returns a structuring element of the specified size and shape for morphological operations. + +.. ocv:function:: Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1)) + +.. ocv:pyfunction:: cv2.getStructuringElement(shape, ksize[, anchor]) -> retval + +.. ocv:cfunction:: IplConvKernel* cvCreateStructuringElementEx( int cols, int rows, int anchor_x, int anchor_y, int shape, int* values=NULL ) + +.. ocv:pyoldfunction:: cv.CreateStructuringElementEx(cols, rows, anchorX, anchorY, shape, values=None)-> kernel + + :param shape: Element shape that could be one of the following: + + * **MORPH_RECT** - a rectangular structuring element: + + .. math:: + + E_{ij}=1 + + * **MORPH_ELLIPSE** - an elliptic structuring element, that is, a filled ellipse inscribed into the rectangle ``Rect(0, 0, esize.width, 0.esize.height)`` + + * **MORPH_CROSS** - a cross-shaped structuring element: + + .. math:: + + E_{ij} = \fork{1}{if i=\texttt{anchor.y} or j=\texttt{anchor.x}}{0}{otherwise} + + * **CV_SHAPE_CUSTOM** - custom structuring element (OpenCV 1.x API) + + :param ksize: Size of the structuring element. + + :param cols: Width of the structuring element + + :param rows: Height of the structuring element + + :param anchor: Anchor position within the element. The default value :math:`(-1, -1)` means that the anchor is at the center. Note that only the shape of a cross-shaped element depends on the anchor position. In other cases the anchor just regulates how much the result of the morphological operation is shifted. + + :param anchor_x: x-coordinate of the anchor + + :param anchor_y: y-coordinate of the anchor + + :param values: integer array of ``cols``*``rows`` elements that specifies the custom shape of the structuring element, when ``shape=CV_SHAPE_CUSTOM``. + +The function constructs and returns the structuring element that can be further passed to +:ocv:func:`createMorphologyFilter`, +:ocv:func:`erode`, +:ocv:func:`dilate` or +:ocv:func:`morphologyEx` . But you can also construct an arbitrary binary mask yourself and use it as the structuring element. + +.. note:: When using OpenCV 1.x C API, the created structuring element ``IplConvKernel* element`` must be released in the end using ``cvReleaseStructuringElement(&element)``. + + +medianBlur +---------- +Blurs an image using the median filter. + +.. ocv:function:: void medianBlur( InputArray src, OutputArray dst, int ksize ) + +.. ocv:pyfunction:: cv2.medianBlur(src, ksize[, dst]) -> dst + + :param src: input 1-, 3-, or 4-channel image; when ``ksize`` is 3 or 5, the image depth should be ``CV_8U``, ``CV_16U``, or ``CV_32F``, for larger aperture sizes, it can only be ``CV_8U``. + + :param dst: destination array of the same size and type as ``src``. + + :param ksize: aperture linear size; it must be odd and greater than 1, for example: 3, 5, 7 ... + +The function smoothes an image using the median filter with the +:math:`\texttt{ksize} \times \texttt{ksize}` aperture. Each channel of a multi-channel image is processed independently. In-place operation is supported. + +.. seealso:: + + :ocv:func:`bilateralFilter`, + :ocv:func:`blur`, + :ocv:func:`boxFilter`, + :ocv:func:`GaussianBlur` + + + +morphologyEx +------------ +Performs advanced morphological transformations. + +.. ocv:function:: void morphologyEx( InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() ) + +.. ocv:pyfunction:: cv2.morphologyEx(src, op, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]) -> dst + +.. ocv:cfunction:: void cvMorphologyEx( const CvArr* src, CvArr* dst, CvArr* temp, IplConvKernel* element, int operation, int iterations=1 ) +.. ocv:pyoldfunction:: cv.MorphologyEx(src, dst, temp, element, operation, iterations=1)-> None + + :param src: Source image. The number of channels can be arbitrary. The depth should be one of ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F` or ``CV_64F``. + + :param dst: Destination image of the same size and type as ``src`` . + + :param element: Structuring element. + + :param op: Type of a morphological operation that can be one of the following: + + * **MORPH_OPEN** - an opening operation + + * **MORPH_CLOSE** - a closing operation + + * **MORPH_GRADIENT** - a morphological gradient + + * **MORPH_TOPHAT** - "top hat" + + * **MORPH_BLACKHAT** - "black hat" + + :param iterations: Number of times erosion and dilation are applied. + + :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` for details. + + :param borderValue: Border value in case of a constant border. The default value has a special meaning. See :ocv:func:`createMorphologyFilter` for details. + +The function can perform advanced morphological transformations using an erosion and dilation as basic operations. + +Opening operation: + +.. math:: + + \texttt{dst} = \mathrm{open} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \mathrm{erode} ( \texttt{src} , \texttt{element} )) + +Closing operation: + +.. math:: + + \texttt{dst} = \mathrm{close} ( \texttt{src} , \texttt{element} )= \mathrm{erode} ( \mathrm{dilate} ( \texttt{src} , \texttt{element} )) + +Morphological gradient: + +.. math:: + + \texttt{dst} = \mathrm{morph\_grad} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \texttt{src} , \texttt{element} )- \mathrm{erode} ( \texttt{src} , \texttt{element} ) + +"Top hat": + +.. math:: + + \texttt{dst} = \mathrm{tophat} ( \texttt{src} , \texttt{element} )= \texttt{src} - \mathrm{open} ( \texttt{src} , \texttt{element} ) + +"Black hat": + +.. math:: + + \texttt{dst} = \mathrm{blackhat} ( \texttt{src} , \texttt{element} )= \mathrm{close} ( \texttt{src} , \texttt{element} )- \texttt{src} + +Any of the operations can be done in-place. In case of multi-channel images, each channel is processed independently. + +.. seealso:: + + :ocv:func:`dilate`, + :ocv:func:`erode`, + :ocv:func:`createMorphologyFilter` + + +Laplacian +--------- +Calculates the Laplacian of an image. + +.. ocv:function:: void Laplacian( InputArray src, OutputArray dst, int ddepth, int ksize=1, double scale=1, double delta=0, int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]]) -> dst + +.. ocv:cfunction:: void cvLaplace( const CvArr* src, CvArr* dst, int aperture_size=3 ) + +.. ocv:pyoldfunction:: cv.Laplace(src, dst, apertureSize=3) -> None + + :param src: Source image. + + :param dst: Destination image of the same size and the same number of channels as ``src`` . + + :param ddepth: Desired depth of the destination image. + + :param ksize: Aperture size used to compute the second-derivative filters. See :ocv:func:`getDerivKernels` for details. The size must be positive and odd. + + :param scale: Optional scale factor for the computed Laplacian values. By default, no scaling is applied. See :ocv:func:`getDerivKernels` for details. + + :param delta: Optional delta value that is added to the results prior to storing them in ``dst`` . + + :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` for details. + +The function calculates the Laplacian of the source image by adding up the second x and y derivatives calculated using the Sobel operator: + +.. math:: + + \texttt{dst} = \Delta \texttt{src} = \frac{\partial^2 \texttt{src}}{\partial x^2} + \frac{\partial^2 \texttt{src}}{\partial y^2} + +This is done when ``ksize > 1`` . When ``ksize == 1`` , the Laplacian is computed by filtering the image with the following +:math:`3 \times 3` aperture: + +.. math:: + + \vecthreethree {0}{1}{0}{1}{-4}{1}{0}{1}{0} + +.. seealso:: + + :ocv:func:`Sobel`, + :ocv:func:`Scharr` + + + +pyrDown +------- +Blurs an image and downsamples it. + +.. ocv:function:: void pyrDown( InputArray src, OutputArray dst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.pyrDown(src[, dst[, dstsize[, borderType]]]) -> dst + +.. ocv:cfunction:: void cvPyrDown( const CvArr* src, CvArr* dst, int filter=CV_GAUSSIAN_5x5 ) + +.. ocv:pyoldfunction:: cv.PyrDown(src, dst, filter=CV_GAUSSIAN_5X5) -> None + + :param src: input image. + + :param dst: output image; it has the specified size and the same type as ``src``. + + :param dstsize: size of the output image; by default, it is computed as ``Size((src.cols+1)/2, (src.rows+1)/2)``, but in any case, the following conditions should be satisfied: + + .. math:: + + \begin{array}{l} + | \texttt{dstsize.width} *2-src.cols| \leq 2 \\ | \texttt{dstsize.height} *2-src.rows| \leq 2 \end{array} + +The function performs the downsampling step of the Gaussian pyramid construction. First, it convolves the source image with the kernel: + +.. math:: + + \frac{1}{256} \begin{bmatrix} 1 & 4 & 6 & 4 & 1 \\ 4 & 16 & 24 & 16 & 4 \\ 6 & 24 & 36 & 24 & 6 \\ 4 & 16 & 24 & 16 & 4 \\ 1 & 4 & 6 & 4 & 1 \end{bmatrix} + +Then, it downsamples the image by rejecting even rows and columns. + + + +pyrUp +----- +Upsamples an image and then blurs it. + +.. ocv:function:: void pyrUp( InputArray src, OutputArray dst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.pyrUp(src[, dst[, dstsize[, borderType]]]) -> dst + +.. ocv:cfunction:: cvPyrUp( const CvArr* src, CvArr* dst, int filter=CV_GAUSSIAN_5x5 ) + +.. ocv:pyoldfunction:: cv.PyrUp(src, dst, filter=CV_GAUSSIAN_5X5) -> None + + :param src: input image. + + :param dst: output image. It has the specified size and the same type as ``src`` . + + :param dstsize: size of the output image; by default, it is computed as ``Size(src.cols*2, (src.rows*2)``, but in any case, the following conditions should be satisfied: + + .. math:: + + \begin{array}{l} + | \texttt{dstsize.width} -src.cols*2| \leq ( \texttt{dstsize.width} \mod 2) \\ | \texttt{dstsize.height} -src.rows*2| \leq ( \texttt{dstsize.height} \mod 2) \end{array} + +The function performs the upsampling step of the Gaussian pyramid construction, though it can actually be used to construct the Laplacian pyramid. First, it upsamples the source image by injecting even zero rows and columns and then convolves the result with the same kernel as in +:ocv:func:`pyrDown` multiplied by 4. + + +pyrMeanShiftFiltering +--------------------- +Performs initial step of meanshift segmentation of an image. + +.. ocv:function:: void pyrMeanShiftFiltering( InputArray src, OutputArray dst, double sp, double sr, int maxLevel=1, TermCriteria termcrit=TermCriteria( TermCriteria::MAX_ITER+TermCriteria::EPS,5,1) ) + +.. ocv:pyfunction:: cv2.pyrMeanShiftFiltering(src, sp, sr[, dst[, maxLevel[, termcrit]]]) -> dst + +.. ocv:cfunction:: void cvPyrMeanShiftFiltering( const CvArr* src, CvArr* dst, double sp, double sr, int max_level=1, CvTermCriteria termcrit= cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,5,1)) + +.. ocv:pyoldfunction:: cv.PyrMeanShiftFiltering(src, dst, sp, sr, max_level=1, termcrit=(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 5, 1)) -> None + + :param src: The source 8-bit, 3-channel image. + + :param dst: The destination image of the same format and the same size as the source. + + :param sp: The spatial window radius. + + :param sr: The color window radius. + + :param maxLevel: Maximum level of the pyramid for the segmentation. + + :param termcrit: Termination criteria: when to stop meanshift iterations. + + +The function implements the filtering stage of meanshift segmentation, that is, the output of the function is the filtered "posterized" image with color gradients and fine-grain texture flattened. At every pixel +``(X,Y)`` of the input image (or down-sized input image, see below) the function executes meanshift +iterations, that is, the pixel ``(X,Y)`` neighborhood in the joint space-color hyperspace is considered: + + .. math:: + + (x,y): X- \texttt{sp} \le x \le X+ \texttt{sp} , Y- \texttt{sp} \le y \le Y+ \texttt{sp} , ||(R,G,B)-(r,g,b)|| \le \texttt{sr} + + +where ``(R,G,B)`` and ``(r,g,b)`` are the vectors of color components at ``(X,Y)`` and ``(x,y)``, respectively (though, the algorithm does not depend on the color space used, so any 3-component color space can be used instead). Over the neighborhood the average spatial value ``(X',Y')`` and average color vector ``(R',G',B')`` are found and they act as the neighborhood center on the next iteration: + + .. math:: + + (X,Y)~(X',Y'), (R,G,B)~(R',G',B'). + +After the iterations over, the color components of the initial pixel (that is, the pixel from where the iterations started) are set to the final value (average color at the last iteration): + + .. math:: + + I(X,Y) <- (R*,G*,B*) + +When ``maxLevel > 0``, the gaussian pyramid of ``maxLevel+1`` levels is built, and the above procedure is run on the smallest layer first. After that, the results are propagated to the larger layer and the iterations are run again only on those pixels where the layer colors differ by more than ``sr`` from the lower-resolution layer of the pyramid. That makes boundaries of color regions sharper. Note that the results will be actually different from the ones obtained by running the meanshift procedure on the whole original image (i.e. when ``maxLevel==0``). + + +sepFilter2D +----------- +Applies a separable linear filter to an image. + +.. ocv:function:: void sepFilter2D( InputArray src, OutputArray dst, int ddepth, InputArray kernelX, InputArray kernelY, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.sepFilter2D(src, ddepth, kernelX, kernelY[, dst[, anchor[, delta[, borderType]]]]) -> dst + + :param src: Source image. + + :param dst: Destination image of the same size and the same number of channels as ``src`` . + + :param ddepth: Destination image depth. The following combination of ``src.depth()`` and ``ddepth`` are supported: + * ``src.depth()`` = ``CV_8U``, ``ddepth`` = -1/``CV_16S``/``CV_32F``/``CV_64F`` + * ``src.depth()`` = ``CV_16U``/``CV_16S``, ``ddepth`` = -1/``CV_32F``/``CV_64F`` + * ``src.depth()`` = ``CV_32F``, ``ddepth`` = -1/``CV_32F``/``CV_64F`` + * ``src.depth()`` = ``CV_64F``, ``ddepth`` = -1/``CV_64F`` + + when ``ddepth=-1``, the destination image will have the same depth as the source. + + :param kernelX: Coefficients for filtering each row. + + :param kernelY: Coefficients for filtering each column. + + :param anchor: Anchor position within the kernel. The default value :math:`(-1, 1)` means that the anchor is at the kernel center. + + :param delta: Value added to the filtered results before storing them. + + :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` for details. + +The function applies a separable linear filter to the image. That is, first, every row of ``src`` is filtered with the 1D kernel ``kernelX`` . Then, every column of the result is filtered with the 1D kernel ``kernelY`` . The final result shifted by ``delta`` is stored in ``dst`` . + +.. seealso:: + + :ocv:func:`createSeparableLinearFilter`, + :ocv:func:`filter2D`, + :ocv:func:`Sobel`, + :ocv:func:`GaussianBlur`, + :ocv:func:`boxFilter`, + :ocv:func:`blur` + + +Smooth +------ +Smooths the image in one of several ways. + +.. ocv:cfunction:: void cvSmooth( const CvArr* src, CvArr* dst, int smoothtype=CV_GAUSSIAN, int size1=3, int size2=0, double sigma1=0, double sigma2=0 ) + +.. ocv:pyoldfunction:: cv.Smooth(src, dst, smoothtype=CV_GAUSSIAN, param1=3, param2=0, param3=0, param4=0)-> None + + :param src: The source image + + :param dst: The destination image + + :param smoothtype: Type of the smoothing: + + * **CV_BLUR_NO_SCALE** linear convolution with :math:`\texttt{size1}\times\texttt{size2}` box kernel (all 1's). If you want to smooth different pixels with different-size box kernels, you can use the integral image that is computed using :ocv:func:`integral` + + + * **CV_BLUR** linear convolution with :math:`\texttt{size1}\times\texttt{size2}` box kernel (all 1's) with subsequent scaling by :math:`1/(\texttt{size1}\cdot\texttt{size2})` + + + * **CV_GAUSSIAN** linear convolution with a :math:`\texttt{size1}\times\texttt{size2}` Gaussian kernel + + + * **CV_MEDIAN** median filter with a :math:`\texttt{size1}\times\texttt{size1}` square aperture + + + * **CV_BILATERAL** bilateral filter with a :math:`\texttt{size1}\times\texttt{size1}` square aperture, color sigma= ``sigma1`` and spatial sigma= ``sigma2`` . If ``size1=0`` , the aperture square side is set to ``cvRound(sigma2*1.5)*2+1`` . Information about bilateral filtering can be found at http://www.dai.ed.ac.uk/CVonline/LOCAL\_COPIES/MANDUCHI1/Bilateral\_Filtering.html + + + :param size1: The first parameter of the smoothing operation, the aperture width. Must be a positive odd number (1, 3, 5, ...) + + :param size2: The second parameter of the smoothing operation, the aperture height. Ignored by ``CV_MEDIAN`` and ``CV_BILATERAL`` methods. In the case of simple scaled/non-scaled and Gaussian blur if ``size2`` is zero, it is set to ``size1`` . Otherwise it must be a positive odd number. + + :param sigma1: In the case of a Gaussian parameter this parameter may specify Gaussian :math:`\sigma` (standard deviation). If it is zero, it is calculated from the kernel size: + + .. math:: + + \sigma = 0.3 (n/2 - 1) + 0.8 \quad \text{where} \quad n= \begin{array}{l l} \mbox{\texttt{size1} for horizontal kernel} \\ \mbox{\texttt{size2} for vertical kernel} \end{array} + + Using standard sigma for small kernels ( :math:`3\times 3` to :math:`7\times 7` ) gives better speed. If ``sigma1`` is not zero, while ``size1`` and ``size2`` are zeros, the kernel size is calculated from the sigma (to provide accurate enough operation). + +The function smooths an image using one of several methods. Every of the methods has some features and restrictions listed below: + + * Blur with no scaling works with single-channel images only and supports accumulation of 8-bit to 16-bit format (similar to :ocv:func:`Sobel` and :ocv:func:`Laplacian`) and 32-bit floating point to 32-bit floating-point format. + + * Simple blur and Gaussian blur support 1- or 3-channel, 8-bit and 32-bit floating point images. These two methods can process images in-place. + + * Median and bilateral filters work with 1- or 3-channel 8-bit images and can not process images in-place. + +.. note:: The function is now obsolete. Use :ocv:func:`GaussianBlur`, :ocv:func:`blur`, :ocv:func:`medianBlur` or :ocv:func:`bilateralFilter`. + + +Sobel +----- +Calculates the first, second, third, or mixed image derivatives using an extended Sobel operator. + +.. ocv:function:: void Sobel( InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize=3, double scale=1, double delta=0, int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]]) -> dst + +.. ocv:cfunction:: void cvSobel( const CvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size=3 ) + +.. ocv:pyoldfunction:: cv.Sobel(src, dst, xorder, yorder, apertureSize=3)-> None + + :param src: input image. + + :param dst: output image of the same size and the same number of channels as ``src`` . + + :param ddepth: output image depth; the following combinations of ``src.depth()`` and ``ddepth`` are supported: + * ``src.depth()`` = ``CV_8U``, ``ddepth`` = -1/``CV_16S``/``CV_32F``/``CV_64F`` + * ``src.depth()`` = ``CV_16U``/``CV_16S``, ``ddepth`` = -1/``CV_32F``/``CV_64F`` + * ``src.depth()`` = ``CV_32F``, ``ddepth`` = -1/``CV_32F``/``CV_64F`` + * ``src.depth()`` = ``CV_64F``, ``ddepth`` = -1/``CV_64F`` + + when ``ddepth=-1``, the destination image will have the same depth as the source; in the case of 8-bit input images it will result in truncated derivatives. + + :param xorder: order of the derivative x. + + :param yorder: order of the derivative y. + + :param ksize: size of the extended Sobel kernel; it must be 1, 3, 5, or 7. + + :param scale: optional scale factor for the computed derivative values; by default, no scaling is applied (see :ocv:func:`getDerivKernels` for details). + + :param delta: optional delta value that is added to the results prior to storing them in ``dst``. + + :param borderType: pixel extrapolation method (see :ocv:func:`borderInterpolate` for details). + +In all cases except one, the +:math:`\texttt{ksize} \times +\texttt{ksize}` separable kernel is used to calculate the +derivative. When +:math:`\texttt{ksize = 1}` , the +:math:`3 \times 1` or +:math:`1 \times 3` kernel is used (that is, no Gaussian smoothing is done). ``ksize = 1`` can only be used for the first or the second x- or y- derivatives. + +There is also the special value ``ksize = CV_SCHARR`` (-1) that corresponds to the +:math:`3\times3` Scharr +filter that may give more accurate results than the +:math:`3\times3` Sobel. The Scharr aperture is + +.. math:: + + \vecthreethree{-3}{0}{3}{-10}{0}{10}{-3}{0}{3} + +for the x-derivative, or transposed for the y-derivative. + +The function calculates an image derivative by convolving the image with the appropriate kernel: + +.. math:: + + \texttt{dst} = \frac{\partial^{xorder+yorder} \texttt{src}}{\partial x^{xorder} \partial y^{yorder}} + +The Sobel operators combine Gaussian smoothing and differentiation, +so the result is more or less resistant to the noise. Most often, +the function is called with ( ``xorder`` = 1, ``yorder`` = 0, ``ksize`` = 3) or ( ``xorder`` = 0, ``yorder`` = 1, ``ksize`` = 3) to calculate the first x- or y- image +derivative. The first case corresponds to a kernel of: + +.. math:: + + \vecthreethree{-1}{0}{1}{-2}{0}{2}{-1}{0}{1} + +The second case corresponds to a kernel of: + +.. math:: + + \vecthreethree{-1}{-2}{-1}{0}{0}{0}{1}{2}{1} + +.. seealso:: + + :ocv:func:`Scharr`, + :ocv:func:`Laplacian`, + :ocv:func:`sepFilter2D`, + :ocv:func:`filter2D`, + :ocv:func:`GaussianBlur`, + :ocv:func:`cartToPolar` + + + +Scharr +------ +Calculates the first x- or y- image derivative using Scharr operator. + +.. ocv:function:: void Scharr( InputArray src, OutputArray dst, int ddepth, int dx, int dy, double scale=1, double delta=0, int borderType=BORDER_DEFAULT ) + +.. ocv:pyfunction:: cv2.Scharr(src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]]) -> dst + + :param src: input image. + + :param dst: output image of the same size and the same number of channels as ``src``. + + :param ddepth: output image depth (see :ocv:func:`Sobel` for the list of supported combination of ``src.depth()`` and ``ddepth``). + + :param dx: order of the derivative x. + + :param dy: order of the derivative y. + + :param scale: optional scale factor for the computed derivative values; by default, no scaling is applied (see :ocv:func:`getDerivKernels` for details). + + :param delta: optional delta value that is added to the results prior to storing them in ``dst``. + + :param borderType: pixel extrapolation method (see :ocv:func:`borderInterpolate` for details). + +The function computes the first x- or y- spatial image derivative using the Scharr operator. The call + +.. math:: + + \texttt{Scharr(src, dst, ddepth, dx, dy, scale, delta, borderType)} + +is equivalent to + +.. math:: + + \texttt{Sobel(src, dst, ddepth, dx, dy, CV\_SCHARR, scale, delta, borderType)} . + +.. seealso:: + + :ocv:func:`cartToPolar` + diff --git a/imgproc/doc/geometric_transformations.rst b/imgproc/doc/geometric_transformations.rst new file mode 100644 index 0000000..c48da01 --- /dev/null +++ b/imgproc/doc/geometric_transformations.rst @@ -0,0 +1,706 @@ +Geometric Image Transformations +=============================== +.. highlight:: cpp + +The functions in this section perform various geometrical transformations of 2D images. They do not change the image content but deform the pixel grid and map this deformed grid to the destination image. In fact, to avoid sampling artifacts, the mapping is done in the reverse order, from destination to the source. That is, for each pixel :math:`(x, y)` of the destination image, the functions compute coordinates of the corresponding "donor" pixel in the source image and copy the pixel value: + +.. math:: + + \texttt{dst} (x,y)= \texttt{src} (f_x(x,y), f_y(x,y)) + +In case when you specify the forward mapping +:math:`\left: \texttt{src} \rightarrow \texttt{dst}` , the OpenCV functions first compute the corresponding inverse mapping +:math:`\left: \texttt{dst} \rightarrow \texttt{src}` and then use the above formula. + +The actual implementations of the geometrical transformations, from the most generic +:ocv:func:`remap` and to the simplest and the fastest +:ocv:func:`resize` , need to solve two main problems with the above formula: + +* + Extrapolation of non-existing pixels. Similarly to the filtering functions described in the previous section, for some + :math:`(x,y)` , either one of + :math:`f_x(x,y)` , or + :math:`f_y(x,y)` , or both of them may fall outside of the image. In this case, an extrapolation method needs to be used. OpenCV provides the same selection of extrapolation methods as in the filtering functions. In addition, it provides the method ``BORDER_TRANSPARENT`` . This means that the corresponding pixels in the destination image will not be modified at all. + +* + Interpolation of pixel values. Usually + :math:`f_x(x,y)` and + :math:`f_y(x,y)` are floating-point numbers. This means that + :math:`\left` can be either an affine or perspective transformation, or radial lens distortion correction, and so on. So, a pixel value at fractional coordinates needs to be retrieved. In the simplest case, the coordinates can be just rounded to the nearest integer coordinates and the corresponding pixel can be used. This is called a nearest-neighbor interpolation. However, a better result can be achieved by using more sophisticated `interpolation methods `_ + , where a polynomial function is fit into some neighborhood of the computed pixel + :math:`(f_x(x,y), f_y(x,y))` , and then the value of the polynomial at + :math:`(f_x(x,y), f_y(x,y))` is taken as the interpolated pixel value. In OpenCV, you can choose between several interpolation methods. See + :ocv:func:`resize` for details. + +convertMaps +----------- +Converts image transformation maps from one representation to another. + +.. ocv:function:: void convertMaps( InputArray map1, InputArray map2, OutputArray dstmap1, OutputArray dstmap2, int dstmap1type, bool nninterpolation=false ) + +.. ocv:pyfunction:: cv2.convertMaps(map1, map2, dstmap1type[, dstmap1[, dstmap2[, nninterpolation]]]) -> dstmap1, dstmap2 + + :param map1: The first input map of type ``CV_16SC2`` , ``CV_32FC1`` , or ``CV_32FC2`` . + + :param map2: The second input map of type ``CV_16UC1`` , ``CV_32FC1`` , or none (empty matrix), respectively. + + :param dstmap1: The first output map that has the type ``dstmap1type`` and the same size as ``src`` . + + :param dstmap2: The second output map. + + :param dstmap1type: Type of the first output map that should be ``CV_16SC2`` , ``CV_32FC1`` , or ``CV_32FC2`` . + + :param nninterpolation: Flag indicating whether the fixed-point maps are used for the nearest-neighbor or for a more complex interpolation. + +The function converts a pair of maps for +:ocv:func:`remap` from one representation to another. The following options ( ``(map1.type(), map2.type())`` :math:`\rightarrow` ``(dstmap1.type(), dstmap2.type())`` ) are supported: + +* + :math:`\texttt{(CV\_32FC1, CV\_32FC1)} \rightarrow \texttt{(CV\_16SC2, CV\_16UC1)}` . This is the most frequently used conversion operation, in which the original floating-point maps (see + :ocv:func:`remap` ) are converted to a more compact and much faster fixed-point representation. The first output array contains the rounded coordinates and the second array (created only when ``nninterpolation=false`` ) contains indices in the interpolation tables. + +* + :math:`\texttt{(CV\_32FC2)} \rightarrow \texttt{(CV\_16SC2, CV\_16UC1)}` . The same as above but the original maps are stored in one 2-channel matrix. + +* + Reverse conversion. Obviously, the reconstructed floating-point maps will not be exactly the same as the originals. + +.. seealso:: + + :ocv:func:`remap`, + :ocv:func:`undistort`, + :ocv:func:`initUndistortRectifyMap` + + + +getAffineTransform +---------------------- +Calculates an affine transform from three pairs of the corresponding points. + +.. ocv:function:: Mat getAffineTransform( InputArray src, InputArray dst ) + +.. ocv:function:: Mat getAffineTransform( const Point2f src[], const Point2f dst[] ) + +.. ocv:pyfunction:: cv2.getAffineTransform(src, dst) -> retval + +.. ocv:cfunction:: CvMat* cvGetAffineTransform( const CvPoint2D32f * src, const CvPoint2D32f * dst, CvMat * map_matrix ) + +.. ocv:pyoldfunction:: cv.GetAffineTransform(src, dst, mapMatrix)-> None + + :param src: Coordinates of triangle vertices in the source image. + + :param dst: Coordinates of the corresponding triangle vertices in the destination image. + +The function calculates the :math:`2 \times 3` matrix of an affine transform so that: + +.. math:: + + \begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{map\_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix} + +where + +.. math:: + + dst(i)=(x'_i,y'_i), + src(i)=(x_i, y_i), + i=0,1,2 + +.. seealso:: + + :ocv:func:`warpAffine`, + :ocv:func:`transform` + + + +getPerspectiveTransform +--------------------------- +Calculates a perspective transform from four pairs of the corresponding points. + +.. ocv:function:: Mat getPerspectiveTransform( InputArray src, InputArray dst ) + +.. ocv:function:: Mat getPerspectiveTransform( const Point2f src[], const Point2f dst[] ) + +.. ocv:pyfunction:: cv2.getPerspectiveTransform(src, dst) -> retval + +.. ocv:cfunction:: CvMat* cvGetPerspectiveTransform( const CvPoint2D32f* src, const CvPoint2D32f* dst, CvMat* map_matrix ) + +.. ocv:pyoldfunction:: cv.GetPerspectiveTransform(src, dst, mapMatrix)-> None + + :param src: Coordinates of quadrangle vertices in the source image. + + :param dst: Coordinates of the corresponding quadrangle vertices in the destination image. + +The function calculates the :math:`3 \times 3` matrix of a perspective transform so that: + +.. math:: + + \begin{bmatrix} t_i x'_i \\ t_i y'_i \\ t_i \end{bmatrix} = \texttt{map\_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix} + +where + +.. math:: + + dst(i)=(x'_i,y'_i), + src(i)=(x_i, y_i), + i=0,1,2,3 + +.. seealso:: + + :ocv:func:`findHomography`, + :ocv:func:`warpPerspective`, + :ocv:func:`perspectiveTransform` + + +getRectSubPix +----------------- +Retrieves a pixel rectangle from an image with sub-pixel accuracy. + +.. ocv:function:: void getRectSubPix( InputArray image, Size patchSize, Point2f center, OutputArray patch, int patchType=-1 ) + +.. ocv:pyfunction:: cv2.getRectSubPix(image, patchSize, center[, patch[, patchType]]) -> patch + +.. ocv:cfunction:: void cvGetRectSubPix( const CvArr* src, CvArr* dst, CvPoint2D32f center ) +.. ocv:pyoldfunction:: cv.GetRectSubPix(src, dst, center)-> None + + :param src: Source image. + + :param patchSize: Size of the extracted patch. + + :param center: Floating point coordinates of the center of the extracted rectangle within the source image. The center must be inside the image. + + :param dst: Extracted patch that has the size ``patchSize`` and the same number of channels as ``src`` . + + :param patchType: Depth of the extracted pixels. By default, they have the same depth as ``src`` . + +The function ``getRectSubPix`` extracts pixels from ``src`` : + +.. math:: + + dst(x, y) = src(x + \texttt{center.x} - ( \texttt{dst.cols} -1)*0.5, y + \texttt{center.y} - ( \texttt{dst.rows} -1)*0.5) + +where the values of the pixels at non-integer coordinates are retrieved +using bilinear interpolation. Every channel of multi-channel +images is processed independently. While the center of the rectangle +must be inside the image, parts of the rectangle may be +outside. In this case, the replication border mode (see +:ocv:func:`borderInterpolate` ) is used to extrapolate +the pixel values outside of the image. + +.. seealso:: + + :ocv:func:`warpAffine`, + :ocv:func:`warpPerspective` + + +getRotationMatrix2D +----------------------- +Calculates an affine matrix of 2D rotation. + +.. ocv:function:: Mat getRotationMatrix2D( Point2f center, double angle, double scale ) + +.. ocv:pyfunction:: cv2.getRotationMatrix2D(center, angle, scale) -> retval + +.. ocv:cfunction:: CvMat* cv2DRotationMatrix( CvPoint2D32f center, double angle, double scale, CvMat* map_matrix ) + +.. ocv:pyoldfunction:: cv.GetRotationMatrix2D(center, angle, scale, mapMatrix)-> None + + :param center: Center of the rotation in the source image. + + :param angle: Rotation angle in degrees. Positive values mean counter-clockwise rotation (the coordinate origin is assumed to be the top-left corner). + + :param scale: Isotropic scale factor. + + :param map_matrix: The output affine transformation, 2x3 floating-point matrix. + +The function calculates the following matrix: + +.. math:: + + \begin{bmatrix} \alpha & \beta & (1- \alpha ) \cdot \texttt{center.x} - \beta \cdot \texttt{center.y} \\ - \beta & \alpha & \beta \cdot \texttt{center.x} + (1- \alpha ) \cdot \texttt{center.y} \end{bmatrix} + +where + +.. math:: + + \begin{array}{l} \alpha = \texttt{scale} \cdot \cos \texttt{angle} , \\ \beta = \texttt{scale} \cdot \sin \texttt{angle} \end{array} + +The transformation maps the rotation center to itself. If this is not the target, adjust the shift. + +.. seealso:: + + :ocv:func:`getAffineTransform`, + :ocv:func:`warpAffine`, + :ocv:func:`transform` + + + +invertAffineTransform +------------------------- +Inverts an affine transformation. + +.. ocv:function:: void invertAffineTransform(InputArray M, OutputArray iM) + +.. ocv:pyfunction:: cv2.invertAffineTransform(M[, iM]) -> iM + + :param M: Original affine transformation. + + :param iM: Output reverse affine transformation. + +The function computes an inverse affine transformation represented by +:math:`2 \times 3` matrix ``M`` : + +.. math:: + + \begin{bmatrix} a_{11} & a_{12} & b_1 \\ a_{21} & a_{22} & b_2 \end{bmatrix} + +The result is also a +:math:`2 \times 3` matrix of the same type as ``M`` . + + + +LogPolar +-------- +Remaps an image to log-polar space. + +.. ocv:cfunction:: void cvLogPolar( const CvArr* src, CvArr* dst, CvPoint2D32f center, double M, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS ) + +.. ocv:pyoldfunction:: cv.LogPolar(src, dst, center, M, flags=CV_INNER_LINEAR+CV_WARP_FILL_OUTLIERS)-> None + + :param src: Source image + + :param dst: Destination image + + :param center: The transformation center; where the output precision is maximal + + :param M: Magnitude scale parameter. See below + + :param flags: A combination of interpolation methods and the following optional flags: + + * **CV_WARP_FILL_OUTLIERS** fills all of the destination image pixels. If some of them correspond to outliers in the source image, they are set to zero + + * **CV_WARP_INVERSE_MAP** See below + +The function ``cvLogPolar`` transforms the source image using the following transformation: + + * + Forward transformation (``CV_WARP_INVERSE_MAP`` is not set): + + .. math:: + + dst( \phi , \rho ) = src(x,y) + + + * + Inverse transformation (``CV_WARP_INVERSE_MAP`` is set): + + .. math:: + + dst(x,y) = src( \phi , \rho ) + + +where + + .. math:: + + \rho = M \cdot \log{\sqrt{x^2 + y^2}} , \phi =atan(y/x) + + +The function emulates the human "foveal" vision and can be used for fast scale and rotation-invariant template matching, for object tracking and so forth. The function can not operate in-place. + + +remap +----- +Applies a generic geometrical transformation to an image. + +.. ocv:function:: void remap( InputArray src, OutputArray dst, InputArray map1, InputArray map2, int interpolation, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar()) + +.. ocv:pyfunction:: cv2.remap(src, map1, map2, interpolation[, dst[, borderMode[, borderValue]]]) -> dst + +.. ocv:cfunction:: void cvRemap( const CvArr* src, CvArr* dst, const CvArr* mapx, const CvArr* mapy, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar fillval=cvScalarAll(0) ) +.. ocv:pyoldfunction:: cv.Remap(src, dst, mapx, mapy, flags=CV_INNER_LINEAR+CV_WARP_FILL_OUTLIERS, fillval=(0, 0, 0, 0))-> None + + :param src: Source image. + + :param dst: Destination image. It has the same size as ``map1`` and the same type as ``src`` . + :param map1: The first map of either ``(x,y)`` points or just ``x`` values having the type ``CV_16SC2`` , ``CV_32FC1`` , or ``CV_32FC2`` . See :ocv:func:`convertMaps` for details on converting a floating point representation to fixed-point for speed. + + :param map2: The second map of ``y`` values having the type ``CV_16UC1`` , ``CV_32FC1`` , or none (empty map if ``map1`` is ``(x,y)`` points), respectively. + + :param interpolation: Interpolation method (see :ocv:func:`resize` ). The method ``INTER_AREA`` is not supported by this function. + + :param borderMode: Pixel extrapolation method (see :ocv:func:`borderInterpolate` ). When \ ``borderMode=BORDER_TRANSPARENT`` , it means that the pixels in the destination image that corresponds to the "outliers" in the source image are not modified by the function. + + :param borderValue: Value used in case of a constant border. By default, it is 0. + +The function ``remap`` transforms the source image using the specified map: + +.. math:: + + \texttt{dst} (x,y) = \texttt{src} (map_x(x,y),map_y(x,y)) + +where values of pixels with non-integer coordinates are computed using one of available interpolation methods. +:math:`map_x` and +:math:`map_y` can be encoded as separate floating-point maps in +:math:`map_1` and +:math:`map_2` respectively, or interleaved floating-point maps of +:math:`(x,y)` in +:math:`map_1` , or +fixed-point maps created by using +:ocv:func:`convertMaps` . The reason you might want to convert from floating to fixed-point +representations of a map is that they can yield much faster (~2x) remapping operations. In the converted case, +:math:`map_1` contains pairs ``(cvFloor(x), cvFloor(y))`` and +:math:`map_2` contains indices in a table of interpolation coefficients. + +This function cannot operate in-place. + + + +resize +------ +Resizes an image. + +.. ocv:function:: void resize( InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR ) + +.. ocv:pyfunction:: cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) -> dst + +.. ocv:cfunction:: void cvResize( const CvArr* src, CvArr* dst, int interpolation=CV_INTER_LINEAR ) +.. ocv:pyoldfunction:: cv.Resize(src, dst, interpolation=CV_INTER_LINEAR)-> None + + :param src: input image. + + :param dst: output image; it has the size ``dsize`` (when it is non-zero) or the size computed from ``src.size()``, ``fx``, and ``fy``; the type of ``dst`` is the same as of ``src``. + + :param dsize: output image size; if it equals zero, it is computed as: + + .. math:: + + \texttt{dsize = Size(round(fx*src.cols), round(fy*src.rows))} + + + Either ``dsize`` or both ``fx`` and ``fy`` must be non-zero. + + :param fx: scale factor along the horizontal axis; when it equals 0, it is computed as + + .. math:: + + \texttt{(double)dsize.width/src.cols} + + :param fy: scale factor along the vertical axis; when it equals 0, it is computed as + + .. math:: + + \texttt{(double)dsize.height/src.rows} + + :param interpolation: interpolation method: + + * **INTER_NEAREST** - a nearest-neighbor interpolation + + * **INTER_LINEAR** - a bilinear interpolation (used by default) + + * **INTER_AREA** - resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire'-free results. But when the image is zoomed, it is similar to the ``INTER_NEAREST`` method. + + * **INTER_CUBIC** - a bicubic interpolation over 4x4 pixel neighborhood + + * **INTER_LANCZOS4** - a Lanczos interpolation over 8x8 pixel neighborhood + +The function ``resize`` resizes the image ``src`` down to or up to the specified size. +Note that the initial ``dst`` type or size are not taken into account. Instead, the size and type are derived from the ``src``,``dsize``,``fx`` , and ``fy`` . If you want to resize ``src`` so that it fits the pre-created ``dst`` , you may call the function as follows: :: + + // explicitly specify dsize=dst.size(); fx and fy will be computed from that. + resize(src, dst, dst.size(), 0, 0, interpolation); + + +If you want to decimate the image by factor of 2 in each direction, you can call the function this way: :: + + // specify fx and fy and let the function compute the destination image size. + resize(src, dst, Size(), 0.5, 0.5, interpolation); + +To shrink an image, it will generally look best with CV_INTER_AREA interpolation, whereas to enlarge an image, it will generally look best with CV_INTER_CUBIC (slow) or CV_INTER_LINEAR (faster but still looks OK). + +.. seealso:: + + :ocv:func:`warpAffine`, + :ocv:func:`warpPerspective`, + :ocv:func:`remap` + + +warpAffine +---------- +Applies an affine transformation to an image. + +.. ocv:function:: void warpAffine( InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar()) + +.. ocv:pyfunction:: cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) -> dst + +.. ocv:cfunction:: void cvWarpAffine( const CvArr* src, CvArr* dst, const CvMat* map_matrix, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar fillval=cvScalarAll(0) ) + +.. ocv:pyoldfunction:: cv.WarpAffine(src, dst, mapMatrix, flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, fillval=(0, 0, 0, 0))-> None + +.. ocv:cfunction:: void cvGetQuadrangleSubPix( const CvArr* src, CvArr* dst, const CvMat* map_matrix ) + +.. ocv:pyoldfunction:: cv.GetQuadrangleSubPix(src, dst, mapMatrix)-> None + + :param src: input image. + + :param dst: output image that has the size ``dsize`` and the same type as ``src`` . + + :param M: :math:`2\times 3` transformation matrix. + + :param dsize: size of the output image. + + :param flags: combination of interpolation methods (see :ocv:func:`resize` ) and the optional flag ``WARP_INVERSE_MAP`` that means that ``M`` is the inverse transformation ( :math:`\texttt{dst}\rightarrow\texttt{src}` ). + + :param borderMode: pixel extrapolation method (see :ocv:func:`borderInterpolate`); when \ ``borderMode=BORDER_TRANSPARENT`` , it means that the pixels in the destination image corresponding to the "outliers" in the source image are not modified by the function. + + :param borderValue: value used in case of a constant border; by default, it is 0. + +The function ``warpAffine`` transforms the source image using the specified matrix: + +.. math:: + + \texttt{dst} (x,y) = \texttt{src} ( \texttt{M} _{11} x + \texttt{M} _{12} y + \texttt{M} _{13}, \texttt{M} _{21} x + \texttt{M} _{22} y + \texttt{M} _{23}) + +when the flag ``WARP_INVERSE_MAP`` is set. Otherwise, the transformation is first inverted with +:ocv:func:`invertAffineTransform` and then put in the formula above instead of ``M`` . +The function cannot operate in-place. + +.. seealso:: + + :ocv:func:`warpPerspective`, + :ocv:func:`resize`, + :ocv:func:`remap`, + :ocv:func:`getRectSubPix`, + :ocv:func:`transform` + + +.. note:: ``cvGetQuadrangleSubPix`` is similar to ``cvWarpAffine``, but the outliers are extrapolated using replication border mode. + +warpPerspective +--------------- +Applies a perspective transformation to an image. + +.. ocv:function:: void warpPerspective( InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar()) + +.. ocv:pyfunction:: cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) -> dst + +.. ocv:cfunction:: void cvWarpPerspective( const CvArr* src, CvArr* dst, const CvMat* map_matrix, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar fillval=cvScalarAll(0) ) + +.. ocv:pyoldfunction:: cv.WarpPerspective(src, dst, mapMatrix, flags=CV_INNER_LINEAR+CV_WARP_FILL_OUTLIERS, fillval=(0, 0, 0, 0))-> None + + :param src: input image. + + :param dst: output image that has the size ``dsize`` and the same type as ``src`` . + + :param M: :math:`3\times 3` transformation matrix. + + :param dsize: size of the output image. + + :param flags: combination of interpolation methods (``INTER_LINEAR`` or ``INTER_NEAREST``) and the optional flag ``WARP_INVERSE_MAP``, that sets ``M`` as the inverse transformation ( :math:`\texttt{dst}\rightarrow\texttt{src}` ). + + :param borderMode: pixel extrapolation method (``BORDER_CONSTANT`` or ``BORDER_REPLICATE``). + + :param borderValue: value used in case of a constant border; by default, it equals 0. + +The function ``warpPerspective`` transforms the source image using the specified matrix: + +.. math:: + + \texttt{dst} (x,y) = \texttt{src} \left ( \frac{M_{11} x + M_{12} y + M_{13}}{M_{31} x + M_{32} y + M_{33}} , + \frac{M_{21} x + M_{22} y + M_{23}}{M_{31} x + M_{32} y + M_{33}} \right ) + +when the flag ``WARP_INVERSE_MAP`` is set. Otherwise, the transformation is first inverted with +:ocv:func:`invert` and then put in the formula above instead of ``M`` . +The function cannot operate in-place. + +.. seealso:: + + :ocv:func:`warpAffine`, + :ocv:func:`resize`, + :ocv:func:`remap`, + :ocv:func:`getRectSubPix`, + :ocv:func:`perspectiveTransform` + + + + +initUndistortRectifyMap +----------------------- +Computes the undistortion and rectification transformation map. + +.. ocv:function:: void initUndistortRectifyMap( InputArray cameraMatrix, InputArray distCoeffs, InputArray R, InputArray newCameraMatrix, Size size, int m1type, OutputArray map1, OutputArray map2 ) + +.. ocv:pyfunction:: cv2.initUndistortRectifyMap(cameraMatrix, distCoeffs, R, newCameraMatrix, size, m1type[, map1[, map2]]) -> map1, map2 + +.. ocv:cfunction:: void cvInitUndistortRectifyMap( const CvMat* camera_matrix, const CvMat* dist_coeffs, const CvMat * R, const CvMat* new_camera_matrix, CvArr* mapx, CvArr* mapy ) +.. ocv:cfunction:: void cvInitUndistortMap( const CvMat* camera_matrix, const CvMat* distortion_coeffs, CvArr* mapx, CvArr* mapy ) + +.. ocv:pyoldfunction:: cv.InitUndistortRectifyMap(cameraMatrix, distCoeffs, R, newCameraMatrix, map1, map2)-> None +.. ocv:pyoldfunction:: cv.InitUndistortMap(cameraMatrix, distCoeffs, map1, map2)-> None + + :param cameraMatrix: Input camera matrix :math:`A=\vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}` . + + :param distCoeffs: Input vector of distortion coefficients :math:`(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6]])` of 4, 5, or 8 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. + + :param R: Optional rectification transformation in the object space (3x3 matrix). ``R1`` or ``R2`` , computed by :ocv:func:`stereoRectify` can be passed here. If the matrix is empty, the identity transformation is assumed. In ``cvInitUndistortMap`` R assumed to be an identity matrix. + + :param newCameraMatrix: New camera matrix :math:`A'=\vecthreethree{f_x'}{0}{c_x'}{0}{f_y'}{c_y'}{0}{0}{1}` . + + :param size: Undistorted image size. + + :param m1type: Type of the first output map that can be ``CV_32FC1`` or ``CV_16SC2`` . See :ocv:func:`convertMaps` for details. + + :param map1: The first output map. + + :param map2: The second output map. + +The function computes the joint undistortion and rectification transformation and represents the result in the form of maps for +:ocv:func:`remap` . The undistorted image looks like original, as if it is captured with a camera using the camera matrix ``=newCameraMatrix`` and zero distortion. In case of a monocular camera, ``newCameraMatrix`` is usually equal to ``cameraMatrix`` , or it can be computed by +:ocv:func:`getOptimalNewCameraMatrix` for a better control over scaling. In case of a stereo camera, ``newCameraMatrix`` is normally set to ``P1`` or ``P2`` computed by +:ocv:func:`stereoRectify` . + +Also, this new camera is oriented differently in the coordinate space, according to ``R`` . That, for example, helps to align two heads of a stereo camera so that the epipolar lines on both images become horizontal and have the same y- coordinate (in case of a horizontally aligned stereo camera). + +The function actually builds the maps for the inverse mapping algorithm that is used by +:ocv:func:`remap` . That is, for each pixel +:math:`(u, v)` in the destination (corrected and rectified) image, the function computes the corresponding coordinates in the source image (that is, in the original image from camera). The following process is applied: + +.. math:: + + \begin{array}{l} x \leftarrow (u - {c'}_x)/{f'}_x \\ y \leftarrow (v - {c'}_y)/{f'}_y \\{[X\,Y\,W]} ^T \leftarrow R^{-1}*[x \, y \, 1]^T \\ x' \leftarrow X/W \\ y' \leftarrow Y/W \\ x" \leftarrow x' (1 + k_1 r^2 + k_2 r^4 + k_3 r^6) + 2p_1 x' y' + p_2(r^2 + 2 x'^2) \\ y" \leftarrow y' (1 + k_1 r^2 + k_2 r^4 + k_3 r^6) + p_1 (r^2 + 2 y'^2) + 2 p_2 x' y' \\ map_x(u,v) \leftarrow x" f_x + c_x \\ map_y(u,v) \leftarrow y" f_y + c_y \end{array} + +where +:math:`(k_1, k_2, p_1, p_2[, k_3])` are the distortion coefficients. + +In case of a stereo camera, this function is called twice: once for each camera head, after +:ocv:func:`stereoRectify` , which in its turn is called after +:ocv:func:`stereoCalibrate` . But if the stereo camera was not calibrated, it is still possible to compute the rectification transformations directly from the fundamental matrix using +:ocv:func:`stereoRectifyUncalibrated` . For each camera, the function computes homography ``H`` as the rectification transformation in a pixel domain, not a rotation matrix ``R`` in 3D space. ``R`` can be computed from ``H`` as + +.. math:: + + \texttt{R} = \texttt{cameraMatrix} ^{-1} \cdot \texttt{H} \cdot \texttt{cameraMatrix} + +where ``cameraMatrix`` can be chosen arbitrarily. + + + + +getDefaultNewCameraMatrix +------------------------- +Returns the default new camera matrix. + +.. ocv:function:: Mat getDefaultNewCameraMatrix(InputArray cameraMatrix, Size imgsize=Size(), bool centerPrincipalPoint=false ) + +.. ocv:pyfunction:: cv2.getDefaultNewCameraMatrix(cameraMatrix[, imgsize[, centerPrincipalPoint]]) -> retval + + :param cameraMatrix: Input camera matrix. + + :param imgsize: Camera view image size in pixels. + + :param centerPrincipalPoint: Location of the principal point in the new camera matrix. The parameter indicates whether this location should be at the image center or not. + +The function returns the camera matrix that is either an exact copy of the input ``cameraMatrix`` (when ``centerPrinicipalPoint=false`` ), or the modified one (when ``centerPrincipalPoint=true``). + +In the latter case, the new camera matrix will be: + +.. math:: + + \begin{bmatrix} f_x && 0 && ( \texttt{imgSize.width} -1)*0.5 \\ 0 && f_y && ( \texttt{imgSize.height} -1)*0.5 \\ 0 && 0 && 1 \end{bmatrix} , + +where +:math:`f_x` and +:math:`f_y` are +:math:`(0,0)` and +:math:`(1,1)` elements of ``cameraMatrix`` , respectively. + +By default, the undistortion functions in OpenCV (see +:ocv:func:`initUndistortRectifyMap`, +:ocv:func:`undistort`) do not move the principal point. However, when you work with stereo, it is important to move the principal points in both views to the same y-coordinate (which is required by most of stereo correspondence algorithms), and may be to the same x-coordinate too. So, you can form the new camera matrix for each view where the principal points are located at the center. + + + + +undistort +------------- +Transforms an image to compensate for lens distortion. + +.. ocv:function:: void undistort( InputArray src, OutputArray dst, InputArray cameraMatrix, InputArray distCoeffs, InputArray newCameraMatrix=noArray() ) + +.. ocv:pyfunction:: cv2.undistort(src, cameraMatrix, distCoeffs[, dst[, newCameraMatrix]]) -> dst + +.. ocv:cfunction:: void cvUndistort2( const CvArr* src, CvArr* dst, const CvMat* camera_matrix, const CvMat* distortion_coeffs, const CvMat* new_camera_matrix=0 ) + +.. ocv:pyoldfunction:: cv.Undistort2(src, dst, cameraMatrix, distCoeffs)-> None + + :param src: Input (distorted) image. + + :param dst: Output (corrected) image that has the same size and type as ``src`` . + + :param cameraMatrix: Input camera matrix :math:`A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}` . + + :param distCoeffs: Input vector of distortion coefficients :math:`(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6]])` of 4, 5, or 8 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. + + :param newCameraMatrix: Camera matrix of the distorted image. By default, it is the same as ``cameraMatrix`` but you may additionally scale and shift the result by using a different matrix. + +The function transforms an image to compensate radial and tangential lens distortion. + +The function is simply a combination of +:ocv:func:`initUndistortRectifyMap` (with unity ``R`` ) and +:ocv:func:`remap` (with bilinear interpolation). See the former function for details of the transformation being performed. + +Those pixels in the destination image, for which there is no correspondent pixels in the source image, are filled with zeros (black color). + +A particular subset of the source image that will be visible in the corrected image can be regulated by ``newCameraMatrix`` . You can use +:ocv:func:`getOptimalNewCameraMatrix` to compute the appropriate ``newCameraMatrix`` depending on your requirements. + +The camera matrix and the distortion parameters can be determined using +:ocv:func:`calibrateCamera` . If the resolution of images is different from the resolution used at the calibration stage, +:math:`f_x, f_y, c_x` and +:math:`c_y` need to be scaled accordingly, while the distortion coefficients remain the same. + + + + +undistortPoints +------------------- +Computes the ideal point coordinates from the observed point coordinates. + +.. ocv:function:: void undistortPoints( InputArray src, OutputArray dst, InputArray cameraMatrix, InputArray distCoeffs, InputArray R=noArray(), InputArray P=noArray()) + +.. ocv:cfunction:: void cvUndistortPoints( const CvMat* src, CvMat* dst, const CvMat* camera_matrix, const CvMat* dist_coeffs, const CvMat* R=0, const CvMat* P=0 ) +.. ocv:pyoldfunction:: cv.UndistortPoints(src, dst, cameraMatrix, distCoeffs, R=None, P=None)-> None + + :param src: Observed point coordinates, 1xN or Nx1 2-channel (CV_32FC2 or CV_64FC2). + + :param dst: Output ideal point coordinates after undistortion and reverse perspective transformation. If matrix ``P`` is identity or omitted, ``dst`` will contain normalized point coordinates. + + :param cameraMatrix: Camera matrix :math:`\vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}` . + + :param distCoeffs: Input vector of distortion coefficients :math:`(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6]])` of 4, 5, or 8 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. + + :param R: Rectification transformation in the object space (3x3 matrix). ``R1`` or ``R2`` computed by :ocv:func:`stereoRectify` can be passed here. If the matrix is empty, the identity transformation is used. + + :param P: New camera matrix (3x3) or new projection matrix (3x4). ``P1`` or ``P2`` computed by :ocv:func:`stereoRectify` can be passed here. If the matrix is empty, the identity new camera matrix is used. + +The function is similar to +:ocv:func:`undistort` and +:ocv:func:`initUndistortRectifyMap` but it operates on a sparse set of points instead of a raster image. Also the function performs a reverse transformation to +:ocv:func:`projectPoints` . In case of a 3D object, it does not reconstruct its 3D coordinates, but for a planar object, it does, up to a translation vector, if the proper ``R`` is specified. :: + + // (u,v) is the input point, (u', v') is the output point + // camera_matrix=[fx 0 cx; 0 fy cy; 0 0 1] + // P=[fx' 0 cx' tx; 0 fy' cy' ty; 0 0 1 tz] + x" = (u - cx)/fx + y" = (v - cy)/fy + (x',y') = undistort(x",y",dist_coeffs) + [X,Y,W]T = R*[x' y' 1]T + x = X/W, y = Y/W + // only performed if P=[fx' 0 cx' [tx]; 0 fy' cy' [ty]; 0 0 1 [tz]] is specified + u' = x*fx' + cx' + v' = y*fy' + cy', + +where ``undistort()`` is an approximate iterative algorithm that estimates the normalized original point coordinates out of the normalized distorted point coordinates ("normalized" means that the coordinates do not depend on the camera matrix). + +The function can be used for both a stereo camera head or a monocular camera (when R is empty). + + diff --git a/imgproc/doc/histograms.rst b/imgproc/doc/histograms.rst new file mode 100644 index 0000000..f576d5d --- /dev/null +++ b/imgproc/doc/histograms.rst @@ -0,0 +1,506 @@ +Histograms +========== + +.. highlight:: cpp + + + +calcHist +------------ +Calculates a histogram of a set of arrays. + +.. ocv:function:: void calcHist( const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false ) + +.. ocv:function:: void calcHist( const Mat* images, int nimages, const int* channels, InputArray mask, SparseMat& hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false ) + +.. ocv:pyfunction:: cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]]) -> hist + +.. ocv:cfunction:: void cvCalcHist( IplImage** image, CvHistogram* hist, int accumulate=0, const CvArr* mask=NULL ) +.. ocv:pyoldfunction:: cv.CalcHist(image, hist, accumulate=0, mask=None)-> None + + :param images: Source arrays. They all should have the same depth, ``CV_8U`` or ``CV_32F`` , and the same size. Each of them can have an arbitrary number of channels. + + :param nimages: Number of source images. + + :param channels: List of the ``dims`` channels used to compute the histogram. The first array channels are numerated from 0 to ``images[0].channels()-1`` , the second array channels are counted from ``images[0].channels()`` to ``images[0].channels() + images[1].channels()-1``, and so on. + + :param mask: Optional mask. If the matrix is not empty, it must be an 8-bit array of the same size as ``images[i]`` . The non-zero mask elements mark the array elements counted in the histogram. + + :param hist: Output histogram, which is a dense or sparse ``dims`` -dimensional array. + + :param dims: Histogram dimensionality that must be positive and not greater than ``CV_MAX_DIMS`` (equal to 32 in the current OpenCV version). + + :param histSize: Array of histogram sizes in each dimension. + + :param ranges: Array of the ``dims`` arrays of the histogram bin boundaries in each dimension. When the histogram is uniform ( ``uniform`` =true), then for each dimension ``i`` it is enough to specify the lower (inclusive) boundary :math:`L_0` of the 0-th histogram bin and the upper (exclusive) boundary :math:`U_{\texttt{histSize}[i]-1}` for the last histogram bin ``histSize[i]-1`` . That is, in case of a uniform histogram each of ``ranges[i]`` is an array of 2 elements. When the histogram is not uniform ( ``uniform=false`` ), then each of ``ranges[i]`` contains ``histSize[i]+1`` elements: :math:`L_0, U_0=L_1, U_1=L_2, ..., U_{\texttt{histSize[i]}-2}=L_{\texttt{histSize[i]}-1}, U_{\texttt{histSize[i]}-1}` . The array elements, that are not between :math:`L_0` and :math:`U_{\texttt{histSize[i]}-1}` , are not counted in the histogram. + + :param uniform: Flag indicating whether the histogram is uniform or not (see above). + + :param accumulate: Accumulation flag. If it is set, the histogram is not cleared in the beginning when it is allocated. This feature enables you to compute a single histogram from several sets of arrays, or to update the histogram in time. + +The functions ``calcHist`` calculate the histogram of one or more +arrays. The elements of a tuple used to increment +a histogram bin are taken from the corresponding +input arrays at the same location. The sample below shows how to compute a 2D Hue-Saturation histogram for a color image. :: + + #include + #include + + using namespace cv; + + int main( int argc, char** argv ) + { + Mat src, hsv; + if( argc != 2 || !(src=imread(argv[1], 1)).data ) + return -1; + + cvtColor(src, hsv, CV_BGR2HSV); + + // Quantize the hue to 30 levels + // and the saturation to 32 levels + int hbins = 30, sbins = 32; + int histSize[] = {hbins, sbins}; + // hue varies from 0 to 179, see cvtColor + float hranges[] = { 0, 180 }; + // saturation varies from 0 (black-gray-white) to + // 255 (pure spectrum color) + float sranges[] = { 0, 256 }; + const float* ranges[] = { hranges, sranges }; + MatND hist; + // we compute the histogram from the 0-th and 1-st channels + int channels[] = {0, 1}; + + calcHist( &hsv, 1, channels, Mat(), // do not use mask + hist, 2, histSize, ranges, + true, // the histogram is uniform + false ); + double maxVal=0; + minMaxLoc(hist, 0, &maxVal, 0, 0); + + int scale = 10; + Mat histImg = Mat::zeros(sbins*scale, hbins*10, CV_8UC3); + + for( int h = 0; h < hbins; h++ ) + for( int s = 0; s < sbins; s++ ) + { + float binVal = hist.at(h, s); + int intensity = cvRound(binVal*255/maxVal); + rectangle( histImg, Point(h*scale, s*scale), + Point( (h+1)*scale - 1, (s+1)*scale - 1), + Scalar::all(intensity), + CV_FILLED ); + } + + namedWindow( "Source", 1 ); + imshow( "Source", src ); + + namedWindow( "H-S Histogram", 1 ); + imshow( "H-S Histogram", histImg ); + waitKey(); + } + + + + +calcBackProject +------------------- +Calculates the back projection of a histogram. + +.. ocv:function:: void calcBackProject( const Mat* images, int nimages, const int* channels, InputArray hist, OutputArray backProject, const float** ranges, double scale=1, bool uniform=true ) + +.. ocv:function:: void calcBackProject( const Mat* images, int nimages, const int* channels, const SparseMat& hist, OutputArray backProject, const float** ranges, double scale=1, bool uniform=true ) + +.. ocv:pyfunction:: cv2.calcBackProject(images, channels, hist, ranges, scale[, dst]) -> dst + +.. ocv:cfunction:: void cvCalcBackProject( IplImage** image, CvArr* backProject, const CvHistogram* hist ) +.. ocv:pyoldfunction:: cv.CalcBackProject(image, back_project, hist) -> None + + :param images: Source arrays. They all should have the same depth, ``CV_8U`` or ``CV_32F`` , and the same size. Each of them can have an arbitrary number of channels. + + :param nimages: Number of source images. + + :param channels: The list of channels used to compute the back projection. The number of channels must match the histogram dimensionality. The first array channels are numerated from 0 to ``images[0].channels()-1`` , the second array channels are counted from ``images[0].channels()`` to ``images[0].channels() + images[1].channels()-1``, and so on. + + :param hist: Input histogram that can be dense or sparse. + + :param backProject: Destination back projection array that is a single-channel array of the same size and depth as ``images[0]`` . + + :param ranges: Array of arrays of the histogram bin boundaries in each dimension. See :ocv:func:`calcHist` . + + :param scale: Optional scale factor for the output back projection. + + :param uniform: Flag indicating whether the histogram is uniform or not (see above). + +The functions ``calcBackProject`` calculate the back project of the histogram. That is, similarly to ``calcHist`` , at each location ``(x, y)`` the function collects the values from the selected channels in the input images and finds the corresponding histogram bin. But instead of incrementing it, the function reads the bin value, scales it by ``scale`` , and stores in ``backProject(x,y)`` . In terms of statistics, the function computes probability of each element value in respect with the empirical probability distribution represented by the histogram. See how, for example, you can find and track a bright-colored object in a scene: + +#. + Before tracking, show the object to the camera so that it covers almost the whole frame. Calculate a hue histogram. The histogram may have strong maximums, corresponding to the dominant colors in the object. + +#. + When tracking, calculate a back projection of a hue plane of each input video frame using that pre-computed histogram. Threshold the back projection to suppress weak colors. It may also make sense to suppress pixels with non-sufficient color saturation and too dark or too bright pixels. + +#. + Find connected components in the resulting picture and choose, for example, the largest component. + +This is an approximate algorithm of the +:ocv:func:`CamShift` color object tracker. + +.. seealso:: :ocv:func:`calcHist` +.. _compareHist: + +compareHist +----------- +Compares two histograms. + +.. ocv:function:: double compareHist( InputArray H1, InputArray H2, int method ) + +.. ocv:function:: double compareHist( const SparseMat& H1, const SparseMat& H2, int method ) + +.. ocv:pyfunction:: cv2.compareHist(H1, H2, method) -> retval + +.. ocv:cfunction:: double cvCompareHist( const CvHistogram* hist1, const CvHistogram* hist2, int method ) +.. ocv:pyoldfunction:: cv.CompareHist(hist1, hist2, method)->float + + :param H1: First compared histogram. + + :param H2: Second compared histogram of the same size as ``H1`` . + + :param method: Comparison method that could be one of the following: + + * **CV_COMP_CORREL** Correlation + + * **CV_COMP_CHISQR** Chi-Square + + * **CV_COMP_INTERSECT** Intersection + + * **CV_COMP_BHATTACHARYYA** Bhattacharyya distance + + * **CV_COMP_HELLINGER** Synonym for ``CV_COMP_BHATTACHARYYA`` + +The functions ``compareHist`` compare two dense or two sparse histograms using the specified method: + +* Correlation (``method=CV_COMP_CORREL``) + + .. math:: + + d(H_1,H_2) = \frac{\sum_I (H_1(I) - \bar{H_1}) (H_2(I) - \bar{H_2})}{\sqrt{\sum_I(H_1(I) - \bar{H_1})^2 \sum_I(H_2(I) - \bar{H_2})^2}} + + where + + .. math:: + + \bar{H_k} = \frac{1}{N} \sum _J H_k(J) + + and + :math:`N` is a total number of histogram bins. + +* Chi-Square (``method=CV_COMP_CHISQR``) + + .. math:: + + d(H_1,H_2) = \sum _I \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)} + +* Intersection (``method=CV_COMP_INTERSECT``) + + .. math:: + + d(H_1,H_2) = \sum _I \min (H_1(I), H_2(I)) + +* Bhattacharyya distance (``method=CV_COMP_BHATTACHARYYA`` or ``method=CV_COMP_HELLINGER``). In fact, OpenCV computes Hellinger distance, which is related to Bhattacharyya coefficient. + + .. math:: + + d(H_1,H_2) = \sqrt{1 - \frac{1}{\sqrt{\bar{H_1} \bar{H_2} N^2}} \sum_I \sqrt{H_1(I) \cdot H_2(I)}} + +The function returns +:math:`d(H_1, H_2)` . + +While the function works well with 1-, 2-, 3-dimensional dense histograms, it may not be suitable for high-dimensional sparse histograms. In such histograms, because of aliasing and sampling problems, the coordinates of non-zero histogram bins can slightly shift. To compare such histograms or more general sparse configurations of weighted points, consider using the +:ocv:func:`EMD` function. + + + + +EMD +------ +Computes the "minimal work" distance between two weighted point configurations. + +.. ocv:function:: float EMD( InputArray signature1, InputArray signature2, int distType, InputArray cost=noArray(), float* lowerBound=0, OutputArray flow=noArray() ) + +.. ocv:cfunction:: float cvCalcEMD2( const CvArr* signature1, const CvArr* signature2, int distance_type, CvDistanceFunction distance_func=NULL, const CvArr* cost_matrix=NULL, CvArr* flow=NULL, float* lower_bound=NULL, void* userdata=NULL ) + +.. ocv:pyoldfunction:: cv.CalcEMD2(signature1, signature2, distance_type, distance_func=None, cost_matrix=None, flow=None, lower_bound=None, userdata=None) -> float + + :param signature1: First signature, a :math:`\texttt{size1}\times \texttt{dims}+1` floating-point matrix. Each row stores the point weight followed by the point coordinates. The matrix is allowed to have a single column (weights only) if the user-defined cost matrix is used. + + :param signature2: Second signature of the same format as ``signature1`` , though the number of rows may be different. The total weights may be different. In this case an extra "dummy" point is added to either ``signature1`` or ``signature2`` . + + :param distType: Used metric. ``CV_DIST_L1, CV_DIST_L2`` , and ``CV_DIST_C`` stand for one of the standard metrics. ``CV_DIST_USER`` means that a pre-calculated cost matrix ``cost`` is used. + + :param distance_func: Custom distance function supported by the old interface. ``CvDistanceFunction`` is defined as: :: + + typedef float (CV_CDECL * CvDistanceFunction)( const float* a, + const float* b, void* userdata ); + + where ``a`` and ``b`` are point coordinates and ``userdata`` is the same as the last parameter. + + :param cost: User-defined :math:`\texttt{size1}\times \texttt{size2}` cost matrix. Also, if a cost matrix is used, lower boundary ``lowerBound`` cannot be calculated because it needs a metric function. + + :param lowerBound: Optional input/output parameter: lower boundary of a distance between the two signatures that is a distance between mass centers. The lower boundary may not be calculated if the user-defined cost matrix is used, the total weights of point configurations are not equal, or if the signatures consist of weights only (the signature matrices have a single column). You **must** initialize ``*lowerBound`` . If the calculated distance between mass centers is greater or equal to ``*lowerBound`` (it means that the signatures are far enough), the function does not calculate EMD. In any case ``*lowerBound`` is set to the calculated distance between mass centers on return. Thus, if you want to calculate both distance between mass centers and EMD, ``*lowerBound`` should be set to 0. + + :param flow: Resultant :math:`\texttt{size1} \times \texttt{size2}` flow matrix: :math:`\texttt{flow}_{i,j}` is a flow from :math:`i` -th point of ``signature1`` to :math:`j` -th point of ``signature2`` . + + :param userdata: Optional pointer directly passed to the custom distance function. + +The function computes the earth mover distance and/or a lower boundary of the distance between the two weighted point configurations. One of the applications described in [RubnerSept98]_ is multi-dimensional histogram comparison for image retrieval. EMD is a transportation problem that is solved using some modification of a simplex algorithm, thus the complexity is exponential in the worst case, though, on average it is much faster. In the case of a real metric the lower boundary can be calculated even faster (using linear-time algorithm) and it can be used to determine roughly whether the two signatures are far enough so that they cannot relate to the same object. + + +equalizeHist +---------------- +Equalizes the histogram of a grayscale image. + +.. ocv:function:: void equalizeHist( InputArray src, OutputArray dst ) + +.. ocv:pyfunction:: cv2.equalizeHist(src[, dst]) -> dst + +.. ocv:cfunction:: void cvEqualizeHist( const CvArr* src, CvArr* dst ) + + :param src: Source 8-bit single channel image. + + :param dst: Destination image of the same size and type as ``src`` . + +The function equalizes the histogram of the input image using the following algorithm: + +#. + Calculate the histogram + :math:`H` for ``src`` . + +#. + Normalize the histogram so that the sum of histogram bins is 255. + +#. + Compute the integral of the histogram: + + .. math:: + + H'_i = \sum _{0 \le j < i} H(j) + +#. + Transform the image using + :math:`H'` as a look-up table: + :math:`\texttt{dst}(x,y) = H'(\texttt{src}(x,y))` + +The algorithm normalizes the brightness and increases the contrast of the image. + + +Extra Histogram Functions (C API) +--------------------------------- + +The rest of the section describes additional C functions operating on ``CvHistogram``. + +CalcBackProjectPatch +-------------------- +Locates a template within an image by using a histogram comparison. + +.. ocv:cfunction:: void cvCalcBackProjectPatch( IplImage** images, CvArr* dst, CvSize patch_size, CvHistogram* hist, int method, double factor ) + +.. ocv:pyoldfunction:: cv.CalcBackProjectPatch(images, dst, patch_size, hist, method, factor)-> None + + :param images: Source images (though, you may pass CvMat** as well). + + :param dst: Destination image. + + :param patch_size: Size of the patch slid though the source image. + + :param hist: Histogram. + + :param method: Comparison method passed to :ocv:cfunc:`CompareHist` (see the function description). + + :param factor: Normalization factor for histograms that affects the normalization scale of the destination image. Pass 1 if not sure. + +The function calculates the back projection by comparing histograms of the source image patches with the given histogram. The function is similar to :ocv:func:`matchTemplate`, but instead of comparing the raster patch with all its possible positions within the search window, the function ``CalcBackProjectPatch`` compares histograms. See the algorithm diagram below: + +.. image:: pics/backprojectpatch.png + + +CalcProbDensity +--------------- +Divides one histogram by another. + +.. ocv:cfunction:: void cvCalcProbDensity( const CvHistogram* hist1, const CvHistogram* hist2, CvHistogram* dst_hist, double scale=255 ) + +.. ocv:pyoldfunction:: cv.CalcProbDensity(hist1, hist2, dst_hist, scale=255) -> None + + :param hist1: First histogram (the divisor). + + :param hist2: Second histogram. + + :param dst_hist: Destination histogram. + + :param scale: Scale factor for the destination histogram. + +The function calculates the object probability density from two histograms as: + +.. math:: + + \texttt{disthist} (I)= \forkthree{0}{if $\texttt{hist1}(I)=0$}{\texttt{scale}}{if $\texttt{hist1}(I) \ne 0$ and $\texttt{hist2}(I) > \texttt{hist1}(I)$}{\frac{\texttt{hist2}(I) \cdot \texttt{scale}}{\texttt{hist1}(I)}}{if $\texttt{hist1}(I) \ne 0$ and $\texttt{hist2}(I) \le \texttt{hist1}(I)$} + + +ClearHist +--------- +Clears the histogram. + +.. ocv:cfunction:: void cvClearHist( CvHistogram* hist ) +.. ocv:pyoldfunction:: cv.ClearHist(hist)-> None + + :param hist: Histogram. + +The function sets all of the histogram bins to 0 in case of a dense histogram and removes all histogram bins in case of a sparse array. + + +CopyHist +-------- +Copies a histogram. + +.. ocv:cfunction:: void cvCopyHist( const CvHistogram* src, CvHistogram** dst ) + + :param src: Source histogram. + + :param dst: Pointer to the destination histogram. + +The function makes a copy of the histogram. If the second histogram pointer ``*dst`` is NULL, a new histogram of the same size as ``src`` is created. Otherwise, both histograms must have equal types and sizes. Then the function copies the bin values of the source histogram to the destination histogram and sets the same bin value ranges as in ``src``. + +.. _createhist: + +CreateHist +---------- +Creates a histogram. + +.. ocv:cfunction:: CvHistogram* cvCreateHist( int dims, int* sizes, int type, float** ranges=NULL, int uniform=1 ) + +.. ocv:pyoldfunction:: cv.CreateHist(dims, type, ranges=None, uniform=1) -> hist + + :param dims: Number of histogram dimensions. + + :param sizes: Array of the histogram dimension sizes. + + :param type: Histogram representation format. ``CV_HIST_ARRAY`` means that the histogram data is represented as a multi-dimensional dense array CvMatND. ``CV_HIST_SPARSE`` means that histogram data is represented as a multi-dimensional sparse array ``CvSparseMat``. + + :param ranges: Array of ranges for the histogram bins. Its meaning depends on the ``uniform`` parameter value. The ranges are used when the histogram is calculated or backprojected to determine which histogram bin corresponds to which value/tuple of values from the input image(s). + + :param uniform: Uniformity flag. If not zero, the histogram has evenly + spaced bins and for every :math:`0<=i (min_value, max_value, min_idx, max_idx) + + :param hist: Histogram. + + :param min_value: Pointer to the minimum value of the histogram. + + :param max_value: Pointer to the maximum value of the histogram. + + :param min_idx: Pointer to the array of coordinates for the minimum. + + :param max_idx: Pointer to the array of coordinates for the maximum. + +The function finds the minimum and maximum histogram bins and their positions. All of output arguments are optional. Among several extremas with the same value the ones with the minimum index (in the lexicographical order) are returned. In case of several maximums or minimums, the earliest in the lexicographical order (extrema locations) is returned. + + +MakeHistHeaderForArray +---------------------- +Makes a histogram out of an array. + +.. ocv:cfunction:: CvHistogram* cvMakeHistHeaderForArray( int dims, int* sizes, CvHistogram* hist, float* data, float** ranges=NULL, int uniform=1 ) + + :param dims: Number of the histogram dimensions. + + :param sizes: Array of the histogram dimension sizes. + + :param hist: Histogram header initialized by the function. + + :param data: Array used to store histogram bins. + + :param ranges: Histogram bin ranges. See :ocv:cfunc:`CreateHist` for details. + + :param uniform: Uniformity flag. See :ocv:cfunc:`CreateHist` for details. + +The function initializes the histogram, whose header and bins are allocated by the user. :ocv:cfunc:`ReleaseHist` does not need to be called afterwards. Only dense histograms can be initialized this way. The function returns ``hist``. + +NormalizeHist +------------- +Normalizes the histogram. + +.. ocv:cfunction:: void cvNormalizeHist( CvHistogram* hist, double factor ) +.. ocv:pyoldfunction:: cv.NormalizeHist(hist, factor)-> None + + :param hist: Pointer to the histogram. + + :param factor: Normalization factor. + +The function normalizes the histogram bins by scaling them so that the sum of the bins becomes equal to ``factor``. + + +ReleaseHist +----------- +Releases the histogram. + +.. ocv:cfunction:: void cvReleaseHist( CvHistogram** hist ) + + :param hist: Double pointer to the released histogram. + +The function releases the histogram (header and the data). The pointer to the histogram is cleared by the function. If ``*hist`` pointer is already ``NULL``, the function does nothing. + + +SetHistBinRanges +---------------- +Sets the bounds of the histogram bins. + +.. ocv:cfunction:: void cvSetHistBinRanges( CvHistogram* hist, float** ranges, int uniform=1 ) + + :param hist: Histogram. + + :param ranges: Array of bin ranges arrays. See :ocv:cfunc:`CreateHist` for details. + + :param uniform: Uniformity flag. See :ocv:cfunc:`CreateHist` for details. + +This is a standalone function for setting bin ranges in the histogram. For a more detailed description of the parameters ``ranges`` and ``uniform``, see the :ocv:cfunc:`CalcHist` function that can initialize the ranges as well. Ranges for the histogram bins must be set before the histogram is calculated or the backproject of the histogram is calculated. + + +ThreshHist +---------- +Thresholds the histogram. + +.. ocv:cfunction:: void cvThreshHist( CvHistogram* hist, double threshold ) +.. ocv:pyoldfunction:: cv.ThreshHist(hist, threshold) -> None + + :param hist: Pointer to the histogram. + + :param threshold: Threshold level. + +The function clears histogram bins that are below the specified threshold. + + +.. [RubnerSept98] Y. Rubner. C. Tomasi, L.J. Guibas. *The Earth Mover’s Distance as a Metric for Image Retrieval*. Technical Report STAN-CS-TN-98-86, Department of Computer Science, Stanford University, September 1998. diff --git a/imgproc/doc/imgproc.rst b/imgproc/doc/imgproc.rst new file mode 100644 index 0000000..acaebc4 --- /dev/null +++ b/imgproc/doc/imgproc.rst @@ -0,0 +1,17 @@ +************************* +imgproc. Image Processing +************************* + +.. highlight:: cpp + +.. toctree:: + :maxdepth: 2 + + filtering + geometric_transformations + miscellaneous_transformations + histograms + structural_analysis_and_shape_descriptors + motion_analysis_and_object_tracking + feature_detection + object_detection diff --git a/imgproc/doc/miscellaneous_transformations.rst b/imgproc/doc/miscellaneous_transformations.rst new file mode 100644 index 0000000..9b0ee6d --- /dev/null +++ b/imgproc/doc/miscellaneous_transformations.rst @@ -0,0 +1,795 @@ +Miscellaneous Image Transformations +=================================== + +.. highlight:: cpp + + +adaptiveThreshold +--------------------- +Applies an adaptive threshold to an array. + +.. ocv:function:: void adaptiveThreshold( InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C ) + +.. ocv:pyfunction:: cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst]) -> dst + +.. ocv:cfunction:: void cvAdaptiveThreshold( const CvArr* src, CvArr* dst, double max_value, int adaptive_method=CV_ADAPTIVE_THRESH_MEAN_C, int threshold_type=CV_THRESH_BINARY, int block_size=3, double param1=5 ) + +.. ocv:pyoldfunction:: cv.AdaptiveThreshold(src, dst, maxValue, adaptive_method=CV_ADAPTIVE_THRESH_MEAN_C, thresholdType=CV_THRESH_BINARY, blockSize=3, param1=5)-> None + + :param src: Source 8-bit single-channel image. + + :param dst: Destination image of the same size and the same type as ``src`` . + + :param maxValue: Non-zero value assigned to the pixels for which the condition is satisfied. See the details below. + + :param adaptiveMethod: Adaptive thresholding algorithm to use, ``ADAPTIVE_THRESH_MEAN_C`` or ``ADAPTIVE_THRESH_GAUSSIAN_C`` . See the details below. + + :param thresholdType: Thresholding type that must be either ``THRESH_BINARY`` or ``THRESH_BINARY_INV`` . + + :param blockSize: Size of a pixel neighborhood that is used to calculate a threshold value for the pixel: 3, 5, 7, and so on. + + :param C: Constant subtracted from the mean or weighted mean (see the details below). Normally, it is positive but may be zero or negative as well. + +The function transforms a grayscale image to a binary image according to the formulae: + + * **THRESH_BINARY** + + .. math:: + + dst(x,y) = \fork{\texttt{maxValue}}{if $src(x,y) > T(x,y)$}{0}{otherwise} + + * **THRESH_BINARY_INV** + + .. math:: + + dst(x,y) = \fork{0}{if $src(x,y) > T(x,y)$}{\texttt{maxValue}}{otherwise} + +where +:math:`T(x,y)` is a threshold calculated individually for each pixel. + +* + For the method ``ADAPTIVE_THRESH_MEAN_C`` , the threshold value + :math:`T(x,y)` is a mean of the + :math:`\texttt{blockSize} \times \texttt{blockSize}` neighborhood of + :math:`(x, y)` minus ``C`` . + +* + For the method ``ADAPTIVE_THRESH_GAUSSIAN_C`` , the threshold value + :math:`T(x, y)` is a weighted sum (cross-correlation with a Gaussian window) of the + :math:`\texttt{blockSize} \times \texttt{blockSize}` neighborhood of + :math:`(x, y)` minus ``C`` . The default sigma (standard deviation) is used for the specified ``blockSize`` . See + :ocv:func:`getGaussianKernel` . + +The function can process the image in-place. + +.. seealso:: + + :ocv:func:`threshold`, + :ocv:func:`blur`, + :ocv:func:`GaussianBlur` + + + +cvtColor +-------- +Converts an image from one color space to another. + +.. ocv:function:: void cvtColor( InputArray src, OutputArray dst, int code, int dstCn=0 ) + +.. ocv:pyfunction:: cv2.cvtColor(src, code[, dst[, dstCn]]) -> dst + +.. ocv:cfunction:: void cvCvtColor( const CvArr* src, CvArr* dst, int code ) +.. ocv:pyoldfunction:: cv.CvtColor(src, dst, code)-> None + + :param src: input image: 8-bit unsigned, 16-bit unsigned ( ``CV_16UC...`` ), or single-precision floating-point. + + :param dst: output image of the same size and depth as ``src``. + + :param code: color space conversion code (see the description below). + + :param dstCn: number of channels in the destination image; if the parameter is 0, the number of the channels is derived automatically from ``src`` and ``code`` . + +The function converts an input image from one color +space to another. In case of a transformation to-from RGB color space, the order of the channels should be specified explicitly (RGB or BGR). +Note that the default color format in OpenCV is often referred to as RGB but it is actually BGR (the bytes are reversed). So the first byte in a standard (24-bit) color image will be an 8-bit Blue component, the second byte will be Green, and the third byte will be Red. The fourth, fifth, and sixth bytes would then be the second pixel (Blue, then Green, then Red), and so on. + +The conventional ranges for R, G, and B channel values are: + +* + 0 to 255 for ``CV_8U`` images + +* + 0 to 65535 for ``CV_16U`` images + +* + 0 to 1 for ``CV_32F`` images + +In case of linear transformations, the range does not matter. +But in case of a non-linear transformation, an input RGB image should be normalized to the proper value range to get the correct results, for example, for RGB +:math:`\rightarrow` L*u*v* transformation. For example, if you have a 32-bit floating-point image directly converted from an 8-bit image without any scaling, then it will have the 0..255 value range instead of 0..1 assumed by the function. So, before calling ``cvtColor`` , you need first to scale the image down: :: + + img *= 1./255; + cvtColor(img, img, CV_BGR2Luv); + +If you use ``cvtColor`` with 8-bit images, the conversion will have some information lost. For many applications, this will not be noticeable but it is recommended to use 32-bit images in applications that need the full range of colors or that convert an image before an operation and then convert back. + +The function can do the following transformations: + +* + Transformations within RGB space like adding/removing the alpha channel, reversing the channel order, conversion to/from 16-bit RGB color (R5:G6:B5 or R5:G5:B5), as well as conversion to/from grayscale using: + + .. math:: + + \text{RGB[A] to Gray:} \quad Y \leftarrow 0.299 \cdot R + 0.587 \cdot G + 0.114 \cdot B + + and + + .. math:: + + \text{Gray to RGB[A]:} \quad R \leftarrow Y, G \leftarrow Y, B \leftarrow Y, A \leftarrow 0 + + The conversion from a RGB image to gray is done with: + + :: + + cvtColor(src, bwsrc, CV_RGB2GRAY); + + .. + + More advanced channel reordering can also be done with + :ocv:func:`mixChannels` . + +* + RGB + :math:`\leftrightarrow` CIE XYZ.Rec 709 with D65 white point ( ``CV_BGR2XYZ, CV_RGB2XYZ, CV_XYZ2BGR, CV_XYZ2RGB`` ): + + .. math:: + + \begin{bmatrix} X \\ Y \\ Z + \end{bmatrix} \leftarrow \begin{bmatrix} 0.412453 & 0.357580 & 0.180423 \\ 0.212671 & 0.715160 & 0.072169 \\ 0.019334 & 0.119193 & 0.950227 + \end{bmatrix} \cdot \begin{bmatrix} R \\ G \\ B + \end{bmatrix} + + .. math:: + + \begin{bmatrix} R \\ G \\ B + \end{bmatrix} \leftarrow \begin{bmatrix} 3.240479 & -1.53715 & -0.498535 \\ -0.969256 & 1.875991 & 0.041556 \\ 0.055648 & -0.204043 & 1.057311 + \end{bmatrix} \cdot \begin{bmatrix} X \\ Y \\ Z + \end{bmatrix} + + :math:`X`, :math:`Y` and + :math:`Z` cover the whole value range (in case of floating-point images, + :math:`Z` may exceed 1). + +* + RGB + :math:`\leftrightarrow` YCrCb JPEG (or YCC) ( ``CV_BGR2YCrCb, CV_RGB2YCrCb, CV_YCrCb2BGR, CV_YCrCb2RGB`` ) + + .. math:: + + Y \leftarrow 0.299 \cdot R + 0.587 \cdot G + 0.114 \cdot B + + .. math:: + + Cr \leftarrow (R-Y) \cdot 0.713 + delta + + .. math:: + + Cb \leftarrow (B-Y) \cdot 0.564 + delta + + .. math:: + + R \leftarrow Y + 1.403 \cdot (Cr - delta) + + .. math:: + + G \leftarrow Y - 0.344 \cdot (Cr - delta) - 0.714 \cdot (Cb - delta) + + .. math:: + + B \leftarrow Y + 1.773 \cdot (Cb - delta) + + where + + .. math:: + + delta = \left \{ \begin{array}{l l} 128 & \mbox{for 8-bit images} \\ 32768 & \mbox{for 16-bit images} \\ 0.5 & \mbox{for floating-point images} \end{array} \right . + + Y, Cr, and Cb cover the whole value range. + +* + RGB :math:`\leftrightarrow` HSV ( ``CV_BGR2HSV, CV_RGB2HSV, CV_HSV2BGR, CV_HSV2RGB`` ) + In case of 8-bit and 16-bit images, + R, G, and B are converted to the floating-point format and scaled to fit the 0 to 1 range. + + .. math:: + + V \leftarrow max(R,G,B) + + .. math:: + + S \leftarrow \fork{\frac{V-min(R,G,B)}{V}}{if $V \neq 0$}{0}{otherwise} + + .. math:: + + H \leftarrow \forkthree{{60(G - B)}/{(V-min(R,G,B))}}{if $V=R$}{{120+60(B - R)}/{(V-min(R,G,B))}}{if $V=G$}{{240+60(R - G)}/{(V-min(R,G,B))}}{if $V=B$} + + If + :math:`H<0` then + :math:`H \leftarrow H+360` . On output + :math:`0 \leq V \leq 1`, :math:`0 \leq S \leq 1`, :math:`0 \leq H \leq 360` . + + The values are then converted to the destination data type: + + * 8-bit images + + .. math:: + + V \leftarrow 255 V, S \leftarrow 255 S, H \leftarrow H/2 \text{(to fit to 0 to 255)} + + * 16-bit images (currently not supported) + + .. math:: + + V <- 65535 V, S <- 65535 S, H <- H + + * 32-bit images + H, S, and V are left as is + +* + RGB :math:`\leftrightarrow` HLS ( ``CV_BGR2HLS, CV_RGB2HLS, CV_HLS2BGR, CV_HLS2RGB`` ). + In case of 8-bit and 16-bit images, + R, G, and B are converted to the floating-point format and scaled to fit the 0 to 1 range. + + .. math:: + + V_{max} \leftarrow {max}(R,G,B) + + .. math:: + + V_{min} \leftarrow {min}(R,G,B) + + .. math:: + + L \leftarrow \frac{V_{max} + V_{min}}{2} + + .. math:: + + S \leftarrow \fork { \frac{V_{max} - V_{min}}{V_{max} + V_{min}} }{if $L < 0.5$ } + { \frac{V_{max} - V_{min}}{2 - (V_{max} + V_{min})} }{if $L \ge 0.5$ } + + .. math:: + + H \leftarrow \forkthree {{60(G - B)}/{S}}{if $V_{max}=R$ } + {{120+60(B - R)}/{S}}{if $V_{max}=G$ } + {{240+60(R - G)}/{S}}{if $V_{max}=B$ } + + If + :math:`H<0` then + :math:`H \leftarrow H+360` . On output + :math:`0 \leq L \leq 1`, :math:`0 \leq S \leq 1`, :math:`0 \leq H \leq 360` . + + The values are then converted to the destination data type: + + * 8-bit images + + .. math:: + + V \leftarrow 255 \cdot V, S \leftarrow 255 \cdot S, H \leftarrow H/2 \; \text{(to fit to 0 to 255)} + + * 16-bit images (currently not supported) + + .. math:: + + V <- 65535 \cdot V, S <- 65535 \cdot S, H <- H + + * 32-bit images + H, S, V are left as is + +* + RGB :math:`\leftrightarrow` CIE L*a*b* ( ``CV_BGR2Lab, CV_RGB2Lab, CV_Lab2BGR, CV_Lab2RGB`` ). + In case of 8-bit and 16-bit images, + R, G, and B are converted to the floating-point format and scaled to fit the 0 to 1 range. + + .. math:: + + \vecthree{X}{Y}{Z} \leftarrow \vecthreethree{0.412453}{0.357580}{0.180423}{0.212671}{0.715160}{0.072169}{0.019334}{0.119193}{0.950227} \cdot \vecthree{R}{G}{B} + + .. math:: + + X \leftarrow X/X_n, \text{where} X_n = 0.950456 + + .. math:: + + Z \leftarrow Z/Z_n, \text{where} Z_n = 1.088754 + + .. math:: + + L \leftarrow \fork{116*Y^{1/3}-16}{for $Y>0.008856$}{903.3*Y}{for $Y \le 0.008856$} + + .. math:: + + a \leftarrow 500 (f(X)-f(Y)) + delta + + .. math:: + + b \leftarrow 200 (f(Y)-f(Z)) + delta + + where + + .. math:: + + f(t)= \fork{t^{1/3}}{for $t>0.008856$}{7.787 t+16/116}{for $t\leq 0.008856$} + + and + + .. math:: + + delta = \fork{128}{for 8-bit images}{0}{for floating-point images} + + This outputs + :math:`0 \leq L \leq 100`, :math:`-127 \leq a \leq 127`, :math:`-127 \leq b \leq 127` . The values are then converted to the destination data type: + + * 8-bit images + + .. math:: + + L \leftarrow L*255/100, \; a \leftarrow a + 128, \; b \leftarrow b + 128 + + * 16-bit images + (currently not supported) + + * 32-bit images + L, a, and b are left as is + +* + RGB :math:`\leftrightarrow` CIE L*u*v* ( ``CV_BGR2Luv, CV_RGB2Luv, CV_Luv2BGR, CV_Luv2RGB`` ). + In case of 8-bit and 16-bit images, + R, G, and B are converted to the floating-point format and scaled to fit 0 to 1 range. + + .. math:: + + \vecthree{X}{Y}{Z} \leftarrow \vecthreethree{0.412453}{0.357580}{0.180423}{0.212671}{0.715160}{0.072169}{0.019334}{0.119193}{0.950227} \cdot \vecthree{R}{G}{B} + + .. math:: + + L \leftarrow \fork{116 Y^{1/3}}{for $Y>0.008856$}{903.3 Y}{for $Y\leq 0.008856$} + + .. math:: + + u' \leftarrow 4*X/(X + 15*Y + 3 Z) + + .. math:: + + v' \leftarrow 9*Y/(X + 15*Y + 3 Z) + + .. math:: + + u \leftarrow 13*L*(u' - u_n) \quad \text{where} \quad u_n=0.19793943 + + .. math:: + + v \leftarrow 13*L*(v' - v_n) \quad \text{where} \quad v_n=0.46831096 + + This outputs + :math:`0 \leq L \leq 100`, :math:`-134 \leq u \leq 220`, :math:`-140 \leq v \leq 122` . + + The values are then converted to the destination data type: + + * 8-bit images + + .. math:: + + L \leftarrow 255/100 L, \; u \leftarrow 255/354 (u + 134), \; v \leftarrow 255/256 (v + 140) + + * 16-bit images + (currently not supported) + + * 32-bit images + L, u, and v are left as is + + The above formulae for converting RGB to/from various color spaces have been taken from multiple sources on the web, primarily from the Charles Poynton site + http://www.poynton.com/ColorFAQ.html + +* + Bayer :math:`\rightarrow` RGB ( ``CV_BayerBG2BGR, CV_BayerGB2BGR, CV_BayerRG2BGR, CV_BayerGR2BGR, CV_BayerBG2RGB, CV_BayerGB2RGB, CV_BayerRG2RGB, CV_BayerGR2RGB`` ). The Bayer pattern is widely used in CCD and CMOS cameras. It enables you to get color pictures from a single plane where R,G, and B pixels (sensors of a particular component) are interleaved as follows: + + .. image:: pics/bayer.png + + The output RGB components of a pixel are interpolated from 1, 2, or + 4 neighbors of the pixel having the same color. There are several + modifications of the above pattern that can be achieved by shifting + the pattern one pixel left and/or one pixel up. The two letters + :math:`C_1` and + :math:`C_2` in the conversion constants ``CV_Bayer`` :math:`C_1 C_2` ``2BGR`` and ``CV_Bayer`` :math:`C_1 C_2` ``2RGB`` indicate the particular pattern + type. These are components from the second row, second and third + columns, respectively. For example, the above pattern has a very + popular "BG" type. + + +distanceTransform +----------------- +Calculates the distance to the closest zero pixel for each pixel of the source image. + +.. ocv:function:: void distanceTransform( InputArray src, OutputArray dst, int distanceType, int maskSize ) + +.. ocv:function:: void distanceTransform( InputArray src, OutputArray dst, OutputArray labels, int distanceType, int maskSize, int labelType=DIST_LABEL_CCOMP ) + +.. ocv:pyfunction:: cv2.distanceTransform(src, distanceType, maskSize[, dst]) -> dst + +.. ocv:cfunction:: void cvDistTransform( const CvArr* src, CvArr* dst, int distance_type=CV_DIST_L2, int mask_size=3, const float* mask=NULL, CvArr* labels=NULL, int labelType=CV_DIST_LABEL_CCOMP ) + +.. ocv:pyoldfunction:: cv.DistTransform(src, dst, distance_type=CV_DIST_L2, mask_size=3, mask=None, labels=None) -> None + + :param src: 8-bit, single-channel (binary) source image. + + :param dst: Output image with calculated distances. It is a 32-bit floating-point, single-channel image of the same size as ``src`` . + + :param distanceType: Type of distance. It can be ``CV_DIST_L1, CV_DIST_L2`` , or ``CV_DIST_C`` . + + :param maskSize: Size of the distance transform mask. It can be 3, 5, or ``CV_DIST_MASK_PRECISE`` (the latter option is only supported by the first function). In case of the ``CV_DIST_L1`` or ``CV_DIST_C`` distance type, the parameter is forced to 3 because a :math:`3\times 3` mask gives the same result as :math:`5\times 5` or any larger aperture. + + :param labels: Optional output 2D array of labels (the discrete Voronoi diagram). It has the type ``CV_32SC1`` and the same size as ``src`` . See the details below. + + :param labelType: Type of the label array to build. If ``labelType==DIST_LABEL_CCOMP`` then each connected component of zeros in ``src`` (as well as all the non-zero pixels closest to the connected component) will be assigned the same label. If ``labelType==DIST_LABEL_PIXEL`` then each zero pixel (and all the non-zero pixels closest to it) gets its own label. + +The functions ``distanceTransform`` calculate the approximate or precise +distance from every binary image pixel to the nearest zero pixel. +For zero image pixels, the distance will obviously be zero. + +When ``maskSize == CV_DIST_MASK_PRECISE`` and ``distanceType == CV_DIST_L2`` , the function runs the algorithm described in [Felzenszwalb04]_. This algorithm is parallelized with the TBB library. + +In other cases, the algorithm +[Borgefors86]_ +is used. This means that +for a pixel the function finds the shortest path to the nearest zero pixel +consisting of basic shifts: horizontal, +vertical, diagonal, or knight's move (the latest is available for a +:math:`5\times 5` mask). The overall distance is calculated as a sum of these +basic distances. Since the distance function should be symmetric, +all of the horizontal and vertical shifts must have the same cost (denoted as ``a`` ), all the diagonal shifts must have the +same cost (denoted as ``b`` ), and all knight's moves must have +the same cost (denoted as ``c`` ). For the ``CV_DIST_C`` and ``CV_DIST_L1`` types, the distance is calculated precisely, +whereas for ``CV_DIST_L2`` (Euclidean distance) the distance +can be calculated only with a relative error (a +:math:`5\times 5` mask +gives more accurate results). For ``a``,``b`` , and ``c`` , OpenCV uses the values suggested in the original paper: + +.. table:: + + ============== =================== ====================== + ``CV_DIST_C`` :math:`(3\times 3)` a = 1, b = 1 \ + ============== =================== ====================== + ``CV_DIST_L1`` :math:`(3\times 3)` a = 1, b = 2 \ + ``CV_DIST_L2`` :math:`(3\times 3)` a=0.955, b=1.3693 \ + ``CV_DIST_L2`` :math:`(5\times 5)` a=1, b=1.4, c=2.1969 \ + ============== =================== ====================== + +Typically, for a fast, coarse distance estimation ``CV_DIST_L2``, a +:math:`3\times 3` mask is used. For a more accurate distance estimation ``CV_DIST_L2`` , a +:math:`5\times 5` mask or the precise algorithm is used. +Note that both the precise and the approximate algorithms are linear on the number of pixels. + +The second variant of the function does not only compute the minimum distance for each pixel +:math:`(x, y)` but also identifies the nearest connected +component consisting of zero pixels (``labelType==DIST_LABEL_CCOMP``) or the nearest zero pixel (``labelType==DIST_LABEL_PIXEL``). Index of the component/pixel is stored in +:math:`\texttt{labels}(x, y)` . +When ``labelType==DIST_LABEL_CCOMP``, the function automatically finds connected components of zero pixels in the input image and marks them with distinct labels. When ``labelType==DIST_LABEL_CCOMP``, the function scans through the input image and marks all the zero pixels with distinct labels. + +In this mode, the complexity is still linear. +That is, the function provides a very fast way to compute the Voronoi diagram for a binary image. +Currently, the second variant can use only the approximate distance transform algorithm, i.e. ``maskSize=CV_DIST_MASK_PRECISE`` is not supported yet. + +floodFill +--------- +Fills a connected component with the given color. + +.. ocv:function:: int floodFill( InputOutputArray image, Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 ) + +.. ocv:function:: int floodFill( InputOutputArray image, InputOutputArray mask, Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 ) + +.. ocv:pyfunction:: cv2.floodFill(image, mask, seedPoint, newVal[, loDiff[, upDiff[, flags]]]) -> retval, rect + +.. ocv:cfunction:: void cvFloodFill( CvArr* image, CvPoint seed_point, CvScalar new_val, CvScalar lo_diff=cvScalarAll(0), CvScalar up_diff=cvScalarAll(0), CvConnectedComp* comp=NULL, int flags=4, CvArr* mask=NULL ) +.. ocv:pyoldfunction:: cv.FloodFill(image, seed_point, new_val, lo_diff=(0, 0, 0, 0), up_diff=(0, 0, 0, 0), flags=4, mask=None)-> comp + + :param image: Input/output 1- or 3-channel, 8-bit, or floating-point image. It is modified by the function unless the ``FLOODFILL_MASK_ONLY`` flag is set in the second variant of the function. See the details below. + + :param mask: (For the second function only) Operation mask that should be a single-channel 8-bit image, 2 pixels wider and 2 pixels taller. The function uses and updates the mask, so you take responsibility of initializing the ``mask`` content. Flood-filling cannot go across non-zero pixels in the mask. For example, an edge detector output can be used as a mask to stop filling at edges. It is possible to use the same mask in multiple calls to the function to make sure the filled area does not overlap. + + .. note:: Since the mask is larger than the filled image, a pixel :math:`(x, y)` in ``image`` corresponds to the pixel :math:`(x+1, y+1)` in the ``mask`` . + + :param seedPoint: Starting point. + + :param newVal: New value of the repainted domain pixels. + + :param loDiff: Maximal lower brightness/color difference between the currently observed pixel and one of its neighbors belonging to the component, or a seed pixel being added to the component. + + :param upDiff: Maximal upper brightness/color difference between the currently observed pixel and one of its neighbors belonging to the component, or a seed pixel being added to the component. + + :param rect: Optional output parameter set by the function to the minimum bounding rectangle of the repainted domain. + + :param flags: Operation flags. Lower bits contain a connectivity value, 4 (default) or 8, used within the function. Connectivity determines which neighbors of a pixel are considered. Upper bits can be 0 or a combination of the following flags: + + * **FLOODFILL_FIXED_RANGE** If set, the difference between the current pixel and seed pixel is considered. Otherwise, the difference between neighbor pixels is considered (that is, the range is floating). + + * **FLOODFILL_MASK_ONLY** If set, the function does not change the image ( ``newVal`` is ignored), but fills the mask. The flag can be used for the second variant only. + +The functions ``floodFill`` fill a connected component starting from the seed point with the specified color. The connectivity is determined by the color/brightness closeness of the neighbor pixels. The pixel at +:math:`(x,y)` is considered to belong to the repainted domain if: + +* + .. math:: + + \texttt{src} (x',y')- \texttt{loDiff} \leq \texttt{src} (x,y) \leq \texttt{src} (x',y')+ \texttt{upDiff} + + in case of a grayscale image and floating range + +* + + .. math:: + + \texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)- \texttt{loDiff} \leq \texttt{src} (x,y) \leq \texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)+ \texttt{upDiff} + + in case of a grayscale image and fixed range + +* + + .. math:: + + \texttt{src} (x',y')_r- \texttt{loDiff} _r \leq \texttt{src} (x,y)_r \leq \texttt{src} (x',y')_r+ \texttt{upDiff} _r, + + .. math:: + + \texttt{src} (x',y')_g- \texttt{loDiff} _g \leq \texttt{src} (x,y)_g \leq \texttt{src} (x',y')_g+ \texttt{upDiff} _g + + and + + .. math:: + + \texttt{src} (x',y')_b- \texttt{loDiff} _b \leq \texttt{src} (x,y)_b \leq \texttt{src} (x',y')_b+ \texttt{upDiff} _b + + in case of a color image and floating range + + +* + + .. math:: + + \texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)_r- \texttt{loDiff} _r \leq \texttt{src} (x,y)_r \leq \texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)_r+ \texttt{upDiff} _r, + + .. math:: + + \texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)_g- \texttt{loDiff} _g \leq \texttt{src} (x,y)_g \leq \texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)_g+ \texttt{upDiff} _g + + and + + .. math:: + + \texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)_b- \texttt{loDiff} _b \leq \texttt{src} (x,y)_b \leq \texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)_b+ \texttt{upDiff} _b + + in case of a color image and fixed range + +where +:math:`src(x',y')` is the value of one of pixel neighbors that is already known to belong to the component. That is, to be added to the connected component, a color/brightness of the pixel should be close enough to: + +* + Color/brightness of one of its neighbors that already belong to the connected component in case of a floating range. + +* + Color/brightness of the seed point in case of a fixed range. + +Use these functions to either mark a connected component with the specified color in-place, or build a mask and then extract the contour, or copy the region to another image, and so on. Various modes of the function are demonstrated in the ``floodfill.cpp`` sample. + +.. seealso:: :ocv:func:`findContours` + + + +integral +-------- +Calculates the integral of an image. + +.. ocv:function:: void integral( InputArray src, OutputArray sum, int sdepth=-1 ) + +.. ocv:function:: void integral( InputArray src, OutputArray sum, OutputArray sqsum, int sdepth=-1 ) + +.. ocv:function:: void integral( InputArray src, OutputArray sum, OutputArray sqsum, OutputArray tilted, int sdepth=-1 ) + +.. ocv:pyfunction:: cv2.integral(src[, sum[, sdepth]]) -> sum + +.. ocv:pyfunction:: cv2.integral2(src[, sum[, sqsum[, sdepth]]]) -> sum, sqsum + +.. ocv:pyfunction:: cv2.integral3(src[, sum[, sqsum[, tilted[, sdepth]]]]) -> sum, sqsum, tilted + +.. ocv:cfunction:: void cvIntegral( const CvArr* image, CvArr* sum, CvArr* sqsum=NULL, CvArr* tilted_sum=NULL ) + +.. ocv:pyoldfunction:: cv.Integral(image, sum, sqsum=None, tiltedSum=None)-> None + + :param image: input image as :math:`W \times H`, 8-bit or floating-point (32f or 64f). + + :param sum: integral image as :math:`(W+1)\times (H+1)` , 32-bit integer or floating-point (32f or 64f). + + :param sqsum: integral image for squared pixel values; it is :math:`(W+1)\times (H+1)`, double-precision floating-point (64f) array. + + :param tilted: integral for the image rotated by 45 degrees; it is :math:`(W+1)\times (H+1)` array with the same data type as ``sum``. + + :param sdepth: desired depth of the integral and the tilted integral images, ``CV_32S``, ``CV_32F``, or ``CV_64F``. + +The functions calculate one or more integral images for the source image as follows: + +.. math:: + + \texttt{sum} (X,Y) = \sum _{x retval, dst + +.. ocv:cfunction:: double cvThreshold( const CvArr* src, CvArr* dst, double threshold, double max_value, int threshold_type ) + +.. ocv:pyoldfunction:: cv.Threshold(src, dst, threshold, maxValue, thresholdType)-> None + + :param src: input array (single-channel, 8-bit or 32-bit floating point). + + :param dst: output array of the same size and type as ``src``. + + :param thresh: treshold value. + + :param maxval: maximum value to use with the ``THRESH_BINARY`` and ``THRESH_BINARY_INV`` thresholding types. + + :param type: thresholding type (see the details below). + +The function applies fixed-level thresholding +to a single-channel array. The function is typically used to get a +bi-level (binary) image out of a grayscale image ( +:ocv:func:`compare` could +be also used for this purpose) or for removing a noise, that is, filtering +out pixels with too small or too large values. There are several +types of thresholding supported by the function. They are determined by ``type`` : + + * **THRESH_BINARY** + + .. math:: + + \texttt{dst} (x,y) = \fork{\texttt{maxval}}{if $\texttt{src}(x,y) > \texttt{thresh}$}{0}{otherwise} + + * **THRESH_BINARY_INV** + + .. math:: + + \texttt{dst} (x,y) = \fork{0}{if $\texttt{src}(x,y) > \texttt{thresh}$}{\texttt{maxval}}{otherwise} + + * **THRESH_TRUNC** + + .. math:: + + \texttt{dst} (x,y) = \fork{\texttt{threshold}}{if $\texttt{src}(x,y) > \texttt{thresh}$}{\texttt{src}(x,y)}{otherwise} + + * **THRESH_TOZERO** + + .. math:: + + \texttt{dst} (x,y) = \fork{\texttt{src}(x,y)}{if $\texttt{src}(x,y) > \texttt{thresh}$}{0}{otherwise} + + * **THRESH_TOZERO_INV** + + .. math:: + + \texttt{dst} (x,y) = \fork{0}{if $\texttt{src}(x,y) > \texttt{thresh}$}{\texttt{src}(x,y)}{otherwise} + +Also, the special value ``THRESH_OTSU`` may be combined with +one of the above values. In this case, the function determines the optimal threshold +value using the Otsu's algorithm and uses it instead of the specified ``thresh`` . +The function returns the computed threshold value. +Currently, the Otsu's method is implemented only for 8-bit images. + + +.. image:: pics/threshold.png + +.. seealso:: + + :ocv:func:`adaptiveThreshold`, + :ocv:func:`findContours`, + :ocv:func:`compare`, + :ocv:func:`min`, + :ocv:func:`max` + + +watershed +--------- +Performs a marker-based image segmentation using the watershed algorithm. + +.. ocv:function:: void watershed( InputArray image, InputOutputArray markers ) + +.. ocv:cfunction:: void cvWatershed( const CvArr* image, CvArr* markers ) + +.. ocv:pyfunction:: cv2.watershed(image, markers) -> None + + :param image: Input 8-bit 3-channel image. + + :param markers: Input/output 32-bit single-channel image (map) of markers. It should have the same size as ``image`` . + +The function implements one of the variants of watershed, non-parametric marker-based segmentation algorithm, described in [Meyer92]_. + +Before passing the image to the function, you have to roughly outline the desired regions in the image ``markers`` with positive (``>0``) indices. So, every region is represented as one or more connected components with the pixel values 1, 2, 3, and so on. Such markers can be retrieved from a binary mask using :ocv:func:`findContours` and :ocv:func:`drawContours` (see the ``watershed.cpp`` demo). The markers are "seeds" of the future image regions. All the other pixels in ``markers`` , whose relation to the outlined regions is not known and should be defined by the algorithm, should be set to 0's. In the function output, each pixel in markers is set to a value of the "seed" components or to -1 at boundaries between the regions. + +Visual demonstration and usage example of the function can be found in the OpenCV samples directory (see the ``watershed.cpp`` demo). + +.. note:: Any two neighbor connected components are not necessarily separated by a watershed boundary (-1's pixels); for example, they can touch each other in the initial marker image passed to the function. + +.. seealso:: :ocv:func:`findContours` + +grabCut +------- +Runs the GrabCut algorithm. + +.. ocv:function:: void grabCut( InputArray img, InputOutputArray mask, Rect rect, InputOutputArray bgdModel, InputOutputArray fgdModel, int iterCount, int mode=GC_EVAL ) + +.. ocv:pyfunction:: cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount[, mode]) -> None + + :param img: Input 8-bit 3-channel image. + + :param mask: Input/output 8-bit single-channel mask. The mask is initialized by the function when ``mode`` is set to ``GC_INIT_WITH_RECT``. Its elements may have one of following values: + + * **GC_BGD** defines an obvious background pixels. + + * **GC_FGD** defines an obvious foreground (object) pixel. + + * **GC_PR_BGD** defines a possible background pixel. + + * **GC_PR_BGD** defines a possible foreground pixel. + + :param rect: ROI containing a segmented object. The pixels outside of the ROI are marked as "obvious background". The parameter is only used when ``mode==GC_INIT_WITH_RECT`` . + + :param bgdModel: Temporary array for the background model. Do not modify it while you are processing the same image. + + :param fgdModel: Temporary arrays for the foreground model. Do not modify it while you are processing the same image. + + :param iterCount: Number of iterations the algorithm should make before returning the result. Note that the result can be refined with further calls with ``mode==GC_INIT_WITH_MASK`` or ``mode==GC_EVAL`` . + + :param mode: Operation mode that could be one of the following: + + * **GC_INIT_WITH_RECT** The function initializes the state and the mask using the provided rectangle. After that it runs ``iterCount`` iterations of the algorithm. + + * **GC_INIT_WITH_MASK** The function initializes the state using the provided mask. Note that ``GC_INIT_WITH_RECT`` and ``GC_INIT_WITH_MASK`` can be combined. Then, all the pixels outside of the ROI are automatically initialized with ``GC_BGD`` . + + * **GC_EVAL** The value means that the algorithm should just resume. + +The function implements the `GrabCut image segmentation algorithm `_. +See the sample ``grabcut.cpp`` to learn how to use the function. + +.. [Borgefors86] Borgefors, Gunilla, *Distance transformations in digital images*. Comput. Vision Graph. Image Process. 34 3, pp 344–371 (1986) + +.. [Felzenszwalb04] Felzenszwalb, Pedro F. and Huttenlocher, Daniel P. *Distance Transforms of Sampled Functions*, TR2004-1963, TR2004-1963 (2004) + +.. [Meyer92] Meyer, F. *Color Image Segmentation*, ICIP92, 1992 + +.. [Telea04] Alexandru Telea, *An Image Inpainting Technique Based on the Fast Marching Method*. Journal of Graphics, GPU, and Game Tools 9 1, pp 23-34 (2004) diff --git a/imgproc/doc/motion_analysis_and_object_tracking.rst b/imgproc/doc/motion_analysis_and_object_tracking.rst new file mode 100644 index 0000000..8083481 --- /dev/null +++ b/imgproc/doc/motion_analysis_and_object_tracking.rst @@ -0,0 +1,220 @@ +Motion Analysis and Object Tracking +=================================== + +.. highlight:: cpp + +accumulate +-------------- +Adds an image to the accumulator. + +.. ocv:function:: void accumulate( InputArray src, InputOutputArray dst, InputArray mask=noArray() ) + +.. ocv:pyfunction:: cv2.accumulate(src, dst[, mask]) -> None + +.. ocv:cfunction:: void cvAcc( const CvArr* image, CvArr* sum, const CvArr* mask=NULL ) + +.. ocv:pyoldfunction:: cv.Acc(image, sum, mask=None) -> None + + :param src: Input image as 1- or 3-channel, 8-bit or 32-bit floating point. + + :param dst: Accumulator image with the same number of channels as input image, 32-bit or 64-bit floating-point. + + :param mask: Optional operation mask. + +The function adds ``src`` or some of its elements to ``dst`` : + +.. math:: + + \texttt{dst} (x,y) \leftarrow \texttt{dst} (x,y) + \texttt{src} (x,y) \quad \text{if} \quad \texttt{mask} (x,y) \ne 0 + +The function supports multi-channel images. Each channel is processed independently. + +The functions ``accumulate*`` can be used, for example, to collect statistics of a scene background viewed by a still camera and for the further foreground-background segmentation. + +.. seealso:: + + :ocv:func:`accumulateSquare`, + :ocv:func:`accumulateProduct`, + :ocv:func:`accumulateWeighted` + + + +accumulateSquare +-------------------- +Adds the square of a source image to the accumulator. + +.. ocv:function:: void accumulateSquare( InputArray src, InputOutputArray dst, InputArray mask=noArray() ) + +.. ocv:pyfunction:: cv2.accumulateSquare(src, dst[, mask]) -> None + +.. ocv:cfunction:: void cvSquareAcc( const CvArr* image, CvArr* sqsum, const CvArr* mask=NULL ) + +.. ocv:pyoldfunction:: cv.SquareAcc(image, sqsum, mask=None) -> None + + :param src: Input image as 1- or 3-channel, 8-bit or 32-bit floating point. + + :param dst: Accumulator image with the same number of channels as input image, 32-bit or 64-bit floating-point. + + :param mask: Optional operation mask. + +The function adds the input image ``src`` or its selected region, raised to a power of 2, to the accumulator ``dst`` : + +.. math:: + + \texttt{dst} (x,y) \leftarrow \texttt{dst} (x,y) + \texttt{src} (x,y)^2 \quad \text{if} \quad \texttt{mask} (x,y) \ne 0 + +The function supports multi-channel images. Each channel is processed independently. + +.. seealso:: + + :ocv:func:`accumulateSquare`, + :ocv:func:`accumulateProduct`, + :ocv:func:`accumulateWeighted` + + + +accumulateProduct +--------------------- +Adds the per-element product of two input images to the accumulator. + +.. ocv:function:: void accumulateProduct( InputArray src1, InputArray src2, InputOutputArray dst, InputArray mask=noArray() ) + +.. ocv:pyfunction:: cv2.accumulateProduct(src1, src2, dst[, mask]) -> None + +.. ocv:cfunction:: void cvMultiplyAcc( const CvArr* image1, const CvArr* image2, CvArr* acc, const CvArr* mask=NULL ) + +.. ocv:pyoldfunction:: cv.MultiplyAcc(image1, image2, acc, mask=None)-> None + + :param src1: First input image, 1- or 3-channel, 8-bit or 32-bit floating point. + + :param src2: Second input image of the same type and the same size as ``src1`` . + + :param dst: Accumulator with the same number of channels as input images, 32-bit or 64-bit floating-point. + + :param mask: Optional operation mask. + +The function adds the product of two images or their selected regions to the accumulator ``dst`` : + +.. math:: + + \texttt{dst} (x,y) \leftarrow \texttt{dst} (x,y) + \texttt{src1} (x,y) \cdot \texttt{src2} (x,y) \quad \text{if} \quad \texttt{mask} (x,y) \ne 0 + +The function supports multi-channel images. Each channel is processed independently. + +.. seealso:: + + :ocv:func:`accumulate`, + :ocv:func:`accumulateSquare`, + :ocv:func:`accumulateWeighted` + + + +accumulateWeighted +---------------------- +Updates a running average. + +.. ocv:function:: void accumulateWeighted( InputArray src, InputOutputArray dst, double alpha, InputArray mask=noArray() ) + +.. ocv:pyfunction:: cv2.accumulateWeighted(src, dst, alpha[, mask]) -> None + +.. ocv:cfunction:: void cvRunningAvg( const CvArr* image, CvArr* acc, double alpha, const CvArr* mask=NULL ) +.. ocv:pyoldfunction:: cv.RunningAvg(image, acc, alpha, mask=None)-> None + + :param src: Input image as 1- or 3-channel, 8-bit or 32-bit floating point. + + :param dst: Accumulator image with the same number of channels as input image, 32-bit or 64-bit floating-point. + + :param alpha: Weight of the input image. + + :param mask: Optional operation mask. + +The function calculates the weighted sum of the input image ``src`` and the accumulator ``dst`` so that ``dst`` becomes a running average of a frame sequence: + +.. math:: + + \texttt{dst} (x,y) \leftarrow (1- \texttt{alpha} ) \cdot \texttt{dst} (x,y) + \texttt{alpha} \cdot \texttt{src} (x,y) \quad \text{if} \quad \texttt{mask} (x,y) \ne 0 + +That is, ``alpha`` regulates the update speed (how fast the accumulator "forgets" about earlier images). +The function supports multi-channel images. Each channel is processed independently. + +.. seealso:: + + :ocv:func:`accumulate`, + :ocv:func:`accumulateSquare`, + :ocv:func:`accumulateProduct` + + + +phaseCorrelate +-------------- +The function is used to detect translational shifts that occur between two images. The operation takes advantage of the Fourier shift theorem for detecting the translational shift in the frequency domain. It can be used for fast image registration as well as motion estimation. For more information please see http://en.wikipedia.org/wiki/Phase\_correlation . + +Calculates the cross-power spectrum of two supplied source arrays. The arrays are padded if needed with :ocv:func:`getOptimalDFTSize`. + +.. ocv:function:: Point2d phaseCorrelate(InputArray src1, InputArray src2, InputArray window = noArray(), double* response = 0) + + :param src1: Source floating point array (CV_32FC1 or CV_64FC1) + :param src2: Source floating point array (CV_32FC1 or CV_64FC1) + :param window: Floating point array with windowing coefficients to reduce edge effects (optional). + :param response: Signal power within the 5x5 centroid around the peak, between 0 and 1 (optional). + +Return value: detected phase shift (sub-pixel) between the two arrays. + +The function performs the following equations + +* First it applies a Hanning window (see http://en.wikipedia.org/wiki/Hann\_function) to each image to remove possible edge effects. This window is cached until the array size changes to speed up processing time. + +* Next it computes the forward DFTs of each source array: + + .. math:: + + \mathbf{G}_a = \mathcal{F}\{src_1\}, \; \mathbf{G}_b = \mathcal{F}\{src_2\} + + where + :math:`\mathcal{F}` is the forward DFT. + +* It then computes the cross-power spectrum of each frequency domain array: + + .. math:: + + R = \frac{ \mathbf{G}_a \mathbf{G}_b^*}{|\mathbf{G}_a \mathbf{G}_b^*|} + +* Next the cross-correlation is converted back into the time domain via the inverse DFT: + + .. math:: + + r = \mathcal{F}^{-1}\{R\} + +* Finally, it computes the peak location and computes a 5x5 weighted centroid around the peak to achieve sub-pixel accuracy. + + .. math:: + + (\Delta x, \Delta y) = \texttt{weightedCentroid} \{\arg \max_{(x, y)}\{r\}\} + +* If non-zero, the response parameter is computed as the sum of the elements of r within the 5x5 centroid around the peak location. It is normalized to a maximum of 1 (meaning there is a single peak) and will be smaller when there are multiple peaks. + +.. seealso:: + :ocv:func:`dft`, + :ocv:func:`getOptimalDFTSize`, + :ocv:func:`idft`, + :ocv:func:`mulSpectrums` + :ocv:func:`createHanningWindow` + +createHanningWindow +------------------------------- +This function computes a Hanning window coefficients in two dimensions. See http://en.wikipedia.org/wiki/Hann\_function and http://en.wikipedia.org/wiki/Window\_function for more information. + +.. ocv:function:: void createHanningWindow(OutputArray dst, Size winSize, int type) + + :param dst: Destination array to place Hann coefficients in + :param winSize: The window size specifications + :param type: Created array type + +An example is shown below: :: + + // create hanning window of size 100x100 and type CV_32F + Mat hann; + createHanningWindow(hann, Size(100, 100), CV_32F); + +.. seealso:: + :ocv:func:`phaseCorrelate` diff --git a/imgproc/doc/object_detection.rst b/imgproc/doc/object_detection.rst new file mode 100644 index 0000000..c6231a0 --- /dev/null +++ b/imgproc/doc/object_detection.rst @@ -0,0 +1,76 @@ +Object Detection +================ + +.. highlight:: cpp + +matchTemplate +----------------- +Compares a template against overlapped image regions. + +.. ocv:function:: void matchTemplate( InputArray image, InputArray templ, OutputArray result, int method ) + +.. ocv:pyfunction:: cv2.matchTemplate(image, templ, method[, result]) -> result + +.. ocv:cfunction:: void cvMatchTemplate( const CvArr* image, const CvArr* templ, CvArr* result, int method ) +.. ocv:pyoldfunction:: cv.MatchTemplate(image, templ, result, method)-> None + + :param image: Image where the search is running. It must be 8-bit or 32-bit floating-point. + + :param templ: Searched template. It must be not greater than the source image and have the same data type. + + :param result: Map of comparison results. It must be single-channel 32-bit floating-point. If ``image`` is :math:`W \times H` and ``templ`` is :math:`w \times h` , then ``result`` is :math:`(W-w+1) \times (H-h+1)` . + + :param method: Parameter specifying the comparison method (see below). + +The function slides through ``image`` , compares the +overlapped patches of size +:math:`w \times h` against ``templ`` using the specified method and stores the comparison results in ``result`` . Here are the formulae for the available comparison +methods ( +:math:`I` denotes ``image``, :math:`T` ``template``, :math:`R` ``result`` ). The summation is done over template and/or the +image patch: +:math:`x' = 0...w-1, y' = 0...h-1` +* method=CV\_TM\_SQDIFF + + .. math:: + + R(x,y)= \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2 + +* method=CV\_TM\_SQDIFF\_NORMED + + .. math:: + + R(x,y)= \frac{\sum_{x',y'} (T(x',y')-I(x+x',y+y'))^2}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}} + +* method=CV\_TM\_CCORR + + .. math:: + + R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y')) + +* method=CV\_TM\_CCORR\_NORMED + + .. math:: + + R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I(x+x',y+y'))}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}} + +* method=CV\_TM\_CCOEFF + + .. math:: + + R(x,y)= \sum _{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) + + where + + .. math:: + + \begin{array}{l} T'(x',y')=T(x',y') - 1/(w \cdot h) \cdot \sum _{x'',y''} T(x'',y'') \\ I'(x+x',y+y')=I(x+x',y+y') - 1/(w \cdot h) \cdot \sum _{x'',y''} I(x+x'',y+y'') \end{array} + +* method=CV\_TM\_CCOEFF\_NORMED + + .. math:: + + R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) }{ \sqrt{\sum_{x',y'}T'(x',y')^2 \cdot \sum_{x',y'} I'(x+x',y+y')^2} } + +After the function finishes the comparison, the best matches can be found as global minimums (when ``CV_TM_SQDIFF`` was used) or maximums (when ``CV_TM_CCORR`` or ``CV_TM_CCOEFF`` was used) using the +:ocv:func:`minMaxLoc` function. In case of a color image, template summation in the numerator and each sum in the denominator is done over all of the channels and separate mean values are used for each channel. That is, the function can take a color template and a color image. The result will still be a single-channel image, which is easier to analyze. + diff --git a/imgproc/doc/pics/backprojectpatch.png b/imgproc/doc/pics/backprojectpatch.png new file mode 100644 index 0000000..11dfb29 Binary files /dev/null and b/imgproc/doc/pics/backprojectpatch.png differ diff --git a/imgproc/doc/pics/bayer.png b/imgproc/doc/pics/bayer.png new file mode 100644 index 0000000..92fe2dd Binary files /dev/null and b/imgproc/doc/pics/bayer.png differ diff --git a/imgproc/doc/pics/boundingrect.png b/imgproc/doc/pics/boundingrect.png new file mode 100644 index 0000000..3ccfe4b Binary files /dev/null and b/imgproc/doc/pics/boundingrect.png differ diff --git a/imgproc/doc/pics/building.jpg b/imgproc/doc/pics/building.jpg new file mode 100644 index 0000000..6056492 Binary files /dev/null and b/imgproc/doc/pics/building.jpg differ diff --git a/imgproc/doc/pics/contoursecarea.png b/imgproc/doc/pics/contoursecarea.png new file mode 100644 index 0000000..de67e28 Binary files /dev/null and b/imgproc/doc/pics/contoursecarea.png differ diff --git a/imgproc/doc/pics/cornersubpix.png b/imgproc/doc/pics/cornersubpix.png new file mode 100644 index 0000000..b86febb Binary files /dev/null and b/imgproc/doc/pics/cornersubpix.png differ diff --git a/imgproc/doc/pics/defects.png b/imgproc/doc/pics/defects.png new file mode 100644 index 0000000..2ec45ac Binary files /dev/null and b/imgproc/doc/pics/defects.png differ diff --git a/imgproc/doc/pics/houghp.png b/imgproc/doc/pics/houghp.png new file mode 100644 index 0000000..18d2096 Binary files /dev/null and b/imgproc/doc/pics/houghp.png differ diff --git a/imgproc/doc/pics/integral.png b/imgproc/doc/pics/integral.png new file mode 100644 index 0000000..97a69c6 Binary files /dev/null and b/imgproc/doc/pics/integral.png differ diff --git a/imgproc/doc/pics/inv_logpolar.jpg b/imgproc/doc/pics/inv_logpolar.jpg new file mode 100644 index 0000000..d76f067 Binary files /dev/null and b/imgproc/doc/pics/inv_logpolar.jpg differ diff --git a/imgproc/doc/pics/logpolar.jpg b/imgproc/doc/pics/logpolar.jpg new file mode 100644 index 0000000..6c062e7 Binary files /dev/null and b/imgproc/doc/pics/logpolar.jpg differ diff --git a/imgproc/doc/pics/minareabox.png b/imgproc/doc/pics/minareabox.png new file mode 100644 index 0000000..7c10da1 Binary files /dev/null and b/imgproc/doc/pics/minareabox.png differ diff --git a/imgproc/doc/pics/pointpolygon.png b/imgproc/doc/pics/pointpolygon.png new file mode 100644 index 0000000..de49031 Binary files /dev/null and b/imgproc/doc/pics/pointpolygon.png differ diff --git a/imgproc/doc/pics/quadedge.png b/imgproc/doc/pics/quadedge.png new file mode 100644 index 0000000..2fc6c2b Binary files /dev/null and b/imgproc/doc/pics/quadedge.png differ diff --git a/imgproc/doc/pics/subdiv.png b/imgproc/doc/pics/subdiv.png new file mode 100644 index 0000000..21026e5 Binary files /dev/null and b/imgproc/doc/pics/subdiv.png differ diff --git a/imgproc/doc/pics/threshold.png b/imgproc/doc/pics/threshold.png new file mode 100644 index 0000000..2e1bfdf Binary files /dev/null and b/imgproc/doc/pics/threshold.png differ diff --git a/imgproc/doc/structural_analysis_and_shape_descriptors.rst b/imgproc/doc/structural_analysis_and_shape_descriptors.rst new file mode 100644 index 0000000..3019063 --- /dev/null +++ b/imgproc/doc/structural_analysis_and_shape_descriptors.rst @@ -0,0 +1,636 @@ +Structural Analysis and Shape Descriptors +========================================= + +.. highlight:: cpp + +moments +----------- +Calculates all of the moments up to the third order of a polygon or rasterized shape. + +.. ocv:function:: Moments moments( InputArray array, bool binaryImage=false ) + +.. ocv:pyfunction:: cv2.moments(array[, binaryImage]) -> retval + +.. ocv:cfunction:: void cvMoments( const CvArr* arr, CvMoments* moments, int binary=0 ) + +.. ocv:pyoldfunction:: cv.Moments(arr, binary=0) -> moments + + :param array: Raster image (single-channel, 8-bit or floating-point 2D array) or an array ( :math:`1 \times N` or :math:`N \times 1` ) of 2D points (``Point`` or ``Point2f`` ). + + :param binaryImage: If it is true, all non-zero image pixels are treated as 1's. The parameter is used for images only. + + :param moments: Output moments. + +The function computes moments, up to the 3rd order, of a vector shape or a rasterized shape. The results are returned in the structure ``Moments`` defined as: :: + + class Moments + { + public: + Moments(); + Moments(double m00, double m10, double m01, double m20, double m11, + double m02, double m30, double m21, double m12, double m03 ); + Moments( const CvMoments& moments ); + operator CvMoments() const; + + // spatial moments + double m00, m10, m01, m20, m11, m02, m30, m21, m12, m03; + // central moments + double mu20, mu11, mu02, mu30, mu21, mu12, mu03; + // central normalized moments + double nu20, nu11, nu02, nu30, nu21, nu12, nu03; + } + +In case of a raster image, the spatial moments :math:`\texttt{Moments::m}_{ji}` are computed as: + +.. math:: + + \texttt{m} _{ji}= \sum _{x,y} \left ( \texttt{array} (x,y) \cdot x^j \cdot y^i \right ) + +The central moments +:math:`\texttt{Moments::mu}_{ji}` are computed as: + +.. math:: + + \texttt{mu} _{ji}= \sum _{x,y} \left ( \texttt{array} (x,y) \cdot (x - \bar{x} )^j \cdot (y - \bar{y} )^i \right ) + +where +:math:`(\bar{x}, \bar{y})` is the mass center: + +.. math:: + + \bar{x} = \frac{\texttt{m}_{10}}{\texttt{m}_{00}} , \; \bar{y} = \frac{\texttt{m}_{01}}{\texttt{m}_{00}} + +The normalized central moments +:math:`\texttt{Moments::nu}_{ij}` are computed as: + +.. math:: + + \texttt{nu} _{ji}= \frac{\texttt{mu}_{ji}}{\texttt{m}_{00}^{(i+j)/2+1}} . + +.. note:: + + :math:`\texttt{mu}_{00}=\texttt{m}_{00}`, + :math:`\texttt{nu}_{00}=1` + :math:`\texttt{nu}_{10}=\texttt{mu}_{10}=\texttt{mu}_{01}=\texttt{mu}_{10}=0` , hence the values are not stored. + +The moments of a contour are defined in the same way but computed using the Green's formula (see http://en.wikipedia.org/wiki/Green_theorem). So, due to a limited raster resolution, the moments computed for a contour are slightly different from the moments computed for the same rasterized contour. + +.. note:: + + Since the contour moments are computed using Green formula, you may get seemingly odd results for contours with self-intersections, e.g. a zero area (``m00``) for butterfly-shaped contours. + +.. seealso:: + + :ocv:func:`contourArea`, + :ocv:func:`arcLength` + + + +HuMoments +------------- +Calculates seven Hu invariants. + +.. ocv:function:: void HuMoments( const Moments& m, OutputArray hu ) + +.. ocv:function:: void HuMoments( const Moments& moments, double hu[7] ) + +.. ocv:pyfunction:: cv2.HuMoments(m[, hu]) -> hu + +.. ocv:cfunction:: void cvGetHuMoments( CvMoments* moments, CvHuMoments* hu_moments ) + +.. ocv:pyoldfunction:: cv.GetHuMoments(moments) -> hu + + :param moments: Input moments computed with :ocv:func:`moments` . + :param hu: Output Hu invariants. + +The function calculates seven Hu invariants (introduced in [Hu62]_; see also +http://en.wikipedia.org/wiki/Image_moment) defined as: + +.. math:: + + \begin{array}{l} hu[0]= \eta _{20}+ \eta _{02} \\ hu[1]=( \eta _{20}- \eta _{02})^{2}+4 \eta _{11}^{2} \\ hu[2]=( \eta _{30}-3 \eta _{12})^{2}+ (3 \eta _{21}- \eta _{03})^{2} \\ hu[3]=( \eta _{30}+ \eta _{12})^{2}+ ( \eta _{21}+ \eta _{03})^{2} \\ hu[4]=( \eta _{30}-3 \eta _{12})( \eta _{30}+ \eta _{12})[( \eta _{30}+ \eta _{12})^{2}-3( \eta _{21}+ \eta _{03})^{2}]+(3 \eta _{21}- \eta _{03})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}] \\ hu[5]=( \eta _{20}- \eta _{02})[( \eta _{30}+ \eta _{12})^{2}- ( \eta _{21}+ \eta _{03})^{2}]+4 \eta _{11}( \eta _{30}+ \eta _{12})( \eta _{21}+ \eta _{03}) \\ hu[6]=(3 \eta _{21}- \eta _{03})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}]-( \eta _{30}-3 \eta _{12})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}] \\ \end{array} + +where +:math:`\eta_{ji}` stands for +:math:`\texttt{Moments::nu}_{ji}` . + +These values are proved to be invariants to the image scale, rotation, and reflection except the seventh one, whose sign is changed by reflection. This invariance is proved with the assumption of infinite image resolution. In case of raster images, the computed Hu invariants for the original and transformed images are a bit different. + +.. seealso:: :ocv:func:`matchShapes` + + +findContours +---------------- +Finds contours in a binary image. + +.. ocv:function:: void findContours( InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point()) + +.. ocv:function:: void findContours( InputOutputArray image, OutputArrayOfArrays contours, int mode, int method, Point offset=Point()) + +.. ocv:pyfunction:: cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]]) -> contours, hierarchy + +.. ocv:cfunction:: int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour, int header_size=sizeof(CvContour), int mode=CV_RETR_LIST, int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) ) + +.. ocv:pyoldfunction:: cv.FindContours(image, storage, mode=CV_RETR_LIST, method=CV_CHAIN_APPROX_SIMPLE, offset=(0, 0)) -> contours + + :param image: Source, an 8-bit single-channel image. Non-zero pixels are treated as 1's. Zero pixels remain 0's, so the image is treated as ``binary`` . You can use :ocv:func:`compare` , :ocv:func:`inRange` , :ocv:func:`threshold` , :ocv:func:`adaptiveThreshold` , :ocv:func:`Canny` , and others to create a binary image out of a grayscale or color one. The function modifies the ``image`` while extracting the contours. + + :param contours: Detected contours. Each contour is stored as a vector of points. + + :param hierarchy: Optional output vector containing information about the image topology. It has as many elements as the number of contours. For each contour ``contours[i]`` , the elements ``hierarchy[i][0]`` , ``hiearchy[i][1]`` , ``hiearchy[i][2]`` , and ``hiearchy[i][3]`` are set to 0-based indices in ``contours`` of the next and previous contours at the same hierarchical level: the first child contour and the parent contour, respectively. If for a contour ``i`` there are no next, previous, parent, or nested contours, the corresponding elements of ``hierarchy[i]`` will be negative. + + :param mode: Contour retrieval mode (if you use Python see also a note below). + + * **CV_RETR_EXTERNAL** retrieves only the extreme outer contours. It sets ``hierarchy[i][2]=hierarchy[i][3]=-1`` for all the contours. + + * **CV_RETR_LIST** retrieves all of the contours without establishing any hierarchical relationships. + + * **CV_RETR_CCOMP** retrieves all of the contours and organizes them into a two-level hierarchy. At the top level, there are external boundaries of the components. At the second level, there are boundaries of the holes. If there is another contour inside a hole of a connected component, it is still put at the top level. + + * **CV_RETR_TREE** retrieves all of the contours and reconstructs a full hierarchy of nested contours. This full hierarchy is built and shown in the OpenCV ``contours.c`` demo. + + :param method: Contour approximation method (if you use Python see also a note below). + + * **CV_CHAIN_APPROX_NONE** stores absolutely all the contour points. That is, any 2 subsequent points ``(x1,y1)`` and ``(x2,y2)`` of the contour will be either horizontal, vertical or diagonal neighbors, that is, ``max(abs(x1-x2),abs(y2-y1))==1``. + + * **CV_CHAIN_APPROX_SIMPLE** compresses horizontal, vertical, and diagonal segments and leaves only their end points. For example, an up-right rectangular contour is encoded with 4 points. + + * **CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS** applies one of the flavors of the Teh-Chin chain approximation algorithm. See [TehChin89]_ for details. + + :param offset: Optional offset by which every contour point is shifted. This is useful if the contours are extracted from the image ROI and then they should be analyzed in the whole image context. + +The function retrieves contours from the binary image using the algorithm +[Suzuki85]_. The contours are a useful tool for shape analysis and object detection and recognition. See ``squares.c`` in the OpenCV sample directory. + +.. note:: Source ``image`` is modified by this function. + +.. note:: If you use the new Python interface then the ``CV_`` prefix has to be omitted in contour retrieval mode and contour approximation method parameters (for example, use ``cv2.RETR_LIST`` and ``cv2.CHAIN_APPROX_NONE`` parameters). If you use the old Python interface then these parameters have the ``CV_`` prefix (for example, use ``cv.CV_RETR_LIST`` and ``cv.CV_CHAIN_APPROX_NONE``). + + +approxPolyDP +---------------- +Approximates a polygonal curve(s) with the specified precision. + +.. ocv:function:: void approxPolyDP( InputArray curve, OutputArray approxCurve, double epsilon, bool closed ) + +.. ocv:pyfunction:: cv2.approxPolyDP(curve, epsilon, closed[, approxCurve]) -> approxCurve + +.. ocv:cfunction:: CvSeq* cvApproxPoly( const void* src_seq, int header_size, CvMemStorage* storage, int method, double eps, int recursive=0 ) + + :param curve: Input vector of a 2D point stored in: + + * ``std::vector`` or ``Mat`` (C++ interface) + + * ``Nx2`` numpy array (Python interface) + + * ``CvSeq`` or `` ``CvMat`` (C interface) + + :param approxCurve: Result of the approximation. The type should match the type of the input curve. In case of C interface the approximated curve is stored in the memory storage and pointer to it is returned. + + :param epsilon: Parameter specifying the approximation accuracy. This is the maximum distance between the original curve and its approximation. + + :param closed: If true, the approximated curve is closed (its first and last vertices are connected). Otherwise, it is not closed. + + :param header_size: Header size of the approximated curve. Normally, ``sizeof(CvContour)`` is used. + + :param storage: Memory storage where the approximated curve is stored. + + :param method: Contour approximation algorithm. Only ``CV_POLY_APPROX_DP`` is supported. + + :param recursive: Recursion flag. If it is non-zero and ``curve`` is ``CvSeq*``, the function ``cvApproxPoly`` approximates all the contours accessible from ``curve`` by ``h_next`` and ``v_next`` links. + +The functions ``approxPolyDP`` approximate a curve or a polygon with another curve/polygon with less vertices so that the distance between them is less or equal to the specified precision. It uses the Douglas-Peucker algorithm +http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm + +See http://code.opencv.org/projects/opencv/repository/revisions/master/entry/samples/cpp/contours.cpp for the function usage model. + + +ApproxChains +------------- +Approximates Freeman chain(s) with a polygonal curve. + +.. ocv:cfunction:: CvSeq* cvApproxChains( CvSeq* src_seq, CvMemStorage* storage, int method=CV_CHAIN_APPROX_SIMPLE, double parameter=0, int minimal_perimeter=0, int recursive=0 ) + +.. ocv:pyoldfunction:: cv.ApproxChains(src_seq, storage, method=CV_CHAIN_APPROX_SIMPLE, parameter=0, minimal_perimeter=0, recursive=0)-> contours + + :param src_seq: Pointer to the approximated Freeman chain that can refer to other chains. + + :param storage: Storage location for the resulting polylines. + + :param method: Approximation method (see the description of the function :ocv:cfunc:`FindContours` ). + + :param parameter: Method parameter (not used now). + + :param minimal_perimeter: Approximates only those contours whose perimeters are not less than ``minimal_perimeter`` . Other chains are removed from the resulting structure. + + :param recursive: Recursion flag. If it is non-zero, the function approximates all chains that can be obtained from ``chain`` by using the ``h_next`` or ``v_next`` links. Otherwise, the single input chain is approximated. + +This is a standalone contour approximation routine, not represented in the new interface. When :ocv:cfunc:`FindContours` retrieves contours as Freeman chains, it calls the function to get approximated contours, represented as polygons. + + +arcLength +------------- +Calculates a contour perimeter or a curve length. + +.. ocv:function:: double arcLength( InputArray curve, bool closed ) + +.. ocv:pyfunction:: cv2.arcLength(curve, closed) -> retval + +.. ocv:cfunction:: double cvArcLength( const void* curve, CvSlice slice=CV_WHOLE_SEQ, int is_closed=-1 ) + +.. ocv:pyoldfunction:: cv.ArcLength(curve, slice=CV_WHOLE_SEQ, isClosed=-1) -> float + + :param curve: Input vector of 2D points, stored in ``std::vector`` or ``Mat``. + + :param closed: Flag indicating whether the curve is closed or not. + +The function computes a curve length or a closed contour perimeter. + + + +boundingRect +---------------- +Calculates the up-right bounding rectangle of a point set. + +.. ocv:function:: Rect boundingRect( InputArray points ) + +.. ocv:pyfunction:: cv2.boundingRect(points) -> retval + +.. ocv:cfunction:: CvRect cvBoundingRect( CvArr* points, int update=0 ) +.. ocv:pyoldfunction:: cv.BoundingRect(points, update=0)-> CvRect + + :param points: Input 2D point set, stored in ``std::vector`` or ``Mat``. + +The function calculates and returns the minimal up-right bounding rectangle for the specified point set. + + + + +contourArea +--------------- +Calculates a contour area. + +.. ocv:function:: double contourArea( InputArray contour, bool oriented=false ) + +.. ocv:pyfunction:: cv2.contourArea(contour[, oriented]) -> retval + +.. ocv:cfunction:: double cvContourArea( const CvArr* contour, CvSlice slice=CV_WHOLE_SEQ, int oriented=0 ) + +.. ocv:pyoldfunction:: cv.ContourArea(contour, slice=CV_WHOLE_SEQ) -> float + + :param contour: Input vector of 2D points (contour vertices), stored in ``std::vector`` or ``Mat``. + + :param oriented: Oriented area flag. If it is true, the function returns a signed area value, depending on the contour orientation (clockwise or counter-clockwise). Using this feature you can determine orientation of a contour by taking the sign of an area. By default, the parameter is ``false``, which means that the absolute value is returned. + +The function computes a contour area. Similarly to +:ocv:func:`moments` , the area is computed using the Green formula. Thus, the returned area and the number of non-zero pixels, if you draw the contour using +:ocv:func:`drawContours` or +:ocv:func:`fillPoly` , can be different. +Also, the function will most certainly give a wrong results for contours with self-intersections. + +Example: :: + + vector contour; + contour.push_back(Point2f(0, 0)); + contour.push_back(Point2f(10, 0)); + contour.push_back(Point2f(10, 10)); + contour.push_back(Point2f(5, 4)); + + double area0 = contourArea(contour); + vector approx; + approxPolyDP(contour, approx, 5, true); + double area1 = contourArea(approx); + + cout << "area0 =" << area0 << endl << + "area1 =" << area1 << endl << + "approx poly vertices" << approx.size() << endl; + + + +convexHull +-------------- +Finds the convex hull of a point set. + +.. ocv:function:: void convexHull( InputArray points, OutputArray hull, bool clockwise=false, bool returnPoints=true ) + +.. ocv:pyfunction:: cv2.convexHull(points[, hull[, clockwise[, returnPoints]]]) -> hull + +.. ocv:cfunction:: CvSeq* cvConvexHull2( const CvArr* input, void* hull_storage=NULL, int orientation=CV_CLOCKWISE, int return_points=0 ) + +.. ocv:pyoldfunction:: cv.ConvexHull2(points, storage, orientation=CV_CLOCKWISE, return_points=0) -> convexHull + + :param points: Input 2D point set, stored in ``std::vector`` or ``Mat``. + + :param hull: Output convex hull. It is either an integer vector of indices or vector of points. In the first case, the ``hull`` elements are 0-based indices of the convex hull points in the original array (since the set of convex hull points is a subset of the original point set). In the second case, ``hull`` elements are the convex hull points themselves. + + :param hull_storage: Output memory storage in the old API (``cvConvexHull2`` returns a sequence containing the convex hull points or their indices). + + :param clockwise: Orientation flag. If it is true, the output convex hull is oriented clockwise. Otherwise, it is oriented counter-clockwise. The usual screen coordinate system is assumed so that the origin is at the top-left corner, x axis is oriented to the right, and y axis is oriented downwards. + + :param orientation: Convex hull orientation parameter in the old API, ``CV_CLOCKWISE`` or ``CV_COUNTERCLOCKWISE``. + + :param returnPoints: Operation flag. In case of a matrix, when the flag is true, the function returns convex hull points. Otherwise, it returns indices of the convex hull points. When the output array is ``std::vector``, the flag is ignored, and the output depends on the type of the vector: ``std::vector`` implies ``returnPoints=true``, ``std::vector`` implies ``returnPoints=false``. + +The functions find the convex hull of a 2D point set using the Sklansky's algorithm +[Sklansky82]_ +that has +*O(N logN)* complexity in the current implementation. See the OpenCV sample ``convexhull.cpp`` that demonstrates the usage of different function variants. + + +convexityDefects +---------------- +Finds the convexity defects of a contour. + +.. ocv:function:: void convexityDefects( InputArray contour, InputArray convexhull, OutputArray convexityDefects ) + +.. ocv:pyfunction:: cv2.convexityDefects(contour, convexhull[, convexityDefects]) -> convexityDefects + +.. ocv:cfunction:: CvSeq* cvConvexityDefects( const CvArr* contour, const CvArr* convexhull, CvMemStorage* storage=NULL ) + +.. ocv:pyoldfunction:: cv.ConvexityDefects(contour, convexhull, storage)-> convexityDefects + + :param contour: Input contour. + + :param convexhull: Convex hull obtained using :ocv:func:`convexHull` that should contain indices of the contour points that make the hull. + + :param convexityDefects: The output vector of convexity defects. In C++ and the new Python/Java interface each convexity defect is represented as 4-element integer vector (a.k.a. ``cv::Vec4i``): ``(start_index, end_index, farthest_pt_index, fixpt_depth)``, where indices are 0-based indices in the original contour of the convexity defect beginning, end and the farthest point, and ``fixpt_depth`` is fixed-point approximation (with 8 fractional bits) of the distance between the farthest contour point and the hull. That is, to get the floating-point value of the depth will be ``fixpt_depth/256.0``. In C interface convexity defect is represented by ``CvConvexityDefect`` structure - see below. + + :param storage: Container for the output sequence of convexity defects. If it is NULL, the contour or hull (in that order) storage is used. + +The function finds all convexity defects of the input contour and returns a sequence of the ``CvConvexityDefect`` structures, where ``CvConvexityDetect`` is defined as: :: + + struct CvConvexityDefect + { + CvPoint* start; // point of the contour where the defect begins + CvPoint* end; // point of the contour where the defect ends + CvPoint* depth_point; // the farthest from the convex hull point within the defect + float depth; // distance between the farthest point and the convex hull + }; + +The figure below displays convexity defects of a hand contour: + +.. image:: pics/defects.png + +fitEllipse +-------------- +Fits an ellipse around a set of 2D points. + +.. ocv:function:: RotatedRect fitEllipse( InputArray points ) + +.. ocv:pyfunction:: cv2.fitEllipse(points) -> retval + +.. ocv:cfunction:: CvBox2D cvFitEllipse2( const CvArr* points ) +.. ocv:pyoldfunction:: cv.FitEllipse2(points)-> Box2D + + :param points: Input 2D point set, stored in: + + * ``std::vector<>`` or ``Mat`` (C++ interface) + + * ``CvSeq*`` or ``CvMat*`` (C interface) + + * Nx2 numpy array (Python interface) + +The function calculates the ellipse that fits (in a least-squares sense) a set of 2D points best of all. It returns the rotated rectangle in which the ellipse is inscribed. The algorithm [Fitzgibbon95]_ is used. + +fitLine +----------- +Fits a line to a 2D or 3D point set. + +.. ocv:function:: void fitLine( InputArray points, OutputArray line, int distType, double param, double reps, double aeps ) + +.. ocv:pyfunction:: cv2.fitLine(points, distType, param, reps, aeps[, line]) -> line + +.. ocv:cfunction:: void cvFitLine( const CvArr* points, int dist_type, double param, double reps, double aeps, float* line ) + +.. ocv:pyoldfunction:: cv.FitLine(points, dist_type, param, reps, aeps) -> line + + :param points: Input vector of 2D or 3D points, stored in ``std::vector<>`` or ``Mat``. + + :param line: Output line parameters. In case of 2D fitting, it should be a vector of 4 elements (like ``Vec4f``) - ``(vx, vy, x0, y0)``, where ``(vx, vy)`` is a normalized vector collinear to the line and ``(x0, y0)`` is a point on the line. In case of 3D fitting, it should be a vector of 6 elements (like ``Vec6f``) - ``(vx, vy, vz, x0, y0, z0)``, where ``(vx, vy, vz)`` is a normalized vector collinear to the line and ``(x0, y0, z0)`` is a point on the line. + + :param distType: Distance used by the M-estimator (see the discussion below). + + :param param: Numerical parameter ( ``C`` ) for some types of distances. If it is 0, an optimal value is chosen. + + :param reps: Sufficient accuracy for the radius (distance between the coordinate origin and the line). + + :param aeps: Sufficient accuracy for the angle. 0.01 would be a good default value for ``reps`` and ``aeps``. + +The function ``fitLine`` fits a line to a 2D or 3D point set by minimizing +:math:`\sum_i \rho(r_i)` where +:math:`r_i` is a distance between the +:math:`i^{th}` point, the line and +:math:`\rho(r)` is a distance function, one of the following: + +* distType=CV\_DIST\_L2 + + .. math:: + + \rho (r) = r^2/2 \quad \text{(the simplest and the fastest least-squares method)} + +* distType=CV\_DIST\_L1 + + .. math:: + + \rho (r) = r + +* distType=CV\_DIST\_L12 + + .. math:: + + \rho (r) = 2 \cdot ( \sqrt{1 + \frac{r^2}{2}} - 1) + +* distType=CV\_DIST\_FAIR + + .. math:: + + \rho \left (r \right ) = C^2 \cdot \left ( \frac{r}{C} - \log{\left(1 + \frac{r}{C}\right)} \right ) \quad \text{where} \quad C=1.3998 + +* distType=CV\_DIST\_WELSCH + + .. math:: + + \rho \left (r \right ) = \frac{C^2}{2} \cdot \left ( 1 - \exp{\left(-\left(\frac{r}{C}\right)^2\right)} \right ) \quad \text{where} \quad C=2.9846 + +* distType=CV\_DIST\_HUBER + + .. math:: + + \rho (r) = \fork{r^2/2}{if $r < C$}{C \cdot (r-C/2)}{otherwise} \quad \text{where} \quad C=1.345 + +The algorithm is based on the M-estimator ( +http://en.wikipedia.org/wiki/M-estimator +) technique that iteratively fits the line using the weighted least-squares algorithm. After each iteration the weights +:math:`w_i` are adjusted to be inversely proportional to +:math:`\rho(r_i)` . + + + +isContourConvex +------------------- +Tests a contour convexity. + +.. ocv:function:: bool isContourConvex( InputArray contour ) + +.. ocv:pyfunction:: cv2.isContourConvex(contour) -> retval + +.. ocv:cfunction:: int cvCheckContourConvexity( const CvArr* contour ) +.. ocv:pyoldfunction:: cv.CheckContourConvexity(contour)-> int + + :param contour: Input vector of 2D points, stored in: + + * ``std::vector<>`` or ``Mat`` (C++ interface) + + * ``CvSeq*`` or ``CvMat*`` (C interface) + + * Nx2 numpy array (Python interface) + +The function tests whether the input contour is convex or not. The contour must be simple, that is, without self-intersections. Otherwise, the function output is undefined. + + + +minAreaRect +--------------- +Finds a rotated rectangle of the minimum area enclosing the input 2D point set. + +.. ocv:function:: RotatedRect minAreaRect( InputArray points ) + +.. ocv:pyfunction:: cv2.minAreaRect(points) -> retval + +.. ocv:cfunction:: CvBox2D cvMinAreaRect2( const CvArr* points, CvMemStorage* storage=NULL ) + +.. ocv:pyoldfunction:: cv.MinAreaRect2(points, storage=None) -> Box2D + + :param points: Input vector of 2D points, stored in: + + * ``std::vector<>`` or ``Mat`` (C++ interface) + + * ``CvSeq*`` or ``CvMat*`` (C interface) + + * Nx2 numpy array (Python interface) + +The function calculates and returns the minimum-area bounding rectangle (possibly rotated) for a specified point set. See the OpenCV sample ``minarea.cpp`` . + + + +minEnclosingCircle +---------------------- +Finds a circle of the minimum area enclosing a 2D point set. + +.. ocv:function:: void minEnclosingCircle( InputArray points, Point2f& center, float& radius ) + +.. ocv:pyfunction:: cv2.minEnclosingCircle(points) -> center, radius + +.. ocv:cfunction:: int cvMinEnclosingCircle( const CvArr* points, CvPoint2D32f* center, float* radius ) + +.. ocv:pyoldfunction:: cv.MinEnclosingCircle(points)-> (int, center, radius) + + :param points: Input vector of 2D points, stored in: + + * ``std::vector<>`` or ``Mat`` (C++ interface) + + * ``CvSeq*`` or ``CvMat*`` (C interface) + + * Nx2 numpy array (Python interface) + + :param center: Output center of the circle. + + :param radius: Output radius of the circle. + +The function finds the minimal enclosing circle of a 2D point set using an iterative algorithm. See the OpenCV sample ``minarea.cpp`` . + + + +matchShapes +--------------- +Compares two shapes. + +.. ocv:function:: double matchShapes( InputArray contour1, InputArray contour2, int method, double parameter ) + +.. ocv:pyfunction:: cv2.matchShapes(contour1, contour2, method, parameter) -> retval + +.. ocv:cfunction:: double cvMatchShapes( const void* object1, const void* object2, int method, double parameter=0 ) +.. ocv:pyoldfunction:: cv.MatchShapes(object1, object2, method, parameter=0) -> float + + :param object1: First contour or grayscale image. + + :param object2: Second contour or grayscale image. + + :param method: Comparison method: ``CV_CONTOURS_MATCH_I1`` , \ ``CV_CONTOURS_MATCH_I2`` \ + or ``CV_CONTOURS_MATCH_I3`` (see the details below). + + :param parameter: Method-specific parameter (not supported now). + +The function compares two shapes. All three implemented methods use the Hu invariants (see +:ocv:func:`HuMoments` ) as follows ( +:math:`A` denotes ``object1``,:math:`B` denotes ``object2`` ): + +* method=CV_CONTOURS_MATCH_I1 + + .. math:: + + I_1(A,B) = \sum _{i=1...7} \left | \frac{1}{m^A_i} - \frac{1}{m^B_i} \right | + +* method=CV_CONTOURS_MATCH_I2 + + .. math:: + + I_2(A,B) = \sum _{i=1...7} \left | m^A_i - m^B_i \right | + +* method=CV_CONTOURS_MATCH_I3 + + .. math:: + + I_3(A,B) = \max _{i=1...7} \frac{ \left| m^A_i - m^B_i \right| }{ \left| m^A_i \right| } + +where + +.. math:: + + \begin{array}{l} m^A_i = \mathrm{sign} (h^A_i) \cdot \log{h^A_i} \\ m^B_i = \mathrm{sign} (h^B_i) \cdot \log{h^B_i} \end{array} + +and +:math:`h^A_i, h^B_i` are the Hu moments of +:math:`A` and +:math:`B` , respectively. + + + +pointPolygonTest +-------------------- +Performs a point-in-contour test. + +.. ocv:function:: double pointPolygonTest( InputArray contour, Point2f pt, bool measureDist ) + +.. ocv:pyfunction:: cv2.pointPolygonTest(contour, pt, measureDist) -> retval + +.. ocv:cfunction:: double cvPointPolygonTest( const CvArr* contour, CvPoint2D32f pt, int measure_dist ) +.. ocv:pyoldfunction:: cv.PointPolygonTest(contour, pt, measure_dist) -> float + + :param contour: Input contour. + + :param pt: Point tested against the contour. + + :param measureDist: If true, the function estimates the signed distance from the point to the nearest contour edge. Otherwise, the function only checks if the point is inside a contour or not. + +The function determines whether the +point is inside a contour, outside, or lies on an edge (or coincides +with a vertex). It returns positive (inside), negative (outside), or zero (on an edge) value, +correspondingly. When ``measureDist=false`` , the return value +is +1, -1, and 0, respectively. Otherwise, the return value +is a signed distance between the point and the nearest contour +edge. + +See below a sample output of the function where each image pixel is tested against the contour. + +.. image:: pics/pointpolygon.png + +.. [Fitzgibbon95] Andrew W. Fitzgibbon, R.B.Fisher. *A Buyer's Guide to Conic Fitting*. Proc.5th British Machine Vision Conference, Birmingham, pp. 513-522, 1995. + +.. [Hu62] M. Hu. *Visual Pattern Recognition by Moment Invariants*, IRE Transactions on Information Theory, 8:2, pp. 179-187, 1962. + +.. [Sklansky82] Sklansky, J., *Finding the Convex Hull of a Simple Polygon*. PRL 1 $number, pp 79-83 (1982) + +.. [Suzuki85] Suzuki, S. and Abe, K., *Topological Structural Analysis of Digitized Binary Images by Border Following*. CVGIP 30 1, pp 32-46 (1985) + +.. [TehChin89] Teh, C.H. and Chin, R.T., *On the Detection of Dominant Points on Digital Curve*. PAMI 11 8, pp 859-872 (1989) diff --git a/imgproc/include/.DS_Store b/imgproc/include/.DS_Store new file mode 100644 index 0000000..9619eb9 Binary files /dev/null and b/imgproc/include/.DS_Store differ diff --git a/imgproc/include/opencv2/.DS_Store b/imgproc/include/opencv2/.DS_Store new file mode 100644 index 0000000..25ada15 Binary files /dev/null and b/imgproc/include/opencv2/.DS_Store differ diff --git a/imgproc/include/opencv2/imgproc/imgproc.hpp b/imgproc/include/opencv2/imgproc/imgproc.hpp new file mode 100644 index 0000000..d0031bf --- /dev/null +++ b/imgproc/include/opencv2/imgproc/imgproc.hpp @@ -0,0 +1,1225 @@ +/*! \file imgproc.hpp + \brief The Image Processing + */ + +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_IMGPROC_HPP__ +#define __OPENCV_IMGPROC_HPP__ + +#include "opencv2/core/core.hpp" +#include "opencv2/imgproc/types_c.h" + +#ifdef __cplusplus + +/*! \namespace cv + Namespace where all the C++ OpenCV functionality resides + */ +namespace cv +{ + +//! various border interpolation methods +enum { BORDER_REPLICATE=IPL_BORDER_REPLICATE, BORDER_CONSTANT=IPL_BORDER_CONSTANT, + BORDER_REFLECT=IPL_BORDER_REFLECT, BORDER_WRAP=IPL_BORDER_WRAP, + BORDER_REFLECT_101=IPL_BORDER_REFLECT_101, BORDER_REFLECT101=BORDER_REFLECT_101, + BORDER_TRANSPARENT=IPL_BORDER_TRANSPARENT, + BORDER_DEFAULT=BORDER_REFLECT_101, BORDER_ISOLATED=16 }; + +//! 1D interpolation function: returns coordinate of the "donor" pixel for the specified location p. +CV_EXPORTS_W int borderInterpolate( int p, int len, int borderType ); + +/*! + The Base Class for 1D or Row-wise Filters + + This is the base class for linear or non-linear filters that process 1D data. + In particular, such filters are used for the "horizontal" filtering parts in separable filters. + + Several functions in OpenCV return Ptr for the specific types of filters, + and those pointers can be used directly or within cv::FilterEngine. +*/ +class CV_EXPORTS BaseRowFilter +{ +public: + //! the default constructor + BaseRowFilter(); + //! the destructor + virtual ~BaseRowFilter(); + //! the filtering operator. Must be overrided in the derived classes. The horizontal border interpolation is done outside of the class. + virtual void operator()(const uchar* src, uchar* dst, + int width, int cn) = 0; + int ksize, anchor; +}; + + +/*! + The Base Class for Column-wise Filters + + This is the base class for linear or non-linear filters that process columns of 2D arrays. + Such filters are used for the "vertical" filtering parts in separable filters. + + Several functions in OpenCV return Ptr for the specific types of filters, + and those pointers can be used directly or within cv::FilterEngine. + + Unlike cv::BaseRowFilter, cv::BaseColumnFilter may have some context information, + i.e. box filter keeps the sliding sum of elements. To reset the state BaseColumnFilter::reset() + must be called (e.g. the method is called by cv::FilterEngine) + */ +class CV_EXPORTS BaseColumnFilter +{ +public: + //! the default constructor + BaseColumnFilter(); + //! the destructor + virtual ~BaseColumnFilter(); + //! the filtering operator. Must be overrided in the derived classes. The vertical border interpolation is done outside of the class. + virtual void operator()(const uchar** src, uchar* dst, int dststep, + int dstcount, int width) = 0; + //! resets the internal buffers, if any + virtual void reset(); + int ksize, anchor; +}; + +/*! + The Base Class for Non-Separable 2D Filters. + + This is the base class for linear or non-linear 2D filters. + + Several functions in OpenCV return Ptr for the specific types of filters, + and those pointers can be used directly or within cv::FilterEngine. + + Similar to cv::BaseColumnFilter, the class may have some context information, + that should be reset using BaseFilter::reset() method before processing the new array. +*/ +class CV_EXPORTS BaseFilter +{ +public: + //! the default constructor + BaseFilter(); + //! the destructor + virtual ~BaseFilter(); + //! the filtering operator. The horizontal and the vertical border interpolation is done outside of the class. + virtual void operator()(const uchar** src, uchar* dst, int dststep, + int dstcount, int width, int cn) = 0; + //! resets the internal buffers, if any + virtual void reset(); + Size ksize; + Point anchor; +}; + +/*! + The Main Class for Image Filtering. + + The class can be used to apply an arbitrary filtering operation to an image. + It contains all the necessary intermediate buffers, it computes extrapolated values + of the "virtual" pixels outside of the image etc. + Pointers to the initialized cv::FilterEngine instances + are returned by various OpenCV functions, such as cv::createSeparableLinearFilter(), + cv::createLinearFilter(), cv::createGaussianFilter(), cv::createDerivFilter(), + cv::createBoxFilter() and cv::createMorphologyFilter(). + + Using the class you can process large images by parts and build complex pipelines + that include filtering as some of the stages. If all you need is to apply some pre-defined + filtering operation, you may use cv::filter2D(), cv::erode(), cv::dilate() etc. + functions that create FilterEngine internally. + + Here is the example on how to use the class to implement Laplacian operator, which is the sum of + second-order derivatives. More complex variant for different types is implemented in cv::Laplacian(). + + \code + void laplace_f(const Mat& src, Mat& dst) + { + CV_Assert( src.type() == CV_32F ); + // make sure the destination array has the proper size and type + dst.create(src.size(), src.type()); + + // get the derivative and smooth kernels for d2I/dx2. + // for d2I/dy2 we could use the same kernels, just swapped + Mat kd, ks; + getSobelKernels( kd, ks, 2, 0, ksize, false, ktype ); + + // let's process 10 source rows at once + int DELTA = std::min(10, src.rows); + Ptr Fxx = createSeparableLinearFilter(src.type(), + dst.type(), kd, ks, Point(-1,-1), 0, borderType, borderType, Scalar() ); + Ptr Fyy = createSeparableLinearFilter(src.type(), + dst.type(), ks, kd, Point(-1,-1), 0, borderType, borderType, Scalar() ); + + int y = Fxx->start(src), dsty = 0, dy = 0; + Fyy->start(src); + const uchar* sptr = src.data + y*src.step; + + // allocate the buffers for the spatial image derivatives; + // the buffers need to have more than DELTA rows, because at the + // last iteration the output may take max(kd.rows-1,ks.rows-1) + // rows more than the input. + Mat Ixx( DELTA + kd.rows - 1, src.cols, dst.type() ); + Mat Iyy( DELTA + kd.rows - 1, src.cols, dst.type() ); + + // inside the loop we always pass DELTA rows to the filter + // (note that the "proceed" method takes care of possibe overflow, since + // it was given the actual image height in the "start" method) + // on output we can get: + // * < DELTA rows (the initial buffer accumulation stage) + // * = DELTA rows (settled state in the middle) + // * > DELTA rows (then the input image is over, but we generate + // "virtual" rows using the border mode and filter them) + // this variable number of output rows is dy. + // dsty is the current output row. + // sptr is the pointer to the first input row in the portion to process + for( ; dsty < dst.rows; sptr += DELTA*src.step, dsty += dy ) + { + Fxx->proceed( sptr, (int)src.step, DELTA, Ixx.data, (int)Ixx.step ); + dy = Fyy->proceed( sptr, (int)src.step, DELTA, d2y.data, (int)Iyy.step ); + if( dy > 0 ) + { + Mat dstripe = dst.rowRange(dsty, dsty + dy); + add(Ixx.rowRange(0, dy), Iyy.rowRange(0, dy), dstripe); + } + } + } + \endcode +*/ +class CV_EXPORTS FilterEngine +{ +public: + //! the default constructor + FilterEngine(); + //! the full constructor. Either _filter2D or both _rowFilter and _columnFilter must be non-empty. + FilterEngine(const Ptr& _filter2D, + const Ptr& _rowFilter, + const Ptr& _columnFilter, + int srcType, int dstType, int bufType, + int _rowBorderType=BORDER_REPLICATE, + int _columnBorderType=-1, + const Scalar& _borderValue=Scalar()); + //! the destructor + virtual ~FilterEngine(); + //! reinitializes the engine. The previously assigned filters are released. + void init(const Ptr& _filter2D, + const Ptr& _rowFilter, + const Ptr& _columnFilter, + int srcType, int dstType, int bufType, + int _rowBorderType=BORDER_REPLICATE, int _columnBorderType=-1, + const Scalar& _borderValue=Scalar()); + //! starts filtering of the specified ROI of an image of size wholeSize. + virtual int start(Size wholeSize, Rect roi, int maxBufRows=-1); + //! starts filtering of the specified ROI of the specified image. + virtual int start(const Mat& src, const Rect& srcRoi=Rect(0,0,-1,-1), + bool isolated=false, int maxBufRows=-1); + //! processes the next srcCount rows of the image. + virtual int proceed(const uchar* src, int srcStep, int srcCount, + uchar* dst, int dstStep); + //! applies filter to the specified ROI of the image. if srcRoi=(0,0,-1,-1), the whole image is filtered. + virtual void apply( const Mat& src, Mat& dst, + const Rect& srcRoi=Rect(0,0,-1,-1), + Point dstOfs=Point(0,0), + bool isolated=false); + //! returns true if the filter is separable + bool isSeparable() const { return (const BaseFilter*)filter2D == 0; } + //! returns the number + int remainingInputRows() const; + int remainingOutputRows() const; + + int srcType, dstType, bufType; + Size ksize; + Point anchor; + int maxWidth; + Size wholeSize; + Rect roi; + int dx1, dx2; + int rowBorderType, columnBorderType; + vector borderTab; + int borderElemSize; + vector ringBuf; + vector srcRow; + vector constBorderValue; + vector constBorderRow; + int bufStep, startY, startY0, endY, rowCount, dstY; + vector rows; + + Ptr filter2D; + Ptr rowFilter; + Ptr columnFilter; +}; + +//! type of the kernel +enum { KERNEL_GENERAL=0, KERNEL_SYMMETRICAL=1, KERNEL_ASYMMETRICAL=2, + KERNEL_SMOOTH=4, KERNEL_INTEGER=8 }; + +//! returns type (one of KERNEL_*) of 1D or 2D kernel specified by its coefficients. +CV_EXPORTS int getKernelType(InputArray kernel, Point anchor); + +//! returns the primitive row filter with the specified kernel +CV_EXPORTS Ptr getLinearRowFilter(int srcType, int bufType, + InputArray kernel, int anchor, + int symmetryType); + +//! returns the primitive column filter with the specified kernel +CV_EXPORTS Ptr getLinearColumnFilter(int bufType, int dstType, + InputArray kernel, int anchor, + int symmetryType, double delta=0, + int bits=0); + +//! returns 2D filter with the specified kernel +CV_EXPORTS Ptr getLinearFilter(int srcType, int dstType, + InputArray kernel, + Point anchor=Point(-1,-1), + double delta=0, int bits=0); + +//! returns the separable linear filter engine +CV_EXPORTS Ptr createSeparableLinearFilter(int srcType, int dstType, + InputArray rowKernel, InputArray columnKernel, + Point anchor=Point(-1,-1), double delta=0, + int rowBorderType=BORDER_DEFAULT, + int columnBorderType=-1, + const Scalar& borderValue=Scalar()); + +//! returns the non-separable linear filter engine +CV_EXPORTS Ptr createLinearFilter(int srcType, int dstType, + InputArray kernel, Point _anchor=Point(-1,-1), + double delta=0, int rowBorderType=BORDER_DEFAULT, + int columnBorderType=-1, const Scalar& borderValue=Scalar()); + +//! returns the Gaussian kernel with the specified parameters +CV_EXPORTS_W Mat getGaussianKernel( int ksize, double sigma, int ktype=CV_64F ); + +//! returns the Gaussian filter engine +CV_EXPORTS Ptr createGaussianFilter( int type, Size ksize, + double sigma1, double sigma2=0, + int borderType=BORDER_DEFAULT); +//! initializes kernels of the generalized Sobel operator +CV_EXPORTS_W void getDerivKernels( OutputArray kx, OutputArray ky, + int dx, int dy, int ksize, + bool normalize=false, int ktype=CV_32F ); +//! returns filter engine for the generalized Sobel operator +CV_EXPORTS Ptr createDerivFilter( int srcType, int dstType, + int dx, int dy, int ksize, + int borderType=BORDER_DEFAULT ); +//! returns horizontal 1D box filter +CV_EXPORTS Ptr getRowSumFilter(int srcType, int sumType, + int ksize, int anchor=-1); +//! returns vertical 1D box filter +CV_EXPORTS Ptr getColumnSumFilter( int sumType, int dstType, + int ksize, int anchor=-1, + double scale=1); +//! returns box filter engine +CV_EXPORTS Ptr createBoxFilter( int srcType, int dstType, Size ksize, + Point anchor=Point(-1,-1), + bool normalize=true, + int borderType=BORDER_DEFAULT); + +//! returns the Gabor kernel with the specified parameters +CV_EXPORTS_W Mat getGaborKernel( Size ksize, double sigma, double theta, double lambd, + double gamma, double psi=CV_PI*0.5, int ktype=CV_64F ); + +//! type of morphological operation +enum { MORPH_ERODE=CV_MOP_ERODE, MORPH_DILATE=CV_MOP_DILATE, + MORPH_OPEN=CV_MOP_OPEN, MORPH_CLOSE=CV_MOP_CLOSE, + MORPH_GRADIENT=CV_MOP_GRADIENT, MORPH_TOPHAT=CV_MOP_TOPHAT, + MORPH_BLACKHAT=CV_MOP_BLACKHAT }; + +//! returns horizontal 1D morphological filter +CV_EXPORTS Ptr getMorphologyRowFilter(int op, int type, int ksize, int anchor=-1); +//! returns vertical 1D morphological filter +CV_EXPORTS Ptr getMorphologyColumnFilter(int op, int type, int ksize, int anchor=-1); +//! returns 2D morphological filter +CV_EXPORTS Ptr getMorphologyFilter(int op, int type, InputArray kernel, + Point anchor=Point(-1,-1)); + +//! returns "magic" border value for erosion and dilation. It is automatically transformed to Scalar::all(-DBL_MAX) for dilation. +static inline Scalar morphologyDefaultBorderValue() { return Scalar::all(DBL_MAX); } + +//! returns morphological filter engine. Only MORPH_ERODE and MORPH_DILATE are supported. +CV_EXPORTS Ptr createMorphologyFilter(int op, int type, InputArray kernel, + Point anchor=Point(-1,-1), int rowBorderType=BORDER_CONSTANT, + int columnBorderType=-1, + const Scalar& borderValue=morphologyDefaultBorderValue()); + +//! shape of the structuring element +enum { MORPH_RECT=0, MORPH_CROSS=1, MORPH_ELLIPSE=2 }; +//! returns structuring element of the specified shape and size +CV_EXPORTS_W Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1)); + +template<> CV_EXPORTS void Ptr::delete_obj(); + +//! copies 2D array to a larger destination array with extrapolation of the outer part of src using the specified border mode +CV_EXPORTS_W void copyMakeBorder( InputArray src, OutputArray dst, + int top, int bottom, int left, int right, + int borderType, const Scalar& value=Scalar() ); + +//! smooths the image using median filter. +CV_EXPORTS_W void medianBlur( InputArray src, OutputArray dst, int ksize ); +//! smooths the image using Gaussian filter. +CV_EXPORTS_W void GaussianBlur( InputArray src, + OutputArray dst, Size ksize, + double sigmaX, double sigmaY=0, + int borderType=BORDER_DEFAULT ); +//! smooths the image using bilateral filter +CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d, + double sigmaColor, double sigmaSpace, + int borderType=BORDER_DEFAULT ); +//! smooths the image using the box filter. Each pixel is processed in O(1) time +CV_EXPORTS_W void boxFilter( InputArray src, OutputArray dst, int ddepth, + Size ksize, Point anchor=Point(-1,-1), + bool normalize=true, + int borderType=BORDER_DEFAULT ); +//! a synonym for normalized box filter +CV_EXPORTS_W void blur( InputArray src, OutputArray dst, + Size ksize, Point anchor=Point(-1,-1), + int borderType=BORDER_DEFAULT ); + +//! applies non-separable 2D linear filter to the image +CV_EXPORTS_W void filter2D( InputArray src, OutputArray dst, int ddepth, + InputArray kernel, Point anchor=Point(-1,-1), + double delta=0, int borderType=BORDER_DEFAULT ); + +//! applies separable 2D linear filter to the image +CV_EXPORTS_W void sepFilter2D( InputArray src, OutputArray dst, int ddepth, + InputArray kernelX, InputArray kernelY, + Point anchor=Point(-1,-1), + double delta=0, int borderType=BORDER_DEFAULT ); + +//! applies generalized Sobel operator to the image +CV_EXPORTS_W void Sobel( InputArray src, OutputArray dst, int ddepth, + int dx, int dy, int ksize=3, + double scale=1, double delta=0, + int borderType=BORDER_DEFAULT ); + +//! applies the vertical or horizontal Scharr operator to the image +CV_EXPORTS_W void Scharr( InputArray src, OutputArray dst, int ddepth, + int dx, int dy, double scale=1, double delta=0, + int borderType=BORDER_DEFAULT ); + +//! applies Laplacian operator to the image +CV_EXPORTS_W void Laplacian( InputArray src, OutputArray dst, int ddepth, + int ksize=1, double scale=1, double delta=0, + int borderType=BORDER_DEFAULT ); + +//! applies Canny edge detector and produces the edge map. +CV_EXPORTS_W void Canny( InputArray image, OutputArray edges, + double threshold1, double threshold2, + int apertureSize=3, bool L2gradient=false ); + +//! computes minimum eigen value of 2x2 derivative covariation matrix at each pixel - the cornerness criteria +CV_EXPORTS_W void cornerMinEigenVal( InputArray src, OutputArray dst, + int blockSize, int ksize=3, + int borderType=BORDER_DEFAULT ); + +//! computes Harris cornerness criteria at each image pixel +CV_EXPORTS_W void cornerHarris( InputArray src, OutputArray dst, int blockSize, + int ksize, double k, + int borderType=BORDER_DEFAULT ); + +// low-level function for computing eigenvalues and eigenvectors of 2x2 matrices +CV_EXPORTS void eigen2x2( const float* a, float* e, int n ); + +//! computes both eigenvalues and the eigenvectors of 2x2 derivative covariation matrix at each pixel. The output is stored as 6-channel matrix. +CV_EXPORTS_W void cornerEigenValsAndVecs( InputArray src, OutputArray dst, + int blockSize, int ksize, + int borderType=BORDER_DEFAULT ); + +//! computes another complex cornerness criteria at each pixel +CV_EXPORTS_W void preCornerDetect( InputArray src, OutputArray dst, int ksize, + int borderType=BORDER_DEFAULT ); + +//! adjusts the corner locations with sub-pixel accuracy to maximize the certain cornerness criteria +CV_EXPORTS_W void cornerSubPix( InputArray image, InputOutputArray corners, + Size winSize, Size zeroZone, + TermCriteria criteria ); + +//! finds the strong enough corners where the cornerMinEigenVal() or cornerHarris() report the local maxima +CV_EXPORTS_W void goodFeaturesToTrack( InputArray image, OutputArray corners, + int maxCorners, double qualityLevel, double minDistance, + InputArray mask=noArray(), int blockSize=3, + bool useHarrisDetector=false, double k=0.04 ); + +//! finds lines in the black-n-white image using the standard or pyramid Hough transform +CV_EXPORTS_W void HoughLines( InputArray image, OutputArray lines, + double rho, double theta, int threshold, + double srn=0, double stn=0 ); + +//! finds line segments in the black-n-white image using probabalistic Hough transform +CV_EXPORTS_W void HoughLinesP( InputArray image, OutputArray lines, + double rho, double theta, int threshold, + double minLineLength=0, double maxLineGap=0 ); + +//! finds circles in the grayscale image using 2+1 gradient Hough transform +CV_EXPORTS_W void HoughCircles( InputArray image, OutputArray circles, + int method, double dp, double minDist, + double param1=100, double param2=100, + int minRadius=0, int maxRadius=0 ); + +//! erodes the image (applies the local minimum operator) +CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel, + Point anchor=Point(-1,-1), int iterations=1, + int borderType=BORDER_CONSTANT, + const Scalar& borderValue=morphologyDefaultBorderValue() ); + +//! dilates the image (applies the local maximum operator) +CV_EXPORTS_W void dilate( InputArray src, OutputArray dst, InputArray kernel, + Point anchor=Point(-1,-1), int iterations=1, + int borderType=BORDER_CONSTANT, + const Scalar& borderValue=morphologyDefaultBorderValue() ); + +//! applies an advanced morphological operation to the image +CV_EXPORTS_W void morphologyEx( InputArray src, OutputArray dst, + int op, InputArray kernel, + Point anchor=Point(-1,-1), int iterations=1, + int borderType=BORDER_CONSTANT, + const Scalar& borderValue=morphologyDefaultBorderValue() ); + +//! interpolation algorithm +enum +{ + INTER_NEAREST=CV_INTER_NN, //!< nearest neighbor interpolation + INTER_LINEAR=CV_INTER_LINEAR, //!< bilinear interpolation + INTER_CUBIC=CV_INTER_CUBIC, //!< bicubic interpolation + INTER_AREA=CV_INTER_AREA, //!< area-based (or super) interpolation + INTER_LANCZOS4=CV_INTER_LANCZOS4, //!< Lanczos interpolation over 8x8 neighborhood + INTER_MAX=7, + WARP_INVERSE_MAP=CV_WARP_INVERSE_MAP +}; + +//! resizes the image +CV_EXPORTS_W void resize( InputArray src, OutputArray dst, + Size dsize, double fx=0, double fy=0, + int interpolation=INTER_LINEAR ); + +//! warps the image using affine transformation +CV_EXPORTS_W void warpAffine( InputArray src, OutputArray dst, + InputArray M, Size dsize, + int flags=INTER_LINEAR, + int borderMode=BORDER_CONSTANT, + const Scalar& borderValue=Scalar()); + +//! warps the image using perspective transformation +CV_EXPORTS_W void warpPerspective( InputArray src, OutputArray dst, + InputArray M, Size dsize, + int flags=INTER_LINEAR, + int borderMode=BORDER_CONSTANT, + const Scalar& borderValue=Scalar()); + +enum +{ + INTER_BITS=5, INTER_BITS2=INTER_BITS*2, + INTER_TAB_SIZE=(1< CV_EXPORTS void Ptr::delete_obj(); + +//! computes the joint dense histogram for a set of images. +CV_EXPORTS void calcHist( const Mat* images, int nimages, + const int* channels, InputArray mask, + OutputArray hist, int dims, const int* histSize, + const float** ranges, bool uniform=true, bool accumulate=false ); + +//! computes the joint sparse histogram for a set of images. +CV_EXPORTS void calcHist( const Mat* images, int nimages, + const int* channels, InputArray mask, + SparseMat& hist, int dims, + const int* histSize, const float** ranges, + bool uniform=true, bool accumulate=false ); + +CV_EXPORTS_W void calcHist( InputArrayOfArrays images, + const vector& channels, + InputArray mask, OutputArray hist, + const vector& histSize, + const vector& ranges, + bool accumulate=false ); + +//! computes back projection for the set of images +CV_EXPORTS void calcBackProject( const Mat* images, int nimages, + const int* channels, InputArray hist, + OutputArray backProject, const float** ranges, + double scale=1, bool uniform=true ); + +//! computes back projection for the set of images +CV_EXPORTS void calcBackProject( const Mat* images, int nimages, + const int* channels, const SparseMat& hist, + OutputArray backProject, const float** ranges, + double scale=1, bool uniform=true ); + +CV_EXPORTS_W void calcBackProject( InputArrayOfArrays images, const vector& channels, + InputArray hist, OutputArray dst, + const vector& ranges, + double scale ); + +/*CV_EXPORTS void calcBackProjectPatch( const Mat* images, int nimages, const int* channels, + InputArray hist, OutputArray dst, Size patchSize, + int method, double factor=1 ); + +CV_EXPORTS_W void calcBackProjectPatch( InputArrayOfArrays images, const vector& channels, + InputArray hist, OutputArray dst, Size patchSize, + int method, double factor=1 );*/ + +//! compares two histograms stored in dense arrays +CV_EXPORTS_W double compareHist( InputArray H1, InputArray H2, int method ); + +//! compares two histograms stored in sparse arrays +CV_EXPORTS double compareHist( const SparseMat& H1, const SparseMat& H2, int method ); + +//! normalizes the grayscale image brightness and contrast by normalizing its histogram +CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst ); + +CV_EXPORTS float EMD( InputArray signature1, InputArray signature2, + int distType, InputArray cost=noArray(), + float* lowerBound=0, OutputArray flow=noArray() ); + +//! segments the image using watershed algorithm +CV_EXPORTS_W void watershed( InputArray image, InputOutputArray markers ); + +//! filters image using meanshift algorithm +CV_EXPORTS_W void pyrMeanShiftFiltering( InputArray src, OutputArray dst, + double sp, double sr, int maxLevel=1, + TermCriteria termcrit=TermCriteria( + TermCriteria::MAX_ITER+TermCriteria::EPS,5,1) ); + +//! class of the pixel in GrabCut algorithm +enum +{ + GC_BGD = 0, //!< background + GC_FGD = 1, //!< foreground + GC_PR_BGD = 2, //!< most probably background + GC_PR_FGD = 3 //!< most probably foreground +}; + +//! GrabCut algorithm flags +enum +{ + GC_INIT_WITH_RECT = 0, + GC_INIT_WITH_MASK = 1, + GC_EVAL = 2 +}; + +//! segments the image using GrabCut algorithm +CV_EXPORTS_W void grabCut( InputArray img, InputOutputArray mask, Rect rect, + InputOutputArray bgdModel, InputOutputArray fgdModel, + int iterCount, int mode = GC_EVAL ); + +enum +{ + DIST_LABEL_CCOMP = 0, + DIST_LABEL_PIXEL = 1 +}; + +//! builds the discrete Voronoi diagram +CV_EXPORTS_AS(distanceTransformWithLabels) void distanceTransform( InputArray src, OutputArray dst, + OutputArray labels, int distanceType, int maskSize, + int labelType=DIST_LABEL_CCOMP ); + +//! computes the distance transform map +CV_EXPORTS_W void distanceTransform( InputArray src, OutputArray dst, + int distanceType, int maskSize ); + +enum { FLOODFILL_FIXED_RANGE = 1 << 16, FLOODFILL_MASK_ONLY = 1 << 17 }; + +//! fills the semi-uniform image region starting from the specified seed point +CV_EXPORTS int floodFill( InputOutputArray image, + Point seedPoint, Scalar newVal, CV_OUT Rect* rect=0, + Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), + int flags=4 ); + +//! fills the semi-uniform image region and/or the mask starting from the specified seed point +CV_EXPORTS_W int floodFill( InputOutputArray image, InputOutputArray mask, + Point seedPoint, Scalar newVal, CV_OUT Rect* rect=0, + Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), + int flags=4 ); + + +enum +{ + COLOR_BGR2BGRA =0, + COLOR_RGB2RGBA =COLOR_BGR2BGRA, + + COLOR_BGRA2BGR =1, + COLOR_RGBA2RGB =COLOR_BGRA2BGR, + + COLOR_BGR2RGBA =2, + COLOR_RGB2BGRA =COLOR_BGR2RGBA, + + COLOR_RGBA2BGR =3, + COLOR_BGRA2RGB =COLOR_RGBA2BGR, + + COLOR_BGR2RGB =4, + COLOR_RGB2BGR =COLOR_BGR2RGB, + + COLOR_BGRA2RGBA =5, + COLOR_RGBA2BGRA =COLOR_BGRA2RGBA, + + COLOR_BGR2GRAY =6, + COLOR_RGB2GRAY =7, + COLOR_GRAY2BGR =8, + COLOR_GRAY2RGB =COLOR_GRAY2BGR, + COLOR_GRAY2BGRA =9, + COLOR_GRAY2RGBA =COLOR_GRAY2BGRA, + COLOR_BGRA2GRAY =10, + COLOR_RGBA2GRAY =11, + + COLOR_BGR2BGR565 =12, + COLOR_RGB2BGR565 =13, + COLOR_BGR5652BGR =14, + COLOR_BGR5652RGB =15, + COLOR_BGRA2BGR565 =16, + COLOR_RGBA2BGR565 =17, + COLOR_BGR5652BGRA =18, + COLOR_BGR5652RGBA =19, + + COLOR_GRAY2BGR565 =20, + COLOR_BGR5652GRAY =21, + + COLOR_BGR2BGR555 =22, + COLOR_RGB2BGR555 =23, + COLOR_BGR5552BGR =24, + COLOR_BGR5552RGB =25, + COLOR_BGRA2BGR555 =26, + COLOR_RGBA2BGR555 =27, + COLOR_BGR5552BGRA =28, + COLOR_BGR5552RGBA =29, + + COLOR_GRAY2BGR555 =30, + COLOR_BGR5552GRAY =31, + + COLOR_BGR2XYZ =32, + COLOR_RGB2XYZ =33, + COLOR_XYZ2BGR =34, + COLOR_XYZ2RGB =35, + + COLOR_BGR2YCrCb =36, + COLOR_RGB2YCrCb =37, + COLOR_YCrCb2BGR =38, + COLOR_YCrCb2RGB =39, + + COLOR_BGR2HSV =40, + COLOR_RGB2HSV =41, + + COLOR_BGR2Lab =44, + COLOR_RGB2Lab =45, + + COLOR_BayerBG2BGR =46, + COLOR_BayerGB2BGR =47, + COLOR_BayerRG2BGR =48, + COLOR_BayerGR2BGR =49, + + COLOR_BayerBG2RGB =COLOR_BayerRG2BGR, + COLOR_BayerGB2RGB =COLOR_BayerGR2BGR, + COLOR_BayerRG2RGB =COLOR_BayerBG2BGR, + COLOR_BayerGR2RGB =COLOR_BayerGB2BGR, + + COLOR_BGR2Luv =50, + COLOR_RGB2Luv =51, + COLOR_BGR2HLS =52, + COLOR_RGB2HLS =53, + + COLOR_HSV2BGR =54, + COLOR_HSV2RGB =55, + + COLOR_Lab2BGR =56, + COLOR_Lab2RGB =57, + COLOR_Luv2BGR =58, + COLOR_Luv2RGB =59, + COLOR_HLS2BGR =60, + COLOR_HLS2RGB =61, + + COLOR_BayerBG2BGR_VNG =62, + COLOR_BayerGB2BGR_VNG =63, + COLOR_BayerRG2BGR_VNG =64, + COLOR_BayerGR2BGR_VNG =65, + + COLOR_BayerBG2RGB_VNG =COLOR_BayerRG2BGR_VNG, + COLOR_BayerGB2RGB_VNG =COLOR_BayerGR2BGR_VNG, + COLOR_BayerRG2RGB_VNG =COLOR_BayerBG2BGR_VNG, + COLOR_BayerGR2RGB_VNG =COLOR_BayerGB2BGR_VNG, + + COLOR_BGR2HSV_FULL = 66, + COLOR_RGB2HSV_FULL = 67, + COLOR_BGR2HLS_FULL = 68, + COLOR_RGB2HLS_FULL = 69, + + COLOR_HSV2BGR_FULL = 70, + COLOR_HSV2RGB_FULL = 71, + COLOR_HLS2BGR_FULL = 72, + COLOR_HLS2RGB_FULL = 73, + + COLOR_LBGR2Lab = 74, + COLOR_LRGB2Lab = 75, + COLOR_LBGR2Luv = 76, + COLOR_LRGB2Luv = 77, + + COLOR_Lab2LBGR = 78, + COLOR_Lab2LRGB = 79, + COLOR_Luv2LBGR = 80, + COLOR_Luv2LRGB = 81, + + COLOR_BGR2YUV = 82, + COLOR_RGB2YUV = 83, + COLOR_YUV2BGR = 84, + COLOR_YUV2RGB = 85, + + COLOR_BayerBG2GRAY = 86, + COLOR_BayerGB2GRAY = 87, + COLOR_BayerRG2GRAY = 88, + COLOR_BayerGR2GRAY = 89, + + //YUV 4:2:0 formats family + COLOR_YUV2RGB_NV12 = 90, + COLOR_YUV2BGR_NV12 = 91, + COLOR_YUV2RGB_NV21 = 92, + COLOR_YUV2BGR_NV21 = 93, + COLOR_YUV420sp2RGB = COLOR_YUV2RGB_NV21, + COLOR_YUV420sp2BGR = COLOR_YUV2BGR_NV21, + + COLOR_YUV2RGBA_NV12 = 94, + COLOR_YUV2BGRA_NV12 = 95, + COLOR_YUV2RGBA_NV21 = 96, + COLOR_YUV2BGRA_NV21 = 97, + COLOR_YUV420sp2RGBA = COLOR_YUV2RGBA_NV21, + COLOR_YUV420sp2BGRA = COLOR_YUV2BGRA_NV21, + + COLOR_YUV2RGB_YV12 = 98, + COLOR_YUV2BGR_YV12 = 99, + COLOR_YUV2RGB_IYUV = 100, + COLOR_YUV2BGR_IYUV = 101, + COLOR_YUV2RGB_I420 = COLOR_YUV2RGB_IYUV, + COLOR_YUV2BGR_I420 = COLOR_YUV2BGR_IYUV, + COLOR_YUV420p2RGB = COLOR_YUV2RGB_YV12, + COLOR_YUV420p2BGR = COLOR_YUV2BGR_YV12, + + COLOR_YUV2RGBA_YV12 = 102, + COLOR_YUV2BGRA_YV12 = 103, + COLOR_YUV2RGBA_IYUV = 104, + COLOR_YUV2BGRA_IYUV = 105, + COLOR_YUV2RGBA_I420 = COLOR_YUV2RGBA_IYUV, + COLOR_YUV2BGRA_I420 = COLOR_YUV2BGRA_IYUV, + COLOR_YUV420p2RGBA = COLOR_YUV2RGBA_YV12, + COLOR_YUV420p2BGRA = COLOR_YUV2BGRA_YV12, + + COLOR_YUV2GRAY_420 = 106, + COLOR_YUV2GRAY_NV21 = COLOR_YUV2GRAY_420, + COLOR_YUV2GRAY_NV12 = COLOR_YUV2GRAY_420, + COLOR_YUV2GRAY_YV12 = COLOR_YUV2GRAY_420, + COLOR_YUV2GRAY_IYUV = COLOR_YUV2GRAY_420, + COLOR_YUV2GRAY_I420 = COLOR_YUV2GRAY_420, + COLOR_YUV420sp2GRAY = COLOR_YUV2GRAY_420, + COLOR_YUV420p2GRAY = COLOR_YUV2GRAY_420, + + //YUV 4:2:2 formats family + COLOR_YUV2RGB_UYVY = 107, + COLOR_YUV2BGR_UYVY = 108, + //COLOR_YUV2RGB_VYUY = 109, + //COLOR_YUV2BGR_VYUY = 110, + COLOR_YUV2RGB_Y422 = COLOR_YUV2RGB_UYVY, + COLOR_YUV2BGR_Y422 = COLOR_YUV2BGR_UYVY, + COLOR_YUV2RGB_UYNV = COLOR_YUV2RGB_UYVY, + COLOR_YUV2BGR_UYNV = COLOR_YUV2BGR_UYVY, + + COLOR_YUV2RGBA_UYVY = 111, + COLOR_YUV2BGRA_UYVY = 112, + //COLOR_YUV2RGBA_VYUY = 113, + //COLOR_YUV2BGRA_VYUY = 114, + COLOR_YUV2RGBA_Y422 = COLOR_YUV2RGBA_UYVY, + COLOR_YUV2BGRA_Y422 = COLOR_YUV2BGRA_UYVY, + COLOR_YUV2RGBA_UYNV = COLOR_YUV2RGBA_UYVY, + COLOR_YUV2BGRA_UYNV = COLOR_YUV2BGRA_UYVY, + + COLOR_YUV2RGB_YUY2 = 115, + COLOR_YUV2BGR_YUY2 = 116, + COLOR_YUV2RGB_YVYU = 117, + COLOR_YUV2BGR_YVYU = 118, + COLOR_YUV2RGB_YUYV = COLOR_YUV2RGB_YUY2, + COLOR_YUV2BGR_YUYV = COLOR_YUV2BGR_YUY2, + COLOR_YUV2RGB_YUNV = COLOR_YUV2RGB_YUY2, + COLOR_YUV2BGR_YUNV = COLOR_YUV2BGR_YUY2, + + COLOR_YUV2RGBA_YUY2 = 119, + COLOR_YUV2BGRA_YUY2 = 120, + COLOR_YUV2RGBA_YVYU = 121, + COLOR_YUV2BGRA_YVYU = 122, + COLOR_YUV2RGBA_YUYV = COLOR_YUV2RGBA_YUY2, + COLOR_YUV2BGRA_YUYV = COLOR_YUV2BGRA_YUY2, + COLOR_YUV2RGBA_YUNV = COLOR_YUV2RGBA_YUY2, + COLOR_YUV2BGRA_YUNV = COLOR_YUV2BGRA_YUY2, + + COLOR_YUV2GRAY_UYVY = 123, + COLOR_YUV2GRAY_YUY2 = 124, + //COLOR_YUV2GRAY_VYUY = COLOR_YUV2GRAY_UYVY, + COLOR_YUV2GRAY_Y422 = COLOR_YUV2GRAY_UYVY, + COLOR_YUV2GRAY_UYNV = COLOR_YUV2GRAY_UYVY, + COLOR_YUV2GRAY_YVYU = COLOR_YUV2GRAY_YUY2, + COLOR_YUV2GRAY_YUYV = COLOR_YUV2GRAY_YUY2, + COLOR_YUV2GRAY_YUNV = COLOR_YUV2GRAY_YUY2, + + // alpha premultiplication + COLOR_RGBA2mRGBA = 125, + COLOR_mRGBA2RGBA = 126, + + COLOR_COLORCVT_MAX = 127 +}; + + +//! converts image from one color space to another +CV_EXPORTS_W void cvtColor( InputArray src, OutputArray dst, int code, int dstCn=0 ); + +//! raster image moments +class CV_EXPORTS_W_MAP Moments +{ +public: + //! the default constructor + Moments(); + //! the full constructor + Moments(double m00, double m10, double m01, double m20, double m11, + double m02, double m30, double m21, double m12, double m03 ); + //! the conversion from CvMoments + Moments( const CvMoments& moments ); + //! the conversion to CvMoments + operator CvMoments() const; + + //! spatial moments + CV_PROP_RW double m00, m10, m01, m20, m11, m02, m30, m21, m12, m03; + //! central moments + CV_PROP_RW double mu20, mu11, mu02, mu30, mu21, mu12, mu03; + //! central normalized moments + CV_PROP_RW double nu20, nu11, nu02, nu30, nu21, nu12, nu03; +}; + +//! computes moments of the rasterized shape or a vector of points +CV_EXPORTS_W Moments moments( InputArray array, bool binaryImage=false ); + +//! computes 7 Hu invariants from the moments +CV_EXPORTS void HuMoments( const Moments& moments, double hu[7] ); +CV_EXPORTS_W void HuMoments( const Moments& m, CV_OUT OutputArray hu ); + +//! type of the template matching operation +enum { TM_SQDIFF=0, TM_SQDIFF_NORMED=1, TM_CCORR=2, TM_CCORR_NORMED=3, TM_CCOEFF=4, TM_CCOEFF_NORMED=5 }; + +//! computes the proximity map for the raster template and the image where the template is searched for +CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ, + OutputArray result, int method ); + +//! mode of the contour retrieval algorithm +enum +{ + RETR_EXTERNAL=CV_RETR_EXTERNAL, //!< retrieve only the most external (top-level) contours + RETR_LIST=CV_RETR_LIST, //!< retrieve all the contours without any hierarchical information + RETR_CCOMP=CV_RETR_CCOMP, //!< retrieve the connected components (that can possibly be nested) + RETR_TREE=CV_RETR_TREE, //!< retrieve all the contours and the whole hierarchy + RETR_FLOODFILL=CV_RETR_FLOODFILL +}; + +//! the contour approximation algorithm +enum +{ + CHAIN_APPROX_NONE=CV_CHAIN_APPROX_NONE, + CHAIN_APPROX_SIMPLE=CV_CHAIN_APPROX_SIMPLE, + CHAIN_APPROX_TC89_L1=CV_CHAIN_APPROX_TC89_L1, + CHAIN_APPROX_TC89_KCOS=CV_CHAIN_APPROX_TC89_KCOS +}; + +//! retrieves contours and the hierarchical information from black-n-white image. +CV_EXPORTS_W void findContours( InputOutputArray image, OutputArrayOfArrays contours, + OutputArray hierarchy, int mode, + int method, Point offset=Point()); + +//! retrieves contours from black-n-white image. +CV_EXPORTS void findContours( InputOutputArray image, OutputArrayOfArrays contours, + int mode, int method, Point offset=Point()); + +//! approximates contour or a curve using Douglas-Peucker algorithm +CV_EXPORTS_W void approxPolyDP( InputArray curve, + OutputArray approxCurve, + double epsilon, bool closed ); + +//! computes the contour perimeter (closed=true) or a curve length +CV_EXPORTS_W double arcLength( InputArray curve, bool closed ); +//! computes the bounding rectangle for a contour +CV_EXPORTS_W Rect boundingRect( InputArray points ); +//! computes the contour area +CV_EXPORTS_W double contourArea( InputArray contour, bool oriented=false ); +//! computes the minimal rotated rectangle for a set of points +CV_EXPORTS_W RotatedRect minAreaRect( InputArray points ); +//! computes the minimal enclosing circle for a set of points +CV_EXPORTS_W void minEnclosingCircle( InputArray points, + CV_OUT Point2f& center, CV_OUT float& radius ); +//! matches two contours using one of the available algorithms +CV_EXPORTS_W double matchShapes( InputArray contour1, InputArray contour2, + int method, double parameter ); +//! computes convex hull for a set of 2D points. +CV_EXPORTS_W void convexHull( InputArray points, OutputArray hull, + bool clockwise=false, bool returnPoints=true ); +//! computes the contour convexity defects +CV_EXPORTS_W void convexityDefects( InputArray contour, InputArray convexhull, OutputArray convexityDefects ); + +//! returns true if the contour is convex. Does not support contours with self-intersection +CV_EXPORTS_W bool isContourConvex( InputArray contour ); + +//! finds intersection of two convex polygons +CV_EXPORTS_W float intersectConvexConvex( InputArray _p1, InputArray _p2, + OutputArray _p12, bool handleNested=true ); + +//! fits ellipse to the set of 2D points +CV_EXPORTS_W RotatedRect fitEllipse( InputArray points ); + +//! fits line to the set of 2D points using M-estimator algorithm +CV_EXPORTS_W void fitLine( InputArray points, OutputArray line, int distType, + double param, double reps, double aeps ); +//! checks if the point is inside the contour. Optionally computes the signed distance from the point to the contour boundary +CV_EXPORTS_W double pointPolygonTest( InputArray contour, Point2f pt, bool measureDist ); + + +class CV_EXPORTS_W Subdiv2D +{ +public: + enum + { + PTLOC_ERROR = -2, + PTLOC_OUTSIDE_RECT = -1, + PTLOC_INSIDE = 0, + PTLOC_VERTEX = 1, + PTLOC_ON_EDGE = 2 + }; + + enum + { + NEXT_AROUND_ORG = 0x00, + NEXT_AROUND_DST = 0x22, + PREV_AROUND_ORG = 0x11, + PREV_AROUND_DST = 0x33, + NEXT_AROUND_LEFT = 0x13, + NEXT_AROUND_RIGHT = 0x31, + PREV_AROUND_LEFT = 0x20, + PREV_AROUND_RIGHT = 0x02 + }; + + CV_WRAP Subdiv2D(); + CV_WRAP Subdiv2D(Rect rect); + CV_WRAP void initDelaunay(Rect rect); + + CV_WRAP int insert(Point2f pt); + CV_WRAP void insert(const vector& ptvec); + CV_WRAP int locate(Point2f pt, CV_OUT int& edge, CV_OUT int& vertex); + + CV_WRAP int findNearest(Point2f pt, CV_OUT Point2f* nearestPt=0); + CV_WRAP void getEdgeList(CV_OUT vector& edgeList) const; + CV_WRAP void getTriangleList(CV_OUT vector& triangleList) const; + CV_WRAP void getVoronoiFacetList(const vector& idx, CV_OUT vector >& facetList, + CV_OUT vector& facetCenters); + + CV_WRAP Point2f getVertex(int vertex, CV_OUT int* firstEdge=0) const; + + CV_WRAP int getEdge( int edge, int nextEdgeType ) const; + CV_WRAP int nextEdge(int edge) const; + CV_WRAP int rotateEdge(int edge, int rotate) const; + CV_WRAP int symEdge(int edge) const; + CV_WRAP int edgeOrg(int edge, CV_OUT Point2f* orgpt=0) const; + CV_WRAP int edgeDst(int edge, CV_OUT Point2f* dstpt=0) const; + +protected: + int newEdge(); + void deleteEdge(int edge); + int newPoint(Point2f pt, bool isvirtual, int firstEdge=0); + void deletePoint(int vtx); + void setEdgePoints( int edge, int orgPt, int dstPt ); + void splice( int edgeA, int edgeB ); + int connectEdges( int edgeA, int edgeB ); + void swapEdges( int edge ); + int isRightOf(Point2f pt, int edge) const; + void calcVoronoi(); + void clearVoronoi(); + void checkSubdiv() const; + + struct CV_EXPORTS Vertex + { + Vertex(); + Vertex(Point2f pt, bool _isvirtual, int _firstEdge=0); + bool isvirtual() const; + bool isfree() const; + int firstEdge; + int type; + Point2f pt; + }; + struct CV_EXPORTS QuadEdge + { + QuadEdge(); + QuadEdge(int edgeidx); + bool isfree() const; + int next[4]; + int pt[4]; + }; + + vector vtx; + vector qedges; + int freeQEdge; + int freePoint; + bool validGeometry; + + int recentEdge; + Point2f topLeft; + Point2f bottomRight; +}; + +} + +#endif /* __cplusplus */ + +#endif + +/* End of file. */ diff --git a/imgproc/include/opencv2/imgproc/imgproc_c.h b/imgproc/include/opencv2/imgproc/imgproc_c.h new file mode 100644 index 0000000..ec84cf8 --- /dev/null +++ b/imgproc/include/opencv2/imgproc/imgproc_c.h @@ -0,0 +1,623 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_IMGPROC_IMGPROC_C_H__ +#define __OPENCV_IMGPROC_IMGPROC_C_H__ + +#include "opencv2/core/core_c.h" +#include "opencv2/imgproc/types_c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*********************** Background statistics accumulation *****************************/ + +/* Adds image to accumulator */ +CVAPI(void) cvAcc( const CvArr* image, CvArr* sum, + const CvArr* mask CV_DEFAULT(NULL) ); + +/* Adds squared image to accumulator */ +CVAPI(void) cvSquareAcc( const CvArr* image, CvArr* sqsum, + const CvArr* mask CV_DEFAULT(NULL) ); + +/* Adds a product of two images to accumulator */ +CVAPI(void) cvMultiplyAcc( const CvArr* image1, const CvArr* image2, CvArr* acc, + const CvArr* mask CV_DEFAULT(NULL) ); + +/* Adds image to accumulator with weights: acc = acc*(1-alpha) + image*alpha */ +CVAPI(void) cvRunningAvg( const CvArr* image, CvArr* acc, double alpha, + const CvArr* mask CV_DEFAULT(NULL) ); + +/****************************************************************************************\ +* Image Processing * +\****************************************************************************************/ + +/* Copies source 2D array inside of the larger destination array and + makes a border of the specified type (IPL_BORDER_*) around the copied area. */ +CVAPI(void) cvCopyMakeBorder( const CvArr* src, CvArr* dst, CvPoint offset, + int bordertype, CvScalar value CV_DEFAULT(cvScalarAll(0))); + +/* Smoothes array (removes noise) */ +CVAPI(void) cvSmooth( const CvArr* src, CvArr* dst, + int smoothtype CV_DEFAULT(CV_GAUSSIAN), + int size1 CV_DEFAULT(3), + int size2 CV_DEFAULT(0), + double sigma1 CV_DEFAULT(0), + double sigma2 CV_DEFAULT(0)); + +/* Convolves the image with the kernel */ +CVAPI(void) cvFilter2D( const CvArr* src, CvArr* dst, const CvMat* kernel, + CvPoint anchor CV_DEFAULT(cvPoint(-1,-1))); + +/* Finds integral image: SUM(X,Y) = sum(x. + After that sum of histogram bins is equal to */ +CVAPI(void) cvNormalizeHist( CvHistogram* hist, double factor ); + + +/* Clear all histogram bins that are below the threshold */ +CVAPI(void) cvThreshHist( CvHistogram* hist, double threshold ); + + +/* Compares two histogram */ +CVAPI(double) cvCompareHist( const CvHistogram* hist1, + const CvHistogram* hist2, + int method); + +/* Copies one histogram to another. Destination histogram is created if + the destination pointer is NULL */ +CVAPI(void) cvCopyHist( const CvHistogram* src, CvHistogram** dst ); + + +/* Calculates bayesian probabilistic histograms + (each or src and dst is an array of histograms */ +CVAPI(void) cvCalcBayesianProb( CvHistogram** src, int number, + CvHistogram** dst); + +/* Calculates array histogram */ +CVAPI(void) cvCalcArrHist( CvArr** arr, CvHistogram* hist, + int accumulate CV_DEFAULT(0), + const CvArr* mask CV_DEFAULT(NULL) ); + +CV_INLINE void cvCalcHist( IplImage** image, CvHistogram* hist, + int accumulate CV_DEFAULT(0), + const CvArr* mask CV_DEFAULT(NULL) ) +{ + cvCalcArrHist( (CvArr**)image, hist, accumulate, mask ); +} + +/* Calculates back project */ +CVAPI(void) cvCalcArrBackProject( CvArr** image, CvArr* dst, + const CvHistogram* hist ); +#define cvCalcBackProject(image, dst, hist) cvCalcArrBackProject((CvArr**)image, dst, hist) + + +/* Does some sort of template matching but compares histograms of + template and each window location */ +CVAPI(void) cvCalcArrBackProjectPatch( CvArr** image, CvArr* dst, CvSize range, + CvHistogram* hist, int method, + double factor ); +#define cvCalcBackProjectPatch( image, dst, range, hist, method, factor ) \ + cvCalcArrBackProjectPatch( (CvArr**)image, dst, range, hist, method, factor ) + + +/* calculates probabilistic density (divides one histogram by another) */ +CVAPI(void) cvCalcProbDensity( const CvHistogram* hist1, const CvHistogram* hist2, + CvHistogram* dst_hist, double scale CV_DEFAULT(255) ); + +/* equalizes histogram of 8-bit single-channel image */ +CVAPI(void) cvEqualizeHist( const CvArr* src, CvArr* dst ); + + +/* Applies distance transform to binary image */ +CVAPI(void) cvDistTransform( const CvArr* src, CvArr* dst, + int distance_type CV_DEFAULT(CV_DIST_L2), + int mask_size CV_DEFAULT(3), + const float* mask CV_DEFAULT(NULL), + CvArr* labels CV_DEFAULT(NULL), + int labelType CV_DEFAULT(CV_DIST_LABEL_CCOMP)); + + +/* Applies fixed-level threshold to grayscale image. + This is a basic operation applied before retrieving contours */ +CVAPI(double) cvThreshold( const CvArr* src, CvArr* dst, + double threshold, double max_value, + int threshold_type ); + +/* Applies adaptive threshold to grayscale image. + The two parameters for methods CV_ADAPTIVE_THRESH_MEAN_C and + CV_ADAPTIVE_THRESH_GAUSSIAN_C are: + neighborhood size (3, 5, 7 etc.), + and a constant subtracted from mean (...,-3,-2,-1,0,1,2,3,...) */ +CVAPI(void) cvAdaptiveThreshold( const CvArr* src, CvArr* dst, double max_value, + int adaptive_method CV_DEFAULT(CV_ADAPTIVE_THRESH_MEAN_C), + int threshold_type CV_DEFAULT(CV_THRESH_BINARY), + int block_size CV_DEFAULT(3), + double param1 CV_DEFAULT(5)); + +/* Fills the connected component until the color difference gets large enough */ +CVAPI(void) cvFloodFill( CvArr* image, CvPoint seed_point, + CvScalar new_val, CvScalar lo_diff CV_DEFAULT(cvScalarAll(0)), + CvScalar up_diff CV_DEFAULT(cvScalarAll(0)), + CvConnectedComp* comp CV_DEFAULT(NULL), + int flags CV_DEFAULT(4), + CvArr* mask CV_DEFAULT(NULL)); + +/****************************************************************************************\ +* Feature detection * +\****************************************************************************************/ + +/* Runs canny edge detector */ +CVAPI(void) cvCanny( const CvArr* image, CvArr* edges, double threshold1, + double threshold2, int aperture_size CV_DEFAULT(3) ); + +/* Calculates constraint image for corner detection + Dx^2 * Dyy + Dxx * Dy^2 - 2 * Dx * Dy * Dxy. + Applying threshold to the result gives coordinates of corners */ +CVAPI(void) cvPreCornerDetect( const CvArr* image, CvArr* corners, + int aperture_size CV_DEFAULT(3) ); + +/* Calculates eigen values and vectors of 2x2 + gradient covariation matrix at every image pixel */ +CVAPI(void) cvCornerEigenValsAndVecs( const CvArr* image, CvArr* eigenvv, + int block_size, int aperture_size CV_DEFAULT(3) ); + +/* Calculates minimal eigenvalue for 2x2 gradient covariation matrix at + every image pixel */ +CVAPI(void) cvCornerMinEigenVal( const CvArr* image, CvArr* eigenval, + int block_size, int aperture_size CV_DEFAULT(3) ); + +/* Harris corner detector: + Calculates det(M) - k*(trace(M)^2), where M is 2x2 gradient covariation matrix for each pixel */ +CVAPI(void) cvCornerHarris( const CvArr* image, CvArr* harris_responce, + int block_size, int aperture_size CV_DEFAULT(3), + double k CV_DEFAULT(0.04) ); + +/* Adjust corner position using some sort of gradient search */ +CVAPI(void) cvFindCornerSubPix( const CvArr* image, CvPoint2D32f* corners, + int count, CvSize win, CvSize zero_zone, + CvTermCriteria criteria ); + +/* Finds a sparse set of points within the selected region + that seem to be easy to track */ +CVAPI(void) cvGoodFeaturesToTrack( const CvArr* image, CvArr* eig_image, + CvArr* temp_image, CvPoint2D32f* corners, + int* corner_count, double quality_level, + double min_distance, + const CvArr* mask CV_DEFAULT(NULL), + int block_size CV_DEFAULT(3), + int use_harris CV_DEFAULT(0), + double k CV_DEFAULT(0.04) ); + +/* Finds lines on binary image using one of several methods. + line_storage is either memory storage or 1 x CvMat, its + number of columns is changed by the function. + method is one of CV_HOUGH_*; + rho, theta and threshold are used for each of those methods; + param1 ~ line length, param2 ~ line gap - for probabilistic, + param1 ~ srn, param2 ~ stn - for multi-scale */ +CVAPI(CvSeq*) cvHoughLines2( CvArr* image, void* line_storage, int method, + double rho, double theta, int threshold, + double param1 CV_DEFAULT(0), double param2 CV_DEFAULT(0)); + +/* Finds circles in the image */ +CVAPI(CvSeq*) cvHoughCircles( CvArr* image, void* circle_storage, + int method, double dp, double min_dist, + double param1 CV_DEFAULT(100), + double param2 CV_DEFAULT(100), + int min_radius CV_DEFAULT(0), + int max_radius CV_DEFAULT(0)); + +/* Fits a line into set of 2d or 3d points in a robust way (M-estimator technique) */ +CVAPI(void) cvFitLine( const CvArr* points, int dist_type, double param, + double reps, double aeps, float* line ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/imgproc/include/opencv2/imgproc/types_c.h b/imgproc/include/opencv2/imgproc/types_c.h new file mode 100644 index 0000000..4154eb1 --- /dev/null +++ b/imgproc/include/opencv2/imgproc/types_c.h @@ -0,0 +1,553 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_IMGPROC_TYPES_C_H__ +#define __OPENCV_IMGPROC_TYPES_C_H__ + +#include "opencv2/core/core_c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Connected component structure */ +typedef struct CvConnectedComp +{ + double area; /* area of the connected component */ + CvScalar value; /* average color of the connected component */ + CvRect rect; /* ROI of the component */ + CvSeq* contour; /* optional component boundary + (the contour might have child contours corresponding to the holes)*/ +} +CvConnectedComp; + +/* Image smooth methods */ +enum +{ + CV_BLUR_NO_SCALE =0, + CV_BLUR =1, + CV_GAUSSIAN =2, + CV_MEDIAN =3, + CV_BILATERAL =4 +}; + +/* Filters used in pyramid decomposition */ +enum +{ + CV_GAUSSIAN_5x5 = 7 +}; + +/* Special filters */ +enum +{ + CV_SCHARR =-1, + CV_MAX_SOBEL_KSIZE =7 +}; + +/* Constants for color conversion */ +enum +{ + CV_BGR2BGRA =0, + CV_RGB2RGBA =CV_BGR2BGRA, + + CV_BGRA2BGR =1, + CV_RGBA2RGB =CV_BGRA2BGR, + + CV_BGR2RGBA =2, + CV_RGB2BGRA =CV_BGR2RGBA, + + CV_RGBA2BGR =3, + CV_BGRA2RGB =CV_RGBA2BGR, + + CV_BGR2RGB =4, + CV_RGB2BGR =CV_BGR2RGB, + + CV_BGRA2RGBA =5, + CV_RGBA2BGRA =CV_BGRA2RGBA, + + CV_BGR2GRAY =6, + CV_RGB2GRAY =7, + CV_GRAY2BGR =8, + CV_GRAY2RGB =CV_GRAY2BGR, + CV_GRAY2BGRA =9, + CV_GRAY2RGBA =CV_GRAY2BGRA, + CV_BGRA2GRAY =10, + CV_RGBA2GRAY =11, + + CV_BGR2BGR565 =12, + CV_RGB2BGR565 =13, + CV_BGR5652BGR =14, + CV_BGR5652RGB =15, + CV_BGRA2BGR565 =16, + CV_RGBA2BGR565 =17, + CV_BGR5652BGRA =18, + CV_BGR5652RGBA =19, + + CV_GRAY2BGR565 =20, + CV_BGR5652GRAY =21, + + CV_BGR2BGR555 =22, + CV_RGB2BGR555 =23, + CV_BGR5552BGR =24, + CV_BGR5552RGB =25, + CV_BGRA2BGR555 =26, + CV_RGBA2BGR555 =27, + CV_BGR5552BGRA =28, + CV_BGR5552RGBA =29, + + CV_GRAY2BGR555 =30, + CV_BGR5552GRAY =31, + + CV_BGR2XYZ =32, + CV_RGB2XYZ =33, + CV_XYZ2BGR =34, + CV_XYZ2RGB =35, + + CV_BGR2YCrCb =36, + CV_RGB2YCrCb =37, + CV_YCrCb2BGR =38, + CV_YCrCb2RGB =39, + + CV_BGR2HSV =40, + CV_RGB2HSV =41, + + CV_BGR2Lab =44, + CV_RGB2Lab =45, + + CV_BayerBG2BGR =46, + CV_BayerGB2BGR =47, + CV_BayerRG2BGR =48, + CV_BayerGR2BGR =49, + + CV_BayerBG2RGB =CV_BayerRG2BGR, + CV_BayerGB2RGB =CV_BayerGR2BGR, + CV_BayerRG2RGB =CV_BayerBG2BGR, + CV_BayerGR2RGB =CV_BayerGB2BGR, + + CV_BGR2Luv =50, + CV_RGB2Luv =51, + CV_BGR2HLS =52, + CV_RGB2HLS =53, + + CV_HSV2BGR =54, + CV_HSV2RGB =55, + + CV_Lab2BGR =56, + CV_Lab2RGB =57, + CV_Luv2BGR =58, + CV_Luv2RGB =59, + CV_HLS2BGR =60, + CV_HLS2RGB =61, + + CV_BayerBG2BGR_VNG =62, + CV_BayerGB2BGR_VNG =63, + CV_BayerRG2BGR_VNG =64, + CV_BayerGR2BGR_VNG =65, + + CV_BayerBG2RGB_VNG =CV_BayerRG2BGR_VNG, + CV_BayerGB2RGB_VNG =CV_BayerGR2BGR_VNG, + CV_BayerRG2RGB_VNG =CV_BayerBG2BGR_VNG, + CV_BayerGR2RGB_VNG =CV_BayerGB2BGR_VNG, + + CV_BGR2HSV_FULL = 66, + CV_RGB2HSV_FULL = 67, + CV_BGR2HLS_FULL = 68, + CV_RGB2HLS_FULL = 69, + + CV_HSV2BGR_FULL = 70, + CV_HSV2RGB_FULL = 71, + CV_HLS2BGR_FULL = 72, + CV_HLS2RGB_FULL = 73, + + CV_LBGR2Lab = 74, + CV_LRGB2Lab = 75, + CV_LBGR2Luv = 76, + CV_LRGB2Luv = 77, + + CV_Lab2LBGR = 78, + CV_Lab2LRGB = 79, + CV_Luv2LBGR = 80, + CV_Luv2LRGB = 81, + + CV_BGR2YUV = 82, + CV_RGB2YUV = 83, + CV_YUV2BGR = 84, + CV_YUV2RGB = 85, + + CV_BayerBG2GRAY = 86, + CV_BayerGB2GRAY = 87, + CV_BayerRG2GRAY = 88, + CV_BayerGR2GRAY = 89, + + //YUV 4:2:0 formats family + CV_YUV2RGB_NV12 = 90, + CV_YUV2BGR_NV12 = 91, + CV_YUV2RGB_NV21 = 92, + CV_YUV2BGR_NV21 = 93, + CV_YUV420sp2RGB = CV_YUV2RGB_NV21, + CV_YUV420sp2BGR = CV_YUV2BGR_NV21, + + CV_YUV2RGBA_NV12 = 94, + CV_YUV2BGRA_NV12 = 95, + CV_YUV2RGBA_NV21 = 96, + CV_YUV2BGRA_NV21 = 97, + CV_YUV420sp2RGBA = CV_YUV2RGBA_NV21, + CV_YUV420sp2BGRA = CV_YUV2BGRA_NV21, + + CV_YUV2RGB_YV12 = 98, + CV_YUV2BGR_YV12 = 99, + CV_YUV2RGB_IYUV = 100, + CV_YUV2BGR_IYUV = 101, + CV_YUV2RGB_I420 = CV_YUV2RGB_IYUV, + CV_YUV2BGR_I420 = CV_YUV2BGR_IYUV, + CV_YUV420p2RGB = CV_YUV2RGB_YV12, + CV_YUV420p2BGR = CV_YUV2BGR_YV12, + + CV_YUV2RGBA_YV12 = 102, + CV_YUV2BGRA_YV12 = 103, + CV_YUV2RGBA_IYUV = 104, + CV_YUV2BGRA_IYUV = 105, + CV_YUV2RGBA_I420 = CV_YUV2RGBA_IYUV, + CV_YUV2BGRA_I420 = CV_YUV2BGRA_IYUV, + CV_YUV420p2RGBA = CV_YUV2RGBA_YV12, + CV_YUV420p2BGRA = CV_YUV2BGRA_YV12, + + CV_YUV2GRAY_420 = 106, + CV_YUV2GRAY_NV21 = CV_YUV2GRAY_420, + CV_YUV2GRAY_NV12 = CV_YUV2GRAY_420, + CV_YUV2GRAY_YV12 = CV_YUV2GRAY_420, + CV_YUV2GRAY_IYUV = CV_YUV2GRAY_420, + CV_YUV2GRAY_I420 = CV_YUV2GRAY_420, + CV_YUV420sp2GRAY = CV_YUV2GRAY_420, + CV_YUV420p2GRAY = CV_YUV2GRAY_420, + + //YUV 4:2:2 formats family + CV_YUV2RGB_UYVY = 107, + CV_YUV2BGR_UYVY = 108, + //CV_YUV2RGB_VYUY = 109, + //CV_YUV2BGR_VYUY = 110, + CV_YUV2RGB_Y422 = CV_YUV2RGB_UYVY, + CV_YUV2BGR_Y422 = CV_YUV2BGR_UYVY, + CV_YUV2RGB_UYNV = CV_YUV2RGB_UYVY, + CV_YUV2BGR_UYNV = CV_YUV2BGR_UYVY, + + CV_YUV2RGBA_UYVY = 111, + CV_YUV2BGRA_UYVY = 112, + //CV_YUV2RGBA_VYUY = 113, + //CV_YUV2BGRA_VYUY = 114, + CV_YUV2RGBA_Y422 = CV_YUV2RGBA_UYVY, + CV_YUV2BGRA_Y422 = CV_YUV2BGRA_UYVY, + CV_YUV2RGBA_UYNV = CV_YUV2RGBA_UYVY, + CV_YUV2BGRA_UYNV = CV_YUV2BGRA_UYVY, + + CV_YUV2RGB_YUY2 = 115, + CV_YUV2BGR_YUY2 = 116, + CV_YUV2RGB_YVYU = 117, + CV_YUV2BGR_YVYU = 118, + CV_YUV2RGB_YUYV = CV_YUV2RGB_YUY2, + CV_YUV2BGR_YUYV = CV_YUV2BGR_YUY2, + CV_YUV2RGB_YUNV = CV_YUV2RGB_YUY2, + CV_YUV2BGR_YUNV = CV_YUV2BGR_YUY2, + + CV_YUV2RGBA_YUY2 = 119, + CV_YUV2BGRA_YUY2 = 120, + CV_YUV2RGBA_YVYU = 121, + CV_YUV2BGRA_YVYU = 122, + CV_YUV2RGBA_YUYV = CV_YUV2RGBA_YUY2, + CV_YUV2BGRA_YUYV = CV_YUV2BGRA_YUY2, + CV_YUV2RGBA_YUNV = CV_YUV2RGBA_YUY2, + CV_YUV2BGRA_YUNV = CV_YUV2BGRA_YUY2, + + CV_YUV2GRAY_UYVY = 123, + CV_YUV2GRAY_YUY2 = 124, + //CV_YUV2GRAY_VYUY = CV_YUV2GRAY_UYVY, + CV_YUV2GRAY_Y422 = CV_YUV2GRAY_UYVY, + CV_YUV2GRAY_UYNV = CV_YUV2GRAY_UYVY, + CV_YUV2GRAY_YVYU = CV_YUV2GRAY_YUY2, + CV_YUV2GRAY_YUYV = CV_YUV2GRAY_YUY2, + CV_YUV2GRAY_YUNV = CV_YUV2GRAY_YUY2, + + // alpha premultiplication + CV_RGBA2mRGBA = 125, + CV_mRGBA2RGBA = 126, + + CV_COLORCVT_MAX = 127 +}; + + +/* Sub-pixel interpolation methods */ +enum +{ + CV_INTER_NN =0, + CV_INTER_LINEAR =1, + CV_INTER_CUBIC =2, + CV_INTER_AREA =3, + CV_INTER_LANCZOS4 =4 +}; + +/* ... and other image warping flags */ +enum +{ + CV_WARP_FILL_OUTLIERS =8, + CV_WARP_INVERSE_MAP =16 +}; + +/* Shapes of a structuring element for morphological operations */ +enum +{ + CV_SHAPE_RECT =0, + CV_SHAPE_CROSS =1, + CV_SHAPE_ELLIPSE =2, + CV_SHAPE_CUSTOM =100 +}; + +/* Morphological operations */ +enum +{ + CV_MOP_ERODE =0, + CV_MOP_DILATE =1, + CV_MOP_OPEN =2, + CV_MOP_CLOSE =3, + CV_MOP_GRADIENT =4, + CV_MOP_TOPHAT =5, + CV_MOP_BLACKHAT =6 +}; + +/* Spatial and central moments */ +typedef struct CvMoments +{ + double m00, m10, m01, m20, m11, m02, m30, m21, m12, m03; /* spatial moments */ + double mu20, mu11, mu02, mu30, mu21, mu12, mu03; /* central moments */ + double inv_sqrt_m00; /* m00 != 0 ? 1/sqrt(m00) : 0 */ +} +CvMoments; + +/* Hu invariants */ +typedef struct CvHuMoments +{ + double hu1, hu2, hu3, hu4, hu5, hu6, hu7; /* Hu invariants */ +} +CvHuMoments; + +/* Template matching methods */ +enum +{ + CV_TM_SQDIFF =0, + CV_TM_SQDIFF_NORMED =1, + CV_TM_CCORR =2, + CV_TM_CCORR_NORMED =3, + CV_TM_CCOEFF =4, + CV_TM_CCOEFF_NORMED =5 +}; + +typedef float (CV_CDECL * CvDistanceFunction)( const float* a, const float* b, void* user_param ); + +/* Contour retrieval modes */ +enum +{ + CV_RETR_EXTERNAL=0, + CV_RETR_LIST=1, + CV_RETR_CCOMP=2, + CV_RETR_TREE=3, + CV_RETR_FLOODFILL=4 +}; + +/* Contour approximation methods */ +enum +{ + CV_CHAIN_CODE=0, + CV_CHAIN_APPROX_NONE=1, + CV_CHAIN_APPROX_SIMPLE=2, + CV_CHAIN_APPROX_TC89_L1=3, + CV_CHAIN_APPROX_TC89_KCOS=4, + CV_LINK_RUNS=5 +}; + +/* +Internal structure that is used for sequental retrieving contours from the image. +It supports both hierarchical and plane variants of Suzuki algorithm. +*/ +typedef struct _CvContourScanner* CvContourScanner; + +/* Freeman chain reader state */ +typedef struct CvChainPtReader +{ + CV_SEQ_READER_FIELDS() + char code; + CvPoint pt; + schar deltas[8][2]; +} +CvChainPtReader; + +/* initializes 8-element array for fast access to 3x3 neighborhood of a pixel */ +#define CV_INIT_3X3_DELTAS( deltas, step, nch ) \ + ((deltas)[0] = (nch), (deltas)[1] = -(step) + (nch), \ + (deltas)[2] = -(step), (deltas)[3] = -(step) - (nch), \ + (deltas)[4] = -(nch), (deltas)[5] = (step) - (nch), \ + (deltas)[6] = (step), (deltas)[7] = (step) + (nch)) + + +/* Contour approximation algorithms */ +enum +{ + CV_POLY_APPROX_DP = 0 +}; + +/* Shape matching methods */ +enum +{ + CV_CONTOURS_MATCH_I1 =1, + CV_CONTOURS_MATCH_I2 =2, + CV_CONTOURS_MATCH_I3 =3 +}; + +/* Shape orientation */ +enum +{ + CV_CLOCKWISE =1, + CV_COUNTER_CLOCKWISE =2 +}; + + +/* Convexity defect */ +typedef struct CvConvexityDefect +{ + CvPoint* start; /* point of the contour where the defect begins */ + CvPoint* end; /* point of the contour where the defect ends */ + CvPoint* depth_point; /* the farthest from the convex hull point within the defect */ + float depth; /* distance between the farthest point and the convex hull */ +} CvConvexityDefect; + + +/* Histogram comparison methods */ +enum +{ + CV_COMP_CORREL =0, + CV_COMP_CHISQR =1, + CV_COMP_INTERSECT =2, + CV_COMP_BHATTACHARYYA =3, + CV_COMP_HELLINGER =CV_COMP_BHATTACHARYYA +}; + +/* Mask size for distance transform */ +enum +{ + CV_DIST_MASK_3 =3, + CV_DIST_MASK_5 =5, + CV_DIST_MASK_PRECISE =0 +}; + +/* Content of output label array: connected components or pixels */ +enum +{ + CV_DIST_LABEL_CCOMP = 0, + CV_DIST_LABEL_PIXEL = 1 +}; + +/* Distance types for Distance Transform and M-estimators */ +enum +{ + CV_DIST_USER =-1, /* User defined distance */ + CV_DIST_L1 =1, /* distance = |x1-x2| + |y1-y2| */ + CV_DIST_L2 =2, /* the simple euclidean distance */ + CV_DIST_C =3, /* distance = max(|x1-x2|,|y1-y2|) */ + CV_DIST_L12 =4, /* L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1)) */ + CV_DIST_FAIR =5, /* distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998 */ + CV_DIST_WELSCH =6, /* distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846 */ + CV_DIST_HUBER =7 /* distance = |x| threshold ? max_value : 0 */ + CV_THRESH_BINARY_INV =1, /* value = value > threshold ? 0 : max_value */ + CV_THRESH_TRUNC =2, /* value = value > threshold ? threshold : value */ + CV_THRESH_TOZERO =3, /* value = value > threshold ? value : 0 */ + CV_THRESH_TOZERO_INV =4, /* value = value > threshold ? 0 : value */ + CV_THRESH_MASK =7, + CV_THRESH_OTSU =8 /* use Otsu algorithm to choose the optimal threshold value; + combine the flag with one of the above CV_THRESH_* values */ +}; + +/* Adaptive threshold methods */ +enum +{ + CV_ADAPTIVE_THRESH_MEAN_C =0, + CV_ADAPTIVE_THRESH_GAUSSIAN_C =1 +}; + +/* FloodFill flags */ +enum +{ + CV_FLOODFILL_FIXED_RANGE =(1 << 16), + CV_FLOODFILL_MASK_ONLY =(1 << 17) +}; + + +/* Canny edge detector flags */ +enum +{ + CV_CANNY_L2_GRADIENT =(1 << 31) +}; + +/* Variants of a Hough transform */ +enum +{ + CV_HOUGH_STANDARD =0, + CV_HOUGH_PROBABILISTIC =1, + CV_HOUGH_MULTI_SCALE =2, + CV_HOUGH_GRADIENT =3 +}; + + +/* Fast search data structures */ +struct CvFeatureTree; +struct CvLSH; +struct CvLSHOperations; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/imgproc/perf/perf_bilateral.cpp b/imgproc/perf/perf_bilateral.cpp new file mode 100644 index 0000000..85cfc7d --- /dev/null +++ b/imgproc/perf/perf_bilateral.cpp @@ -0,0 +1,38 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using namespace testing; +using std::tr1::make_tuple; +using std::tr1::get; + +CV_ENUM(Mat_Type, CV_8UC1, CV_8UC3, CV_32FC1, CV_32FC3) + +typedef TestBaseWithParam< tr1::tuple > TestBilateralFilter; + +PERF_TEST_P( TestBilateralFilter, BilateralFilter, + Combine( + Values( szVGA, sz1080p ), // image size + Values( 3, 5 ), // d + ValuesIn( Mat_Type::all() ) // image type + ) +) +{ + Size sz; + int d, type; + const double sigmaColor = 1., sigmaSpace = 1.; + + sz = get<0>(GetParam()); + d = get<1>(GetParam()); + type = get<2>(GetParam()); + + Mat src(sz, type); + Mat dst(sz, type); + + declare.in(src, WARMUP_RNG).out(dst).time(20); + + TEST_CYCLE() bilateralFilter(src, dst, d, sigmaColor, sigmaSpace, BORDER_DEFAULT); + + SANITY_CHECK(dst); +} diff --git a/imgproc/perf/perf_blur.cpp b/imgproc/perf/perf_blur.cpp new file mode 100644 index 0000000..36519f3 --- /dev/null +++ b/imgproc/perf/perf_blur.cpp @@ -0,0 +1,209 @@ +#include "perf_precomp.hpp" +#include "opencv2/core/internal.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef std::tr1::tuple Size_MatType_kSize_t; +typedef perf::TestBaseWithParam Size_MatType_kSize; + +PERF_TEST_P(Size_MatType_kSize, medianBlur, + testing::Combine( + testing::Values(szODD, szQVGA, szVGA, sz720p), + testing::Values(CV_8UC1, CV_8UC4, CV_16UC1, CV_16SC1, CV_32FC1), + testing::Values(3, 5) + ) + ) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + int ksize = get<2>(GetParam()); + + Mat src(size, type); + Mat dst(size, type); + + declare.in(src, WARMUP_RNG).out(dst); + + if (CV_MAT_DEPTH(type) > CV_16S || CV_MAT_CN(type) > 1) + declare.time(15); + + TEST_CYCLE() medianBlur(src, dst, ksize); + + SANITY_CHECK(dst); +} + +CV_ENUM(BorderType3x3, BORDER_REPLICATE, BORDER_CONSTANT) +CV_ENUM(BorderType, BORDER_REPLICATE, BORDER_CONSTANT, BORDER_REFLECT, BORDER_REFLECT101) + +typedef std::tr1::tuple Size_MatType_BorderType3x3_t; +typedef perf::TestBaseWithParam Size_MatType_BorderType3x3; + +typedef std::tr1::tuple Size_MatType_BorderType_t; +typedef perf::TestBaseWithParam Size_MatType_BorderType; + +PERF_TEST_P(Size_MatType_BorderType3x3, gaussianBlur3x3, + testing::Combine( + testing::Values(szODD, szQVGA, szVGA, sz720p), + testing::Values(CV_8UC1, CV_8UC4, CV_16UC1, CV_16SC1, CV_32FC1), + testing::ValuesIn(BorderType3x3::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + BorderType3x3 btype = get<2>(GetParam()); + + Mat src(size, type); + Mat dst(size, type); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() GaussianBlur(src, dst, Size(3,3), 0, 0, btype); + +#if CV_SSE2 + SANITY_CHECK(dst, 1); +#else + SANITY_CHECK(dst); +#endif +} + +PERF_TEST_P(Size_MatType_BorderType3x3, blur3x3, + testing::Combine( + testing::Values(szODD, szQVGA, szVGA, sz720p), + testing::Values(CV_8UC1, CV_8UC4, CV_16UC1, CV_16SC1, CV_32FC1), + testing::ValuesIn(BorderType3x3::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + BorderType3x3 btype = get<2>(GetParam()); + + Mat src(size, type); + Mat dst(size, type); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() blur(src, dst, Size(3,3), Point(-1,-1), btype); + + SANITY_CHECK(dst, 1e-3); +} + +PERF_TEST_P(Size_MatType_BorderType, blur16x16, + testing::Combine( + testing::Values(szODD, szQVGA, szVGA, sz720p), + testing::Values(CV_8UC1, CV_8UC4, CV_16UC1, CV_16SC1, CV_32FC1), + testing::ValuesIn(BorderType::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + BorderType btype = get<2>(GetParam()); + + Mat src(size, type); + Mat dst(size, type); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() blur(src, dst, Size(16,16), Point(-1,-1), btype); + + SANITY_CHECK(dst, 1e-3); +} + +PERF_TEST_P(Size_MatType_BorderType3x3, box3x3, + testing::Combine( + testing::Values(szODD, szQVGA, szVGA, sz720p), + testing::Values(CV_8UC1, CV_16SC1, CV_32SC1, CV_32FC1, CV_32FC3), + testing::ValuesIn(BorderType3x3::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + BorderType3x3 btype = get<2>(GetParam()); + + Mat src(size, type); + Mat dst(size, type); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() boxFilter(src, dst, -1, Size(3,3), Point(-1,-1), false, btype); + + SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE); +} + +PERF_TEST_P(Size_MatType_BorderType3x3, box3x3_inplace, + testing::Combine( + testing::Values(szODD, szQVGA, szVGA, sz720p), + testing::Values(CV_8UC1, CV_16SC1, CV_32SC1, CV_32FC1, CV_32FC3), + testing::ValuesIn(BorderType3x3::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + BorderType3x3 btype = get<2>(GetParam()); + + Mat src(size, type); + Mat dst(size, type); + + declare.in(src, WARMUP_RNG).out(dst); + + while(next()) + { + src.copyTo(dst); + startTimer(); + boxFilter(dst, dst, -1, Size(3,3), Point(-1,-1), false, btype); + stopTimer(); + } + + SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE); +} + +PERF_TEST_P(Size_MatType_BorderType, gaussianBlur5x5, + testing::Combine( + testing::Values(szODD, szQVGA, szVGA, sz720p), + testing::Values(CV_8UC1, CV_8UC4, CV_16UC1, CV_16SC1, CV_32FC1), + testing::ValuesIn(BorderType::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + BorderType btype = get<2>(GetParam()); + + Mat src(size, type); + Mat dst(size, type); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() GaussianBlur(src, dst, Size(5,5), 0, 0, btype); + + SANITY_CHECK(dst); +} + +PERF_TEST_P(Size_MatType_BorderType, blur5x5, + testing::Combine( + testing::Values(szODD, szQVGA, szVGA, sz720p), + testing::Values(CV_8UC1, CV_8UC4, CV_16UC1, CV_16SC1, CV_32FC1, CV_32FC3), + testing::ValuesIn(BorderType::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int type = get<1>(GetParam()); + BorderType btype = get<2>(GetParam()); + + Mat src(size, type); + Mat dst(size, type); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() blur(src, dst, Size(5,5), Point(-1,-1), btype); + + SANITY_CHECK(dst, 1e-3); +} diff --git a/imgproc/perf/perf_canny.cpp b/imgproc/perf/perf_canny.cpp new file mode 100644 index 0000000..b59cfe9 --- /dev/null +++ b/imgproc/perf/perf_canny.cpp @@ -0,0 +1,37 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef std::tr1::tuple > Img_Aperture_L2_thresholds_t; +typedef perf::TestBaseWithParam Img_Aperture_L2_thresholds; + +PERF_TEST_P(Img_Aperture_L2_thresholds, canny, + testing::Combine( + testing::Values( "cv/shared/lena.jpg", "stitching/b1.jpg", "cv/detectors_descriptors_evaluation/images_datasets/leuven/img1.png" ), + testing::Values( 3, 5 ), + testing::Bool(), + testing::Values( make_tuple(50.0, 100.0), make_tuple(0.0, 50.0), make_tuple(100.0, 120.0) ) + ) + ) +{ + String filename = getDataPath(get<0>(GetParam())); + int aperture = get<1>(GetParam()); + bool useL2 = get<2>(GetParam()); + double thresh_low = get<0>(get<3>(GetParam())); + double thresh_high = get<1>(get<3>(GetParam())); + + Mat img = imread(filename, IMREAD_GRAYSCALE); + if (img.empty()) + FAIL() << "Unable to load source image " << filename; + Mat edges(img.size(), img.type()); + + declare.in(img).out(edges); + + TEST_CYCLE() Canny(img, edges, thresh_low, thresh_high, aperture, useL2); + + SANITY_CHECK(edges); +} diff --git a/imgproc/perf/perf_cornerEigenValsAndVecs.cpp b/imgproc/perf/perf_cornerEigenValsAndVecs.cpp new file mode 100644 index 0000000..0eba7b4 --- /dev/null +++ b/imgproc/perf/perf_cornerEigenValsAndVecs.cpp @@ -0,0 +1,40 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +CV_ENUM(BorderType, BORDER_REPLICATE, BORDER_CONSTANT, BORDER_REFLECT, BORDER_REFLECT_101) + +typedef std::tr1::tuple Img_BlockSize_ApertureSize_BorderType_t; +typedef perf::TestBaseWithParam Img_BlockSize_ApertureSize_BorderType; + +PERF_TEST_P(Img_BlockSize_ApertureSize_BorderType, cornerEigenValsAndVecs, + testing::Combine( + testing::Values( "stitching/a1.jpg", "cv/shared/pic5.png"), + testing::Values( 3, 5 ), + testing::Values( 3, 5 ), + testing::ValuesIn(BorderType::all()) + ) + ) +{ + String filename = getDataPath(get<0>(GetParam())); + int blockSize = get<1>(GetParam()); + int apertureSize = get<2>(GetParam()); + BorderType borderType = get<3>(GetParam()); + + Mat src = imread(filename, IMREAD_GRAYSCALE); + if (src.empty()) + FAIL() << "Unable to load source image" << filename; + + Mat dst; + + TEST_CYCLE() cornerEigenValsAndVecs(src, dst, blockSize, apertureSize, borderType); + + Mat l1; + extractChannel(dst, l1, 0); + + SANITY_CHECK(l1, 2e-5); +} \ No newline at end of file diff --git a/imgproc/perf/perf_cornerHarris.cpp b/imgproc/perf/perf_cornerHarris.cpp new file mode 100644 index 0000000..379d8b33 --- /dev/null +++ b/imgproc/perf/perf_cornerHarris.cpp @@ -0,0 +1,39 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +CV_ENUM(BorderType, BORDER_REPLICATE, BORDER_CONSTANT, BORDER_REFLECT, BORDER_REFLECT_101) + +typedef std::tr1::tuple Img_BlockSize_ApertureSize_k_BorderType_t; +typedef perf::TestBaseWithParam Img_BlockSize_ApertureSize_k_BorderType; + +PERF_TEST_P(Img_BlockSize_ApertureSize_k_BorderType, cornerHarris, + testing::Combine( + testing::Values( "stitching/a1.jpg", "cv/shared/pic5.png"), + testing::Values( 3, 5 ), + testing::Values( 3, 5 ), + testing::Values( 0.04, 0.1 ), + testing::ValuesIn(BorderType::all()) + ) + ) +{ + String filename = getDataPath(get<0>(GetParam())); + int blockSize = get<1>(GetParam()); + int apertureSize = get<2>(GetParam()); + double k = get<3>(GetParam()); + BorderType borderType = get<4>(GetParam()); + + Mat src = imread(filename, IMREAD_GRAYSCALE); + if (src.empty()) + FAIL() << "Unable to load source image" << filename; + + Mat dst; + + TEST_CYCLE() cornerHarris(src, dst, blockSize, apertureSize, k, borderType); + + SANITY_CHECK(dst, 2e-5); +} \ No newline at end of file diff --git a/imgproc/perf/perf_cvt_color.cpp b/imgproc/perf/perf_cvt_color.cpp new file mode 100644 index 0000000..42914fb --- /dev/null +++ b/imgproc/perf/perf_cvt_color.cpp @@ -0,0 +1,276 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +//extra color conversions supported implicitly +enum +{ + CX_BGRA2HLS = CV_COLORCVT_MAX + CV_BGR2HLS, + CX_BGRA2HLS_FULL = CV_COLORCVT_MAX + CV_BGR2HLS_FULL, + CX_BGRA2HSV = CV_COLORCVT_MAX + CV_BGR2HSV, + CX_BGRA2HSV_FULL = CV_COLORCVT_MAX + CV_BGR2HSV_FULL, + CX_BGRA2Lab = CV_COLORCVT_MAX + CV_BGR2Lab, + CX_BGRA2Luv = CV_COLORCVT_MAX + CV_BGR2Luv, + CX_BGRA2XYZ = CV_COLORCVT_MAX + CV_BGR2XYZ, + CX_BGRA2YCrCb = CV_COLORCVT_MAX + CV_BGR2YCrCb, + CX_BGRA2YUV = CV_COLORCVT_MAX + CV_BGR2YUV, + CX_HLS2BGRA = CV_COLORCVT_MAX + CV_HLS2BGR, + CX_HLS2BGRA_FULL = CV_COLORCVT_MAX + CV_HLS2BGR_FULL, + CX_HLS2RGBA = CV_COLORCVT_MAX + CV_HLS2RGB, + CX_HLS2RGBA_FULL = CV_COLORCVT_MAX + CV_HLS2RGB_FULL, + CX_HSV2BGRA = CV_COLORCVT_MAX + CV_HSV2BGR, + CX_HSV2BGRA_FULL = CV_COLORCVT_MAX + CV_HSV2BGR_FULL, + CX_HSV2RGBA = CV_COLORCVT_MAX + CV_HSV2RGB, + CX_HSV2RGBA_FULL = CV_COLORCVT_MAX + CV_HSV2RGB_FULL, + CX_Lab2BGRA = CV_COLORCVT_MAX + CV_Lab2BGR, + CX_Lab2LBGRA = CV_COLORCVT_MAX + CV_Lab2LBGR, + CX_Lab2LRGBA = CV_COLORCVT_MAX + CV_Lab2LRGB, + CX_Lab2RGBA = CV_COLORCVT_MAX + CV_Lab2RGB, + CX_LBGRA2Lab = CV_COLORCVT_MAX + CV_LBGR2Lab, + CX_LBGRA2Luv = CV_COLORCVT_MAX + CV_LBGR2Luv, + CX_LRGBA2Lab = CV_COLORCVT_MAX + CV_LRGB2Lab, + CX_LRGBA2Luv = CV_COLORCVT_MAX + CV_LRGB2Luv, + CX_Luv2BGRA = CV_COLORCVT_MAX + CV_Luv2BGR, + CX_Luv2LBGRA = CV_COLORCVT_MAX + CV_Luv2LBGR, + CX_Luv2LRGBA = CV_COLORCVT_MAX + CV_Luv2LRGB, + CX_Luv2RGBA = CV_COLORCVT_MAX + CV_Luv2RGB, + CX_RGBA2HLS = CV_COLORCVT_MAX + CV_RGB2HLS, + CX_RGBA2HLS_FULL = CV_COLORCVT_MAX + CV_RGB2HLS_FULL, + CX_RGBA2HSV = CV_COLORCVT_MAX + CV_RGB2HSV, + CX_RGBA2HSV_FULL = CV_COLORCVT_MAX + CV_RGB2HSV_FULL, + CX_RGBA2Lab = CV_COLORCVT_MAX + CV_RGB2Lab, + CX_RGBA2Luv = CV_COLORCVT_MAX + CV_RGB2Luv, + CX_RGBA2XYZ = CV_COLORCVT_MAX + CV_RGB2XYZ, + CX_RGBA2YCrCb = CV_COLORCVT_MAX + CV_RGB2YCrCb, + CX_RGBA2YUV = CV_COLORCVT_MAX + CV_RGB2YUV, + CX_XYZ2BGRA = CV_COLORCVT_MAX + CV_XYZ2BGR, + CX_XYZ2RGBA = CV_COLORCVT_MAX + CV_XYZ2RGB, + CX_YCrCb2BGRA = CV_COLORCVT_MAX + CV_YCrCb2BGR, + CX_YCrCb2RGBA = CV_COLORCVT_MAX + CV_YCrCb2RGB, + CX_YUV2BGRA = CV_COLORCVT_MAX + CV_YUV2BGR, + CX_YUV2RGBA = CV_COLORCVT_MAX + CV_YUV2RGB +}; + +CV_ENUM(CvtMode, + CV_BayerBG2BGR, CV_BayerBG2BGR_VNG, CV_BayerBG2GRAY, + CV_BayerGB2BGR, CV_BayerGB2BGR_VNG, CV_BayerGB2GRAY, + CV_BayerGR2BGR, CV_BayerGR2BGR_VNG, CV_BayerGR2GRAY, + CV_BayerRG2BGR, CV_BayerRG2BGR_VNG, CV_BayerRG2GRAY, + + CV_BGR2BGR555, CV_BGR2BGR565, CV_BGR2BGRA, CV_BGR2GRAY, + CV_BGR2HLS, CV_BGR2HLS_FULL, CV_BGR2HSV, CV_BGR2HSV_FULL, + CV_BGR2Lab, CV_BGR2Luv, CV_BGR2RGB, CV_BGR2RGBA, CV_BGR2XYZ, + CV_BGR2YCrCb, CV_BGR2YUV, CV_BGR5552BGR, CV_BGR5552BGRA, + + CV_BGR5552GRAY, CV_BGR5552RGB, CV_BGR5552RGBA, CV_BGR5652BGR, + CV_BGR5652BGRA, CV_BGR5652GRAY, CV_BGR5652RGB, CV_BGR5652RGBA, + + CV_BGRA2BGR, CV_BGRA2BGR555, CV_BGRA2BGR565, CV_BGRA2GRAY, CV_BGRA2RGBA, + CX_BGRA2HLS, CX_BGRA2HLS_FULL, CX_BGRA2HSV, CX_BGRA2HSV_FULL, + CX_BGRA2Lab, CX_BGRA2Luv, CX_BGRA2XYZ, + CX_BGRA2YCrCb, CX_BGRA2YUV, + + CV_GRAY2BGR, CV_GRAY2BGR555, CV_GRAY2BGR565, CV_GRAY2BGRA, + + CV_HLS2BGR, CV_HLS2BGR_FULL, CV_HLS2RGB, CV_HLS2RGB_FULL, + CX_HLS2BGRA, CX_HLS2BGRA_FULL, CX_HLS2RGBA, CX_HLS2RGBA_FULL, + + CV_HSV2BGR, CV_HSV2BGR_FULL, CV_HSV2RGB, CV_HSV2RGB_FULL, + CX_HSV2BGRA, CX_HSV2BGRA_FULL, CX_HSV2RGBA, CX_HSV2RGBA_FULL, + + CV_Lab2BGR, CV_Lab2LBGR, CV_Lab2LRGB, CV_Lab2RGB, + CX_Lab2BGRA, CX_Lab2LBGRA, CX_Lab2LRGBA, CX_Lab2RGBA, + + CV_LBGR2Lab, CV_LBGR2Luv, CV_LRGB2Lab, CV_LRGB2Luv, + CX_LBGRA2Lab, CX_LBGRA2Luv, CX_LRGBA2Lab, CX_LRGBA2Luv, + + CV_Luv2BGR, CV_Luv2LBGR, CV_Luv2LRGB, CV_Luv2RGB, + CX_Luv2BGRA, CX_Luv2LBGRA, CX_Luv2LRGBA, CX_Luv2RGBA, + + CV_RGB2BGR555, CV_RGB2BGR565, CV_RGB2GRAY, + CV_RGB2HLS, CV_RGB2HLS_FULL, CV_RGB2HSV, CV_RGB2HSV_FULL, + CV_RGB2Lab, CV_RGB2Luv, CV_RGB2XYZ, CV_RGB2YCrCb, CV_RGB2YUV, + + CV_RGBA2BGR, CV_RGBA2BGR555, CV_RGBA2BGR565, CV_RGBA2GRAY, + CX_RGBA2HLS, CX_RGBA2HLS_FULL, CX_RGBA2HSV, CX_RGBA2HSV_FULL, + CX_RGBA2Lab, CX_RGBA2Luv, CX_RGBA2XYZ, + CX_RGBA2YCrCb, CX_RGBA2YUV, + + CV_XYZ2BGR, CV_XYZ2RGB, CX_XYZ2BGRA, CX_XYZ2RGBA, + + CV_YCrCb2BGR, CV_YCrCb2RGB, CX_YCrCb2BGRA, CX_YCrCb2RGBA, + CV_YUV2BGR, CV_YUV2RGB, CX_YUV2BGRA, CX_YUV2RGBA + ) + +CV_ENUM(CvtMode2, CV_YUV2BGR_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGB_NV12, CV_YUV2RGBA_NV12, CV_YUV2BGR_NV21, CV_YUV2BGRA_NV21, CV_YUV2RGB_NV21, CV_YUV2RGBA_NV21, + CV_YUV2BGR_YV12, CV_YUV2BGRA_YV12, CV_YUV2RGB_YV12, CV_YUV2RGBA_YV12, CV_YUV2BGR_IYUV, CV_YUV2BGRA_IYUV, CV_YUV2RGB_IYUV, CV_YUV2RGBA_IYUV, + COLOR_YUV2GRAY_420, CV_YUV2RGB_UYVY, CV_YUV2BGR_UYVY, CV_YUV2RGBA_UYVY, CV_YUV2BGRA_UYVY, CV_YUV2RGB_YUY2, CV_YUV2BGR_YUY2, CV_YUV2RGB_YVYU, + CV_YUV2BGR_YVYU, CV_YUV2RGBA_YUY2, CV_YUV2BGRA_YUY2, CV_YUV2RGBA_YVYU, CV_YUV2BGRA_YVYU) + +struct ChPair +{ + ChPair(int _scn, int _dcn): scn(_scn), dcn(_dcn) {} + int scn, dcn; +}; + +ChPair getConversionInfo(int cvtMode) +{ + switch(cvtMode) + { + case CV_BayerBG2GRAY: case CV_BayerGB2GRAY: + case CV_BayerGR2GRAY: case CV_BayerRG2GRAY: + case CV_YUV2GRAY_420: + return ChPair(1,1); + case CV_GRAY2BGR555: case CV_GRAY2BGR565: + return ChPair(1,2); + case CV_BayerBG2BGR: case CV_BayerBG2BGR_VNG: + case CV_BayerGB2BGR: case CV_BayerGB2BGR_VNG: + case CV_BayerGR2BGR: case CV_BayerGR2BGR_VNG: + case CV_BayerRG2BGR: case CV_BayerRG2BGR_VNG: + case CV_GRAY2BGR: + case CV_YUV2BGR_NV12: case CV_YUV2RGB_NV12: + case CV_YUV2BGR_NV21: case CV_YUV2RGB_NV21: + case CV_YUV2BGR_YV12: case CV_YUV2RGB_YV12: + case CV_YUV2BGR_IYUV: case CV_YUV2RGB_IYUV: + return ChPair(1,3); + case CV_GRAY2BGRA: + case CV_YUV2BGRA_NV12: case CV_YUV2RGBA_NV12: + case CV_YUV2BGRA_NV21: case CV_YUV2RGBA_NV21: + case CV_YUV2BGRA_YV12: case CV_YUV2RGBA_YV12: + case CV_YUV2BGRA_IYUV: case CV_YUV2RGBA_IYUV: + return ChPair(1,4); + case CV_BGR5552GRAY: case CV_BGR5652GRAY: + return ChPair(2,1); + case CV_BGR5552BGR: case CV_BGR5552RGB: + case CV_BGR5652BGR: case CV_BGR5652RGB: + case CV_YUV2RGB_UYVY: case CV_YUV2BGR_UYVY: + case CV_YUV2RGBA_UYVY: case CV_YUV2BGRA_UYVY: + case CV_YUV2RGB_YUY2: case CV_YUV2BGR_YUY2: + case CV_YUV2RGB_YVYU: case CV_YUV2BGR_YVYU: + case CV_YUV2RGBA_YUY2: case CV_YUV2BGRA_YUY2: + case CV_YUV2RGBA_YVYU: case CV_YUV2BGRA_YVYU: + return ChPair(2,3); + case CV_BGR5552BGRA: case CV_BGR5552RGBA: + case CV_BGR5652BGRA: case CV_BGR5652RGBA: + return ChPair(2,4); + case CV_BGR2GRAY: case CV_RGB2GRAY: + return ChPair(3,1); + case CV_BGR2BGR555: case CV_BGR2BGR565: + case CV_RGB2BGR555: case CV_RGB2BGR565: + return ChPair(3,2); + case CV_BGR2HLS: case CV_BGR2HLS_FULL: + case CV_BGR2HSV: case CV_BGR2HSV_FULL: + case CV_BGR2Lab: case CV_BGR2Luv: + case CV_BGR2RGB: case CV_BGR2XYZ: + case CV_BGR2YCrCb: case CV_BGR2YUV: + case CV_HLS2BGR: case CV_HLS2BGR_FULL: + case CV_HLS2RGB: case CV_HLS2RGB_FULL: + case CV_HSV2BGR: case CV_HSV2BGR_FULL: + case CV_HSV2RGB: case CV_HSV2RGB_FULL: + case CV_Lab2BGR: case CV_Lab2LBGR: + case CV_Lab2LRGB: case CV_Lab2RGB: + case CV_LBGR2Lab: case CV_LBGR2Luv: + case CV_LRGB2Lab: case CV_LRGB2Luv: + case CV_Luv2BGR: case CV_Luv2LBGR: + case CV_Luv2LRGB: case CV_Luv2RGB: + case CV_RGB2HLS: case CV_RGB2HLS_FULL: + case CV_RGB2HSV: case CV_RGB2HSV_FULL: + case CV_RGB2Lab: case CV_RGB2Luv: + case CV_RGB2XYZ: case CV_RGB2YCrCb: + case CV_RGB2YUV: case CV_XYZ2BGR: + case CV_XYZ2RGB: case CV_YCrCb2BGR: + case CV_YCrCb2RGB: case CV_YUV2BGR: + case CV_YUV2RGB: + return ChPair(3,3); + case CV_BGR2BGRA: case CV_BGR2RGBA: + case CX_HLS2BGRA: case CX_HLS2BGRA_FULL: + case CX_HLS2RGBA: case CX_HLS2RGBA_FULL: + case CX_HSV2BGRA: case CX_HSV2BGRA_FULL: + case CX_HSV2RGBA: case CX_HSV2RGBA_FULL: + case CX_Lab2BGRA: case CX_Lab2LBGRA: + case CX_Lab2LRGBA: case CX_Lab2RGBA: + case CX_Luv2BGRA: case CX_Luv2LBGRA: + case CX_Luv2LRGBA: case CX_Luv2RGBA: + case CX_XYZ2BGRA: case CX_XYZ2RGBA: + case CX_YCrCb2BGRA: case CX_YCrCb2RGBA: + case CX_YUV2BGRA: case CX_YUV2RGBA: + return ChPair(3,4); + case CV_BGRA2GRAY: case CV_RGBA2GRAY: + return ChPair(4,1); + case CV_BGRA2BGR555: case CV_BGRA2BGR565: + case CV_RGBA2BGR555: case CV_RGBA2BGR565: + return ChPair(4,2); + case CV_BGRA2BGR: case CX_BGRA2HLS: + case CX_BGRA2HLS_FULL: case CX_BGRA2HSV: + case CX_BGRA2HSV_FULL: case CX_BGRA2Lab: + case CX_BGRA2Luv: case CX_BGRA2XYZ: + case CX_BGRA2YCrCb: case CX_BGRA2YUV: + case CX_LBGRA2Lab: case CX_LBGRA2Luv: + case CX_LRGBA2Lab: case CX_LRGBA2Luv: + case CV_RGBA2BGR: case CX_RGBA2HLS: + case CX_RGBA2HLS_FULL: case CX_RGBA2HSV: + case CX_RGBA2HSV_FULL: case CX_RGBA2Lab: + case CX_RGBA2Luv: case CX_RGBA2XYZ: + case CX_RGBA2YCrCb: case CX_RGBA2YUV: + return ChPair(4,3); + case CV_BGRA2RGBA: + return ChPair(4,4); + default: + ADD_FAILURE() << "Unknown conversion type"; + break; + }; + return ChPair(0,0); +} + +typedef std::tr1::tuple Size_CvtMode_t; +typedef perf::TestBaseWithParam Size_CvtMode; + +PERF_TEST_P(Size_CvtMode, cvtColor8u, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::ValuesIn(CvtMode::all()) + ) + ) +{ + Size sz = get<0>(GetParam()); + int mode = get<1>(GetParam()); + ChPair ch = getConversionInfo(mode); + mode %= CV_COLORCVT_MAX; + + Mat src(sz, CV_8UC(ch.scn)); + Mat dst(sz, CV_8UC(ch.dcn)); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() cvtColor(src, dst, mode, ch.dcn); + + SANITY_CHECK(dst, 1); +} + +typedef std::tr1::tuple Size_CvtMode2_t; +typedef perf::TestBaseWithParam Size_CvtMode2; + +PERF_TEST_P(Size_CvtMode2, cvtColorYUV420, + testing::Combine( + testing::Values(szVGA, sz720p, sz1080p, Size(130, 60)), + testing::ValuesIn(CvtMode2::all()) + ) + ) +{ + Size sz = get<0>(GetParam()); + int mode = get<1>(GetParam()); + ChPair ch = getConversionInfo(mode); + + Mat src(sz.height + sz.height / 2, sz.width, CV_8UC(ch.scn)); + Mat dst(sz, CV_8UC(ch.dcn)); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() cvtColor(src, dst, mode, ch.dcn); + + SANITY_CHECK(dst, 1); +} diff --git a/imgproc/perf/perf_distanceTransform.cpp b/imgproc/perf/perf_distanceTransform.cpp new file mode 100644 index 0000000..c1deb93 --- /dev/null +++ b/imgproc/perf/perf_distanceTransform.cpp @@ -0,0 +1,23 @@ +/*#include "perf_precomp.hpp" +#include "distransform.cpp" + +using namespace std; +using namespace cv; +using namespace perf; + +typedef perf::TestBaseWithParam Size_DistanceTransform; + +PERF_TEST_P(Size_DistanceTransform, icvTrueDistTrans, testing::Values(TYPICAL_MAT_SIZES)) +{ + Size size = GetParam(); + Mat src(size, CV_8UC1); + Mat dst(size, CV_32FC1); + CvMat srcStub = src; + CvMat dstStub = dst; + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() icvTrueDistTrans(&srcStub, &dstStub); + + SANITY_CHECK(dst, 1); +}*/ diff --git a/imgproc/perf/perf_filter2d.cpp b/imgproc/perf/perf_filter2d.cpp new file mode 100644 index 0000000..f012096 --- /dev/null +++ b/imgproc/perf/perf_filter2d.cpp @@ -0,0 +1,45 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using namespace testing; +using std::tr1::make_tuple; +using std::tr1::get; + + +CV_ENUM(BorderMode, BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT_101); + +typedef TestBaseWithParam< tr1::tuple > TestFilter2d; + + +PERF_TEST_P( TestFilter2d, Filter2d, + Combine( + Values( Size(320, 240), szVGA, sz720p, sz1080p ), + Values( 3, 5 ), + ValuesIn( BorderMode::all() ) + ) +) +{ + Size sz; + int borderMode, kSize; + sz = get<0>(GetParam()); + kSize = get<1>(GetParam()); + borderMode = get<2>(GetParam()); + + Mat src(sz, CV_8UC4); + Mat dst(sz, CV_8UC4); + + Mat kernel(kSize, kSize, CV_32FC1); + randu(kernel, -3, 10); + double s = fabs( sum(kernel)[0] ); + if(s > 1e-3) kernel /= s; + + declare.in(src, WARMUP_RNG).out(dst).time(20); + + TEST_CYCLE() filter2D(src, dst, CV_8UC4, kernel, Point(1, 1), 0., borderMode); + + SANITY_CHECK(dst); +} + + diff --git a/imgproc/perf/perf_goodFeaturesToTrack.cpp b/imgproc/perf/perf_goodFeaturesToTrack.cpp new file mode 100644 index 0000000..58c2332 --- /dev/null +++ b/imgproc/perf/perf_goodFeaturesToTrack.cpp @@ -0,0 +1,38 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef std::tr1::tuple Image_MaxCorners_QualityLevel_MinDistance_BlockSize_UseHarris_t; +typedef perf::TestBaseWithParam Image_MaxCorners_QualityLevel_MinDistance_BlockSize_UseHarris; + +PERF_TEST_P(Image_MaxCorners_QualityLevel_MinDistance_BlockSize_UseHarris, goodFeaturesToTrack, + testing::Combine( + testing::Values( "stitching/a1.jpg", "cv/shared/pic5.png"), + testing::Values( 100, 500 ), + testing::Values( 0.1, 0.01 ), + testing::Values( 3, 5 ), + testing::Bool() + ) + ) +{ + String filename = getDataPath(get<0>(GetParam())); + int maxCorners = get<1>(GetParam()); + double qualityLevel = get<2>(GetParam()); + int blockSize = get<3>(GetParam()); + bool useHarrisDetector = get<4>(GetParam()); + + Mat image = imread(filename, IMREAD_GRAYSCALE); + if (image.empty()) + FAIL() << "Unable to load source image" << filename; + + std::vector corners; + + double minDistance = 1; + TEST_CYCLE() goodFeaturesToTrack(image, corners, maxCorners, qualityLevel, minDistance, noArray(), blockSize, useHarrisDetector); + + //SANITY_CHECK(corners); +} diff --git a/imgproc/perf/perf_histogram.cpp b/imgproc/perf/perf_histogram.cpp new file mode 100644 index 0000000..2cb7ee5 --- /dev/null +++ b/imgproc/perf/perf_histogram.cpp @@ -0,0 +1,58 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using namespace testing; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef tr1::tuple Size_Source_t; +typedef TestBaseWithParam Size_Source; + +typedef TestBaseWithParam MatSize; + + +PERF_TEST_P(Size_Source, calcHist, + testing::Combine(testing::Values(TYPICAL_MAT_SIZES), + testing::Values(CV_8U, CV_32F) + ) + ) +{ + Size size = get<0>(GetParam()); + MatType type = get<1>(GetParam()); + Mat source(size.height, size.width, type); + Mat hist; + int channels [] = {0}; + int histSize [] = {256}; + int dims = 1; + int numberOfImages = 1; + + const float r[] = {0.0f, 256.0f}; + const float* ranges[] = {r}; + + declare.in(source, WARMUP_RNG).time(20).iterations(1000); + TEST_CYCLE() + { + calcHist(&source, numberOfImages, channels, Mat(), hist, dims, histSize, ranges); + } + + SANITY_CHECK(hist); +} + +PERF_TEST_P(MatSize, equalizeHist, + testing::Values(TYPICAL_MAT_SIZES) + ) +{ + Size size = GetParam(); + Mat source(size.height, size.width, CV_8U); + Mat destination; + declare.in(source, WARMUP_RNG); + + TEST_CYCLE() + { + equalizeHist(source, destination); + } + + SANITY_CHECK(destination); +} diff --git a/imgproc/perf/perf_houghLines.cpp b/imgproc/perf/perf_houghLines.cpp new file mode 100644 index 0000000..6e4179e --- /dev/null +++ b/imgproc/perf/perf_houghLines.cpp @@ -0,0 +1,40 @@ +#include "perf_precomp.hpp" + +#include "cmath" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef std::tr1::tuple Image_RhoStep_ThetaStep_Threshold_t; +typedef perf::TestBaseWithParam Image_RhoStep_ThetaStep_Threshold; + +PERF_TEST_P(Image_RhoStep_ThetaStep_Threshold, HoughLines, + testing::Combine( + testing::Values( "cv/shared/pic5.png", "stitching/a1.jpg" ), + testing::Values( 1, 10 ), + testing::Values( 0.01, 0.1 ), + testing::Values( 300, 500 ) + ) + ) +{ + String filename = getDataPath(get<0>(GetParam())); + double rhoStep = get<1>(GetParam()); + double thetaStep = get<2>(GetParam()); + int threshold = get<3>(GetParam()); + + Mat image = imread(filename, IMREAD_GRAYSCALE); + if (image.empty()) + FAIL() << "Unable to load source image" << filename; + + Canny(image, image, 0, 0); + + Mat lines; + declare.time(7); + + TEST_CYCLE() HoughLines(image, lines, rhoStep, thetaStep, threshold); + + SANITY_CHECK(lines); +} \ No newline at end of file diff --git a/imgproc/perf/perf_integral.cpp b/imgproc/perf/perf_integral.cpp new file mode 100644 index 0000000..c82f885 --- /dev/null +++ b/imgproc/perf/perf_integral.cpp @@ -0,0 +1,82 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef std::tr1::tuple Size_MatType_OutMatDepth_t; +typedef perf::TestBaseWithParam Size_MatType_OutMatDepth; + +PERF_TEST_P(Size_MatType_OutMatDepth, integral, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(CV_8UC1, CV_8UC4), + testing::Values(CV_32S, CV_32F, CV_64F) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + int sdepth = get<2>(GetParam()); + + Mat src(sz, matType); + Mat sum(sz, sdepth); + + declare.in(src, WARMUP_RNG).out(sum); + + TEST_CYCLE() integral(src, sum, sdepth); + + SANITY_CHECK(sum, 1e-6); +} + +PERF_TEST_P(Size_MatType_OutMatDepth, integral_sqsum, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(CV_8UC1, CV_8UC4), + testing::Values(CV_32S, CV_32F, CV_64F) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + int sdepth = get<2>(GetParam()); + + Mat src(sz, matType); + Mat sum(sz, sdepth); + Mat sqsum(sz, sdepth); + + declare.in(src, WARMUP_RNG).out(sum, sqsum); + + TEST_CYCLE() integral(src, sum, sqsum, sdepth); + + SANITY_CHECK(sum, 1e-6); + SANITY_CHECK(sqsum, 1e-6); +} + +PERF_TEST_P( Size_MatType_OutMatDepth, integral_sqsum_tilted, + testing::Combine( + testing::Values( TYPICAL_MAT_SIZES ), + testing::Values( CV_8UC1, CV_8UC4 ), + testing::Values( CV_32S, CV_32F, CV_64F ) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + int sdepth = get<2>(GetParam()); + + Mat src(sz, matType); + Mat sum(sz, sdepth); + Mat sqsum(sz, sdepth); + Mat tilted(sz, sdepth); + + declare.in(src, WARMUP_RNG).out(sum, sqsum, tilted); + + TEST_CYCLE() integral(src, sum, sqsum, tilted, sdepth); + + SANITY_CHECK(sum, 1e-6); + SANITY_CHECK(sqsum, 1e-6); + SANITY_CHECK(tilted, 1e-6, tilted.depth() > CV_32S ? ERROR_RELATIVE : ERROR_ABSOLUTE); +} diff --git a/imgproc/perf/perf_main.cpp b/imgproc/perf/perf_main.cpp new file mode 100644 index 0000000..fc89f52 --- /dev/null +++ b/imgproc/perf/perf_main.cpp @@ -0,0 +1,3 @@ +#include "perf_precomp.hpp" + +CV_PERF_TEST_MAIN(imgproc) diff --git a/imgproc/perf/perf_morph.cpp b/imgproc/perf/perf_morph.cpp new file mode 100644 index 0000000..20d0893 --- /dev/null +++ b/imgproc/perf/perf_morph.cpp @@ -0,0 +1,40 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +#define TYPICAL_MAT_TYPES_MORPH CV_8UC1, CV_8UC4 +#define TYPICAL_MATS_MORPH testing::Combine(SZ_ALL_GA, testing::Values(TYPICAL_MAT_TYPES_MORPH)) + +PERF_TEST_P(Size_MatType, erode, TYPICAL_MATS_MORPH) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + + Mat src(sz, type); + Mat dst(sz, type); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() erode(src, dst, noArray()); + + SANITY_CHECK(dst); +} + +PERF_TEST_P(Size_MatType, dilate, TYPICAL_MATS_MORPH) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + + Mat src(sz, type); + Mat dst(sz, type); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() dilate(src, dst, noArray()); + + SANITY_CHECK(dst); +} diff --git a/imgproc/perf/perf_precomp.cpp b/imgproc/perf/perf_precomp.cpp new file mode 100644 index 0000000..8552ac3 --- /dev/null +++ b/imgproc/perf/perf_precomp.cpp @@ -0,0 +1 @@ +#include "perf_precomp.hpp" diff --git a/imgproc/perf/perf_precomp.hpp b/imgproc/perf/perf_precomp.hpp new file mode 100644 index 0000000..57e6300 --- /dev/null +++ b/imgproc/perf/perf_precomp.hpp @@ -0,0 +1,17 @@ +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wmissing-declarations" +# pragma GCC diagnostic ignored "-Wmissing-prototypes" //OSX +#endif + +#ifndef __OPENCV_PERF_PRECOMP_HPP__ +#define __OPENCV_PERF_PRECOMP_HPP__ + +#include "opencv2/ts/ts.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/highgui/highgui.hpp" + +#ifdef GTEST_CREATE_SHARED_LIBRARY +#error no modules except ts should have GTEST_CREATE_SHARED_LIBRARY defined +#endif + +#endif diff --git a/imgproc/perf/perf_pyramids.cpp b/imgproc/perf/perf_pyramids.cpp new file mode 100644 index 0000000..66ea6d8 --- /dev/null +++ b/imgproc/perf/perf_pyramids.cpp @@ -0,0 +1,45 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +PERF_TEST_P(Size_MatType, pyrDown, testing::Combine( + testing::Values(sz1080p, sz720p, szVGA, szQVGA, szODD), + testing::Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_16SC1, CV_16SC3, CV_16SC4) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + + Mat src(sz, matType); + Mat dst((sz.height + 1)/2, (sz.width + 1)/2, matType); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() pyrDown(src, dst); + + SANITY_CHECK(dst); +} + +PERF_TEST_P(Size_MatType, pyrUp, testing::Combine( + testing::Values(sz720p, szVGA, szQVGA, szODD), + testing::Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_16SC1, CV_16SC3, CV_16SC4) + ) + ) +{ + Size sz = get<0>(GetParam()); + int matType = get<1>(GetParam()); + + Mat src(sz, matType); + Mat dst(sz.height*2, sz.width*2, matType); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() pyrUp(src, dst); + + SANITY_CHECK(dst); +} diff --git a/imgproc/perf/perf_remap.cpp b/imgproc/perf/perf_remap.cpp new file mode 100644 index 0000000..62e02e9 --- /dev/null +++ b/imgproc/perf/perf_remap.cpp @@ -0,0 +1,68 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using namespace testing; +using std::tr1::make_tuple; +using std::tr1::get; + +CV_ENUM(MatrixType, CV_16UC1, CV_16SC1, CV_32FC1) +CV_ENUM(MapType, CV_16SC2, CV_32FC1, CV_32FC2) +CV_ENUM(InterType, INTER_LINEAR, INTER_CUBIC, INTER_LANCZOS4, INTER_NEAREST) + +typedef TestBaseWithParam< tr1::tuple > TestRemap; + +PERF_TEST_P( TestRemap, Remap, + Combine( + Values( szVGA, sz1080p ), + ValuesIn( MatrixType::all() ), + ValuesIn( MapType::all() ), + ValuesIn( InterType::all() ) + ) +) +{ + Size sz; + int src_type, map1_type, inter_type; + + sz = get<0>(GetParam()); + src_type = get<1>(GetParam()); + map1_type = get<2>(GetParam()); + inter_type = get<3>(GetParam()); + + Mat src(sz, src_type); + Mat map1(sz, map1_type); + Mat dst(sz, src_type); + + Mat map2(map1_type == CV_32FC1 ? sz : Size(), CV_32FC1); + + RNG rng; + rng.fill(src, RNG::UNIFORM, 0, 256); + + for (int j = 0; j < map1.rows; ++j) + for (int i = 0; i < map1.cols; ++i) + switch (map1_type) + { + case CV_32FC1: + map1.at(j, i) = (float)(src.cols - i); + map2.at(j, i) = (float)j; + break; + case CV_32FC2: + map1.at(j, i)[0] = (float)(src.cols - i); + map1.at(j, i)[1] = (float)j; + break; + case CV_16SC2: + map1.at(j, i)[0] = (short)(src.cols - i); + map1.at(j, i)[1] = (short)j; + break; + default: + CV_Assert(0); + } + + + declare.in(src, WARMUP_RNG).out(dst).time(20); + + TEST_CYCLE() remap(src, dst, map1, map2, inter_type); + + SANITY_CHECK(dst); +} diff --git a/imgproc/perf/perf_resize.cpp b/imgproc/perf/perf_resize.cpp new file mode 100644 index 0000000..15be0ea --- /dev/null +++ b/imgproc/perf/perf_resize.cpp @@ -0,0 +1,114 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +typedef tr1::tuple MatInfo_Size_Size_t; +typedef TestBaseWithParam MatInfo_Size_Size; + +PERF_TEST_P(MatInfo_Size_Size, resizeUpLinear, + testing::Values( + MatInfo_Size_Size_t(CV_8UC1, szVGA, szqHD), + MatInfo_Size_Size_t(CV_8UC1, szVGA, sz720p), + MatInfo_Size_Size_t(CV_8UC4, szVGA, sz720p) + ) + ) +{ + int matType = get<0>(GetParam()); + Size from = get<1>(GetParam()); + Size to = get<2>(GetParam()); + + cv::Mat src(from, matType); + cv::Mat dst(to, matType); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() resize(src, dst, to); + + SANITY_CHECK(dst, 1 + 1e-6); +} + +PERF_TEST_P(MatInfo_Size_Size, resizeDownLinear, + testing::Values( + MatInfo_Size_Size_t(CV_8UC1, szVGA, szQVGA), + MatInfo_Size_Size_t(CV_8UC4, szqHD, szVGA), + MatInfo_Size_Size_t(CV_8UC1, sz720p, Size(120 * sz720p.width / sz720p.height, 120)),//face detection min_face_size = 20% + MatInfo_Size_Size_t(CV_8UC4, sz720p, szVGA), + MatInfo_Size_Size_t(CV_8UC4, sz720p, szQVGA) + ) + ) +{ + int matType = get<0>(GetParam()); + Size from = get<1>(GetParam()); + Size to = get<2>(GetParam()); + + cv::Mat src(from, matType); + cv::Mat dst(to, matType); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() resize(src, dst, to); + + SANITY_CHECK(dst, 1 + 1e-6); +} + + +typedef tr1::tuple MatInfo_Size_Scale_t; +typedef TestBaseWithParam MatInfo_Size_Scale; + +PERF_TEST_P(MatInfo_Size_Scale, ResizeAreaFast, + testing::Combine( + testing::Values(CV_8UC1, CV_8UC4), + testing::Values(szVGA, szqHD, sz720p, sz1080p), + testing::Values(2) + ) + ) +{ + int matType = get<0>(GetParam()); + Size from = get<1>(GetParam()); + int scale = get<2>(GetParam()); + + from.width = (from.width/scale)*scale; + from.height = (from.height/scale)*scale; + + cv::Mat src(from, matType); + cv::Mat dst(from.height / scale, from.width / scale, matType); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() resize(src, dst, dst.size(), 0, 0, INTER_AREA); + + //difference equal to 1 is allowed because of different possible rounding modes: round-to-nearest vs bankers' rounding + SANITY_CHECK(dst, 1); +} + + +typedef TestBaseWithParam > MatInfo_Size_Scale_Area; + +PERF_TEST_P(MatInfo_Size_Scale_Area, ResizeArea, + testing::Combine( + testing::Values(CV_8UC1, CV_8UC4), + testing::Values(szVGA, szqHD, sz720p, sz1080p), + testing::Values(2.4, 3.4, 1.3) + ) + ) +{ + int matType = get<0>(GetParam()); + Size from = get<1>(GetParam()); + double scale = get<2>(GetParam()); + + cv::Mat src(from, matType); + + Size to(cvRound(from.width * scale), cvRound(from.height * scale)); + cv::Mat dst(to, matType); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() resize(src, dst, dst.size(), 0, 0, INTER_AREA); + + //difference equal to 1 is allowed because of different possible rounding modes: round-to-nearest vs bankers' rounding + SANITY_CHECK(dst, 1); +} diff --git a/imgproc/perf/perf_sepfilters.cpp b/imgproc/perf/perf_sepfilters.cpp new file mode 100644 index 0000000..9a5bd4e --- /dev/null +++ b/imgproc/perf/perf_sepfilters.cpp @@ -0,0 +1,244 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +#define FILTER_SRC_SIZES szODD, szQVGA, szVGA + +CV_ENUM(BorderType3x3, BORDER_REPLICATE, BORDER_CONSTANT) +CV_ENUM(BorderType3x3ROI, BORDER_DEFAULT, BORDER_REPLICATE|BORDER_ISOLATED, BORDER_CONSTANT|BORDER_ISOLATED) + +CV_ENUM(BorderType, BORDER_REPLICATE, BORDER_CONSTANT, BORDER_REFLECT, BORDER_REFLECT101) +CV_ENUM(BorderTypeROI, BORDER_DEFAULT, BORDER_REPLICATE|BORDER_ISOLATED, BORDER_CONSTANT|BORDER_ISOLATED, BORDER_REFLECT|BORDER_ISOLATED, BORDER_REFLECT101|BORDER_ISOLATED) + +typedef std::tr1::tuple, BorderType3x3> Size_MatType_dx_dy_Border3x3_t; +typedef perf::TestBaseWithParam Size_MatType_dx_dy_Border3x3; + +typedef std::tr1::tuple, BorderType3x3ROI> Size_MatType_dx_dy_Border3x3ROI_t; +typedef perf::TestBaseWithParam Size_MatType_dx_dy_Border3x3ROI; + +typedef std::tr1::tuple, BorderType> Size_MatType_dx_dy_Border5x5_t; +typedef perf::TestBaseWithParam Size_MatType_dx_dy_Border5x5; + +typedef std::tr1::tuple, BorderTypeROI> Size_MatType_dx_dy_Border5x5ROI_t; +typedef perf::TestBaseWithParam Size_MatType_dx_dy_Border5x5ROI; + + +/**************** Sobel ********************/ + +PERF_TEST_P(Size_MatType_dx_dy_Border3x3, sobelFilter, + testing::Combine( + testing::Values(FILTER_SRC_SIZES), + testing::Values(CV_16S, CV_32F), + testing::Values(make_tuple(0, 1), make_tuple(1, 0), make_tuple(1, 1), make_tuple(0, 2), make_tuple(2, 0), make_tuple(2, 2)), + testing::ValuesIn(BorderType3x3::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int ddepth = get<1>(GetParam()); + int dx = get<0>(get<2>(GetParam())); + int dy = get<1>(get<2>(GetParam())); + BorderType3x3 border = get<3>(GetParam()); + + Mat src(size, CV_8U); + Mat dst(size, ddepth); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() Sobel(src, dst, ddepth, dx, dy, 3, 1, 0, border); + + SANITY_CHECK(dst); +} + +PERF_TEST_P(Size_MatType_dx_dy_Border3x3ROI, sobelFilter, + testing::Combine( + testing::Values(FILTER_SRC_SIZES), + testing::Values(CV_16S, CV_32F), + testing::Values(make_tuple(0, 1), make_tuple(1, 0), make_tuple(1, 1), make_tuple(0, 2), make_tuple(2, 0), make_tuple(2, 2)), + testing::ValuesIn(BorderType3x3ROI::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int ddepth = get<1>(GetParam()); + int dx = get<0>(get<2>(GetParam())); + int dy = get<1>(get<2>(GetParam())); + BorderType3x3ROI border = get<3>(GetParam()); + + Mat src(size.height + 10, size.width + 10, CV_8U); + Mat dst(size, ddepth); + + warmup(src, WARMUP_RNG); + src = src(Range(5, 5 + size.height), Range(5, 5 + size.width)); + + declare.in(src).out(dst); + + TEST_CYCLE() Sobel(src, dst, ddepth, dx, dy, 3, 1, 0, border); + + SANITY_CHECK(dst); +} + +PERF_TEST_P(Size_MatType_dx_dy_Border5x5, sobelFilter, + testing::Combine( + testing::Values(FILTER_SRC_SIZES), + testing::Values(CV_16S, CV_32F), + testing::Values(make_tuple(0, 1), make_tuple(1, 0), make_tuple(1, 1), make_tuple(0, 2), make_tuple(2, 0)), + testing::ValuesIn(BorderType::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int ddepth = get<1>(GetParam()); + int dx = get<0>(get<2>(GetParam())); + int dy = get<1>(get<2>(GetParam())); + BorderType border = get<3>(GetParam()); + + Mat src(size, CV_8U); + Mat dst(size, ddepth); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() Sobel(src, dst, ddepth, dx, dy, 5, 1, 0, border); + + SANITY_CHECK(dst); +} + +PERF_TEST_P(Size_MatType_dx_dy_Border5x5ROI, sobelFilter, + testing::Combine( + testing::Values(FILTER_SRC_SIZES), + testing::Values(CV_16S, CV_32F), + testing::Values(make_tuple(0, 1), make_tuple(1, 0), make_tuple(1, 1), make_tuple(0, 2), make_tuple(2, 0)), + testing::ValuesIn(BorderTypeROI::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int ddepth = get<1>(GetParam()); + int dx = get<0>(get<2>(GetParam())); + int dy = get<1>(get<2>(GetParam())); + BorderTypeROI border = get<3>(GetParam()); + + Mat src(size.height + 10, size.width + 10, CV_8U); + Mat dst(size, ddepth); + + warmup(src, WARMUP_RNG); + src = src(Range(5, 5 + size.height), Range(5, 5 + size.width)); + + declare.in(src).out(dst); + + TEST_CYCLE() Sobel(src, dst, ddepth, dx, dy, 5, 1, 0, border); + + SANITY_CHECK(dst); +} + +/**************** Scharr ********************/ + +PERF_TEST_P(Size_MatType_dx_dy_Border3x3, scharrFilter, + testing::Combine( + testing::Values(FILTER_SRC_SIZES), + testing::Values(CV_16S, CV_32F), + testing::Values(make_tuple(0, 1), make_tuple(1, 0)), + testing::ValuesIn(BorderType3x3::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int ddepth = get<1>(GetParam()); + int dx = get<0>(get<2>(GetParam())); + int dy = get<1>(get<2>(GetParam())); + BorderType3x3 border = get<3>(GetParam()); + + Mat src(size, CV_8U); + Mat dst(size, ddepth); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() Scharr(src, dst, ddepth, dx, dy, 1, 0, border); + + SANITY_CHECK(dst); +} + +PERF_TEST_P(Size_MatType_dx_dy_Border3x3ROI, scharrFilter, + testing::Combine( + testing::Values(FILTER_SRC_SIZES), + testing::Values(CV_16S, CV_32F), + testing::Values(make_tuple(0, 1), make_tuple(1, 0)), + testing::ValuesIn(BorderType3x3ROI::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int ddepth = get<1>(GetParam()); + int dx = get<0>(get<2>(GetParam())); + int dy = get<1>(get<2>(GetParam())); + BorderType3x3ROI border = get<3>(GetParam()); + + Mat src(size.height + 10, size.width + 10, CV_8U); + Mat dst(size, ddepth); + + warmup(src, WARMUP_RNG); + src = src(Range(5, 5 + size.height), Range(5, 5 + size.width)); + + declare.in(src).out(dst); + + TEST_CYCLE() Scharr(src, dst, ddepth, dx, dy, 1, 0, border); + + SANITY_CHECK(dst); +} + +PERF_TEST_P(Size_MatType_dx_dy_Border3x3, scharrViaSobelFilter, + testing::Combine( + testing::Values(FILTER_SRC_SIZES), + testing::Values(CV_16S, CV_32F), + testing::Values(make_tuple(0, 1), make_tuple(1, 0)), + testing::ValuesIn(BorderType3x3::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int ddepth = get<1>(GetParam()); + int dx = get<0>(get<2>(GetParam())); + int dy = get<1>(get<2>(GetParam())); + BorderType3x3 border = get<3>(GetParam()); + + Mat src(size, CV_8U); + Mat dst(size, ddepth); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() Sobel(src, dst, ddepth, dx, dy, -1, 1, 0, border); + + SANITY_CHECK(dst); +} + +PERF_TEST_P(Size_MatType_dx_dy_Border3x3ROI, scharrViaSobelFilter, + testing::Combine( + testing::Values(FILTER_SRC_SIZES), + testing::Values(CV_16S, CV_32F), + testing::Values(make_tuple(0, 1), make_tuple(1, 0)), + testing::ValuesIn(BorderType3x3ROI::all()) + ) + ) +{ + Size size = get<0>(GetParam()); + int ddepth = get<1>(GetParam()); + int dx = get<0>(get<2>(GetParam())); + int dy = get<1>(get<2>(GetParam())); + BorderType3x3ROI border = get<3>(GetParam()); + + Mat src(size.height + 10, size.width + 10, CV_8U); + Mat dst(size, ddepth); + + warmup(src, WARMUP_RNG); + src = src(Range(5, 5 + size.height), Range(5, 5 + size.width)); + + declare.in(src).out(dst); + + TEST_CYCLE() Sobel(src, dst, ddepth, dx, dy, -1, 1, 0, border); + + SANITY_CHECK(dst); +} diff --git a/imgproc/perf/perf_threshold.cpp b/imgproc/perf/perf_threshold.cpp new file mode 100644 index 0000000..02e818c --- /dev/null +++ b/imgproc/perf/perf_threshold.cpp @@ -0,0 +1,90 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +CV_ENUM(ThreshType, THRESH_BINARY, THRESH_BINARY_INV, THRESH_TRUNC, THRESH_TOZERO, THRESH_TOZERO_INV) + +typedef std::tr1::tuple Size_MatType_ThreshType_t; +typedef perf::TestBaseWithParam Size_MatType_ThreshType; + +PERF_TEST_P(Size_MatType_ThreshType, threshold, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::Values(CV_8UC1, CV_16SC1), + testing::ValuesIn(ThreshType::all()) + ) + ) +{ + + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + ThreshType threshType = get<2>(GetParam()); + + Mat src(sz, type); + Mat dst(sz, type); + + double thresh = theRNG().uniform(1, 254); + double maxval = theRNG().uniform(1, 254); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() threshold(src, dst, thresh, maxval, threshType); + + SANITY_CHECK(dst); +} + +typedef perf::TestBaseWithParam Size_Only; + +PERF_TEST_P(Size_Only, threshold_otsu, testing::Values(TYPICAL_MAT_SIZES)) +{ + Size sz = GetParam(); + + Mat src(sz, CV_8UC1); + Mat dst(sz, CV_8UC1); + + double maxval = theRNG().uniform(1, 254); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() threshold(src, dst, 0, maxval, THRESH_BINARY|THRESH_OTSU); + + SANITY_CHECK(dst); +} + +CV_ENUM(AdaptThreshType, THRESH_BINARY, THRESH_BINARY_INV) +CV_ENUM(AdaptThreshMethod, ADAPTIVE_THRESH_MEAN_C, ADAPTIVE_THRESH_GAUSSIAN_C) + +typedef std::tr1::tuple Size_AdaptThreshType_AdaptThreshMethod_BlockSize_t; +typedef perf::TestBaseWithParam Size_AdaptThreshType_AdaptThreshMethod_BlockSize; + +PERF_TEST_P(Size_AdaptThreshType_AdaptThreshMethod_BlockSize, adaptiveThreshold, + testing::Combine( + testing::Values(TYPICAL_MAT_SIZES), + testing::ValuesIn(AdaptThreshType::all()), + testing::ValuesIn(AdaptThreshMethod::all()), + testing::Values(3, 5) + ) + ) +{ + Size sz = get<0>(GetParam()); + AdaptThreshType adaptThreshType = get<1>(GetParam()); + AdaptThreshMethod adaptThreshMethod = get<2>(GetParam()); + int blockSize = get<3>(GetParam()); + + double maxValue = theRNG().uniform(1, 254); + double C = 10.0; + + int type = CV_8UC1; + Mat src(sz, type); + Mat dst(sz, type); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() adaptiveThreshold(src, dst, maxValue, adaptThreshMethod, adaptThreshType, blockSize, C); + + SANITY_CHECK(dst); +} diff --git a/imgproc/perf/perf_warp.cpp b/imgproc/perf/perf_warp.cpp new file mode 100644 index 0000000..8f309a2 --- /dev/null +++ b/imgproc/perf/perf_warp.cpp @@ -0,0 +1,168 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using namespace testing; +using std::tr1::make_tuple; +using std::tr1::get; + +enum{HALF_SIZE=0, UPSIDE_DOWN, REFLECTION_X, REFLECTION_BOTH}; + +CV_ENUM(BorderMode, BORDER_CONSTANT, BORDER_REPLICATE); +CV_ENUM(InterType, INTER_NEAREST, INTER_LINEAR); +CV_ENUM(RemapMode, HALF_SIZE, UPSIDE_DOWN, REFLECTION_X, REFLECTION_BOTH); + +typedef TestBaseWithParam< tr1::tuple > TestWarpAffine; +typedef TestBaseWithParam< tr1::tuple > TestWarpPerspective; +typedef TestBaseWithParam< tr1::tuple > TestRemap; + +void update_map(const Mat& src, Mat& map_x, Mat& map_y, const int remapMode ); + +PERF_TEST_P( TestWarpAffine, WarpAffine, + Combine( + Values( szVGA, sz720p, sz1080p ), + ValuesIn( InterType::all() ), + ValuesIn( BorderMode::all() ) + ) +) +{ + Size sz; + int borderMode, interType; + sz = get<0>(GetParam()); + borderMode = get<1>(GetParam()); + interType = get<2>(GetParam()); + + Mat src, img = imread(getDataPath("cv/shared/fruits.jpg")); + cvtColor(img, src, COLOR_BGR2RGBA, 4); + Mat warpMat = getRotationMatrix2D(Point2f(src.cols/2.f, src.rows/2.f), 30., 2.2); + Mat dst(sz, CV_8UC4); + + declare.in(src).out(dst); + + TEST_CYCLE() warpAffine( src, dst, warpMat, sz, interType, borderMode, Scalar::all(150) ); + + SANITY_CHECK(dst); + +} + +PERF_TEST_P( TestWarpPerspective, WarpPerspective, + Combine( + Values( szVGA, sz720p, sz1080p ), + ValuesIn( InterType::all() ), + ValuesIn( BorderMode::all() ) + ) +) +{ + Size sz; + int borderMode, interType; + sz = get<0>(GetParam()); + borderMode = get<1>(GetParam()); + interType = get<2>(GetParam()); + + + Mat src, img = imread(getDataPath("cv/shared/fruits.jpg")); + cvtColor(img, src, COLOR_BGR2RGBA, 4); + Mat rotMat = getRotationMatrix2D(Point2f(src.cols/2.f, src.rows/2.f), 30., 2.2); + Mat warpMat(3, 3, CV_64FC1); + for(int r=0; r<2; r++) + for(int c=0; c<3; c++) + warpMat.at(r, c) = rotMat.at(r, c); + warpMat.at(2, 0) = .3/sz.width; + warpMat.at(2, 1) = .3/sz.height; + warpMat.at(2, 2) = 1; + Mat dst(sz, CV_8UC4); + + declare.in(src).out(dst); + + TEST_CYCLE() warpPerspective( src, dst, warpMat, sz, interType, borderMode, Scalar::all(150) ); + + SANITY_CHECK(dst); +} + +PERF_TEST_P( TestRemap, remap, + Combine( + Values( TYPICAL_MAT_TYPES ), + Values( szVGA, sz720p, sz1080p ), + ValuesIn( InterType::all() ), + ValuesIn( BorderMode::all() ), + ValuesIn( RemapMode::all() ) + ) + ) +{ + int type = get<0>(GetParam()); + Size size = get<1>(GetParam()); + int interpolationType = get<2>(GetParam()); + int borderMode = get<3>(GetParam()); + int remapMode = get<4>(GetParam()); + unsigned int height = size.height; + unsigned int width = size.width; + Mat source(height, width, type); + Mat destination; + Mat map_x(height, width, CV_32F); + Mat map_y(height, width, CV_32F); + + declare.in(source, WARMUP_RNG); + + update_map(source, map_x, map_y, remapMode); + + TEST_CYCLE() + { + remap(source, destination, map_x, map_y, interpolationType, borderMode); + } + + SANITY_CHECK(destination, 1); +} + +void update_map(const Mat& src, Mat& map_x, Mat& map_y, const int remapMode ) +{ + for( int j = 0; j < src.rows; j++ ) + { + for( int i = 0; i < src.cols; i++ ) + { + switch( remapMode ) + { + case HALF_SIZE: + if( i > src.cols*0.25 && i < src.cols*0.75 && j > src.rows*0.25 && j < src.rows*0.75 ) + { + map_x.at(j,i) = 2*( i - src.cols*0.25f ) + 0.5f ; + map_y.at(j,i) = 2*( j - src.rows*0.25f ) + 0.5f ; + } + else + { + map_x.at(j,i) = 0 ; + map_y.at(j,i) = 0 ; + } + break; + case UPSIDE_DOWN: + map_x.at(j,i) = static_cast(i) ; + map_y.at(j,i) = static_cast(src.rows - j) ; + break; + case REFLECTION_X: + map_x.at(j,i) = static_cast(src.cols - i) ; + map_y.at(j,i) = static_cast(j) ; + break; + case REFLECTION_BOTH: + map_x.at(j,i) = static_cast(src.cols - i) ; + map_y.at(j,i) = static_cast(src.rows - j) ; + break; + } // end of switch + } + } +} + +PERF_TEST(Transform, getPerspectiveTransform) +{ + unsigned int size = 8; + Mat source(1, size/2, CV_32FC2); + Mat destination(1, size/2, CV_32FC2); + Mat transformCoefficient; + + declare.in(source, destination, WARMUP_RNG); + + TEST_CYCLE() + { + transformCoefficient = getPerspectiveTransform(source, destination); + } +} + diff --git a/imgproc/src/_geom.h b/imgproc/src/_geom.h new file mode 100644 index 0000000..2505039 --- /dev/null +++ b/imgproc/src/_geom.h @@ -0,0 +1,70 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _CV_GEOM_H_ +#define _CV_GEOM_H_ + +/* Finds distance between two points */ +CV_INLINE float icvDistanceL2_32f( CvPoint2D32f pt1, CvPoint2D32f pt2 ) +{ + float dx = pt2.x - pt1.x; + float dy = pt2.y - pt1.y; + + return std::sqrt( dx*dx + dy*dy ); +} + + +int icvIntersectLines( double x1, double dx1, double y1, double dy1, + double x2, double dx2, double y2, double dy2, + double* t2 ); + + +void icvIntersectLines3( double* a0, double* b0, double* c0, + double* a1, double* b1, double* c1, + CvPoint2D32f* point ); + + +/* curvature: 0 - 1-curvature, 1 - k-cosine curvature. */ +CvSeq* icvApproximateChainTC89( CvChain* chain, int header_size, CvMemStorage* storage, int method ); + +#endif /*_IPCVGEOM_H_*/ + +/* End of file. */ diff --git a/imgproc/src/_list.h b/imgproc/src/_list.h new file mode 100644 index 0000000..29acdb4 --- /dev/null +++ b/imgproc/src/_list.h @@ -0,0 +1,374 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _CV_LIST_H_ +#define _CV_LIST_H_ + +#include +#include + +#define CV_FORCE_INLINE CV_INLINE + +#if !defined(_LIST_INLINE) +#define _LIST_INLINE CV_FORCE_INLINE +#endif /*_LIST_INLINE*/ + +#if defined DECLARE_LIST +#if defined _MSC_VER && _MSC_VER >= 1200 + #pragma warning("DECLARE_LIST macro is already defined!") +#endif +#endif /*DECLARE_LIST*/ + +static const long default_size = 10; +static const long default_inc_size = 10; + +struct _pos +{ + void* m_pos; +#ifdef _DEBUG + struct _list* m_list; +#endif /*_DEBUG*/ +}; +typedef struct _pos CVPOS; +struct _list +{ + void* m_buffer; + void* m_first_buffer; + long m_buf_size; /* The size of the buffer */ + long m_size; /* The number of elements */ + CVPOS m_head; + CVPOS m_tail; + CVPOS m_head_free; +}; + +typedef struct _list _CVLIST; + +#define DECLARE_LIST(type, prefix)\ + /* Basic element of a list*/\ + struct prefix##element_##type\ + {\ + struct prefix##element_##type* m_prev;\ + struct prefix##element_##type* m_next;\ + type m_data;\ + };\ + typedef struct prefix##element_##type ELEMENT_##type;\ + /* Initialization and destruction*/\ + _LIST_INLINE _CVLIST* prefix##create_list_##type(long);\ + _LIST_INLINE void prefix##destroy_list_##type(_CVLIST*);\ + /* Access functions*/\ + _LIST_INLINE CVPOS prefix##get_head_pos_##type(_CVLIST*);\ + _LIST_INLINE CVPOS prefix##get_tail_pos_##type(_CVLIST*);\ + _LIST_INLINE type* prefix##get_next_##type(CVPOS*);\ + _LIST_INLINE type* prefix##get_prev_##type(CVPOS*);\ + _LIST_INLINE int prefix##is_pos_##type(CVPOS pos);\ + /* Modification functions*/\ + _LIST_INLINE void prefix##clear_list_##type(_CVLIST*);\ + _LIST_INLINE CVPOS prefix##add_head_##type(_CVLIST*, type*);\ + _LIST_INLINE CVPOS prefix##add_tail_##type(_CVLIST*, type*);\ + _LIST_INLINE void prefix##remove_head_##type(_CVLIST*);\ + _LIST_INLINE void prefix##remove_tail_##type(_CVLIST*);\ + _LIST_INLINE CVPOS prefix##insert_before_##type(_CVLIST*, CVPOS, type*);\ + _LIST_INLINE CVPOS prefix##insert_after_##type(_CVLIST*, CVPOS, type*);\ + _LIST_INLINE void prefix##remove_at_##type(_CVLIST*, CVPOS);\ + _LIST_INLINE void prefix##set_##type(CVPOS, type*);\ + _LIST_INLINE type* prefix##get_##type(CVPOS);\ + /* Statistics functions*/\ + _LIST_INLINE int prefix##get_count_##type(_CVLIST*); + +/* This macro finds a space for a new element and puts in into 'element' pointer */ +#define INSERT_NEW(element_type, l, element)\ + l->m_size++;\ + if(l->m_head_free.m_pos != NULL)\ + {\ + element = (element_type*)(l->m_head_free.m_pos);\ + if(element->m_next != NULL)\ + {\ + element->m_next->m_prev = NULL;\ + l->m_head_free.m_pos = element->m_next;\ + }\ + else\ + {\ + l->m_head_free.m_pos = NULL;\ + }\ + }\ + else\ + {\ + if(l->m_buf_size < l->m_size && l->m_head_free.m_pos == NULL)\ + {\ + *(void**)l->m_buffer = cvAlloc(l->m_buf_size*sizeof(element_type) + sizeof(void*));\ + l->m_buffer = *(void**)l->m_buffer;\ + *(void**)l->m_buffer = NULL;\ + element = (element_type*)((char*)l->m_buffer + sizeof(void*));\ + }\ + else\ + {\ + element = (element_type*)((char*)l->m_buffer + sizeof(void*)) + l->m_size - 1;\ + }\ + } + +/* This macro adds 'element' to the list of free elements*/ +#define INSERT_FREE(element_type, l, element)\ + if(l->m_head_free.m_pos != NULL)\ + {\ + ((element_type*)l->m_head_free.m_pos)->m_prev = element;\ + }\ + element->m_next = ((element_type*)l->m_head_free.m_pos);\ + l->m_head_free.m_pos = element; + + +/*#define GET_FIRST_FREE(l) ((ELEMENT_##type*)(l->m_head_free.m_pos))*/ + +#define IMPLEMENT_LIST(type, prefix)\ +_CVLIST* prefix##create_list_##type(long size)\ +{\ + _CVLIST* pl = (_CVLIST*)cvAlloc(sizeof(_CVLIST));\ + pl->m_buf_size = size > 0 ? size : default_size;\ + pl->m_first_buffer = cvAlloc(pl->m_buf_size*sizeof(ELEMENT_##type) + sizeof(void*));\ + pl->m_buffer = pl->m_first_buffer;\ + *(void**)pl->m_buffer = NULL;\ + pl->m_size = 0;\ + pl->m_head.m_pos = NULL;\ + pl->m_tail.m_pos = NULL;\ + pl->m_head_free.m_pos = NULL;\ + return pl;\ +}\ +void prefix##destroy_list_##type(_CVLIST* l)\ +{\ + void* cur = l->m_first_buffer;\ + void* next;\ + while(cur)\ + {\ + next = *(void**)cur;\ + cvFree(&cur);\ + cur = next;\ + }\ + cvFree(&l);\ +}\ +CVPOS prefix##get_head_pos_##type(_CVLIST* l)\ +{\ + return l->m_head;\ +}\ +CVPOS prefix##get_tail_pos_##type(_CVLIST* l)\ +{\ + return l->m_tail;\ +}\ +type* prefix##get_next_##type(CVPOS* pos)\ +{\ + if(pos->m_pos)\ + {\ + ELEMENT_##type* element = (ELEMENT_##type*)(pos->m_pos);\ + pos->m_pos = element->m_next;\ + return &element->m_data;\ + }\ + else\ + {\ + return NULL;\ + }\ +}\ +type* prefix##get_prev_##type(CVPOS* pos)\ +{\ + if(pos->m_pos)\ + {\ + ELEMENT_##type* element = (ELEMENT_##type*)(pos->m_pos);\ + pos->m_pos = element->m_prev;\ + return &element->m_data;\ + }\ + else\ + {\ + return NULL;\ + }\ +}\ +int prefix##is_pos_##type(CVPOS pos)\ +{\ + return !!pos.m_pos;\ +}\ +void prefix##clear_list_##type(_CVLIST* l)\ +{\ + l->m_head.m_pos = NULL;\ + l->m_tail.m_pos = NULL;\ + l->m_size = 0;\ + l->m_head_free.m_pos = NULL;\ +}\ +CVPOS prefix##add_head_##type(_CVLIST* l, type* data)\ +{\ + ELEMENT_##type* element;\ + INSERT_NEW(ELEMENT_##type, l, element);\ + element->m_prev = NULL;\ + element->m_next = (ELEMENT_##type*)(l->m_head.m_pos);\ + memcpy(&(element->m_data), data, sizeof(*data));\ + if(element->m_next)\ + {\ + element->m_next->m_prev = element;\ + }\ + else\ + {\ + l->m_tail.m_pos = element;\ + }\ + l->m_head.m_pos = element;\ + return l->m_head;\ +}\ +CVPOS prefix##add_tail_##type(_CVLIST* l, type* data)\ +{\ + ELEMENT_##type* element;\ + INSERT_NEW(ELEMENT_##type, l, element);\ + element->m_next = NULL;\ + element->m_prev = (ELEMENT_##type*)(l->m_tail.m_pos);\ + memcpy(&(element->m_data), data, sizeof(*data));\ + if(element->m_prev)\ + {\ + element->m_prev->m_next = element;\ + }\ + else\ + {\ + l->m_head.m_pos = element;\ + }\ + l->m_tail.m_pos = element;\ + return l->m_tail;\ +}\ +void prefix##remove_head_##type(_CVLIST* l)\ +{\ + ELEMENT_##type* element = ((ELEMENT_##type*)(l->m_head.m_pos));\ + if(element->m_next != NULL)\ + {\ + element->m_next->m_prev = NULL;\ + }\ + l->m_head.m_pos = element->m_next;\ + INSERT_FREE(ELEMENT_##type, l, element);\ + l->m_size--;\ +}\ +void prefix##remove_tail_##type(_CVLIST* l)\ +{\ + ELEMENT_##type* element = ((ELEMENT_##type*)(l->m_tail.m_pos));\ + if(element->m_prev != NULL)\ + {\ + element->m_prev->m_next = NULL;\ + }\ + l->m_tail.m_pos = element->m_prev;\ + INSERT_FREE(ELEMENT_##type, l, element);\ + l->m_size--;\ +}\ +CVPOS prefix##insert_after_##type(_CVLIST* l, CVPOS pos, type* data)\ +{\ + ELEMENT_##type* element;\ + ELEMENT_##type* before;\ + CVPOS newpos;\ + INSERT_NEW(ELEMENT_##type, l, element);\ + memcpy(&(element->m_data), data, sizeof(*data));\ + before = (ELEMENT_##type*)pos.m_pos;\ + element->m_prev = before;\ + element->m_next = before->m_next;\ + before->m_next = element;\ + if(element->m_next != NULL)\ + element->m_next->m_prev = element;\ + else\ + l->m_tail.m_pos = element;\ + newpos.m_pos = element;\ + return newpos;\ +}\ +CVPOS prefix##insert_before_##type(_CVLIST* l, CVPOS pos, type* data)\ +{\ + ELEMENT_##type* element;\ + ELEMENT_##type* after;\ + CVPOS newpos;\ + INSERT_NEW(ELEMENT_##type, l, element);\ + memcpy(&(element->m_data), data, sizeof(*data));\ + after = (ELEMENT_##type*)pos.m_pos;\ + element->m_prev = after->m_prev;\ + element->m_next = after;\ + after->m_prev = element;\ + if(element->m_prev != NULL)\ + element->m_prev->m_next = element;\ + else\ + l->m_head.m_pos = element;\ + newpos.m_pos = element;\ + return newpos;\ +}\ +void prefix##remove_at_##type(_CVLIST* l, CVPOS pos)\ +{\ + ELEMENT_##type* element = ((ELEMENT_##type*)pos.m_pos);\ + if(element->m_prev != NULL)\ + {\ + element->m_prev->m_next = element->m_next;\ + }\ + else\ + {\ + l->m_head.m_pos = element->m_next;\ + }\ + if(element->m_next != NULL)\ + {\ + element->m_next->m_prev = element->m_prev;\ + }\ + else\ + {\ + l->m_tail.m_pos = element->m_prev;\ + }\ + INSERT_FREE(ELEMENT_##type, l, element);\ + l->m_size--;\ +}\ +void prefix##set_##type(CVPOS pos, type* data)\ +{\ + ELEMENT_##type* element = ((ELEMENT_##type*)(pos.m_pos));\ + memcpy(&(element->m_data), data, sizeof(*data));\ +}\ +type* prefix##get_##type(CVPOS pos)\ +{\ + ELEMENT_##type* element = ((ELEMENT_##type*)(pos.m_pos));\ + return &(element->m_data);\ +}\ +int prefix##get_count_##type(_CVLIST* list)\ +{\ + return list->m_size;\ +} + +#define DECLARE_AND_IMPLEMENT_LIST(type, prefix)\ + DECLARE_LIST(type, prefix)\ + IMPLEMENT_LIST(type, prefix) + +typedef struct __index +{ + int value; + float rho, theta; +} +_index; + +DECLARE_LIST( _index, h_ ) + +#endif/*_CV_LIST_H_*/ diff --git a/imgproc/src/accum.cpp b/imgproc/src/accum.cpp new file mode 100644 index 0000000..2c11f68 --- /dev/null +++ b/imgproc/src/accum.cpp @@ -0,0 +1,485 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +/ +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +namespace cv +{ + +template void +acc_( const T* src, AT* dst, const uchar* mask, int len, int cn ) +{ + int i = 0; + + if( !mask ) + { + len *= cn; + #if CV_ENABLE_UNROLLED + for( ; i <= len - 4; i += 4 ) + { + AT t0, t1; + t0 = src[i] + dst[i]; + t1 = src[i+1] + dst[i+1]; + dst[i] = t0; dst[i+1] = t1; + + t0 = src[i+2] + dst[i+2]; + t1 = src[i+3] + dst[i+3]; + dst[i+2] = t0; dst[i+3] = t1; + } + #endif + for( ; i < len; i++ ) + dst[i] += src[i]; + } + else if( cn == 1 ) + { + for( ; i < len; i++ ) + { + if( mask[i] ) + dst[i] += src[i]; + } + } + else if( cn == 3 ) + { + for( ; i < len; i++, src += 3, dst += 3 ) + { + if( mask[i] ) + { + AT t0 = src[0] + dst[0]; + AT t1 = src[1] + dst[1]; + AT t2 = src[2] + dst[2]; + + dst[0] = t0; dst[1] = t1; dst[2] = t2; + } + } + } + else + { + for( ; i < len; i++, src += cn, dst += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + dst[k] += src[k]; + } + } +} + + +template void +accSqr_( const T* src, AT* dst, const uchar* mask, int len, int cn ) +{ + int i = 0; + + if( !mask ) + { + len *= cn; + #if CV_ENABLE_UNROLLED + for( ; i <= len - 4; i += 4 ) + { + AT t0, t1; + t0 = (AT)src[i]*src[i] + dst[i]; + t1 = (AT)src[i+1]*src[i+1] + dst[i+1]; + dst[i] = t0; dst[i+1] = t1; + + t0 = (AT)src[i+2]*src[i+2] + dst[i+2]; + t1 = (AT)src[i+3]*src[i+3] + dst[i+3]; + dst[i+2] = t0; dst[i+3] = t1; + } + #endif + for( ; i < len; i++ ) + dst[i] += (AT)src[i]*src[i]; + } + else if( cn == 1 ) + { + for( ; i < len; i++ ) + { + if( mask[i] ) + dst[i] += (AT)src[i]*src[i]; + } + } + else if( cn == 3 ) + { + for( ; i < len; i++, src += 3, dst += 3 ) + { + if( mask[i] ) + { + AT t0 = (AT)src[0]*src[0] + dst[0]; + AT t1 = (AT)src[1]*src[1] + dst[1]; + AT t2 = (AT)src[2]*src[2] + dst[2]; + + dst[0] = t0; dst[1] = t1; dst[2] = t2; + } + } + } + else + { + for( ; i < len; i++, src += cn, dst += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + dst[k] += (AT)src[k]*src[k]; + } + } +} + + +template void +accProd_( const T* src1, const T* src2, AT* dst, const uchar* mask, int len, int cn ) +{ + int i = 0; + + if( !mask ) + { + len *= cn; + #if CV_ENABLE_UNROLLED + for( ; i <= len - 4; i += 4 ) + { + AT t0, t1; + t0 = (AT)src1[i]*src2[i] + dst[i]; + t1 = (AT)src1[i+1]*src2[i+1] + dst[i+1]; + dst[i] = t0; dst[i+1] = t1; + + t0 = (AT)src1[i+2]*src2[i+2] + dst[i+2]; + t1 = (AT)src1[i+3]*src2[i+3] + dst[i+3]; + dst[i+2] = t0; dst[i+3] = t1; + } + #endif + for( ; i < len; i++ ) + dst[i] += (AT)src1[i]*src2[i]; + } + else if( cn == 1 ) + { + for( ; i < len; i++ ) + { + if( mask[i] ) + dst[i] += (AT)src1[i]*src2[i]; + } + } + else if( cn == 3 ) + { + for( ; i < len; i++, src1 += 3, src2 += 3, dst += 3 ) + { + if( mask[i] ) + { + AT t0 = (AT)src1[0]*src2[0] + dst[0]; + AT t1 = (AT)src1[1]*src2[1] + dst[1]; + AT t2 = (AT)src1[2]*src2[2] + dst[2]; + + dst[0] = t0; dst[1] = t1; dst[2] = t2; + } + } + } + else + { + for( ; i < len; i++, src1 += cn, src2 += cn, dst += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + dst[k] += (AT)src1[k]*src2[k]; + } + } +} + + +template void +accW_( const T* src, AT* dst, const uchar* mask, int len, int cn, double alpha ) +{ + AT a = (AT)alpha, b = 1 - a; + int i = 0; + + if( !mask ) + { + len *= cn; + #if CV_ENABLE_UNROLLED + for( ; i <= len - 4; i += 4 ) + { + AT t0, t1; + t0 = src[i]*a + dst[i]*b; + t1 = src[i+1]*a + dst[i+1]*b; + dst[i] = t0; dst[i+1] = t1; + + t0 = src[i+2]*a + dst[i+2]*b; + t1 = src[i+3]*a + dst[i+3]*b; + dst[i+2] = t0; dst[i+3] = t1; + } + #endif + for( ; i < len; i++ ) + dst[i] = src[i]*a + dst[i]*b; + } + else if( cn == 1 ) + { + for( ; i < len; i++ ) + { + if( mask[i] ) + dst[i] = src[i]*a + dst[i]*b; + } + } + else if( cn == 3 ) + { + for( ; i < len; i++, src += 3, dst += 3 ) + { + if( mask[i] ) + { + AT t0 = src[0]*a + dst[0]*b; + AT t1 = src[1]*a + dst[1]*b; + AT t2 = src[2]*a + dst[2]*b; + + dst[0] = t0; dst[1] = t1; dst[2] = t2; + } + } + } + else + { + for( ; i < len; i++, src += cn, dst += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + dst[k] = src[k]*a + dst[k]*b; + } + } +} + + +#define DEF_ACC_FUNCS(suffix, type, acctype) \ +static void acc_##suffix(const type* src, acctype* dst, \ + const uchar* mask, int len, int cn) \ +{ acc_(src, dst, mask, len, cn); } \ +\ +static void accSqr_##suffix(const type* src, acctype* dst, \ + const uchar* mask, int len, int cn) \ +{ accSqr_(src, dst, mask, len, cn); } \ +\ +static void accProd_##suffix(const type* src1, const type* src2, \ + acctype* dst, const uchar* mask, int len, int cn) \ +{ accProd_(src1, src2, dst, mask, len, cn); } \ +\ +static void accW_##suffix(const type* src, acctype* dst, \ + const uchar* mask, int len, int cn, double alpha) \ +{ accW_(src, dst, mask, len, cn, alpha); } + + +DEF_ACC_FUNCS(8u32f, uchar, float) +DEF_ACC_FUNCS(8u64f, uchar, double) +DEF_ACC_FUNCS(16u32f, ushort, float) +DEF_ACC_FUNCS(16u64f, ushort, double) +DEF_ACC_FUNCS(32f, float, float) +DEF_ACC_FUNCS(32f64f, float, double) +DEF_ACC_FUNCS(64f, double, double) + + +typedef void (*AccFunc)(const uchar*, uchar*, const uchar*, int, int); +typedef void (*AccProdFunc)(const uchar*, const uchar*, uchar*, const uchar*, int, int); +typedef void (*AccWFunc)(const uchar*, uchar*, const uchar*, int, int, double); + +static AccFunc accTab[] = +{ + (AccFunc)acc_8u32f, (AccFunc)acc_8u64f, + (AccFunc)acc_16u32f, (AccFunc)acc_16u64f, + (AccFunc)acc_32f, (AccFunc)acc_32f64f, + (AccFunc)acc_64f +}; + +static AccFunc accSqrTab[] = +{ + (AccFunc)accSqr_8u32f, (AccFunc)accSqr_8u64f, + (AccFunc)accSqr_16u32f, (AccFunc)accSqr_16u64f, + (AccFunc)accSqr_32f, (AccFunc)accSqr_32f64f, + (AccFunc)accSqr_64f +}; + +static AccProdFunc accProdTab[] = +{ + (AccProdFunc)accProd_8u32f, (AccProdFunc)accProd_8u64f, + (AccProdFunc)accProd_16u32f, (AccProdFunc)accProd_16u64f, + (AccProdFunc)accProd_32f, (AccProdFunc)accProd_32f64f, + (AccProdFunc)accProd_64f +}; + +static AccWFunc accWTab[] = +{ + (AccWFunc)accW_8u32f, (AccWFunc)accW_8u64f, + (AccWFunc)accW_16u32f, (AccWFunc)accW_16u64f, + (AccWFunc)accW_32f, (AccWFunc)accW_32f64f, + (AccWFunc)accW_64f +}; + +inline int getAccTabIdx(int sdepth, int ddepth) +{ + return sdepth == CV_8U && ddepth == CV_32F ? 0 : + sdepth == CV_8U && ddepth == CV_64F ? 1 : + sdepth == CV_16U && ddepth == CV_32F ? 2 : + sdepth == CV_16U && ddepth == CV_64F ? 3 : + sdepth == CV_32F && ddepth == CV_32F ? 4 : + sdepth == CV_32F && ddepth == CV_64F ? 5 : + sdepth == CV_64F && ddepth == CV_64F ? 6 : -1; +} + +} + +void cv::accumulate( InputArray _src, InputOutputArray _dst, InputArray _mask ) +{ + Mat src = _src.getMat(), dst = _dst.getMat(), mask = _mask.getMat(); + int sdepth = src.depth(), ddepth = dst.depth(), cn = src.channels(); + + CV_Assert( dst.size == src.size && dst.channels() == cn ); + CV_Assert( mask.empty() || (mask.size == src.size && mask.type() == CV_8U) ); + + int fidx = getAccTabIdx(sdepth, ddepth); + AccFunc func = fidx >= 0 ? accTab[fidx] : 0; + CV_Assert( func != 0 ); + + const Mat* arrays[] = {&src, &dst, &mask, 0}; + uchar* ptrs[3]; + NAryMatIterator it(arrays, ptrs); + int len = (int)it.size; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + func(ptrs[0], ptrs[1], ptrs[2], len, cn); +} + + +void cv::accumulateSquare( InputArray _src, InputOutputArray _dst, InputArray _mask ) +{ + Mat src = _src.getMat(), dst = _dst.getMat(), mask = _mask.getMat(); + int sdepth = src.depth(), ddepth = dst.depth(), cn = src.channels(); + + CV_Assert( dst.size == src.size && dst.channels() == cn ); + CV_Assert( mask.empty() || (mask.size == src.size && mask.type() == CV_8U) ); + + int fidx = getAccTabIdx(sdepth, ddepth); + AccFunc func = fidx >= 0 ? accSqrTab[fidx] : 0; + CV_Assert( func != 0 ); + + const Mat* arrays[] = {&src, &dst, &mask, 0}; + uchar* ptrs[3]; + NAryMatIterator it(arrays, ptrs); + int len = (int)it.size; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + func(ptrs[0], ptrs[1], ptrs[2], len, cn); +} + +void cv::accumulateProduct( InputArray _src1, InputArray _src2, + InputOutputArray _dst, InputArray _mask ) +{ + Mat src1 = _src1.getMat(), src2 = _src2.getMat(), dst = _dst.getMat(), mask = _mask.getMat(); + int sdepth = src1.depth(), ddepth = dst.depth(), cn = src1.channels(); + + CV_Assert( src2.size && src1.size && src2.type() == src1.type() ); + CV_Assert( dst.size == src1.size && dst.channels() == cn ); + CV_Assert( mask.empty() || (mask.size == src1.size && mask.type() == CV_8U) ); + + int fidx = getAccTabIdx(sdepth, ddepth); + AccProdFunc func = fidx >= 0 ? accProdTab[fidx] : 0; + CV_Assert( func != 0 ); + + const Mat* arrays[] = {&src1, &src2, &dst, &mask, 0}; + uchar* ptrs[4]; + NAryMatIterator it(arrays, ptrs); + int len = (int)it.size; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + func(ptrs[0], ptrs[1], ptrs[2], ptrs[3], len, cn); +} + + +void cv::accumulateWeighted( InputArray _src, InputOutputArray _dst, + double alpha, InputArray _mask ) +{ + Mat src = _src.getMat(), dst = _dst.getMat(), mask = _mask.getMat(); + int sdepth = src.depth(), ddepth = dst.depth(), cn = src.channels(); + + CV_Assert( dst.size == src.size && dst.channels() == cn ); + CV_Assert( mask.empty() || (mask.size == src.size && mask.type() == CV_8U) ); + + int fidx = getAccTabIdx(sdepth, ddepth); + AccWFunc func = fidx >= 0 ? accWTab[fidx] : 0; + CV_Assert( func != 0 ); + + const Mat* arrays[] = {&src, &dst, &mask, 0}; + uchar* ptrs[3]; + NAryMatIterator it(arrays, ptrs); + int len = (int)it.size; + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + func(ptrs[0], ptrs[1], ptrs[2], len, cn, alpha); +} + + +CV_IMPL void +cvAcc( const void* arr, void* sumarr, const void* maskarr ) +{ + cv::Mat src = cv::cvarrToMat(arr), dst = cv::cvarrToMat(sumarr), mask; + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::accumulate( src, dst, mask ); +} + +CV_IMPL void +cvSquareAcc( const void* arr, void* sumarr, const void* maskarr ) +{ + cv::Mat src = cv::cvarrToMat(arr), dst = cv::cvarrToMat(sumarr), mask; + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::accumulateSquare( src, dst, mask ); +} + +CV_IMPL void +cvMultiplyAcc( const void* arr1, const void* arr2, + void* sumarr, const void* maskarr ) +{ + cv::Mat src1 = cv::cvarrToMat(arr1), src2 = cv::cvarrToMat(arr2); + cv::Mat dst = cv::cvarrToMat(sumarr), mask; + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::accumulateProduct( src1, src2, dst, mask ); +} + +CV_IMPL void +cvRunningAvg( const void* arr, void* sumarr, double alpha, const void* maskarr ) +{ + cv::Mat src = cv::cvarrToMat(arr), dst = cv::cvarrToMat(sumarr), mask; + if( maskarr ) + mask = cv::cvarrToMat(maskarr); + cv::accumulateWeighted( src, dst, alpha, mask ); +} + +/* End of file. */ diff --git a/imgproc/src/approx.cpp b/imgproc/src/approx.cpp new file mode 100644 index 0000000..bd0e3da --- /dev/null +++ b/imgproc/src/approx.cpp @@ -0,0 +1,803 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +/****************************************************************************************\ +* Chain Approximation * +\****************************************************************************************/ + +typedef struct _CvPtInfo +{ + CvPoint pt; + int k; /* support region */ + int s; /* curvature value */ + struct _CvPtInfo *next; +} +_CvPtInfo; + + +/* curvature: 0 - 1-curvature, 1 - k-cosine curvature. */ +CvSeq* icvApproximateChainTC89( CvChain* chain, int header_size, + CvMemStorage* storage, int method ) +{ + static const int abs_diff[] = { 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1 }; + + cv::AutoBuffer<_CvPtInfo> buf(chain->total + 8); + + _CvPtInfo temp; + _CvPtInfo *array = buf, *first = 0, *current = 0, *prev_current = 0; + int i, j, i1, i2, s, len; + int count = chain->total; + + CvChainPtReader reader; + CvSeqWriter writer; + CvPoint pt = chain->origin; + + CV_Assert( CV_IS_SEQ_CHAIN_CONTOUR( chain )); + CV_Assert( header_size >= (int)sizeof(CvContour) ); + + cvStartWriteSeq( (chain->flags & ~CV_SEQ_ELTYPE_MASK) | CV_SEQ_ELTYPE_POINT, + header_size, sizeof( CvPoint ), storage, &writer ); + + if( chain->total == 0 ) + { + CV_WRITE_SEQ_ELEM( pt, writer ); + return cvEndWriteSeq( &writer ); + } + + cvStartReadChainPoints( chain, &reader ); + + temp.next = 0; + current = &temp; + + /* Pass 0. + Restores all the digital curve points from the chain code. + Removes the points (from the resultant polygon) + that have zero 1-curvature */ + for( i = 0; i < count; i++ ) + { + int prev_code = *reader.prev_elem; + + reader.prev_elem = reader.ptr; + CV_READ_CHAIN_POINT( pt, reader ); + + /* calc 1-curvature */ + s = abs_diff[reader.code - prev_code + 7]; + + if( method <= CV_CHAIN_APPROX_SIMPLE ) + { + if( method == CV_CHAIN_APPROX_NONE || s != 0 ) + { + CV_WRITE_SEQ_ELEM( pt, writer ); + } + } + else + { + if( s != 0 ) + current = current->next = array + i; + array[i].s = s; + array[i].pt = pt; + } + } + + //assert( pt.x == chain->origin.x && pt.y == chain->origin.y ); + + if( method <= CV_CHAIN_APPROX_SIMPLE ) + return cvEndWriteSeq( &writer ); + + current->next = 0; + + len = i; + current = temp.next; + + assert( current ); + + /* Pass 1. + Determines support region for all the remained points */ + do + { + CvPoint pt0; + int k, l = 0, d_num = 0; + + i = (int)(current - array); + pt0 = array[i].pt; + + /* determine support region */ + for( k = 1;; k++ ) + { + int lk, dk_num; + int dx, dy; + Cv32suf d; + + assert( k <= len ); + + /* calc indices */ + i1 = i - k; + i1 += i1 < 0 ? len : 0; + i2 = i + k; + i2 -= i2 >= len ? len : 0; + + dx = array[i2].pt.x - array[i1].pt.x; + dy = array[i2].pt.y - array[i1].pt.y; + + /* distance between p_(i - k) and p_(i + k) */ + lk = dx * dx + dy * dy; + + /* distance between p_i and the line (p_(i-k), p_(i+k)) */ + dk_num = (pt0.x - array[i1].pt.x) * dy - (pt0.y - array[i1].pt.y) * dx; + d.f = (float) (((double) d_num) * lk - ((double) dk_num) * l); + + if( k > 1 && (l >= lk || ((d_num > 0 && d.i <= 0) || (d_num < 0 && d.i >= 0)))) + break; + + d_num = dk_num; + l = lk; + } + + current->k = --k; + + /* determine cosine curvature if it should be used */ + if( method == CV_CHAIN_APPROX_TC89_KCOS ) + { + /* calc k-cosine curvature */ + for( j = k, s = 0; j > 0; j-- ) + { + double temp_num; + int dx1, dy1, dx2, dy2; + Cv32suf sk; + + i1 = i - j; + i1 += i1 < 0 ? len : 0; + i2 = i + j; + i2 -= i2 >= len ? len : 0; + + dx1 = array[i1].pt.x - pt0.x; + dy1 = array[i1].pt.y - pt0.y; + dx2 = array[i2].pt.x - pt0.x; + dy2 = array[i2].pt.y - pt0.y; + + if( (dx1 | dy1) == 0 || (dx2 | dy2) == 0 ) + break; + + temp_num = dx1 * dx2 + dy1 * dy2; + temp_num = + (float) (temp_num / + sqrt( ((double)dx1 * dx1 + (double)dy1 * dy1) * + ((double)dx2 * dx2 + (double)dy2 * dy2) )); + sk.f = (float) (temp_num + 1.1); + + assert( 0 <= sk.f && sk.f <= 2.2 ); + if( j < k && sk.i <= s ) + break; + + s = sk.i; + } + current->s = s; + } + current = current->next; + } + while( current != 0 ); + + prev_current = &temp; + current = temp.next; + + /* Pass 2. + Performs non-maxima supression */ + do + { + int k2 = current->k >> 1; + + s = current->s; + i = (int)(current - array); + + for( j = 1; j <= k2; j++ ) + { + i2 = i - j; + i2 += i2 < 0 ? len : 0; + + if( array[i2].s > s ) + break; + + i2 = i + j; + i2 -= i2 >= len ? len : 0; + + if( array[i2].s > s ) + break; + } + + if( j <= k2 ) /* exclude point */ + { + prev_current->next = current->next; + current->s = 0; /* "clear" point */ + } + else + prev_current = current; + current = current->next; + } + while( current != 0 ); + + /* Pass 3. + Removes non-dominant points with 1-length support region */ + current = temp.next; + assert( current ); + prev_current = &temp; + + do + { + if( current->k == 1 ) + { + s = current->s; + i = (int)(current - array); + + i1 = i - 1; + i1 += i1 < 0 ? len : 0; + + i2 = i + 1; + i2 -= i2 >= len ? len : 0; + + if( s <= array[i1].s || s <= array[i2].s ) + { + prev_current->next = current->next; + current->s = 0; + } + else + prev_current = current; + } + else + prev_current = current; + current = current->next; + } + while( current != 0 ); + + if( method == CV_CHAIN_APPROX_TC89_KCOS ) + goto copy_vect; + + /* Pass 4. + Cleans remained couples of points */ + assert( temp.next ); + + if( array[0].s != 0 && array[len - 1].s != 0 ) /* specific case */ + { + for( i1 = 1; i1 < len && array[i1].s != 0; i1++ ) + { + array[i1 - 1].s = 0; + } + if( i1 == len ) + goto copy_vect; /* all points survived */ + i1--; + + for( i2 = len - 2; i2 > 0 && array[i2].s != 0; i2-- ) + { + array[i2].next = 0; + array[i2 + 1].s = 0; + } + i2++; + + if( i1 == 0 && i2 == len - 1 ) /* only two points */ + { + i1 = (int)(array[0].next - array); + array[len] = array[0]; /* move to the end */ + array[len].next = 0; + array[len - 1].next = array + len; + } + temp.next = array + i1; + } + + current = temp.next; + first = prev_current = &temp; + count = 1; + + /* do last pass */ + do + { + if( current->next == 0 || current->next - current != 1 ) + { + if( count >= 2 ) + { + if( count == 2 ) + { + int s1 = prev_current->s; + int s2 = current->s; + + if( s1 > s2 || (s1 == s2 && prev_current->k <= current->k) ) + /* remove second */ + prev_current->next = current->next; + else + /* remove first */ + first->next = current; + } + else + first->next->next = current; + } + first = current; + count = 1; + } + else + count++; + prev_current = current; + current = current->next; + } + while( current != 0 ); + +copy_vect: + + // gather points + current = temp.next; + assert( current ); + + do + { + CV_WRITE_SEQ_ELEM( current->pt, writer ); + current = current->next; + } + while( current != 0 ); + + return cvEndWriteSeq( &writer ); +} + + +/*Applies some approximation algorithm to chain-coded contour(s) and + converts it/them to polygonal representation */ +CV_IMPL CvSeq* +cvApproxChains( CvSeq* src_seq, + CvMemStorage* storage, + int method, + double /*parameter*/, + int minimal_perimeter, + int recursive ) +{ + CvSeq *prev_contour = 0, *parent = 0; + CvSeq *dst_seq = 0; + + if( !src_seq || !storage ) + CV_Error( CV_StsNullPtr, "" ); + if( method > CV_CHAIN_APPROX_TC89_KCOS || method <= 0 || minimal_perimeter < 0 ) + CV_Error( CV_StsOutOfRange, "" ); + + while( src_seq != 0 ) + { + int len = src_seq->total; + + if( len >= minimal_perimeter ) + { + CvSeq *contour = 0; + + switch( method ) + { + case CV_CHAIN_APPROX_NONE: + case CV_CHAIN_APPROX_SIMPLE: + case CV_CHAIN_APPROX_TC89_L1: + case CV_CHAIN_APPROX_TC89_KCOS: + contour = icvApproximateChainTC89( (CvChain *) src_seq, sizeof( CvContour ), storage, method ); + break; + default: + CV_Error( CV_StsOutOfRange, "" ); + } + + if( contour->total > 0 ) + { + cvBoundingRect( contour, 1 ); + + contour->v_prev = parent; + contour->h_prev = prev_contour; + + if( prev_contour ) + prev_contour->h_next = contour; + else if( parent ) + parent->v_next = contour; + prev_contour = contour; + if( !dst_seq ) + dst_seq = prev_contour; + } + else /* if resultant contour has zero length, skip it */ + { + len = -1; + } + } + + if( !recursive ) + break; + + if( src_seq->v_next && len >= minimal_perimeter ) + { + assert( prev_contour != 0 ); + parent = prev_contour; + prev_contour = 0; + src_seq = src_seq->v_next; + } + else + { + while( src_seq->h_next == 0 ) + { + src_seq = src_seq->v_prev; + if( src_seq == 0 ) + break; + prev_contour = parent; + if( parent ) + parent = parent->v_prev; + } + if( src_seq ) + src_seq = src_seq->h_next; + } + } + + return dst_seq; +} + + +/****************************************************************************************\ +* Polygonal Approximation * +\****************************************************************************************/ + +/* Ramer-Douglas-Peucker algorithm for polygon simplification */ + +/* the version for integer point coordinates */ +template static CvSeq* +icvApproxPolyDP( CvSeq* src_contour, int header_size, + CvMemStorage* storage, double eps ) +{ + typedef cv::Point_ PT; + int init_iters = 3; + CvSlice slice = {0, 0}, right_slice = {0, 0}; + CvSeqReader reader, reader2; + CvSeqWriter writer; + PT start_pt(-1000000, -1000000), end_pt(0, 0), pt(0,0); + int i = 0, j, count = src_contour->total, new_count; + int is_closed = CV_IS_SEQ_CLOSED( src_contour ); + bool le_eps = false; + CvMemStorage* temp_storage = 0; + CvSeq* stack = 0; + CvSeq* dst_contour; + + assert( CV_SEQ_ELTYPE(src_contour) == cv::DataType::type ); + cvStartWriteSeq( src_contour->flags, header_size, sizeof(pt), storage, &writer ); + + if( src_contour->total == 0 ) + return cvEndWriteSeq( &writer ); + + temp_storage = cvCreateChildMemStorage( storage ); + + assert( src_contour->first != 0 ); + stack = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSlice), temp_storage ); + eps *= eps; + cvStartReadSeq( src_contour, &reader, 0 ); + + if( !is_closed ) + { + right_slice.start_index = count; + end_pt = *(PT*)(reader.ptr); + start_pt = *(PT*)cvGetSeqElem( src_contour, -1 ); + + if( start_pt.x != end_pt.x || start_pt.y != end_pt.y ) + { + slice.start_index = 0; + slice.end_index = count - 1; + cvSeqPush( stack, &slice ); + } + else + { + is_closed = 1; + init_iters = 1; + } + } + + if( is_closed ) + { + /* 1. Find approximately two farthest points of the contour */ + right_slice.start_index = 0; + + for( i = 0; i < init_iters; i++ ) + { + double dist, max_dist = 0; + cvSetSeqReaderPos( &reader, right_slice.start_index, 1 ); + CV_READ_SEQ_ELEM( start_pt, reader ); /* read the first point */ + + for( j = 1; j < count; j++ ) + { + double dx, dy; + + CV_READ_SEQ_ELEM( pt, reader ); + dx = pt.x - start_pt.x; + dy = pt.y - start_pt.y; + + dist = dx * dx + dy * dy; + + if( dist > max_dist ) + { + max_dist = dist; + right_slice.start_index = j; + } + } + + le_eps = max_dist <= eps; + } + + /* 2. initialize the stack */ + if( !le_eps ) + { + slice.start_index = cvGetSeqReaderPos( &reader ); + slice.end_index = right_slice.start_index += slice.start_index; + + right_slice.start_index -= right_slice.start_index >= count ? count : 0; + right_slice.end_index = slice.start_index; + if( right_slice.end_index < right_slice.start_index ) + right_slice.end_index += count; + + cvSeqPush( stack, &right_slice ); + cvSeqPush( stack, &slice ); + } + else + CV_WRITE_SEQ_ELEM( start_pt, writer ); + } + + /* 3. run recursive process */ + while( stack->total != 0 ) + { + cvSeqPop( stack, &slice ); + + cvSetSeqReaderPos( &reader, slice.end_index ); + CV_READ_SEQ_ELEM( end_pt, reader ); + + cvSetSeqReaderPos( &reader, slice.start_index ); + CV_READ_SEQ_ELEM( start_pt, reader ); + + if( slice.end_index > slice.start_index + 1 ) + { + double dx, dy, dist, max_dist = 0; + + dx = end_pt.x - start_pt.x; + dy = end_pt.y - start_pt.y; + + assert( dx != 0 || dy != 0 ); + + for( i = slice.start_index + 1; i < slice.end_index; i++ ) + { + CV_READ_SEQ_ELEM( pt, reader ); + dist = fabs((pt.y - start_pt.y) * dx - (pt.x - start_pt.x) * dy); + + if( dist > max_dist ) + { + max_dist = dist; + right_slice.start_index = i; + } + } + + le_eps = max_dist * max_dist <= eps * (dx * dx + dy * dy); + } + else + { + assert( slice.end_index > slice.start_index ); + le_eps = true; + /* read starting point */ + cvSetSeqReaderPos( &reader, slice.start_index ); + CV_READ_SEQ_ELEM( start_pt, reader ); + } + + if( le_eps ) + { + CV_WRITE_SEQ_ELEM( start_pt, writer ); + } + else + { + right_slice.end_index = slice.end_index; + slice.end_index = right_slice.start_index; + cvSeqPush( stack, &right_slice ); + cvSeqPush( stack, &slice ); + } + } + + is_closed = CV_IS_SEQ_CLOSED( src_contour ); + if( !is_closed ) + CV_WRITE_SEQ_ELEM( end_pt, writer ); + + dst_contour = cvEndWriteSeq( &writer ); + + // last stage: do final clean-up of the approximated contour - + // remove extra points on the [almost] stright lines. + + cvStartReadSeq( dst_contour, &reader, is_closed ); + CV_READ_SEQ_ELEM( start_pt, reader ); + + reader2 = reader; + CV_READ_SEQ_ELEM( pt, reader ); + + new_count = count = dst_contour->total; + for( i = !is_closed; i < count - !is_closed && new_count > 2; i++ ) + { + double dx, dy, dist; + CV_READ_SEQ_ELEM( end_pt, reader ); + + dx = end_pt.x - start_pt.x; + dy = end_pt.y - start_pt.y; + dist = fabs((pt.x - start_pt.x)*dy - (pt.y - start_pt.y)*dx); + if( dist * dist <= 0.5*eps*(dx*dx + dy*dy) && dx != 0 && dy != 0 ) + { + new_count--; + *((PT*)reader2.ptr) = start_pt = end_pt; + CV_NEXT_SEQ_ELEM( sizeof(pt), reader2 ); + CV_READ_SEQ_ELEM( pt, reader ); + i++; + continue; + } + *((PT*)reader2.ptr) = start_pt = pt; + CV_NEXT_SEQ_ELEM( sizeof(pt), reader2 ); + pt = end_pt; + } + + if( !is_closed ) + *((PT*)reader2.ptr) = pt; + + if( new_count < count ) + cvSeqPopMulti( dst_contour, 0, count - new_count ); + + cvReleaseMemStorage( &temp_storage ); + return dst_contour; +} + + +CV_IMPL CvSeq* +cvApproxPoly( const void* array, int header_size, + CvMemStorage* storage, int method, + double parameter, int parameter2 ) +{ + CvSeq* dst_seq = 0; + CvSeq *prev_contour = 0, *parent = 0; + CvContour contour_header; + CvSeq* src_seq = 0; + CvSeqBlock block; + int recursive = 0; + + if( CV_IS_SEQ( array )) + { + src_seq = (CvSeq*)array; + if( !CV_IS_SEQ_POLYLINE( src_seq )) + CV_Error( CV_StsBadArg, "Unsupported sequence type" ); + + recursive = parameter2; + + if( !storage ) + storage = src_seq->storage; + } + else + { + src_seq = cvPointSeqFromMat( + CV_SEQ_KIND_CURVE | (parameter2 ? CV_SEQ_FLAG_CLOSED : 0), + array, &contour_header, &block ); + } + + if( !storage ) + CV_Error( CV_StsNullPtr, "NULL storage pointer " ); + + if( header_size < 0 ) + CV_Error( CV_StsOutOfRange, "header_size is negative. " + "Pass 0 to make the destination header_size == input header_size" ); + + if( header_size == 0 ) + header_size = src_seq->header_size; + + if( !CV_IS_SEQ_POLYLINE( src_seq )) + { + if( CV_IS_SEQ_CHAIN( src_seq )) + { + CV_Error( CV_StsBadArg, "Input curves are not polygonal. " + "Use cvApproxChains first" ); + } + else + { + CV_Error( CV_StsBadArg, "Input curves have uknown type" ); + } + } + + if( header_size == 0 ) + header_size = src_seq->header_size; + + if( header_size < (int)sizeof(CvContour) ) + CV_Error( CV_StsBadSize, "New header size must be non-less than sizeof(CvContour)" ); + + if( method != CV_POLY_APPROX_DP ) + CV_Error( CV_StsOutOfRange, "Unknown approximation method" ); + + while( src_seq != 0 ) + { + CvSeq *contour = 0; + + switch (method) + { + case CV_POLY_APPROX_DP: + if( parameter < 0 ) + CV_Error( CV_StsOutOfRange, "Accuracy must be non-negative" ); + + if( CV_SEQ_ELTYPE(src_seq) == CV_32SC2 ) + contour = icvApproxPolyDP( src_seq, header_size, storage, parameter ); + else + contour = icvApproxPolyDP( src_seq, header_size, storage, parameter ); + break; + default: + assert(0); + CV_Error( CV_StsBadArg, "Invalid approximation method" ); + } + + assert( contour ); + + if( header_size >= (int)sizeof(CvContour)) + cvBoundingRect( contour, 1 ); + + contour->v_prev = parent; + contour->h_prev = prev_contour; + + if( prev_contour ) + prev_contour->h_next = contour; + else if( parent ) + parent->v_next = contour; + prev_contour = contour; + if( !dst_seq ) + dst_seq = prev_contour; + + if( !recursive ) + break; + + if( src_seq->v_next ) + { + assert( prev_contour != 0 ); + parent = prev_contour; + prev_contour = 0; + src_seq = src_seq->v_next; + } + else + { + while( src_seq->h_next == 0 ) + { + src_seq = src_seq->v_prev; + if( src_seq == 0 ) + break; + prev_contour = parent; + if( parent ) + parent = parent->v_prev; + } + if( src_seq ) + src_seq = src_seq->h_next; + } + } + + return dst_seq; +} + +/* End of file. */ diff --git a/imgproc/src/canny.cpp b/imgproc/src/canny.cpp new file mode 100644 index 0000000..c6da708 --- /dev/null +++ b/imgproc/src/canny.cpp @@ -0,0 +1,288 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +void cv::Canny( InputArray _src, OutputArray _dst, + double low_thresh, double high_thresh, + int aperture_size, bool L2gradient ) +{ + Mat src = _src.getMat(); + CV_Assert( src.depth() == CV_8U ); + + _dst.create(src.size(), CV_8U); + Mat dst = _dst.getMat(); + + if (!L2gradient && (aperture_size & CV_CANNY_L2_GRADIENT) == CV_CANNY_L2_GRADIENT) + { + //backward compatibility + aperture_size &= ~CV_CANNY_L2_GRADIENT; + L2gradient = true; + } + + if ((aperture_size & 1) == 0 || (aperture_size != -1 && (aperture_size < 3 || aperture_size > 7))) + CV_Error(CV_StsBadFlag, ""); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if (tegra::canny(src, dst, low_thresh, high_thresh, aperture_size, L2gradient)) + return; +#endif + + const int cn = src.channels(); + cv::Mat dx(src.rows, src.cols, CV_16SC(cn)); + cv::Mat dy(src.rows, src.cols, CV_16SC(cn)); + + cv::Sobel(src, dx, CV_16S, 1, 0, aperture_size, 1, 0, cv::BORDER_REPLICATE); + cv::Sobel(src, dy, CV_16S, 0, 1, aperture_size, 1, 0, cv::BORDER_REPLICATE); + + if (low_thresh > high_thresh) + std::swap(low_thresh, high_thresh); + + if (L2gradient) + { + low_thresh = std::min(32767.0, low_thresh); + high_thresh = std::min(32767.0, high_thresh); + + if (low_thresh > 0) low_thresh *= low_thresh; + if (high_thresh > 0) high_thresh *= high_thresh; + } + int low = cvFloor(low_thresh); + int high = cvFloor(high_thresh); + + ptrdiff_t mapstep = src.cols + 2; + cv::AutoBuffer buffer((src.cols+2)*(src.rows+2) + cn * mapstep * 3 * sizeof(int)); + + int* mag_buf[3]; + mag_buf[0] = (int*)(uchar*)buffer; + mag_buf[1] = mag_buf[0] + mapstep*cn; + mag_buf[2] = mag_buf[1] + mapstep*cn; + memset(mag_buf[0], 0, /* cn* */mapstep*sizeof(int)); + + uchar* map = (uchar*)(mag_buf[2] + mapstep*cn); + memset(map, 1, mapstep); + memset(map + mapstep*(src.rows + 1), 1, mapstep); + + int maxsize = std::max(1 << 10, src.cols * src.rows / 10); + std::vector stack(maxsize); + uchar **stack_top = &stack[0]; + uchar **stack_bottom = &stack[0]; + + /* sector numbers + (Top-Left Origin) + + 1 2 3 + * * * + * * * + 0*******0 + * * * + * * * + 3 2 1 + */ + + #define CANNY_PUSH(d) *(d) = uchar(2), *stack_top++ = (d) + #define CANNY_POP(d) (d) = *--stack_top + + // calculate magnitude and angle of gradient, perform non-maxima supression. + // fill the map with one of the following values: + // 0 - the pixel might belong to an edge + // 1 - the pixel can not belong to an edge + // 2 - the pixel does belong to an edge + for (int i = 0; i <= src.rows; i++) + { + int* _norm = mag_buf[(i > 0) + 1] + 1; + if (i < src.rows) + { + short* _dx = dx.ptr(i); + short* _dy = dy.ptr(i); + + if (!L2gradient) + { + for (int j = 0; j < src.cols*cn; j++) + _norm[j] = std::abs(int(_dx[j])) + std::abs(int(_dy[j])); + } + else + { + for (int j = 0; j < src.cols*cn; j++) + _norm[j] = int(_dx[j])*_dx[j] + int(_dy[j])*_dy[j]; + } + + if (cn > 1) + { + for(int j = 0, jn = 0; j < src.cols; ++j, jn += cn) + { + int maxIdx = jn; + for(int k = 1; k < cn; ++k) + if(_norm[jn + k] > _norm[maxIdx]) maxIdx = jn + k; + _norm[j] = _norm[maxIdx]; + _dx[j] = _dx[maxIdx]; + _dy[j] = _dy[maxIdx]; + } + } + _norm[-1] = _norm[src.cols] = 0; + } + else + memset(_norm-1, 0, /* cn* */mapstep*sizeof(int)); + + // at the very beginning we do not have a complete ring + // buffer of 3 magnitude rows for non-maxima suppression + if (i == 0) + continue; + + uchar* _map = map + mapstep*i + 1; + _map[-1] = _map[src.cols] = 1; + + int* _mag = mag_buf[1] + 1; // take the central row + ptrdiff_t magstep1 = mag_buf[2] - mag_buf[1]; + ptrdiff_t magstep2 = mag_buf[0] - mag_buf[1]; + + const short* _x = dx.ptr(i-1); + const short* _y = dy.ptr(i-1); + + if ((stack_top - stack_bottom) + src.cols > maxsize) + { + int sz = (int)(stack_top - stack_bottom); + maxsize = maxsize * 3/2; + stack.resize(maxsize); + stack_bottom = &stack[0]; + stack_top = stack_bottom + sz; + } + + int prev_flag = 0; + for (int j = 0; j < src.cols; j++) + { + #define CANNY_SHIFT 15 + const int TG22 = (int)(0.4142135623730950488016887242097*(1< low) + { + int xs = _x[j]; + int ys = _y[j]; + int x = std::abs(xs); + int y = std::abs(ys) << CANNY_SHIFT; + + int tg22x = x * TG22; + + if (y < tg22x) + { + if (m > _mag[j-1] && m >= _mag[j+1]) goto __ocv_canny_push; + } + else + { + int tg67x = tg22x + (x << (CANNY_SHIFT+1)); + if (y > tg67x) + { + if (m > _mag[j+magstep2] && m >= _mag[j+magstep1]) goto __ocv_canny_push; + } + else + { + int s = (xs ^ ys) < 0 ? -1 : 1; + if (m > _mag[j+magstep2-s] && m > _mag[j+magstep1+s]) goto __ocv_canny_push; + } + } + } + prev_flag = 0; + _map[j] = uchar(1); + continue; +__ocv_canny_push: + if (!prev_flag && m > high && _map[j-mapstep] != 2) + { + CANNY_PUSH(_map + j); + prev_flag = 1; + } + else + _map[j] = 0; + } + + // scroll the ring buffer + _mag = mag_buf[0]; + mag_buf[0] = mag_buf[1]; + mag_buf[1] = mag_buf[2]; + mag_buf[2] = _mag; + } + + // now track the edges (hysteresis thresholding) + while (stack_top > stack_bottom) + { + uchar* m; + if ((stack_top - stack_bottom) + 8 > maxsize) + { + int sz = (int)(stack_top - stack_bottom); + maxsize = maxsize * 3/2; + stack.resize(maxsize); + stack_bottom = &stack[0]; + stack_top = stack_bottom + sz; + } + + CANNY_POP(m); + + if (!m[-1]) CANNY_PUSH(m - 1); + if (!m[1]) CANNY_PUSH(m + 1); + if (!m[-mapstep-1]) CANNY_PUSH(m - mapstep - 1); + if (!m[-mapstep]) CANNY_PUSH(m - mapstep); + if (!m[-mapstep+1]) CANNY_PUSH(m - mapstep + 1); + if (!m[mapstep-1]) CANNY_PUSH(m + mapstep - 1); + if (!m[mapstep]) CANNY_PUSH(m + mapstep); + if (!m[mapstep+1]) CANNY_PUSH(m + mapstep + 1); + } + + // the final pass, form the final image + const uchar* pmap = map + mapstep + 1; + uchar* pdst = dst.ptr(); + for (int i = 0; i < src.rows; i++, pmap += mapstep, pdst += dst.step) + { + for (int j = 0; j < src.cols; j++) + pdst[j] = (uchar)-(pmap[j] >> 1); + } +} + +void cvCanny( const CvArr* image, CvArr* edges, double threshold1, + double threshold2, int aperture_size ) +{ + cv::Mat src = cv::cvarrToMat(image), dst = cv::cvarrToMat(edges); + CV_Assert( src.size == dst.size && src.depth() == CV_8U && dst.type() == CV_8U ); + + cv::Canny(src, dst, threshold1, threshold2, aperture_size & 255, + (aperture_size & CV_CANNY_L2_GRADIENT) != 0); +} + +/* End of file. */ diff --git a/imgproc/src/color.cpp b/imgproc/src/color.cpp new file mode 100644 index 0000000..8739e42 --- /dev/null +++ b/imgproc/src/color.cpp @@ -0,0 +1,3742 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2010, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +/********************************* COPYRIGHT NOTICE *******************************\ + The function for RGB to Lab conversion is based on the MATLAB script + RGB2Lab.m translated by Mark Ruzon from C code by Yossi Rubner, 23 September 1997. + See the page [http://vision.stanford.edu/~ruzon/software/rgblab.html] +\**********************************************************************************/ + +/********************************* COPYRIGHT NOTICE *******************************\ + Original code for Bayer->BGR/RGB conversion is provided by Dirk Schaefer + from MD-Mathematische Dienste GmbH. Below is the copyright notice: + + IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + By downloading, copying, installing or using the software you agree + to this license. If you do not agree to this license, do not download, + install, copy or use the software. + + Contributors License Agreement: + + Copyright (c) 2002, + MD-Mathematische Dienste GmbH + Im Defdahl 5-10 + 44141 Dortmund + Germany + www.md-it.de + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided + that the following conditions are met: + + Redistributions of source code must retain + the above copyright notice, this list of conditions and the following disclaimer. + 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. + The name of Contributor may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 CONTRIBUTORS 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. +\**********************************************************************************/ + +#include "precomp.hpp" +#include +#include + +namespace cv +{ + +// computes cubic spline coefficients for a function: (xi=i, yi=f[i]), i=0..n +template static void splineBuild(const _Tp* f, int n, _Tp* tab) +{ + _Tp cn = 0; + int i; + tab[0] = tab[1] = (_Tp)0; + + for(i = 1; i < n-1; i++) + { + _Tp t = 3*(f[i+1] - 2*f[i] + f[i-1]); + _Tp l = 1/(4 - tab[(i-1)*4]); + tab[i*4] = l; tab[i*4+1] = (t - tab[(i-1)*4+1])*l; + } + + for(i = n-1; i >= 0; i--) + { + _Tp c = tab[i*4+1] - tab[i*4]*cn; + _Tp b = f[i+1] - f[i] - (cn + c*2)*(_Tp)0.3333333333333333; + _Tp d = (cn - c)*(_Tp)0.3333333333333333; + tab[i*4] = f[i]; tab[i*4+1] = b; + tab[i*4+2] = c; tab[i*4+3] = d; + cn = c; + } +} + +// interpolates value of a function at x, 0 <= x <= n using a cubic spline. +template static inline _Tp splineInterpolate(_Tp x, const _Tp* tab, int n) +{ + int ix = cvFloor(x); + ix = std::min(std::max(ix, 0), n-1); + x -= ix; + tab += ix*4; + return ((tab[3]*x + tab[2])*x + tab[1])*x + tab[0]; +} + + +template struct ColorChannel +{ + typedef float worktype_f; + static _Tp max() { return std::numeric_limits<_Tp>::max(); } + static _Tp half() { return (_Tp)(max()/2 + 1); } +}; + +template<> struct ColorChannel +{ + typedef float worktype_f; + static float max() { return 1.f; } + static float half() { return 0.5f; } +}; + +/*template<> struct ColorChannel +{ + typedef double worktype_f; + static double max() { return 1.; } + static double half() { return 0.5; } +};*/ + + +///////////////////////////// Top-level template function //////////////////////////////// + +template void CvtColorLoop(const Mat& srcmat, Mat& dstmat, const Cvt& cvt) +{ + typedef typename Cvt::channel_type _Tp; + Size sz = srcmat.size(); + const uchar* src = srcmat.data; + uchar* dst = dstmat.data; + size_t srcstep = srcmat.step, dststep = dstmat.step; + + if( srcmat.isContinuous() && dstmat.isContinuous() ) + { + sz.width *= sz.height; + sz.height = 1; + } + + for( ; sz.height--; src += srcstep, dst += dststep ) + cvt((const _Tp*)src, (_Tp*)dst, sz.width); +} + + +////////////////// Various 3/4-channel to 3/4-channel RGB transformations ///////////////// + +template struct RGB2RGB +{ + typedef _Tp channel_type; + + RGB2RGB(int _srccn, int _dstcn, int _blueIdx) : srccn(_srccn), dstcn(_dstcn), blueIdx(_blueIdx) {} + void operator()(const _Tp* src, _Tp* dst, int n) const + { + int scn = srccn, dcn = dstcn, bidx = blueIdx; + if( dcn == 3 ) + { + n *= 3; + for( int i = 0; i < n; i += 3, src += scn ) + { + _Tp t0 = src[bidx], t1 = src[1], t2 = src[bidx ^ 2]; + dst[i] = t0; dst[i+1] = t1; dst[i+2] = t2; + } + } + else if( scn == 3 ) + { + n *= 3; + _Tp alpha = ColorChannel<_Tp>::max(); + for( int i = 0; i < n; i += 3, dst += 4 ) + { + _Tp t0 = src[i], t1 = src[i+1], t2 = src[i+2]; + dst[bidx] = t0; dst[1] = t1; dst[bidx^2] = t2; dst[3] = alpha; + } + } + else + { + n *= 4; + for( int i = 0; i < n; i += 4 ) + { + _Tp t0 = src[i], t1 = src[i+1], t2 = src[i+2], t3 = src[i+3]; + dst[i] = t2; dst[i+1] = t1; dst[i+2] = t0; dst[i+3] = t3; + } + } + } + + int srccn, dstcn, blueIdx; +}; + +/////////// Transforming 16-bit (565 or 555) RGB to/from 24/32-bit (888[8]) RGB ////////// + +struct RGB5x52RGB +{ + typedef uchar channel_type; + + RGB5x52RGB(int _dstcn, int _blueIdx, int _greenBits) + : dstcn(_dstcn), blueIdx(_blueIdx), greenBits(_greenBits) {} + + void operator()(const uchar* src, uchar* dst, int n) const + { + int dcn = dstcn, bidx = blueIdx; + if( greenBits == 6 ) + for( int i = 0; i < n; i++, dst += dcn ) + { + unsigned t = ((const ushort*)src)[i]; + dst[bidx] = (uchar)(t << 3); + dst[1] = (uchar)((t >> 3) & ~3); + dst[bidx ^ 2] = (uchar)((t >> 8) & ~7); + if( dcn == 4 ) + dst[3] = 255; + } + else + for( int i = 0; i < n; i++, dst += dcn ) + { + unsigned t = ((const ushort*)src)[i]; + dst[bidx] = (uchar)(t << 3); + dst[1] = (uchar)((t >> 2) & ~7); + dst[bidx ^ 2] = (uchar)((t >> 7) & ~7); + if( dcn == 4 ) + dst[3] = t & 0x8000 ? 255 : 0; + } + } + + int dstcn, blueIdx, greenBits; +}; + + +struct RGB2RGB5x5 +{ + typedef uchar channel_type; + + RGB2RGB5x5(int _srccn, int _blueIdx, int _greenBits) + : srccn(_srccn), blueIdx(_blueIdx), greenBits(_greenBits) {} + + void operator()(const uchar* src, uchar* dst, int n) const + { + int scn = srccn, bidx = blueIdx; + if( greenBits == 6 ) + for( int i = 0; i < n; i++, src += scn ) + { + ((ushort*)dst)[i] = (ushort)((src[bidx] >> 3)|((src[1]&~3) << 3)|((src[bidx^2]&~7) << 8)); + } + else if( scn == 3 ) + for( int i = 0; i < n; i++, src += 3 ) + { + ((ushort*)dst)[i] = (ushort)((src[bidx] >> 3)|((src[1]&~7) << 2)|((src[bidx^2]&~7) << 7)); + } + else + for( int i = 0; i < n; i++, src += 4 ) + { + ((ushort*)dst)[i] = (ushort)((src[bidx] >> 3)|((src[1]&~7) << 2)| + ((src[bidx^2]&~7) << 7)|(src[3] ? 0x8000 : 0)); + } + } + + int srccn, blueIdx, greenBits; +}; + +///////////////////////////////// Color to/from Grayscale //////////////////////////////// + +template +struct Gray2RGB +{ + typedef _Tp channel_type; + + Gray2RGB(int _dstcn) : dstcn(_dstcn) {} + void operator()(const _Tp* src, _Tp* dst, int n) const + { + if( dstcn == 3 ) + for( int i = 0; i < n; i++, dst += 3 ) + { + dst[0] = dst[1] = dst[2] = src[i]; + } + else + { + _Tp alpha = ColorChannel<_Tp>::max(); + for( int i = 0; i < n; i++, dst += 4 ) + { + dst[0] = dst[1] = dst[2] = src[i]; + dst[3] = alpha; + } + } + } + + int dstcn; +}; + + +struct Gray2RGB5x5 +{ + typedef uchar channel_type; + + Gray2RGB5x5(int _greenBits) : greenBits(_greenBits) {} + void operator()(const uchar* src, uchar* dst, int n) const + { + if( greenBits == 6 ) + for( int i = 0; i < n; i++ ) + { + int t = src[i]; + ((ushort*)dst)[i] = (ushort)((t >> 3)|((t & ~3) << 3)|((t & ~7) << 8)); + } + else + for( int i = 0; i < n; i++ ) + { + int t = src[i] >> 3; + ((ushort*)dst)[i] = (ushort)(t|(t << 5)|(t << 10)); + } + } + int greenBits; +}; + + +#undef R2Y +#undef G2Y +#undef B2Y + +enum +{ + yuv_shift = 14, + xyz_shift = 12, + R2Y = 4899, + G2Y = 9617, + B2Y = 1868, + BLOCK_SIZE = 256 +}; + + +struct RGB5x52Gray +{ + typedef uchar channel_type; + + RGB5x52Gray(int _greenBits) : greenBits(_greenBits) {} + void operator()(const uchar* src, uchar* dst, int n) const + { + if( greenBits == 6 ) + for( int i = 0; i < n; i++ ) + { + int t = ((ushort*)src)[i]; + dst[i] = (uchar)CV_DESCALE(((t << 3) & 0xf8)*B2Y + + ((t >> 3) & 0xfc)*G2Y + + ((t >> 8) & 0xf8)*R2Y, yuv_shift); + } + else + for( int i = 0; i < n; i++ ) + { + int t = ((ushort*)src)[i]; + dst[i] = (uchar)CV_DESCALE(((t << 3) & 0xf8)*B2Y + + ((t >> 2) & 0xf8)*G2Y + + ((t >> 7) & 0xf8)*R2Y, yuv_shift); + } + } + int greenBits; +}; + + +template struct RGB2Gray +{ + typedef _Tp channel_type; + + RGB2Gray(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn) + { + static const float coeffs0[] = { 0.299f, 0.587f, 0.114f }; + memcpy( coeffs, _coeffs ? _coeffs : coeffs0, 3*sizeof(coeffs[0]) ); + if(blueIdx == 0) + std::swap(coeffs[0], coeffs[2]); + } + + void operator()(const _Tp* src, _Tp* dst, int n) const + { + int scn = srccn; + float cb = coeffs[0], cg = coeffs[1], cr = coeffs[2]; + for(int i = 0; i < n; i++, src += scn) + dst[i] = saturate_cast<_Tp>(src[0]*cb + src[1]*cg + src[2]*cr); + } + int srccn; + float coeffs[3]; +}; + + +template<> struct RGB2Gray +{ + typedef uchar channel_type; + + RGB2Gray(int _srccn, int blueIdx, const int* coeffs) : srccn(_srccn) + { + const int coeffs0[] = { R2Y, G2Y, B2Y }; + if(!coeffs) coeffs = coeffs0; + + int b = 0, g = 0, r = (1 << (yuv_shift-1)); + int db = coeffs[blueIdx^2], dg = coeffs[1], dr = coeffs[blueIdx]; + + for( int i = 0; i < 256; i++, b += db, g += dg, r += dr ) + { + tab[i] = b; + tab[i+256] = g; + tab[i+512] = r; + } + } + void operator()(const uchar* src, uchar* dst, int n) const + { + int scn = srccn; + const int* _tab = tab; + for(int i = 0; i < n; i++, src += scn) + dst[i] = (uchar)((_tab[src[0]] + _tab[src[1]+256] + _tab[src[2]+512]) >> yuv_shift); + } + int srccn; + int tab[256*3]; +}; + + +template<> struct RGB2Gray +{ + typedef ushort channel_type; + + RGB2Gray(int _srccn, int blueIdx, const int* _coeffs) : srccn(_srccn) + { + static const int coeffs0[] = { R2Y, G2Y, B2Y }; + memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 3*sizeof(coeffs[0])); + if( blueIdx == 0 ) + std::swap(coeffs[0], coeffs[2]); + } + + void operator()(const ushort* src, ushort* dst, int n) const + { + int scn = srccn, cb = coeffs[0], cg = coeffs[1], cr = coeffs[2]; + for(int i = 0; i < n; i++, src += scn) + dst[i] = (ushort)CV_DESCALE((unsigned)(src[0]*cb + src[1]*cg + src[2]*cr), yuv_shift); + } + int srccn; + int coeffs[3]; +}; + + +///////////////////////////////////// RGB <-> YCrCb ////////////////////////////////////// + +template struct RGB2YCrCb_f +{ + typedef _Tp channel_type; + + RGB2YCrCb_f(int _srccn, int _blueIdx, const float* _coeffs) : srccn(_srccn), blueIdx(_blueIdx) + { + static const float coeffs0[] = {0.299f, 0.587f, 0.114f, 0.713f, 0.564f}; + memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5*sizeof(coeffs[0])); + if(blueIdx==0) std::swap(coeffs[0], coeffs[2]); + } + + void operator()(const _Tp* src, _Tp* dst, int n) const + { + int scn = srccn, bidx = blueIdx; + const _Tp delta = ColorChannel<_Tp>::half(); + float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4]; + n *= 3; + for(int i = 0; i < n; i += 3, src += scn) + { + _Tp Y = saturate_cast<_Tp>(src[0]*C0 + src[1]*C1 + src[2]*C2); + _Tp Cr = saturate_cast<_Tp>((src[bidx^2] - Y)*C3 + delta); + _Tp Cb = saturate_cast<_Tp>((src[bidx] - Y)*C4 + delta); + dst[i] = Y; dst[i+1] = Cr; dst[i+2] = Cb; + } + } + int srccn, blueIdx; + float coeffs[5]; +}; + + +template struct RGB2YCrCb_i +{ + typedef _Tp channel_type; + + RGB2YCrCb_i(int _srccn, int _blueIdx, const int* _coeffs) + : srccn(_srccn), blueIdx(_blueIdx) + { + static const int coeffs0[] = {R2Y, G2Y, B2Y, 11682, 9241}; + memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5*sizeof(coeffs[0])); + if(blueIdx==0) std::swap(coeffs[0], coeffs[2]); + } + void operator()(const _Tp* src, _Tp* dst, int n) const + { + int scn = srccn, bidx = blueIdx; + int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4]; + int delta = ColorChannel<_Tp>::half()*(1 << yuv_shift); + n *= 3; + for(int i = 0; i < n; i += 3, src += scn) + { + int Y = CV_DESCALE(src[0]*C0 + src[1]*C1 + src[2]*C2, yuv_shift); + int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, yuv_shift); + int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift); + dst[i] = saturate_cast<_Tp>(Y); + dst[i+1] = saturate_cast<_Tp>(Cr); + dst[i+2] = saturate_cast<_Tp>(Cb); + } + } + int srccn, blueIdx; + int coeffs[5]; +}; + + +template struct YCrCb2RGB_f +{ + typedef _Tp channel_type; + + YCrCb2RGB_f(int _dstcn, int _blueIdx, const float* _coeffs) + : dstcn(_dstcn), blueIdx(_blueIdx) + { + static const float coeffs0[] = {1.403f, -0.714f, -0.344f, 1.773f}; + memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 4*sizeof(coeffs[0])); + } + void operator()(const _Tp* src, _Tp* dst, int n) const + { + int dcn = dstcn, bidx = blueIdx; + const _Tp delta = ColorChannel<_Tp>::half(), alpha = ColorChannel<_Tp>::max(); + float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3]; + n *= 3; + for(int i = 0; i < n; i += 3, dst += dcn) + { + _Tp Y = src[i]; + _Tp Cr = src[i+1]; + _Tp Cb = src[i+2]; + + _Tp b = saturate_cast<_Tp>(Y + (Cb - delta)*C3); + _Tp g = saturate_cast<_Tp>(Y + (Cb - delta)*C2 + (Cr - delta)*C1); + _Tp r = saturate_cast<_Tp>(Y + (Cr - delta)*C0); + + dst[bidx] = b; dst[1] = g; dst[bidx^2] = r; + if( dcn == 4 ) + dst[3] = alpha; + } + } + int dstcn, blueIdx; + float coeffs[4]; +}; + + +template struct YCrCb2RGB_i +{ + typedef _Tp channel_type; + + YCrCb2RGB_i(int _dstcn, int _blueIdx, const int* _coeffs) + : dstcn(_dstcn), blueIdx(_blueIdx) + { + static const int coeffs0[] = {22987, -11698, -5636, 29049}; + memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 4*sizeof(coeffs[0])); + } + + void operator()(const _Tp* src, _Tp* dst, int n) const + { + int dcn = dstcn, bidx = blueIdx; + const _Tp delta = ColorChannel<_Tp>::half(), alpha = ColorChannel<_Tp>::max(); + int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3]; + n *= 3; + for(int i = 0; i < n; i += 3, dst += dcn) + { + _Tp Y = src[i]; + _Tp Cr = src[i+1]; + _Tp Cb = src[i+2]; + + int b = Y + CV_DESCALE((Cb - delta)*C3, yuv_shift); + int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, yuv_shift); + int r = Y + CV_DESCALE((Cr - delta)*C0, yuv_shift); + + dst[bidx] = saturate_cast<_Tp>(b); + dst[1] = saturate_cast<_Tp>(g); + dst[bidx^2] = saturate_cast<_Tp>(r); + if( dcn == 4 ) + dst[3] = alpha; + } + } + int dstcn, blueIdx; + int coeffs[4]; +}; + + +////////////////////////////////////// RGB <-> XYZ /////////////////////////////////////// + +static const float sRGB2XYZ_D65[] = +{ + 0.412453f, 0.357580f, 0.180423f, + 0.212671f, 0.715160f, 0.072169f, + 0.019334f, 0.119193f, 0.950227f +}; + +static const float XYZ2sRGB_D65[] = +{ + 3.240479f, -1.53715f, -0.498535f, + -0.969256f, 1.875991f, 0.041556f, + 0.055648f, -0.204043f, 1.057311f +}; + +template struct RGB2XYZ_f +{ + typedef _Tp channel_type; + + RGB2XYZ_f(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn) + { + memcpy(coeffs, _coeffs ? _coeffs : sRGB2XYZ_D65, 9*sizeof(coeffs[0])); + if(blueIdx == 0) + { + std::swap(coeffs[0], coeffs[2]); + std::swap(coeffs[3], coeffs[5]); + std::swap(coeffs[6], coeffs[8]); + } + } + void operator()(const _Tp* src, _Tp* dst, int n) const + { + int scn = srccn; + float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], + C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5], + C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8]; + + n *= 3; + for(int i = 0; i < n; i += 3, src += scn) + { + _Tp X = saturate_cast<_Tp>(src[0]*C0 + src[1]*C1 + src[2]*C2); + _Tp Y = saturate_cast<_Tp>(src[0]*C3 + src[1]*C4 + src[2]*C5); + _Tp Z = saturate_cast<_Tp>(src[0]*C6 + src[1]*C7 + src[2]*C8); + dst[i] = X; dst[i+1] = Y; dst[i+2] = Z; + } + } + int srccn; + float coeffs[9]; +}; + + +template struct RGB2XYZ_i +{ + typedef _Tp channel_type; + + RGB2XYZ_i(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn) + { + static const int coeffs0[] = + { + 1689, 1465, 739, + 871, 2929, 296, + 79, 488, 3892 + }; + for( int i = 0; i < 9; i++ ) + coeffs[i] = _coeffs ? cvRound(_coeffs[i]*(1 << xyz_shift)) : coeffs0[i]; + if(blueIdx == 0) + { + std::swap(coeffs[0], coeffs[2]); + std::swap(coeffs[3], coeffs[5]); + std::swap(coeffs[6], coeffs[8]); + } + } + void operator()(const _Tp* src, _Tp* dst, int n) const + { + int scn = srccn; + int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], + C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5], + C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8]; + n *= 3; + for(int i = 0; i < n; i += 3, src += scn) + { + int X = CV_DESCALE(src[0]*C0 + src[1]*C1 + src[2]*C2, xyz_shift); + int Y = CV_DESCALE(src[0]*C3 + src[1]*C4 + src[2]*C5, xyz_shift); + int Z = CV_DESCALE(src[0]*C6 + src[1]*C7 + src[2]*C8, xyz_shift); + dst[i] = saturate_cast<_Tp>(X); dst[i+1] = saturate_cast<_Tp>(Y); + dst[i+2] = saturate_cast<_Tp>(Z); + } + } + int srccn; + int coeffs[9]; +}; + + +template struct XYZ2RGB_f +{ + typedef _Tp channel_type; + + XYZ2RGB_f(int _dstcn, int _blueIdx, const float* _coeffs) + : dstcn(_dstcn), blueIdx(_blueIdx) + { + memcpy(coeffs, _coeffs ? _coeffs : XYZ2sRGB_D65, 9*sizeof(coeffs[0])); + if(blueIdx == 0) + { + std::swap(coeffs[0], coeffs[6]); + std::swap(coeffs[1], coeffs[7]); + std::swap(coeffs[2], coeffs[8]); + } + } + + void operator()(const _Tp* src, _Tp* dst, int n) const + { + int dcn = dstcn; + _Tp alpha = ColorChannel<_Tp>::max(); + float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], + C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5], + C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8]; + n *= 3; + for(int i = 0; i < n; i += 3, dst += dcn) + { + _Tp B = saturate_cast<_Tp>(src[i]*C0 + src[i+1]*C1 + src[i+2]*C2); + _Tp G = saturate_cast<_Tp>(src[i]*C3 + src[i+1]*C4 + src[i+2]*C5); + _Tp R = saturate_cast<_Tp>(src[i]*C6 + src[i+1]*C7 + src[i+2]*C8); + dst[0] = B; dst[1] = G; dst[2] = R; + if( dcn == 4 ) + dst[3] = alpha; + } + } + int dstcn, blueIdx; + float coeffs[9]; +}; + + +template struct XYZ2RGB_i +{ + typedef _Tp channel_type; + + XYZ2RGB_i(int _dstcn, int _blueIdx, const int* _coeffs) + : dstcn(_dstcn), blueIdx(_blueIdx) + { + static const int coeffs0[] = + { + 13273, -6296, -2042, + -3970, 7684, 170, + 228, -836, 4331 + }; + for(int i = 0; i < 9; i++) + coeffs[i] = _coeffs ? cvRound(_coeffs[i]*(1 << xyz_shift)) : coeffs0[i]; + + if(blueIdx == 0) + { + std::swap(coeffs[0], coeffs[6]); + std::swap(coeffs[1], coeffs[7]); + std::swap(coeffs[2], coeffs[8]); + } + } + void operator()(const _Tp* src, _Tp* dst, int n) const + { + int dcn = dstcn; + _Tp alpha = ColorChannel<_Tp>::max(); + int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], + C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5], + C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8]; + n *= 3; + for(int i = 0; i < n; i += 3, dst += dcn) + { + int B = CV_DESCALE(src[i]*C0 + src[i+1]*C1 + src[i+2]*C2, xyz_shift); + int G = CV_DESCALE(src[i]*C3 + src[i+1]*C4 + src[i+2]*C5, xyz_shift); + int R = CV_DESCALE(src[i]*C6 + src[i+1]*C7 + src[i+2]*C8, xyz_shift); + dst[0] = saturate_cast<_Tp>(B); dst[1] = saturate_cast<_Tp>(G); + dst[2] = saturate_cast<_Tp>(R); + if( dcn == 4 ) + dst[3] = alpha; + } + } + int dstcn, blueIdx; + int coeffs[9]; +}; + + +////////////////////////////////////// RGB <-> HSV /////////////////////////////////////// + + +struct RGB2HSV_b +{ + typedef uchar channel_type; + + RGB2HSV_b(int _srccn, int _blueIdx, int _hrange) + : srccn(_srccn), blueIdx(_blueIdx), hrange(_hrange) + { + CV_Assert( hrange == 180 || hrange == 256 ); + } + + void operator()(const uchar* src, uchar* dst, int n) const + { + int i, bidx = blueIdx, scn = srccn; + const int hsv_shift = 12; + + static int sdiv_table[256]; + static int hdiv_table180[256]; + static int hdiv_table256[256]; + static volatile bool initialized = false; + + int hr = hrange; + const int* hdiv_table = hr == 180 ? hdiv_table180 : hdiv_table256; + n *= 3; + + if( !initialized ) + { + sdiv_table[0] = hdiv_table180[0] = hdiv_table256[0] = 0; + for( i = 1; i < 256; i++ ) + { + sdiv_table[i] = saturate_cast((255 << hsv_shift)/(1.*i)); + hdiv_table180[i] = saturate_cast((180 << hsv_shift)/(6.*i)); + hdiv_table256[i] = saturate_cast((256 << hsv_shift)/(6.*i)); + } + initialized = true; + } + + for( i = 0; i < n; i += 3, src += scn ) + { + int b = src[bidx], g = src[1], r = src[bidx^2]; + int h, s, v = b; + int vmin = b, diff; + int vr, vg; + + CV_CALC_MAX_8U( v, g ); + CV_CALC_MAX_8U( v, r ); + CV_CALC_MIN_8U( vmin, g ); + CV_CALC_MIN_8U( vmin, r ); + + diff = v - vmin; + vr = v == r ? -1 : 0; + vg = v == g ? -1 : 0; + + s = (diff * sdiv_table[v] + (1 << (hsv_shift-1))) >> hsv_shift; + h = (vr & (g - b)) + + (~vr & ((vg & (b - r + 2 * diff)) + ((~vg) & (r - g + 4 * diff)))); + h = (h * hdiv_table[diff] + (1 << (hsv_shift-1))) >> hsv_shift; + h += h < 0 ? hr : 0; + + dst[i] = saturate_cast(h); + dst[i+1] = (uchar)s; + dst[i+2] = (uchar)v; + } + } + + int srccn, blueIdx, hrange; +}; + + +struct RGB2HSV_f +{ + typedef float channel_type; + + RGB2HSV_f(int _srccn, int _blueIdx, float _hrange) + : srccn(_srccn), blueIdx(_blueIdx), hrange(_hrange) {} + + void operator()(const float* src, float* dst, int n) const + { + int i, bidx = blueIdx, scn = srccn; + float hscale = hrange*(1.f/360.f); + n *= 3; + + for( i = 0; i < n; i += 3, src += scn ) + { + float b = src[bidx], g = src[1], r = src[bidx^2]; + float h, s, v; + + float vmin, diff; + + v = vmin = r; + if( v < g ) v = g; + if( v < b ) v = b; + if( vmin > g ) vmin = g; + if( vmin > b ) vmin = b; + + diff = v - vmin; + s = diff/(float)(fabs(v) + FLT_EPSILON); + diff = (float)(60./(diff + FLT_EPSILON)); + if( v == r ) + h = (g - b)*diff; + else if( v == g ) + h = (b - r)*diff + 120.f; + else + h = (r - g)*diff + 240.f; + + if( h < 0 ) h += 360.f; + + dst[i] = h*hscale; + dst[i+1] = s; + dst[i+2] = v; + } + } + + int srccn, blueIdx; + float hrange; +}; + + +struct HSV2RGB_f +{ + typedef float channel_type; + + HSV2RGB_f(int _dstcn, int _blueIdx, float _hrange) + : dstcn(_dstcn), blueIdx(_blueIdx), hscale(6.f/_hrange) {} + + void operator()(const float* src, float* dst, int n) const + { + int i, bidx = blueIdx, dcn = dstcn; + float _hscale = hscale; + float alpha = ColorChannel::max(); + n *= 3; + + for( i = 0; i < n; i += 3, dst += dcn ) + { + float h = src[i], s = src[i+1], v = src[i+2]; + float b, g, r; + + if( s == 0 ) + b = g = r = v; + else + { + static const int sector_data[][3]= + {{1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0}}; + float tab[4]; + int sector; + h *= _hscale; + if( h < 0 ) + do h += 6; while( h < 0 ); + else if( h >= 6 ) + do h -= 6; while( h >= 6 ); + sector = cvFloor(h); + h -= sector; + + tab[0] = v; + tab[1] = v*(1.f - s); + tab[2] = v*(1.f - s*h); + tab[3] = v*(1.f - s*(1.f - h)); + + b = tab[sector_data[sector][0]]; + g = tab[sector_data[sector][1]]; + r = tab[sector_data[sector][2]]; + } + + dst[bidx] = b; + dst[1] = g; + dst[bidx^2] = r; + if( dcn == 4 ) + dst[3] = alpha; + } + } + + int dstcn, blueIdx; + float hscale; +}; + + +struct HSV2RGB_b +{ + typedef uchar channel_type; + + HSV2RGB_b(int _dstcn, int _blueIdx, int _hrange) + : dstcn(_dstcn), cvt(3, _blueIdx, (float)_hrange) + {} + + void operator()(const uchar* src, uchar* dst, int n) const + { + int i, j, dcn = dstcn; + uchar alpha = ColorChannel::max(); + float buf[3*BLOCK_SIZE]; + + for( i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE*3 ) + { + int dn = std::min(n - i, (int)BLOCK_SIZE); + + for( j = 0; j < dn*3; j += 3 ) + { + buf[j] = src[j]; + buf[j+1] = src[j+1]*(1.f/255.f); + buf[j+2] = src[j+2]*(1.f/255.f); + } + cvt(buf, buf, dn); + + for( j = 0; j < dn*3; j += 3, dst += dcn ) + { + dst[0] = saturate_cast(buf[j]*255.f); + dst[1] = saturate_cast(buf[j+1]*255.f); + dst[2] = saturate_cast(buf[j+2]*255.f); + if( dcn == 4 ) + dst[3] = alpha; + } + } + } + + int dstcn; + HSV2RGB_f cvt; +}; + + +///////////////////////////////////// RGB <-> HLS //////////////////////////////////////// + +struct RGB2HLS_f +{ + typedef float channel_type; + + RGB2HLS_f(int _srccn, int _blueIdx, float _hrange) + : srccn(_srccn), blueIdx(_blueIdx), hrange(_hrange) {} + + void operator()(const float* src, float* dst, int n) const + { + int i, bidx = blueIdx, scn = srccn; + float hscale = hrange*(1.f/360.f); + n *= 3; + + for( i = 0; i < n; i += 3, src += scn ) + { + float b = src[bidx], g = src[1], r = src[bidx^2]; + float h = 0.f, s = 0.f, l; + float vmin, vmax, diff; + + vmax = vmin = r; + if( vmax < g ) vmax = g; + if( vmax < b ) vmax = b; + if( vmin > g ) vmin = g; + if( vmin > b ) vmin = b; + + diff = vmax - vmin; + l = (vmax + vmin)*0.5f; + + if( diff > FLT_EPSILON ) + { + s = l < 0.5f ? diff/(vmax + vmin) : diff/(2 - vmax - vmin); + diff = 60.f/diff; + + if( vmax == r ) + h = (g - b)*diff; + else if( vmax == g ) + h = (b - r)*diff + 120.f; + else + h = (r - g)*diff + 240.f; + + if( h < 0.f ) h += 360.f; + } + + dst[i] = h*hscale; + dst[i+1] = l; + dst[i+2] = s; + } + } + + int srccn, blueIdx; + float hrange; +}; + + +struct RGB2HLS_b +{ + typedef uchar channel_type; + + RGB2HLS_b(int _srccn, int _blueIdx, int _hrange) + : srccn(_srccn), cvt(3, _blueIdx, (float)_hrange) {} + + void operator()(const uchar* src, uchar* dst, int n) const + { + int i, j, scn = srccn; + float buf[3*BLOCK_SIZE]; + + for( i = 0; i < n; i += BLOCK_SIZE, dst += BLOCK_SIZE*3 ) + { + int dn = std::min(n - i, (int)BLOCK_SIZE); + + for( j = 0; j < dn*3; j += 3, src += scn ) + { + buf[j] = src[0]*(1.f/255.f); + buf[j+1] = src[1]*(1.f/255.f); + buf[j+2] = src[2]*(1.f/255.f); + } + cvt(buf, buf, dn); + + for( j = 0; j < dn*3; j += 3 ) + { + dst[j] = saturate_cast(buf[j]); + dst[j+1] = saturate_cast(buf[j+1]*255.f); + dst[j+2] = saturate_cast(buf[j+2]*255.f); + } + } + } + + int srccn; + RGB2HLS_f cvt; +}; + + +struct HLS2RGB_f +{ + typedef float channel_type; + + HLS2RGB_f(int _dstcn, int _blueIdx, float _hrange) + : dstcn(_dstcn), blueIdx(_blueIdx), hscale(6.f/_hrange) {} + + void operator()(const float* src, float* dst, int n) const + { + int i, bidx = blueIdx, dcn = dstcn; + float _hscale = hscale; + float alpha = ColorChannel::max(); + n *= 3; + + for( i = 0; i < n; i += 3, dst += dcn ) + { + float h = src[i], l = src[i+1], s = src[i+2]; + float b, g, r; + + if( s == 0 ) + b = g = r = l; + else + { + static const int sector_data[][3]= + {{1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0}}; + float tab[4]; + int sector; + + float p2 = l <= 0.5f ? l*(1 + s) : l + s - l*s; + float p1 = 2*l - p2; + + h *= _hscale; + if( h < 0 ) + do h += 6; while( h < 0 ); + else if( h >= 6 ) + do h -= 6; while( h >= 6 ); + + assert( 0 <= h && h < 6 ); + sector = cvFloor(h); + h -= sector; + + tab[0] = p2; + tab[1] = p1; + tab[2] = p1 + (p2 - p1)*(1-h); + tab[3] = p1 + (p2 - p1)*h; + + b = tab[sector_data[sector][0]]; + g = tab[sector_data[sector][1]]; + r = tab[sector_data[sector][2]]; + } + + dst[bidx] = b; + dst[1] = g; + dst[bidx^2] = r; + if( dcn == 4 ) + dst[3] = alpha; + } + } + + int dstcn, blueIdx; + float hscale; +}; + + +struct HLS2RGB_b +{ + typedef uchar channel_type; + + HLS2RGB_b(int _dstcn, int _blueIdx, int _hrange) + : dstcn(_dstcn), cvt(3, _blueIdx, (float)_hrange) + {} + + void operator()(const uchar* src, uchar* dst, int n) const + { + int i, j, dcn = dstcn; + uchar alpha = ColorChannel::max(); + float buf[3*BLOCK_SIZE]; + + for( i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE*3 ) + { + int dn = std::min(n - i, (int)BLOCK_SIZE); + + for( j = 0; j < dn*3; j += 3 ) + { + buf[j] = src[j]; + buf[j+1] = src[j+1]*(1.f/255.f); + buf[j+2] = src[j+2]*(1.f/255.f); + } + cvt(buf, buf, dn); + + for( j = 0; j < dn*3; j += 3, dst += dcn ) + { + dst[0] = saturate_cast(buf[j]*255.f); + dst[1] = saturate_cast(buf[j+1]*255.f); + dst[2] = saturate_cast(buf[j+2]*255.f); + if( dcn == 4 ) + dst[3] = alpha; + } + } + } + + int dstcn; + HLS2RGB_f cvt; +}; + + +///////////////////////////////////// RGB <-> L*a*b* ///////////////////////////////////// + +static const float D65[] = { 0.950456f, 1.f, 1.088754f }; + +enum { LAB_CBRT_TAB_SIZE = 1024, GAMMA_TAB_SIZE = 1024 }; +static float LabCbrtTab[LAB_CBRT_TAB_SIZE*4]; +static const float LabCbrtTabScale = LAB_CBRT_TAB_SIZE/1.5f; + +static float sRGBGammaTab[GAMMA_TAB_SIZE*4], sRGBInvGammaTab[GAMMA_TAB_SIZE*4]; +static const float GammaTabScale = (float)GAMMA_TAB_SIZE; + +static ushort sRGBGammaTab_b[256], linearGammaTab_b[256]; +#undef lab_shift +#define lab_shift xyz_shift +#define gamma_shift 3 +#define lab_shift2 (lab_shift + gamma_shift) +#define LAB_CBRT_TAB_SIZE_B (256*3/2*(1<(255.f*(1 << gamma_shift)*(x <= 0.04045f ? x*(1.f/12.92f) : (float)pow((double)(x + 0.055)*(1./1.055), 2.4))); + linearGammaTab_b[i] = (ushort)(i*(1 << gamma_shift)); + } + + for(i = 0; i < LAB_CBRT_TAB_SIZE_B; i++) + { + float x = i*(1.f/(255.f*(1 << gamma_shift))); + LabCbrtTab_b[i] = saturate_cast((1 << lab_shift2)*(x < 0.008856f ? x*7.787f + 0.13793103448275862f : cvCbrt(x))); + } + initialized = true; + } +} + +struct RGB2Lab_b +{ + typedef uchar channel_type; + + RGB2Lab_b(int _srccn, int blueIdx, const float* _coeffs, + const float* _whitept, bool _srgb) + : srccn(_srccn), srgb(_srgb) + { + static volatile int _3 = 3; + initLabTabs(); + + if(!_coeffs) _coeffs = sRGB2XYZ_D65; + if(!_whitept) _whitept = D65; + float scale[] = + { + (1 << lab_shift)/_whitept[0], + (float)(1 << lab_shift), + (1 << lab_shift)/_whitept[2] + }; + + for( int i = 0; i < _3; i++ ) + { + coeffs[i*3+(blueIdx^2)] = cvRound(_coeffs[i*3]*scale[i]); + coeffs[i*3+1] = cvRound(_coeffs[i*3+1]*scale[i]); + coeffs[i*3+blueIdx] = cvRound(_coeffs[i*3+2]*scale[i]); + + CV_Assert( coeffs[i] >= 0 && coeffs[i*3+1] >= 0 && coeffs[i*3+2] >= 0 && + coeffs[i*3] + coeffs[i*3+1] + coeffs[i*3+2] < 2*(1 << lab_shift) ); + } + } + + void operator()(const uchar* src, uchar* dst, int n) const + { + const int Lscale = (116*255+50)/100; + const int Lshift = -((16*255*(1 << lab_shift2) + 50)/100); + const ushort* tab = srgb ? sRGBGammaTab_b : linearGammaTab_b; + int i, scn = srccn; + int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], + C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5], + C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8]; + n *= 3; + + for( i = 0; i < n; i += 3, src += scn ) + { + int R = tab[src[0]], G = tab[src[1]], B = tab[src[2]]; + int fX = LabCbrtTab_b[CV_DESCALE(R*C0 + G*C1 + B*C2, lab_shift)]; + int fY = LabCbrtTab_b[CV_DESCALE(R*C3 + G*C4 + B*C5, lab_shift)]; + int fZ = LabCbrtTab_b[CV_DESCALE(R*C6 + G*C7 + B*C8, lab_shift)]; + + int L = CV_DESCALE( Lscale*fY + Lshift, lab_shift2 ); + int a = CV_DESCALE( 500*(fX - fY) + 128*(1 << lab_shift2), lab_shift2 ); + int b = CV_DESCALE( 200*(fY - fZ) + 128*(1 << lab_shift2), lab_shift2 ); + + dst[i] = saturate_cast(L); + dst[i+1] = saturate_cast(a); + dst[i+2] = saturate_cast(b); + } + } + + int srccn; + int coeffs[9]; + bool srgb; +}; + + +struct RGB2Lab_f +{ + typedef float channel_type; + + RGB2Lab_f(int _srccn, int blueIdx, const float* _coeffs, + const float* _whitept, bool _srgb) + : srccn(_srccn), srgb(_srgb) + { + volatile int _3 = 3; + initLabTabs(); + + if(!_coeffs) _coeffs = sRGB2XYZ_D65; + if(!_whitept) _whitept = D65; + float scale[] = { LabCbrtTabScale/_whitept[0], LabCbrtTabScale, LabCbrtTabScale/_whitept[2] }; + + for( int i = 0; i < _3; i++ ) + { + coeffs[i*3+(blueIdx^2)] = _coeffs[i*3]*scale[i]; + coeffs[i*3+1] = _coeffs[i*3+1]*scale[i]; + coeffs[i*3+blueIdx] = _coeffs[i*3+2]*scale[i]; + CV_Assert( coeffs[i*3] >= 0 && coeffs[i*3+1] >= 0 && coeffs[i*3+2] >= 0 && + coeffs[i*3] + coeffs[i*3+1] + coeffs[i*3+2] < 1.5f*LabCbrtTabScale ); + } + } + + void operator()(const float* src, float* dst, int n) const + { + int i, scn = srccn; + float gscale = GammaTabScale; + const float* gammaTab = srgb ? sRGBGammaTab : 0; + float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], + C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5], + C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8]; + n *= 3; + + for( i = 0; i < n; i += 3, src += scn ) + { + float R = src[0], G = src[1], B = src[2]; + if( gammaTab ) + { + R = splineInterpolate(R*gscale, gammaTab, GAMMA_TAB_SIZE); + G = splineInterpolate(G*gscale, gammaTab, GAMMA_TAB_SIZE); + B = splineInterpolate(B*gscale, gammaTab, GAMMA_TAB_SIZE); + } + float fX = splineInterpolate(R*C0 + G*C1 + B*C2, LabCbrtTab, LAB_CBRT_TAB_SIZE); + float fY = splineInterpolate(R*C3 + G*C4 + B*C5, LabCbrtTab, LAB_CBRT_TAB_SIZE); + float fZ = splineInterpolate(R*C6 + G*C7 + B*C8, LabCbrtTab, LAB_CBRT_TAB_SIZE); + + float L = 116.f*fY - 16.f; + float a = 500.f*(fX - fY); + float b = 200.f*(fY - fZ); + + dst[i] = L; dst[i+1] = a; dst[i+2] = b; + } + } + + int srccn; + float coeffs[9]; + bool srgb; +}; + + +struct Lab2RGB_f +{ + typedef float channel_type; + + Lab2RGB_f( int _dstcn, int blueIdx, const float* _coeffs, + const float* _whitept, bool _srgb ) + : dstcn(_dstcn), srgb(_srgb) + { + initLabTabs(); + + if(!_coeffs) _coeffs = XYZ2sRGB_D65; + if(!_whitept) _whitept = D65; + + for( int i = 0; i < 3; i++ ) + { + coeffs[i+(blueIdx^2)*3] = _coeffs[i]*_whitept[i]; + coeffs[i+3] = _coeffs[i+3]*_whitept[i]; + coeffs[i+blueIdx*3] = _coeffs[i+6]*_whitept[i]; + } + } + + void operator()(const float* src, float* dst, int n) const + { + int i, dcn = dstcn; + const float* gammaTab = srgb ? sRGBInvGammaTab : 0; + float gscale = GammaTabScale; + float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], + C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5], + C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8]; + float alpha = ColorChannel::max(); + n *= 3; + + for( i = 0; i < n; i += 3, dst += dcn ) + { + float L = src[i], a = src[i+1], b = src[i+2]; + float Y = (L + 16.f)*(1.f/116.f); + float X = (Y + a*0.002f); + float Z = (Y - b*0.005f); + Y = Y*Y*Y; + X = X*X*X; + Z = Z*Z*Z; + + float R = X*C0 + Y*C1 + Z*C2; + float G = X*C3 + Y*C4 + Z*C5; + float B = X*C6 + Y*C7 + Z*C8; + + if( gammaTab ) + { + R = splineInterpolate(R*gscale, gammaTab, GAMMA_TAB_SIZE); + G = splineInterpolate(G*gscale, gammaTab, GAMMA_TAB_SIZE); + B = splineInterpolate(B*gscale, gammaTab, GAMMA_TAB_SIZE); + } + + dst[0] = R; dst[1] = G; dst[2] = B; + if( dcn == 4 ) + dst[3] = alpha; + } + } + + int dstcn; + float coeffs[9]; + bool srgb; +}; + + +struct Lab2RGB_b +{ + typedef uchar channel_type; + + Lab2RGB_b( int _dstcn, int blueIdx, const float* _coeffs, + const float* _whitept, bool _srgb ) + : dstcn(_dstcn), cvt(3, blueIdx, _coeffs, _whitept, _srgb ) {} + + void operator()(const uchar* src, uchar* dst, int n) const + { + int i, j, dcn = dstcn; + uchar alpha = ColorChannel::max(); + float buf[3*BLOCK_SIZE]; + + for( i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE*3 ) + { + int dn = std::min(n - i, (int)BLOCK_SIZE); + + for( j = 0; j < dn*3; j += 3 ) + { + buf[j] = src[j]*(100.f/255.f); + buf[j+1] = (float)(src[j+1] - 128); + buf[j+2] = (float)(src[j+2] - 128); + } + cvt(buf, buf, dn); + + for( j = 0; j < dn*3; j += 3, dst += dcn ) + { + dst[0] = saturate_cast(buf[j]*255.f); + dst[1] = saturate_cast(buf[j+1]*255.f); + dst[2] = saturate_cast(buf[j+2]*255.f); + if( dcn == 4 ) + dst[3] = alpha; + } + } + } + + int dstcn; + Lab2RGB_f cvt; +}; + + +///////////////////////////////////// RGB <-> L*u*v* ///////////////////////////////////// + +struct RGB2Luv_f +{ + typedef float channel_type; + + RGB2Luv_f( int _srccn, int blueIdx, const float* _coeffs, + const float* whitept, bool _srgb ) + : srccn(_srccn), srgb(_srgb) + { + volatile int i; + initLabTabs(); + + if(!_coeffs) _coeffs = sRGB2XYZ_D65; + if(!whitept) whitept = D65; + + for( i = 0; i < 3; i++ ) + { + coeffs[i*3] = _coeffs[i*3]; + coeffs[i*3+1] = _coeffs[i*3+1]; + coeffs[i*3+2] = _coeffs[i*3+2]; + if( blueIdx == 0 ) + std::swap(coeffs[i*3], coeffs[i*3+2]); + CV_Assert( coeffs[i*3] >= 0 && coeffs[i*3+1] >= 0 && coeffs[i*3+2] >= 0 && + coeffs[i*3] + coeffs[i*3+1] + coeffs[i*3+2] < 1.5f ); + } + + float d = 1.f/(whitept[0] + whitept[1]*15 + whitept[2]*3); + un = 4*whitept[0]*d; + vn = 9*whitept[1]*d; + + CV_Assert(whitept[1] == 1.f); + } + + void operator()(const float* src, float* dst, int n) const + { + int i, scn = srccn; + float gscale = GammaTabScale; + const float* gammaTab = srgb ? sRGBGammaTab : 0; + float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], + C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5], + C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8]; + float _un = 13*un, _vn = 13*vn; + n *= 3; + + for( i = 0; i < n; i += 3, src += scn ) + { + float R = src[0], G = src[1], B = src[2]; + if( gammaTab ) + { + R = splineInterpolate(R*gscale, gammaTab, GAMMA_TAB_SIZE); + G = splineInterpolate(G*gscale, gammaTab, GAMMA_TAB_SIZE); + B = splineInterpolate(B*gscale, gammaTab, GAMMA_TAB_SIZE); + } + + float X = R*C0 + G*C1 + B*C2; + float Y = R*C3 + G*C4 + B*C5; + float Z = R*C6 + G*C7 + B*C8; + + float L = splineInterpolate(Y*LabCbrtTabScale, LabCbrtTab, LAB_CBRT_TAB_SIZE); + L = 116.f*L - 16.f; + + float d = (4*13) / std::max(X + 15 * Y + 3 * Z, FLT_EPSILON); + float u = L*(X*d - _un); + float v = L*((9*0.25f)*Y*d - _vn); + + dst[i] = L; dst[i+1] = u; dst[i+2] = v; + } + } + + int srccn; + float coeffs[9], un, vn; + bool srgb; +}; + + +struct Luv2RGB_f +{ + typedef float channel_type; + + Luv2RGB_f( int _dstcn, int blueIdx, const float* _coeffs, + const float* whitept, bool _srgb ) + : dstcn(_dstcn), srgb(_srgb) + { + initLabTabs(); + + if(!_coeffs) _coeffs = XYZ2sRGB_D65; + if(!whitept) whitept = D65; + + for( int i = 0; i < 3; i++ ) + { + coeffs[i+(blueIdx^2)*3] = _coeffs[i]; + coeffs[i+3] = _coeffs[i+3]; + coeffs[i+blueIdx*3] = _coeffs[i+6]; + } + + float d = 1.f/(whitept[0] + whitept[1]*15 + whitept[2]*3); + un = 4*whitept[0]*d; + vn = 9*whitept[1]*d; + + CV_Assert(whitept[1] == 1.f); + } + + void operator()(const float* src, float* dst, int n) const + { + int i, dcn = dstcn; + const float* gammaTab = srgb ? sRGBInvGammaTab : 0; + float gscale = GammaTabScale; + float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], + C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5], + C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8]; + float alpha = ColorChannel::max(); + float _un = un, _vn = vn; + n *= 3; + + for( i = 0; i < n; i += 3, dst += dcn ) + { + float L = src[i], u = src[i+1], v = src[i+2], d, X, Y, Z; + Y = (L + 16.f) * (1.f/116.f); + Y = Y*Y*Y; + d = (1.f/13.f)/L; + u = u*d + _un; + v = v*d + _vn; + float iv = 1.f/v; + X = 2.25f * u * Y * iv ; + Z = (12 - 3 * u - 20 * v) * Y * 0.25f * iv; + + float R = X*C0 + Y*C1 + Z*C2; + float G = X*C3 + Y*C4 + Z*C5; + float B = X*C6 + Y*C7 + Z*C8; + + if( gammaTab ) + { + R = splineInterpolate(R*gscale, gammaTab, GAMMA_TAB_SIZE); + G = splineInterpolate(G*gscale, gammaTab, GAMMA_TAB_SIZE); + B = splineInterpolate(B*gscale, gammaTab, GAMMA_TAB_SIZE); + } + + dst[0] = R; dst[1] = G; dst[2] = B; + if( dcn == 4 ) + dst[3] = alpha; + } + } + + int dstcn; + float coeffs[9], un, vn; + bool srgb; +}; + + +struct RGB2Luv_b +{ + typedef uchar channel_type; + + RGB2Luv_b( int _srccn, int blueIdx, const float* _coeffs, + const float* _whitept, bool _srgb ) + : srccn(_srccn), cvt(3, blueIdx, _coeffs, _whitept, _srgb) {} + + void operator()(const uchar* src, uchar* dst, int n) const + { + int i, j, scn = srccn; + float buf[3*BLOCK_SIZE]; + + for( i = 0; i < n; i += BLOCK_SIZE, dst += BLOCK_SIZE*3 ) + { + int dn = std::min(n - i, (int)BLOCK_SIZE); + + for( j = 0; j < dn*3; j += 3, src += scn ) + { + buf[j] = src[0]*(1.f/255.f); + buf[j+1] = (float)(src[1]*(1.f/255.f)); + buf[j+2] = (float)(src[2]*(1.f/255.f)); + } + cvt(buf, buf, dn); + + for( j = 0; j < dn*3; j += 3 ) + { + dst[j] = saturate_cast(buf[j]*2.55f); + dst[j+1] = saturate_cast(buf[j+1]*0.72033898305084743f + 96.525423728813564f); + dst[j+2] = saturate_cast(buf[j+2]*0.99609375f + 139.453125f); + } + } + } + + int srccn; + RGB2Luv_f cvt; +}; + + +struct Luv2RGB_b +{ + typedef uchar channel_type; + + Luv2RGB_b( int _dstcn, int blueIdx, const float* _coeffs, + const float* _whitept, bool _srgb ) + : dstcn(_dstcn), cvt(3, blueIdx, _coeffs, _whitept, _srgb ) {} + + void operator()(const uchar* src, uchar* dst, int n) const + { + int i, j, dcn = dstcn; + uchar alpha = ColorChannel::max(); + float buf[3*BLOCK_SIZE]; + + for( i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE*3 ) + { + int dn = std::min(n - i, (int)BLOCK_SIZE); + + for( j = 0; j < dn*3; j += 3 ) + { + buf[j] = src[j]*(100.f/255.f); + buf[j+1] = (float)(src[j+1]*1.388235294117647f - 134.f); + buf[j+2] = (float)(src[j+2]*1.003921568627451f - 140.f); + } + cvt(buf, buf, dn); + + for( j = 0; j < dn*3; j += 3, dst += dcn ) + { + dst[0] = saturate_cast(buf[j]*255.f); + dst[1] = saturate_cast(buf[j+1]*255.f); + dst[2] = saturate_cast(buf[j+2]*255.f); + if( dcn == 4 ) + dst[3] = alpha; + } + } + } + + int dstcn; + Luv2RGB_f cvt; +}; + + +//////////////////////////// Bayer Pattern -> RGB conversion ///////////////////////////// + +template +class SIMDBayerStubInterpolator_ +{ +public: + int bayer2Gray(const T*, int, T*, int, int, int, int) const + { + return 0; + } + + int bayer2RGB(const T*, int, T*, int, int) const + { + return 0; + } +}; + +#if CV_SSE2 +class SIMDBayerInterpolator_8u +{ +public: + SIMDBayerInterpolator_8u() + { + use_simd = checkHardwareSupport(CV_CPU_SSE2); + } + + int bayer2Gray(const uchar* bayer, int bayer_step, uchar* dst, + int width, int bcoeff, int gcoeff, int rcoeff) const + { + if( !use_simd ) + return 0; + + __m128i _b2y = _mm_set1_epi16((short)(rcoeff*2)); + __m128i _g2y = _mm_set1_epi16((short)(gcoeff*2)); + __m128i _r2y = _mm_set1_epi16((short)(bcoeff*2)); + const uchar* bayer_end = bayer + width; + + for( ; bayer <= bayer_end - 18; bayer += 14, dst += 14 ) + { + __m128i r0 = _mm_loadu_si128((const __m128i*)bayer); + __m128i r1 = _mm_loadu_si128((const __m128i*)(bayer+bayer_step)); + __m128i r2 = _mm_loadu_si128((const __m128i*)(bayer+bayer_step*2)); + + __m128i b1 = _mm_add_epi16(_mm_srli_epi16(_mm_slli_epi16(r0, 8), 7), + _mm_srli_epi16(_mm_slli_epi16(r2, 8), 7)); + __m128i b0 = _mm_add_epi16(b1, _mm_srli_si128(b1, 2)); + b1 = _mm_slli_epi16(_mm_srli_si128(b1, 2), 1); + + __m128i g0 = _mm_add_epi16(_mm_srli_epi16(r0, 7), _mm_srli_epi16(r2, 7)); + __m128i g1 = _mm_srli_epi16(_mm_slli_epi16(r1, 8), 7); + g0 = _mm_add_epi16(g0, _mm_add_epi16(g1, _mm_srli_si128(g1, 2))); + g1 = _mm_slli_epi16(_mm_srli_si128(g1, 2), 2); + + r0 = _mm_srli_epi16(r1, 8); + r1 = _mm_slli_epi16(_mm_add_epi16(r0, _mm_srli_si128(r0, 2)), 2); + r0 = _mm_slli_epi16(r0, 3); + + g0 = _mm_add_epi16(_mm_mulhi_epi16(b0, _b2y), _mm_mulhi_epi16(g0, _g2y)); + g1 = _mm_add_epi16(_mm_mulhi_epi16(b1, _b2y), _mm_mulhi_epi16(g1, _g2y)); + g0 = _mm_add_epi16(g0, _mm_mulhi_epi16(r0, _r2y)); + g1 = _mm_add_epi16(g1, _mm_mulhi_epi16(r1, _r2y)); + g0 = _mm_srli_epi16(g0, 2); + g1 = _mm_srli_epi16(g1, 2); + g0 = _mm_packus_epi16(g0, g0); + g1 = _mm_packus_epi16(g1, g1); + g0 = _mm_unpacklo_epi8(g0, g1); + _mm_storeu_si128((__m128i*)dst, g0); + } + + return (int)(bayer - (bayer_end - width)); + } + + int bayer2RGB(const uchar* bayer, int bayer_step, uchar* dst, int width, int blue) const + { + if( !use_simd ) + return 0; + /* + B G B G | B G B G | B G B G | B G B G + G R G R | G R G R | G R G R | G R G R + B G B G | B G B G | B G B G | B G B G + */ + __m128i delta1 = _mm_set1_epi16(1), delta2 = _mm_set1_epi16(2); + __m128i mask = _mm_set1_epi16(blue < 0 ? -1 : 0), z = _mm_setzero_si128(); + __m128i masklo = _mm_set1_epi16(0x00ff); + const uchar* bayer_end = bayer + width; + + for( ; bayer <= bayer_end - 18; bayer += 14, dst += 42 ) + { + __m128i r0 = _mm_loadu_si128((const __m128i*)bayer); + __m128i r1 = _mm_loadu_si128((const __m128i*)(bayer+bayer_step)); + __m128i r2 = _mm_loadu_si128((const __m128i*)(bayer+bayer_step*2)); + + __m128i b1 = _mm_add_epi16(_mm_and_si128(r0, masklo), _mm_and_si128(r2, masklo)); + __m128i b0 = _mm_add_epi16(b1, _mm_srli_si128(b1, 2)); + b1 = _mm_srli_si128(b1, 2); + b1 = _mm_srli_epi16(_mm_add_epi16(b1, delta1), 1); + b0 = _mm_srli_epi16(_mm_add_epi16(b0, delta2), 2); + b0 = _mm_packus_epi16(b0, b1); + + __m128i g0 = _mm_add_epi16(_mm_srli_epi16(r0, 8), _mm_srli_epi16(r2, 8)); + __m128i g1 = _mm_and_si128(r1, masklo); + g0 = _mm_add_epi16(g0, _mm_add_epi16(g1, _mm_srli_si128(g1, 2))); + g1 = _mm_srli_si128(g1, 2); + g0 = _mm_srli_epi16(_mm_add_epi16(g0, delta2), 2); + g0 = _mm_packus_epi16(g0, g1); + + r0 = _mm_srli_epi16(r1, 8); + r1 = _mm_add_epi16(r0, _mm_srli_si128(r0, 2)); + r1 = _mm_srli_epi16(_mm_add_epi16(r1, delta1), 1); + r0 = _mm_packus_epi16(r0, r1); + + b1 = _mm_and_si128(_mm_xor_si128(b0, r0), mask); + b0 = _mm_xor_si128(b0, b1); + r0 = _mm_xor_si128(r0, b1); + + // b1 g1 b1 g1 ... + b1 = _mm_unpackhi_epi8(b0, g0); + // b0 g0 b2 g2 b4 g4 .... + b0 = _mm_unpacklo_epi8(b0, g0); + + // r1 0 r3 0 ... + r1 = _mm_unpackhi_epi8(r0, z); + // r0 0 r2 0 r4 0 ... + r0 = _mm_unpacklo_epi8(r0, z); + + // 0 b0 g0 r0 0 b2 g2 r2 0 ... + g0 = _mm_slli_si128(_mm_unpacklo_epi16(b0, r0), 1); + // 0 b8 g8 r8 0 b10 g10 r10 0 ... + g1 = _mm_slli_si128(_mm_unpackhi_epi16(b0, r0), 1); + + // b1 g1 r1 0 b3 g3 r3 .... + r0 = _mm_unpacklo_epi16(b1, r1); + // b9 g9 r9 0 ... + r1 = _mm_unpackhi_epi16(b1, r1); + + b0 = _mm_srli_si128(_mm_unpacklo_epi32(g0, r0), 1); + b1 = _mm_srli_si128(_mm_unpackhi_epi32(g0, r0), 1); + + _mm_storel_epi64((__m128i*)(dst-1+0), b0); + _mm_storel_epi64((__m128i*)(dst-1+6*1), _mm_srli_si128(b0, 8)); + _mm_storel_epi64((__m128i*)(dst-1+6*2), b1); + _mm_storel_epi64((__m128i*)(dst-1+6*3), _mm_srli_si128(b1, 8)); + + g0 = _mm_srli_si128(_mm_unpacklo_epi32(g1, r1), 1); + g1 = _mm_srli_si128(_mm_unpackhi_epi32(g1, r1), 1); + + _mm_storel_epi64((__m128i*)(dst-1+6*4), g0); + _mm_storel_epi64((__m128i*)(dst-1+6*5), _mm_srli_si128(g0, 8)); + + _mm_storel_epi64((__m128i*)(dst-1+6*6), g1); + } + + return (int)(bayer - (bayer_end - width)); + } + + bool use_simd; +}; +#else +typedef SIMDBayerStubInterpolator_ SIMDBayerInterpolator_8u; +#endif + +template +static void Bayer2Gray_( const Mat& srcmat, Mat& dstmat, int code ) +{ + SIMDInterpolator vecOp; + const int R2Y = 4899; + const int G2Y = 9617; + const int B2Y = 1868; + const int SHIFT = 14; + + const T* bayer0 = (const T*)srcmat.data; + int bayer_step = (int)(srcmat.step/sizeof(T)); + T* dst0 = (T*)dstmat.data; + int dst_step = (int)(dstmat.step/sizeof(T)); + Size size = srcmat.size(); + int bcoeff = B2Y, rcoeff = R2Y; + int start_with_green = code == CV_BayerGB2GRAY || code == CV_BayerGR2GRAY; + bool brow = true; + + if( code != CV_BayerBG2GRAY && code != CV_BayerGB2GRAY ) + { + brow = false; + std::swap(bcoeff, rcoeff); + } + + dst0 += dst_step + 1; + size.height -= 2; + size.width -= 2; + + for( ; size.height-- > 0; bayer0 += bayer_step, dst0 += dst_step ) + { + unsigned t0, t1, t2; + const T* bayer = bayer0; + T* dst = dst0; + const T* bayer_end = bayer + size.width; + + if( size.width <= 0 ) + { + dst[-1] = dst[size.width] = 0; + continue; + } + + if( start_with_green ) + { + t0 = (bayer[1] + bayer[bayer_step*2+1])*rcoeff; + t1 = (bayer[bayer_step] + bayer[bayer_step+2])*bcoeff; + t2 = bayer[bayer_step+1]*(2*G2Y); + + dst[0] = (T)CV_DESCALE(t0 + t1 + t2, SHIFT+1); + bayer++; + dst++; + } + + int delta = vecOp.bayer2Gray(bayer, bayer_step, dst, size.width, bcoeff, G2Y, rcoeff); + bayer += delta; + dst += delta; + + for( ; bayer <= bayer_end - 2; bayer += 2, dst += 2 ) + { + t0 = (bayer[0] + bayer[2] + bayer[bayer_step*2] + bayer[bayer_step*2+2])*rcoeff; + t1 = (bayer[1] + bayer[bayer_step] + bayer[bayer_step+2] + bayer[bayer_step*2+1])*G2Y; + t2 = bayer[bayer_step+1]*(4*bcoeff); + dst[0] = (T)CV_DESCALE(t0 + t1 + t2, SHIFT+2); + + t0 = (bayer[2] + bayer[bayer_step*2+2])*rcoeff; + t1 = (bayer[bayer_step+1] + bayer[bayer_step+3])*bcoeff; + t2 = bayer[bayer_step+2]*(2*G2Y); + dst[1] = (T)CV_DESCALE(t0 + t1 + t2, SHIFT+1); + } + + if( bayer < bayer_end ) + { + t0 = (bayer[0] + bayer[2] + bayer[bayer_step*2] + bayer[bayer_step*2+2])*rcoeff; + t1 = (bayer[1] + bayer[bayer_step] + bayer[bayer_step+2] + bayer[bayer_step*2+1])*G2Y; + t2 = bayer[bayer_step+1]*(4*bcoeff); + dst[0] = (T)CV_DESCALE(t0 + t1 + t2, SHIFT+2); + bayer++; + dst++; + } + + dst0[-1] = dst0[0]; + dst0[size.width] = dst0[size.width-1]; + + brow = !brow; + std::swap(bcoeff, rcoeff); + start_with_green = !start_with_green; + } + + size = dstmat.size(); + dst0 = (T*)dstmat.data; + if( size.height > 2 ) + for( int i = 0; i < size.width; i++ ) + { + dst0[i] = dst0[i + dst_step]; + dst0[i + (size.height-1)*dst_step] = dst0[i + (size.height-2)*dst_step]; + } + else + for( int i = 0; i < size.width; i++ ) + { + dst0[i] = dst0[i + (size.height-1)*dst_step] = 0; + } +} + +template +static void Bayer2RGB_( const Mat& srcmat, Mat& dstmat, int code ) +{ + SIMDInterpolator vecOp; + const T* bayer0 = (const T*)srcmat.data; + int bayer_step = (int)(srcmat.step/sizeof(T)); + T* dst0 = (T*)dstmat.data; + int dst_step = (int)(dstmat.step/sizeof(T)); + Size size = srcmat.size(); + int blue = code == CV_BayerBG2BGR || code == CV_BayerGB2BGR ? -1 : 1; + int start_with_green = code == CV_BayerGB2BGR || code == CV_BayerGR2BGR; + + dst0 += dst_step + 3 + 1; + size.height -= 2; + size.width -= 2; + + for( ; size.height-- > 0; bayer0 += bayer_step, dst0 += dst_step ) + { + int t0, t1; + const T* bayer = bayer0; + T* dst = dst0; + const T* bayer_end = bayer + size.width; + + if( size.width <= 0 ) + { + dst[-4] = dst[-3] = dst[-2] = dst[size.width*3-1] = + dst[size.width*3] = dst[size.width*3+1] = 0; + continue; + } + + if( start_with_green ) + { + t0 = (bayer[1] + bayer[bayer_step*2+1] + 1) >> 1; + t1 = (bayer[bayer_step] + bayer[bayer_step+2] + 1) >> 1; + dst[-blue] = (T)t0; + dst[0] = bayer[bayer_step+1]; + dst[blue] = (T)t1; + bayer++; + dst += 3; + } + + int delta = vecOp.bayer2RGB(bayer, bayer_step, dst, size.width, blue); + bayer += delta; + dst += delta*3; + + if( blue > 0 ) + { + for( ; bayer <= bayer_end - 2; bayer += 2, dst += 6 ) + { + t0 = (bayer[0] + bayer[2] + bayer[bayer_step*2] + + bayer[bayer_step*2+2] + 2) >> 2; + t1 = (bayer[1] + bayer[bayer_step] + + bayer[bayer_step+2] + bayer[bayer_step*2+1]+2) >> 2; + dst[-1] = (T)t0; + dst[0] = (T)t1; + dst[1] = bayer[bayer_step+1]; + + t0 = (bayer[2] + bayer[bayer_step*2+2] + 1) >> 1; + t1 = (bayer[bayer_step+1] + bayer[bayer_step+3] + 1) >> 1; + dst[2] = (T)t0; + dst[3] = bayer[bayer_step+2]; + dst[4] = (T)t1; + } + } + else + { + for( ; bayer <= bayer_end - 2; bayer += 2, dst += 6 ) + { + t0 = (bayer[0] + bayer[2] + bayer[bayer_step*2] + + bayer[bayer_step*2+2] + 2) >> 2; + t1 = (bayer[1] + bayer[bayer_step] + + bayer[bayer_step+2] + bayer[bayer_step*2+1]+2) >> 2; + dst[1] = (T)t0; + dst[0] = (T)t1; + dst[-1] = bayer[bayer_step+1]; + + t0 = (bayer[2] + bayer[bayer_step*2+2] + 1) >> 1; + t1 = (bayer[bayer_step+1] + bayer[bayer_step+3] + 1) >> 1; + dst[4] = (T)t0; + dst[3] = bayer[bayer_step+2]; + dst[2] = (T)t1; + } + } + + if( bayer < bayer_end ) + { + t0 = (bayer[0] + bayer[2] + bayer[bayer_step*2] + + bayer[bayer_step*2+2] + 2) >> 2; + t1 = (bayer[1] + bayer[bayer_step] + + bayer[bayer_step+2] + bayer[bayer_step*2+1]+2) >> 2; + dst[-blue] = (T)t0; + dst[0] = (T)t1; + dst[blue] = bayer[bayer_step+1]; + bayer++; + dst += 3; + } + + dst0[-4] = dst0[-1]; + dst0[-3] = dst0[0]; + dst0[-2] = dst0[1]; + dst0[size.width*3-1] = dst0[size.width*3-4]; + dst0[size.width*3] = dst0[size.width*3-3]; + dst0[size.width*3+1] = dst0[size.width*3-2]; + + blue = -blue; + start_with_green = !start_with_green; + } + + size = dstmat.size(); + dst0 = (T*)dstmat.data; + if( size.height > 2 ) + for( int i = 0; i < size.width*3; i++ ) + { + dst0[i] = dst0[i + dst_step]; + dst0[i + (size.height-1)*dst_step] = dst0[i + (size.height-2)*dst_step]; + } + else + for( int i = 0; i < size.width*3; i++ ) + { + dst0[i] = dst0[i + (size.height-1)*dst_step] = 0; + } +} + + +/////////////////// Demosaicing using Variable Number of Gradients /////////////////////// + +static void Bayer2RGB_VNG_8u( const Mat& srcmat, Mat& dstmat, int code ) +{ + const uchar* bayer = srcmat.data; + int bstep = (int)srcmat.step; + uchar* dst = dstmat.data; + int dststep = (int)dstmat.step; + Size size = srcmat.size(); + + int blueIdx = code == CV_BayerBG2BGR_VNG || code == CV_BayerGB2BGR_VNG ? 0 : 2; + bool greenCell0 = code != CV_BayerBG2BGR_VNG && code != CV_BayerRG2BGR_VNG; + + // for too small images use the simple interpolation algorithm + if( MIN(size.width, size.height) < 8 ) + { + Bayer2RGB_( srcmat, dstmat, code ); + return; + } + + const int brows = 3, bcn = 7; + int N = size.width, N2 = N*2, N3 = N*3, N4 = N*4, N5 = N*5, N6 = N*6, N7 = N*7; + int i, bufstep = N7*bcn; + cv::AutoBuffer _buf(bufstep*brows); + ushort* buf = (ushort*)_buf; + + bayer += bstep*2; + +#if CV_SSE2 + bool haveSSE = cv::checkHardwareSupport(CV_CPU_SSE2); + #define _mm_absdiff_epu16(a,b) _mm_adds_epu16(_mm_subs_epu16(a, b), _mm_subs_epu16(b, a)) +#endif + + for( int y = 2; y < size.height - 4; y++ ) + { + uchar* dstrow = dst + dststep*y + 6; + const uchar* srow; + + for( int dy = (y == 2 ? -1 : 1); dy <= 1; dy++ ) + { + ushort* brow = buf + ((y + dy - 1)%brows)*bufstep + 1; + srow = bayer + (y+dy)*bstep + 1; + + for( i = 0; i < bcn; i++ ) + brow[N*i-1] = brow[(N-2) + N*i] = 0; + + i = 1; + +#if CV_SSE2 + if( haveSSE ) + { + __m128i z = _mm_setzero_si128(); + for( ; i <= N-9; i += 8, srow += 8, brow += 8 ) + { + __m128i s1, s2, s3, s4, s6, s7, s8, s9; + + s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)(srow-1-bstep)),z); + s2 = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)(srow-bstep)),z); + s3 = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)(srow+1-bstep)),z); + + s4 = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)(srow-1)),z); + s6 = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)(srow+1)),z); + + s7 = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)(srow-1+bstep)),z); + s8 = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)(srow+bstep)),z); + s9 = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)(srow+1+bstep)),z); + + __m128i b0, b1, b2, b3, b4, b5, b6; + + b0 = _mm_adds_epu16(_mm_slli_epi16(_mm_absdiff_epu16(s2,s8),1), + _mm_adds_epu16(_mm_absdiff_epu16(s1, s7), + _mm_absdiff_epu16(s3, s9))); + b1 = _mm_adds_epu16(_mm_slli_epi16(_mm_absdiff_epu16(s4,s6),1), + _mm_adds_epu16(_mm_absdiff_epu16(s1, s3), + _mm_absdiff_epu16(s7, s9))); + b2 = _mm_slli_epi16(_mm_absdiff_epu16(s3,s7),1); + b3 = _mm_slli_epi16(_mm_absdiff_epu16(s1,s9),1); + + _mm_storeu_si128((__m128i*)brow, b0); + _mm_storeu_si128((__m128i*)(brow + N), b1); + _mm_storeu_si128((__m128i*)(brow + N2), b2); + _mm_storeu_si128((__m128i*)(brow + N3), b3); + + b4 = _mm_adds_epu16(b2,_mm_adds_epu16(_mm_absdiff_epu16(s2, s4), + _mm_absdiff_epu16(s6, s8))); + b5 = _mm_adds_epu16(b3,_mm_adds_epu16(_mm_absdiff_epu16(s2, s6), + _mm_absdiff_epu16(s4, s8))); + b6 = _mm_adds_epu16(_mm_adds_epu16(s2, s4), _mm_adds_epu16(s6, s8)); + b6 = _mm_srli_epi16(b6, 1); + + _mm_storeu_si128((__m128i*)(brow + N4), b4); + _mm_storeu_si128((__m128i*)(brow + N5), b5); + _mm_storeu_si128((__m128i*)(brow + N6), b6); + } + } +#endif + + for( ; i < N-1; i++, srow++, brow++ ) + { + brow[0] = (ushort)(std::abs(srow[-1-bstep] - srow[-1+bstep]) + + std::abs(srow[-bstep] - srow[+bstep])*2 + + std::abs(srow[1-bstep] - srow[1+bstep])); + brow[N] = (ushort)(std::abs(srow[-1-bstep] - srow[1-bstep]) + + std::abs(srow[-1] - srow[1])*2 + + std::abs(srow[-1+bstep] - srow[1+bstep])); + brow[N2] = (ushort)(std::abs(srow[+1-bstep] - srow[-1+bstep])*2); + brow[N3] = (ushort)(std::abs(srow[-1-bstep] - srow[1+bstep])*2); + brow[N4] = (ushort)(brow[N2] + std::abs(srow[-bstep] - srow[-1]) + + std::abs(srow[+bstep] - srow[1])); + brow[N5] = (ushort)(brow[N3] + std::abs(srow[-bstep] - srow[1]) + + std::abs(srow[+bstep] - srow[-1])); + brow[N6] = (ushort)((srow[-bstep] + srow[-1] + srow[1] + srow[+bstep])>>1); + } + } + + const ushort* brow0 = buf + ((y - 2) % brows)*bufstep + 2; + const ushort* brow1 = buf + ((y - 1) % brows)*bufstep + 2; + const ushort* brow2 = buf + (y % brows)*bufstep + 2; + static const float scale[] = { 0.f, 0.5f, 0.25f, 0.1666666666667f, 0.125f, 0.1f, 0.08333333333f, 0.0714286f, 0.0625f }; + srow = bayer + y*bstep + 2; + bool greenCell = greenCell0; + + i = 2; +#if CV_SSE2 + int limit = !haveSSE ? N-2 : greenCell ? std::min(3, N-2) : 2; +#else + int limit = N - 2; +#endif + + do + { + for( ; i < limit; i++, srow++, brow0++, brow1++, brow2++, dstrow += 3 ) + { + int gradN = brow0[0] + brow1[0]; + int gradS = brow1[0] + brow2[0]; + int gradW = brow1[N-1] + brow1[N]; + int gradE = brow1[N] + brow1[N+1]; + int minGrad = std::min(std::min(std::min(gradN, gradS), gradW), gradE); + int maxGrad = std::max(std::max(std::max(gradN, gradS), gradW), gradE); + int R, G, B; + + if( !greenCell ) + { + int gradNE = brow0[N4+1] + brow1[N4]; + int gradSW = brow1[N4] + brow2[N4-1]; + int gradNW = brow0[N5-1] + brow1[N5]; + int gradSE = brow1[N5] + brow2[N5+1]; + + minGrad = std::min(std::min(std::min(std::min(minGrad, gradNE), gradSW), gradNW), gradSE); + maxGrad = std::max(std::max(std::max(std::max(maxGrad, gradNE), gradSW), gradNW), gradSE); + int T = minGrad + maxGrad/2; + + int Rs = 0, Gs = 0, Bs = 0, ng = 0; + if( gradN < T ) + { + Rs += srow[-bstep*2] + srow[0]; + Gs += srow[-bstep]*2; + Bs += srow[-bstep-1] + srow[-bstep+1]; + ng++; + } + if( gradS < T ) + { + Rs += srow[bstep*2] + srow[0]; + Gs += srow[bstep]*2; + Bs += srow[bstep-1] + srow[bstep+1]; + ng++; + } + if( gradW < T ) + { + Rs += srow[-2] + srow[0]; + Gs += srow[-1]*2; + Bs += srow[-bstep-1] + srow[bstep-1]; + ng++; + } + if( gradE < T ) + { + Rs += srow[2] + srow[0]; + Gs += srow[1]*2; + Bs += srow[-bstep+1] + srow[bstep+1]; + ng++; + } + if( gradNE < T ) + { + Rs += srow[-bstep*2+2] + srow[0]; + Gs += brow0[N6+1]; + Bs += srow[-bstep+1]*2; + ng++; + } + if( gradSW < T ) + { + Rs += srow[bstep*2-2] + srow[0]; + Gs += brow2[N6-1]; + Bs += srow[bstep-1]*2; + ng++; + } + if( gradNW < T ) + { + Rs += srow[-bstep*2-2] + srow[0]; + Gs += brow0[N6-1]; + Bs += srow[-bstep+1]*2; + ng++; + } + if( gradSE < T ) + { + Rs += srow[bstep*2+2] + srow[0]; + Gs += brow2[N6+1]; + Bs += srow[-bstep+1]*2; + ng++; + } + R = srow[0]; + G = R + cvRound((Gs - Rs)*scale[ng]); + B = R + cvRound((Bs - Rs)*scale[ng]); + } + else + { + int gradNE = brow0[N2] + brow0[N2+1] + brow1[N2] + brow1[N2+1]; + int gradSW = brow1[N2] + brow1[N2-1] + brow2[N2] + brow2[N2-1]; + int gradNW = brow0[N3] + brow0[N3-1] + brow1[N3] + brow1[N3-1]; + int gradSE = brow1[N3] + brow1[N3+1] + brow2[N3] + brow2[N3+1]; + + minGrad = std::min(std::min(std::min(std::min(minGrad, gradNE), gradSW), gradNW), gradSE); + maxGrad = std::max(std::max(std::max(std::max(maxGrad, gradNE), gradSW), gradNW), gradSE); + int T = minGrad + maxGrad/2; + + int Rs = 0, Gs = 0, Bs = 0, ng = 0; + if( gradN < T ) + { + Rs += srow[-bstep*2-1] + srow[-bstep*2+1]; + Gs += srow[-bstep*2] + srow[0]; + Bs += srow[-bstep]*2; + ng++; + } + if( gradS < T ) + { + Rs += srow[bstep*2-1] + srow[bstep*2+1]; + Gs += srow[bstep*2] + srow[0]; + Bs += srow[bstep]*2; + ng++; + } + if( gradW < T ) + { + Rs += srow[-1]*2; + Gs += srow[-2] + srow[0]; + Bs += srow[-bstep-2]+srow[bstep-2]; + ng++; + } + if( gradE < T ) + { + Rs += srow[1]*2; + Gs += srow[2] + srow[0]; + Bs += srow[-bstep+2]+srow[bstep+2]; + ng++; + } + if( gradNE < T ) + { + Rs += srow[-bstep*2+1] + srow[1]; + Gs += srow[-bstep+1]*2; + Bs += srow[-bstep] + srow[-bstep+2]; + ng++; + } + if( gradSW < T ) + { + Rs += srow[bstep*2-1] + srow[-1]; + Gs += srow[bstep-1]*2; + Bs += srow[bstep] + srow[bstep-2]; + ng++; + } + if( gradNW < T ) + { + Rs += srow[-bstep*2-1] + srow[-1]; + Gs += srow[-bstep-1]*2; + Bs += srow[-bstep-2]+srow[-bstep]; + ng++; + } + if( gradSE < T ) + { + Rs += srow[bstep*2+1] + srow[1]; + Gs += srow[bstep+1]*2; + Bs += srow[bstep+2]+srow[bstep]; + ng++; + } + G = srow[0]; + R = G + cvRound((Rs - Gs)*scale[ng]); + B = G + cvRound((Bs - Gs)*scale[ng]); + } + dstrow[blueIdx] = CV_CAST_8U(B); + dstrow[1] = CV_CAST_8U(G); + dstrow[blueIdx^2] = CV_CAST_8U(R); + greenCell = !greenCell; + } + +#if CV_SSE2 + if( !haveSSE ) + break; + + __m128i emask = _mm_set1_epi32(0x0000ffff), + omask = _mm_set1_epi32(0xffff0000), + z = _mm_setzero_si128(); + __m128 _0_5 = _mm_set1_ps(0.5f); + + #define _mm_merge_epi16(a, b) _mm_or_si128(_mm_and_si128(a, emask), _mm_and_si128(b, omask)) //(aA_aA_aA_aA) * (bB_bB_bB_bB) => (bA_bA_bA_bA) + #define _mm_cvtloepi16_ps(a) _mm_cvtepi32_ps(_mm_srai_epi32(_mm_unpacklo_epi16(a,a), 16)) //(1,2,3,4,5,6,7,8) => (1f,2f,3f,4f) + #define _mm_cvthiepi16_ps(a) _mm_cvtepi32_ps(_mm_srai_epi32(_mm_unpackhi_epi16(a,a), 16)) //(1,2,3,4,5,6,7,8) => (5f,6f,7f,8f) + #define _mm_loadl_u8_s16(ptr, offset) _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)((ptr) + (offset))), z) //load 8 uchars to 8 shorts + + // process 8 pixels at once + for( ; i <= N - 10; i += 8, srow += 8, brow0 += 8, brow1 += 8, brow2 += 8 ) + { + //int gradN = brow0[0] + brow1[0]; + __m128i gradN = _mm_adds_epi16(_mm_loadu_si128((__m128i*)brow0), _mm_loadu_si128((__m128i*)brow1)); + + //int gradS = brow1[0] + brow2[0]; + __m128i gradS = _mm_adds_epi16(_mm_loadu_si128((__m128i*)brow1), _mm_loadu_si128((__m128i*)brow2)); + + //int gradW = brow1[N-1] + brow1[N]; + __m128i gradW = _mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow1+N-1)), _mm_loadu_si128((__m128i*)(brow1+N))); + + //int gradE = brow1[N+1] + brow1[N]; + __m128i gradE = _mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow1+N+1)), _mm_loadu_si128((__m128i*)(brow1+N))); + + //int minGrad = std::min(std::min(std::min(gradN, gradS), gradW), gradE); + //int maxGrad = std::max(std::max(std::max(gradN, gradS), gradW), gradE); + __m128i minGrad = _mm_min_epi16(_mm_min_epi16(gradN, gradS), _mm_min_epi16(gradW, gradE)); + __m128i maxGrad = _mm_max_epi16(_mm_max_epi16(gradN, gradS), _mm_max_epi16(gradW, gradE)); + + __m128i grad0, grad1; + + //int gradNE = brow0[N4+1] + brow1[N4]; + //int gradNE = brow0[N2] + brow0[N2+1] + brow1[N2] + brow1[N2+1]; + grad0 = _mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow0+N4+1)), _mm_loadu_si128((__m128i*)(brow1+N4))); + grad1 = _mm_adds_epi16( _mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow0+N2)), _mm_loadu_si128((__m128i*)(brow0+N2+1))), + _mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow1+N2)), _mm_loadu_si128((__m128i*)(brow1+N2+1)))); + __m128i gradNE = _mm_merge_epi16(grad0, grad1); + + //int gradSW = brow1[N4] + brow2[N4-1]; + //int gradSW = brow1[N2] + brow1[N2-1] + brow2[N2] + brow2[N2-1]; + grad0 = _mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow2+N4-1)), _mm_loadu_si128((__m128i*)(brow1+N4))); + grad1 = _mm_adds_epi16(_mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow2+N2)), _mm_loadu_si128((__m128i*)(brow2+N2-1))), + _mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow1+N2)), _mm_loadu_si128((__m128i*)(brow1+N2-1)))); + __m128i gradSW = _mm_merge_epi16(grad0, grad1); + + minGrad = _mm_min_epi16(_mm_min_epi16(minGrad, gradNE), gradSW); + maxGrad = _mm_max_epi16(_mm_max_epi16(maxGrad, gradNE), gradSW); + + //int gradNW = brow0[N5-1] + brow1[N5]; + //int gradNW = brow0[N3] + brow0[N3-1] + brow1[N3] + brow1[N3-1]; + grad0 = _mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow0+N5-1)), _mm_loadu_si128((__m128i*)(brow1+N5))); + grad1 = _mm_adds_epi16(_mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow0+N3)), _mm_loadu_si128((__m128i*)(brow0+N3-1))), + _mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow1+N3)), _mm_loadu_si128((__m128i*)(brow1+N3-1)))); + __m128i gradNW = _mm_merge_epi16(grad0, grad1); + + //int gradSE = brow1[N5] + brow2[N5+1]; + //int gradSE = brow1[N3] + brow1[N3+1] + brow2[N3] + brow2[N3+1]; + grad0 = _mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow2+N5+1)), _mm_loadu_si128((__m128i*)(brow1+N5))); + grad1 = _mm_adds_epi16(_mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow2+N3)), _mm_loadu_si128((__m128i*)(brow2+N3+1))), + _mm_adds_epi16(_mm_loadu_si128((__m128i*)(brow1+N3)), _mm_loadu_si128((__m128i*)(brow1+N3+1)))); + __m128i gradSE = _mm_merge_epi16(grad0, grad1); + + minGrad = _mm_min_epi16(_mm_min_epi16(minGrad, gradNW), gradSE); + maxGrad = _mm_max_epi16(_mm_max_epi16(maxGrad, gradNW), gradSE); + + //int T = minGrad + maxGrad/2; + __m128i T = _mm_adds_epi16(_mm_srli_epi16(maxGrad, 1), minGrad); + + __m128i RGs = z, GRs = z, Bs = z, ng = z; + + __m128i x0 = _mm_loadl_u8_s16(srow, +0 ); + __m128i x1 = _mm_loadl_u8_s16(srow, -1 - bstep ); + __m128i x2 = _mm_loadl_u8_s16(srow, -1 - bstep*2); + __m128i x3 = _mm_loadl_u8_s16(srow, - bstep ); + __m128i x4 = _mm_loadl_u8_s16(srow, +1 - bstep*2); + __m128i x5 = _mm_loadl_u8_s16(srow, +1 - bstep ); + __m128i x6 = _mm_loadl_u8_s16(srow, +2 - bstep ); + __m128i x7 = _mm_loadl_u8_s16(srow, +1 ); + __m128i x8 = _mm_loadl_u8_s16(srow, +2 + bstep ); + __m128i x9 = _mm_loadl_u8_s16(srow, +1 + bstep ); + __m128i x10 = _mm_loadl_u8_s16(srow, +1 + bstep*2); + __m128i x11 = _mm_loadl_u8_s16(srow, + bstep ); + __m128i x12 = _mm_loadl_u8_s16(srow, -1 + bstep*2); + __m128i x13 = _mm_loadl_u8_s16(srow, -1 + bstep ); + __m128i x14 = _mm_loadl_u8_s16(srow, -2 + bstep ); + __m128i x15 = _mm_loadl_u8_s16(srow, -1 ); + __m128i x16 = _mm_loadl_u8_s16(srow, -2 - bstep ); + + __m128i t0, t1, mask; + + // gradN *********************************************** + mask = _mm_cmpgt_epi16(T, gradN); // mask = T>gradN + ng = _mm_sub_epi16(ng, mask); // ng += (T>gradN) + + t0 = _mm_slli_epi16(x3, 1); // srow[-bstep]*2 + t1 = _mm_adds_epi16(_mm_loadl_u8_s16(srow, -bstep*2), x0); // srow[-bstep*2] + srow[0] + + // RGs += (srow[-bstep*2] + srow[0]) * (T>gradN) + RGs = _mm_adds_epi16(RGs, _mm_and_si128(t1, mask)); + // GRs += {srow[-bstep]*2; (srow[-bstep*2-1] + srow[-bstep*2+1])} * (T>gradN) + GRs = _mm_adds_epi16(GRs, _mm_and_si128(_mm_merge_epi16(t0, _mm_adds_epi16(x2,x4)), mask)); + // Bs += {(srow[-bstep-1]+srow[-bstep+1]); srow[-bstep]*2 } * (T>gradN) + Bs = _mm_adds_epi16(Bs, _mm_and_si128(_mm_merge_epi16(_mm_adds_epi16(x1,x5), t0), mask)); + + // gradNE ********************************************** + mask = _mm_cmpgt_epi16(T, gradNE); // mask = T>gradNE + ng = _mm_sub_epi16(ng, mask); // ng += (T>gradNE) + + t0 = _mm_slli_epi16(x5, 1); // srow[-bstep+1]*2 + t1 = _mm_adds_epi16(_mm_loadl_u8_s16(srow, -bstep*2+2), x0); // srow[-bstep*2+2] + srow[0] + + // RGs += {(srow[-bstep*2+2] + srow[0]); srow[-bstep+1]*2} * (T>gradNE) + RGs = _mm_adds_epi16(RGs, _mm_and_si128(_mm_merge_epi16(t1, t0), mask)); + // GRs += {brow0[N6+1]; (srow[-bstep*2+1] + srow[1])} * (T>gradNE) + GRs = _mm_adds_epi16(GRs, _mm_and_si128(_mm_merge_epi16(_mm_loadu_si128((__m128i*)(brow0+N6+1)), _mm_adds_epi16(x4,x7)), mask)); + // Bs += {srow[-bstep+1]*2; (srow[-bstep] + srow[-bstep+2])} * (T>gradNE) + Bs = _mm_adds_epi16(Bs, _mm_and_si128(_mm_merge_epi16(t0,_mm_adds_epi16(x3,x6)), mask)); + + // gradE *********************************************** + mask = _mm_cmpgt_epi16(T, gradE); // mask = T>gradE + ng = _mm_sub_epi16(ng, mask); // ng += (T>gradE) + + t0 = _mm_slli_epi16(x7, 1); // srow[1]*2 + t1 = _mm_adds_epi16(_mm_loadl_u8_s16(srow, 2), x0); // srow[2] + srow[0] + + // RGs += (srow[2] + srow[0]) * (T>gradE) + RGs = _mm_adds_epi16(RGs, _mm_and_si128(t1, mask)); + // GRs += (srow[1]*2) * (T>gradE) + GRs = _mm_adds_epi16(GRs, _mm_and_si128(t0, mask)); + // Bs += {(srow[-bstep+1]+srow[bstep+1]); (srow[-bstep+2]+srow[bstep+2])} * (T>gradE) + Bs = _mm_adds_epi16(Bs, _mm_and_si128(_mm_merge_epi16(_mm_adds_epi16(x5,x9), _mm_adds_epi16(x6,x8)), mask)); + + // gradSE ********************************************** + mask = _mm_cmpgt_epi16(T, gradSE); // mask = T>gradSE + ng = _mm_sub_epi16(ng, mask); // ng += (T>gradSE) + + t0 = _mm_slli_epi16(x9, 1); // srow[bstep+1]*2 + t1 = _mm_adds_epi16(_mm_loadl_u8_s16(srow, bstep*2+2), x0); // srow[bstep*2+2] + srow[0] + + // RGs += {(srow[bstep*2+2] + srow[0]); srow[bstep+1]*2} * (T>gradSE) + RGs = _mm_adds_epi16(RGs, _mm_and_si128(_mm_merge_epi16(t1, t0), mask)); + // GRs += {brow2[N6+1]; (srow[1]+srow[bstep*2+1])} * (T>gradSE) + GRs = _mm_adds_epi16(GRs, _mm_and_si128(_mm_merge_epi16(_mm_loadu_si128((__m128i*)(brow2+N6+1)), _mm_adds_epi16(x7,x10)), mask)); + // Bs += {srow[-bstep+1]*2; (srow[bstep+2]+srow[bstep])} * (T>gradSE) + Bs = _mm_adds_epi16(Bs, _mm_and_si128(_mm_merge_epi16(_mm_slli_epi16(x5, 1), _mm_adds_epi16(x8,x11)), mask)); + + // gradS *********************************************** + mask = _mm_cmpgt_epi16(T, gradS); // mask = T>gradS + ng = _mm_sub_epi16(ng, mask); // ng += (T>gradS) + + t0 = _mm_slli_epi16(x11, 1); // srow[bstep]*2 + t1 = _mm_adds_epi16(_mm_loadl_u8_s16(srow,bstep*2), x0); // srow[bstep*2]+srow[0] + + // RGs += (srow[bstep*2]+srow[0]) * (T>gradS) + RGs = _mm_adds_epi16(RGs, _mm_and_si128(t1, mask)); + // GRs += {srow[bstep]*2; (srow[bstep*2+1]+srow[bstep*2-1])} * (T>gradS) + GRs = _mm_adds_epi16(GRs, _mm_and_si128(_mm_merge_epi16(t0, _mm_adds_epi16(x10,x12)), mask)); + // Bs += {(srow[bstep+1]+srow[bstep-1]); srow[bstep]*2} * (T>gradS) + Bs = _mm_adds_epi16(Bs, _mm_and_si128(_mm_merge_epi16(_mm_adds_epi16(x9,x13), t0), mask)); + + // gradSW ********************************************** + mask = _mm_cmpgt_epi16(T, gradSW); // mask = T>gradSW + ng = _mm_sub_epi16(ng, mask); // ng += (T>gradSW) + + t0 = _mm_slli_epi16(x13, 1); // srow[bstep-1]*2 + t1 = _mm_adds_epi16(_mm_loadl_u8_s16(srow, bstep*2-2), x0); // srow[bstep*2-2]+srow[0] + + // RGs += {(srow[bstep*2-2]+srow[0]); srow[bstep-1]*2} * (T>gradSW) + RGs = _mm_adds_epi16(RGs, _mm_and_si128(_mm_merge_epi16(t1, t0), mask)); + // GRs += {brow2[N6-1]; (srow[bstep*2-1]+srow[-1])} * (T>gradSW) + GRs = _mm_adds_epi16(GRs, _mm_and_si128(_mm_merge_epi16(_mm_loadu_si128((__m128i*)(brow2+N6-1)), _mm_adds_epi16(x12,x15)), mask)); + // Bs += {srow[bstep-1]*2; (srow[bstep]+srow[bstep-2])} * (T>gradSW) + Bs = _mm_adds_epi16(Bs, _mm_and_si128(_mm_merge_epi16(t0,_mm_adds_epi16(x11,x14)), mask)); + + // gradW *********************************************** + mask = _mm_cmpgt_epi16(T, gradW); // mask = T>gradW + ng = _mm_sub_epi16(ng, mask); // ng += (T>gradW) + + t0 = _mm_slli_epi16(x15, 1); // srow[-1]*2 + t1 = _mm_adds_epi16(_mm_loadl_u8_s16(srow, -2), x0); // srow[-2]+srow[0] + + // RGs += (srow[-2]+srow[0]) * (T>gradW) + RGs = _mm_adds_epi16(RGs, _mm_and_si128(t1, mask)); + // GRs += (srow[-1]*2) * (T>gradW) + GRs = _mm_adds_epi16(GRs, _mm_and_si128(t0, mask)); + // Bs += {(srow[-bstep-1]+srow[bstep-1]); (srow[bstep-2]+srow[-bstep-2])} * (T>gradW) + Bs = _mm_adds_epi16(Bs, _mm_and_si128(_mm_merge_epi16(_mm_adds_epi16(x1,x13), _mm_adds_epi16(x14,x16)), mask)); + + // gradNW ********************************************** + mask = _mm_cmpgt_epi16(T, gradNW); // mask = T>gradNW + ng = _mm_sub_epi16(ng, mask); // ng += (T>gradNW) + + t0 = _mm_slli_epi16(x1, 1); // srow[-bstep-1]*2 + t1 = _mm_adds_epi16(_mm_loadl_u8_s16(srow,-bstep*2-2), x0); // srow[-bstep*2-2]+srow[0] + + // RGs += {(srow[-bstep*2-2]+srow[0]); srow[-bstep-1]*2} * (T>gradNW) + RGs = _mm_adds_epi16(RGs, _mm_and_si128(_mm_merge_epi16(t1, t0), mask)); + // GRs += {brow0[N6-1]; (srow[-bstep*2-1]+srow[-1])} * (T>gradNW) + GRs = _mm_adds_epi16(GRs, _mm_and_si128(_mm_merge_epi16(_mm_loadu_si128((__m128i*)(brow0+N6-1)), _mm_adds_epi16(x2,x15)), mask)); + // Bs += {srow[-bstep-1]*2; (srow[-bstep]+srow[-bstep-2])} * (T>gradNW) + Bs = _mm_adds_epi16(Bs, _mm_and_si128(_mm_merge_epi16(_mm_slli_epi16(x5, 1),_mm_adds_epi16(x3,x16)), mask)); + + __m128 ngf0, ngf1; + ngf0 = _mm_div_ps(_0_5, _mm_cvtloepi16_ps(ng)); + ngf1 = _mm_div_ps(_0_5, _mm_cvthiepi16_ps(ng)); + + // now interpolate r, g & b + t0 = _mm_sub_epi16(GRs, RGs); + t1 = _mm_sub_epi16(Bs, RGs); + + t0 = _mm_add_epi16(x0, _mm_packs_epi32( + _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtloepi16_ps(t0), ngf0)), + _mm_cvtps_epi32(_mm_mul_ps(_mm_cvthiepi16_ps(t0), ngf1)))); + + t1 = _mm_add_epi16(x0, _mm_packs_epi32( + _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtloepi16_ps(t1), ngf0)), + _mm_cvtps_epi32(_mm_mul_ps(_mm_cvthiepi16_ps(t1), ngf1)))); + + x1 = _mm_merge_epi16(x0, t0); + x2 = _mm_merge_epi16(t0, x0); + + uchar R[8], G[8], B[8]; + + _mm_storel_epi64(blueIdx ? (__m128i*)B : (__m128i*)R, _mm_packus_epi16(x1, z)); + _mm_storel_epi64((__m128i*)G, _mm_packus_epi16(x2, z)); + _mm_storel_epi64(blueIdx ? (__m128i*)R : (__m128i*)B, _mm_packus_epi16(t1, z)); + + for( int j = 0; j < 8; j++, dstrow += 3 ) + { + dstrow[0] = B[j]; dstrow[1] = G[j]; dstrow[2] = R[j]; + } + } +#endif + + limit = N - 2; + } + while( i < N - 2 ); + + for( i = 0; i < 6; i++ ) + { + dst[dststep*y + 5 - i] = dst[dststep*y + 8 - i]; + dst[dststep*y + (N - 2)*3 + i] = dst[dststep*y + (N - 3)*3 + i]; + } + + greenCell0 = !greenCell0; + blueIdx ^= 2; + } + + for( i = 0; i < size.width*3; i++ ) + { + dst[i] = dst[i + dststep] = dst[i + dststep*2]; + dst[i + dststep*(size.height-4)] = + dst[i + dststep*(size.height-3)] = + dst[i + dststep*(size.height-2)] = + dst[i + dststep*(size.height-1)] = dst[i + dststep*(size.height-5)]; + } +} + +///////////////////////////////////// YUV420 -> RGB ///////////////////////////////////// + +const int ITUR_BT_601_CY = 1220542; +const int ITUR_BT_601_CUB = 2116026; +const int ITUR_BT_601_CUG = -409993; +const int ITUR_BT_601_CVG = -852492; +const int ITUR_BT_601_CVR = 1673527; +const int ITUR_BT_601_SHIFT = 20; + +template +struct YUV420sp2RGB888Invoker +{ + Mat* dst; + const uchar* my1, *muv; + int width, stride; + + YUV420sp2RGB888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _uv) + : dst(_dst), my1(_y1), muv(_uv), width(_dst->cols), stride(_stride) {} + + void operator()(const BlockedRange& range) const + { + int rangeBegin = range.begin() * 2; + int rangeEnd = range.end() * 2; + + //R = 1.164(Y - 16) + 1.596(V - 128) + //G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128) + //B = 1.164(Y - 16) + 2.018(U - 128) + + //R = (1220542(Y - 16) + 1673527(V - 128) + (1 << 19)) >> 20 + //G = (1220542(Y - 16) - 852492(V - 128) - 409993(U - 128) + (1 << 19)) >> 20 + //B = (1220542(Y - 16) + 2116026(U - 128) + (1 << 19)) >> 20 + + const uchar* y1 = my1 + rangeBegin * stride, *uv = muv + rangeBegin * stride / 2; + +#ifdef HAVE_TEGRA_OPTIMIZATION + if(tegra::cvtYUV4202RGB(bIdx, uIdx, 3, y1, uv, stride, dst->ptr(rangeBegin), dst->step, rangeEnd - rangeBegin, dst->cols)) + return; +#endif + + for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, uv += stride) + { + uchar* row1 = dst->ptr(j); + uchar* row2 = dst->ptr(j + 1); + const uchar* y2 = y1 + stride; + + for (int i = 0; i < width; i += 2, row1 += 6, row2 += 6) + { + int u = int(uv[i + 0 + uIdx]) - 128; + int v = int(uv[i + 1 - uIdx]) - 128; + + int ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * v; + int guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * v + ITUR_BT_601_CUG * u; + int buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * u; + + int y00 = std::max(0, int(y1[i]) - 16) * ITUR_BT_601_CY; + row1[2-bIdx] = saturate_cast((y00 + ruv) >> ITUR_BT_601_SHIFT); + row1[1] = saturate_cast((y00 + guv) >> ITUR_BT_601_SHIFT); + row1[bIdx] = saturate_cast((y00 + buv) >> ITUR_BT_601_SHIFT); + + int y01 = std::max(0, int(y1[i + 1]) - 16) * ITUR_BT_601_CY; + row1[5-bIdx] = saturate_cast((y01 + ruv) >> ITUR_BT_601_SHIFT); + row1[4] = saturate_cast((y01 + guv) >> ITUR_BT_601_SHIFT); + row1[3+bIdx] = saturate_cast((y01 + buv) >> ITUR_BT_601_SHIFT); + + int y10 = std::max(0, int(y2[i]) - 16) * ITUR_BT_601_CY; + row2[2-bIdx] = saturate_cast((y10 + ruv) >> ITUR_BT_601_SHIFT); + row2[1] = saturate_cast((y10 + guv) >> ITUR_BT_601_SHIFT); + row2[bIdx] = saturate_cast((y10 + buv) >> ITUR_BT_601_SHIFT); + + int y11 = std::max(0, int(y2[i + 1]) - 16) * ITUR_BT_601_CY; + row2[5-bIdx] = saturate_cast((y11 + ruv) >> ITUR_BT_601_SHIFT); + row2[4] = saturate_cast((y11 + guv) >> ITUR_BT_601_SHIFT); + row2[3+bIdx] = saturate_cast((y11 + buv) >> ITUR_BT_601_SHIFT); + } + } + } +}; + +template +struct YUV420sp2RGBA8888Invoker +{ + Mat* dst; + const uchar* my1, *muv; + int width, stride; + + YUV420sp2RGBA8888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _uv) + : dst(_dst), my1(_y1), muv(_uv), width(_dst->cols), stride(_stride) {} + + void operator()(const BlockedRange& range) const + { + int rangeBegin = range.begin() * 2; + int rangeEnd = range.end() * 2; + + //R = 1.164(Y - 16) + 1.596(V - 128) + //G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128) + //B = 1.164(Y - 16) + 2.018(U - 128) + + //R = (1220542(Y - 16) + 1673527(V - 128) + (1 << 19)) >> 20 + //G = (1220542(Y - 16) - 852492(V - 128) - 409993(U - 128) + (1 << 19)) >> 20 + //B = (1220542(Y - 16) + 2116026(U - 128) + (1 << 19)) >> 20 + + const uchar* y1 = my1 + rangeBegin * stride, *uv = muv + rangeBegin * stride / 2; + +#ifdef HAVE_TEGRA_OPTIMIZATION + if(tegra::cvtYUV4202RGB(bIdx, uIdx, 4, y1, uv, stride, dst->ptr(rangeBegin), dst->step, rangeEnd - rangeBegin, dst->cols)) + return; +#endif + + for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, uv += stride) + { + uchar* row1 = dst->ptr(j); + uchar* row2 = dst->ptr(j + 1); + const uchar* y2 = y1 + stride; + + for (int i = 0; i < width; i += 2, row1 += 8, row2 += 8) + { + int u = int(uv[i + 0 + uIdx]) - 128; + int v = int(uv[i + 1 - uIdx]) - 128; + + int ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * v; + int guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * v + ITUR_BT_601_CUG * u; + int buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * u; + + int y00 = std::max(0, int(y1[i]) - 16) * ITUR_BT_601_CY; + row1[2-bIdx] = saturate_cast((y00 + ruv) >> ITUR_BT_601_SHIFT); + row1[1] = saturate_cast((y00 + guv) >> ITUR_BT_601_SHIFT); + row1[bIdx] = saturate_cast((y00 + buv) >> ITUR_BT_601_SHIFT); + row1[3] = uchar(0xff); + + int y01 = std::max(0, int(y1[i + 1]) - 16) * ITUR_BT_601_CY; + row1[6-bIdx] = saturate_cast((y01 + ruv) >> ITUR_BT_601_SHIFT); + row1[5] = saturate_cast((y01 + guv) >> ITUR_BT_601_SHIFT); + row1[4+bIdx] = saturate_cast((y01 + buv) >> ITUR_BT_601_SHIFT); + row1[7] = uchar(0xff); + + int y10 = std::max(0, int(y2[i]) - 16) * ITUR_BT_601_CY; + row2[2-bIdx] = saturate_cast((y10 + ruv) >> ITUR_BT_601_SHIFT); + row2[1] = saturate_cast((y10 + guv) >> ITUR_BT_601_SHIFT); + row2[bIdx] = saturate_cast((y10 + buv) >> ITUR_BT_601_SHIFT); + row2[3] = uchar(0xff); + + int y11 = std::max(0, int(y2[i + 1]) - 16) * ITUR_BT_601_CY; + row2[6-bIdx] = saturate_cast((y11 + ruv) >> ITUR_BT_601_SHIFT); + row2[5] = saturate_cast((y11 + guv) >> ITUR_BT_601_SHIFT); + row2[4+bIdx] = saturate_cast((y11 + buv) >> ITUR_BT_601_SHIFT); + row2[7] = uchar(0xff); + } + } + } +}; + +template +struct YUV420p2RGB888Invoker +{ + Mat* dst; + const uchar* my1, *mu, *mv; + int width, stride; + int ustepIdx, vstepIdx; + + YUV420p2RGB888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int _ustepIdx, int _vstepIdx) + : dst(_dst), my1(_y1), mu(_u), mv(_v), width(_dst->cols), stride(_stride), ustepIdx(_ustepIdx), vstepIdx(_vstepIdx) {} + + void operator()(const BlockedRange& range) const + { + const int rangeBegin = range.begin() * 2; + const int rangeEnd = range.end() * 2; + + size_t uvsteps[2] = {width/2, stride - width/2}; + int usIdx = ustepIdx, vsIdx = vstepIdx; + + const uchar* y1 = my1 + rangeBegin * stride; + const uchar* u1 = mu + (range.begin() / 2) * stride; + const uchar* v1 = mv + (range.begin() / 2) * stride; + + if(range.begin() % 2 == 1) + { + u1 += uvsteps[(usIdx++) & 1]; + v1 += uvsteps[(vsIdx++) & 1]; + } + + for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, u1 += uvsteps[(usIdx++) & 1], v1 += uvsteps[(vsIdx++) & 1]) + { + uchar* row1 = dst->ptr(j); + uchar* row2 = dst->ptr(j + 1); + const uchar* y2 = y1 + stride; + + for (int i = 0; i < width / 2; i += 1, row1 += 6, row2 += 6) + { + int u = int(u1[i]) - 128; + int v = int(v1[i]) - 128; + + int ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * v; + int guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * v + ITUR_BT_601_CUG * u; + int buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * u; + + int y00 = std::max(0, int(y1[2 * i]) - 16) * ITUR_BT_601_CY; + row1[2-bIdx] = saturate_cast((y00 + ruv) >> ITUR_BT_601_SHIFT); + row1[1] = saturate_cast((y00 + guv) >> ITUR_BT_601_SHIFT); + row1[bIdx] = saturate_cast((y00 + buv) >> ITUR_BT_601_SHIFT); + + int y01 = std::max(0, int(y1[2 * i + 1]) - 16) * ITUR_BT_601_CY; + row1[5-bIdx] = saturate_cast((y01 + ruv) >> ITUR_BT_601_SHIFT); + row1[4] = saturate_cast((y01 + guv) >> ITUR_BT_601_SHIFT); + row1[3+bIdx] = saturate_cast((y01 + buv) >> ITUR_BT_601_SHIFT); + + int y10 = std::max(0, int(y2[2 * i]) - 16) * ITUR_BT_601_CY; + row2[2-bIdx] = saturate_cast((y10 + ruv) >> ITUR_BT_601_SHIFT); + row2[1] = saturate_cast((y10 + guv) >> ITUR_BT_601_SHIFT); + row2[bIdx] = saturate_cast((y10 + buv) >> ITUR_BT_601_SHIFT); + + int y11 = std::max(0, int(y2[2 * i + 1]) - 16) * ITUR_BT_601_CY; + row2[5-bIdx] = saturate_cast((y11 + ruv) >> ITUR_BT_601_SHIFT); + row2[4] = saturate_cast((y11 + guv) >> ITUR_BT_601_SHIFT); + row2[3+bIdx] = saturate_cast((y11 + buv) >> ITUR_BT_601_SHIFT); + } + } + } +}; + +template +struct YUV420p2RGBA8888Invoker +{ + Mat* dst; + const uchar* my1, *mu, *mv; + int width, stride; + int ustepIdx, vstepIdx; + + YUV420p2RGBA8888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int _ustepIdx, int _vstepIdx) + : dst(_dst), my1(_y1), mu(_u), mv(_v), width(_dst->cols), stride(_stride), ustepIdx(_ustepIdx), vstepIdx(_vstepIdx) {} + + void operator()(const BlockedRange& range) const + { + int rangeBegin = range.begin() * 2; + int rangeEnd = range.end() * 2; + + size_t uvsteps[2] = {width/2, stride - width/2}; + int usIdx = ustepIdx, vsIdx = vstepIdx; + + const uchar* y1 = my1 + rangeBegin * stride; + const uchar* u1 = mu + (range.begin() / 2) * stride; + const uchar* v1 = mv + (range.begin() / 2) * stride; + + if(range.begin() % 2 == 1) + { + u1 += uvsteps[(usIdx++) & 1]; + v1 += uvsteps[(vsIdx++) & 1]; + } + + for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, u1 += uvsteps[(usIdx++) & 1], v1 += uvsteps[(vsIdx++) & 1]) + { + uchar* row1 = dst->ptr(j); + uchar* row2 = dst->ptr(j + 1); + const uchar* y2 = y1 + stride; + + for (int i = 0; i < width / 2; i += 1, row1 += 8, row2 += 8) + { + int u = int(u1[i]) - 128; + int v = int(v1[i]) - 128; + + int ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * v; + int guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * v + ITUR_BT_601_CUG * u; + int buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * u; + + int y00 = std::max(0, int(y1[2 * i]) - 16) * ITUR_BT_601_CY; + row1[2-bIdx] = saturate_cast((y00 + ruv) >> ITUR_BT_601_SHIFT); + row1[1] = saturate_cast((y00 + guv) >> ITUR_BT_601_SHIFT); + row1[bIdx] = saturate_cast((y00 + buv) >> ITUR_BT_601_SHIFT); + row1[3] = uchar(0xff); + + int y01 = std::max(0, int(y1[2 * i + 1]) - 16) * ITUR_BT_601_CY; + row1[6-bIdx] = saturate_cast((y01 + ruv) >> ITUR_BT_601_SHIFT); + row1[5] = saturate_cast((y01 + guv) >> ITUR_BT_601_SHIFT); + row1[4+bIdx] = saturate_cast((y01 + buv) >> ITUR_BT_601_SHIFT); + row1[7] = uchar(0xff); + + int y10 = std::max(0, int(y2[2 * i]) - 16) * ITUR_BT_601_CY; + row2[2-bIdx] = saturate_cast((y10 + ruv) >> ITUR_BT_601_SHIFT); + row2[1] = saturate_cast((y10 + guv) >> ITUR_BT_601_SHIFT); + row2[bIdx] = saturate_cast((y10 + buv) >> ITUR_BT_601_SHIFT); + row2[3] = uchar(0xff); + + int y11 = std::max(0, int(y2[2 * i + 1]) - 16) * ITUR_BT_601_CY; + row2[6-bIdx] = saturate_cast((y11 + ruv) >> ITUR_BT_601_SHIFT); + row2[5] = saturate_cast((y11 + guv) >> ITUR_BT_601_SHIFT); + row2[4+bIdx] = saturate_cast((y11 + buv) >> ITUR_BT_601_SHIFT); + row2[7] = uchar(0xff); + } + } + } +}; + +#define MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION (320*240) + +template +inline void cvtYUV420sp2RGB(Mat& _dst, int _stride, const uchar* _y1, const uchar* _uv) +{ + YUV420sp2RGB888Invoker converter(&_dst, _stride, _y1, _uv); +#ifdef HAVE_TBB + if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION) + parallel_for(BlockedRange(0, _dst.rows/2), converter); + else +#endif + converter(BlockedRange(0, _dst.rows/2)); +} + +template +inline void cvtYUV420sp2RGBA(Mat& _dst, int _stride, const uchar* _y1, const uchar* _uv) +{ + YUV420sp2RGBA8888Invoker converter(&_dst, _stride, _y1, _uv); +#ifdef HAVE_TBB + if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION) + parallel_for(BlockedRange(0, _dst.rows/2), converter); + else +#endif + converter(BlockedRange(0, _dst.rows/2)); +} + +template +inline void cvtYUV420p2RGB(Mat& _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int ustepIdx, int vstepIdx) +{ + YUV420p2RGB888Invoker converter(&_dst, _stride, _y1, _u, _v, ustepIdx, vstepIdx); +#ifdef HAVE_TBB + if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION) + parallel_for(BlockedRange(0, _dst.rows/2), converter); + else +#endif + converter(BlockedRange(0, _dst.rows/2)); +} + +template +inline void cvtYUV420p2RGBA(Mat& _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int ustepIdx, int vstepIdx) +{ + YUV420p2RGBA8888Invoker converter(&_dst, _stride, _y1, _u, _v, ustepIdx, vstepIdx); +#ifdef HAVE_TBB + if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION) + parallel_for(BlockedRange(0, _dst.rows/2), converter); + else +#endif + converter(BlockedRange(0, _dst.rows/2)); +} + +///////////////////////////////////// YUV422 -> RGB ///////////////////////////////////// + +template +struct YUV422toRGB888Invoker +{ + Mat* dst; + const uchar* src; + int width, stride; + + YUV422toRGB888Invoker(Mat* _dst, int _stride, const uchar* _yuv) + : dst(_dst), src(_yuv), width(_dst->cols), stride(_stride) {} + + void operator()(const BlockedRange& range) const + { + int rangeBegin = range.begin(); + int rangeEnd = range.end(); + + const int uidx = 1 - yIdx + uIdx * 2; + const int vidx = (2 + uidx) % 4; + const uchar* yuv_src = src + rangeBegin * stride; + + for (int j = rangeBegin; j < rangeEnd; j++, yuv_src += stride) + { + uchar* row = dst->ptr(j); + + for (int i = 0; i < 2 * width; i += 4, row += 6) + { + int u = int(yuv_src[i + uidx]) - 128; + int v = int(yuv_src[i + vidx]) - 128; + + int ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * v; + int guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * v + ITUR_BT_601_CUG * u; + int buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * u; + + int y00 = std::max(0, int(yuv_src[i + yIdx]) - 16) * ITUR_BT_601_CY; + row[2-bIdx] = saturate_cast((y00 + ruv) >> ITUR_BT_601_SHIFT); + row[1] = saturate_cast((y00 + guv) >> ITUR_BT_601_SHIFT); + row[bIdx] = saturate_cast((y00 + buv) >> ITUR_BT_601_SHIFT); + + int y01 = std::max(0, int(yuv_src[i + yIdx + 2]) - 16) * ITUR_BT_601_CY; + row[5-bIdx] = saturate_cast((y01 + ruv) >> ITUR_BT_601_SHIFT); + row[4] = saturate_cast((y01 + guv) >> ITUR_BT_601_SHIFT); + row[3+bIdx] = saturate_cast((y01 + buv) >> ITUR_BT_601_SHIFT); + } + } + } +}; + +template +struct YUV422toRGBA8888Invoker +{ + Mat* dst; + const uchar* src; + int width, stride; + + YUV422toRGBA8888Invoker(Mat* _dst, int _stride, const uchar* _yuv) + : dst(_dst), src(_yuv), width(_dst->cols), stride(_stride) {} + + void operator()(const BlockedRange& range) const + { + int rangeBegin = range.begin(); + int rangeEnd = range.end(); + + const int uidx = 1 - yIdx + uIdx * 2; + const int vidx = (2 + uidx) % 4; + const uchar* yuv_src = src + rangeBegin * stride; + + for (int j = rangeBegin; j < rangeEnd; j++, yuv_src += stride) + { + uchar* row = dst->ptr(j); + + for (int i = 0; i < 2 * width; i += 4, row += 8) + { + int u = int(yuv_src[i + uidx]) - 128; + int v = int(yuv_src[i + vidx]) - 128; + + int ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * v; + int guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * v + ITUR_BT_601_CUG * u; + int buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * u; + + int y00 = std::max(0, int(yuv_src[i + yIdx]) - 16) * ITUR_BT_601_CY; + row[2-bIdx] = saturate_cast((y00 + ruv) >> ITUR_BT_601_SHIFT); + row[1] = saturate_cast((y00 + guv) >> ITUR_BT_601_SHIFT); + row[bIdx] = saturate_cast((y00 + buv) >> ITUR_BT_601_SHIFT); + row[3] = uchar(0xff); + + int y01 = std::max(0, int(yuv_src[i + yIdx + 2]) - 16) * ITUR_BT_601_CY; + row[6-bIdx] = saturate_cast((y01 + ruv) >> ITUR_BT_601_SHIFT); + row[5] = saturate_cast((y01 + guv) >> ITUR_BT_601_SHIFT); + row[4+bIdx] = saturate_cast((y01 + buv) >> ITUR_BT_601_SHIFT); + row[7] = uchar(0xff); + } + } + } +}; + +#define MIN_SIZE_FOR_PARALLEL_YUV422_CONVERSION (320*240) + +template +inline void cvtYUV422toRGB(Mat& _dst, int _stride, const uchar* _yuv) +{ + YUV422toRGB888Invoker converter(&_dst, _stride, _yuv); +#ifdef HAVE_TBB + if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV422_CONVERSION) + parallel_for(BlockedRange(0, _dst.rows), converter); + else +#endif + converter(BlockedRange(0, _dst.rows)); +} + +template +inline void cvtYUV422toRGBA(Mat& _dst, int _stride, const uchar* _yuv) +{ + YUV422toRGBA8888Invoker converter(&_dst, _stride, _yuv); +#ifdef HAVE_TBB + if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV422_CONVERSION) + parallel_for(BlockedRange(0, _dst.rows), converter); + else +#endif + converter(BlockedRange(0, _dst.rows)); +} + +/////////////////////////// RGBA <-> mRGBA (alpha premultiplied) ////////////// + +template +struct RGBA2mRGBA +{ + typedef _Tp channel_type; + + void operator()(const _Tp* src, _Tp* dst, int n) const + { + _Tp max_val = ColorChannel<_Tp>::max(); + _Tp half_val = ColorChannel<_Tp>::half(); + for( int i = 0; i < n; i++ ) + { + _Tp v0 = *src++; + _Tp v1 = *src++; + _Tp v2 = *src++; + _Tp v3 = *src++; + + *dst++ = (v0 * v3 + half_val) / max_val; + *dst++ = (v1 * v3 + half_val) / max_val; + *dst++ = (v2 * v3 + half_val) / max_val; + *dst++ = v3; + } + } +}; + + +template +struct mRGBA2RGBA +{ + typedef _Tp channel_type; + + void operator()(const _Tp* src, _Tp* dst, int n) const + { + _Tp max_val = ColorChannel<_Tp>::max(); + for( int i = 0; i < n; i++ ) + { + _Tp v0 = *src++; + _Tp v1 = *src++; + _Tp v2 = *src++; + _Tp v3 = *src++; + _Tp v3_half = v3 / 2; + + *dst++ = (v3==0)? 0 : (v0 * max_val + v3_half) / v3; + *dst++ = (v3==0)? 0 : (v1 * max_val + v3_half) / v3; + *dst++ = (v3==0)? 0 : (v2 * max_val + v3_half) / v3; + *dst++ = v3; + } + } +}; + +}//namespace cv + +////////////////////////////////////////////////////////////////////////////////////////// +// The main function // +////////////////////////////////////////////////////////////////////////////////////////// + +void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn ) +{ + Mat src = _src.getMat(), dst; + Size sz = src.size(); + int scn = src.channels(), depth = src.depth(), bidx; + + CV_Assert( depth == CV_8U || depth == CV_16U || depth == CV_32F ); + + switch( code ) + { + case CV_BGR2BGRA: case CV_RGB2BGRA: case CV_BGRA2BGR: + case CV_RGBA2BGR: case CV_RGB2BGR: case CV_BGRA2RGBA: + CV_Assert( scn == 3 || scn == 4 ); + dcn = code == CV_BGR2BGRA || code == CV_RGB2BGRA || code == CV_BGRA2RGBA ? 4 : 3; + bidx = code == CV_BGR2BGRA || code == CV_BGRA2BGR ? 0 : 2; + + _dst.create( sz, CV_MAKETYPE(depth, dcn)); + dst = _dst.getMat(); + + if( depth == CV_8U ) + { +#ifdef HAVE_TEGRA_OPTIMIZATION + if(!tegra::cvtBGR2RGB(src, dst, bidx)) +#endif + CvtColorLoop(src, dst, RGB2RGB(scn, dcn, bidx)); + } + else if( depth == CV_16U ) + CvtColorLoop(src, dst, RGB2RGB(scn, dcn, bidx)); + else + CvtColorLoop(src, dst, RGB2RGB(scn, dcn, bidx)); + break; + + case CV_BGR2BGR565: case CV_BGR2BGR555: case CV_RGB2BGR565: case CV_RGB2BGR555: + case CV_BGRA2BGR565: case CV_BGRA2BGR555: case CV_RGBA2BGR565: case CV_RGBA2BGR555: + CV_Assert( (scn == 3 || scn == 4) && depth == CV_8U ); + _dst.create(sz, CV_8UC2); + dst = _dst.getMat(); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if(code == CV_BGR2BGR565 || code == CV_BGRA2BGR565 || code == CV_RGB2BGR565 || code == CV_RGBA2BGR565) + if(tegra::cvtRGB2RGB565(src, dst, code == CV_RGB2BGR565 || code == CV_RGBA2BGR565 ? 0 : 2)) + break; +#endif + + CvtColorLoop(src, dst, RGB2RGB5x5(scn, + code == CV_BGR2BGR565 || code == CV_BGR2BGR555 || + code == CV_BGRA2BGR565 || code == CV_BGRA2BGR555 ? 0 : 2, + code == CV_BGR2BGR565 || code == CV_RGB2BGR565 || + code == CV_BGRA2BGR565 || code == CV_RGBA2BGR565 ? 6 : 5 // green bits + )); + break; + + case CV_BGR5652BGR: case CV_BGR5552BGR: case CV_BGR5652RGB: case CV_BGR5552RGB: + case CV_BGR5652BGRA: case CV_BGR5552BGRA: case CV_BGR5652RGBA: case CV_BGR5552RGBA: + if(dcn <= 0) dcn = (code==CV_BGR5652BGRA || code==CV_BGR5552BGRA || code==CV_BGR5652RGBA || code==CV_BGR5552RGBA) ? 4 : 3; + CV_Assert( (dcn == 3 || dcn == 4) && scn == 2 && depth == CV_8U ); + _dst.create(sz, CV_MAKETYPE(depth, dcn)); + dst = _dst.getMat(); + + CvtColorLoop(src, dst, RGB5x52RGB(dcn, + code == CV_BGR5652BGR || code == CV_BGR5552BGR || + code == CV_BGR5652BGRA || code == CV_BGR5552BGRA ? 0 : 2, // blue idx + code == CV_BGR5652BGR || code == CV_BGR5652RGB || + code == CV_BGR5652BGRA || code == CV_BGR5652RGBA ? 6 : 5 // green bits + )); + break; + + case CV_BGR2GRAY: case CV_BGRA2GRAY: case CV_RGB2GRAY: case CV_RGBA2GRAY: + CV_Assert( scn == 3 || scn == 4 ); + _dst.create(sz, CV_MAKETYPE(depth, 1)); + dst = _dst.getMat(); + + bidx = code == CV_BGR2GRAY || code == CV_BGRA2GRAY ? 0 : 2; + + if( depth == CV_8U ) + { +#ifdef HAVE_TEGRA_OPTIMIZATION + if(!tegra::cvtRGB2Gray(src, dst, bidx)) +#endif + CvtColorLoop(src, dst, RGB2Gray(scn, bidx, 0)); + } + else if( depth == CV_16U ) + CvtColorLoop(src, dst, RGB2Gray(scn, bidx, 0)); + else + CvtColorLoop(src, dst, RGB2Gray(scn, bidx, 0)); + break; + + case CV_BGR5652GRAY: case CV_BGR5552GRAY: + CV_Assert( scn == 2 && depth == CV_8U ); + _dst.create(sz, CV_8UC1); + dst = _dst.getMat(); + + CvtColorLoop(src, dst, RGB5x52Gray(code == CV_BGR5652GRAY ? 6 : 5)); + break; + + case CV_GRAY2BGR: case CV_GRAY2BGRA: + if( dcn <= 0 ) dcn = (code==CV_GRAY2BGRA) ? 4 : 3; + CV_Assert( scn == 1 && (dcn == 3 || dcn == 4)); + _dst.create(sz, CV_MAKETYPE(depth, dcn)); + dst = _dst.getMat(); + + if( depth == CV_8U ) + { +#ifdef HAVE_TEGRA_OPTIMIZATION + if(!tegra::cvtGray2RGB(src, dst)) +#endif + CvtColorLoop(src, dst, Gray2RGB(dcn)); + } + else if( depth == CV_16U ) + CvtColorLoop(src, dst, Gray2RGB(dcn)); + else + CvtColorLoop(src, dst, Gray2RGB(dcn)); + break; + + case CV_GRAY2BGR565: case CV_GRAY2BGR555: + CV_Assert( scn == 1 && depth == CV_8U ); + _dst.create(sz, CV_8UC2); + dst = _dst.getMat(); + + CvtColorLoop(src, dst, Gray2RGB5x5(code == CV_GRAY2BGR565 ? 6 : 5)); + break; + + case CV_BGR2YCrCb: case CV_RGB2YCrCb: + case CV_BGR2YUV: case CV_RGB2YUV: + { + CV_Assert( scn == 3 || scn == 4 ); + bidx = code == CV_BGR2YCrCb || code == CV_RGB2YUV ? 0 : 2; + static const float yuv_f[] = { 0.114f, 0.587f, 0.299f, 0.492f, 0.877f }; + static const int yuv_i[] = { B2Y, G2Y, R2Y, 8061, 14369 }; + const float* coeffs_f = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? 0 : yuv_f; + const int* coeffs_i = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? 0 : yuv_i; + + _dst.create(sz, CV_MAKETYPE(depth, 3)); + dst = _dst.getMat(); + + if( depth == CV_8U ) + { +#ifdef HAVE_TEGRA_OPTIMIZATION + if((code == CV_RGB2YCrCb || code == CV_BGR2YCrCb) && tegra::cvtRGB2YCrCb(src, dst, bidx)) + break; +#endif + CvtColorLoop(src, dst, RGB2YCrCb_i(scn, bidx, coeffs_i)); + } + else if( depth == CV_16U ) + CvtColorLoop(src, dst, RGB2YCrCb_i(scn, bidx, coeffs_i)); + else + CvtColorLoop(src, dst, RGB2YCrCb_f(scn, bidx, coeffs_f)); + } + break; + + case CV_YCrCb2BGR: case CV_YCrCb2RGB: + case CV_YUV2BGR: case CV_YUV2RGB: + { + if( dcn <= 0 ) dcn = 3; + CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) ); + bidx = code == CV_YCrCb2BGR || code == CV_YUV2RGB ? 0 : 2; + static const float yuv_f[] = { 2.032f, -0.395f, -0.581f, 1.140f }; + static const int yuv_i[] = { 33292, -6472, -9519, 18678 }; + const float* coeffs_f = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? 0 : yuv_f; + const int* coeffs_i = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? 0 : yuv_i; + + _dst.create(sz, CV_MAKETYPE(depth, dcn)); + dst = _dst.getMat(); + + if( depth == CV_8U ) + CvtColorLoop(src, dst, YCrCb2RGB_i(dcn, bidx, coeffs_i)); + else if( depth == CV_16U ) + CvtColorLoop(src, dst, YCrCb2RGB_i(dcn, bidx, coeffs_i)); + else + CvtColorLoop(src, dst, YCrCb2RGB_f(dcn, bidx, coeffs_f)); + } + break; + + case CV_BGR2XYZ: case CV_RGB2XYZ: + CV_Assert( scn == 3 || scn == 4 ); + bidx = code == CV_BGR2XYZ ? 0 : 2; + + _dst.create(sz, CV_MAKETYPE(depth, 3)); + dst = _dst.getMat(); + + if( depth == CV_8U ) + CvtColorLoop(src, dst, RGB2XYZ_i(scn, bidx, 0)); + else if( depth == CV_16U ) + CvtColorLoop(src, dst, RGB2XYZ_i(scn, bidx, 0)); + else + CvtColorLoop(src, dst, RGB2XYZ_f(scn, bidx, 0)); + break; + + case CV_XYZ2BGR: case CV_XYZ2RGB: + if( dcn <= 0 ) dcn = 3; + CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) ); + bidx = code == CV_XYZ2BGR ? 0 : 2; + + _dst.create(sz, CV_MAKETYPE(depth, dcn)); + dst = _dst.getMat(); + + if( depth == CV_8U ) + CvtColorLoop(src, dst, XYZ2RGB_i(dcn, bidx, 0)); + else if( depth == CV_16U ) + CvtColorLoop(src, dst, XYZ2RGB_i(dcn, bidx, 0)); + else + CvtColorLoop(src, dst, XYZ2RGB_f(dcn, bidx, 0)); + break; + + case CV_BGR2HSV: case CV_RGB2HSV: case CV_BGR2HSV_FULL: case CV_RGB2HSV_FULL: + case CV_BGR2HLS: case CV_RGB2HLS: case CV_BGR2HLS_FULL: case CV_RGB2HLS_FULL: + { + CV_Assert( (scn == 3 || scn == 4) && (depth == CV_8U || depth == CV_32F) ); + bidx = code == CV_BGR2HSV || code == CV_BGR2HLS || + code == CV_BGR2HSV_FULL || code == CV_BGR2HLS_FULL ? 0 : 2; + int hrange = depth == CV_32F ? 360 : code == CV_BGR2HSV || code == CV_RGB2HSV || + code == CV_BGR2HLS || code == CV_RGB2HLS ? 180 : 256; + + _dst.create(sz, CV_MAKETYPE(depth, 3)); + dst = _dst.getMat(); + + if( code == CV_BGR2HSV || code == CV_RGB2HSV || + code == CV_BGR2HSV_FULL || code == CV_RGB2HSV_FULL ) + { +#ifdef HAVE_TEGRA_OPTIMIZATION + if(tegra::cvtRGB2HSV(src, dst, bidx, hrange)) + break; +#endif + if( depth == CV_8U ) + CvtColorLoop(src, dst, RGB2HSV_b(scn, bidx, hrange)); + else + CvtColorLoop(src, dst, RGB2HSV_f(scn, bidx, (float)hrange)); + } + else + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, RGB2HLS_b(scn, bidx, hrange)); + else + CvtColorLoop(src, dst, RGB2HLS_f(scn, bidx, (float)hrange)); + } + } + break; + + case CV_HSV2BGR: case CV_HSV2RGB: case CV_HSV2BGR_FULL: case CV_HSV2RGB_FULL: + case CV_HLS2BGR: case CV_HLS2RGB: case CV_HLS2BGR_FULL: case CV_HLS2RGB_FULL: + { + if( dcn <= 0 ) dcn = 3; + CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) && (depth == CV_8U || depth == CV_32F) ); + bidx = code == CV_HSV2BGR || code == CV_HLS2BGR || + code == CV_HSV2BGR_FULL || code == CV_HLS2BGR_FULL ? 0 : 2; + int hrange = depth == CV_32F ? 360 : code == CV_HSV2BGR || code == CV_HSV2RGB || + code == CV_HLS2BGR || code == CV_HLS2RGB ? 180 : 255; + + _dst.create(sz, CV_MAKETYPE(depth, dcn)); + dst = _dst.getMat(); + + if( code == CV_HSV2BGR || code == CV_HSV2RGB || + code == CV_HSV2BGR_FULL || code == CV_HSV2RGB_FULL ) + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, HSV2RGB_b(dcn, bidx, hrange)); + else + CvtColorLoop(src, dst, HSV2RGB_f(dcn, bidx, (float)hrange)); + } + else + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, HLS2RGB_b(dcn, bidx, hrange)); + else + CvtColorLoop(src, dst, HLS2RGB_f(dcn, bidx, (float)hrange)); + } + } + break; + + case CV_BGR2Lab: case CV_RGB2Lab: case CV_LBGR2Lab: case CV_LRGB2Lab: + case CV_BGR2Luv: case CV_RGB2Luv: case CV_LBGR2Luv: case CV_LRGB2Luv: + { + CV_Assert( (scn == 3 || scn == 4) && (depth == CV_8U || depth == CV_32F) ); + bidx = code == CV_BGR2Lab || code == CV_BGR2Luv || + code == CV_LBGR2Lab || code == CV_LBGR2Luv ? 0 : 2; + bool srgb = code == CV_BGR2Lab || code == CV_RGB2Lab || + code == CV_BGR2Luv || code == CV_RGB2Luv; + + _dst.create(sz, CV_MAKETYPE(depth, 3)); + dst = _dst.getMat(); + + if( code == CV_BGR2Lab || code == CV_RGB2Lab || + code == CV_LBGR2Lab || code == CV_LRGB2Lab ) + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, RGB2Lab_b(scn, bidx, 0, 0, srgb)); + else + CvtColorLoop(src, dst, RGB2Lab_f(scn, bidx, 0, 0, srgb)); + } + else + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, RGB2Luv_b(scn, bidx, 0, 0, srgb)); + else + CvtColorLoop(src, dst, RGB2Luv_f(scn, bidx, 0, 0, srgb)); + } + } + break; + + case CV_Lab2BGR: case CV_Lab2RGB: case CV_Lab2LBGR: case CV_Lab2LRGB: + case CV_Luv2BGR: case CV_Luv2RGB: case CV_Luv2LBGR: case CV_Luv2LRGB: + { + if( dcn <= 0 ) dcn = 3; + CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) && (depth == CV_8U || depth == CV_32F) ); + bidx = code == CV_Lab2BGR || code == CV_Luv2BGR || + code == CV_Lab2LBGR || code == CV_Luv2LBGR ? 0 : 2; + bool srgb = code == CV_Lab2BGR || code == CV_Lab2RGB || + code == CV_Luv2BGR || code == CV_Luv2RGB; + + _dst.create(sz, CV_MAKETYPE(depth, dcn)); + dst = _dst.getMat(); + + if( code == CV_Lab2BGR || code == CV_Lab2RGB || + code == CV_Lab2LBGR || code == CV_Lab2LRGB ) + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, Lab2RGB_b(dcn, bidx, 0, 0, srgb)); + else + CvtColorLoop(src, dst, Lab2RGB_f(dcn, bidx, 0, 0, srgb)); + } + else + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, Luv2RGB_b(dcn, bidx, 0, 0, srgb)); + else + CvtColorLoop(src, dst, Luv2RGB_f(dcn, bidx, 0, 0, srgb)); + } + } + break; + + case CV_BayerBG2GRAY: case CV_BayerGB2GRAY: case CV_BayerRG2GRAY: case CV_BayerGR2GRAY: + if(dcn <= 0) dcn = 1; + CV_Assert( scn == 1 && dcn == 1 ); + + _dst.create(sz, depth); + dst = _dst.getMat(); + + if( depth == CV_8U ) + Bayer2Gray_(src, dst, code); + else if( depth == CV_16U ) + Bayer2Gray_ >(src, dst, code); + else + CV_Error(CV_StsUnsupportedFormat, "Bayer->Gray demosaicing only supports 8u and 16u types"); + break; + + case CV_BayerBG2BGR: case CV_BayerGB2BGR: case CV_BayerRG2BGR: case CV_BayerGR2BGR: + case CV_BayerBG2BGR_VNG: case CV_BayerGB2BGR_VNG: case CV_BayerRG2BGR_VNG: case CV_BayerGR2BGR_VNG: + if(dcn <= 0) dcn = 3; + CV_Assert( scn == 1 && dcn == 3 ); + + _dst.create(sz, CV_MAKETYPE(depth, dcn)); + dst = _dst.getMat(); + + if( code == CV_BayerBG2BGR || code == CV_BayerGB2BGR || + code == CV_BayerRG2BGR || code == CV_BayerGR2BGR ) + { + if( depth == CV_8U ) + Bayer2RGB_(src, dst, code); + else if( depth == CV_16U ) + Bayer2RGB_ >(src, dst, code); + else + CV_Error(CV_StsUnsupportedFormat, "Bayer->RGB demosaicing only supports 8u and 16u types"); + } + else + { + CV_Assert( depth == CV_8U ); + Bayer2RGB_VNG_8u(src, dst, code); + } + break; + case CV_YUV2BGR_NV21: case CV_YUV2RGB_NV21: case CV_YUV2BGR_NV12: case CV_YUV2RGB_NV12: + case CV_YUV2BGRA_NV21: case CV_YUV2RGBA_NV21: case CV_YUV2BGRA_NV12: case CV_YUV2RGBA_NV12: + { + // http://www.fourcc.org/yuv.php#NV21 == yuv420sp -> a plane of 8 bit Y samples followed by an interleaved V/U plane containing 8 bit 2x2 subsampled chroma samples + // http://www.fourcc.org/yuv.php#NV12 -> a plane of 8 bit Y samples followed by an interleaved U/V plane containing 8 bit 2x2 subsampled colour difference samples + + if (dcn <= 0) dcn = (code==CV_YUV420sp2BGRA || code==CV_YUV420sp2RGBA || code==CV_YUV2BGRA_NV12 || code==CV_YUV2RGBA_NV12) ? 4 : 3; + const int bIdx = (code==CV_YUV2BGR_NV21 || code==CV_YUV2BGRA_NV21 || code==CV_YUV2BGR_NV12 || code==CV_YUV2BGRA_NV12) ? 0 : 2; + const int uIdx = (code==CV_YUV2BGR_NV21 || code==CV_YUV2BGRA_NV21 || code==CV_YUV2RGB_NV21 || code==CV_YUV2RGBA_NV21) ? 1 : 0; + + CV_Assert( dcn == 3 || dcn == 4 ); + CV_Assert( sz.width % 2 == 0 && sz.height % 3 == 0 && depth == CV_8U ); + + Size dstSz(sz.width, sz.height * 2 / 3); + _dst.create(dstSz, CV_MAKETYPE(depth, dcn)); + dst = _dst.getMat(); + + int srcstep = (int)src.step; + const uchar* y = src.ptr(); + const uchar* uv = y + srcstep * dstSz.height; + + switch(dcn*100 + bIdx * 10 + uIdx) + { + case 300: cvtYUV420sp2RGB<0, 0> (dst, srcstep, y, uv); break; + case 301: cvtYUV420sp2RGB<0, 1> (dst, srcstep, y, uv); break; + case 320: cvtYUV420sp2RGB<2, 0> (dst, srcstep, y, uv); break; + case 321: cvtYUV420sp2RGB<2, 1> (dst, srcstep, y, uv); break; + case 400: cvtYUV420sp2RGBA<0, 0>(dst, srcstep, y, uv); break; + case 401: cvtYUV420sp2RGBA<0, 1>(dst, srcstep, y, uv); break; + case 420: cvtYUV420sp2RGBA<2, 0>(dst, srcstep, y, uv); break; + case 421: cvtYUV420sp2RGBA<2, 1>(dst, srcstep, y, uv); break; + default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break; + }; + } + break; + case CV_YUV2BGR_YV12: case CV_YUV2RGB_YV12: case CV_YUV2BGRA_YV12: case CV_YUV2RGBA_YV12: + case CV_YUV2BGR_IYUV: case CV_YUV2RGB_IYUV: case CV_YUV2BGRA_IYUV: case CV_YUV2RGBA_IYUV: + { + //http://www.fourcc.org/yuv.php#YV12 == yuv420p -> It comprises an NxM Y plane followed by (N/2)x(M/2) V and U planes. + //http://www.fourcc.org/yuv.php#IYUV == I420 -> It comprises an NxN Y plane followed by (N/2)x(N/2) U and V planes + + if (dcn <= 0) dcn = (code==CV_YUV2BGRA_YV12 || code==CV_YUV2RGBA_YV12 || code==CV_YUV2RGBA_IYUV || code==CV_YUV2BGRA_IYUV) ? 4 : 3; + const int bIdx = (code==CV_YUV2BGR_YV12 || code==CV_YUV2BGRA_YV12 || code==CV_YUV2BGR_IYUV || code==CV_YUV2BGRA_IYUV) ? 0 : 2; + const int uIdx = (code==CV_YUV2BGR_YV12 || code==CV_YUV2RGB_YV12 || code==CV_YUV2BGRA_YV12 || code==CV_YUV2RGBA_YV12) ? 1 : 0; + + CV_Assert( dcn == 3 || dcn == 4 ); + CV_Assert( sz.width % 2 == 0 && sz.height % 3 == 0 && depth == CV_8U ); + + Size dstSz(sz.width, sz.height * 2 / 3); + _dst.create(dstSz, CV_MAKETYPE(depth, dcn)); + dst = _dst.getMat(); + + int srcstep = (int)src.step; + const uchar* y = src.ptr(); + const uchar* u = y + srcstep * dstSz.height; + const uchar* v = y + srcstep * (dstSz.height + dstSz.height/4) + (dstSz.width/2) * ((dstSz.height % 4)/2); + + int ustepIdx = 0; + int vstepIdx = dstSz.height % 4 == 2 ? 1 : 0; + + if(uIdx == 1) { std::swap(u ,v), std::swap(ustepIdx, vstepIdx); }; + + switch(dcn*10 + bIdx) + { + case 30: cvtYUV420p2RGB<0>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break; + case 32: cvtYUV420p2RGB<2>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break; + case 40: cvtYUV420p2RGBA<0>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break; + case 42: cvtYUV420p2RGBA<2>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break; + default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break; + }; + } + break; + case CV_YUV2GRAY_420: + { + if (dcn <= 0) dcn = 1; + + CV_Assert( dcn == 1 ); + CV_Assert( sz.width % 2 == 0 && sz.height % 3 == 0 && depth == CV_8U ); + + Size dstSz(sz.width, sz.height * 2 / 3); + _dst.create(dstSz, CV_MAKETYPE(depth, dcn)); + dst = _dst.getMat(); + + src(Range(0, dstSz.height), Range::all()).copyTo(dst); + } + break; + case CV_YUV2RGB_UYVY: case CV_YUV2BGR_UYVY: case CV_YUV2RGBA_UYVY: case CV_YUV2BGRA_UYVY: + case CV_YUV2RGB_YUY2: case CV_YUV2BGR_YUY2: case CV_YUV2RGB_YVYU: case CV_YUV2BGR_YVYU: + case CV_YUV2RGBA_YUY2: case CV_YUV2BGRA_YUY2: case CV_YUV2RGBA_YVYU: case CV_YUV2BGRA_YVYU: + { + //http://www.fourcc.org/yuv.php#UYVY + //http://www.fourcc.org/yuv.php#YUY2 + //http://www.fourcc.org/yuv.php#YVYU + + if (dcn <= 0) dcn = (code==CV_YUV2RGBA_UYVY || code==CV_YUV2BGRA_UYVY || code==CV_YUV2RGBA_YUY2 || code==CV_YUV2BGRA_YUY2 || code==CV_YUV2RGBA_YVYU || code==CV_YUV2BGRA_YVYU) ? 4 : 3; + const int bIdx = (code==CV_YUV2BGR_UYVY || code==CV_YUV2BGRA_UYVY || code==CV_YUV2BGR_YUY2 || code==CV_YUV2BGRA_YUY2 || code==CV_YUV2BGR_YVYU || code==CV_YUV2BGRA_YVYU) ? 0 : 2; + const int ycn = (code==CV_YUV2RGB_UYVY || code==CV_YUV2BGR_UYVY || code==CV_YUV2RGBA_UYVY || code==CV_YUV2BGRA_UYVY) ? 1 : 0; + const int uIdx = (code==CV_YUV2RGB_YVYU || code==CV_YUV2BGR_YVYU || code==CV_YUV2RGBA_YVYU || code==CV_YUV2BGRA_YVYU) ? 1 : 0; + + CV_Assert( dcn == 3 || dcn == 4 ); + CV_Assert( scn == 2 && depth == CV_8U ); + + _dst.create(sz, CV_8UC(dcn)); + dst = _dst.getMat(); + + switch(dcn*1000 + bIdx*100 + uIdx*10 + ycn) + { + case 3000: cvtYUV422toRGB<0,0,0>(dst, (int)src.step, src.ptr()); break; + case 3001: cvtYUV422toRGB<0,0,1>(dst, (int)src.step, src.ptr()); break; + case 3010: cvtYUV422toRGB<0,1,0>(dst, (int)src.step, src.ptr()); break; + case 3011: cvtYUV422toRGB<0,1,1>(dst, (int)src.step, src.ptr()); break; + case 3200: cvtYUV422toRGB<2,0,0>(dst, (int)src.step, src.ptr()); break; + case 3201: cvtYUV422toRGB<2,0,1>(dst, (int)src.step, src.ptr()); break; + case 3210: cvtYUV422toRGB<2,1,0>(dst, (int)src.step, src.ptr()); break; + case 3211: cvtYUV422toRGB<2,1,1>(dst, (int)src.step, src.ptr()); break; + case 4000: cvtYUV422toRGBA<0,0,0>(dst, (int)src.step, src.ptr()); break; + case 4001: cvtYUV422toRGBA<0,0,1>(dst, (int)src.step, src.ptr()); break; + case 4010: cvtYUV422toRGBA<0,1,0>(dst, (int)src.step, src.ptr()); break; + case 4011: cvtYUV422toRGBA<0,1,1>(dst, (int)src.step, src.ptr()); break; + case 4200: cvtYUV422toRGBA<2,0,0>(dst, (int)src.step, src.ptr()); break; + case 4201: cvtYUV422toRGBA<2,0,1>(dst, (int)src.step, src.ptr()); break; + case 4210: cvtYUV422toRGBA<2,1,0>(dst, (int)src.step, src.ptr()); break; + case 4211: cvtYUV422toRGBA<2,1,1>(dst, (int)src.step, src.ptr()); break; + default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break; + }; + } + break; + case CV_YUV2GRAY_UYVY: case CV_YUV2GRAY_YUY2: + { + if (dcn <= 0) dcn = 1; + + CV_Assert( dcn == 1 ); + CV_Assert( scn == 2 && depth == CV_8U ); + + extractChannel(_src, _dst, code == CV_YUV2GRAY_UYVY ? 1 : 0); + } + break; + case CV_RGBA2mRGBA: + { + if (dcn <= 0) dcn = 4; + CV_Assert( scn == 4 && dcn == 4 ); + + _dst.create(sz, CV_MAKETYPE(depth, dcn)); + dst = _dst.getMat(); + + if( depth == CV_8U ) + { + CvtColorLoop(src, dst, RGBA2mRGBA()); + } else { + CV_Error( CV_StsBadArg, "Unsupported image depth" ); + } + } + break; + case CV_mRGBA2RGBA: + { + if (dcn <= 0) dcn = 4; + CV_Assert( scn == 4 && dcn == 4 ); + + _dst.create(sz, CV_MAKETYPE(depth, dcn)); + dst = _dst.getMat(); + + if( depth == CV_8U ) + { + CvtColorLoop(src, dst, mRGBA2RGBA()); + } else { + CV_Error( CV_StsBadArg, "Unsupported image depth" ); + } + } + break; + default: + CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); + } +} + +CV_IMPL void +cvCvtColor( const CvArr* srcarr, CvArr* dstarr, int code ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst0 = cv::cvarrToMat(dstarr), dst = dst0; + CV_Assert( src.depth() == dst.depth() ); + + cv::cvtColor(src, dst, code, dst.channels()); + CV_Assert( dst.data == dst0.data ); +} + + +/* End of file. */ diff --git a/imgproc/src/contours.cpp b/imgproc/src/contours.cpp new file mode 100644 index 0000000..c290385 --- /dev/null +++ b/imgproc/src/contours.cpp @@ -0,0 +1,1947 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +/* initializes 8-element array for fast access to 3x3 neighborhood of a pixel */ +#define CV_INIT_3X3_DELTAS( deltas, step, nch ) \ + ((deltas)[0] = (nch), (deltas)[1] = -(step) + (nch), \ + (deltas)[2] = -(step), (deltas)[3] = -(step) - (nch), \ + (deltas)[4] = -(nch), (deltas)[5] = (step) - (nch), \ + (deltas)[6] = (step), (deltas)[7] = (step) + (nch)) + +static const CvPoint icvCodeDeltas[8] = + { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} }; + +CV_IMPL void +cvStartReadChainPoints( CvChain * chain, CvChainPtReader * reader ) +{ + int i; + + if( !chain || !reader ) + CV_Error( CV_StsNullPtr, "" ); + + if( chain->elem_size != 1 || chain->header_size < (int)sizeof(CvChain)) + CV_Error( CV_StsBadSize, "" ); + + cvStartReadSeq( (CvSeq *) chain, (CvSeqReader *) reader, 0 ); + + reader->pt = chain->origin; + for( i = 0; i < 8; i++ ) + { + reader->deltas[i][0] = (schar) icvCodeDeltas[i].x; + reader->deltas[i][1] = (schar) icvCodeDeltas[i].y; + } +} + + +/* retrieves next point of the chain curve and updates reader */ +CV_IMPL CvPoint +cvReadChainPoint( CvChainPtReader * reader ) +{ + schar *ptr; + int code; + CvPoint pt = { 0, 0 }; + + if( !reader ) + CV_Error( CV_StsNullPtr, "" ); + + pt = reader->pt; + + ptr = reader->ptr; + if( ptr ) + { + code = *ptr++; + + if( ptr >= reader->block_max ) + { + cvChangeSeqBlock( (CvSeqReader *) reader, 1 ); + ptr = reader->ptr; + } + + reader->ptr = ptr; + reader->code = (schar)code; + assert( (code & ~7) == 0 ); + reader->pt.x = pt.x + icvCodeDeltas[code].x; + reader->pt.y = pt.y + icvCodeDeltas[code].y; + } + + return pt; +} + + +/****************************************************************************************\ +* Raster->Chain Tree (Suzuki algorithms) * +\****************************************************************************************/ + +typedef struct _CvContourInfo +{ + int flags; + struct _CvContourInfo *next; /* next contour with the same mark value */ + struct _CvContourInfo *parent; /* information about parent contour */ + CvSeq *contour; /* corresponding contour (may be 0, if rejected) */ + CvRect rect; /* bounding rectangle */ + CvPoint origin; /* origin point (where the contour was traced from) */ + int is_hole; /* hole flag */ +} +_CvContourInfo; + + +/* + Structure that is used for sequental retrieving contours from the image. + It supports both hierarchical and plane variants of Suzuki algorithm. +*/ +typedef struct _CvContourScanner +{ + CvMemStorage *storage1; /* contains fetched contours */ + CvMemStorage *storage2; /* contains approximated contours + (!=storage1 if approx_method2 != approx_method1) */ + CvMemStorage *cinfo_storage; /* contains _CvContourInfo nodes */ + CvSet *cinfo_set; /* set of _CvContourInfo nodes */ + CvMemStoragePos initial_pos; /* starting storage pos */ + CvMemStoragePos backup_pos; /* beginning of the latest approx. contour */ + CvMemStoragePos backup_pos2; /* ending of the latest approx. contour */ + schar *img0; /* image origin */ + schar *img; /* current image row */ + int img_step; /* image step */ + CvSize img_size; /* ROI size */ + CvPoint offset; /* ROI offset: coordinates, added to each contour point */ + CvPoint pt; /* current scanner position */ + CvPoint lnbd; /* position of the last met contour */ + int nbd; /* current mark val */ + _CvContourInfo *l_cinfo; /* information about latest approx. contour */ + _CvContourInfo cinfo_temp; /* temporary var which is used in simple modes */ + _CvContourInfo frame_info; /* information about frame */ + CvSeq frame; /* frame itself */ + int approx_method1; /* approx method when tracing */ + int approx_method2; /* final approx method */ + int mode; /* contour scanning mode: + 0 - external only + 1 - all the contours w/o any hierarchy + 2 - connected components (i.e. two-level structure - + external contours and holes), + 3 - full hierarchy; + 4 - connected components of a multi-level image + */ + int subst_flag; + int seq_type1; /* type of fetched contours */ + int header_size1; /* hdr size of fetched contours */ + int elem_size1; /* elem size of fetched contours */ + int seq_type2; /* */ + int header_size2; /* the same for approx. contours */ + int elem_size2; /* */ + _CvContourInfo *cinfo_table[128]; +} +_CvContourScanner; + +#define _CV_FIND_CONTOURS_FLAGS_EXTERNAL_ONLY 1 +#define _CV_FIND_CONTOURS_FLAGS_HIERARCHIC 2 + +/* + Initializes scanner structure. + Prepare image for scanning ( clear borders and convert all pixels to 0-1. +*/ +CV_IMPL CvContourScanner +cvStartFindContours( void* _img, CvMemStorage* storage, + int header_size, int mode, + int method, CvPoint offset ) +{ + if( !storage ) + CV_Error( CV_StsNullPtr, "" ); + + CvMat stub, *mat = cvGetMat( _img, &stub ); + + if( CV_MAT_TYPE(mat->type) == CV_32SC1 && mode == CV_RETR_CCOMP ) + mode = CV_RETR_FLOODFILL; + + if( !((CV_IS_MASK_ARR( mat ) && mode < CV_RETR_FLOODFILL) || + (CV_MAT_TYPE(mat->type) == CV_32SC1 && mode == CV_RETR_FLOODFILL)) ) + CV_Error( CV_StsUnsupportedFormat, "[Start]FindContours support only 8uC1 and 32sC1 images" ); + + CvSize size = cvSize( mat->width, mat->height ); + int step = mat->step; + uchar* img = (uchar*)(mat->data.ptr); + + if( method < 0 || method > CV_CHAIN_APPROX_TC89_KCOS ) + CV_Error( CV_StsOutOfRange, "" ); + + if( header_size < (int) (method == CV_CHAIN_CODE ? sizeof( CvChain ) : sizeof( CvContour ))) + CV_Error( CV_StsBadSize, "" ); + + CvContourScanner scanner = (CvContourScanner)cvAlloc( sizeof( *scanner )); + memset( scanner, 0, sizeof(*scanner) ); + + scanner->storage1 = scanner->storage2 = storage; + scanner->img0 = (schar *) img; + scanner->img = (schar *) (img + step); + scanner->img_step = step; + scanner->img_size.width = size.width - 1; /* exclude rightest column */ + scanner->img_size.height = size.height - 1; /* exclude bottomost row */ + scanner->mode = mode; + scanner->offset = offset; + scanner->pt.x = scanner->pt.y = 1; + scanner->lnbd.x = 0; + scanner->lnbd.y = 1; + scanner->nbd = 2; + scanner->mode = (int) mode; + scanner->frame_info.contour = &(scanner->frame); + scanner->frame_info.is_hole = 1; + scanner->frame_info.next = 0; + scanner->frame_info.parent = 0; + scanner->frame_info.rect = cvRect( 0, 0, size.width, size.height ); + scanner->l_cinfo = 0; + scanner->subst_flag = 0; + + scanner->frame.flags = CV_SEQ_FLAG_HOLE; + + scanner->approx_method2 = scanner->approx_method1 = method; + + if( method == CV_CHAIN_APPROX_TC89_L1 || method == CV_CHAIN_APPROX_TC89_KCOS ) + scanner->approx_method1 = CV_CHAIN_CODE; + + if( scanner->approx_method1 == CV_CHAIN_CODE ) + { + scanner->seq_type1 = CV_SEQ_CHAIN_CONTOUR; + scanner->header_size1 = scanner->approx_method1 == scanner->approx_method2 ? + header_size : sizeof( CvChain ); + scanner->elem_size1 = sizeof( char ); + } + else + { + scanner->seq_type1 = CV_SEQ_POLYGON; + scanner->header_size1 = scanner->approx_method1 == scanner->approx_method2 ? + header_size : sizeof( CvContour ); + scanner->elem_size1 = sizeof( CvPoint ); + } + + scanner->header_size2 = header_size; + + if( scanner->approx_method2 == CV_CHAIN_CODE ) + { + scanner->seq_type2 = scanner->seq_type1; + scanner->elem_size2 = scanner->elem_size1; + } + else + { + scanner->seq_type2 = CV_SEQ_POLYGON; + scanner->elem_size2 = sizeof( CvPoint ); + } + + scanner->seq_type1 = scanner->approx_method1 == CV_CHAIN_CODE ? + CV_SEQ_CHAIN_CONTOUR : CV_SEQ_POLYGON; + + scanner->seq_type2 = scanner->approx_method2 == CV_CHAIN_CODE ? + CV_SEQ_CHAIN_CONTOUR : CV_SEQ_POLYGON; + + cvSaveMemStoragePos( storage, &(scanner->initial_pos) ); + + if( method > CV_CHAIN_APPROX_SIMPLE ) + { + scanner->storage1 = cvCreateChildMemStorage( scanner->storage2 ); + } + + if( mode > CV_RETR_LIST ) + { + scanner->cinfo_storage = cvCreateChildMemStorage( scanner->storage2 ); + scanner->cinfo_set = cvCreateSet( 0, sizeof( CvSet ), sizeof( _CvContourInfo ), + scanner->cinfo_storage ); + } + + /* make zero borders */ + int esz = CV_ELEM_SIZE(mat->type); + memset( img, 0, size.width*esz ); + memset( img + step * (size.height - 1), 0, size.width*esz ); + + img += step; + for( int y = 1; y < size.height - 1; y++, img += step ) + { + for( int k = 0; k < esz; k++ ) + img[k] = img[(size.width - 1)*esz + k] = (schar)0; + } + + /* converts all pixels to 0 or 1 */ + if( CV_MAT_TYPE(mat->type) != CV_32S ) + cvThreshold( mat, mat, 0, 1, CV_THRESH_BINARY ); + + return scanner; +} + +/* + Final stage of contour processing. + Three variants possible: + 1. Contour, which was retrieved using border following, is added to + the contour tree. It is the case when the icvSubstituteContour function + was not called after retrieving the contour. + + 2. New contour, assigned by icvSubstituteContour function, is added to the + tree. The retrieved contour itself is removed from the storage. + Here two cases are possible: + 2a. If one deals with plane variant of algorithm + (hierarchical strucutre is not reconstructed), + the contour is removed completely. + 2b. In hierarchical case, the header of the contour is not removed. + It's marked as "link to contour" and h_next pointer of it is set to + new, substituting contour. + + 3. The similar to 2, but when NULL pointer was assigned by + icvSubstituteContour function. In this case, the function removes + retrieved contour completely if plane case and + leaves header if hierarchical (but doesn't mark header as "link"). + ------------------------------------------------------------------------ + The 1st variant can be used to retrieve and store all the contours from the image + (with optional convertion from chains to contours using some approximation from + restriced set of methods). Some characteristics of contour can be computed in the + same pass. + + The usage scheme can look like: + + icvContourScanner scanner; + CvMemStorage* contour_storage; + CvSeq* first_contour; + CvStatus result; + + ... + + icvCreateMemStorage( &contour_storage, block_size/0 ); + + ... + + cvStartFindContours + ( img, contour_storage, + header_size, approx_method, + [external_only,] + &scanner ); + + for(;;) + { + [CvSeq* contour;] + result = icvFindNextContour( &scanner, &contour/0 ); + + if( result != CV_OK ) break; + + // calculate some characteristics + ... + } + + if( result < 0 ) goto error_processing; + + cvEndFindContours( &scanner, &first_contour ); + ... + + ----------------------------------------------------------------- + + Second variant is more complex and can be used when someone wants store not + the retrieved contours but transformed ones. (e.g. approximated with some + non-default algorithm ). + + The scheme can be the as following: + + icvContourScanner scanner; + CvMemStorage* contour_storage; + CvMemStorage* temp_storage; + CvSeq* first_contour; + CvStatus result; + + ... + + icvCreateMemStorage( &contour_storage, block_size/0 ); + icvCreateMemStorage( &temp_storage, block_size/0 ); + + ... + + icvStartFindContours8uC1R + ( , temp_storage, + header_size, approx_method, + [retrival_mode], + &scanner ); + + for(;;) + { + CvSeq* temp_contour; + CvSeq* new_contour; + result = icvFindNextContour( scanner, &temp_contour ); + + if( result != CV_OK ) break; + + ( temp_contour, contour_storage, + &new_contour, ); + + icvSubstituteContour( scanner, new_contour ); + ... + } + + if( result < 0 ) goto error_processing; + + cvEndFindContours( &scanner, &first_contour ); + ... + + ---------------------------------------------------------------------------- + Third method to retrieve contours may be applied if contours are irrelevant + themselves but some characteristics of them are used only. + The usage is similar to second except slightly different internal loop + + for(;;) + { + CvSeq* temp_contour; + result = icvFindNextContour( &scanner, &temp_contour ); + + if( result != CV_OK ) break; + + // calculate some characteristics of temp_contour + + icvSubstituteContour( scanner, 0 ); + ... + } + + new_storage variable is not needed here. + + Note, that the second and the third methods can interleave. I.e. it is possible to + retain contours that satisfy with some criteria and reject others. + In hierarchic case the resulting tree is the part of original tree with + some nodes absent. But in the resulting tree the contour1 is a child + (may be indirect) of contour2 iff in the original tree the contour1 + is a child (may be indirect) of contour2. +*/ +static void +icvEndProcessContour( CvContourScanner scanner ) +{ + _CvContourInfo *l_cinfo = scanner->l_cinfo; + + if( l_cinfo ) + { + if( scanner->subst_flag ) + { + CvMemStoragePos temp; + + cvSaveMemStoragePos( scanner->storage2, &temp ); + + if( temp.top == scanner->backup_pos2.top && + temp.free_space == scanner->backup_pos2.free_space ) + { + cvRestoreMemStoragePos( scanner->storage2, &scanner->backup_pos ); + } + scanner->subst_flag = 0; + } + + if( l_cinfo->contour ) + { + cvInsertNodeIntoTree( l_cinfo->contour, l_cinfo->parent->contour, + &(scanner->frame) ); + } + scanner->l_cinfo = 0; + } +} + +/* replaces one contour with another */ +CV_IMPL void +cvSubstituteContour( CvContourScanner scanner, CvSeq * new_contour ) +{ + _CvContourInfo *l_cinfo; + + if( !scanner ) + CV_Error( CV_StsNullPtr, "" ); + + l_cinfo = scanner->l_cinfo; + if( l_cinfo && l_cinfo->contour && l_cinfo->contour != new_contour ) + { + l_cinfo->contour = new_contour; + scanner->subst_flag = 1; + } +} + + +/* + marks domain border with +/- and stores the contour into CvSeq. + method: + <0 - chain + ==0 - direct + >0 - simple approximation +*/ +static void +icvFetchContour( schar *ptr, + int step, + CvPoint pt, + CvSeq* contour, + int _method ) +{ + const schar nbd = 2; + int deltas[16]; + CvSeqWriter writer; + schar *i0 = ptr, *i1, *i3, *i4 = 0; + int prev_s = -1, s, s_end; + int method = _method - 1; + + assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE ); + + /* initialize local state */ + CV_INIT_3X3_DELTAS( deltas, step, 1 ); + memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] )); + + /* initialize writer */ + cvStartAppendToSeq( contour, &writer ); + + if( method < 0 ) + ((CvChain *) contour)->origin = pt; + + s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4; + + do + { + s = (s - 1) & 7; + i1 = i0 + deltas[s]; + if( *i1 != 0 ) + break; + } + while( s != s_end ); + + if( s == s_end ) /* single pixel domain */ + { + *i0 = (schar) (nbd | -128); + if( method >= 0 ) + { + CV_WRITE_SEQ_ELEM( pt, writer ); + } + } + else + { + i3 = i0; + prev_s = s ^ 4; + + /* follow border */ + for( ;; ) + { + s_end = s; + + for( ;; ) + { + i4 = i3 + deltas[++s]; + if( *i4 != 0 ) + break; + } + s &= 7; + + /* check "right" bound */ + if( (unsigned) (s - 1) < (unsigned) s_end ) + { + *i3 = (schar) (nbd | -128); + } + else if( *i3 == 1 ) + { + *i3 = nbd; + } + + if( method < 0 ) + { + schar _s = (schar) s; + + CV_WRITE_SEQ_ELEM( _s, writer ); + } + else + { + if( s != prev_s || method == 0 ) + { + CV_WRITE_SEQ_ELEM( pt, writer ); + prev_s = s; + } + + pt.x += icvCodeDeltas[s].x; + pt.y += icvCodeDeltas[s].y; + + } + + if( i4 == i0 && i3 == i1 ) + break; + + i3 = i4; + s = (s + 4) & 7; + } /* end of border following loop */ + } + + cvEndWriteSeq( &writer ); + + if( _method != CV_CHAIN_CODE ) + cvBoundingRect( contour, 1 ); + + assert( (writer.seq->total == 0 && writer.seq->first == 0) || + writer.seq->total > writer.seq->first->count || + (writer.seq->first->prev == writer.seq->first && + writer.seq->first->next == writer.seq->first) ); +} + + + +/* + trace contour until certain point is met. + returns 1 if met, 0 else. +*/ +static int +icvTraceContour( schar *ptr, int step, schar *stop_ptr, int is_hole ) +{ + int deltas[16]; + schar *i0 = ptr, *i1, *i3, *i4; + int s, s_end; + + /* initialize local state */ + CV_INIT_3X3_DELTAS( deltas, step, 1 ); + memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] )); + + assert( (*i0 & -2) != 0 ); + + s_end = s = is_hole ? 0 : 4; + + do + { + s = (s - 1) & 7; + i1 = i0 + deltas[s]; + if( *i1 != 0 ) + break; + } + while( s != s_end ); + + i3 = i0; + + /* check single pixel domain */ + if( s != s_end ) + { + /* follow border */ + for( ;; ) + { + s_end = s; + + for( ;; ) + { + i4 = i3 + deltas[++s]; + if( *i4 != 0 ) + break; + } + + if( i3 == stop_ptr || (i4 == i0 && i3 == i1) ) + break; + + i3 = i4; + s = (s + 4) & 7; + } /* end of border following loop */ + } + return i3 == stop_ptr; +} + + +static void +icvFetchContourEx( schar* ptr, + int step, + CvPoint pt, + CvSeq* contour, + int _method, + int nbd, + CvRect* _rect ) +{ + int deltas[16]; + CvSeqWriter writer; + schar *i0 = ptr, *i1, *i3, *i4; + CvRect rect; + int prev_s = -1, s, s_end; + int method = _method - 1; + + assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE ); + assert( 1 < nbd && nbd < 128 ); + + /* initialize local state */ + CV_INIT_3X3_DELTAS( deltas, step, 1 ); + memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] )); + + /* initialize writer */ + cvStartAppendToSeq( contour, &writer ); + + if( method < 0 ) + ((CvChain *)contour)->origin = pt; + + rect.x = rect.width = pt.x; + rect.y = rect.height = pt.y; + + s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4; + + do + { + s = (s - 1) & 7; + i1 = i0 + deltas[s]; + if( *i1 != 0 ) + break; + } + while( s != s_end ); + + if( s == s_end ) /* single pixel domain */ + { + *i0 = (schar) (nbd | 0x80); + if( method >= 0 ) + { + CV_WRITE_SEQ_ELEM( pt, writer ); + } + } + else + { + i3 = i0; + + prev_s = s ^ 4; + + /* follow border */ + for( ;; ) + { + s_end = s; + + for( ;; ) + { + i4 = i3 + deltas[++s]; + if( *i4 != 0 ) + break; + } + s &= 7; + + /* check "right" bound */ + if( (unsigned) (s - 1) < (unsigned) s_end ) + { + *i3 = (schar) (nbd | 0x80); + } + else if( *i3 == 1 ) + { + *i3 = (schar) nbd; + } + + if( method < 0 ) + { + schar _s = (schar) s; + CV_WRITE_SEQ_ELEM( _s, writer ); + } + else if( s != prev_s || method == 0 ) + { + CV_WRITE_SEQ_ELEM( pt, writer ); + } + + if( s != prev_s ) + { + /* update bounds */ + if( pt.x < rect.x ) + rect.x = pt.x; + else if( pt.x > rect.width ) + rect.width = pt.x; + + if( pt.y < rect.y ) + rect.y = pt.y; + else if( pt.y > rect.height ) + rect.height = pt.y; + } + + prev_s = s; + pt.x += icvCodeDeltas[s].x; + pt.y += icvCodeDeltas[s].y; + + if( i4 == i0 && i3 == i1 ) break; + + i3 = i4; + s = (s + 4) & 7; + } /* end of border following loop */ + } + + rect.width -= rect.x - 1; + rect.height -= rect.y - 1; + + cvEndWriteSeq( &writer ); + + if( _method != CV_CHAIN_CODE ) + ((CvContour*)contour)->rect = rect; + + assert( (writer.seq->total == 0 && writer.seq->first == 0) || + writer.seq->total > writer.seq->first->count || + (writer.seq->first->prev == writer.seq->first && + writer.seq->first->next == writer.seq->first) ); + + if( _rect ) *_rect = rect; +} + + +static int +icvTraceContour_32s( int *ptr, int step, int *stop_ptr, int is_hole ) +{ + int deltas[16]; + int *i0 = ptr, *i1, *i3, *i4; + int s, s_end; + const int right_flag = INT_MIN; + const int new_flag = (int)((unsigned)INT_MIN >> 1); + const int value_mask = ~(right_flag | new_flag); + const int ccomp_val = *i0 & value_mask; + + /* initialize local state */ + CV_INIT_3X3_DELTAS( deltas, step, 1 ); + memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] )); + + s_end = s = is_hole ? 0 : 4; + + do + { + s = (s - 1) & 7; + i1 = i0 + deltas[s]; + if( (*i1 & value_mask) == ccomp_val ) + break; + } + while( s != s_end ); + + i3 = i0; + + /* check single pixel domain */ + if( s != s_end ) + { + /* follow border */ + for( ;; ) + { + s_end = s; + + for( ;; ) + { + i4 = i3 + deltas[++s]; + if( (*i4 & value_mask) == ccomp_val ) + break; + } + + if( i3 == stop_ptr || (i4 == i0 && i3 == i1) ) + break; + + i3 = i4; + s = (s + 4) & 7; + } /* end of border following loop */ + } + return i3 == stop_ptr; +} + + +static void +icvFetchContourEx_32s( int* ptr, + int step, + CvPoint pt, + CvSeq* contour, + int _method, + CvRect* _rect ) +{ + int deltas[16]; + CvSeqWriter writer; + int *i0 = ptr, *i1, *i3, *i4; + CvRect rect; + int prev_s = -1, s, s_end; + int method = _method - 1; + const int right_flag = INT_MIN; + const int new_flag = (int)((unsigned)INT_MIN >> 1); + const int value_mask = ~(right_flag | new_flag); + const int ccomp_val = *i0 & value_mask; + const int nbd0 = ccomp_val | new_flag; + const int nbd1 = nbd0 | right_flag; + + assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE ); + + /* initialize local state */ + CV_INIT_3X3_DELTAS( deltas, step, 1 ); + memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] )); + + /* initialize writer */ + cvStartAppendToSeq( contour, &writer ); + + if( method < 0 ) + ((CvChain *)contour)->origin = pt; + + rect.x = rect.width = pt.x; + rect.y = rect.height = pt.y; + + s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4; + + do + { + s = (s - 1) & 7; + i1 = i0 + deltas[s]; + if( (*i1 & value_mask) == ccomp_val ) + break; + } + while( s != s_end ); + + if( s == s_end ) /* single pixel domain */ + { + *i0 = nbd1; + if( method >= 0 ) + { + CV_WRITE_SEQ_ELEM( pt, writer ); + } + } + else + { + i3 = i0; + prev_s = s ^ 4; + + /* follow border */ + for( ;; ) + { + s_end = s; + + for( ;; ) + { + i4 = i3 + deltas[++s]; + if( (*i4 & value_mask) == ccomp_val ) + break; + } + s &= 7; + + /* check "right" bound */ + if( (unsigned) (s - 1) < (unsigned) s_end ) + { + *i3 = nbd1; + } + else if( *i3 == ccomp_val ) + { + *i3 = nbd0; + } + + if( method < 0 ) + { + schar _s = (schar) s; + CV_WRITE_SEQ_ELEM( _s, writer ); + } + else if( s != prev_s || method == 0 ) + { + CV_WRITE_SEQ_ELEM( pt, writer ); + } + + if( s != prev_s ) + { + /* update bounds */ + if( pt.x < rect.x ) + rect.x = pt.x; + else if( pt.x > rect.width ) + rect.width = pt.x; + + if( pt.y < rect.y ) + rect.y = pt.y; + else if( pt.y > rect.height ) + rect.height = pt.y; + } + + prev_s = s; + pt.x += icvCodeDeltas[s].x; + pt.y += icvCodeDeltas[s].y; + + if( i4 == i0 && i3 == i1 ) break; + + i3 = i4; + s = (s + 4) & 7; + } /* end of border following loop */ + } + + rect.width -= rect.x - 1; + rect.height -= rect.y - 1; + + cvEndWriteSeq( &writer ); + + if( _method != CV_CHAIN_CODE ) + ((CvContour*)contour)->rect = rect; + + assert( (writer.seq->total == 0 && writer.seq->first == 0) || + writer.seq->total > writer.seq->first->count || + (writer.seq->first->prev == writer.seq->first && + writer.seq->first->next == writer.seq->first) ); + + if( _rect ) *_rect = rect; +} + + +CvSeq * +cvFindNextContour( CvContourScanner scanner ) +{ + if( !scanner ) + CV_Error( CV_StsNullPtr, "" ); + icvEndProcessContour( scanner ); + + /* initialize local state */ + schar* img0 = scanner->img0; + schar* img = scanner->img; + int step = scanner->img_step; + int step_i = step / sizeof(int); + int x = scanner->pt.x; + int y = scanner->pt.y; + int width = scanner->img_size.width; + int height = scanner->img_size.height; + int mode = scanner->mode; + CvPoint lnbd = scanner->lnbd; + int nbd = scanner->nbd; + int prev = img[x - 1]; + int new_mask = -2; + + if( mode == CV_RETR_FLOODFILL ) + { + prev = ((int*)img)[x - 1]; + new_mask = INT_MIN >> 1; + } + + for( ; y < height; y++, img += step ) + { + int* img0_i = 0; + int* img_i = 0; + int p = 0; + + if( mode == CV_RETR_FLOODFILL ) + { + img0_i = (int*)img0; + img_i = (int*)img; + } + + for( ; x < width; x++ ) + { + if( img_i ) + { + for( ; x < width && ((p = img_i[x]) == prev || (p & ~new_mask) == (prev & ~new_mask)); x++ ) + prev = p; + } + else + { + for( ; x < width && (p = img[x]) == prev; x++ ) + ; + } + + if( x >= width ) + break; + + { + _CvContourInfo *par_info = 0; + _CvContourInfo *l_cinfo = 0; + CvSeq *seq = 0; + int is_hole = 0; + CvPoint origin; + + /* if not external contour */ + if( (!img_i && !(prev == 0 && p == 1)) || + (img_i && !(((prev & new_mask) != 0 || prev == 0) && (p & new_mask) == 0)) ) + { + /* check hole */ + if( (!img_i && (p != 0 || prev < 1)) || + (img_i && ((prev & new_mask) != 0 || (p & new_mask) != 0))) + goto resume_scan; + + if( prev & new_mask ) + { + lnbd.x = x - 1; + } + is_hole = 1; + } + + if( mode == 0 && (is_hole || img0[lnbd.y * step + lnbd.x] > 0) ) + goto resume_scan; + + origin.y = y; + origin.x = x - is_hole; + + /* find contour parent */ + if( mode <= 1 || (!is_hole && (mode == CV_RETR_CCOMP || mode == CV_RETR_FLOODFILL)) || lnbd.x <= 0 ) + { + par_info = &(scanner->frame_info); + } + else + { + int lval = (img0_i ? + img0_i[lnbd.y * step_i + lnbd.x] : + (int)img0[lnbd.y * step + lnbd.x]) & 0x7f; + _CvContourInfo *cur = scanner->cinfo_table[lval]; + + /* find the first bounding contour */ + while( cur ) + { + if( (unsigned) (lnbd.x - cur->rect.x) < (unsigned) cur->rect.width && + (unsigned) (lnbd.y - cur->rect.y) < (unsigned) cur->rect.height ) + { + if( par_info ) + { + if( (img0_i && + icvTraceContour_32s( img0_i + par_info->origin.y * step_i + + par_info->origin.x, step_i, img_i + lnbd.x, + par_info->is_hole ) > 0) || + (!img0_i && + icvTraceContour( img0 + par_info->origin.y * step + + par_info->origin.x, step, img + lnbd.x, + par_info->is_hole ) > 0) ) + break; + } + par_info = cur; + } + cur = cur->next; + } + + assert( par_info != 0 ); + + /* if current contour is a hole and previous contour is a hole or + current contour is external and previous contour is external then + the parent of the contour is the parent of the previous contour else + the parent is the previous contour itself. */ + if( par_info->is_hole == is_hole ) + { + par_info = par_info->parent; + /* every contour must have a parent + (at least, the frame of the image) */ + if( !par_info ) + par_info = &(scanner->frame_info); + } + + /* hole flag of the parent must differ from the flag of the contour */ + assert( par_info->is_hole != is_hole ); + if( par_info->contour == 0 ) /* removed contour */ + goto resume_scan; + } + + lnbd.x = x - is_hole; + + cvSaveMemStoragePos( scanner->storage2, &(scanner->backup_pos) ); + + seq = cvCreateSeq( scanner->seq_type1, scanner->header_size1, + scanner->elem_size1, scanner->storage1 ); + seq->flags |= is_hole ? CV_SEQ_FLAG_HOLE : 0; + + /* initialize header */ + if( mode <= 1 ) + { + l_cinfo = &(scanner->cinfo_temp); + icvFetchContour( img + x - is_hole, step, + cvPoint( origin.x + scanner->offset.x, + origin.y + scanner->offset.y), + seq, scanner->approx_method1 ); + } + else + { + union { _CvContourInfo* ci; CvSetElem* se; } v; + v.ci = l_cinfo; + cvSetAdd( scanner->cinfo_set, 0, &v.se ); + l_cinfo = v.ci; + int lval; + + if( img_i ) + { + lval = img_i[x - is_hole] & 127; + icvFetchContourEx_32s(img_i + x - is_hole, step_i, + cvPoint( origin.x + scanner->offset.x, + origin.y + scanner->offset.y), + seq, scanner->approx_method1, + &(l_cinfo->rect) ); + } + else + { + lval = nbd; + // change nbd + nbd = (nbd + 1) & 127; + nbd += nbd == 0 ? 3 : 0; + icvFetchContourEx( img + x - is_hole, step, + cvPoint( origin.x + scanner->offset.x, + origin.y + scanner->offset.y), + seq, scanner->approx_method1, + lval, &(l_cinfo->rect) ); + } + l_cinfo->rect.x -= scanner->offset.x; + l_cinfo->rect.y -= scanner->offset.y; + + l_cinfo->next = scanner->cinfo_table[lval]; + scanner->cinfo_table[lval] = l_cinfo; + } + + l_cinfo->is_hole = is_hole; + l_cinfo->contour = seq; + l_cinfo->origin = origin; + l_cinfo->parent = par_info; + + if( scanner->approx_method1 != scanner->approx_method2 ) + { + l_cinfo->contour = icvApproximateChainTC89( (CvChain *) seq, + scanner->header_size2, + scanner->storage2, + scanner->approx_method2 ); + cvClearMemStorage( scanner->storage1 ); + } + + l_cinfo->contour->v_prev = l_cinfo->parent->contour; + + if( par_info->contour == 0 ) + { + l_cinfo->contour = 0; + if( scanner->storage1 == scanner->storage2 ) + { + cvRestoreMemStoragePos( scanner->storage1, &(scanner->backup_pos) ); + } + else + { + cvClearMemStorage( scanner->storage1 ); + } + p = img[x]; + goto resume_scan; + } + + cvSaveMemStoragePos( scanner->storage2, &(scanner->backup_pos2) ); + scanner->l_cinfo = l_cinfo; + scanner->pt.x = !img_i ? x + 1 : x + 1 - is_hole; + scanner->pt.y = y; + scanner->lnbd = lnbd; + scanner->img = (schar *) img; + scanner->nbd = nbd; + return l_cinfo->contour; + + resume_scan: + + prev = p; + /* update lnbd */ + if( prev & -2 ) + { + lnbd.x = x; + } + } /* end of prev != p */ + } /* end of loop on x */ + + lnbd.x = 0; + lnbd.y = y + 1; + x = 1; + prev = 0; + } /* end of loop on y */ + + return 0; +} + + +/* + The function add to tree the last retrieved/substituted contour, + releases temp_storage, restores state of dst_storage (if needed), and + returns pointer to root of the contour tree */ +CV_IMPL CvSeq * +cvEndFindContours( CvContourScanner * _scanner ) +{ + CvContourScanner scanner; + CvSeq *first = 0; + + if( !_scanner ) + CV_Error( CV_StsNullPtr, "" ); + scanner = *_scanner; + + if( scanner ) + { + icvEndProcessContour( scanner ); + + if( scanner->storage1 != scanner->storage2 ) + cvReleaseMemStorage( &(scanner->storage1) ); + + if( scanner->cinfo_storage ) + cvReleaseMemStorage( &(scanner->cinfo_storage) ); + + first = scanner->frame.v_next; + cvFree( _scanner ); + } + + return first; +} + + +#define ICV_SINGLE 0 +#define ICV_CONNECTING_ABOVE 1 +#define ICV_CONNECTING_BELOW -1 +#define ICV_IS_COMPONENT_POINT(val) ((val) != 0) + +#define CV_GET_WRITTEN_ELEM( writer ) ((writer).ptr - (writer).seq->elem_size) + +typedef struct CvLinkedRunPoint +{ + struct CvLinkedRunPoint* link; + struct CvLinkedRunPoint* next; + CvPoint pt; +} +CvLinkedRunPoint; + + +static int +icvFindContoursInInterval( const CvArr* src, + /*int minValue, int maxValue,*/ + CvMemStorage* storage, + CvSeq** result, + int contourHeaderSize ) +{ + int count = 0; + cv::Ptr storage00; + cv::Ptr storage01; + CvSeq* first = 0; + + int i, j, k, n; + + uchar* src_data = 0; + int img_step = 0; + CvSize img_size; + + int connect_flag; + int lower_total; + int upper_total; + int all_total; + + CvSeq* runs; + CvLinkedRunPoint tmp; + CvLinkedRunPoint* tmp_prev; + CvLinkedRunPoint* upper_line = 0; + CvLinkedRunPoint* lower_line = 0; + CvLinkedRunPoint* last_elem; + + CvLinkedRunPoint* upper_run = 0; + CvLinkedRunPoint* lower_run = 0; + CvLinkedRunPoint* prev_point = 0; + + CvSeqWriter writer_ext; + CvSeqWriter writer_int; + CvSeqWriter writer; + CvSeqReader reader; + + CvSeq* external_contours; + CvSeq* internal_contours; + CvSeq* prev = 0; + + if( !storage ) + CV_Error( CV_StsNullPtr, "NULL storage pointer" ); + + if( !result ) + CV_Error( CV_StsNullPtr, "NULL double CvSeq pointer" ); + + if( contourHeaderSize < (int)sizeof(CvContour)) + CV_Error( CV_StsBadSize, "Contour header size must be >= sizeof(CvContour)" ); + + storage00 = cvCreateChildMemStorage(storage); + storage01 = cvCreateChildMemStorage(storage); + + CvMat stub, *mat; + + mat = cvGetMat( src, &stub ); + if( !CV_IS_MASK_ARR(mat)) + CV_Error( CV_StsBadArg, "Input array must be 8uC1 or 8sC1" ); + src_data = mat->data.ptr; + img_step = mat->step; + img_size = cvGetMatSize( mat ); + + // Create temporary sequences + runs = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvLinkedRunPoint), storage00 ); + cvStartAppendToSeq( runs, &writer ); + + cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_ext ); + cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_int ); + + tmp_prev = &(tmp); + tmp_prev->next = 0; + tmp_prev->link = 0; + + // First line. None of runs is binded + tmp.pt.y = 0; + i = 0; + CV_WRITE_SEQ_ELEM( tmp, writer ); + upper_line = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer ); + + tmp_prev = upper_line; + for( j = 0; j < img_size.width; ) + { + for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ ) + ; + if( j == img_size.width ) + break; + + tmp.pt.x = j; + CV_WRITE_SEQ_ELEM( tmp, writer ); + tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer ); + tmp_prev = tmp_prev->next; + + for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ ) + ; + + tmp.pt.x = j-1; + CV_WRITE_SEQ_ELEM( tmp, writer ); + tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer ); + tmp_prev->link = tmp_prev->next; + // First point of contour + CV_WRITE_SEQ_ELEM( tmp_prev, writer_ext ); + tmp_prev = tmp_prev->next; + } + cvFlushSeqWriter( &writer ); + upper_line = upper_line->next; + upper_total = runs->total - 1; + last_elem = tmp_prev; + tmp_prev->next = 0; + + for( i = 1; i < img_size.height; i++ ) + { +//------// Find runs in next line + src_data += img_step; + tmp.pt.y = i; + all_total = runs->total; + for( j = 0; j < img_size.width; ) + { + for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ ) + ; + if( j == img_size.width ) break; + + tmp.pt.x = j; + CV_WRITE_SEQ_ELEM( tmp, writer ); + tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer ); + tmp_prev = tmp_prev->next; + + for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ ) + ; + + tmp.pt.x = j-1; + CV_WRITE_SEQ_ELEM( tmp, writer ); + tmp_prev = tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer ); + }//j + cvFlushSeqWriter( &writer ); + lower_line = last_elem->next; + lower_total = runs->total - all_total; + last_elem = tmp_prev; + tmp_prev->next = 0; +//------// +//------// Find links between runs of lower_line and upper_line + upper_run = upper_line; + lower_run = lower_line; + connect_flag = ICV_SINGLE; + + for( k = 0, n = 0; k < upper_total/2 && n < lower_total/2; ) + { + switch( connect_flag ) + { + case ICV_SINGLE: + if( upper_run->next->pt.x < lower_run->next->pt.x ) + { + if( upper_run->next->pt.x >= lower_run->pt.x -1 ) + { + lower_run->link = upper_run; + connect_flag = ICV_CONNECTING_ABOVE; + prev_point = upper_run->next; + } + else + upper_run->next->link = upper_run; + k++; + upper_run = upper_run->next->next; + } + else + { + if( upper_run->pt.x <= lower_run->next->pt.x +1 ) + { + lower_run->link = upper_run; + connect_flag = ICV_CONNECTING_BELOW; + prev_point = lower_run->next; + } + else + { + lower_run->link = lower_run->next; + // First point of contour + CV_WRITE_SEQ_ELEM( lower_run, writer_ext ); + } + n++; + lower_run = lower_run->next->next; + } + break; + case ICV_CONNECTING_ABOVE: + if( upper_run->pt.x > lower_run->next->pt.x +1 ) + { + prev_point->link = lower_run->next; + connect_flag = ICV_SINGLE; + n++; + lower_run = lower_run->next->next; + } + else + { + prev_point->link = upper_run; + if( upper_run->next->pt.x < lower_run->next->pt.x ) + { + k++; + prev_point = upper_run->next; + upper_run = upper_run->next->next; + } + else + { + connect_flag = ICV_CONNECTING_BELOW; + prev_point = lower_run->next; + n++; + lower_run = lower_run->next->next; + } + } + break; + case ICV_CONNECTING_BELOW: + if( lower_run->pt.x > upper_run->next->pt.x +1 ) + { + upper_run->next->link = prev_point; + connect_flag = ICV_SINGLE; + k++; + upper_run = upper_run->next->next; + } + else + { + // First point of contour + CV_WRITE_SEQ_ELEM( lower_run, writer_int ); + + lower_run->link = prev_point; + if( lower_run->next->pt.x < upper_run->next->pt.x ) + { + n++; + prev_point = lower_run->next; + lower_run = lower_run->next->next; + } + else + { + connect_flag = ICV_CONNECTING_ABOVE; + k++; + prev_point = upper_run->next; + upper_run = upper_run->next->next; + } + } + break; + } + }// k, n + + for( ; n < lower_total/2; n++ ) + { + if( connect_flag != ICV_SINGLE ) + { + prev_point->link = lower_run->next; + connect_flag = ICV_SINGLE; + lower_run = lower_run->next->next; + continue; + } + lower_run->link = lower_run->next; + + //First point of contour + CV_WRITE_SEQ_ELEM( lower_run, writer_ext ); + + lower_run = lower_run->next->next; + } + + for( ; k < upper_total/2; k++ ) + { + if( connect_flag != ICV_SINGLE ) + { + upper_run->next->link = prev_point; + connect_flag = ICV_SINGLE; + upper_run = upper_run->next->next; + continue; + } + upper_run->next->link = upper_run; + upper_run = upper_run->next->next; + } + upper_line = lower_line; + upper_total = lower_total; + }//i + + upper_run = upper_line; + + //the last line of image + for( k = 0; k < upper_total/2; k++ ) + { + upper_run->next->link = upper_run; + upper_run = upper_run->next->next; + } + +//------// +//------//Find end read contours + external_contours = cvEndWriteSeq( &writer_ext ); + internal_contours = cvEndWriteSeq( &writer_int ); + + for( k = 0; k < 2; k++ ) + { + CvSeq* contours = k == 0 ? external_contours : internal_contours; + + cvStartReadSeq( contours, &reader ); + + for( j = 0; j < contours->total; j++, count++ ) + { + CvLinkedRunPoint* p_temp; + CvLinkedRunPoint* p00; + CvLinkedRunPoint* p01; + CvSeq* contour; + + CV_READ_SEQ_ELEM( p00, reader ); + p01 = p00; + + if( !p00->link ) + continue; + + cvStartWriteSeq( CV_SEQ_ELTYPE_POINT | CV_SEQ_POLYLINE | CV_SEQ_FLAG_CLOSED, + contourHeaderSize, sizeof(CvPoint), storage, &writer ); + do + { + CV_WRITE_SEQ_ELEM( p00->pt, writer ); + p_temp = p00; + p00 = p00->link; + p_temp->link = 0; + } + while( p00 != p01 ); + + contour = cvEndWriteSeq( &writer ); + cvBoundingRect( contour, 1 ); + + if( k != 0 ) + contour->flags |= CV_SEQ_FLAG_HOLE; + + if( !first ) + prev = first = contour; + else + { + contour->h_prev = prev; + prev = prev->h_next = contour; + } + } + } + + if( !first ) + count = -1; + + if( result ) + *result = first; + + return count; +} + + + +/*F/////////////////////////////////////////////////////////////////////////////////////// +// Name: cvFindContours +// Purpose: +// Finds all the contours on the bi-level image. +// Context: +// Parameters: +// img - source image. +// Non-zero pixels are considered as 1-pixels +// and zero pixels as 0-pixels. +// step - full width of source image in bytes. +// size - width and height of the image in pixels +// storage - pointer to storage where will the output contours be placed. +// header_size - header size of resulting contours +// mode - mode of contour retrieval. +// method - method of approximation that is applied to contours +// first_contour - pointer to first contour pointer +// Returns: +// CV_OK or error code +// Notes: +//F*/ +CV_IMPL int +cvFindContours( void* img, CvMemStorage* storage, + CvSeq** firstContour, int cntHeaderSize, + int mode, + int method, CvPoint offset ) +{ + CvContourScanner scanner = 0; + CvSeq *contour = 0; + int count = -1; + + if( !firstContour ) + CV_Error( CV_StsNullPtr, "NULL double CvSeq pointer" ); + + *firstContour = 0; + + if( method == CV_LINK_RUNS ) + { + if( offset.x != 0 || offset.y != 0 ) + CV_Error( CV_StsOutOfRange, + "Nonzero offset is not supported in CV_LINK_RUNS yet" ); + + count = icvFindContoursInInterval( img, storage, firstContour, cntHeaderSize ); + } + else + { + try + { + scanner = cvStartFindContours( img, storage, cntHeaderSize, mode, method, offset ); + + do + { + count++; + contour = cvFindNextContour( scanner ); + } + while( contour != 0 ); + } + catch(...) + { + if( scanner ) + cvEndFindContours(&scanner); + throw; + } + + *firstContour = cvEndFindContours( &scanner ); + } + + return count; +} + +void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours, + OutputArray _hierarchy, int mode, int method, Point offset ) +{ + Mat image = _image.getMat(); + MemStorage storage(cvCreateMemStorage()); + CvMat _cimage = image; + CvSeq* _ccontours = 0; + if( _hierarchy.needed() ) + _hierarchy.clear(); + cvFindContours(&_cimage, storage, &_ccontours, sizeof(CvContour), mode, method, offset); + if( !_ccontours ) + { + _contours.clear(); + return; + } + Seq all_contours(cvTreeToNodeSeq( _ccontours, sizeof(CvSeq), storage )); + int i, total = (int)all_contours.size(); + _contours.create(total, 1, 0, -1, true); + SeqIterator it = all_contours.begin(); + for( i = 0; i < total; i++, ++it ) + { + CvSeq* c = *it; + ((CvContour*)c)->color = (int)i; + _contours.create((int)c->total, 1, CV_32SC2, i, true); + Mat ci = _contours.getMat(i); + CV_Assert( ci.isContinuous() ); + cvCvtSeqToArray(c, ci.data); + } + + if( _hierarchy.needed() ) + { + _hierarchy.create(1, total, CV_32SC4, -1, true); + Vec4i* hierarchy = _hierarchy.getMat().ptr(); + + it = all_contours.begin(); + for( i = 0; i < total; i++, ++it ) + { + CvSeq* c = *it; + int h_next = c->h_next ? ((CvContour*)c->h_next)->color : -1; + int h_prev = c->h_prev ? ((CvContour*)c->h_prev)->color : -1; + int v_next = c->v_next ? ((CvContour*)c->v_next)->color : -1; + int v_prev = c->v_prev ? ((CvContour*)c->v_prev)->color : -1; + hierarchy[i] = Vec4i(h_next, h_prev, v_next, v_prev); + } + } +} + +void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours, + int mode, int method, Point offset) +{ + findContours(_image, _contours, noArray(), mode, method, offset); +} + +void cv::approxPolyDP( InputArray _curve, OutputArray _approxCurve, + double epsilon, bool closed ) +{ + Mat curve = _curve.getMat(); + int npoints = curve.checkVector(2), depth = curve.depth(); + CV_Assert( npoints >= 0 && (depth == CV_32S || depth == CV_32F)); + CvMat _ccurve = curve; + MemStorage storage(cvCreateMemStorage()); + CvSeq* result = cvApproxPoly(&_ccurve, sizeof(CvContour), storage, CV_POLY_APPROX_DP, epsilon, closed); + if( result->total > 0 ) + { + _approxCurve.create(result->total, 1, CV_MAKETYPE(curve.depth(), 2), -1, true); + cvCvtSeqToArray(result, _approxCurve.getMat().data ); + } +} + + +double cv::arcLength( InputArray _curve, bool closed ) +{ + Mat curve = _curve.getMat(); + CV_Assert(curve.checkVector(2) >= 0 && (curve.depth() == CV_32F || curve.depth() == CV_32S)); + CvMat _ccurve = curve; + return cvArcLength(&_ccurve, CV_WHOLE_SEQ, closed); +} + + +cv::Rect cv::boundingRect( InputArray _points ) +{ + Mat points = _points.getMat(); + CV_Assert(points.checkVector(2) >= 0 && (points.depth() == CV_32F || points.depth() == CV_32S)); + CvMat _cpoints = points; + return cvBoundingRect(&_cpoints, 0); +} + + +double cv::contourArea( InputArray _contour, bool oriented ) +{ + Mat contour = _contour.getMat(); + CV_Assert(contour.checkVector(2) >= 0 && (contour.depth() == CV_32F || contour.depth() == CV_32S)); + CvMat _ccontour = contour; + return cvContourArea(&_ccontour, CV_WHOLE_SEQ, oriented); +} + + +cv::RotatedRect cv::minAreaRect( InputArray _points ) +{ + Mat points = _points.getMat(); + CV_Assert(points.checkVector(2) >= 0 && (points.depth() == CV_32F || points.depth() == CV_32S)); + CvMat _cpoints = points; + return cvMinAreaRect2(&_cpoints, 0); +} + + +void cv::minEnclosingCircle( InputArray _points, + Point2f& center, float& radius ) +{ + Mat points = _points.getMat(); + CV_Assert(points.checkVector(2) >= 0 && (points.depth() == CV_32F || points.depth() == CV_32S)); + CvMat _cpoints = points; + cvMinEnclosingCircle( &_cpoints, (CvPoint2D32f*)¢er, &radius ); +} + + +double cv::matchShapes( InputArray _contour1, + InputArray _contour2, + int method, double parameter ) +{ + Mat contour1 = _contour1.getMat(), contour2 = _contour2.getMat(); + CV_Assert(contour1.checkVector(2) >= 0 && contour2.checkVector(2) >= 0 && + (contour1.depth() == CV_32F || contour1.depth() == CV_32S) && + contour1.depth() == contour2.depth()); + + CvMat c1 = Mat(contour1), c2 = Mat(contour2); + return cvMatchShapes(&c1, &c2, method, parameter); +} + + +void cv::convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool returnPoints ) +{ + Mat points = _points.getMat(); + int nelems = points.checkVector(2), depth = points.depth(); + CV_Assert(nelems >= 0 && (depth == CV_32F || depth == CV_32S)); + + if( nelems == 0 ) + { + _hull.release(); + return; + } + + returnPoints = !_hull.fixedType() ? returnPoints : _hull.type() != CV_32S; + Mat hull(nelems, 1, returnPoints ? CV_MAKETYPE(depth, 2) : CV_32S); + CvMat _cpoints = points, _chull = hull; + cvConvexHull2(&_cpoints, &_chull, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, returnPoints); + _hull.create(_chull.rows, 1, hull.type(), -1, true); + Mat dhull = _hull.getMat(), shull(dhull.size(), dhull.type(), hull.data); + shull.copyTo(dhull); +} + + +void cv::convexityDefects( InputArray _points, InputArray _hull, OutputArray _defects ) +{ + Mat points = _points.getMat(); + int ptnum = points.checkVector(2, CV_32S); + CV_Assert( ptnum > 3 ); + Mat hull = _hull.getMat(); + CV_Assert( hull.checkVector(1, CV_32S) > 2 ); + Ptr storage = cvCreateMemStorage(); + + CvMat c_points = points, c_hull = hull; + CvSeq* seq = cvConvexityDefects(&c_points, &c_hull, storage); + int i, n = seq->total; + + if( n == 0 ) + { + _defects.release(); + return; + } + + _defects.create(n, 1, CV_32SC4); + Mat defects = _defects.getMat(); + + SeqIterator it = Seq(seq).begin(); + CvPoint* ptorg = (CvPoint*)points.data; + + for( i = 0; i < n; i++, ++it ) + { + CvConvexityDefect& d = *it; + int idx0 = (int)(d.start - ptorg); + int idx1 = (int)(d.end - ptorg); + int idx2 = (int)(d.depth_point - ptorg); + CV_Assert( 0 <= idx0 && idx0 < ptnum ); + CV_Assert( 0 <= idx1 && idx1 < ptnum ); + CV_Assert( 0 <= idx2 && idx2 < ptnum ); + CV_Assert( d.depth >= 0 ); + int idepth = cvRound(d.depth*256); + defects.at(i) = Vec4i(idx0, idx1, idx2, idepth); + } +} + + +bool cv::isContourConvex( InputArray _contour ) +{ + Mat contour = _contour.getMat(); + CV_Assert(contour.checkVector(2) >= 0 && + (contour.depth() == CV_32F || contour.depth() == CV_32S)); + CvMat c = Mat(contour); + return cvCheckContourConvexity(&c) > 0; +} + +cv::RotatedRect cv::fitEllipse( InputArray _points ) +{ + Mat points = _points.getMat(); + CV_Assert(points.checkVector(2) >= 0 && + (points.depth() == CV_32F || points.depth() == CV_32S)); + CvMat _cpoints = points; + return cvFitEllipse2(&_cpoints); +} + + +void cv::fitLine( InputArray _points, OutputArray _line, int distType, + double param, double reps, double aeps ) +{ + Mat points = _points.getMat(); + + bool is3d = points.checkVector(3) >= 0; + bool is2d = points.checkVector(2) >= 0; + + CV_Assert( (is2d || is3d) && (points.depth() == CV_32F || points.depth() == CV_32S) ); + CvMat _cpoints = points.reshape(2 + (int)is3d); + float line[6]; + cvFitLine(&_cpoints, distType, param, reps, aeps, &line[0]); + + int out_size = (is2d)?( (is3d)? (points.channels() * points.rows * 2) : 4 ): 6; + + _line.create(out_size, 1, CV_32F, -1, true); + Mat l = _line.getMat(); + CV_Assert( l.isContinuous() ); + memcpy( l.data, line, out_size * sizeof(line[0]) ); +} + + +double cv::pointPolygonTest( InputArray _contour, + Point2f pt, bool measureDist ) +{ + Mat contour = _contour.getMat(); + CV_Assert(contour.checkVector(2) >= 0 && + (contour.depth() == CV_32F || contour.depth() == CV_32S)); + CvMat c = Mat(contour); + return cvPointPolygonTest( &c, pt, measureDist ); +} + +/* End of file. */ diff --git a/imgproc/src/convhull.cpp b/imgproc/src/convhull.cpp new file mode 100644 index 0000000..145c55e --- /dev/null +++ b/imgproc/src/convhull.cpp @@ -0,0 +1,815 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +static int +icvSklansky_32s( CvPoint** array, int start, int end, int* stack, int nsign, int sign2 ) +{ + int incr = end > start ? 1 : -1; + /* prepare first triangle */ + int pprev = start, pcur = pprev + incr, pnext = pcur + incr; + int stacksize = 3; + + if( start == end || + (array[start]->x == array[end]->x && + array[start]->y == array[end]->y) ) + { + stack[0] = start; + return 1; + } + + stack[0] = pprev; + stack[1] = pcur; + stack[2] = pnext; + + end += incr; /* make end = afterend */ + + while( pnext != end ) + { + /* check the angle p1,p2,p3 */ + int cury = array[pcur]->y; + int nexty = array[pnext]->y; + int by = nexty - cury; + + if( CV_SIGN(by) != nsign ) + { + int ax = array[pcur]->x - array[pprev]->x; + int bx = array[pnext]->x - array[pcur]->x; + int ay = cury - array[pprev]->y; + int convexity = ay*bx - ax*by;/* if >0 then convex angle */ + + if( CV_SIGN(convexity) == sign2 && (ax != 0 || ay != 0) ) + { + pprev = pcur; + pcur = pnext; + pnext += incr; + stack[stacksize] = pnext; + stacksize++; + } + else + { + if( pprev == start ) + { + pcur = pnext; + stack[1] = pcur; + pnext += incr; + stack[2] = pnext; + } + else + { + stack[stacksize-2] = pnext; + pcur = pprev; + pprev = stack[stacksize-4]; + stacksize--; + } + } + } + else + { + pnext += incr; + stack[stacksize-1] = pnext; + } + } + + return --stacksize; +} + + +static int +icvSklansky_32f( CvPoint2D32f** array, int start, int end, int* stack, int nsign, int sign2 ) +{ + int incr = end > start ? 1 : -1; + /* prepare first triangle */ + int pprev = start, pcur = pprev + incr, pnext = pcur + incr; + int stacksize = 3; + + if( start == end || + (array[start]->x == array[end]->x && + array[start]->y == array[end]->y) ) + { + stack[0] = start; + return 1; + } + + stack[0] = pprev; + stack[1] = pcur; + stack[2] = pnext; + + end += incr; /* make end = afterend */ + + while( pnext != end ) + { + /* check the angle p1,p2,p3 */ + float cury = array[pcur]->y; + float nexty = array[pnext]->y; + float by = nexty - cury; + + if( CV_SIGN( by ) != nsign ) + { + float ax = array[pcur]->x - array[pprev]->x; + float bx = array[pnext]->x - array[pcur]->x; + float ay = cury - array[pprev]->y; + float convexity = ay*bx - ax*by;/* if >0 then convex angle */ + + if( CV_SIGN( convexity ) == sign2 && (ax != 0 || ay != 0) ) + { + pprev = pcur; + pcur = pnext; + pnext += incr; + stack[stacksize] = pnext; + stacksize++; + } + else + { + if( pprev == start ) + { + pcur = pnext; + stack[1] = pcur; + pnext += incr; + stack[2] = pnext; + + } + else + { + stack[stacksize-2] = pnext; + pcur = pprev; + pprev = stack[stacksize-4]; + stacksize--; + } + } + } + else + { + pnext += incr; + stack[stacksize-1] = pnext; + } + } + + return --stacksize; +} + +typedef int (*sklansky_func)( CvPoint** points, int start, int end, + int* stack, int sign, int sign2 ); + +#define cmp_pts( pt1, pt2 ) \ + ((pt1)->x < (pt2)->x || ((pt1)->x <= (pt2)->x && (pt1)->y < (pt2)->y)) +static CV_IMPLEMENT_QSORT( icvSortPointsByPointers_32s, CvPoint*, cmp_pts ) +static CV_IMPLEMENT_QSORT( icvSortPointsByPointers_32f, CvPoint2D32f*, cmp_pts ) + +static void +icvCalcAndWritePtIndices( CvPoint** pointer, int* stack, int start, int end, + CvSeq* ptseq, CvSeqWriter* writer ) +{ + int i, incr = start < end ? 1 : -1; + int idx, first_idx = ptseq->first->start_index; + + for( i = start; i != end; i += incr ) + { + CvPoint* ptr = (CvPoint*)pointer[stack[i]]; + CvSeqBlock* block = ptseq->first; + while( (unsigned)(idx = (int)(ptr - (CvPoint*)block->data)) >= (unsigned)block->count ) + { + block = block->next; + if( block == ptseq->first ) + CV_Error( CV_StsError, "Internal error" ); + } + idx += block->start_index - first_idx; + CV_WRITE_SEQ_ELEM( idx, *writer ); + } +} + + +CV_IMPL CvSeq* +cvConvexHull2( const CvArr* array, void* hull_storage, + int orientation, int return_points ) +{ + union { CvContour* c; CvSeq* s; } hull; + cv::AutoBuffer _pointer; + CvPoint** pointer; + CvPoint2D32f** pointerf = 0; + cv::AutoBuffer _stack; + int* stack; + + hull.s = 0; + + CvMat* mat = 0; + CvSeqReader reader; + CvSeqWriter writer; + CvContour contour_header; + union { CvContour c; CvSeq s; } hull_header; + CvSeqBlock block, hullblock; + CvSeq* ptseq = 0; + CvSeq* hullseq = 0; + int is_float; + int* t_stack; + int t_count; + int i, miny_ind = 0, maxy_ind = 0, total; + int hulltype; + int stop_idx; + sklansky_func sklansky; + + if( CV_IS_SEQ( array )) + { + ptseq = (CvSeq*)array; + if( !CV_IS_SEQ_POINT_SET( ptseq )) + CV_Error( CV_StsBadArg, "Unsupported sequence type" ); + if( hull_storage == 0 ) + hull_storage = ptseq->storage; + } + else + { + ptseq = cvPointSeqFromMat( CV_SEQ_KIND_GENERIC, array, &contour_header, &block ); + } + + if( CV_IS_STORAGE( hull_storage )) + { + if( return_points ) + { + hullseq = cvCreateSeq( + CV_SEQ_KIND_CURVE|CV_SEQ_ELTYPE(ptseq)| + CV_SEQ_FLAG_CLOSED|CV_SEQ_FLAG_CONVEX, + sizeof(CvContour), sizeof(CvPoint),(CvMemStorage*)hull_storage ); + } + else + { + hullseq = cvCreateSeq( + CV_SEQ_KIND_CURVE|CV_SEQ_ELTYPE_PPOINT| + CV_SEQ_FLAG_CLOSED|CV_SEQ_FLAG_CONVEX, + sizeof(CvContour), sizeof(CvPoint*), (CvMemStorage*)hull_storage ); + } + } + else + { + if( !CV_IS_MAT( hull_storage )) + CV_Error(CV_StsBadArg, "Destination must be valid memory storage or matrix"); + + mat = (CvMat*)hull_storage; + + if( (mat->cols != 1 && mat->rows != 1) || !CV_IS_MAT_CONT(mat->type)) + CV_Error( CV_StsBadArg, + "The hull matrix should be continuous and have a single row or a single column" ); + + if( mat->cols + mat->rows - 1 < ptseq->total ) + CV_Error( CV_StsBadSize, "The hull matrix size might be not enough to fit the hull" ); + + if( CV_MAT_TYPE(mat->type) != CV_SEQ_ELTYPE(ptseq) && + CV_MAT_TYPE(mat->type) != CV_32SC1 ) + CV_Error( CV_StsUnsupportedFormat, + "The hull matrix must have the same type as input or 32sC1 (integers)" ); + + hullseq = cvMakeSeqHeaderForArray( + CV_SEQ_KIND_CURVE|CV_MAT_TYPE(mat->type)|CV_SEQ_FLAG_CLOSED, + sizeof(contour_header), CV_ELEM_SIZE(mat->type), mat->data.ptr, + mat->cols + mat->rows - 1, &hull_header.s, &hullblock ); + + cvClearSeq( hullseq ); + } + + total = ptseq->total; + if( total == 0 ) + { + if( mat ) + CV_Error( CV_StsBadSize, + "Point sequence can not be empty if the output is matrix" ); + return hull.s; + } + + cvStartAppendToSeq( hullseq, &writer ); + + is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2; + hulltype = CV_SEQ_ELTYPE(hullseq); + sklansky = !is_float ? (sklansky_func)icvSklansky_32s : + (sklansky_func)icvSklansky_32f; + + _pointer.allocate( ptseq->total ); + _stack.allocate( ptseq->total + 2); + pointer = _pointer; + pointerf = (CvPoint2D32f**)pointer; + stack = _stack; + + cvStartReadSeq( ptseq, &reader ); + + for( i = 0; i < total; i++ ) + { + pointer[i] = (CvPoint*)reader.ptr; + CV_NEXT_SEQ_ELEM( ptseq->elem_size, reader ); + } + + // sort the point set by x-coordinate, find min and max y + if( !is_float ) + { + icvSortPointsByPointers_32s( pointer, total, 0 ); + for( i = 1; i < total; i++ ) + { + int y = pointer[i]->y; + if( pointer[miny_ind]->y > y ) + miny_ind = i; + if( pointer[maxy_ind]->y < y ) + maxy_ind = i; + } + } + else + { + icvSortPointsByPointers_32f( pointerf, total, 0 ); + for( i = 1; i < total; i++ ) + { + float y = pointerf[i]->y; + if( pointerf[miny_ind]->y > y ) + miny_ind = i; + if( pointerf[maxy_ind]->y < y ) + maxy_ind = i; + } + } + + if( pointer[0]->x == pointer[total-1]->x && + pointer[0]->y == pointer[total-1]->y ) + { + if( hulltype == CV_SEQ_ELTYPE_PPOINT ) + { + CV_WRITE_SEQ_ELEM( pointer[0], writer ); + } + else if( hulltype == CV_SEQ_ELTYPE_INDEX ) + { + int index = 0; + CV_WRITE_SEQ_ELEM( index, writer ); + } + else + { + CvPoint pt = pointer[0][0]; + CV_WRITE_SEQ_ELEM( pt, writer ); + } + goto finish_hull; + } + + /*upper half */ + { + int *tl_stack = stack; + int tl_count = sklansky( pointer, 0, maxy_ind, tl_stack, -1, 1 ); + int *tr_stack = tl_stack + tl_count; + int tr_count = sklansky( pointer, ptseq->total - 1, maxy_ind, tr_stack, -1, -1 ); + + /* gather upper part of convex hull to output */ + if( orientation == CV_COUNTER_CLOCKWISE ) + { + CV_SWAP( tl_stack, tr_stack, t_stack ); + CV_SWAP( tl_count, tr_count, t_count ); + } + + if( hulltype == CV_SEQ_ELTYPE_PPOINT ) + { + for( i = 0; i < tl_count - 1; i++ ) + CV_WRITE_SEQ_ELEM( pointer[tl_stack[i]], writer ); + + for( i = tr_count - 1; i > 0; i-- ) + CV_WRITE_SEQ_ELEM( pointer[tr_stack[i]], writer ); + } + else if( hulltype == CV_SEQ_ELTYPE_INDEX ) + { + icvCalcAndWritePtIndices( pointer, tl_stack, 0, tl_count-1, ptseq, &writer ); + icvCalcAndWritePtIndices( pointer, tr_stack, tr_count-1, 0, ptseq, &writer ); + } + else + { + for( i = 0; i < tl_count - 1; i++ ) + CV_WRITE_SEQ_ELEM( pointer[tl_stack[i]][0], writer ); + + for( i = tr_count - 1; i > 0; i-- ) + CV_WRITE_SEQ_ELEM( pointer[tr_stack[i]][0], writer ); + } + stop_idx = tr_count > 2 ? tr_stack[1] : tl_count > 2 ? tl_stack[tl_count - 2] : -1; + } + + /* lower half */ + { + int *bl_stack = stack; + int bl_count = sklansky( pointer, 0, miny_ind, bl_stack, 1, -1 ); + int *br_stack = stack + bl_count; + int br_count = sklansky( pointer, ptseq->total - 1, miny_ind, br_stack, 1, 1 ); + + if( orientation != CV_COUNTER_CLOCKWISE ) + { + CV_SWAP( bl_stack, br_stack, t_stack ); + CV_SWAP( bl_count, br_count, t_count ); + } + + if( stop_idx >= 0 ) + { + int check_idx = bl_count > 2 ? bl_stack[1] : + bl_count + br_count > 2 ? br_stack[2-bl_count] : -1; + if( check_idx == stop_idx || (check_idx >= 0 && + pointer[check_idx]->x == pointer[stop_idx]->x && + pointer[check_idx]->y == pointer[stop_idx]->y) ) + { + /* if all the points lie on the same line, then + the bottom part of the convex hull is the mirrored top part + (except the exteme points).*/ + bl_count = MIN( bl_count, 2 ); + br_count = MIN( br_count, 2 ); + } + } + + if( hulltype == CV_SEQ_ELTYPE_PPOINT ) + { + for( i = 0; i < bl_count - 1; i++ ) + CV_WRITE_SEQ_ELEM( pointer[bl_stack[i]], writer ); + + for( i = br_count - 1; i > 0; i-- ) + CV_WRITE_SEQ_ELEM( pointer[br_stack[i]], writer ); + } + else if( hulltype == CV_SEQ_ELTYPE_INDEX ) + { + icvCalcAndWritePtIndices( pointer, bl_stack, 0, bl_count-1, ptseq, &writer ); + icvCalcAndWritePtIndices( pointer, br_stack, br_count-1, 0, ptseq, &writer ); + } + else + { + for( i = 0; i < bl_count - 1; i++ ) + CV_WRITE_SEQ_ELEM( pointer[bl_stack[i]][0], writer ); + + for( i = br_count - 1; i > 0; i-- ) + CV_WRITE_SEQ_ELEM( pointer[br_stack[i]][0], writer ); + } + } + +finish_hull: + cvEndWriteSeq( &writer ); + + if( mat ) + { + if( mat->rows > mat->cols ) + mat->rows = hullseq->total; + else + mat->cols = hullseq->total; + } + else + { + hull.s = hullseq; + hull.c->rect = cvBoundingRect( ptseq, + ptseq->header_size < (int)sizeof(CvContour) || + &ptseq->flags == &contour_header.flags ); + + /*if( ptseq != (CvSeq*)&contour_header ) + hullseq->v_prev = ptseq;*/ + } + + return hull.s; +} + + +/* contour must be a simple polygon */ +/* it must have more than 3 points */ +CV_IMPL CvSeq* cvConvexityDefects( const CvArr* array, + const CvArr* hullarray, + CvMemStorage* storage ) +{ + CvSeq* defects = 0; + + int i, index; + CvPoint* hull_cur; + + /* is orientation of hull different from contour one */ + int rev_orientation; + + CvContour contour_header; + union { CvContour c; CvSeq s; } hull_header; + CvSeqBlock block, hullblock; + CvSeq *ptseq = (CvSeq*)array, *hull = (CvSeq*)hullarray; + + CvSeqReader hull_reader; + CvSeqReader ptseq_reader; + CvSeqWriter writer; + int is_index; + + if( CV_IS_SEQ( ptseq )) + { + if( !CV_IS_SEQ_POINT_SET( ptseq )) + CV_Error( CV_StsUnsupportedFormat, + "Input sequence is not a sequence of points" ); + if( !storage ) + storage = ptseq->storage; + } + else + { + ptseq = cvPointSeqFromMat( CV_SEQ_KIND_GENERIC, array, &contour_header, &block ); + } + + if( CV_SEQ_ELTYPE( ptseq ) != CV_32SC2 ) + CV_Error( CV_StsUnsupportedFormat, "Floating-point coordinates are not supported here" ); + + if( CV_IS_SEQ( hull )) + { + int hulltype = CV_SEQ_ELTYPE( hull ); + if( hulltype != CV_SEQ_ELTYPE_PPOINT && hulltype != CV_SEQ_ELTYPE_INDEX ) + CV_Error( CV_StsUnsupportedFormat, + "Convex hull must represented as a sequence " + "of indices or sequence of pointers" ); + if( !storage ) + storage = hull->storage; + } + else + { + CvMat* mat = (CvMat*)hull; + + if( !CV_IS_MAT( hull )) + CV_Error(CV_StsBadArg, "Convex hull is neither sequence nor matrix"); + + if( (mat->cols != 1 && mat->rows != 1) || + !CV_IS_MAT_CONT(mat->type) || CV_MAT_TYPE(mat->type) != CV_32SC1 ) + CV_Error( CV_StsBadArg, + "The matrix should be 1-dimensional and continuous array of int's" ); + + if( mat->cols + mat->rows - 1 > ptseq->total ) + CV_Error( CV_StsBadSize, "Convex hull is larger than the point sequence" ); + + hull = cvMakeSeqHeaderForArray( + CV_SEQ_KIND_CURVE|CV_MAT_TYPE(mat->type)|CV_SEQ_FLAG_CLOSED, + sizeof(CvContour), CV_ELEM_SIZE(mat->type), mat->data.ptr, + mat->cols + mat->rows - 1, &hull_header.s, &hullblock ); + } + + is_index = CV_SEQ_ELTYPE(hull) == CV_SEQ_ELTYPE_INDEX; + + if( !storage ) + CV_Error( CV_StsNullPtr, "NULL storage pointer" ); + + defects = cvCreateSeq( CV_SEQ_KIND_GENERIC, sizeof(CvSeq), sizeof(CvConvexityDefect), storage ); + + if( ptseq->total < 4 || hull->total < 3) + { + //CV_ERROR( CV_StsBadSize, + // "point seq size must be >= 4, convex hull size must be >= 3" ); + return defects; + } + + /* recognize co-orientation of ptseq and its hull */ + { + int sign = 0; + int index1, index2, index3; + + if( !is_index ) + { + CvPoint* pos = *CV_SEQ_ELEM( hull, CvPoint*, 0 ); + index1 = cvSeqElemIdx( ptseq, pos ); + + pos = *CV_SEQ_ELEM( hull, CvPoint*, 1 ); + index2 = cvSeqElemIdx( ptseq, pos ); + + pos = *CV_SEQ_ELEM( hull, CvPoint*, 2 ); + index3 = cvSeqElemIdx( ptseq, pos ); + } + else + { + index1 = *CV_SEQ_ELEM( hull, int, 0 ); + index2 = *CV_SEQ_ELEM( hull, int, 1 ); + index3 = *CV_SEQ_ELEM( hull, int, 2 ); + } + + sign += (index2 > index1) ? 1 : 0; + sign += (index3 > index2) ? 1 : 0; + sign += (index1 > index3) ? 1 : 0; + + rev_orientation = (sign == 2) ? 0 : 1; + } + + cvStartReadSeq( ptseq, &ptseq_reader, 0 ); + cvStartReadSeq( hull, &hull_reader, rev_orientation ); + + if( !is_index ) + { + hull_cur = *(CvPoint**)hull_reader.prev_elem; + index = cvSeqElemIdx( ptseq, (char*)hull_cur, 0 ); + } + else + { + index = *(int*)hull_reader.prev_elem; + hull_cur = CV_GET_SEQ_ELEM( CvPoint, ptseq, index ); + } + cvSetSeqReaderPos( &ptseq_reader, index ); + cvStartAppendToSeq( defects, &writer ); + + /* cycle through ptseq and hull with computing defects */ + for( i = 0; i < hull->total; i++ ) + { + CvConvexityDefect defect; + int is_defect = 0; + double dx0, dy0; + double depth = 0, scale; + CvPoint* hull_next; + + if( !is_index ) + hull_next = *(CvPoint**)hull_reader.ptr; + else + { + int t = *(int*)hull_reader.ptr; + hull_next = CV_GET_SEQ_ELEM( CvPoint, ptseq, t ); + } + + dx0 = (double)hull_next->x - (double)hull_cur->x; + dy0 = (double)hull_next->y - (double)hull_cur->y; + assert( dx0 != 0 || dy0 != 0 ); + scale = 1./sqrt(dx0*dx0 + dy0*dy0); + + defect.start = hull_cur; + defect.end = hull_next; + + for(;;) + { + /* go through ptseq to achieve next hull point */ + CV_NEXT_SEQ_ELEM( sizeof(CvPoint), ptseq_reader ); + + if( ptseq_reader.ptr == (schar*)hull_next ) + break; + else + { + CvPoint* cur = (CvPoint*)ptseq_reader.ptr; + + /* compute distance from current point to hull edge */ + double dx = (double)cur->x - (double)hull_cur->x; + double dy = (double)cur->y - (double)hull_cur->y; + + /* compute depth */ + double dist = fabs(-dy0*dx + dx0*dy) * scale; + + if( dist > depth ) + { + depth = dist; + defect.depth_point = cur; + defect.depth = (float)depth; + is_defect = 1; + } + } + } + if( is_defect ) + { + CV_WRITE_SEQ_ELEM( defect, writer ); + } + + hull_cur = hull_next; + if( rev_orientation ) + { + CV_PREV_SEQ_ELEM( hull->elem_size, hull_reader ); + } + else + { + CV_NEXT_SEQ_ELEM( hull->elem_size, hull_reader ); + } + } + + return cvEndWriteSeq( &writer ); +} + + +CV_IMPL int +cvCheckContourConvexity( const CvArr* array ) +{ + int flag = -1; + + int i; + int orientation = 0; + CvSeqReader reader; + CvContour contour_header; + CvSeqBlock block; + CvSeq* contour = (CvSeq*)array; + + if( CV_IS_SEQ(contour) ) + { + if( !CV_IS_SEQ_POINT_SET(contour)) + CV_Error( CV_StsUnsupportedFormat, + "Input sequence must be polygon (closed 2d curve)" ); + } + else + { + contour = cvPointSeqFromMat(CV_SEQ_KIND_CURVE|CV_SEQ_FLAG_CLOSED, array, &contour_header, &block ); + } + + if( contour->total == 0 ) + return -1; + + cvStartReadSeq( contour, &reader, 0 ); + flag = 1; + + if( CV_SEQ_ELTYPE( contour ) == CV_32SC2 ) + { + CvPoint *prev_pt = (CvPoint*)reader.prev_elem; + CvPoint *cur_pt = (CvPoint*)reader.ptr; + + int dx0 = cur_pt->x - prev_pt->x; + int dy0 = cur_pt->y - prev_pt->y; + + for( i = 0; i < contour->total; i++ ) + { + int dxdy0, dydx0; + int dx, dy; + + /*int orient; */ + CV_NEXT_SEQ_ELEM( sizeof(CvPoint), reader ); + prev_pt = cur_pt; + cur_pt = (CvPoint *) reader.ptr; + + dx = cur_pt->x - prev_pt->x; + dy = cur_pt->y - prev_pt->y; + dxdy0 = dx * dy0; + dydx0 = dy * dx0; + + /* find orientation */ + /*orient = -dy0 * dx + dx0 * dy; + orientation |= (orient > 0) ? 1 : 2; + */ + orientation |= (dydx0 > dxdy0) ? 1 : ((dydx0 < dxdy0) ? 2 : 3); + + if( orientation == 3 ) + { + flag = 0; + break; + } + + dx0 = dx; + dy0 = dy; + } + } + else + { + CV_Assert( CV_SEQ_ELTYPE(contour) == CV_32FC2 ); + + CvPoint2D32f *prev_pt = (CvPoint2D32f*)reader.prev_elem; + CvPoint2D32f *cur_pt = (CvPoint2D32f*)reader.ptr; + + float dx0 = cur_pt->x - prev_pt->x; + float dy0 = cur_pt->y - prev_pt->y; + + for( i = 0; i < contour->total; i++ ) + { + float dxdy0, dydx0; + float dx, dy; + + /*int orient; */ + CV_NEXT_SEQ_ELEM( sizeof(CvPoint2D32f), reader ); + prev_pt = cur_pt; + cur_pt = (CvPoint2D32f*) reader.ptr; + + dx = cur_pt->x - prev_pt->x; + dy = cur_pt->y - prev_pt->y; + dxdy0 = dx * dy0; + dydx0 = dy * dx0; + + /* find orientation */ + /*orient = -dy0 * dx + dx0 * dy; + orientation |= (orient > 0) ? 1 : 2; + */ + orientation |= (dydx0 > dxdy0) ? 1 : ((dydx0 < dxdy0) ? 2 : 3); + + if( orientation == 3 ) + { + flag = 0; + break; + } + + dx0 = dx; + dy0 = dy; + } + } + + return flag; +} + + +/* End of file. */ diff --git a/imgproc/src/corner.cpp b/imgproc/src/corner.cpp new file mode 100644 index 0000000..a66459a --- /dev/null +++ b/imgproc/src/corner.cpp @@ -0,0 +1,422 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include + + +namespace cv +{ + +static void +calcMinEigenVal( const Mat& _cov, Mat& _dst ) +{ + int i, j; + Size size = _cov.size(); +#if CV_SSE + volatile bool simd = checkHardwareSupport(CV_CPU_SSE); +#endif + + if( _cov.isContinuous() && _dst.isContinuous() ) + { + size.width *= size.height; + size.height = 1; + } + + for( i = 0; i < size.height; i++ ) + { + const float* cov = (const float*)(_cov.data + _cov.step*i); + float* dst = (float*)(_dst.data + _dst.step*i); + j = 0; + #if CV_SSE + if( simd ) + { + __m128 half = _mm_set1_ps(0.5f); + for( ; j <= size.width - 5; j += 4 ) + { + __m128 t0 = _mm_loadu_ps(cov + j*3); // a0 b0 c0 x + __m128 t1 = _mm_loadu_ps(cov + j*3 + 3); // a1 b1 c1 x + __m128 t2 = _mm_loadu_ps(cov + j*3 + 6); // a2 b2 c2 x + __m128 t3 = _mm_loadu_ps(cov + j*3 + 9); // a3 b3 c3 x + __m128 a, b, c, t; + t = _mm_unpacklo_ps(t0, t1); // a0 a1 b0 b1 + c = _mm_unpackhi_ps(t0, t1); // c0 c1 x x + b = _mm_unpacklo_ps(t2, t3); // a2 a3 b2 b3 + c = _mm_movelh_ps(c, _mm_unpackhi_ps(t2, t3)); // c0 c1 c2 c3 + a = _mm_movelh_ps(t, b); + b = _mm_movehl_ps(b, t); + a = _mm_mul_ps(a, half); + c = _mm_mul_ps(c, half); + t = _mm_sub_ps(a, c); + t = _mm_add_ps(_mm_mul_ps(t, t), _mm_mul_ps(b,b)); + a = _mm_sub_ps(_mm_add_ps(a, c), _mm_sqrt_ps(t)); + _mm_storeu_ps(dst + j, a); + } + } + #endif + for( ; j < size.width; j++ ) + { + float a = cov[j*3]*0.5f; + float b = cov[j*3+1]; + float c = cov[j*3+2]*0.5f; + dst[j] = (float)((a + c) - std::sqrt((a - c)*(a - c) + b*b)); + } + } +} + + +static void +calcHarris( const Mat& _cov, Mat& _dst, double k ) +{ + int i, j; + Size size = _cov.size(); +#if CV_SSE + volatile bool simd = checkHardwareSupport(CV_CPU_SSE); +#endif + + if( _cov.isContinuous() && _dst.isContinuous() ) + { + size.width *= size.height; + size.height = 1; + } + + for( i = 0; i < size.height; i++ ) + { + const float* cov = (const float*)(_cov.data + _cov.step*i); + float* dst = (float*)(_dst.data + _dst.step*i); + j = 0; + + #if CV_SSE + if( simd ) + { + __m128 k4 = _mm_set1_ps((float)k); + for( ; j <= size.width - 5; j += 4 ) + { + __m128 t0 = _mm_loadu_ps(cov + j*3); // a0 b0 c0 x + __m128 t1 = _mm_loadu_ps(cov + j*3 + 3); // a1 b1 c1 x + __m128 t2 = _mm_loadu_ps(cov + j*3 + 6); // a2 b2 c2 x + __m128 t3 = _mm_loadu_ps(cov + j*3 + 9); // a3 b3 c3 x + __m128 a, b, c, t; + t = _mm_unpacklo_ps(t0, t1); // a0 a1 b0 b1 + c = _mm_unpackhi_ps(t0, t1); // c0 c1 x x + b = _mm_unpacklo_ps(t2, t3); // a2 a3 b2 b3 + c = _mm_movelh_ps(c, _mm_unpackhi_ps(t2, t3)); // c0 c1 c2 c3 + a = _mm_movelh_ps(t, b); + b = _mm_movehl_ps(b, t); + t = _mm_add_ps(a, c); + a = _mm_sub_ps(_mm_mul_ps(a, c), _mm_mul_ps(b, b)); + t = _mm_mul_ps(_mm_mul_ps(k4, t), t); + a = _mm_sub_ps(a, t); + _mm_storeu_ps(dst + j, a); + } + } + #endif + + for( ; j < size.width; j++ ) + { + float a = cov[j*3]; + float b = cov[j*3+1]; + float c = cov[j*3+2]; + dst[j] = (float)(a*c - b*b - k*(a + c)*(a + c)); + } + } +} + + +void eigen2x2( const float* cov, float* dst, int n ) +{ + for( int j = 0; j < n; j++ ) + { + double a = cov[j*3]; + double b = cov[j*3+1]; + double c = cov[j*3+2]; + + double u = (a + c)*0.5; + double v = std::sqrt((a - c)*(a - c)*0.25 + b*b); + double l1 = u + v; + double l2 = u - v; + + double x = b; + double y = l1 - a; + double e = fabs(x); + + if( e + fabs(y) < 1e-4 ) + { + y = b; + x = l1 - c; + e = fabs(x); + if( e + fabs(y) < 1e-4 ) + { + e = 1./(e + fabs(y) + FLT_EPSILON); + x *= e, y *= e; + } + } + + double d = 1./std::sqrt(x*x + y*y + DBL_EPSILON); + dst[6*j] = (float)l1; + dst[6*j + 2] = (float)(x*d); + dst[6*j + 3] = (float)(y*d); + + x = b; + y = l2 - a; + e = fabs(x); + + if( e + fabs(y) < 1e-4 ) + { + y = b; + x = l2 - c; + e = fabs(x); + if( e + fabs(y) < 1e-4 ) + { + e = 1./(e + fabs(y) + FLT_EPSILON); + x *= e, y *= e; + } + } + + d = 1./std::sqrt(x*x + y*y + DBL_EPSILON); + dst[6*j + 1] = (float)l2; + dst[6*j + 4] = (float)(x*d); + dst[6*j + 5] = (float)(y*d); + } +} + +static void +calcEigenValsVecs( const Mat& _cov, Mat& _dst ) +{ + Size size = _cov.size(); + if( _cov.isContinuous() && _dst.isContinuous() ) + { + size.width *= size.height; + size.height = 1; + } + + for( int i = 0; i < size.height; i++ ) + { + const float* cov = (const float*)(_cov.data + _cov.step*i); + float* dst = (float*)(_dst.data + _dst.step*i); + + eigen2x2(cov, dst, size.width); + } +} + + +enum { MINEIGENVAL=0, HARRIS=1, EIGENVALSVECS=2 }; + + +static void +cornerEigenValsVecs( const Mat& src, Mat& eigenv, int block_size, + int aperture_size, int op_type, double k=0., + int borderType=BORDER_DEFAULT ) +{ +#ifdef HAVE_TEGRA_OPTIMIZATION + if (tegra::cornerEigenValsVecs(src, eigenv, block_size, aperture_size, op_type, k, borderType)) + return; +#endif + + int depth = src.depth(); + double scale = (double)(1 << ((aperture_size > 0 ? aperture_size : 3) - 1)) * block_size; + if( aperture_size < 0 ) + scale *= 2.; + if( depth == CV_8U ) + scale *= 255.; + scale = 1./scale; + + CV_Assert( src.type() == CV_8UC1 || src.type() == CV_32FC1 ); + + Mat Dx, Dy; + if( aperture_size > 0 ) + { + Sobel( src, Dx, CV_32F, 1, 0, aperture_size, scale, 0, borderType ); + Sobel( src, Dy, CV_32F, 0, 1, aperture_size, scale, 0, borderType ); + } + else + { + Scharr( src, Dx, CV_32F, 1, 0, scale, 0, borderType ); + Scharr( src, Dy, CV_32F, 0, 1, scale, 0, borderType ); + } + + Size size = src.size(); + Mat cov( size, CV_32FC3 ); + int i, j; + + for( i = 0; i < size.height; i++ ) + { + float* cov_data = (float*)(cov.data + i*cov.step); + const float* dxdata = (const float*)(Dx.data + i*Dx.step); + const float* dydata = (const float*)(Dy.data + i*Dy.step); + + for( j = 0; j < size.width; j++ ) + { + float dx = dxdata[j]; + float dy = dydata[j]; + + cov_data[j*3] = dx*dx; + cov_data[j*3+1] = dx*dy; + cov_data[j*3+2] = dy*dy; + } + } + + boxFilter(cov, cov, cov.depth(), Size(block_size, block_size), + Point(-1,-1), false, borderType ); + + if( op_type == MINEIGENVAL ) + calcMinEigenVal( cov, eigenv ); + else if( op_type == HARRIS ) + calcHarris( cov, eigenv, k ); + else if( op_type == EIGENVALSVECS ) + calcEigenValsVecs( cov, eigenv ); +} + +} + +void cv::cornerMinEigenVal( InputArray _src, OutputArray _dst, int blockSize, int ksize, int borderType ) +{ + Mat src = _src.getMat(); + _dst.create( src.size(), CV_32F ); + Mat dst = _dst.getMat(); + cornerEigenValsVecs( src, dst, blockSize, ksize, MINEIGENVAL, 0, borderType ); +} + + +void cv::cornerHarris( InputArray _src, OutputArray _dst, int blockSize, int ksize, double k, int borderType ) +{ + Mat src = _src.getMat(); + _dst.create( src.size(), CV_32F ); + Mat dst = _dst.getMat(); + cornerEigenValsVecs( src, dst, blockSize, ksize, HARRIS, k, borderType ); +} + + +void cv::cornerEigenValsAndVecs( InputArray _src, OutputArray _dst, int blockSize, int ksize, int borderType ) +{ + Mat src = _src.getMat(); + Size dsz = _dst.size(); + int dtype = _dst.type(); + + if( dsz.height != src.rows || dsz.width*CV_MAT_CN(dtype) != src.cols*6 || CV_MAT_DEPTH(dtype) != CV_32F ) + _dst.create( src.size(), CV_32FC(6) ); + Mat dst = _dst.getMat(); + cornerEigenValsVecs( src, dst, blockSize, ksize, EIGENVALSVECS, 0, borderType ); +} + + +void cv::preCornerDetect( InputArray _src, OutputArray _dst, int ksize, int borderType ) +{ + Mat Dx, Dy, D2x, D2y, Dxy, src = _src.getMat(); + + CV_Assert( src.type() == CV_8UC1 || src.type() == CV_32FC1 ); + _dst.create( src.size(), CV_32F ); + Mat dst = _dst.getMat(); + + Sobel( src, Dx, CV_32F, 1, 0, ksize, 1, 0, borderType ); + Sobel( src, Dy, CV_32F, 0, 1, ksize, 1, 0, borderType ); + Sobel( src, D2x, CV_32F, 2, 0, ksize, 1, 0, borderType ); + Sobel( src, D2y, CV_32F, 0, 2, ksize, 1, 0, borderType ); + Sobel( src, Dxy, CV_32F, 1, 1, ksize, 1, 0, borderType ); + + double factor = 1 << (ksize - 1); + if( src.depth() == CV_8U ) + factor *= 255; + factor = 1./(factor * factor * factor); + + Size size = src.size(); + int i, j; + for( i = 0; i < size.height; i++ ) + { + float* dstdata = (float*)(dst.data + i*dst.step); + const float* dxdata = (const float*)(Dx.data + i*Dx.step); + const float* dydata = (const float*)(Dy.data + i*Dy.step); + const float* d2xdata = (const float*)(D2x.data + i*D2x.step); + const float* d2ydata = (const float*)(D2y.data + i*D2y.step); + const float* dxydata = (const float*)(Dxy.data + i*Dxy.step); + + for( j = 0; j < size.width; j++ ) + { + float dx = dxdata[j]; + float dy = dydata[j]; + dstdata[j] = (float)(factor*(dx*dx*d2ydata[j] + dy*dy*d2xdata[j] - 2*dx*dy*dxydata[j])); + } + } +} + +CV_IMPL void +cvCornerMinEigenVal( const CvArr* srcarr, CvArr* dstarr, + int block_size, int aperture_size ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + CV_Assert( src.size() == dst.size() && dst.type() == CV_32FC1 ); + cv::cornerMinEigenVal( src, dst, block_size, aperture_size, cv::BORDER_REPLICATE ); +} + +CV_IMPL void +cvCornerHarris( const CvArr* srcarr, CvArr* dstarr, + int block_size, int aperture_size, double k ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + CV_Assert( src.size() == dst.size() && dst.type() == CV_32FC1 ); + cv::cornerHarris( src, dst, block_size, aperture_size, k, cv::BORDER_REPLICATE ); +} + + +CV_IMPL void +cvCornerEigenValsAndVecs( const void* srcarr, void* dstarr, + int block_size, int aperture_size ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + CV_Assert( src.rows == dst.rows && src.cols*6 == dst.cols*dst.channels() && dst.depth() == CV_32F ); + cv::cornerEigenValsAndVecs( src, dst, block_size, aperture_size, cv::BORDER_REPLICATE ); +} + + +CV_IMPL void +cvPreCornerDetect( const void* srcarr, void* dstarr, int aperture_size ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + CV_Assert( src.size() == dst.size() && dst.type() == CV_32FC1 ); + cv::preCornerDetect( src, dst, aperture_size, cv::BORDER_REPLICATE ); +} + +/* End of file */ diff --git a/imgproc/src/cornersubpix.cpp b/imgproc/src/cornersubpix.cpp new file mode 100644 index 0000000..83a5bdb --- /dev/null +++ b/imgproc/src/cornersubpix.cpp @@ -0,0 +1,271 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +CV_IMPL void +cvFindCornerSubPix( const void* srcarr, CvPoint2D32f* corners, + int count, CvSize win, CvSize zeroZone, + CvTermCriteria criteria ) +{ + cv::AutoBuffer buffer; + + const int MAX_ITERS = 100; + const float drv_x[] = { -1.f, 0.f, 1.f }; + const float drv_y[] = { 0.f, 0.5f, 0.f }; + float *maskX; + float *maskY; + float *mask; + float *src_buffer; + float *gx_buffer; + float *gy_buffer; + int win_w = win.width * 2 + 1, win_h = win.height * 2 + 1; + int win_rect_size = (win_w + 4) * (win_h + 4); + double coeff; + CvSize size, src_buf_size; + int i, j, k, pt_i; + int max_iters = 10; + double eps = 0; + + CvMat stub, *src = (CvMat*)srcarr; + src = cvGetMat( srcarr, &stub ); + + if( CV_MAT_TYPE( src->type ) != CV_8UC1 ) + CV_Error( CV_StsUnsupportedFormat, "The source image must be 8-bit single-channel (CV_8UC1)" ); + + if( !corners ) + CV_Error( CV_StsNullPtr, "" ); + + if( count < 0 ) + CV_Error( CV_StsBadSize, "" ); + + if( count == 0 ) + return; + + if( win.width <= 0 || win.height <= 0 ) + CV_Error( CV_StsBadSize, "" ); + + size = cvGetMatSize( src ); + + if( size.width < win_w + 4 || size.height < win_h + 4 ) + CV_Error( CV_StsBadSize, "" ); + + /* initialize variables, controlling loop termination */ + switch( criteria.type ) + { + case CV_TERMCRIT_ITER: + eps = 0.f; + max_iters = criteria.max_iter; + break; + case CV_TERMCRIT_EPS: + eps = criteria.epsilon; + max_iters = MAX_ITERS; + break; + case CV_TERMCRIT_ITER | CV_TERMCRIT_EPS: + eps = criteria.epsilon; + max_iters = criteria.max_iter; + break; + default: + assert( 0 ); + CV_Error( CV_StsBadFlag, "" ); + } + + eps = MAX( eps, 0 ); + eps *= eps; /* use square of error in comparsion operations. */ + + max_iters = MAX( max_iters, 1 ); + max_iters = MIN( max_iters, MAX_ITERS ); + + buffer.allocate( win_rect_size * 5 + win_w + win_h + 32 ); + + /* assign pointers */ + maskX = buffer; + maskY = maskX + win_w + 4; + mask = maskY + win_h + 4; + src_buffer = mask + win_w * win_h; + gx_buffer = src_buffer + win_rect_size; + gy_buffer = gx_buffer + win_rect_size; + + coeff = 1. / (win.width * win.width); + + /* calculate mask */ + for( i = -win.width, k = 0; i <= win.width; i++, k++ ) + { + maskX[k] = (float)exp( -i * i * coeff ); + } + + if( win.width == win.height ) + { + maskY = maskX; + } + else + { + coeff = 1. / (win.height * win.height); + for( i = -win.height, k = 0; i <= win.height; i++, k++ ) + { + maskY[k] = (float) exp( -i * i * coeff ); + } + } + + for( i = 0; i < win_h; i++ ) + { + for( j = 0; j < win_w; j++ ) + { + mask[i * win_w + j] = maskX[j] * maskY[i]; + } + } + + + /* make zero_zone */ + if( zeroZone.width >= 0 && zeroZone.height >= 0 && + zeroZone.width * 2 + 1 < win_w && zeroZone.height * 2 + 1 < win_h ) + { + for( i = win.height - zeroZone.height; i <= win.height + zeroZone.height; i++ ) + { + for( j = win.width - zeroZone.width; j <= win.width + zeroZone.width; j++ ) + { + mask[i * win_w + j] = 0; + } + } + } + + /* set sizes of image rectangles, used in convolutions */ + src_buf_size.width = win_w + 2; + src_buf_size.height = win_h + 2; + + /* do optimization loop for all the points */ + for( pt_i = 0; pt_i < count; pt_i++ ) + { + CvPoint2D32f cT = corners[pt_i], cI = cT; + int iter = 0; + double err; + + do + { + CvPoint2D32f cI2; + double a, b, c, bb1, bb2; + + IPPI_CALL( icvGetRectSubPix_8u32f_C1R( (uchar*)src->data.ptr, src->step, size, + src_buffer, (win_w + 2) * sizeof( src_buffer[0] ), + cvSize( win_w + 2, win_h + 2 ), cI )); + + /* calc derivatives */ + icvSepConvSmall3_32f( src_buffer, src_buf_size.width * sizeof(src_buffer[0]), + gx_buffer, win_w * sizeof(gx_buffer[0]), + src_buf_size, drv_x, drv_y, buffer ); + + icvSepConvSmall3_32f( src_buffer, src_buf_size.width * sizeof(src_buffer[0]), + gy_buffer, win_w * sizeof(gy_buffer[0]), + src_buf_size, drv_y, drv_x, buffer ); + + a = b = c = bb1 = bb2 = 0; + + /* process gradient */ + for( i = 0, k = 0; i < win_h; i++ ) + { + double py = i - win.height; + + for( j = 0; j < win_w; j++, k++ ) + { + double m = mask[k]; + double tgx = gx_buffer[k]; + double tgy = gy_buffer[k]; + double gxx = tgx * tgx * m; + double gxy = tgx * tgy * m; + double gyy = tgy * tgy * m; + double px = j - win.width; + + a += gxx; + b += gxy; + c += gyy; + + bb1 += gxx * px + gxy * py; + bb2 += gxy * px + gyy * py; + } + } + + { + double A[4]; + double InvA[4]; + CvMat matA, matInvA; + + A[0] = a; + A[1] = A[2] = b; + A[3] = c; + + cvInitMatHeader( &matA, 2, 2, CV_64F, A ); + cvInitMatHeader( &matInvA, 2, 2, CV_64FC1, InvA ); + + cvInvert( &matA, &matInvA, CV_SVD ); + cI2.x = (float)(cI.x + InvA[0]*bb1 + InvA[1]*bb2); + cI2.y = (float)(cI.y + InvA[2]*bb1 + InvA[3]*bb2); + } + + err = (cI2.x - cI.x) * (cI2.x - cI.x) + (cI2.y - cI.y) * (cI2.y - cI.y); + cI = cI2; + } + while( ++iter < max_iters && err > eps ); + + /* if new point is too far from initial, it means poor convergence. + leave initial point as the result */ + if( fabs( cI.x - cT.x ) > win.width || fabs( cI.y - cT.y ) > win.height ) + { + cI = cT; + } + + corners[pt_i] = cI; /* store result */ + } +} + +void cv::cornerSubPix( InputArray _image, InputOutputArray _corners, + Size winSize, Size zeroZone, + TermCriteria criteria ) +{ + Mat corners = _corners.getMat(); + int ncorners = corners.checkVector(2); + CV_Assert( ncorners >= 0 && corners.depth() == CV_32F ); + Mat image = _image.getMat(); + CvMat c_image = image; + + cvFindCornerSubPix( &c_image, (CvPoint2D32f*)corners.data, ncorners, + winSize, zeroZone, criteria ); +} + +/* End of file. */ diff --git a/imgproc/src/deriv.cpp b/imgproc/src/deriv.cpp new file mode 100644 index 0000000..94f2e67 --- /dev/null +++ b/imgproc/src/deriv.cpp @@ -0,0 +1,653 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) +static IppStatus sts = ippInit(); +#endif +/****************************************************************************************/ + +/* lightweight convolution with 3x3 kernel */ +void icvSepConvSmall3_32f( float* src, int src_step, float* dst, int dst_step, + CvSize src_size, const float* kx, const float* ky, float* buffer ) +{ + int dst_width, buffer_step = 0; + int x, y; + + assert( src && dst && src_size.width > 2 && src_size.height > 2 && + (src_step & 3) == 0 && (dst_step & 3) == 0 && + (kx || ky) && (buffer || !kx || !ky)); + + src_step /= sizeof(src[0]); + dst_step /= sizeof(dst[0]); + + dst_width = src_size.width - 2; + + if( !kx ) + { + /* set vars, so that vertical convolution + will write results into destination ROI and + horizontal convolution won't run */ + src_size.width = dst_width; + buffer_step = dst_step; + buffer = dst; + dst_width = 0; + } + + assert( src_step >= src_size.width && dst_step >= dst_width ); + + src_size.height -= 3; + if( !ky ) + { + /* set vars, so that vertical convolution won't run and + horizontal convolution will write results into destination ROI */ + src_size.height += 3; + buffer_step = src_step; + buffer = src; + src_size.width = 0; + } + + for( y = 0; y <= src_size.height; y++, src += src_step, + dst += dst_step, + buffer += buffer_step ) + { + float* src2 = src + src_step; + float* src3 = src + src_step*2; + for( x = 0; x < src_size.width; x++ ) + { + buffer[x] = (float)(ky[0]*src[x] + ky[1]*src2[x] + ky[2]*src3[x]); + } + + for( x = 0; x < dst_width; x++ ) + { + dst[x] = (float)(kx[0]*buffer[x] + kx[1]*buffer[x+1] + kx[2]*buffer[x+2]); + } + } +} + + +/****************************************************************************************\ + Sobel & Scharr Derivative Filters +\****************************************************************************************/ + +namespace cv +{ + +static void getScharrKernels( OutputArray _kx, OutputArray _ky, + int dx, int dy, bool normalize, int ktype ) +{ + const int ksize = 3; + + CV_Assert( ktype == CV_32F || ktype == CV_64F ); + _kx.create(ksize, 1, ktype, -1, true); + _ky.create(ksize, 1, ktype, -1, true); + Mat kx = _kx.getMat(); + Mat ky = _ky.getMat(); + + CV_Assert( dx >= 0 && dy >= 0 && dx+dy == 1 ); + + for( int k = 0; k < 2; k++ ) + { + Mat* kernel = k == 0 ? &kx : &ky; + int order = k == 0 ? dx : dy; + int kerI[3]; + + if( order == 0 ) + kerI[0] = 3, kerI[1] = 10, kerI[2] = 3; + else if( order == 1 ) + kerI[0] = -1, kerI[1] = 0, kerI[2] = 1; + + Mat temp(kernel->rows, kernel->cols, CV_32S, &kerI[0]); + double scale = !normalize || order == 1 ? 1. : 1./32; + temp.convertTo(*kernel, ktype, scale); + } +} + + +static void getSobelKernels( OutputArray _kx, OutputArray _ky, + int dx, int dy, int _ksize, bool normalize, int ktype ) +{ + int i, j, ksizeX = _ksize, ksizeY = _ksize; + if( ksizeX == 1 && dx > 0 ) + ksizeX = 3; + if( ksizeY == 1 && dy > 0 ) + ksizeY = 3; + + CV_Assert( ktype == CV_32F || ktype == CV_64F ); + + _kx.create(ksizeX, 1, ktype, -1, true); + _ky.create(ksizeY, 1, ktype, -1, true); + Mat kx = _kx.getMat(); + Mat ky = _ky.getMat(); + + if( _ksize % 2 == 0 || _ksize > 31 ) + CV_Error( CV_StsOutOfRange, "The kernel size must be odd and not larger than 31" ); + vector kerI(std::max(ksizeX, ksizeY) + 1); + + CV_Assert( dx >= 0 && dy >= 0 && dx+dy > 0 ); + + for( int k = 0; k < 2; k++ ) + { + Mat* kernel = k == 0 ? &kx : &ky; + int order = k == 0 ? dx : dy; + int ksize = k == 0 ? ksizeX : ksizeY; + + CV_Assert( ksize > order ); + + if( ksize == 1 ) + kerI[0] = 1; + else if( ksize == 3 ) + { + if( order == 0 ) + kerI[0] = 1, kerI[1] = 2, kerI[2] = 1; + else if( order == 1 ) + kerI[0] = -1, kerI[1] = 0, kerI[2] = 1; + else + kerI[0] = 1, kerI[1] = -2, kerI[2] = 1; + } + else + { + int oldval, newval; + kerI[0] = 1; + for( i = 0; i < ksize; i++ ) + kerI[i+1] = 0; + + for( i = 0; i < ksize - order - 1; i++ ) + { + oldval = kerI[0]; + for( j = 1; j <= ksize; j++ ) + { + newval = kerI[j]+kerI[j-1]; + kerI[j-1] = oldval; + oldval = newval; + } + } + + for( i = 0; i < order; i++ ) + { + oldval = -kerI[0]; + for( j = 1; j <= ksize; j++ ) + { + newval = kerI[j-1] - kerI[j]; + kerI[j-1] = oldval; + oldval = newval; + } + } + } + + Mat temp(kernel->rows, kernel->cols, CV_32S, &kerI[0]); + double scale = !normalize ? 1. : 1./(1 << (ksize-order-1)); + temp.convertTo(*kernel, ktype, scale); + } +} + +} + +void cv::getDerivKernels( OutputArray kx, OutputArray ky, int dx, int dy, + int ksize, bool normalize, int ktype ) +{ + if( ksize <= 0 ) + getScharrKernels( kx, ky, dx, dy, normalize, ktype ); + else + getSobelKernels( kx, ky, dx, dy, ksize, normalize, ktype ); +} + + +cv::Ptr cv::createDerivFilter(int srcType, int dstType, + int dx, int dy, int ksize, int borderType ) +{ + Mat kx, ky; + getDerivKernels( kx, ky, dx, dy, ksize, false, CV_32F ); + return createSeparableLinearFilter(srcType, dstType, + kx, ky, Point(-1,-1), 0, borderType ); +} + +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) + +namespace cv +{ + +static bool IPPDerivScharr(const Mat& src, Mat& dst, int ddepth, int dx, int dy, double scale) +{ + int bufSize = 0; + cv::AutoBuffer buffer; + IppiSize roi = ippiSize(src.cols, src.rows); + + if( ddepth < 0 ) + ddepth = src.depth(); + + dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) ); + + switch(src.type()) + { + case CV_8U: + { + if(scale != 1) + return false; + + switch(dst.type()) + { + case CV_16S: + { + if((dx == 1) && (dy == 0)) + { + ippiFilterScharrVertGetBufferSize_8u16s_C1R(roi,&bufSize); + buffer.allocate(bufSize); + + ippiFilterScharrVertBorder_8u16s_C1R((const Ipp8u*)src.data, src.step, + (Ipp16s*)dst.data, dst.step, roi, ippBorderRepl, 0, (Ipp8u*)(char*)buffer); + + return true; + } + + if((dx == 0) && (dy == 1)) + { + ippiFilterScharrHorizGetBufferSize_8u16s_C1R(roi,&bufSize); + buffer.allocate(bufSize); + + ippiFilterScharrHorizBorder_8u16s_C1R((const Ipp8u*)src.data, src.step, + (Ipp16s*)dst.data, dst.step, roi, ippBorderRepl, 0, (Ipp8u*)(char*)buffer); + + return true; + } + } + + default: + return false; + } + } + + case CV_32F: + { + switch(dst.type()) + { + case CV_32F: + if((dx == 1) && (dy == 0)) + { + ippiFilterScharrVertGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows),&bufSize); + buffer.allocate(bufSize); + + ippiFilterScharrVertBorder_32f_C1R((const Ipp32f*)src.data, src.step, + (Ipp32f*)dst.data, dst.step, ippiSize(src.cols, src.rows), + ippBorderRepl, 0, (Ipp8u*)(char*)buffer); + if(scale != 1) + /* IPP is fast, so MulC produce very little perf degradation */ + ippiMulC_32f_C1IR((Ipp32f)scale,(Ipp32f*)dst.data,dst.step,ippiSize(dst.cols*dst.channels(),dst.rows)); + + return true; + } + + if((dx == 0) && (dy == 1)) + { + ippiFilterScharrHorizGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows),&bufSize); + buffer.allocate(bufSize); + + ippiFilterScharrHorizBorder_32f_C1R((const Ipp32f*)src.data, src.step, + (Ipp32f*)dst.data, dst.step, ippiSize(src.cols, src.rows), + ippBorderRepl, 0, (Ipp8u*)(char*)buffer); + if(scale != 1) + ippiMulC_32f_C1IR((Ipp32f)scale,(Ipp32f *)dst.data,dst.step,ippiSize(dst.cols*dst.channels(),dst.rows)); + + return true; + } + + default: + return false; + } + } + + default: + return false; + } +} + + +static bool IPPDeriv(const Mat& src, Mat& dst, int ddepth, int dx, int dy, int ksize, double scale) +{ + int bufSize = 0; + cv::AutoBuffer buffer; + + if(ksize == 3 || ksize == 5) + { + if( ddepth < 0 ) + ddepth = src.depth(); + + if(src.type() == CV_8U && dst.type() == CV_16S && scale == 1) + { + if((dx == 1) && (dy == 0)) + { + ippiFilterSobelNegVertGetBufferSize_8u16s_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize); + buffer.allocate(bufSize); + + ippiFilterSobelNegVertBorder_8u16s_C1R((const Ipp8u*)src.data, src.step, + (Ipp16s*)dst.data, dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize), + ippBorderRepl, 0, (Ipp8u*)(char*)buffer); + return true; + } + + if((dx == 0) && (dy == 1)) + { + ippiFilterSobelHorizGetBufferSize_8u16s_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize); + buffer.allocate(bufSize); + + ippiFilterSobelHorizBorder_8u16s_C1R((const Ipp8u*)src.data, src.step, + (Ipp16s*)dst.data, dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize), + ippBorderRepl, 0, (Ipp8u*)(char*)buffer); + + return true; + } + + if((dx == 2) && (dy == 0)) + { + ippiFilterSobelVertSecondGetBufferSize_8u16s_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize); + buffer.allocate(bufSize); + + ippiFilterSobelVertSecondBorder_8u16s_C1R((const Ipp8u*)src.data, src.step, + (Ipp16s*)dst.data, dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize), + ippBorderRepl, 0, (Ipp8u*)(char*)buffer); + + return true; + } + + if((dx == 0) && (dy == 2)) + { + ippiFilterSobelHorizSecondGetBufferSize_8u16s_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize); + buffer.allocate(bufSize); + + ippiFilterSobelHorizSecondBorder_8u16s_C1R((const Ipp8u*)src.data, src.step, + (Ipp16s*)dst.data, dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize), + ippBorderRepl, 0, (Ipp8u*)(char*)buffer); + + return true; + } + } + + if(src.type() == CV_32F && dst.type() == CV_32F) + { + if((dx == 1) && (dy == 0)) + { + ippiFilterSobelNegVertGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize); + buffer.allocate(bufSize); + + ippiFilterSobelNegVertBorder_32f_C1R((const Ipp32f*)src.data, src.step, + (Ipp32f*)dst.data, dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize), + ippBorderRepl, 0, (Ipp8u*)(char*)buffer); + if(scale != 1) + ippiMulC_32f_C1IR((Ipp32f)scale,(Ipp32f *)dst.data,dst.step,ippiSize(dst.cols*dst.channels(),dst.rows)); + + return true; + } + + if((dx == 0) && (dy == 1)) + { + ippiFilterSobelHorizGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize); + buffer.allocate(bufSize); + + ippiFilterSobelHorizBorder_32f_C1R((const Ipp32f*)src.data, src.step, + (Ipp32f*)dst.data, dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize), + ippBorderRepl, 0, (Ipp8u*)(char*)buffer); + if(scale != 1) + ippiMulC_32f_C1IR((Ipp32f)scale,(Ipp32f *)dst.data,dst.step,ippiSize(dst.cols*dst.channels(),dst.rows)); + + return true; + } + + if((dx == 2) && (dy == 0)) + { + ippiFilterSobelVertSecondGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize); + buffer.allocate(bufSize); + + ippiFilterSobelVertSecondBorder_32f_C1R((const Ipp32f*)src.data, src.step, + (Ipp32f*)dst.data, dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize), + ippBorderRepl, 0, (Ipp8u*)(char*)buffer); + if(scale != 1) + ippiMulC_32f_C1IR((Ipp32f)scale,(Ipp32f *)dst.data,dst.step,ippiSize(dst.cols*dst.channels(),dst.rows)); + + return true; + } + + if((dx == 0) && (dy == 2)) + { + ippiFilterSobelHorizSecondGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize); + buffer.allocate(bufSize); + + ippiFilterSobelHorizSecondBorder_32f_C1R((const Ipp32f*)src.data, src.step, + (Ipp32f*)dst.data, dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize), + ippBorderRepl, 0, (Ipp8u*)(char*)buffer); + if(scale != 1) + ippiMulC_32f_C1IR((Ipp32f)scale,(Ipp32f *)dst.data,dst.step,ippiSize(dst.cols*dst.channels(),dst.rows)); + + return true; + } + } + } + + if(ksize <= 0) + return IPPDerivScharr(src, dst, ddepth, dx, dy, scale); + + return false; +} + +} + +#endif + +void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, + int ksize, double scale, double delta, int borderType ) +{ + Mat src = _src.getMat(); + if (ddepth < 0) + ddepth = src.depth(); + _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) ); + Mat dst = _dst.getMat(); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if (scale == 1.0 && delta == 0) + { + if (ksize == 3 && tegra::sobel3x3(src, dst, dx, dy, borderType)) + return; + if (ksize == -1 && tegra::scharr(src, dst, dx, dy, borderType)) + return; + } +#endif + +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) + if(dx < 3 && dy < 3 && src.channels() == 1 && borderType == 1) + { + if(IPPDeriv(src, dst, ddepth, dx, dy, ksize,scale)) + return; + } +#endif + int ktype = std::max(CV_32F, std::max(ddepth, src.depth())); + + Mat kx, ky; + getDerivKernels( kx, ky, dx, dy, ksize, false, ktype ); + if( scale != 1 ) + { + // usually the smoothing part is the slowest to compute, + // so try to scale it instead of the faster differenciating part + if( dx == 0 ) + kx *= scale; + else + ky *= scale; + } + sepFilter2D( src, dst, ddepth, kx, ky, Point(-1,-1), delta, borderType ); +} + + +void cv::Scharr( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, + double scale, double delta, int borderType ) +{ + Mat src = _src.getMat(); + if (ddepth < 0) + ddepth = src.depth(); + _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) ); + Mat dst = _dst.getMat(); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if (scale == 1.0 && delta == 0) + if (tegra::scharr(src, dst, dx, dy, borderType)) + return; +#endif + +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) + if(dx < 2 && dy < 2 && src.channels() == 1 && borderType == 1) + { + if(IPPDerivScharr(src, dst, ddepth, dx, dy, scale)) + return; + } +#endif + int ktype = std::max(CV_32F, std::max(ddepth, src.depth())); + + Mat kx, ky; + getScharrKernels( kx, ky, dx, dy, false, ktype ); + if( scale != 1 ) + { + // usually the smoothing part is the slowest to compute, + // so try to scale it instead of the faster differenciating part + if( dx == 0 ) + kx *= scale; + else + ky *= scale; + } + sepFilter2D( src, dst, ddepth, kx, ky, Point(-1,-1), delta, borderType ); +} + + +void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize, + double scale, double delta, int borderType ) +{ + Mat src = _src.getMat(); + if (ddepth < 0) + ddepth = src.depth(); + _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) ); + Mat dst = _dst.getMat(); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if (scale == 1.0 && delta == 0) + { + if (ksize == 1 && tegra::laplace1(src, dst, borderType)) + return; + if (ksize == 3 && tegra::laplace3(src, dst, borderType)) + return; + if (ksize == 5 && tegra::laplace5(src, dst, borderType)) + return; + } +#endif + + if( ksize == 1 || ksize == 3 ) + { + float K[2][9] = + {{0, 1, 0, 1, -4, 1, 0, 1, 0}, + {2, 0, 2, 0, -8, 0, 2, 0, 2}}; + Mat kernel(3, 3, CV_32F, K[ksize == 3]); + if( scale != 1 ) + kernel *= scale; + filter2D( src, dst, ddepth, kernel, Point(-1,-1), delta, borderType ); + } + else + { + const size_t STRIPE_SIZE = 1 << 14; + + int depth = src.depth(); + int ktype = std::max(CV_32F, std::max(ddepth, depth)); + int wdepth = depth == CV_8U && ksize <= 5 ? CV_16S : depth <= CV_32F ? CV_32F : CV_64F; + int wtype = CV_MAKETYPE(wdepth, src.channels()); + Mat kd, ks; + getSobelKernels( kd, ks, 2, 0, ksize, false, ktype ); + if( ddepth < 0 ) + ddepth = src.depth(); + int dtype = CV_MAKETYPE(ddepth, src.channels()); + + int dy0 = std::min(std::max((int)(STRIPE_SIZE/(getElemSize(src.type())*src.cols)), 1), src.rows); + Ptr fx = createSeparableLinearFilter(src.type(), + wtype, kd, ks, Point(-1,-1), 0, borderType, borderType, Scalar() ); + Ptr fy = createSeparableLinearFilter(src.type(), + wtype, ks, kd, Point(-1,-1), 0, borderType, borderType, Scalar() ); + + int y = fx->start(src), dsty = 0, dy = 0; + fy->start(src); + const uchar* sptr = src.data + y*src.step; + + Mat d2x( dy0 + kd.rows - 1, src.cols, wtype ); + Mat d2y( dy0 + kd.rows - 1, src.cols, wtype ); + + for( ; dsty < src.rows; sptr += dy0*src.step, dsty += dy ) + { + fx->proceed( sptr, (int)src.step, dy0, d2x.data, (int)d2x.step ); + dy = fy->proceed( sptr, (int)src.step, dy0, d2y.data, (int)d2y.step ); + if( dy > 0 ) + { + Mat dstripe = dst.rowRange(dsty, dsty + dy); + d2x.rows = d2y.rows = dy; // modify the headers, which should work + d2x += d2y; + d2x.convertTo( dstripe, dtype, scale, delta ); + } + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +CV_IMPL void +cvSobel( const void* srcarr, void* dstarr, int dx, int dy, int aperture_size ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() ); + + cv::Sobel( src, dst, dst.depth(), dx, dy, aperture_size, 1, 0, cv::BORDER_REPLICATE ); + if( CV_IS_IMAGE(srcarr) && ((IplImage*)srcarr)->origin && dy % 2 != 0 ) + dst *= -1; +} + + +CV_IMPL void +cvLaplace( const void* srcarr, void* dstarr, int aperture_size ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() ); + + cv::Laplacian( src, dst, dst.depth(), aperture_size, 1, 0, cv::BORDER_REPLICATE ); +} + +/* End of file. */ diff --git a/imgproc/src/distransform.cpp b/imgproc/src/distransform.cpp new file mode 100644 index 0000000..80ff77b --- /dev/null +++ b/imgproc/src/distransform.cpp @@ -0,0 +1,849 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +#define ICV_DIST_SHIFT 16 +#define ICV_INIT_DIST0 (INT_MAX >> 2) + +static CvStatus +icvInitTopBottom( int* temp, int tempstep, CvSize size, int border ) +{ + int i, j; + for( i = 0; i < border; i++ ) + { + int* ttop = (int*)(temp + i*tempstep); + int* tbottom = (int*)(temp + (size.height + border*2 - i - 1)*tempstep); + + for( j = 0; j < size.width + border*2; j++ ) + { + ttop[j] = ICV_INIT_DIST0; + tbottom[j] = ICV_INIT_DIST0; + } + } + + return CV_OK; +} + + +static CvStatus CV_STDCALL +icvDistanceTransform_3x3_C1R( const uchar* src, int srcstep, int* temp, + int step, float* dist, int dststep, CvSize size, const float* metrics ) +{ + const int BORDER = 1; + int i, j; + const int HV_DIST = CV_FLT_TO_FIX( metrics[0], ICV_DIST_SHIFT ); + const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], ICV_DIST_SHIFT ); + const float scale = 1.f/(1 << ICV_DIST_SHIFT); + + srcstep /= sizeof(src[0]); + step /= sizeof(temp[0]); + dststep /= sizeof(dist[0]); + + icvInitTopBottom( temp, step, size, BORDER ); + + // forward pass + for( i = 0; i < size.height; i++ ) + { + const uchar* s = src + i*srcstep; + int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + + for( j = 0; j < BORDER; j++ ) + tmp[-j-1] = tmp[size.width + j] = ICV_INIT_DIST0; + + for( j = 0; j < size.width; j++ ) + { + if( !s[j] ) + tmp[j] = 0; + else + { + int t0 = tmp[j-step-1] + DIAG_DIST; + int t = tmp[j-step] + HV_DIST; + if( t0 > t ) t0 = t; + t = tmp[j-step+1] + DIAG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j-1] + HV_DIST; + if( t0 > t ) t0 = t; + tmp[j] = t0; + } + } + } + + // backward pass + for( i = size.height - 1; i >= 0; i-- ) + { + float* d = (float*)(dist + i*dststep); + int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + + for( j = size.width - 1; j >= 0; j-- ) + { + int t0 = tmp[j]; + if( t0 > HV_DIST ) + { + int t = tmp[j+step+1] + DIAG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j+step] + HV_DIST; + if( t0 > t ) t0 = t; + t = tmp[j+step-1] + DIAG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j+1] + HV_DIST; + if( t0 > t ) t0 = t; + tmp[j] = t0; + } + d[j] = (float)(t0 * scale); + } + } + + return CV_OK; +} + + +static CvStatus CV_STDCALL +icvDistanceTransform_5x5_C1R( const uchar* src, int srcstep, int* temp, + int step, float* dist, int dststep, CvSize size, const float* metrics ) +{ + const int BORDER = 2; + int i, j; + const int HV_DIST = CV_FLT_TO_FIX( metrics[0], ICV_DIST_SHIFT ); + const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], ICV_DIST_SHIFT ); + const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], ICV_DIST_SHIFT ); + const float scale = 1.f/(1 << ICV_DIST_SHIFT); + + srcstep /= sizeof(src[0]); + step /= sizeof(temp[0]); + dststep /= sizeof(dist[0]); + + icvInitTopBottom( temp, step, size, BORDER ); + + // forward pass + for( i = 0; i < size.height; i++ ) + { + const uchar* s = src + i*srcstep; + int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + + for( j = 0; j < BORDER; j++ ) + tmp[-j-1] = tmp[size.width + j] = ICV_INIT_DIST0; + + for( j = 0; j < size.width; j++ ) + { + if( !s[j] ) + tmp[j] = 0; + else + { + int t0 = tmp[j-step*2-1] + LONG_DIST; + int t = tmp[j-step*2+1] + LONG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j-step-2] + LONG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j-step-1] + DIAG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j-step] + HV_DIST; + if( t0 > t ) t0 = t; + t = tmp[j-step+1] + DIAG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j-step+2] + LONG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j-1] + HV_DIST; + if( t0 > t ) t0 = t; + tmp[j] = t0; + } + } + } + + // backward pass + for( i = size.height - 1; i >= 0; i-- ) + { + float* d = (float*)(dist + i*dststep); + int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + + for( j = size.width - 1; j >= 0; j-- ) + { + int t0 = tmp[j]; + if( t0 > HV_DIST ) + { + int t = tmp[j+step*2+1] + LONG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j+step*2-1] + LONG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j+step+2] + LONG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j+step+1] + DIAG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j+step] + HV_DIST; + if( t0 > t ) t0 = t; + t = tmp[j+step-1] + DIAG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j+step-2] + LONG_DIST; + if( t0 > t ) t0 = t; + t = tmp[j+1] + HV_DIST; + if( t0 > t ) t0 = t; + tmp[j] = t0; + } + d[j] = (float)(t0 * scale); + } + } + + return CV_OK; +} + + +static CvStatus CV_STDCALL +icvDistanceTransformEx_5x5_C1R( const uchar* src, int srcstep, int* temp, + int step, float* dist, int dststep, int* labels, int lstep, + CvSize size, const float* metrics ) +{ + const int BORDER = 2; + + int i, j; + const int HV_DIST = CV_FLT_TO_FIX( metrics[0], ICV_DIST_SHIFT ); + const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], ICV_DIST_SHIFT ); + const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], ICV_DIST_SHIFT ); + const float scale = 1.f/(1 << ICV_DIST_SHIFT); + + srcstep /= sizeof(src[0]); + step /= sizeof(temp[0]); + dststep /= sizeof(dist[0]); + lstep /= sizeof(labels[0]); + + icvInitTopBottom( temp, step, size, BORDER ); + + // forward pass + for( i = 0; i < size.height; i++ ) + { + const uchar* s = src + i*srcstep; + int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + int* lls = (int*)(labels + i*lstep); + + for( j = 0; j < BORDER; j++ ) + tmp[-j-1] = tmp[size.width + j] = ICV_INIT_DIST0; + + for( j = 0; j < size.width; j++ ) + { + if( !s[j] ) + { + tmp[j] = 0; + //assert( lls[j] != 0 ); + } + else + { + int t0 = ICV_INIT_DIST0, t; + int l0 = 0; + + t = tmp[j-step*2-1] + LONG_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j-lstep*2-1]; + } + t = tmp[j-step*2+1] + LONG_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j-lstep*2+1]; + } + t = tmp[j-step-2] + LONG_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j-lstep-2]; + } + t = tmp[j-step-1] + DIAG_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j-lstep-1]; + } + t = tmp[j-step] + HV_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j-lstep]; + } + t = tmp[j-step+1] + DIAG_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j-lstep+1]; + } + t = tmp[j-step+2] + LONG_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j-lstep+2]; + } + t = tmp[j-1] + HV_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j-1]; + } + + tmp[j] = t0; + lls[j] = l0; + } + } + } + + // backward pass + for( i = size.height - 1; i >= 0; i-- ) + { + float* d = (float*)(dist + i*dststep); + int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + int* lls = (int*)(labels + i*lstep); + + for( j = size.width - 1; j >= 0; j-- ) + { + int t0 = tmp[j]; + int l0 = lls[j]; + if( t0 > HV_DIST ) + { + int t = tmp[j+step*2+1] + LONG_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j+lstep*2+1]; + } + t = tmp[j+step*2-1] + LONG_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j+lstep*2-1]; + } + t = tmp[j+step+2] + LONG_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j+lstep+2]; + } + t = tmp[j+step+1] + DIAG_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j+lstep+1]; + } + t = tmp[j+step] + HV_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j+lstep]; + } + t = tmp[j+step-1] + DIAG_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j+lstep-1]; + } + t = tmp[j+step-2] + LONG_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j+lstep-2]; + } + t = tmp[j+1] + HV_DIST; + if( t0 > t ) + { + t0 = t; + l0 = lls[j+1]; + } + tmp[j] = t0; + lls[j] = l0; + } + d[j] = (float)(t0 * scale); + } + } + + return CV_OK; +} + + +static CvStatus +icvGetDistanceTransformMask( int maskType, float *metrics ) +{ + if( !metrics ) + return CV_NULLPTR_ERR; + + switch (maskType) + { + case 30: + metrics[0] = 1.0f; + metrics[1] = 1.0f; + break; + + case 31: + metrics[0] = 1.0f; + metrics[1] = 2.0f; + break; + + case 32: + metrics[0] = 0.955f; + metrics[1] = 1.3693f; + break; + + case 50: + metrics[0] = 1.0f; + metrics[1] = 1.0f; + metrics[2] = 2.0f; + break; + + case 51: + metrics[0] = 1.0f; + metrics[1] = 2.0f; + metrics[2] = 3.0f; + break; + + case 52: + metrics[0] = 1.0f; + metrics[1] = 1.4f; + metrics[2] = 2.1969f; + break; + default: + return CV_BADRANGE_ERR; + } + + return CV_OK; +} + +namespace cv +{ + +struct DTColumnInvoker +{ + DTColumnInvoker( const CvMat* _src, CvMat* _dst, const int* _sat_tab, const float* _sqr_tab) + { + src = _src; + dst = _dst; + sat_tab = _sat_tab + src->rows*2 + 1; + sqr_tab = _sqr_tab; + } + + void operator()( const BlockedRange& range ) const + { + int i, i1 = range.begin(), i2 = range.end(); + int m = src->rows; + size_t sstep = src->step, dstep = dst->step/sizeof(float); + AutoBuffer _d(m); + int* d = _d; + + for( i = i1; i < i2; i++ ) + { + const uchar* sptr = src->data.ptr + i + (m-1)*sstep; + float* dptr = dst->data.fl + i; + int j, dist = m-1; + + for( j = m-1; j >= 0; j--, sptr -= sstep ) + { + dist = (dist + 1) & (sptr[0] == 0 ? 0 : -1); + d[j] = dist; + } + + dist = m-1; + for( j = 0; j < m; j++, dptr += dstep ) + { + dist = dist + 1 - sat_tab[dist - d[j]]; + d[j] = dist; + dptr[0] = sqr_tab[dist]; + } + } + } + + const CvMat* src; + CvMat* dst; + const int* sat_tab; + const float* sqr_tab; +}; + + +struct DTRowInvoker +{ + DTRowInvoker( CvMat* _dst, const float* _sqr_tab, const float* _inv_tab ) + { + dst = _dst; + sqr_tab = _sqr_tab; + inv_tab = _inv_tab; + } + + void operator()( const BlockedRange& range ) const + { + const float inf = 1e15f; + int i, i1 = range.begin(), i2 = range.end(); + int n = dst->cols; + AutoBuffer _buf((n+2)*2*sizeof(float) + (n+2)*sizeof(int)); + float* f = (float*)(uchar*)_buf; + float* z = f + n; + int* v = alignPtr((int*)(z + n + 1), sizeof(int)); + + for( i = i1; i < i2; i++ ) + { + float* d = (float*)(dst->data.ptr + i*dst->step); + int p, q, k; + + v[0] = 0; + z[0] = -inf; + z[1] = inf; + f[0] = d[0]; + + for( q = 1, k = 0; q < n; q++ ) + { + float fq = d[q]; + f[q] = fq; + + for(;;k--) + { + p = v[k]; + float s = (fq + sqr_tab[q] - d[p] - sqr_tab[p])*inv_tab[q - p]; + if( s > z[k] ) + { + k++; + v[k] = q; + z[k] = s; + z[k+1] = inf; + break; + } + } + } + + for( q = 0, k = 0; q < n; q++ ) + { + while( z[k+1] < q ) + k++; + p = v[k]; + d[q] = std::sqrt(sqr_tab[std::abs(q - p)] + f[p]); + } + } + } + + CvMat* dst; + const float* sqr_tab; + const float* inv_tab; +}; + +} + +static void +icvTrueDistTrans( const CvMat* src, CvMat* dst ) +{ + const float inf = 1e15f; + + if( !CV_ARE_SIZES_EQ( src, dst )) + CV_Error( CV_StsUnmatchedSizes, "" ); + + if( CV_MAT_TYPE(src->type) != CV_8UC1 || + CV_MAT_TYPE(dst->type) != CV_32FC1 ) + CV_Error( CV_StsUnsupportedFormat, + "The input image must have 8uC1 type and the output one must have 32fC1 type" ); + + int i, m = src->rows, n = src->cols; + + cv::AutoBuffer _buf(std::max(m*2*sizeof(float) + (m*3+1)*sizeof(int), n*2*sizeof(float))); + // stage 1: compute 1d distance transform of each column + float* sqr_tab = (float*)(uchar*)_buf; + int* sat_tab = cv::alignPtr((int*)(sqr_tab + m*2), sizeof(int)); + int shift = m*2; + + for( i = 0; i < m; i++ ) + sqr_tab[i] = (float)(i*i); + for( i = m; i < m*2; i++ ) + sqr_tab[i] = inf; + for( i = 0; i < shift; i++ ) + sat_tab[i] = 0; + for( ; i <= m*3; i++ ) + sat_tab[i] = i - shift; + + cv::parallel_for(cv::BlockedRange(0, n), cv::DTColumnInvoker(src, dst, sat_tab, sqr_tab)); + + // stage 2: compute modified distance transform for each row + float* inv_tab = sqr_tab + n; + + inv_tab[0] = sqr_tab[0] = 0.f; + for( i = 1; i < n; i++ ) + { + inv_tab[i] = (float)(0.5/i); + sqr_tab[i] = (float)(i*i); + } + + cv::parallel_for(cv::BlockedRange(0, m), cv::DTRowInvoker(dst, sqr_tab, inv_tab)); +} + + +/*********************************** IPP functions *********************************/ + +typedef CvStatus (CV_STDCALL * CvIPPDistTransFunc)( const uchar* src, int srcstep, + void* dst, int dststep, + CvSize size, const void* metrics ); + +typedef CvStatus (CV_STDCALL * CvIPPDistTransFunc2)( uchar* src, int srcstep, + CvSize size, const int* metrics ); + +/***********************************************************************************/ + +typedef CvStatus (CV_STDCALL * CvDistTransFunc)( const uchar* src, int srcstep, + int* temp, int tempstep, + float* dst, int dststep, + CvSize size, const float* metrics ); + + +/****************************************************************************************\ + Non-inplace and Inplace 8u->8u Distance Transform for CityBlock (a.k.a. L1) metric + (C) 2006 by Jay Stavinzky. +\****************************************************************************************/ + +//BEGIN ATS ADDITION +/* 8-bit grayscale distance transform function */ +static void +icvDistanceATS_L1_8u( const CvMat* src, CvMat* dst ) +{ + int width = src->cols, height = src->rows; + + int a; + uchar lut[256]; + int x, y; + + const uchar *sbase = src->data.ptr; + uchar *dbase = dst->data.ptr; + int srcstep = src->step; + int dststep = dst->step; + + CV_Assert( CV_IS_MASK_ARR( src ) && CV_MAT_TYPE( dst->type ) == CV_8UC1 ); + CV_Assert( CV_ARE_SIZES_EQ( src, dst )); + + ////////////////////// forward scan //////////////////////// + for( x = 0; x < 256; x++ ) + lut[x] = CV_CAST_8U(x+1); + + //init first pixel to max (we're going to be skipping it) + dbase[0] = (uchar)(sbase[0] == 0 ? 0 : 255); + + //first row (scan west only, skip first pixel) + for( x = 1; x < width; x++ ) + dbase[x] = (uchar)(sbase[x] == 0 ? 0 : lut[dbase[x-1]]); + + for( y = 1; y < height; y++ ) + { + sbase += srcstep; + dbase += dststep; + + //for left edge, scan north only + a = sbase[0] == 0 ? 0 : lut[dbase[-dststep]]; + dbase[0] = (uchar)a; + + for( x = 1; x < width; x++ ) + { + a = sbase[x] == 0 ? 0 : lut[MIN(a, dbase[x - dststep])]; + dbase[x] = (uchar)a; + } + } + + ////////////////////// backward scan /////////////////////// + + a = dbase[width-1]; + + // do last row east pixel scan here (skip bottom right pixel) + for( x = width - 2; x >= 0; x-- ) + { + a = lut[a]; + dbase[x] = (uchar)(CV_CALC_MIN_8U(a, dbase[x])); + } + + // right edge is the only error case + for( y = height - 2; y >= 0; y-- ) + { + dbase -= dststep; + + // do right edge + a = lut[dbase[width-1+dststep]]; + dbase[width-1] = (uchar)(MIN(a, dbase[width-1])); + + for( x = width - 2; x >= 0; x-- ) + { + int b = dbase[x+dststep]; + a = lut[MIN(a, b)]; + dbase[x] = (uchar)(MIN(a, dbase[x])); + } + } +} +//END ATS ADDITION + + +/* Wrapper function for distance transform group */ +CV_IMPL void +cvDistTransform( const void* srcarr, void* dstarr, + int distType, int maskSize, + const float *mask, + void* labelsarr, int labelType ) +{ + float _mask[5] = {0}; + CvMat srcstub, *src = (CvMat*)srcarr; + CvMat dststub, *dst = (CvMat*)dstarr; + CvMat lstub, *labels = (CvMat*)labelsarr; + + src = cvGetMat( src, &srcstub ); + dst = cvGetMat( dst, &dststub ); + + if( !CV_IS_MASK_ARR( src ) || (CV_MAT_TYPE( dst->type ) != CV_32FC1 && + (CV_MAT_TYPE(dst->type) != CV_8UC1 || distType != CV_DIST_L1 || labels)) ) + CV_Error( CV_StsUnsupportedFormat, + "source image must be 8uC1 and the distance map must be 32fC1 " + "(or 8uC1 in case of simple L1 distance transform)" ); + + if( !CV_ARE_SIZES_EQ( src, dst )) + CV_Error( CV_StsUnmatchedSizes, "the source and the destination images must be of the same size" ); + + if( maskSize != CV_DIST_MASK_3 && maskSize != CV_DIST_MASK_5 && maskSize != CV_DIST_MASK_PRECISE ) + CV_Error( CV_StsBadSize, "Mask size should be 3 or 5 or 0 (presize)" ); + + if( distType == CV_DIST_C || distType == CV_DIST_L1 ) + maskSize = !labels ? CV_DIST_MASK_3 : CV_DIST_MASK_5; + else if( distType == CV_DIST_L2 && labels ) + maskSize = CV_DIST_MASK_5; + + if( maskSize == CV_DIST_MASK_PRECISE ) + { + icvTrueDistTrans( src, dst ); + return; + } + + if( labels ) + { + labels = cvGetMat( labels, &lstub ); + if( CV_MAT_TYPE( labels->type ) != CV_32SC1 ) + CV_Error( CV_StsUnsupportedFormat, "the output array of labels must be 32sC1" ); + + if( !CV_ARE_SIZES_EQ( labels, dst )) + CV_Error( CV_StsUnmatchedSizes, "the array of labels has a different size" ); + + if( maskSize == CV_DIST_MASK_3 ) + CV_Error( CV_StsNotImplemented, + "3x3 mask can not be used for \"labeled\" distance transform. Use 5x5 mask" ); + } + + if( distType == CV_DIST_C || distType == CV_DIST_L1 || distType == CV_DIST_L2 ) + { + icvGetDistanceTransformMask( (distType == CV_DIST_C ? 0 : + distType == CV_DIST_L1 ? 1 : 2) + maskSize*10, _mask ); + } + else if( distType == CV_DIST_USER ) + { + if( !mask ) + CV_Error( CV_StsNullPtr, "" ); + + memcpy( _mask, mask, (maskSize/2 + 1)*sizeof(float)); + } + + CvSize size = cvGetMatSize(src); + + if( CV_MAT_TYPE(dst->type) == CV_8UC1 ) + { + icvDistanceATS_L1_8u( src, dst ); + } + else + { + int border = maskSize == CV_DIST_MASK_3 ? 1 : 2; + cv::Ptr temp = cvCreateMat( size.height + border*2, size.width + border*2, CV_32SC1 ); + + if( !labels ) + { + CvDistTransFunc func = maskSize == CV_DIST_MASK_3 ? + icvDistanceTransform_3x3_C1R : + icvDistanceTransform_5x5_C1R; + + func( src->data.ptr, src->step, temp->data.i, temp->step, + dst->data.fl, dst->step, size, _mask ); + } + else + { + cvZero( labels ); + + if( labelType == CV_DIST_LABEL_CCOMP ) + { + CvSeq *contours = 0; + cv::Ptr st = cvCreateMemStorage(); + cv::Ptr src_copy = cvCreateMat( size.height+border*2, size.width+border*2, src->type ); + cvCopyMakeBorder(src, src_copy, cvPoint(border, border), IPL_BORDER_CONSTANT, cvScalarAll(255)); + cvCmpS( src_copy, 0, src_copy, CV_CMP_EQ ); + cvFindContours( src_copy, st, &contours, sizeof(CvContour), + CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(-border, -border)); + + for( int label = 1; contours != 0; contours = contours->h_next, label++ ) + { + CvScalar area_color = cvScalarAll(label); + cvDrawContours( labels, contours, area_color, area_color, -255, -1, 8 ); + } + } + else + { + int k = 1; + for( int i = 0; i < src->rows; i++ ) + { + const uchar* srcptr = src->data.ptr + src->step*i; + int* labelptr = (int*)(labels->data.ptr + labels->step*i); + + for( int j = 0; j < src->cols; j++ ) + if( srcptr[j] == 0 ) + labelptr[j] = k++; + } + } + + icvDistanceTransformEx_5x5_C1R( src->data.ptr, src->step, temp->data.i, temp->step, + dst->data.fl, dst->step, labels->data.i, labels->step, size, _mask ); + } + } +} + +void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels, + int distanceType, int maskSize, int labelType ) +{ + Mat src = _src.getMat(); + _dst.create(src.size(), CV_32F); + _labels.create(src.size(), CV_32S); + CvMat c_src = src, c_dst = _dst.getMat(), c_labels = _labels.getMat(); + cvDistTransform(&c_src, &c_dst, distanceType, maskSize, 0, &c_labels, labelType); +} + +void cv::distanceTransform( InputArray _src, OutputArray _dst, + int distanceType, int maskSize ) +{ + Mat src = _src.getMat(); + _dst.create(src.size(), CV_32F); + Mat dst = _dst.getMat(); + CvMat c_src = src, c_dst = _dst.getMat(); + cvDistTransform(&c_src, &c_dst, distanceType, maskSize, 0, 0, -1); +} + +/* End of file. */ diff --git a/imgproc/src/emd.cpp b/imgproc/src/emd.cpp new file mode 100644 index 0000000..734e7aa --- /dev/null +++ b/imgproc/src/emd.cpp @@ -0,0 +1,1162 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +/* + Partially based on Yossi Rubner code: + ========================================================================= + emd.c + + Last update: 3/14/98 + + An implementation of the Earth Movers Distance. + Based of the solution for the Transportation problem as described in + "Introduction to Mathematical Programming" by F. S. Hillier and + G. J. Lieberman, McGraw-Hill, 1990. + + Copyright (C) 1998 Yossi Rubner + Computer Science Department, Stanford University + E-Mail: rubner@cs.stanford.edu URL: http://vision.stanford.edu/~rubner + ========================================================================== +*/ +#include "precomp.hpp" + +#define MAX_ITERATIONS 500 +#define CV_EMD_INF ((float)1e20) +#define CV_EMD_EPS ((float)1e-5) + +/* CvNode1D is used for lists, representing 1D sparse array */ +typedef struct CvNode1D +{ + float val; + struct CvNode1D *next; +} +CvNode1D; + +/* CvNode2D is used for lists, representing 2D sparse matrix */ +typedef struct CvNode2D +{ + float val; + struct CvNode2D *next[2]; /* next row & next column */ + int i, j; +} +CvNode2D; + + +typedef struct CvEMDState +{ + int ssize, dsize; + + float **cost; + CvNode2D *_x; + CvNode2D *end_x; + CvNode2D *enter_x; + char **is_x; + + CvNode2D **rows_x; + CvNode2D **cols_x; + + CvNode1D *u; + CvNode1D *v; + + int* idx1; + int* idx2; + + /* find_loop buffers */ + CvNode2D **loop; + char *is_used; + + /* russel buffers */ + float *s; + float *d; + float **delta; + + float weight, max_cost; + char *buffer; +} +CvEMDState; + +/* static function declaration */ +static int icvInitEMD( const float *signature1, int size1, + const float *signature2, int size2, + int dims, CvDistanceFunction dist_func, void *user_param, + const float* cost, int cost_step, + CvEMDState * state, float *lower_bound, + cv::AutoBuffer& _buffer ); + +static int icvFindBasicVariables( float **cost, char **is_x, + CvNode1D * u, CvNode1D * v, int ssize, int dsize ); + +static float icvIsOptimal( float **cost, char **is_x, + CvNode1D * u, CvNode1D * v, + int ssize, int dsize, CvNode2D * enter_x ); + +static void icvRussel( CvEMDState * state ); + + +static bool icvNewSolution( CvEMDState * state ); +static int icvFindLoop( CvEMDState * state ); + +static void icvAddBasicVariable( CvEMDState * state, + int min_i, int min_j, + CvNode1D * prev_u_min_i, + CvNode1D * prev_v_min_j, + CvNode1D * u_head ); + +static float icvDistL2( const float *x, const float *y, void *user_param ); +static float icvDistL1( const float *x, const float *y, void *user_param ); +static float icvDistC( const float *x, const float *y, void *user_param ); + +/* The main function */ +CV_IMPL float cvCalcEMD2( const CvArr* signature_arr1, + const CvArr* signature_arr2, + int dist_type, + CvDistanceFunction dist_func, + const CvArr* cost_matrix, + CvArr* flow_matrix, + float *lower_bound, + void *user_param ) +{ + cv::AutoBuffer local_buf; + CvEMDState state; + float emd = 0; + + memset( &state, 0, sizeof(state)); + + double total_cost = 0; + int result = 0; + float eps, min_delta; + CvNode2D *xp = 0; + CvMat sign_stub1, *signature1 = (CvMat*)signature_arr1; + CvMat sign_stub2, *signature2 = (CvMat*)signature_arr2; + CvMat cost_stub, *cost = &cost_stub; + CvMat flow_stub, *flow = (CvMat*)flow_matrix; + int dims, size1, size2; + + signature1 = cvGetMat( signature1, &sign_stub1 ); + signature2 = cvGetMat( signature2, &sign_stub2 ); + + if( signature1->cols != signature2->cols ) + CV_Error( CV_StsUnmatchedSizes, "The arrays must have equal number of columns (which is number of dimensions but 1)" ); + + dims = signature1->cols - 1; + size1 = signature1->rows; + size2 = signature2->rows; + + if( !CV_ARE_TYPES_EQ( signature1, signature2 )) + CV_Error( CV_StsUnmatchedFormats, "The array must have equal types" ); + + if( CV_MAT_TYPE( signature1->type ) != CV_32FC1 ) + CV_Error( CV_StsUnsupportedFormat, "The signatures must be 32fC1" ); + + if( flow ) + { + flow = cvGetMat( flow, &flow_stub ); + + if( flow->rows != size1 || flow->cols != size2 ) + CV_Error( CV_StsUnmatchedSizes, + "The flow matrix size does not match to the signatures' sizes" ); + + if( CV_MAT_TYPE( flow->type ) != CV_32FC1 ) + CV_Error( CV_StsUnsupportedFormat, "The flow matrix must be 32fC1" ); + } + + cost->data.fl = 0; + cost->step = 0; + + if( dist_type < 0 ) + { + if( cost_matrix ) + { + if( dist_func ) + CV_Error( CV_StsBadArg, + "Only one of cost matrix or distance function should be non-NULL in case of user-defined distance" ); + + if( lower_bound ) + CV_Error( CV_StsBadArg, + "The lower boundary can not be calculated if the cost matrix is used" ); + + cost = cvGetMat( cost_matrix, &cost_stub ); + if( cost->rows != size1 || cost->cols != size2 ) + CV_Error( CV_StsUnmatchedSizes, + "The cost matrix size does not match to the signatures' sizes" ); + + if( CV_MAT_TYPE( cost->type ) != CV_32FC1 ) + CV_Error( CV_StsUnsupportedFormat, "The cost matrix must be 32fC1" ); + } + else if( !dist_func ) + CV_Error( CV_StsNullPtr, "In case of user-defined distance Distance function is undefined" ); + } + else + { + if( dims == 0 ) + CV_Error( CV_StsBadSize, + "Number of dimensions can be 0 only if a user-defined metric is used" ); + user_param = (void *) (size_t)dims; + switch (dist_type) + { + case CV_DIST_L1: + dist_func = icvDistL1; + break; + case CV_DIST_L2: + dist_func = icvDistL2; + break; + case CV_DIST_C: + dist_func = icvDistC; + break; + default: + CV_Error( CV_StsBadFlag, "Bad or unsupported metric type" ); + } + } + + result = icvInitEMD( signature1->data.fl, size1, + signature2->data.fl, size2, + dims, dist_func, user_param, + cost->data.fl, cost->step, + &state, lower_bound, local_buf ); + + if( result > 0 && lower_bound ) + { + emd = *lower_bound; + return emd; + } + + eps = CV_EMD_EPS * state.max_cost; + + /* if ssize = 1 or dsize = 1 then we are done, else ... */ + if( state.ssize > 1 && state.dsize > 1 ) + { + int itr; + + for( itr = 1; itr < MAX_ITERATIONS; itr++ ) + { + /* find basic variables */ + result = icvFindBasicVariables( state.cost, state.is_x, + state.u, state.v, state.ssize, state.dsize ); + if( result < 0 ) + break; + + /* check for optimality */ + min_delta = icvIsOptimal( state.cost, state.is_x, + state.u, state.v, + state.ssize, state.dsize, state.enter_x ); + + if( min_delta == CV_EMD_INF ) + CV_Error( CV_StsNoConv, "" ); + + /* if no negative deltamin, we found the optimal solution */ + if( min_delta >= -eps ) + break; + + /* improve solution */ + if(!icvNewSolution( &state )) + CV_Error( CV_StsNoConv, "" ); + } + } + + /* compute the total flow */ + for( xp = state._x; xp < state.end_x; xp++ ) + { + float val = xp->val; + int i = xp->i; + int j = xp->j; + + if( xp == state.enter_x ) + continue; + + int ci = state.idx1[i]; + int cj = state.idx2[j]; + + if( ci >= 0 && cj >= 0 ) + { + total_cost += (double)val * state.cost[i][j]; + if( flow ) + ((float*)(flow->data.ptr + flow->step*ci))[cj] = val; + } + } + + emd = (float) (total_cost / state.weight); + return emd; +} + + +/************************************************************************************\ +* initialize structure, allocate buffers and generate initial golution * +\************************************************************************************/ +static int icvInitEMD( const float* signature1, int size1, + const float* signature2, int size2, + int dims, CvDistanceFunction dist_func, void* user_param, + const float* cost, int cost_step, + CvEMDState* state, float* lower_bound, + cv::AutoBuffer& _buffer ) +{ + float s_sum = 0, d_sum = 0, diff; + int i, j; + int ssize = 0, dsize = 0; + int equal_sums = 1; + int buffer_size; + float max_cost = 0; + char *buffer, *buffer_end; + + memset( state, 0, sizeof( *state )); + assert( cost_step % sizeof(float) == 0 ); + cost_step /= sizeof(float); + + /* calculate buffer size */ + buffer_size = (size1+1) * (size2+1) * (sizeof( float ) + /* cost */ + sizeof( char ) + /* is_x */ + sizeof( float )) + /* delta matrix */ + (size1 + size2 + 2) * (sizeof( CvNode2D ) + /* _x */ + sizeof( CvNode2D * ) + /* cols_x & rows_x */ + sizeof( CvNode1D ) + /* u & v */ + sizeof( float ) + /* s & d */ + sizeof( int ) + sizeof(CvNode2D*)) + /* idx1 & idx2 */ + (size1+1) * (sizeof( float * ) + sizeof( char * ) + /* rows pointers for */ + sizeof( float * )) + 256; /* cost, is_x and delta */ + + if( buffer_size < (int) (dims * 2 * sizeof( float ))) + { + buffer_size = dims * 2 * sizeof( float ); + } + + /* allocate buffers */ + _buffer.allocate(buffer_size); + + state->buffer = buffer = _buffer; + buffer_end = buffer + buffer_size; + + state->idx1 = (int*) buffer; + buffer += (size1 + 1) * sizeof( int ); + + state->idx2 = (int*) buffer; + buffer += (size2 + 1) * sizeof( int ); + + state->s = (float *) buffer; + buffer += (size1 + 1) * sizeof( float ); + + state->d = (float *) buffer; + buffer += (size2 + 1) * sizeof( float ); + + /* sum up the supply and demand */ + for( i = 0; i < size1; i++ ) + { + float weight = signature1[i * (dims + 1)]; + + if( weight > 0 ) + { + s_sum += weight; + state->s[ssize] = weight; + state->idx1[ssize++] = i; + + } + else if( weight < 0 ) + CV_Error(CV_StsOutOfRange, ""); + } + + for( i = 0; i < size2; i++ ) + { + float weight = signature2[i * (dims + 1)]; + + if( weight > 0 ) + { + d_sum += weight; + state->d[dsize] = weight; + state->idx2[dsize++] = i; + } + else if( weight < 0 ) + CV_Error(CV_StsOutOfRange, ""); + } + + if( ssize == 0 || dsize == 0 ) + CV_Error(CV_StsOutOfRange, ""); + + /* if supply different than the demand, add a zero-cost dummy cluster */ + diff = s_sum - d_sum; + if( fabs( diff ) >= CV_EMD_EPS * s_sum ) + { + equal_sums = 0; + if( diff < 0 ) + { + state->s[ssize] = -diff; + state->idx1[ssize++] = -1; + } + else + { + state->d[dsize] = diff; + state->idx2[dsize++] = -1; + } + } + + state->ssize = ssize; + state->dsize = dsize; + state->weight = s_sum > d_sum ? s_sum : d_sum; + + if( lower_bound && equal_sums ) /* check lower bound */ + { + int sz1 = size1 * (dims + 1), sz2 = size2 * (dims + 1); + float lb = 0; + + float* xs = (float *) buffer; + float* xd = xs + dims; + + memset( xs, 0, dims*sizeof(xs[0])); + memset( xd, 0, dims*sizeof(xd[0])); + + for( j = 0; j < sz1; j += dims + 1 ) + { + float weight = signature1[j]; + for( i = 0; i < dims; i++ ) + xs[i] += signature1[j + i + 1] * weight; + } + + for( j = 0; j < sz2; j += dims + 1 ) + { + float weight = signature2[j]; + for( i = 0; i < dims; i++ ) + xd[i] += signature2[j + i + 1] * weight; + } + + lb = dist_func( xs, xd, user_param ) / state->weight; + i = *lower_bound <= lb; + *lower_bound = lb; + if( i ) + return 1; + } + + /* assign pointers */ + state->is_used = (char *) buffer; + /* init delta matrix */ + state->delta = (float **) buffer; + buffer += ssize * sizeof( float * ); + + for( i = 0; i < ssize; i++ ) + { + state->delta[i] = (float *) buffer; + buffer += dsize * sizeof( float ); + } + + state->loop = (CvNode2D **) buffer; + buffer += (ssize + dsize + 1) * sizeof(CvNode2D*); + + state->_x = state->end_x = (CvNode2D *) buffer; + buffer += (ssize + dsize) * sizeof( CvNode2D ); + + /* init cost matrix */ + state->cost = (float **) buffer; + buffer += ssize * sizeof( float * ); + + /* compute the distance matrix */ + for( i = 0; i < ssize; i++ ) + { + int ci = state->idx1[i]; + + state->cost[i] = (float *) buffer; + buffer += dsize * sizeof( float ); + + if( ci >= 0 ) + { + for( j = 0; j < dsize; j++ ) + { + int cj = state->idx2[j]; + if( cj < 0 ) + state->cost[i][j] = 0; + else + { + float val; + if( dist_func ) + { + val = dist_func( signature1 + ci * (dims + 1) + 1, + signature2 + cj * (dims + 1) + 1, + user_param ); + } + else + { + assert( cost ); + val = cost[cost_step*ci + cj]; + } + state->cost[i][j] = val; + if( max_cost < val ) + max_cost = val; + } + } + } + else + { + for( j = 0; j < dsize; j++ ) + state->cost[i][j] = 0; + } + } + + state->max_cost = max_cost; + + memset( buffer, 0, buffer_end - buffer ); + + state->rows_x = (CvNode2D **) buffer; + buffer += ssize * sizeof( CvNode2D * ); + + state->cols_x = (CvNode2D **) buffer; + buffer += dsize * sizeof( CvNode2D * ); + + state->u = (CvNode1D *) buffer; + buffer += ssize * sizeof( CvNode1D ); + + state->v = (CvNode1D *) buffer; + buffer += dsize * sizeof( CvNode1D ); + + /* init is_x matrix */ + state->is_x = (char **) buffer; + buffer += ssize * sizeof( char * ); + + for( i = 0; i < ssize; i++ ) + { + state->is_x[i] = buffer; + buffer += dsize; + } + + assert( buffer <= buffer_end ); + + icvRussel( state ); + + state->enter_x = (state->end_x)++; + return 0; +} + + +/****************************************************************************************\ +* icvFindBasicVariables * +\****************************************************************************************/ +static int icvFindBasicVariables( float **cost, char **is_x, + CvNode1D * u, CvNode1D * v, int ssize, int dsize ) +{ + int i, j, found; + int u_cfound, v_cfound; + CvNode1D u0_head, u1_head, *cur_u, *prev_u; + CvNode1D v0_head, v1_head, *cur_v, *prev_v; + + /* initialize the rows list (u) and the columns list (v) */ + u0_head.next = u; + for( i = 0; i < ssize; i++ ) + { + u[i].next = u + i + 1; + } + u[ssize - 1].next = 0; + u1_head.next = 0; + + v0_head.next = ssize > 1 ? v + 1 : 0; + for( i = 1; i < dsize; i++ ) + { + v[i].next = v + i + 1; + } + v[dsize - 1].next = 0; + v1_head.next = 0; + + /* there are ssize+dsize variables but only ssize+dsize-1 independent equations, + so set v[0]=0 */ + v[0].val = 0; + v1_head.next = v; + v1_head.next->next = 0; + + /* loop until all variables are found */ + u_cfound = v_cfound = 0; + while( u_cfound < ssize || v_cfound < dsize ) + { + found = 0; + if( v_cfound < dsize ) + { + /* loop over all marked columns */ + prev_v = &v1_head; + + for( found |= (cur_v = v1_head.next) != 0; cur_v != 0; cur_v = cur_v->next ) + { + float cur_v_val = cur_v->val; + + j = (int)(cur_v - v); + /* find the variables in column j */ + prev_u = &u0_head; + for( cur_u = u0_head.next; cur_u != 0; ) + { + i = (int)(cur_u - u); + if( is_x[i][j] ) + { + /* compute u[i] */ + cur_u->val = cost[i][j] - cur_v_val; + /* ...and add it to the marked list */ + prev_u->next = cur_u->next; + cur_u->next = u1_head.next; + u1_head.next = cur_u; + cur_u = prev_u->next; + } + else + { + prev_u = cur_u; + cur_u = cur_u->next; + } + } + prev_v->next = cur_v->next; + v_cfound++; + } + } + + if( u_cfound < ssize ) + { + /* loop over all marked rows */ + prev_u = &u1_head; + for( found |= (cur_u = u1_head.next) != 0; cur_u != 0; cur_u = cur_u->next ) + { + float cur_u_val = cur_u->val; + float *_cost; + char *_is_x; + + i = (int)(cur_u - u); + _cost = cost[i]; + _is_x = is_x[i]; + /* find the variables in rows i */ + prev_v = &v0_head; + for( cur_v = v0_head.next; cur_v != 0; ) + { + j = (int)(cur_v - v); + if( _is_x[j] ) + { + /* compute v[j] */ + cur_v->val = _cost[j] - cur_u_val; + /* ...and add it to the marked list */ + prev_v->next = cur_v->next; + cur_v->next = v1_head.next; + v1_head.next = cur_v; + cur_v = prev_v->next; + } + else + { + prev_v = cur_v; + cur_v = cur_v->next; + } + } + prev_u->next = cur_u->next; + u_cfound++; + } + } + + if( !found ) + return -1; + } + + return 0; +} + + +/****************************************************************************************\ +* icvIsOptimal * +\****************************************************************************************/ +static float +icvIsOptimal( float **cost, char **is_x, + CvNode1D * u, CvNode1D * v, int ssize, int dsize, CvNode2D * enter_x ) +{ + float delta, min_delta = CV_EMD_INF; + int i, j, min_i = 0, min_j = 0; + + /* find the minimal cij-ui-vj over all i,j */ + for( i = 0; i < ssize; i++ ) + { + float u_val = u[i].val; + float *_cost = cost[i]; + char *_is_x = is_x[i]; + + for( j = 0; j < dsize; j++ ) + { + if( !_is_x[j] ) + { + delta = _cost[j] - u_val - v[j].val; + if( min_delta > delta ) + { + min_delta = delta; + min_i = i; + min_j = j; + } + } + } + } + + enter_x->i = min_i; + enter_x->j = min_j; + + return min_delta; +} + +/****************************************************************************************\ +* icvNewSolution * +\****************************************************************************************/ +static bool +icvNewSolution( CvEMDState * state ) +{ + int i, j; + float min_val = CV_EMD_INF; + int steps; + CvNode2D head, *cur_x, *next_x, *leave_x = 0; + CvNode2D *enter_x = state->enter_x; + CvNode2D **loop = state->loop; + + /* enter the new basic variable */ + i = enter_x->i; + j = enter_x->j; + state->is_x[i][j] = 1; + enter_x->next[0] = state->rows_x[i]; + enter_x->next[1] = state->cols_x[j]; + enter_x->val = 0; + state->rows_x[i] = enter_x; + state->cols_x[j] = enter_x; + + /* find a chain reaction */ + steps = icvFindLoop( state ); + + if( steps == 0 ) + return false; + + /* find the largest value in the loop */ + for( i = 1; i < steps; i += 2 ) + { + float temp = loop[i]->val; + + if( min_val > temp ) + { + leave_x = loop[i]; + min_val = temp; + } + } + + /* update the loop */ + for( i = 0; i < steps; i += 2 ) + { + float temp0 = loop[i]->val + min_val; + float temp1 = loop[i + 1]->val - min_val; + + loop[i]->val = temp0; + loop[i + 1]->val = temp1; + } + + /* remove the leaving basic variable */ + i = leave_x->i; + j = leave_x->j; + state->is_x[i][j] = 0; + + head.next[0] = state->rows_x[i]; + cur_x = &head; + while( (next_x = cur_x->next[0]) != leave_x ) + { + cur_x = next_x; + assert( cur_x ); + } + cur_x->next[0] = next_x->next[0]; + state->rows_x[i] = head.next[0]; + + head.next[1] = state->cols_x[j]; + cur_x = &head; + while( (next_x = cur_x->next[1]) != leave_x ) + { + cur_x = next_x; + assert( cur_x ); + } + cur_x->next[1] = next_x->next[1]; + state->cols_x[j] = head.next[1]; + + /* set enter_x to be the new empty slot */ + state->enter_x = leave_x; + + return true; +} + + + +/****************************************************************************************\ +* icvFindLoop * +\****************************************************************************************/ +static int +icvFindLoop( CvEMDState * state ) +{ + int i, steps = 1; + CvNode2D *new_x; + CvNode2D **loop = state->loop; + CvNode2D *enter_x = state->enter_x, *_x = state->_x; + char *is_used = state->is_used; + + memset( is_used, 0, state->ssize + state->dsize ); + + new_x = loop[0] = enter_x; + is_used[enter_x - _x] = 1; + steps = 1; + + do + { + if( (steps & 1) == 1 ) + { + /* find an unused x in the row */ + new_x = state->rows_x[new_x->i]; + while( new_x != 0 && is_used[new_x - _x] ) + new_x = new_x->next[0]; + } + else + { + /* find an unused x in the column, or the entering x */ + new_x = state->cols_x[new_x->j]; + while( new_x != 0 && is_used[new_x - _x] && new_x != enter_x ) + new_x = new_x->next[1]; + if( new_x == enter_x ) + break; + } + + if( new_x != 0 ) /* found the next x */ + { + /* add x to the loop */ + loop[steps++] = new_x; + is_used[new_x - _x] = 1; + } + else /* didn't find the next x */ + { + /* backtrack */ + do + { + i = steps & 1; + new_x = loop[steps - 1]; + do + { + new_x = new_x->next[i]; + } + while( new_x != 0 && is_used[new_x - _x] ); + + if( new_x == 0 ) + { + is_used[loop[--steps] - _x] = 0; + } + } + while( new_x == 0 && steps > 0 ); + + is_used[loop[steps - 1] - _x] = 0; + loop[steps - 1] = new_x; + is_used[new_x - _x] = 1; + } + } + while( steps > 0 ); + + return steps; +} + + + +/****************************************************************************************\ +* icvRussel * +\****************************************************************************************/ +static void +icvRussel( CvEMDState * state ) +{ + int i, j, min_i = -1, min_j = -1; + float min_delta, diff; + CvNode1D u_head, *cur_u, *prev_u; + CvNode1D v_head, *cur_v, *prev_v; + CvNode1D *prev_u_min_i = 0, *prev_v_min_j = 0, *remember; + CvNode1D *u = state->u, *v = state->v; + int ssize = state->ssize, dsize = state->dsize; + float eps = CV_EMD_EPS * state->max_cost; + float **cost = state->cost; + float **delta = state->delta; + + /* initialize the rows list (ur), and the columns list (vr) */ + u_head.next = u; + for( i = 0; i < ssize; i++ ) + { + u[i].next = u + i + 1; + } + u[ssize - 1].next = 0; + + v_head.next = v; + for( i = 0; i < dsize; i++ ) + { + v[i].val = -CV_EMD_INF; + v[i].next = v + i + 1; + } + v[dsize - 1].next = 0; + + /* find the maximum row and column values (ur[i] and vr[j]) */ + for( i = 0; i < ssize; i++ ) + { + float u_val = -CV_EMD_INF; + float *cost_row = cost[i]; + + for( j = 0; j < dsize; j++ ) + { + float temp = cost_row[j]; + + if( u_val < temp ) + u_val = temp; + if( v[j].val < temp ) + v[j].val = temp; + } + u[i].val = u_val; + } + + /* compute the delta matrix */ + for( i = 0; i < ssize; i++ ) + { + float u_val = u[i].val; + float *delta_row = delta[i]; + float *cost_row = cost[i]; + + for( j = 0; j < dsize; j++ ) + { + delta_row[j] = cost_row[j] - u_val - v[j].val; + } + } + + /* find the basic variables */ + do + { + /* find the smallest delta[i][j] */ + min_i = -1; + min_delta = CV_EMD_INF; + prev_u = &u_head; + for( cur_u = u_head.next; cur_u != 0; cur_u = cur_u->next ) + { + i = (int)(cur_u - u); + float *delta_row = delta[i]; + + prev_v = &v_head; + for( cur_v = v_head.next; cur_v != 0; cur_v = cur_v->next ) + { + j = (int)(cur_v - v); + if( min_delta > delta_row[j] ) + { + min_delta = delta_row[j]; + min_i = i; + min_j = j; + prev_u_min_i = prev_u; + prev_v_min_j = prev_v; + } + prev_v = cur_v; + } + prev_u = cur_u; + } + + if( min_i < 0 ) + break; + + /* add x[min_i][min_j] to the basis, and adjust supplies and cost */ + remember = prev_u_min_i->next; + icvAddBasicVariable( state, min_i, min_j, prev_u_min_i, prev_v_min_j, &u_head ); + + /* update the necessary delta[][] */ + if( remember == prev_u_min_i->next ) /* line min_i was deleted */ + { + for( cur_v = v_head.next; cur_v != 0; cur_v = cur_v->next ) + { + j = (int)(cur_v - v); + if( cur_v->val == cost[min_i][j] ) /* column j needs updating */ + { + float max_val = -CV_EMD_INF; + + /* find the new maximum value in the column */ + for( cur_u = u_head.next; cur_u != 0; cur_u = cur_u->next ) + { + float temp = cost[cur_u - u][j]; + + if( max_val < temp ) + max_val = temp; + } + + /* if needed, adjust the relevant delta[*][j] */ + diff = max_val - cur_v->val; + cur_v->val = max_val; + if( fabs( diff ) < eps ) + { + for( cur_u = u_head.next; cur_u != 0; cur_u = cur_u->next ) + delta[cur_u - u][j] += diff; + } + } + } + } + else /* column min_j was deleted */ + { + for( cur_u = u_head.next; cur_u != 0; cur_u = cur_u->next ) + { + i = (int)(cur_u - u); + if( cur_u->val == cost[i][min_j] ) /* row i needs updating */ + { + float max_val = -CV_EMD_INF; + + /* find the new maximum value in the row */ + for( cur_v = v_head.next; cur_v != 0; cur_v = cur_v->next ) + { + float temp = cost[i][cur_v - v]; + + if( max_val < temp ) + max_val = temp; + } + + /* if needed, adjust the relevant delta[i][*] */ + diff = max_val - cur_u->val; + cur_u->val = max_val; + + if( fabs( diff ) < eps ) + { + for( cur_v = v_head.next; cur_v != 0; cur_v = cur_v->next ) + delta[i][cur_v - v] += diff; + } + } + } + } + } + while( u_head.next != 0 || v_head.next != 0 ); +} + + + +/****************************************************************************************\ +* icvAddBasicVariable * +\****************************************************************************************/ +static void +icvAddBasicVariable( CvEMDState * state, + int min_i, int min_j, + CvNode1D * prev_u_min_i, CvNode1D * prev_v_min_j, CvNode1D * u_head ) +{ + float temp; + CvNode2D *end_x = state->end_x; + + if( state->s[min_i] < state->d[min_j] + state->weight * CV_EMD_EPS ) + { /* supply exhausted */ + temp = state->s[min_i]; + state->s[min_i] = 0; + state->d[min_j] -= temp; + } + else /* demand exhausted */ + { + temp = state->d[min_j]; + state->d[min_j] = 0; + state->s[min_i] -= temp; + } + + /* x(min_i,min_j) is a basic variable */ + state->is_x[min_i][min_j] = 1; + + end_x->val = temp; + end_x->i = min_i; + end_x->j = min_j; + end_x->next[0] = state->rows_x[min_i]; + end_x->next[1] = state->cols_x[min_j]; + state->rows_x[min_i] = end_x; + state->cols_x[min_j] = end_x; + state->end_x = end_x + 1; + + /* delete supply row only if the empty, and if not last row */ + if( state->s[min_i] == 0 && u_head->next->next != 0 ) + prev_u_min_i->next = prev_u_min_i->next->next; /* remove row from list */ + else + prev_v_min_j->next = prev_v_min_j->next->next; /* remove column from list */ +} + + +/****************************************************************************************\ +* standard metrics * +\****************************************************************************************/ +static float +icvDistL1( const float *x, const float *y, void *user_param ) +{ + int i, dims = (int)(size_t)user_param; + double s = 0; + + for( i = 0; i < dims; i++ ) + { + double t = x[i] - y[i]; + + s += fabs( t ); + } + return (float)s; +} + +static float +icvDistL2( const float *x, const float *y, void *user_param ) +{ + int i, dims = (int)(size_t)user_param; + double s = 0; + + for( i = 0; i < dims; i++ ) + { + double t = x[i] - y[i]; + + s += t * t; + } + return cvSqrt( (float)s ); +} + +static float +icvDistC( const float *x, const float *y, void *user_param ) +{ + int i, dims = (int)(size_t)user_param; + double s = 0; + + for( i = 0; i < dims; i++ ) + { + double t = fabs( x[i] - y[i] ); + + if( s < t ) + s = t; + } + return (float)s; +} + + +float cv::EMD( InputArray _signature1, InputArray _signature2, + int distType, InputArray _cost, + float* lowerBound, OutputArray _flow ) +{ + Mat signature1 = _signature1.getMat(), signature2 = _signature2.getMat(); + Mat cost = _cost.getMat(), flow; + + CvMat _csignature1 = signature1; + CvMat _csignature2 = signature2; + CvMat _ccost = cost, _cflow; + if( _flow.needed() ) + { + _flow.create(signature1.rows, signature2.rows, CV_32F); + flow = _flow.getMat(); + _cflow = flow; + } + + return cvCalcEMD2( &_csignature1, &_csignature2, distType, 0, cost.empty() ? 0 : &_ccost, + _flow.needed() ? &_cflow : 0, lowerBound, 0 ); +} + +/* End of file. */ diff --git a/imgproc/src/featureselect.cpp b/imgproc/src/featureselect.cpp new file mode 100644 index 0000000..d19b04d --- /dev/null +++ b/imgproc/src/featureselect.cpp @@ -0,0 +1,242 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" +#include +#include + +namespace cv +{ + +template struct greaterThanPtr +{ + bool operator()(const T* a, const T* b) const { return *a > *b; } +}; + +} + +void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners, + int maxCorners, double qualityLevel, double minDistance, + InputArray _mask, int blockSize, + bool useHarrisDetector, double harrisK ) +{ + Mat image = _image.getMat(), mask = _mask.getMat(); + + CV_Assert( qualityLevel > 0 && minDistance >= 0 && maxCorners >= 0 ); + CV_Assert( mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size()) ); + + Mat eig, tmp; + if( useHarrisDetector ) + cornerHarris( image, eig, blockSize, 3, harrisK ); + else + cornerMinEigenVal( image, eig, blockSize, 3 ); + + double maxVal = 0; + minMaxLoc( eig, 0, &maxVal, 0, 0, mask ); + threshold( eig, eig, maxVal*qualityLevel, 0, THRESH_TOZERO ); + dilate( eig, tmp, Mat()); + + Size imgsize = image.size(); + + vector tmpCorners; + + // collect list of pointers to features - put them into temporary image + for( int y = 1; y < imgsize.height - 1; y++ ) + { + const float* eig_data = (const float*)eig.ptr(y); + const float* tmp_data = (const float*)tmp.ptr(y); + const uchar* mask_data = mask.data ? mask.ptr(y) : 0; + + for( int x = 1; x < imgsize.width - 1; x++ ) + { + float val = eig_data[x]; + if( val != 0 && val == tmp_data[x] && (!mask_data || mask_data[x]) ) + tmpCorners.push_back(eig_data + x); + } + } + + sort( tmpCorners, greaterThanPtr() ); + vector corners; + size_t i, j, total = tmpCorners.size(), ncorners = 0; + + if(minDistance >= 1) + { + // Partition the image into larger grids + int w = image.cols; + int h = image.rows; + + const int cell_size = cvRound(minDistance); + const int grid_width = (w + cell_size - 1) / cell_size; + const int grid_height = (h + cell_size - 1) / cell_size; + + std::vector > grid(grid_width*grid_height); + + minDistance *= minDistance; + + for( i = 0; i < total; i++ ) + { + int ofs = (int)((const uchar*)tmpCorners[i] - eig.data); + int y = (int)(ofs / eig.step); + int x = (int)((ofs - y*eig.step)/sizeof(float)); + + bool good = true; + + int x_cell = x / cell_size; + int y_cell = y / cell_size; + + int x1 = x_cell - 1; + int y1 = y_cell - 1; + int x2 = x_cell + 1; + int y2 = y_cell + 1; + + // boundary check + x1 = std::max(0, x1); + y1 = std::max(0, y1); + x2 = std::min(grid_width-1, x2); + y2 = std::min(grid_height-1, y2); + + for( int yy = y1; yy <= y2; yy++ ) + { + for( int xx = x1; xx <= x2; xx++ ) + { + vector &m = grid[yy*grid_width + xx]; + + if( m.size() ) + { + for(j = 0; j < m.size(); j++) + { + float dx = x - m[j].x; + float dy = y - m[j].y; + + if( dx*dx + dy*dy < minDistance ) + { + good = false; + goto break_out; + } + } + } + } + } + + break_out: + + if(good) + { + // printf("%d: %d %d -> %d %d, %d, %d -- %d %d %d %d, %d %d, c=%d\n", + // i,x, y, x_cell, y_cell, (int)minDistance, cell_size,x1,y1,x2,y2, grid_width,grid_height,c); + grid[y_cell*grid_width + x_cell].push_back(Point2f((float)x, (float)y)); + + corners.push_back(Point2f((float)x, (float)y)); + ++ncorners; + + if( maxCorners > 0 && (int)ncorners == maxCorners ) + break; + } + } + } + else + { + for( i = 0; i < total; i++ ) + { + int ofs = (int)((const uchar*)tmpCorners[i] - eig.data); + int y = (int)(ofs / eig.step); + int x = (int)((ofs - y*eig.step)/sizeof(float)); + + corners.push_back(Point2f((float)x, (float)y)); + ++ncorners; + if( maxCorners > 0 && (int)ncorners == maxCorners ) + break; + } + } + + Mat(corners).convertTo(_corners, _corners.fixedType() ? _corners.type() : CV_32F); + + /* + for( i = 0; i < total; i++ ) + { + int ofs = (int)((const uchar*)tmpCorners[i] - eig.data); + int y = (int)(ofs / eig.step); + int x = (int)((ofs - y*eig.step)/sizeof(float)); + + if( minDistance > 0 ) + { + for( j = 0; j < ncorners; j++ ) + { + float dx = x - corners[j].x; + float dy = y - corners[j].y; + if( dx*dx + dy*dy < minDistance ) + break; + } + if( j < ncorners ) + continue; + } + + corners.push_back(Point2f((float)x, (float)y)); + ++ncorners; + if( maxCorners > 0 && (int)ncorners == maxCorners ) + break; + } +*/ +} + +CV_IMPL void +cvGoodFeaturesToTrack( const void* _image, void*, void*, + CvPoint2D32f* _corners, int *_corner_count, + double quality_level, double min_distance, + const void* _maskImage, int block_size, + int use_harris, double harris_k ) +{ + cv::Mat image = cv::cvarrToMat(_image), mask; + cv::vector corners; + + if( _maskImage ) + mask = cv::cvarrToMat(_maskImage); + + CV_Assert( _corners && _corner_count ); + cv::goodFeaturesToTrack( image, corners, *_corner_count, quality_level, + min_distance, mask, block_size, use_harris != 0, harris_k ); + + size_t i, ncorners = corners.size(); + for( i = 0; i < ncorners; i++ ) + _corners[i] = corners[i]; + *_corner_count = (int)ncorners; +} + +/* End of file. */ diff --git a/imgproc/src/filter.cpp b/imgproc/src/filter.cpp new file mode 100644 index 0000000..7cbab4e --- /dev/null +++ b/imgproc/src/filter.cpp @@ -0,0 +1,4506 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +/****************************************************************************************\ + Base Image Filter +\****************************************************************************************/ + +/* + Various border types, image boundaries are denoted with '|' + + * BORDER_REPLICATE: aaaaaa|abcdefgh|hhhhhhh + * BORDER_REFLECT: fedcba|abcdefgh|hgfedcb + * BORDER_REFLECT_101: gfedcb|abcdefgh|gfedcba + * BORDER_WRAP: cdefgh|abcdefgh|abcdefg + * BORDER_CONSTANT: iiiiii|abcdefgh|iiiiiii with some specified 'i' + */ +int cv::borderInterpolate( int p, int len, int borderType ) +{ + if( (unsigned)p < (unsigned)len ) + ; + else if( borderType == BORDER_REPLICATE ) + p = p < 0 ? 0 : len - 1; + else if( borderType == BORDER_REFLECT || borderType == BORDER_REFLECT_101 ) + { + int delta = borderType == BORDER_REFLECT_101; + if( len == 1 ) + return 0; + do + { + if( p < 0 ) + p = -p - 1 + delta; + else + p = len - 1 - (p - len) - delta; + } + while( (unsigned)p >= (unsigned)len ); + } + else if( borderType == BORDER_WRAP ) + { + if( p < 0 ) + p -= ((p-len+1)/len)*len; + if( p >= len ) + p %= len; + } + else if( borderType == BORDER_CONSTANT ) + p = -1; + else + CV_Error( CV_StsBadArg, "Unknown/unsupported border type" ); + return p; +} + + +namespace cv +{ + +BaseRowFilter::BaseRowFilter() { ksize = anchor = -1; } +BaseRowFilter::~BaseRowFilter() {} + +BaseColumnFilter::BaseColumnFilter() { ksize = anchor = -1; } +BaseColumnFilter::~BaseColumnFilter() {} +void BaseColumnFilter::reset() {} + +BaseFilter::BaseFilter() { ksize = Size(-1,-1); anchor = Point(-1,-1); } +BaseFilter::~BaseFilter() {} +void BaseFilter::reset() {} + +FilterEngine::FilterEngine() +{ + srcType = dstType = bufType = -1; + rowBorderType = columnBorderType = BORDER_REPLICATE; + bufStep = startY = startY0 = endY = rowCount = dstY = 0; + maxWidth = 0; + + wholeSize = Size(-1,-1); +} + + +FilterEngine::FilterEngine( const Ptr& _filter2D, + const Ptr& _rowFilter, + const Ptr& _columnFilter, + int _srcType, int _dstType, int _bufType, + int _rowBorderType, int _columnBorderType, + const Scalar& _borderValue ) +{ + init(_filter2D, _rowFilter, _columnFilter, _srcType, _dstType, _bufType, + _rowBorderType, _columnBorderType, _borderValue); +} + +FilterEngine::~FilterEngine() +{ +} + + +void FilterEngine::init( const Ptr& _filter2D, + const Ptr& _rowFilter, + const Ptr& _columnFilter, + int _srcType, int _dstType, int _bufType, + int _rowBorderType, int _columnBorderType, + const Scalar& _borderValue ) +{ + _srcType = CV_MAT_TYPE(_srcType); + _bufType = CV_MAT_TYPE(_bufType); + _dstType = CV_MAT_TYPE(_dstType); + + srcType = _srcType; + int srcElemSize = (int)getElemSize(srcType); + dstType = _dstType; + bufType = _bufType; + + filter2D = _filter2D; + rowFilter = _rowFilter; + columnFilter = _columnFilter; + + if( _columnBorderType < 0 ) + _columnBorderType = _rowBorderType; + + rowBorderType = _rowBorderType; + columnBorderType = _columnBorderType; + + CV_Assert( columnBorderType != BORDER_WRAP ); + + if( isSeparable() ) + { + CV_Assert( !rowFilter.empty() && !columnFilter.empty() ); + ksize = Size(rowFilter->ksize, columnFilter->ksize); + anchor = Point(rowFilter->anchor, columnFilter->anchor); + } + else + { + CV_Assert( bufType == srcType ); + ksize = filter2D->ksize; + anchor = filter2D->anchor; + } + + CV_Assert( 0 <= anchor.x && anchor.x < ksize.width && + 0 <= anchor.y && anchor.y < ksize.height ); + + borderElemSize = srcElemSize/(CV_MAT_DEPTH(srcType) >= CV_32S ? sizeof(int) : 1); + int borderLength = std::max(ksize.width - 1, 1); + borderTab.resize(borderLength*borderElemSize); + + maxWidth = bufStep = 0; + constBorderRow.clear(); + + if( rowBorderType == BORDER_CONSTANT || columnBorderType == BORDER_CONSTANT ) + { + constBorderValue.resize(srcElemSize*borderLength); + int srcType1 = CV_MAKETYPE(CV_MAT_DEPTH(srcType), MIN(CV_MAT_CN(srcType), 4)); + scalarToRawData(_borderValue, &constBorderValue[0], srcType1, + borderLength*CV_MAT_CN(srcType)); + } + + wholeSize = Size(-1,-1); +} + +static const int VEC_ALIGN = CV_MALLOC_ALIGN; + +int FilterEngine::start(Size _wholeSize, Rect _roi, int _maxBufRows) +{ + int i, j; + + wholeSize = _wholeSize; + roi = _roi; + CV_Assert( roi.x >= 0 && roi.y >= 0 && roi.width >= 0 && roi.height >= 0 && + roi.x + roi.width <= wholeSize.width && + roi.y + roi.height <= wholeSize.height ); + + int esz = (int)getElemSize(srcType); + int bufElemSize = (int)getElemSize(bufType); + const uchar* constVal = !constBorderValue.empty() ? &constBorderValue[0] : 0; + + if( _maxBufRows < 0 ) + _maxBufRows = ksize.height + 3; + _maxBufRows = std::max(_maxBufRows, std::max(anchor.y, ksize.height-anchor.y-1)*2+1); + + if( maxWidth < roi.width || _maxBufRows != (int)rows.size() ) + { + rows.resize(_maxBufRows); + maxWidth = std::max(maxWidth, roi.width); + int cn = CV_MAT_CN(srcType); + srcRow.resize(esz*(maxWidth + ksize.width - 1)); + if( columnBorderType == BORDER_CONSTANT ) + { + constBorderRow.resize(getElemSize(bufType)*(maxWidth + ksize.width - 1 + VEC_ALIGN)); + uchar *dst = alignPtr(&constBorderRow[0], VEC_ALIGN), *tdst; + int n = (int)constBorderValue.size(), N; + N = (maxWidth + ksize.width - 1)*esz; + tdst = isSeparable() ? &srcRow[0] : dst; + + for( i = 0; i < N; i += n ) + { + n = std::min( n, N - i ); + for(j = 0; j < n; j++) + tdst[i+j] = constVal[j]; + } + + if( isSeparable() ) + (*rowFilter)(&srcRow[0], dst, maxWidth, cn); + } + + int maxBufStep = bufElemSize*(int)alignSize(maxWidth + + (!isSeparable() ? ksize.width - 1 : 0),VEC_ALIGN); + ringBuf.resize(maxBufStep*rows.size()+VEC_ALIGN); + } + + // adjust bufstep so that the used part of the ring buffer stays compact in memory + bufStep = bufElemSize*(int)alignSize(roi.width + (!isSeparable() ? ksize.width - 1 : 0),16); + + dx1 = std::max(anchor.x - roi.x, 0); + dx2 = std::max(ksize.width - anchor.x - 1 + roi.x + roi.width - wholeSize.width, 0); + + // recompute border tables + if( dx1 > 0 || dx2 > 0 ) + { + if( rowBorderType == BORDER_CONSTANT ) + { + int nr = isSeparable() ? 1 : (int)rows.size(); + for( i = 0; i < nr; i++ ) + { + uchar* dst = isSeparable() ? &srcRow[0] : alignPtr(&ringBuf[0],VEC_ALIGN) + bufStep*i; + memcpy( dst, constVal, dx1*esz ); + memcpy( dst + (roi.width + ksize.width - 1 - dx2)*esz, constVal, dx2*esz ); + } + } + else + { + int xofs1 = std::min(roi.x, anchor.x) - roi.x; + + int btab_esz = borderElemSize, wholeWidth = wholeSize.width; + int* btab = (int*)&borderTab[0]; + + for( i = 0; i < dx1; i++ ) + { + int p0 = (borderInterpolate(i-dx1, wholeWidth, rowBorderType) + xofs1)*btab_esz; + for( j = 0; j < btab_esz; j++ ) + btab[i*btab_esz + j] = p0 + j; + } + + for( i = 0; i < dx2; i++ ) + { + int p0 = (borderInterpolate(wholeWidth + i, wholeWidth, rowBorderType) + xofs1)*btab_esz; + for( j = 0; j < btab_esz; j++ ) + btab[(i + dx1)*btab_esz + j] = p0 + j; + } + } + } + + rowCount = dstY = 0; + startY = startY0 = std::max(roi.y - anchor.y, 0); + endY = std::min(roi.y + roi.height + ksize.height - anchor.y - 1, wholeSize.height); + if( !columnFilter.empty() ) + columnFilter->reset(); + if( !filter2D.empty() ) + filter2D->reset(); + + return startY; +} + + +int FilterEngine::start(const Mat& src, const Rect& _srcRoi, + bool isolated, int maxBufRows) +{ + Rect srcRoi = _srcRoi; + + if( srcRoi == Rect(0,0,-1,-1) ) + srcRoi = Rect(0,0,src.cols,src.rows); + + CV_Assert( srcRoi.x >= 0 && srcRoi.y >= 0 && + srcRoi.width >= 0 && srcRoi.height >= 0 && + srcRoi.x + srcRoi.width <= src.cols && + srcRoi.y + srcRoi.height <= src.rows ); + + Point ofs; + Size wsz(src.cols, src.rows); + if( !isolated ) + src.locateROI( wsz, ofs ); + start( wsz, srcRoi + ofs, maxBufRows ); + + return startY - ofs.y; +} + + +int FilterEngine::remainingInputRows() const +{ + return endY - startY - rowCount; +} + +int FilterEngine::remainingOutputRows() const +{ + return roi.height - dstY; +} + +int FilterEngine::proceed( const uchar* src, int srcstep, int count, + uchar* dst, int dststep ) +{ + CV_Assert( wholeSize.width > 0 && wholeSize.height > 0 ); + + const int *btab = &borderTab[0]; + int esz = (int)getElemSize(srcType), btab_esz = borderElemSize; + uchar** brows = &rows[0]; + int bufRows = (int)rows.size(); + int cn = CV_MAT_CN(bufType); + int width = roi.width, kwidth = ksize.width; + int kheight = ksize.height, ay = anchor.y; + int _dx1 = dx1, _dx2 = dx2; + int width1 = roi.width + kwidth - 1; + int xofs1 = std::min(roi.x, anchor.x); + bool isSep = isSeparable(); + bool makeBorder = (_dx1 > 0 || _dx2 > 0) && rowBorderType != BORDER_CONSTANT; + int dy = 0, i = 0; + + src -= xofs1*esz; + count = std::min(count, remainingInputRows()); + + CV_Assert( src && dst && count > 0 ); + + for(;; dst += dststep*i, dy += i) + { + int dcount = bufRows - ay - startY - rowCount + roi.y; + dcount = dcount > 0 ? dcount : bufRows - kheight + 1; + dcount = std::min(dcount, count); + count -= dcount; + for( ; dcount-- > 0; src += srcstep ) + { + int bi = (startY - startY0 + rowCount) % bufRows; + uchar* brow = alignPtr(&ringBuf[0], VEC_ALIGN) + bi*bufStep; + uchar* row = isSep ? &srcRow[0] : brow; + + if( ++rowCount > bufRows ) + { + --rowCount; + ++startY; + } + + memcpy( row + _dx1*esz, src, (width1 - _dx2 - _dx1)*esz ); + + if( makeBorder ) + { + if( btab_esz*(int)sizeof(int) == esz ) + { + const int* isrc = (const int*)src; + int* irow = (int*)row; + + for( i = 0; i < _dx1*btab_esz; i++ ) + irow[i] = isrc[btab[i]]; + for( i = 0; i < _dx2*btab_esz; i++ ) + irow[i + (width1 - _dx2)*btab_esz] = isrc[btab[i+_dx1*btab_esz]]; + } + else + { + for( i = 0; i < _dx1*esz; i++ ) + row[i] = src[btab[i]]; + for( i = 0; i < _dx2*esz; i++ ) + row[i + (width1 - _dx2)*esz] = src[btab[i+_dx1*esz]]; + } + } + + if( isSep ) + (*rowFilter)(row, brow, width, CV_MAT_CN(srcType)); + } + + int max_i = std::min(bufRows, roi.height - (dstY + dy) + (kheight - 1)); + for( i = 0; i < max_i; i++ ) + { + int srcY = borderInterpolate(dstY + dy + i + roi.y - ay, + wholeSize.height, columnBorderType); + if( srcY < 0 ) // can happen only with constant border type + brows[i] = alignPtr(&constBorderRow[0], VEC_ALIGN); + else + { + CV_Assert( srcY >= startY ); + if( srcY >= startY + rowCount ) + break; + int bi = (srcY - startY0) % bufRows; + brows[i] = alignPtr(&ringBuf[0], VEC_ALIGN) + bi*bufStep; + } + } + if( i < kheight ) + break; + i -= kheight - 1; + if( isSeparable() ) + (*columnFilter)((const uchar**)brows, dst, dststep, i, roi.width*cn); + else + (*filter2D)((const uchar**)brows, dst, dststep, i, roi.width, cn); + } + + dstY += dy; + CV_Assert( dstY <= roi.height ); + return dy; +} + + +void FilterEngine::apply(const Mat& src, Mat& dst, + const Rect& _srcRoi, Point dstOfs, bool isolated) +{ + CV_Assert( src.type() == srcType && dst.type() == dstType ); + + Rect srcRoi = _srcRoi; + if( srcRoi == Rect(0,0,-1,-1) ) + srcRoi = Rect(0,0,src.cols,src.rows); + + if( srcRoi.area() == 0 ) + return; + + CV_Assert( dstOfs.x >= 0 && dstOfs.y >= 0 && + dstOfs.x + srcRoi.width <= dst.cols && + dstOfs.y + srcRoi.height <= dst.rows ); + + int y = start(src, srcRoi, isolated); + proceed( src.data + y*src.step, (int)src.step, endY - startY, + dst.data + dstOfs.y*dst.step + dstOfs.x*dst.elemSize(), (int)dst.step ); +} + +} + +/****************************************************************************************\ +* Separable linear filter * +\****************************************************************************************/ + +int cv::getKernelType(InputArray filter_kernel, Point anchor) +{ + Mat _kernel = filter_kernel.getMat(); + CV_Assert( _kernel.channels() == 1 ); + int i, sz = _kernel.rows*_kernel.cols; + + Mat kernel; + _kernel.convertTo(kernel, CV_64F); + + const double* coeffs = (double*)kernel.data; + double sum = 0; + int type = KERNEL_SMOOTH + KERNEL_INTEGER; + if( (_kernel.rows == 1 || _kernel.cols == 1) && + anchor.x*2 + 1 == _kernel.cols && + anchor.y*2 + 1 == _kernel.rows ) + type |= (KERNEL_SYMMETRICAL + KERNEL_ASYMMETRICAL); + + for( i = 0; i < sz; i++ ) + { + double a = coeffs[i], b = coeffs[sz - i - 1]; + if( a != b ) + type &= ~KERNEL_SYMMETRICAL; + if( a != -b ) + type &= ~KERNEL_ASYMMETRICAL; + if( a < 0 ) + type &= ~KERNEL_SMOOTH; + if( a != saturate_cast(a) ) + type &= ~KERNEL_INTEGER; + sum += a; + } + + if( fabs(sum - 1) > FLT_EPSILON*(fabs(sum) + 1) ) + type &= ~KERNEL_SMOOTH; + return type; +} + + +namespace cv +{ + +struct RowNoVec +{ + RowNoVec() {} + RowNoVec(const Mat&) {} + int operator()(const uchar*, uchar*, int, int) const { return 0; } +}; + +struct ColumnNoVec +{ + ColumnNoVec() {} + ColumnNoVec(const Mat&, int, int, double) {} + int operator()(const uchar**, uchar*, int) const { return 0; } +}; + +struct SymmRowSmallNoVec +{ + SymmRowSmallNoVec() {} + SymmRowSmallNoVec(const Mat&, int) {} + int operator()(const uchar*, uchar*, int, int) const { return 0; } +}; + +struct SymmColumnSmallNoVec +{ + SymmColumnSmallNoVec() {} + SymmColumnSmallNoVec(const Mat&, int, int, double) {} + int operator()(const uchar**, uchar*, int) const { return 0; } +}; + +struct FilterNoVec +{ + FilterNoVec() {} + FilterNoVec(const Mat&, int, double) {} + int operator()(const uchar**, uchar*, int) const { return 0; } +}; + + + +#if CV_SSE2 + +///////////////////////////////////// 8u-16s & 8u-8u ////////////////////////////////// + +struct RowVec_8u32s +{ + RowVec_8u32s() { smallValues = false; } + RowVec_8u32s( const Mat& _kernel ) + { + kernel = _kernel; + smallValues = true; + int k, ksize = kernel.rows + kernel.cols - 1; + for( k = 0; k < ksize; k++ ) + { + int v = ((const int*)kernel.data)[k]; + if( v < SHRT_MIN || v > SHRT_MAX ) + { + smallValues = false; + break; + } + } + } + + int operator()(const uchar* _src, uchar* _dst, int width, int cn) const + { + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + int i = 0, k, _ksize = kernel.rows + kernel.cols - 1; + int* dst = (int*)_dst; + const int* _kx = (const int*)kernel.data; + width *= cn; + + if( smallValues ) + { + for( ; i <= width - 16; i += 16 ) + { + const uchar* src = _src + i; + __m128i f, z = _mm_setzero_si128(), s0 = z, s1 = z, s2 = z, s3 = z; + __m128i x0, x1, x2, x3; + + for( k = 0; k < _ksize; k++, src += cn ) + { + f = _mm_cvtsi32_si128(_kx[k]); + f = _mm_shuffle_epi32(f, 0); + f = _mm_packs_epi32(f, f); + + x0 = _mm_loadu_si128((const __m128i*)src); + x2 = _mm_unpackhi_epi8(x0, z); + x0 = _mm_unpacklo_epi8(x0, z); + x1 = _mm_mulhi_epi16(x0, f); + x3 = _mm_mulhi_epi16(x2, f); + x0 = _mm_mullo_epi16(x0, f); + x2 = _mm_mullo_epi16(x2, f); + + s0 = _mm_add_epi32(s0, _mm_unpacklo_epi16(x0, x1)); + s1 = _mm_add_epi32(s1, _mm_unpackhi_epi16(x0, x1)); + s2 = _mm_add_epi32(s2, _mm_unpacklo_epi16(x2, x3)); + s3 = _mm_add_epi32(s3, _mm_unpackhi_epi16(x2, x3)); + } + + _mm_store_si128((__m128i*)(dst + i), s0); + _mm_store_si128((__m128i*)(dst + i + 4), s1); + _mm_store_si128((__m128i*)(dst + i + 8), s2); + _mm_store_si128((__m128i*)(dst + i + 12), s3); + } + + for( ; i <= width - 4; i += 4 ) + { + const uchar* src = _src + i; + __m128i f, z = _mm_setzero_si128(), s0 = z, x0, x1; + + for( k = 0; k < _ksize; k++, src += cn ) + { + f = _mm_cvtsi32_si128(_kx[k]); + f = _mm_shuffle_epi32(f, 0); + f = _mm_packs_epi32(f, f); + + x0 = _mm_cvtsi32_si128(*(const int*)src); + x0 = _mm_unpacklo_epi8(x0, z); + x1 = _mm_mulhi_epi16(x0, f); + x0 = _mm_mullo_epi16(x0, f); + s0 = _mm_add_epi32(s0, _mm_unpacklo_epi16(x0, x1)); + } + _mm_store_si128((__m128i*)(dst + i), s0); + } + } + return i; + } + + Mat kernel; + bool smallValues; +}; + + +struct SymmRowSmallVec_8u32s +{ + + SymmRowSmallVec_8u32s() { smallValues = false; } + SymmRowSmallVec_8u32s( const Mat& _kernel, int _symmetryType ) + { + kernel = _kernel; + symmetryType = _symmetryType; + smallValues = true; + int k, ksize = kernel.rows + kernel.cols - 1; + for( k = 0; k < ksize; k++ ) + { + int v = ((const int*)kernel.data)[k]; + if( v < SHRT_MIN || v > SHRT_MAX ) + { + smallValues = false; + break; + } + } + } + + int operator()(const uchar* src, uchar* _dst, int width, int cn) const + { + + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + int i = 0, j, k, _ksize = kernel.rows + kernel.cols - 1; + int* dst = (int*)_dst; + bool symmetrical = (symmetryType & KERNEL_SYMMETRICAL) != 0; + const int* kx = (const int*)kernel.data + _ksize/2; + if( !smallValues ) + return 0; + + src += (_ksize/2)*cn; + width *= cn; + + __m128i z = _mm_setzero_si128(); + if( symmetrical ) + { + if( _ksize == 1 ) + return 0; + if( _ksize == 3 ) + { + if( kx[0] == 2 && kx[1] == 1 ) + for( ; i <= width - 16; i += 16, src += 16 ) + { + __m128i x0, x1, x2, y0, y1, y2; + x0 = _mm_loadu_si128((__m128i*)(src - cn)); + x1 = _mm_loadu_si128((__m128i*)src); + x2 = _mm_loadu_si128((__m128i*)(src + cn)); + y0 = _mm_unpackhi_epi8(x0, z); + x0 = _mm_unpacklo_epi8(x0, z); + y1 = _mm_unpackhi_epi8(x1, z); + x1 = _mm_unpacklo_epi8(x1, z); + y2 = _mm_unpackhi_epi8(x2, z); + x2 = _mm_unpacklo_epi8(x2, z); + x0 = _mm_add_epi16(x0, _mm_add_epi16(_mm_add_epi16(x1, x1), x2)); + y0 = _mm_add_epi16(y0, _mm_add_epi16(_mm_add_epi16(y1, y1), y2)); + _mm_store_si128((__m128i*)(dst + i), _mm_unpacklo_epi16(x0, z)); + _mm_store_si128((__m128i*)(dst + i + 4), _mm_unpackhi_epi16(x0, z)); + _mm_store_si128((__m128i*)(dst + i + 8), _mm_unpacklo_epi16(y0, z)); + _mm_store_si128((__m128i*)(dst + i + 12), _mm_unpackhi_epi16(y0, z)); + } + else if( kx[0] == -2 && kx[1] == 1 ) + for( ; i <= width - 16; i += 16, src += 16 ) + { + __m128i x0, x1, x2, y0, y1, y2; + x0 = _mm_loadu_si128((__m128i*)(src - cn)); + x1 = _mm_loadu_si128((__m128i*)src); + x2 = _mm_loadu_si128((__m128i*)(src + cn)); + y0 = _mm_unpackhi_epi8(x0, z); + x0 = _mm_unpacklo_epi8(x0, z); + y1 = _mm_unpackhi_epi8(x1, z); + x1 = _mm_unpacklo_epi8(x1, z); + y2 = _mm_unpackhi_epi8(x2, z); + x2 = _mm_unpacklo_epi8(x2, z); + x0 = _mm_add_epi16(x0, _mm_sub_epi16(x2, _mm_add_epi16(x1, x1))); + y0 = _mm_add_epi16(y0, _mm_sub_epi16(y2, _mm_add_epi16(y1, y1))); + _mm_store_si128((__m128i*)(dst + i), _mm_srai_epi32(_mm_unpacklo_epi16(x0, x0),16)); + _mm_store_si128((__m128i*)(dst + i + 4), _mm_srai_epi32(_mm_unpackhi_epi16(x0, x0),16)); + _mm_store_si128((__m128i*)(dst + i + 8), _mm_srai_epi32(_mm_unpacklo_epi16(y0, y0),16)); + _mm_store_si128((__m128i*)(dst + i + 12), _mm_srai_epi32(_mm_unpackhi_epi16(y0, y0),16)); + } + else + { + __m128i k0 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[0]), 0), + k1 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[1]), 0); + k0 = _mm_packs_epi32(k0, k0); + k1 = _mm_packs_epi32(k1, k1); + + for( ; i <= width - 16; i += 16, src += 16 ) + { + __m128i x0, x1, x2, y0, y1, t0, t1, z0, z1, z2, z3; + x0 = _mm_loadu_si128((__m128i*)(src - cn)); + x1 = _mm_loadu_si128((__m128i*)src); + x2 = _mm_loadu_si128((__m128i*)(src + cn)); + y0 = _mm_add_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x2, z)); + x0 = _mm_add_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x2, z)); + y1 = _mm_unpackhi_epi8(x1, z); + x1 = _mm_unpacklo_epi8(x1, z); + + t1 = _mm_mulhi_epi16(x1, k0); + t0 = _mm_mullo_epi16(x1, k0); + x2 = _mm_mulhi_epi16(x0, k1); + x0 = _mm_mullo_epi16(x0, k1); + z0 = _mm_unpacklo_epi16(t0, t1); + z1 = _mm_unpackhi_epi16(t0, t1); + z0 = _mm_add_epi32(z0, _mm_unpacklo_epi16(x0, x2)); + z1 = _mm_add_epi32(z1, _mm_unpackhi_epi16(x0, x2)); + + t1 = _mm_mulhi_epi16(y1, k0); + t0 = _mm_mullo_epi16(y1, k0); + y1 = _mm_mulhi_epi16(y0, k1); + y0 = _mm_mullo_epi16(y0, k1); + z2 = _mm_unpacklo_epi16(t0, t1); + z3 = _mm_unpackhi_epi16(t0, t1); + z2 = _mm_add_epi32(z2, _mm_unpacklo_epi16(y0, y1)); + z3 = _mm_add_epi32(z3, _mm_unpackhi_epi16(y0, y1)); + _mm_store_si128((__m128i*)(dst + i), z0); + _mm_store_si128((__m128i*)(dst + i + 4), z1); + _mm_store_si128((__m128i*)(dst + i + 8), z2); + _mm_store_si128((__m128i*)(dst + i + 12), z3); + } + } + } + else if( _ksize == 5 ) + { + if( kx[0] == -2 && kx[1] == 0 && kx[2] == 1 ) + for( ; i <= width - 16; i += 16, src += 16 ) + { + __m128i x0, x1, x2, y0, y1, y2; + x0 = _mm_loadu_si128((__m128i*)(src - cn*2)); + x1 = _mm_loadu_si128((__m128i*)src); + x2 = _mm_loadu_si128((__m128i*)(src + cn*2)); + y0 = _mm_unpackhi_epi8(x0, z); + x0 = _mm_unpacklo_epi8(x0, z); + y1 = _mm_unpackhi_epi8(x1, z); + x1 = _mm_unpacklo_epi8(x1, z); + y2 = _mm_unpackhi_epi8(x2, z); + x2 = _mm_unpacklo_epi8(x2, z); + x0 = _mm_add_epi16(x0, _mm_sub_epi16(x2, _mm_add_epi16(x1, x1))); + y0 = _mm_add_epi16(y0, _mm_sub_epi16(y2, _mm_add_epi16(y1, y1))); + _mm_store_si128((__m128i*)(dst + i), _mm_srai_epi32(_mm_unpacklo_epi16(x0, x0),16)); + _mm_store_si128((__m128i*)(dst + i + 4), _mm_srai_epi32(_mm_unpackhi_epi16(x0, x0),16)); + _mm_store_si128((__m128i*)(dst + i + 8), _mm_srai_epi32(_mm_unpacklo_epi16(y0, y0),16)); + _mm_store_si128((__m128i*)(dst + i + 12), _mm_srai_epi32(_mm_unpackhi_epi16(y0, y0),16)); + } + else + { + __m128i k0 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[0]), 0), + k1 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[1]), 0), + k2 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[2]), 0); + k0 = _mm_packs_epi32(k0, k0); + k1 = _mm_packs_epi32(k1, k1); + k2 = _mm_packs_epi32(k2, k2); + + for( ; i <= width - 16; i += 16, src += 16 ) + { + __m128i x0, x1, x2, y0, y1, t0, t1, z0, z1, z2, z3; + x0 = _mm_loadu_si128((__m128i*)(src - cn)); + x1 = _mm_loadu_si128((__m128i*)src); + x2 = _mm_loadu_si128((__m128i*)(src + cn)); + y0 = _mm_add_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x2, z)); + x0 = _mm_add_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x2, z)); + y1 = _mm_unpackhi_epi8(x1, z); + x1 = _mm_unpacklo_epi8(x1, z); + + t1 = _mm_mulhi_epi16(x1, k0); + t0 = _mm_mullo_epi16(x1, k0); + x2 = _mm_mulhi_epi16(x0, k1); + x0 = _mm_mullo_epi16(x0, k1); + z0 = _mm_unpacklo_epi16(t0, t1); + z1 = _mm_unpackhi_epi16(t0, t1); + z0 = _mm_add_epi32(z0, _mm_unpacklo_epi16(x0, x2)); + z1 = _mm_add_epi32(z1, _mm_unpackhi_epi16(x0, x2)); + + t1 = _mm_mulhi_epi16(y1, k0); + t0 = _mm_mullo_epi16(y1, k0); + y1 = _mm_mulhi_epi16(y0, k1); + y0 = _mm_mullo_epi16(y0, k1); + z2 = _mm_unpacklo_epi16(t0, t1); + z3 = _mm_unpackhi_epi16(t0, t1); + z2 = _mm_add_epi32(z2, _mm_unpacklo_epi16(y0, y1)); + z3 = _mm_add_epi32(z3, _mm_unpackhi_epi16(y0, y1)); + + x0 = _mm_loadu_si128((__m128i*)(src - cn*2)); + x1 = _mm_loadu_si128((__m128i*)(src + cn*2)); + y1 = _mm_add_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x1, z)); + y0 = _mm_add_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x1, z)); + + t1 = _mm_mulhi_epi16(y0, k2); + t0 = _mm_mullo_epi16(y0, k2); + y0 = _mm_mullo_epi16(y1, k2); + y1 = _mm_mulhi_epi16(y1, k2); + z0 = _mm_add_epi32(z0, _mm_unpacklo_epi16(t0, t1)); + z1 = _mm_add_epi32(z1, _mm_unpackhi_epi16(t0, t1)); + z2 = _mm_add_epi32(z2, _mm_unpacklo_epi16(y0, y1)); + z3 = _mm_add_epi32(z3, _mm_unpackhi_epi16(y0, y1)); + + _mm_store_si128((__m128i*)(dst + i), z0); + _mm_store_si128((__m128i*)(dst + i + 4), z1); + _mm_store_si128((__m128i*)(dst + i + 8), z2); + _mm_store_si128((__m128i*)(dst + i + 12), z3); + } + } + } + } + else + { + if( _ksize == 3 ) + { + if( kx[0] == 0 && kx[1] == 1 ) + for( ; i <= width - 16; i += 16, src += 16 ) + { + __m128i x0, x1, y0; + x0 = _mm_loadu_si128((__m128i*)(src + cn)); + x1 = _mm_loadu_si128((__m128i*)(src - cn)); + y0 = _mm_sub_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x1, z)); + x0 = _mm_sub_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x1, z)); + _mm_store_si128((__m128i*)(dst + i), _mm_srai_epi32(_mm_unpacklo_epi16(x0, x0),16)); + _mm_store_si128((__m128i*)(dst + i + 4), _mm_srai_epi32(_mm_unpackhi_epi16(x0, x0),16)); + _mm_store_si128((__m128i*)(dst + i + 8), _mm_srai_epi32(_mm_unpacklo_epi16(y0, y0),16)); + _mm_store_si128((__m128i*)(dst + i + 12), _mm_srai_epi32(_mm_unpackhi_epi16(y0, y0),16)); + } + else + { + __m128i k1 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[1]), 0); + k1 = _mm_packs_epi32(k1, k1); + + for( ; i <= width - 16; i += 16, src += 16 ) + { + __m128i x0, x1, y0, y1, z0, z1, z2, z3; + x0 = _mm_loadu_si128((__m128i*)(src + cn)); + x1 = _mm_loadu_si128((__m128i*)(src - cn)); + y0 = _mm_sub_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x1, z)); + x0 = _mm_sub_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x1, z)); + + x1 = _mm_mulhi_epi16(x0, k1); + x0 = _mm_mullo_epi16(x0, k1); + z0 = _mm_unpacklo_epi16(x0, x1); + z1 = _mm_unpackhi_epi16(x0, x1); + + y1 = _mm_mulhi_epi16(y0, k1); + y0 = _mm_mullo_epi16(y0, k1); + z2 = _mm_unpacklo_epi16(y0, y1); + z3 = _mm_unpackhi_epi16(y0, y1); + _mm_store_si128((__m128i*)(dst + i), z0); + _mm_store_si128((__m128i*)(dst + i + 4), z1); + _mm_store_si128((__m128i*)(dst + i + 8), z2); + _mm_store_si128((__m128i*)(dst + i + 12), z3); + } + } + } + else if( _ksize == 5 ) + { + __m128i k0 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[0]), 0), + k1 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[1]), 0), + k2 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[2]), 0); + k0 = _mm_packs_epi32(k0, k0); + k1 = _mm_packs_epi32(k1, k1); + k2 = _mm_packs_epi32(k2, k2); + + for( ; i <= width - 16; i += 16, src += 16 ) + { + __m128i x0, x1, x2, y0, y1, t0, t1, z0, z1, z2, z3; + x0 = _mm_loadu_si128((__m128i*)(src + cn)); + x2 = _mm_loadu_si128((__m128i*)(src - cn)); + y0 = _mm_sub_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x2, z)); + x0 = _mm_sub_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x2, z)); + + x2 = _mm_mulhi_epi16(x0, k1); + x0 = _mm_mullo_epi16(x0, k1); + z0 = _mm_unpacklo_epi16(x0, x2); + z1 = _mm_unpackhi_epi16(x0, x2); + y1 = _mm_mulhi_epi16(y0, k1); + y0 = _mm_mullo_epi16(y0, k1); + z2 = _mm_unpacklo_epi16(y0, y1); + z3 = _mm_unpackhi_epi16(y0, y1); + + x0 = _mm_loadu_si128((__m128i*)(src + cn*2)); + x1 = _mm_loadu_si128((__m128i*)(src - cn*2)); + y1 = _mm_sub_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x1, z)); + y0 = _mm_sub_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x1, z)); + + t1 = _mm_mulhi_epi16(y0, k2); + t0 = _mm_mullo_epi16(y0, k2); + y0 = _mm_mullo_epi16(y1, k2); + y1 = _mm_mulhi_epi16(y1, k2); + z0 = _mm_add_epi32(z0, _mm_unpacklo_epi16(t0, t1)); + z1 = _mm_add_epi32(z1, _mm_unpackhi_epi16(t0, t1)); + z2 = _mm_add_epi32(z2, _mm_unpacklo_epi16(y0, y1)); + z3 = _mm_add_epi32(z3, _mm_unpackhi_epi16(y0, y1)); + + _mm_store_si128((__m128i*)(dst + i), z0); + _mm_store_si128((__m128i*)(dst + i + 4), z1); + _mm_store_si128((__m128i*)(dst + i + 8), z2); + _mm_store_si128((__m128i*)(dst + i + 12), z3); + } + } + } + + src -= (_ksize/2)*cn; + kx -= _ksize/2; + for( ; i <= width - 4; i += 4, src += 4 ) + { + __m128i f, s0 = z, x0, x1; + + for( k = j = 0; k < _ksize; k++, j += cn ) + { + f = _mm_cvtsi32_si128(kx[k]); + f = _mm_shuffle_epi32(f, 0); + f = _mm_packs_epi32(f, f); + + x0 = _mm_cvtsi32_si128(*(const int*)(src + j)); + x0 = _mm_unpacklo_epi8(x0, z); + x1 = _mm_mulhi_epi16(x0, f); + x0 = _mm_mullo_epi16(x0, f); + s0 = _mm_add_epi32(s0, _mm_unpacklo_epi16(x0, x1)); + } + _mm_store_si128((__m128i*)(dst + i), s0); + } + + return i; + } + + Mat kernel; + int symmetryType; + bool smallValues; +}; + + +struct SymmColumnVec_32s8u +{ + SymmColumnVec_32s8u() { symmetryType=0; } + SymmColumnVec_32s8u(const Mat& _kernel, int _symmetryType, int _bits, double _delta) + { + symmetryType = _symmetryType; + _kernel.convertTo(kernel, CV_32F, 1./(1 << _bits), 0); + delta = (float)(_delta/(1 << _bits)); + CV_Assert( (symmetryType & (KERNEL_SYMMETRICAL | KERNEL_ASYMMETRICAL)) != 0 ); + } + + int operator()(const uchar** _src, uchar* dst, int width) const + { + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + int ksize2 = (kernel.rows + kernel.cols - 1)/2; + const float* ky = (const float*)kernel.data + ksize2; + int i = 0, k; + bool symmetrical = (symmetryType & KERNEL_SYMMETRICAL) != 0; + const int** src = (const int**)_src; + const __m128i *S, *S2; + __m128 d4 = _mm_set1_ps(delta); + + if( symmetrical ) + { + for( ; i <= width - 16; i += 16 ) + { + __m128 f = _mm_load_ss(ky); + f = _mm_shuffle_ps(f, f, 0); + __m128 s0, s1, s2, s3; + __m128i x0, x1; + S = (const __m128i*)(src[0] + i); + s0 = _mm_cvtepi32_ps(_mm_load_si128(S)); + s1 = _mm_cvtepi32_ps(_mm_load_si128(S+1)); + s0 = _mm_add_ps(_mm_mul_ps(s0, f), d4); + s1 = _mm_add_ps(_mm_mul_ps(s1, f), d4); + s2 = _mm_cvtepi32_ps(_mm_load_si128(S+2)); + s3 = _mm_cvtepi32_ps(_mm_load_si128(S+3)); + s2 = _mm_add_ps(_mm_mul_ps(s2, f), d4); + s3 = _mm_add_ps(_mm_mul_ps(s3, f), d4); + + for( k = 1; k <= ksize2; k++ ) + { + S = (const __m128i*)(src[k] + i); + S2 = (const __m128i*)(src[-k] + i); + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_add_epi32(_mm_load_si128(S), _mm_load_si128(S2)); + x1 = _mm_add_epi32(_mm_load_si128(S+1), _mm_load_si128(S2+1)); + s0 = _mm_add_ps(s0, _mm_mul_ps(_mm_cvtepi32_ps(x0), f)); + s1 = _mm_add_ps(s1, _mm_mul_ps(_mm_cvtepi32_ps(x1), f)); + x0 = _mm_add_epi32(_mm_load_si128(S+2), _mm_load_si128(S2+2)); + x1 = _mm_add_epi32(_mm_load_si128(S+3), _mm_load_si128(S2+3)); + s2 = _mm_add_ps(s2, _mm_mul_ps(_mm_cvtepi32_ps(x0), f)); + s3 = _mm_add_ps(s3, _mm_mul_ps(_mm_cvtepi32_ps(x1), f)); + } + + x0 = _mm_packs_epi32(_mm_cvtps_epi32(s0), _mm_cvtps_epi32(s1)); + x1 = _mm_packs_epi32(_mm_cvtps_epi32(s2), _mm_cvtps_epi32(s3)); + x0 = _mm_packus_epi16(x0, x1); + _mm_storeu_si128((__m128i*)(dst + i), x0); + } + + for( ; i <= width - 4; i += 4 ) + { + __m128 f = _mm_load_ss(ky); + f = _mm_shuffle_ps(f, f, 0); + __m128i x0; + __m128 s0 = _mm_cvtepi32_ps(_mm_load_si128((const __m128i*)(src[0] + i))); + s0 = _mm_add_ps(_mm_mul_ps(s0, f), d4); + + for( k = 1; k <= ksize2; k++ ) + { + S = (const __m128i*)(src[k] + i); + S2 = (const __m128i*)(src[-k] + i); + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_add_epi32(_mm_load_si128(S), _mm_load_si128(S2)); + s0 = _mm_add_ps(s0, _mm_mul_ps(_mm_cvtepi32_ps(x0), f)); + } + + x0 = _mm_cvtps_epi32(s0); + x0 = _mm_packs_epi32(x0, x0); + x0 = _mm_packus_epi16(x0, x0); + *(int*)(dst + i) = _mm_cvtsi128_si32(x0); + } + } + else + { + for( ; i <= width - 16; i += 16 ) + { + __m128 f, s0 = d4, s1 = d4, s2 = d4, s3 = d4; + __m128i x0, x1; + + for( k = 1; k <= ksize2; k++ ) + { + S = (const __m128i*)(src[k] + i); + S2 = (const __m128i*)(src[-k] + i); + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_sub_epi32(_mm_load_si128(S), _mm_load_si128(S2)); + x1 = _mm_sub_epi32(_mm_load_si128(S+1), _mm_load_si128(S2+1)); + s0 = _mm_add_ps(s0, _mm_mul_ps(_mm_cvtepi32_ps(x0), f)); + s1 = _mm_add_ps(s1, _mm_mul_ps(_mm_cvtepi32_ps(x1), f)); + x0 = _mm_sub_epi32(_mm_load_si128(S+2), _mm_load_si128(S2+2)); + x1 = _mm_sub_epi32(_mm_load_si128(S+3), _mm_load_si128(S2+3)); + s2 = _mm_add_ps(s2, _mm_mul_ps(_mm_cvtepi32_ps(x0), f)); + s3 = _mm_add_ps(s3, _mm_mul_ps(_mm_cvtepi32_ps(x1), f)); + } + + x0 = _mm_packs_epi32(_mm_cvtps_epi32(s0), _mm_cvtps_epi32(s1)); + x1 = _mm_packs_epi32(_mm_cvtps_epi32(s2), _mm_cvtps_epi32(s3)); + x0 = _mm_packus_epi16(x0, x1); + _mm_storeu_si128((__m128i*)(dst + i), x0); + } + + for( ; i <= width - 4; i += 4 ) + { + __m128 f, s0 = d4; + __m128i x0; + + for( k = 1; k <= ksize2; k++ ) + { + S = (const __m128i*)(src[k] + i); + S2 = (const __m128i*)(src[-k] + i); + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_sub_epi32(_mm_load_si128(S), _mm_load_si128(S2)); + s0 = _mm_add_ps(s0, _mm_mul_ps(_mm_cvtepi32_ps(x0), f)); + } + + x0 = _mm_cvtps_epi32(s0); + x0 = _mm_packs_epi32(x0, x0); + x0 = _mm_packus_epi16(x0, x0); + *(int*)(dst + i) = _mm_cvtsi128_si32(x0); + } + } + + return i; + } + + int symmetryType; + float delta; + Mat kernel; +}; + + +struct SymmColumnSmallVec_32s16s +{ + SymmColumnSmallVec_32s16s() { symmetryType=0; } + SymmColumnSmallVec_32s16s(const Mat& _kernel, int _symmetryType, int _bits, double _delta) + { + symmetryType = _symmetryType; + _kernel.convertTo(kernel, CV_32F, 1./(1 << _bits), 0); + delta = (float)(_delta/(1 << _bits)); + CV_Assert( (symmetryType & (KERNEL_SYMMETRICAL | KERNEL_ASYMMETRICAL)) != 0 ); + } + + int operator()(const uchar** _src, uchar* _dst, int width) const + { + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + int ksize2 = (kernel.rows + kernel.cols - 1)/2; + const float* ky = (const float*)kernel.data + ksize2; + int i = 0; + bool symmetrical = (symmetryType & KERNEL_SYMMETRICAL) != 0; + const int** src = (const int**)_src; + const int *S0 = src[-1], *S1 = src[0], *S2 = src[1]; + short* dst = (short*)_dst; + __m128 df4 = _mm_set1_ps(delta); + __m128i d4 = _mm_cvtps_epi32(df4); + + if( symmetrical ) + { + if( ky[0] == 2 && ky[1] == 1 ) + { + for( ; i <= width - 8; i += 8 ) + { + __m128i s0, s1, s2, s3, s4, s5; + s0 = _mm_load_si128((__m128i*)(S0 + i)); + s1 = _mm_load_si128((__m128i*)(S0 + i + 4)); + s2 = _mm_load_si128((__m128i*)(S1 + i)); + s3 = _mm_load_si128((__m128i*)(S1 + i + 4)); + s4 = _mm_load_si128((__m128i*)(S2 + i)); + s5 = _mm_load_si128((__m128i*)(S2 + i + 4)); + s0 = _mm_add_epi32(s0, _mm_add_epi32(s4, _mm_add_epi32(s2, s2))); + s1 = _mm_add_epi32(s1, _mm_add_epi32(s5, _mm_add_epi32(s3, s3))); + s0 = _mm_add_epi32(s0, d4); + s1 = _mm_add_epi32(s1, d4); + _mm_storeu_si128((__m128i*)(dst + i), _mm_packs_epi32(s0, s1)); + } + } + else if( ky[0] == -2 && ky[1] == 1 ) + { + for( ; i <= width - 8; i += 8 ) + { + __m128i s0, s1, s2, s3, s4, s5; + s0 = _mm_load_si128((__m128i*)(S0 + i)); + s1 = _mm_load_si128((__m128i*)(S0 + i + 4)); + s2 = _mm_load_si128((__m128i*)(S1 + i)); + s3 = _mm_load_si128((__m128i*)(S1 + i + 4)); + s4 = _mm_load_si128((__m128i*)(S2 + i)); + s5 = _mm_load_si128((__m128i*)(S2 + i + 4)); + s0 = _mm_add_epi32(s0, _mm_sub_epi32(s4, _mm_add_epi32(s2, s2))); + s1 = _mm_add_epi32(s1, _mm_sub_epi32(s5, _mm_add_epi32(s3, s3))); + s0 = _mm_add_epi32(s0, d4); + s1 = _mm_add_epi32(s1, d4); + _mm_storeu_si128((__m128i*)(dst + i), _mm_packs_epi32(s0, s1)); + } + } + else + { + __m128 k0 = _mm_set1_ps(ky[0]), k1 = _mm_set1_ps(ky[1]); + for( ; i <= width - 8; i += 8 ) + { + __m128 s0, s1; + s0 = _mm_cvtepi32_ps(_mm_load_si128((__m128i*)(S1 + i))); + s1 = _mm_cvtepi32_ps(_mm_load_si128((__m128i*)(S1 + i + 4))); + s0 = _mm_add_ps(_mm_mul_ps(s0, k0), df4); + s1 = _mm_add_ps(_mm_mul_ps(s1, k0), df4); + __m128i x0, x1; + x0 = _mm_add_epi32(_mm_load_si128((__m128i*)(S0 + i)), + _mm_load_si128((__m128i*)(S2 + i))); + x1 = _mm_add_epi32(_mm_load_si128((__m128i*)(S0 + i + 4)), + _mm_load_si128((__m128i*)(S2 + i + 4))); + s0 = _mm_add_ps(s0, _mm_mul_ps(_mm_cvtepi32_ps(x0),k1)); + s1 = _mm_add_ps(s1, _mm_mul_ps(_mm_cvtepi32_ps(x1),k1)); + x0 = _mm_packs_epi32(_mm_cvtps_epi32(s0), _mm_cvtps_epi32(s1)); + _mm_storeu_si128((__m128i*)(dst + i), x0); + } + } + } + else + { + if( fabs(ky[1]) == 1 && ky[1] == -ky[-1] ) + { + if( ky[1] < 0 ) + std::swap(S0, S2); + for( ; i <= width - 8; i += 8 ) + { + __m128i s0, s1, s2, s3; + s0 = _mm_load_si128((__m128i*)(S2 + i)); + s1 = _mm_load_si128((__m128i*)(S2 + i + 4)); + s2 = _mm_load_si128((__m128i*)(S0 + i)); + s3 = _mm_load_si128((__m128i*)(S0 + i + 4)); + s0 = _mm_add_epi32(_mm_sub_epi32(s0, s2), d4); + s1 = _mm_add_epi32(_mm_sub_epi32(s1, s3), d4); + _mm_storeu_si128((__m128i*)(dst + i), _mm_packs_epi32(s0, s1)); + } + } + else + { + __m128 k1 = _mm_set1_ps(ky[1]); + for( ; i <= width - 8; i += 8 ) + { + __m128 s0 = df4, s1 = df4; + __m128i x0, x1; + x0 = _mm_sub_epi32(_mm_load_si128((__m128i*)(S0 + i)), + _mm_load_si128((__m128i*)(S2 + i))); + x1 = _mm_sub_epi32(_mm_load_si128((__m128i*)(S0 + i + 4)), + _mm_load_si128((__m128i*)(S2 + i + 4))); + s0 = _mm_add_ps(s0, _mm_mul_ps(_mm_cvtepi32_ps(x0),k1)); + s1 = _mm_add_ps(s1, _mm_mul_ps(_mm_cvtepi32_ps(x1),k1)); + x0 = _mm_packs_epi32(_mm_cvtps_epi32(s0), _mm_cvtps_epi32(s1)); + _mm_storeu_si128((__m128i*)(dst + i), x0); + } + } + } + + return i; + } + + int symmetryType; + float delta; + Mat kernel; +}; + + +/////////////////////////////////////// 16s ////////////////////////////////// + +struct RowVec_16s32f +{ + RowVec_16s32f() {} + RowVec_16s32f( const Mat& _kernel ) + { + kernel = _kernel; + sse2_supported = checkHardwareSupport(CV_CPU_SSE2); + } + + int operator()(const uchar* _src, uchar* _dst, int width, int cn) const + { + + + if( !sse2_supported ) + return 0; + + int i = 0, k, _ksize = kernel.rows + kernel.cols - 1; + float* dst = (float*)_dst; + const float* _kx = (const float*)kernel.data; + width *= cn; + + for( ; i <= width - 8; i += 8 ) + { + const short* src = (const short*)_src + i; + __m128 f, s0 = _mm_setzero_ps(), s1 = s0, x0, x1; + for( k = 0; k < _ksize; k++, src += cn ) + { + f = _mm_load_ss(_kx+k); + f = _mm_shuffle_ps(f, f, 0); + + __m128i x0i = _mm_loadu_si128((const __m128i*)src); + __m128i x1i = _mm_srai_epi32(_mm_unpackhi_epi16(x0i, x0i), 16); + x0i = _mm_srai_epi32(_mm_unpacklo_epi16(x0i, x0i), 16); + x0 = _mm_cvtepi32_ps(x0i); + x1 = _mm_cvtepi32_ps(x1i); + s0 = _mm_add_ps(s0, _mm_mul_ps(x0, f)); + s1 = _mm_add_ps(s1, _mm_mul_ps(x1, f)); + } + _mm_store_ps(dst + i, s0); + _mm_store_ps(dst + i + 4, s1); + } + return i; + } + + Mat kernel; + bool sse2_supported; + + +}; + + +struct SymmColumnVec_32f16s +{ + SymmColumnVec_32f16s() { symmetryType=0; } + SymmColumnVec_32f16s(const Mat& _kernel, int _symmetryType, int, double _delta) + { + symmetryType = _symmetryType; + kernel = _kernel; + delta = (float)_delta; + CV_Assert( (symmetryType & (KERNEL_SYMMETRICAL | KERNEL_ASYMMETRICAL)) != 0 ); + sse2_supported = checkHardwareSupport(CV_CPU_SSE2); + } + + int operator()(const uchar** _src, uchar* _dst, int width) const + { + if( !sse2_supported ) + return 0; + + int ksize2 = (kernel.rows + kernel.cols - 1)/2; + const float* ky = (const float*)kernel.data + ksize2; + int i = 0, k; + bool symmetrical = (symmetryType & KERNEL_SYMMETRICAL) != 0; + const float** src = (const float**)_src; + const float *S, *S2; + short* dst = (short*)_dst; + __m128 d4 = _mm_set1_ps(delta); + + if( symmetrical ) + { + for( ; i <= width - 16; i += 16 ) + { + __m128 f = _mm_load_ss(ky); + f = _mm_shuffle_ps(f, f, 0); + __m128 s0, s1, s2, s3; + __m128 x0, x1; + S = src[0] + i; + s0 = _mm_load_ps(S); + s1 = _mm_load_ps(S+4); + s0 = _mm_add_ps(_mm_mul_ps(s0, f), d4); + s1 = _mm_add_ps(_mm_mul_ps(s1, f), d4); + s2 = _mm_load_ps(S+8); + s3 = _mm_load_ps(S+12); + s2 = _mm_add_ps(_mm_mul_ps(s2, f), d4); + s3 = _mm_add_ps(_mm_mul_ps(s3, f), d4); + + for( k = 1; k <= ksize2; k++ ) + { + S = src[k] + i; + S2 = src[-k] + i; + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_add_ps(_mm_load_ps(S), _mm_load_ps(S2)); + x1 = _mm_add_ps(_mm_load_ps(S+4), _mm_load_ps(S2+4)); + s0 = _mm_add_ps(s0, _mm_mul_ps(x0, f)); + s1 = _mm_add_ps(s1, _mm_mul_ps(x1, f)); + x0 = _mm_add_ps(_mm_load_ps(S+8), _mm_load_ps(S2+8)); + x1 = _mm_add_ps(_mm_load_ps(S+12), _mm_load_ps(S2+12)); + s2 = _mm_add_ps(s2, _mm_mul_ps(x0, f)); + s3 = _mm_add_ps(s3, _mm_mul_ps(x1, f)); + } + + __m128i s0i = _mm_cvtps_epi32(s0); + __m128i s1i = _mm_cvtps_epi32(s1); + __m128i s2i = _mm_cvtps_epi32(s2); + __m128i s3i = _mm_cvtps_epi32(s3); + + _mm_storeu_si128((__m128i*)(dst + i), _mm_packs_epi32(s0i, s1i)); + _mm_storeu_si128((__m128i*)(dst + i + 8), _mm_packs_epi32(s2i, s3i)); + } + + for( ; i <= width - 4; i += 4 ) + { + __m128 f = _mm_load_ss(ky); + f = _mm_shuffle_ps(f, f, 0); + __m128 x0, s0 = _mm_load_ps(src[0] + i); + s0 = _mm_add_ps(_mm_mul_ps(s0, f), d4); + + for( k = 1; k <= ksize2; k++ ) + { + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + S = src[k] + i; + S2 = src[-k] + i; + x0 = _mm_add_ps(_mm_load_ps(src[k]+i), _mm_load_ps(src[-k] + i)); + s0 = _mm_add_ps(s0, _mm_mul_ps(x0, f)); + } + + __m128i s0i = _mm_cvtps_epi32(s0); + _mm_storel_epi64((__m128i*)(dst + i), _mm_packs_epi32(s0i, s0i)); + } + } + else + { + for( ; i <= width - 16; i += 16 ) + { + __m128 f, s0 = d4, s1 = d4, s2 = d4, s3 = d4; + __m128 x0, x1; + S = src[0] + i; + + for( k = 1; k <= ksize2; k++ ) + { + S = src[k] + i; + S2 = src[-k] + i; + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_sub_ps(_mm_load_ps(S), _mm_load_ps(S2)); + x1 = _mm_sub_ps(_mm_load_ps(S+4), _mm_load_ps(S2+4)); + s0 = _mm_add_ps(s0, _mm_mul_ps(x0, f)); + s1 = _mm_add_ps(s1, _mm_mul_ps(x1, f)); + x0 = _mm_sub_ps(_mm_load_ps(S+8), _mm_load_ps(S2+8)); + x1 = _mm_sub_ps(_mm_load_ps(S+12), _mm_load_ps(S2+12)); + s2 = _mm_add_ps(s2, _mm_mul_ps(x0, f)); + s3 = _mm_add_ps(s3, _mm_mul_ps(x1, f)); + } + + __m128i s0i = _mm_cvtps_epi32(s0); + __m128i s1i = _mm_cvtps_epi32(s1); + __m128i s2i = _mm_cvtps_epi32(s2); + __m128i s3i = _mm_cvtps_epi32(s3); + + _mm_storeu_si128((__m128i*)(dst + i), _mm_packs_epi32(s0i, s1i)); + _mm_storeu_si128((__m128i*)(dst + i + 8), _mm_packs_epi32(s2i, s3i)); + } + + for( ; i <= width - 4; i += 4 ) + { + __m128 f, x0, s0 = d4; + + for( k = 1; k <= ksize2; k++ ) + { + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_sub_ps(_mm_load_ps(src[k]+i), _mm_load_ps(src[-k] + i)); + s0 = _mm_add_ps(s0, _mm_mul_ps(x0, f)); + } + + __m128i s0i = _mm_cvtps_epi32(s0); + _mm_storel_epi64((__m128i*)(dst + i), _mm_packs_epi32(s0i, s0i)); + } + } + + return i; + } + + int symmetryType; + float delta; + Mat kernel; + bool sse2_supported; +}; + + +/////////////////////////////////////// 32f ////////////////////////////////// + +struct RowVec_32f +{ + RowVec_32f() {} + RowVec_32f( const Mat& _kernel ) + { + kernel = _kernel; + } + + int operator()(const uchar* _src, uchar* _dst, int width, int cn) const + { + if( !checkHardwareSupport(CV_CPU_SSE) ) + return 0; + + int i = 0, k, _ksize = kernel.rows + kernel.cols - 1; + float* dst = (float*)_dst; + const float* _kx = (const float*)kernel.data; + width *= cn; + + for( ; i <= width - 8; i += 8 ) + { + const float* src = (const float*)_src + i; + __m128 f, s0 = _mm_setzero_ps(), s1 = s0, x0, x1; + for( k = 0; k < _ksize; k++, src += cn ) + { + f = _mm_load_ss(_kx+k); + f = _mm_shuffle_ps(f, f, 0); + + x0 = _mm_loadu_ps(src); + x1 = _mm_loadu_ps(src + 4); + s0 = _mm_add_ps(s0, _mm_mul_ps(x0, f)); + s1 = _mm_add_ps(s1, _mm_mul_ps(x1, f)); + } + _mm_store_ps(dst + i, s0); + _mm_store_ps(dst + i + 4, s1); + } + return i; + } + + Mat kernel; +}; + + +struct SymmRowSmallVec_32f +{ + SymmRowSmallVec_32f() {} + SymmRowSmallVec_32f( const Mat& _kernel, int _symmetryType ) + { + kernel = _kernel; + symmetryType = _symmetryType; + } + + int operator()(const uchar* _src, uchar* _dst, int width, int cn) const + { + if( !checkHardwareSupport(CV_CPU_SSE) ) + return 0; + + int i = 0, _ksize = kernel.rows + kernel.cols - 1; + float* dst = (float*)_dst; + const float* src = (const float*)_src + (_ksize/2)*cn; + bool symmetrical = (symmetryType & KERNEL_SYMMETRICAL) != 0; + const float* kx = (const float*)kernel.data + _ksize/2; + width *= cn; + + if( symmetrical ) + { + if( _ksize == 1 ) + return 0; + if( _ksize == 3 ) + { + if( kx[0] == 2 && kx[1] == 1 ) + for( ; i <= width - 8; i += 8, src += 8 ) + { + __m128 x0, x1, x2, y0, y1, y2; + x0 = _mm_loadu_ps(src - cn); + x1 = _mm_loadu_ps(src); + x2 = _mm_loadu_ps(src + cn); + y0 = _mm_loadu_ps(src - cn + 4); + y1 = _mm_loadu_ps(src + 4); + y2 = _mm_loadu_ps(src + cn + 4); + x0 = _mm_add_ps(x0, _mm_add_ps(_mm_add_ps(x1, x1), x2)); + y0 = _mm_add_ps(y0, _mm_add_ps(_mm_add_ps(y1, y1), y2)); + _mm_store_ps(dst + i, x0); + _mm_store_ps(dst + i + 4, y0); + } + else if( kx[0] == -2 && kx[1] == 1 ) + for( ; i <= width - 8; i += 8, src += 8 ) + { + __m128 x0, x1, x2, y0, y1, y2; + x0 = _mm_loadu_ps(src - cn); + x1 = _mm_loadu_ps(src); + x2 = _mm_loadu_ps(src + cn); + y0 = _mm_loadu_ps(src - cn + 4); + y1 = _mm_loadu_ps(src + 4); + y2 = _mm_loadu_ps(src + cn + 4); + x0 = _mm_add_ps(x0, _mm_sub_ps(x2, _mm_add_ps(x1, x1))); + y0 = _mm_add_ps(y0, _mm_sub_ps(y2, _mm_add_ps(y1, y1))); + _mm_store_ps(dst + i, x0); + _mm_store_ps(dst + i + 4, y0); + } + else + { + __m128 k0 = _mm_set1_ps(kx[0]), k1 = _mm_set1_ps(kx[1]); + for( ; i <= width - 8; i += 8, src += 8 ) + { + __m128 x0, x1, x2, y0, y1, y2; + x0 = _mm_loadu_ps(src - cn); + x1 = _mm_loadu_ps(src); + x2 = _mm_loadu_ps(src + cn); + y0 = _mm_loadu_ps(src - cn + 4); + y1 = _mm_loadu_ps(src + 4); + y2 = _mm_loadu_ps(src + cn + 4); + + x0 = _mm_mul_ps(_mm_add_ps(x0, x2), k1); + y0 = _mm_mul_ps(_mm_add_ps(y0, y2), k1); + x0 = _mm_add_ps(x0, _mm_mul_ps(x1, k0)); + y0 = _mm_add_ps(y0, _mm_mul_ps(y1, k0)); + _mm_store_ps(dst + i, x0); + _mm_store_ps(dst + i + 4, y0); + } + } + } + else if( _ksize == 5 ) + { + if( kx[0] == -2 && kx[1] == 0 && kx[2] == 1 ) + for( ; i <= width - 8; i += 8, src += 8 ) + { + __m128 x0, x1, x2, y0, y1, y2; + x0 = _mm_loadu_ps(src - cn*2); + x1 = _mm_loadu_ps(src); + x2 = _mm_loadu_ps(src + cn*2); + y0 = _mm_loadu_ps(src - cn*2 + 4); + y1 = _mm_loadu_ps(src + 4); + y2 = _mm_loadu_ps(src + cn*2 + 4); + x0 = _mm_add_ps(x0, _mm_sub_ps(x2, _mm_add_ps(x1, x1))); + y0 = _mm_add_ps(y0, _mm_sub_ps(y2, _mm_add_ps(y1, y1))); + _mm_store_ps(dst + i, x0); + _mm_store_ps(dst + i + 4, y0); + } + else + { + __m128 k0 = _mm_set1_ps(kx[0]), k1 = _mm_set1_ps(kx[1]), k2 = _mm_set1_ps(kx[2]); + for( ; i <= width - 8; i += 8, src += 8 ) + { + __m128 x0, x1, x2, y0, y1, y2; + x0 = _mm_loadu_ps(src - cn); + x1 = _mm_loadu_ps(src); + x2 = _mm_loadu_ps(src + cn); + y0 = _mm_loadu_ps(src - cn + 4); + y1 = _mm_loadu_ps(src + 4); + y2 = _mm_loadu_ps(src + cn + 4); + + x0 = _mm_mul_ps(_mm_add_ps(x0, x2), k1); + y0 = _mm_mul_ps(_mm_add_ps(y0, y2), k1); + x0 = _mm_add_ps(x0, _mm_mul_ps(x1, k0)); + y0 = _mm_add_ps(y0, _mm_mul_ps(y1, k0)); + + x2 = _mm_add_ps(_mm_loadu_ps(src + cn*2), _mm_loadu_ps(src - cn*2)); + y2 = _mm_add_ps(_mm_loadu_ps(src + cn*2 + 4), _mm_loadu_ps(src - cn*2 + 4)); + x0 = _mm_add_ps(x0, _mm_mul_ps(x2, k2)); + y0 = _mm_add_ps(y0, _mm_mul_ps(y2, k2)); + + _mm_store_ps(dst + i, x0); + _mm_store_ps(dst + i + 4, y0); + } + } + } + } + else + { + if( _ksize == 3 ) + { + if( kx[0] == 0 && kx[1] == 1 ) + for( ; i <= width - 8; i += 8, src += 8 ) + { + __m128 x0, x2, y0, y2; + x0 = _mm_loadu_ps(src + cn); + x2 = _mm_loadu_ps(src - cn); + y0 = _mm_loadu_ps(src + cn + 4); + y2 = _mm_loadu_ps(src - cn + 4); + x0 = _mm_sub_ps(x0, x2); + y0 = _mm_sub_ps(y0, y2); + _mm_store_ps(dst + i, x0); + _mm_store_ps(dst + i + 4, y0); + } + else + { + __m128 k1 = _mm_set1_ps(kx[1]); + for( ; i <= width - 8; i += 8, src += 8 ) + { + __m128 x0, x2, y0, y2; + x0 = _mm_loadu_ps(src + cn); + x2 = _mm_loadu_ps(src - cn); + y0 = _mm_loadu_ps(src + cn + 4); + y2 = _mm_loadu_ps(src - cn + 4); + + x0 = _mm_mul_ps(_mm_sub_ps(x0, x2), k1); + y0 = _mm_mul_ps(_mm_sub_ps(y0, y2), k1); + _mm_store_ps(dst + i, x0); + _mm_store_ps(dst + i + 4, y0); + } + } + } + else if( _ksize == 5 ) + { + __m128 k1 = _mm_set1_ps(kx[1]), k2 = _mm_set1_ps(kx[2]); + for( ; i <= width - 8; i += 8, src += 8 ) + { + __m128 x0, x2, y0, y2; + x0 = _mm_loadu_ps(src + cn); + x2 = _mm_loadu_ps(src - cn); + y0 = _mm_loadu_ps(src + cn + 4); + y2 = _mm_loadu_ps(src - cn + 4); + + x0 = _mm_mul_ps(_mm_sub_ps(x0, x2), k1); + y0 = _mm_mul_ps(_mm_sub_ps(y0, y2), k1); + + x2 = _mm_sub_ps(_mm_loadu_ps(src + cn*2), _mm_loadu_ps(src - cn*2)); + y2 = _mm_sub_ps(_mm_loadu_ps(src + cn*2 + 4), _mm_loadu_ps(src - cn*2 + 4)); + x0 = _mm_add_ps(x0, _mm_mul_ps(x2, k2)); + y0 = _mm_add_ps(y0, _mm_mul_ps(y2, k2)); + + _mm_store_ps(dst + i, x0); + _mm_store_ps(dst + i + 4, y0); + } + } + } + + return i; + } + + Mat kernel; + int symmetryType; +}; + + +struct SymmColumnVec_32f +{ + SymmColumnVec_32f() { symmetryType=0; } + SymmColumnVec_32f(const Mat& _kernel, int _symmetryType, int, double _delta) + { + symmetryType = _symmetryType; + kernel = _kernel; + delta = (float)_delta; + CV_Assert( (symmetryType & (KERNEL_SYMMETRICAL | KERNEL_ASYMMETRICAL)) != 0 ); + } + + int operator()(const uchar** _src, uchar* _dst, int width) const + { + if( !checkHardwareSupport(CV_CPU_SSE) ) + return 0; + + int ksize2 = (kernel.rows + kernel.cols - 1)/2; + const float* ky = (const float*)kernel.data + ksize2; + int i = 0, k; + bool symmetrical = (symmetryType & KERNEL_SYMMETRICAL) != 0; + const float** src = (const float**)_src; + const float *S, *S2; + float* dst = (float*)_dst; + __m128 d4 = _mm_set1_ps(delta); + + if( symmetrical ) + { + for( ; i <= width - 16; i += 16 ) + { + __m128 f = _mm_load_ss(ky); + f = _mm_shuffle_ps(f, f, 0); + __m128 s0, s1, s2, s3; + __m128 x0, x1; + S = src[0] + i; + s0 = _mm_load_ps(S); + s1 = _mm_load_ps(S+4); + s0 = _mm_add_ps(_mm_mul_ps(s0, f), d4); + s1 = _mm_add_ps(_mm_mul_ps(s1, f), d4); + s2 = _mm_load_ps(S+8); + s3 = _mm_load_ps(S+12); + s2 = _mm_add_ps(_mm_mul_ps(s2, f), d4); + s3 = _mm_add_ps(_mm_mul_ps(s3, f), d4); + + for( k = 1; k <= ksize2; k++ ) + { + S = src[k] + i; + S2 = src[-k] + i; + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_add_ps(_mm_load_ps(S), _mm_load_ps(S2)); + x1 = _mm_add_ps(_mm_load_ps(S+4), _mm_load_ps(S2+4)); + s0 = _mm_add_ps(s0, _mm_mul_ps(x0, f)); + s1 = _mm_add_ps(s1, _mm_mul_ps(x1, f)); + x0 = _mm_add_ps(_mm_load_ps(S+8), _mm_load_ps(S2+8)); + x1 = _mm_add_ps(_mm_load_ps(S+12), _mm_load_ps(S2+12)); + s2 = _mm_add_ps(s2, _mm_mul_ps(x0, f)); + s3 = _mm_add_ps(s3, _mm_mul_ps(x1, f)); + } + + _mm_storeu_ps(dst + i, s0); + _mm_storeu_ps(dst + i + 4, s1); + _mm_storeu_ps(dst + i + 8, s2); + _mm_storeu_ps(dst + i + 12, s3); + } + + for( ; i <= width - 4; i += 4 ) + { + __m128 f = _mm_load_ss(ky); + f = _mm_shuffle_ps(f, f, 0); + __m128 x0, s0 = _mm_load_ps(src[0] + i); + s0 = _mm_add_ps(_mm_mul_ps(s0, f), d4); + + for( k = 1; k <= ksize2; k++ ) + { + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + S = src[k] + i; + S2 = src[-k] + i; + x0 = _mm_add_ps(_mm_load_ps(src[k]+i), _mm_load_ps(src[-k] + i)); + s0 = _mm_add_ps(s0, _mm_mul_ps(x0, f)); + } + + _mm_storeu_ps(dst + i, s0); + } + } + else + { + for( ; i <= width - 16; i += 16 ) + { + __m128 f, s0 = d4, s1 = d4, s2 = d4, s3 = d4; + __m128 x0, x1; + S = src[0] + i; + + for( k = 1; k <= ksize2; k++ ) + { + S = src[k] + i; + S2 = src[-k] + i; + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_sub_ps(_mm_load_ps(S), _mm_load_ps(S2)); + x1 = _mm_sub_ps(_mm_load_ps(S+4), _mm_load_ps(S2+4)); + s0 = _mm_add_ps(s0, _mm_mul_ps(x0, f)); + s1 = _mm_add_ps(s1, _mm_mul_ps(x1, f)); + x0 = _mm_sub_ps(_mm_load_ps(S+8), _mm_load_ps(S2+8)); + x1 = _mm_sub_ps(_mm_load_ps(S+12), _mm_load_ps(S2+12)); + s2 = _mm_add_ps(s2, _mm_mul_ps(x0, f)); + s3 = _mm_add_ps(s3, _mm_mul_ps(x1, f)); + } + + _mm_storeu_ps(dst + i, s0); + _mm_storeu_ps(dst + i + 4, s1); + _mm_storeu_ps(dst + i + 8, s2); + _mm_storeu_ps(dst + i + 12, s3); + } + + for( ; i <= width - 4; i += 4 ) + { + __m128 f, x0, s0 = d4; + + for( k = 1; k <= ksize2; k++ ) + { + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_sub_ps(_mm_load_ps(src[k]+i), _mm_load_ps(src[-k] + i)); + s0 = _mm_add_ps(s0, _mm_mul_ps(x0, f)); + } + + _mm_storeu_ps(dst + i, s0); + } + } + + return i; + } + + int symmetryType; + float delta; + Mat kernel; +}; + + +struct SymmColumnSmallVec_32f +{ + SymmColumnSmallVec_32f() { symmetryType=0; } + SymmColumnSmallVec_32f(const Mat& _kernel, int _symmetryType, int, double _delta) + { + symmetryType = _symmetryType; + kernel = _kernel; + delta = (float)_delta; + CV_Assert( (symmetryType & (KERNEL_SYMMETRICAL | KERNEL_ASYMMETRICAL)) != 0 ); + } + + int operator()(const uchar** _src, uchar* _dst, int width) const + { + if( !checkHardwareSupport(CV_CPU_SSE) ) + return 0; + + int ksize2 = (kernel.rows + kernel.cols - 1)/2; + const float* ky = (const float*)kernel.data + ksize2; + int i = 0; + bool symmetrical = (symmetryType & KERNEL_SYMMETRICAL) != 0; + const float** src = (const float**)_src; + const float *S0 = src[-1], *S1 = src[0], *S2 = src[1]; + float* dst = (float*)_dst; + __m128 d4 = _mm_set1_ps(delta); + + if( symmetrical ) + { + if( ky[0] == 2 && ky[1] == 1 ) + { + for( ; i <= width - 8; i += 8 ) + { + __m128 s0, s1, s2, s3, s4, s5; + s0 = _mm_load_ps(S0 + i); + s1 = _mm_load_ps(S0 + i + 4); + s2 = _mm_load_ps(S1 + i); + s3 = _mm_load_ps(S1 + i + 4); + s4 = _mm_load_ps(S2 + i); + s5 = _mm_load_ps(S2 + i + 4); + s0 = _mm_add_ps(s0, _mm_add_ps(s4, _mm_add_ps(s2, s2))); + s1 = _mm_add_ps(s1, _mm_add_ps(s5, _mm_add_ps(s3, s3))); + s0 = _mm_add_ps(s0, d4); + s1 = _mm_add_ps(s1, d4); + _mm_storeu_ps(dst + i, s0); + _mm_storeu_ps(dst + i + 4, s1); + } + } + else if( ky[0] == -2 && ky[1] == 1 ) + { + for( ; i <= width - 8; i += 8 ) + { + __m128 s0, s1, s2, s3, s4, s5; + s0 = _mm_load_ps(S0 + i); + s1 = _mm_load_ps(S0 + i + 4); + s2 = _mm_load_ps(S1 + i); + s3 = _mm_load_ps(S1 + i + 4); + s4 = _mm_load_ps(S2 + i); + s5 = _mm_load_ps(S2 + i + 4); + s0 = _mm_add_ps(s0, _mm_sub_ps(s4, _mm_add_ps(s2, s2))); + s1 = _mm_add_ps(s1, _mm_sub_ps(s5, _mm_add_ps(s3, s3))); + s0 = _mm_add_ps(s0, d4); + s1 = _mm_add_ps(s1, d4); + _mm_storeu_ps(dst + i, s0); + _mm_storeu_ps(dst + i + 4, s1); + } + } + else + { + __m128 k0 = _mm_set1_ps(ky[0]), k1 = _mm_set1_ps(ky[1]); + for( ; i <= width - 8; i += 8 ) + { + __m128 s0, s1, x0, x1; + s0 = _mm_load_ps(S1 + i); + s1 = _mm_load_ps(S1 + i + 4); + s0 = _mm_add_ps(_mm_mul_ps(s0, k0), d4); + s1 = _mm_add_ps(_mm_mul_ps(s1, k0), d4); + x0 = _mm_add_ps(_mm_load_ps(S0 + i), _mm_load_ps(S2 + i)); + x1 = _mm_add_ps(_mm_load_ps(S0 + i + 4), _mm_load_ps(S2 + i + 4)); + s0 = _mm_add_ps(s0, _mm_mul_ps(x0,k1)); + s1 = _mm_add_ps(s1, _mm_mul_ps(x1,k1)); + _mm_storeu_ps(dst + i, s0); + _mm_storeu_ps(dst + i + 4, s1); + } + } + } + else + { + if( fabs(ky[1]) == 1 && ky[1] == -ky[-1] ) + { + if( ky[1] < 0 ) + std::swap(S0, S2); + for( ; i <= width - 8; i += 8 ) + { + __m128 s0, s1, s2, s3; + s0 = _mm_load_ps(S2 + i); + s1 = _mm_load_ps(S2 + i + 4); + s2 = _mm_load_ps(S0 + i); + s3 = _mm_load_ps(S0 + i + 4); + s0 = _mm_add_ps(_mm_sub_ps(s0, s2), d4); + s1 = _mm_add_ps(_mm_sub_ps(s1, s3), d4); + _mm_storeu_ps(dst + i, s0); + _mm_storeu_ps(dst + i + 4, s1); + } + } + else + { + __m128 k1 = _mm_set1_ps(ky[1]); + for( ; i <= width - 8; i += 8 ) + { + __m128 s0 = d4, s1 = d4, x0, x1; + x0 = _mm_sub_ps(_mm_load_ps(S2 + i), _mm_load_ps(S0 + i)); + x1 = _mm_sub_ps(_mm_load_ps(S2 + i + 4), _mm_load_ps(S0 + i + 4)); + s0 = _mm_add_ps(s0, _mm_mul_ps(x0,k1)); + s1 = _mm_add_ps(s1, _mm_mul_ps(x1,k1)); + _mm_storeu_ps(dst + i, s0); + _mm_storeu_ps(dst + i + 4, s1); + } + } + } + + return i; + } + + int symmetryType; + float delta; + Mat kernel; +}; + + +/////////////////////////////// non-separable filters /////////////////////////////// + +///////////////////////////////// 8u<->8u, 8u<->16s ///////////////////////////////// + +struct FilterVec_8u +{ + FilterVec_8u() {} + FilterVec_8u(const Mat& _kernel, int _bits, double _delta) + { + Mat kernel; + _kernel.convertTo(kernel, CV_32F, 1./(1 << _bits), 0); + delta = (float)(_delta/(1 << _bits)); + vector coords; + preprocess2DKernel(kernel, coords, coeffs); + _nz = (int)coords.size(); + } + + int operator()(const uchar** src, uchar* dst, int width) const + { + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + const float* kf = (const float*)&coeffs[0]; + int i = 0, k, nz = _nz; + __m128 d4 = _mm_set1_ps(delta); + + for( ; i <= width - 16; i += 16 ) + { + __m128 s0 = d4, s1 = d4, s2 = d4, s3 = d4; + __m128i x0, x1, z = _mm_setzero_si128(); + + for( k = 0; k < nz; k++ ) + { + __m128 f = _mm_load_ss(kf+k), t0, t1; + f = _mm_shuffle_ps(f, f, 0); + + x0 = _mm_loadu_si128((const __m128i*)(src[k] + i)); + x1 = _mm_unpackhi_epi8(x0, z); + x0 = _mm_unpacklo_epi8(x0, z); + + t0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(x0, z)); + t1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(x0, z)); + s0 = _mm_add_ps(s0, _mm_mul_ps(t0, f)); + s1 = _mm_add_ps(s1, _mm_mul_ps(t1, f)); + + t0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(x1, z)); + t1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(x1, z)); + s2 = _mm_add_ps(s2, _mm_mul_ps(t0, f)); + s3 = _mm_add_ps(s3, _mm_mul_ps(t1, f)); + } + + x0 = _mm_packs_epi32(_mm_cvtps_epi32(s0), _mm_cvtps_epi32(s1)); + x1 = _mm_packs_epi32(_mm_cvtps_epi32(s2), _mm_cvtps_epi32(s3)); + x0 = _mm_packus_epi16(x0, x1); + _mm_storeu_si128((__m128i*)(dst + i), x0); + } + + for( ; i <= width - 4; i += 4 ) + { + __m128 s0 = d4; + __m128i x0, z = _mm_setzero_si128(); + + for( k = 0; k < nz; k++ ) + { + __m128 f = _mm_load_ss(kf+k), t0; + f = _mm_shuffle_ps(f, f, 0); + + x0 = _mm_cvtsi32_si128(*(const int*)(src[k] + i)); + x0 = _mm_unpacklo_epi8(x0, z); + t0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(x0, z)); + s0 = _mm_add_ps(s0, _mm_mul_ps(t0, f)); + } + + x0 = _mm_packs_epi32(_mm_cvtps_epi32(s0), z); + x0 = _mm_packus_epi16(x0, x0); + *(int*)(dst + i) = _mm_cvtsi128_si32(x0); + } + + return i; + } + + int _nz; + vector coeffs; + float delta; +}; + + +struct FilterVec_8u16s +{ + FilterVec_8u16s() {} + FilterVec_8u16s(const Mat& _kernel, int _bits, double _delta) + { + Mat kernel; + _kernel.convertTo(kernel, CV_32F, 1./(1 << _bits), 0); + delta = (float)(_delta/(1 << _bits)); + vector coords; + preprocess2DKernel(kernel, coords, coeffs); + _nz = (int)coords.size(); + } + + int operator()(const uchar** src, uchar* _dst, int width) const + { + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + const float* kf = (const float*)&coeffs[0]; + short* dst = (short*)_dst; + int i = 0, k, nz = _nz; + __m128 d4 = _mm_set1_ps(delta); + + for( ; i <= width - 16; i += 16 ) + { + __m128 s0 = d4, s1 = d4, s2 = d4, s3 = d4; + __m128i x0, x1, z = _mm_setzero_si128(); + + for( k = 0; k < nz; k++ ) + { + __m128 f = _mm_load_ss(kf+k), t0, t1; + f = _mm_shuffle_ps(f, f, 0); + + x0 = _mm_loadu_si128((const __m128i*)(src[k] + i)); + x1 = _mm_unpackhi_epi8(x0, z); + x0 = _mm_unpacklo_epi8(x0, z); + + t0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(x0, z)); + t1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(x0, z)); + s0 = _mm_add_ps(s0, _mm_mul_ps(t0, f)); + s1 = _mm_add_ps(s1, _mm_mul_ps(t1, f)); + + t0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(x1, z)); + t1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(x1, z)); + s2 = _mm_add_ps(s2, _mm_mul_ps(t0, f)); + s3 = _mm_add_ps(s3, _mm_mul_ps(t1, f)); + } + + x0 = _mm_packs_epi32(_mm_cvtps_epi32(s0), _mm_cvtps_epi32(s1)); + x1 = _mm_packs_epi32(_mm_cvtps_epi32(s2), _mm_cvtps_epi32(s3)); + _mm_storeu_si128((__m128i*)(dst + i), x0); + _mm_storeu_si128((__m128i*)(dst + i + 8), x1); + } + + for( ; i <= width - 4; i += 4 ) + { + __m128 s0 = d4; + __m128i x0, z = _mm_setzero_si128(); + + for( k = 0; k < nz; k++ ) + { + __m128 f = _mm_load_ss(kf+k), t0; + f = _mm_shuffle_ps(f, f, 0); + + x0 = _mm_cvtsi32_si128(*(const int*)(src[k] + i)); + x0 = _mm_unpacklo_epi8(x0, z); + t0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(x0, z)); + s0 = _mm_add_ps(s0, _mm_mul_ps(t0, f)); + } + + x0 = _mm_packs_epi32(_mm_cvtps_epi32(s0), z); + _mm_storel_epi64((__m128i*)(dst + i), x0); + } + + return i; + } + + int _nz; + vector coeffs; + float delta; +}; + + +struct FilterVec_32f +{ + FilterVec_32f() {} + FilterVec_32f(const Mat& _kernel, int, double _delta) + { + delta = (float)_delta; + vector coords; + preprocess2DKernel(_kernel, coords, coeffs); + _nz = (int)coords.size(); + } + + int operator()(const uchar** _src, uchar* _dst, int width) const + { + if( !checkHardwareSupport(CV_CPU_SSE) ) + return 0; + + const float* kf = (const float*)&coeffs[0]; + const float** src = (const float**)_src; + float* dst = (float*)_dst; + int i = 0, k, nz = _nz; + __m128 d4 = _mm_set1_ps(delta); + + for( ; i <= width - 16; i += 16 ) + { + __m128 s0 = d4, s1 = d4, s2 = d4, s3 = d4; + + for( k = 0; k < nz; k++ ) + { + __m128 f = _mm_load_ss(kf+k), t0, t1; + f = _mm_shuffle_ps(f, f, 0); + const float* S = src[k] + i; + + t0 = _mm_loadu_ps(S); + t1 = _mm_loadu_ps(S + 4); + s0 = _mm_add_ps(s0, _mm_mul_ps(t0, f)); + s1 = _mm_add_ps(s1, _mm_mul_ps(t1, f)); + + t0 = _mm_loadu_ps(S + 8); + t1 = _mm_loadu_ps(S + 12); + s2 = _mm_add_ps(s2, _mm_mul_ps(t0, f)); + s3 = _mm_add_ps(s3, _mm_mul_ps(t1, f)); + } + + _mm_storeu_ps(dst + i, s0); + _mm_storeu_ps(dst + i + 4, s1); + _mm_storeu_ps(dst + i + 8, s2); + _mm_storeu_ps(dst + i + 12, s3); + } + + for( ; i <= width - 4; i += 4 ) + { + __m128 s0 = d4; + + for( k = 0; k < nz; k++ ) + { + __m128 f = _mm_load_ss(kf+k), t0; + f = _mm_shuffle_ps(f, f, 0); + t0 = _mm_loadu_ps(src[k] + i); + s0 = _mm_add_ps(s0, _mm_mul_ps(t0, f)); + } + _mm_storeu_ps(dst + i, s0); + } + + return i; + } + + int _nz; + vector coeffs; + float delta; +}; + + +#elif CV_NEON +#pragma mark CV_NEON optimisations + /* + * Set this to log which function is called (for logging) + */ + #define ANUVIS_TEST 0 + + /* + * Toggle these to use Neon reimplemented versions + */ + #define USE_SymmRowSmallVec_8u32s 1 + #define USE_SymmColumnVec_32s8u 1 + #define USE_SymmColumnSmallVec_32s16s 1 + + + typedef RowNoVec RowVec_8u32s; + typedef RowNoVec RowVec_16s32f; + typedef RowNoVec RowVec_32f; + #if !USE_SymmRowSmallVec_8u32s + typedef SymmRowSmallNoVec SymmRowSmallVec_8u32s; + #endif + typedef SymmRowSmallNoVec SymmRowSmallVec_32f; + #if !USE_SymmColumnVec_32s8u + typedef ColumnNoVec SymmColumnVec_32s8u; + #endif + typedef ColumnNoVec SymmColumnVec_32f16s; + typedef ColumnNoVec SymmColumnVec_32f; + #if !USE_SymmColumnSmallVec_32s16s + typedef SymmColumnSmallNoVec SymmColumnSmallVec_32s16s; + #endif + typedef SymmColumnSmallNoVec SymmColumnSmallVec_32f; + typedef FilterNoVec FilterVec_8u; + typedef FilterNoVec FilterVec_8u16s; + typedef FilterNoVec FilterVec_32f; + + #pragma mark ANUVIS SymmRowSmallVec_8u32s + #if USE_SymmRowSmallVec_8u32s + struct SymmRowSmallVec_8u32s + { + + SymmRowSmallVec_8u32s() { smallValues = false; } + SymmRowSmallVec_8u32s( const Mat& _kernel, int _symmetryType ) + { + kernel = _kernel; + symmetryType = _symmetryType; + smallValues = true; + int k, ksize = kernel.rows + kernel.cols - 1; + for( k = 0; k < ksize; k++ ) + { + int v = ((const int*)kernel.data)[k]; + if( v < SHRT_MIN || v > SHRT_MAX ) + { + smallValues = false; + break; + } + } + } + + int operator()(const uchar* src, uchar* _dst, int width, int cn) const + { + + /* + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + */ + + if (!cv::useOptimized()) { + return 0; + } + + int i = 0, j, k, _ksize = kernel.rows + kernel.cols - 1; + int* dst = (int*)_dst; + int32_t *dest = (int32_t*)_dst; + + bool symmetrical = (symmetryType & KERNEL_SYMMETRICAL) != 0; + const int* kx = (const int*)kernel.data + _ksize/2; + if( !smallValues ) + return 0; + + src += (_ksize/2)*cn; + width *= cn; + /* + __m128i z = _mm_setzero_si128(); + */ + if( symmetrical ) + { + if( _ksize == 1 ) + return 0; + if( _ksize == 3 ) + { + if( kx[0] == 2 && kx[1] == 1 ) + + #pragma mark Optimise here for Gaussian Blur and Sobel! (But should we also march through 16 pixels at a time) + + + //neon version + // + for( ; i<=width - 8; i += 8, src += 8){ + int32x4_t x0,x1,x2; + uint8x8_t tx0,tx1,tx2; + + tx0 = vld1_u8((uint8_t *)(src-cn)); + tx1 = vld1_u8((uint8_t *)(src)); + tx2 = vld1_u8((uint8_t *)(src+cn)); + + x0 = (int32x4_t) vmovl_u16( vget_low_u16( vmovl_u8(tx0) ) ); + x1 = (int32x4_t) vmovl_u16( vget_low_u16( vmovl_u8(tx1) ) ); + x2 = (int32x4_t) vmovl_u16( vget_low_u16( vmovl_u8(tx2) ) ); + + vst1q_s32((int32_t*)(dest+i), vaddq_s32(x0, vaddq_s32( vaddq_s32(x1, x1), x2) ) ); + + + //to 16x8_t then split then to 32x4_t + x0 = (int32x4_t) vmovl_u16( vget_high_u16( vmovl_u8(tx0) ) ); + x1 = (int32x4_t) vmovl_u16( vget_high_u16( vmovl_u8(tx1) ) ); + x2 = (int32x4_t) vmovl_u16( vget_high_u16( vmovl_u8(tx2) ) ); + + vst1q_s32((int32_t*)(dest+i+4), vaddq_s32(x0, vaddq_s32( vaddq_s32(x1, x1), x2) ) ); + + } + + + /* + for( ; i <= width - 16; i += 16, src += 16 ) + { + + //sse version + // + //__m128i x0, x1, x2, y0, y1, y2; + //x0 = _mm_loadu_si128((__m128i*)(src - cn)); + //x1 = _mm_loadu_si128((__m128i*)src); + //x2 = _mm_loadu_si128((__m128i*)(src + cn)); + //y0 = _mm_unpackhi_epi8(x0, z); + //x0 = _mm_unpacklo_epi8(x0, z); + //y1 = _mm_unpackhi_epi8(x1, z); + //x1 = _mm_unpacklo_epi8(x1, z); + //y2 = _mm_unpackhi_epi8(x2, z); + //x2 = _mm_unpacklo_epi8(x2, z); + //x0 = _mm_add_epi16(x0, _mm_add_epi16(_mm_add_epi16(x1, x1), x2)); + //y0 = _mm_add_epi16(y0, _mm_add_epi16(_mm_add_epi16(y1, y1), y2)); + //_mm_store_si128((__m128i*)(dst + i), _mm_unpacklo_epi16(x0, z)); + //_mm_store_si128((__m128i*)(dst + i + 4), _mm_unpackhi_epi16(x0, z)); + //_mm_store_si128((__m128i*)(dst + i + 8), _mm_unpacklo_epi16(y0, z)); + //_mm_store_si128((__m128i*)(dst + i + 12), _mm_unpackhi_epi16(y0, z)); + + //c version + // + for (int j = 0; j < 16; j++) { + int32_t x0, x1, x2; + x0 = (int32_t)*(src + j - cn); + x1 = (int32_t)*(src + j); + x2 = (int32_t)*(src + j + cn); + int32_t res = x0 + x1 + x1 + x2; + //dest is a 32-bit int pointer to _dst + *(dest+j+i) = (int32_t)res; + } + + } + */ + + else if( kx[0] == -2 && kx[1] == 1 ){ + + CV_Error(CV_StsBadArg, "NEON's SymmRowSmallVec_8u32s function not fully implemented (1)"); + + for( ; i <= width - 16; i += 16, src += 16 ) + { + /* + __m128i x0, x1, x2, y0, y1, y2; + x0 = _mm_loadu_si128((__m128i*)(src - cn)); + x1 = _mm_loadu_si128((__m128i*)src); + x2 = _mm_loadu_si128((__m128i*)(src + cn)); + y0 = _mm_unpackhi_epi8(x0, z); + x0 = _mm_unpacklo_epi8(x0, z); + y1 = _mm_unpackhi_epi8(x1, z); + x1 = _mm_unpacklo_epi8(x1, z); + y2 = _mm_unpackhi_epi8(x2, z); + x2 = _mm_unpacklo_epi8(x2, z); + x0 = _mm_add_epi16(x0, _mm_sub_epi16(x2, _mm_add_epi16(x1, x1))); + y0 = _mm_add_epi16(y0, _mm_sub_epi16(y2, _mm_add_epi16(y1, y1))); + _mm_store_si128((__m128i*)(dst + i), _mm_srai_epi32(_mm_unpacklo_epi16(x0, x0),16)); + _mm_store_si128((__m128i*)(dst + i + 4), _mm_srai_epi32(_mm_unpackhi_epi16(x0, x0),16)); + _mm_store_si128((__m128i*)(dst + i + 8), _mm_srai_epi32(_mm_unpacklo_epi16(y0, y0),16)); + _mm_store_si128((__m128i*)(dst + i + 12), _mm_srai_epi32(_mm_unpackhi_epi16(y0, y0),16)); + */ + } + } + else + { + #pragma mark Gaussian with 3x3 kernel window runs here + //CV_Error(CV_StsBadArg, "NEON's SymmRowSmallVec_8u32s function not fully implemented (2)"); + + //neon version + // + int32x4_t k0 = vdupq_n_s32(kx[0]); + int32x4_t k1 = vdupq_n_s32(kx[1]); + + for( ; i<=width - 8; i += 8, src += 8){ + int32x4_t x0,x1,x2; + uint8x8_t tx0,tx1,tx2; + + tx0 = vld1_u8((uint8_t *)(src-cn)); + tx1 = vld1_u8((uint8_t *)(src)); + tx2 = vld1_u8((uint8_t *)(src+cn)); + + x0 = (int32x4_t) vmovl_u16( vget_low_u16( vmovl_u8(tx0) ) ); + x1 = (int32x4_t) vmovl_u16( vget_low_u16( vmovl_u8(tx1) ) ); + x2 = (int32x4_t) vmovl_u16( vget_low_u16( vmovl_u8(tx2) ) ); + + vst1q_s32((int32_t*)(dest+i), vaddq_s32( vmulq_s32( x0, k1 ) , vaddq_s32( vmulq_s32( x1, k0 ), vmulq_s32( x2, k1 ) ) ) ); + + + //to 16x8_t then split then to 32x4_t + x0 = (int32x4_t) vmovl_u16( vget_high_u16( vmovl_u8(tx0) ) ); + x1 = (int32x4_t) vmovl_u16( vget_high_u16( vmovl_u8(tx1) ) ); + x2 = (int32x4_t) vmovl_u16( vget_high_u16( vmovl_u8(tx2) ) ); + + vst1q_s32((int32_t*)(dest+i+4), vaddq_s32( vmulq_s32( x0, k1 ) , vaddq_s32( vmulq_s32( x1, k0 ), vmulq_s32( x2, k1 ) ) ) ); + + } + + + + /* + //c version + // + int32_t k0 = kx[0]; + int32_t k1 = kx[1]; + + //sse version + // + //__m128i k0 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[0]), 0), + //k1 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[1]), 0); + //k0 = _mm_packs_epi32(k0, k0); + //k1 = _mm_packs_epi32(k1, k1); + + + for( ; i <= width - 16; i += 16, src += 16 ) + { + //c version + // + for (int j = 0; j < 16; j++) { + int32_t x0, x1, x2; + x0 = (int32_t)*(src + j - cn); + x1 = (int32_t)*(src + j); + x2 = (int32_t)*(src + j + cn); + int32_t res = (x0*k1) + (x1*k0) + (x2*k1); + //dest is a 32-bit int pointer to _dst + *(dest+j+i) = (int32_t)res; + } + + //sse version + // + //__m128i x0, x1, x2, y0, y1, t0, t1, z0, z1, z2, z3; + //x0 = _mm_loadu_si128((__m128i*)(src - cn)); + //x1 = _mm_loadu_si128((__m128i*)src); + //x2 = _mm_loadu_si128((__m128i*)(src + cn)); + //y0 = _mm_add_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x2, z)); + //x0 = _mm_add_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x2, z)); + //y1 = _mm_unpackhi_epi8(x1, z); + //x1 = _mm_unpacklo_epi8(x1, z); + + //t1 = _mm_mulhi_epi16(x1, k0); + //t0 = _mm_mullo_epi16(x1, k0); + //x2 = _mm_mulhi_epi16(x0, k1); + //x0 = _mm_mullo_epi16(x0, k1); + //z0 = _mm_unpacklo_epi16(t0, t1); + //z1 = _mm_unpackhi_epi16(t0, t1); + //z0 = _mm_add_epi32(z0, _mm_unpacklo_epi16(x0, x2)); + //z1 = _mm_add_epi32(z1, _mm_unpackhi_epi16(x0, x2)); + + //t1 = _mm_mulhi_epi16(y1, k0); + //t0 = _mm_mullo_epi16(y1, k0); + //y1 = _mm_mulhi_epi16(y0, k1); + //y0 = _mm_mullo_epi16(y0, k1); + //z2 = _mm_unpacklo_epi16(t0, t1); + //z3 = _mm_unpackhi_epi16(t0, t1); + //z2 = _mm_add_epi32(z2, _mm_unpacklo_epi16(y0, y1)); + //z3 = _mm_add_epi32(z3, _mm_unpackhi_epi16(y0, y1)); + //_mm_store_si128((__m128i*)(dst + i), z0); + //_mm_store_si128((__m128i*)(dst + i + 4), z1); + //_mm_store_si128((__m128i*)(dst + i + 8), z2); + //_mm_store_si128((__m128i*)(dst + i + 12), z3); + + } + */ + + + + } + } + else if( _ksize == 5 ) + { + if( kx[0] == -2 && kx[1] == 0 && kx[2] == 1 ){ + CV_Error(CV_StsBadArg, "NEON's SymmRowSmallVec_8u32s function not fully implemented (3)"); + + for( ; i <= width - 16; i += 16, src += 16 ) + { + /* + __m128i x0, x1, x2, y0, y1, y2; + x0 = _mm_loadu_si128((__m128i*)(src - cn*2)); + x1 = _mm_loadu_si128((__m128i*)src); + x2 = _mm_loadu_si128((__m128i*)(src + cn*2)); + y0 = _mm_unpackhi_epi8(x0, z); + x0 = _mm_unpacklo_epi8(x0, z); + y1 = _mm_unpackhi_epi8(x1, z); + x1 = _mm_unpacklo_epi8(x1, z); + y2 = _mm_unpackhi_epi8(x2, z); + x2 = _mm_unpacklo_epi8(x2, z); + x0 = _mm_add_epi16(x0, _mm_sub_epi16(x2, _mm_add_epi16(x1, x1))); + y0 = _mm_add_epi16(y0, _mm_sub_epi16(y2, _mm_add_epi16(y1, y1))); + _mm_store_si128((__m128i*)(dst + i), _mm_srai_epi32(_mm_unpacklo_epi16(x0, x0),16)); + _mm_store_si128((__m128i*)(dst + i + 4), _mm_srai_epi32(_mm_unpackhi_epi16(x0, x0),16)); + _mm_store_si128((__m128i*)(dst + i + 8), _mm_srai_epi32(_mm_unpacklo_epi16(y0, y0),16)); + _mm_store_si128((__m128i*)(dst + i + 12), _mm_srai_epi32(_mm_unpackhi_epi16(y0, y0),16)); + */ + } + } + else + { + #pragma mark gaussian Optimise here! + #if ANUVIS_TEST + CV_Error(CV_StsBadArg, "NEON's SymmRowSmallVec_8u32s function not fully implemented (4)"); + #endif + + //sse version + // + //__m128i k0 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[0]), 0), + //k1 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[1]), 0), + //k2 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[2]), 0); + //k0 = _mm_packs_epi32(k0, k0); + //k1 = _mm_packs_epi32(k1, k1); + //k2 = _mm_packs_epi32(k2, k2); + + + //c version + // + int32_t k0 = kx[0]; + int32_t k1 = kx[1]; + int32_t k2 = kx[2]; + + + + + for( ; i <= width - 16; i += 16, src += 16 ) + { + //c version + // + for (int j = 0; j < 16; j++) { + + uint32_t xm2, xm1, x0, xp1, xp2; + xm2 = (uint32_t)*(src+j-cn*2); + xm1 = (uint32_t)*(src+j-cn); + x0 = (uint32_t)*(src+j); + xp1 = (uint32_t)*(src+j+cn); + xp2 = (uint32_t)*(src+j+cn*2); + + xm2 = (xm2 * k2); + xm1 = (xm1 * k1); + x0 = (x0 * k0); + xp1 = (xm1 * k1); + xp2 = (xp2 * k2); + + x0 = xm2+xm1+x0+xp1+xp2; + + //dest is a 32-bit int pointer to _dst + *(dest+j+i) = (int32_t)x0/5; + + } + + /* + //sse version + __m128i x0, x1, x2, y0, y1, t0, t1, z0, z1, z2, z3; + x0 = _mm_loadu_si128((__m128i*)(src - cn)); + x1 = _mm_loadu_si128((__m128i*)src); + x2 = _mm_loadu_si128((__m128i*)(src + cn)); + y0 = _mm_add_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x2, z)); + x0 = _mm_add_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x2, z)); + y1 = _mm_unpackhi_epi8(x1, z); + x1 = _mm_unpacklo_epi8(x1, z); + + t1 = _mm_mulhi_epi16(x1, k0); + t0 = _mm_mullo_epi16(x1, k0); + x2 = _mm_mulhi_epi16(x0, k1); + x0 = _mm_mullo_epi16(x0, k1); + z0 = _mm_unpacklo_epi16(t0, t1); + z1 = _mm_unpackhi_epi16(t0, t1); + z0 = _mm_add_epi32(z0, _mm_unpacklo_epi16(x0, x2)); + z1 = _mm_add_epi32(z1, _mm_unpackhi_epi16(x0, x2)); + + t1 = _mm_mulhi_epi16(y1, k0); + t0 = _mm_mullo_epi16(y1, k0); + y1 = _mm_mulhi_epi16(y0, k1); + y0 = _mm_mullo_epi16(y0, k1); + z2 = _mm_unpacklo_epi16(t0, t1); + z3 = _mm_unpackhi_epi16(t0, t1); + z2 = _mm_add_epi32(z2, _mm_unpacklo_epi16(y0, y1)); + z3 = _mm_add_epi32(z3, _mm_unpackhi_epi16(y0, y1)); + + x0 = _mm_loadu_si128((__m128i*)(src - cn*2)); + x1 = _mm_loadu_si128((__m128i*)(src + cn*2)); + y1 = _mm_add_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x1, z)); + y0 = _mm_add_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x1, z)); + + t1 = _mm_mulhi_epi16(y0, k2); + t0 = _mm_mullo_epi16(y0, k2); + y0 = _mm_mullo_epi16(y1, k2); + y1 = _mm_mulhi_epi16(y1, k2); + z0 = _mm_add_epi32(z0, _mm_unpacklo_epi16(t0, t1)); + z1 = _mm_add_epi32(z1, _mm_unpackhi_epi16(t0, t1)); + z2 = _mm_add_epi32(z2, _mm_unpacklo_epi16(y0, y1)); + z3 = _mm_add_epi32(z3, _mm_unpackhi_epi16(y0, y1)); + + _mm_store_si128((__m128i*)(dst + i), z0); + _mm_store_si128((__m128i*)(dst + i + 4), z1); + _mm_store_si128((__m128i*)(dst + i + 8), z2); + _mm_store_si128((__m128i*)(dst + i + 12), z3); + */ + } + } + } + } + else + { + if( _ksize == 3 ) + { + + if( kx[0] == 0 && kx[1] == 1 ){ + #pragma mark sobel Optimise here! + #if ANUVIS_TEST + CV_Error(CV_StsBadArg, "NEON's SymmRowSmallVec_8u32s function not fully implemented (5)"); + #endif + + + //neon version + // + for( ; i<=width - 8; i += 8, src += 8){ + int32x4_t x0,x1; + uint8x8_t tx0,tx1; + + tx0 = vld1_u8((uint8_t *)(src+cn)); + tx1 = vld1_u8((uint8_t *)(src-cn)); + + x0 = (int32x4_t) vmovl_u16( vget_low_u16( vmovl_u8(tx0) ) ); + x1 = (int32x4_t) vmovl_u16( vget_low_u16( vmovl_u8(tx1) ) ); + + vst1q_s32((int32_t*)(dest+i), vsubq_s32(x0, x1) ); + + + //to 16x8_t then split then to 32x4_t + x0 = (int32x4_t) vmovl_u16( vget_high_u16( vmovl_u8(tx0) ) ); + x1 = (int32x4_t) vmovl_u16( vget_high_u16( vmovl_u8(tx1) ) ); + + vst1q_s32((int32_t*)(dest+i+4), vsubq_s32(x0, x1) ); + + } + + + /* + for( ; i <= width - 16; i += 16, src += 16 ) + { + + //sse version + //__m128i x0, x1, y0; + //x0 = _mm_loadu_si128((__m128i*)(src + cn)); + //x1 = _mm_loadu_si128((__m128i*)(src - cn)); + //y0 = _mm_sub_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x1, z)); + //x0 = _mm_sub_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x1, z)); + //_mm_store_si128((__m128i*)(dst + i), _mm_srai_epi32(_mm_unpacklo_epi16(x0, x0),16)); + //_mm_store_si128((__m128i*)(dst + i + 4), _mm_srai_epi32(_mm_unpackhi_epi16(x0, x0),16)); + //_mm_store_si128((__m128i*)(dst + i + 8), _mm_srai_epi32(_mm_unpacklo_epi16(y0, y0),16)); + //_mm_store_si128((__m128i*)(dst + i + 12), _mm_srai_epi32(_mm_unpackhi_epi16(y0, y0),16)); + + + //c version + + for (int j = 0; j < 16; j++) { + int32_t x0,x1; + x1 = (int32_t)*(src+j+cn); + x0 = (int32_t)*(src+j-cn); + + x0 = (x0 - x1); + + dest[j+i] = (int32_t)(x0); + + } + + + } + */ + + + } + else + { + CV_Error(CV_StsBadArg, "NEON's SymmRowSmallVec_8u32s function not fully implemented (6)"); + + /* + __m128i k1 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[1]), 0); + k1 = _mm_packs_epi32(k1, k1); + */ + for( ; i <= width - 16; i += 16, src += 16 ) + { + /* + __m128i x0, x1, y0, y1, z0, z1, z2, z3; + x0 = _mm_loadu_si128((__m128i*)(src + cn)); + x1 = _mm_loadu_si128((__m128i*)(src - cn)); + y0 = _mm_sub_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x1, z)); + x0 = _mm_sub_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x1, z)); + + x1 = _mm_mulhi_epi16(x0, k1); + x0 = _mm_mullo_epi16(x0, k1); + z0 = _mm_unpacklo_epi16(x0, x1); + z1 = _mm_unpackhi_epi16(x0, x1); + + y1 = _mm_mulhi_epi16(y0, k1); + y0 = _mm_mullo_epi16(y0, k1); + z2 = _mm_unpacklo_epi16(y0, y1); + z3 = _mm_unpackhi_epi16(y0, y1); + _mm_store_si128((__m128i*)(dst + i), z0); + _mm_store_si128((__m128i*)(dst + i + 4), z1); + _mm_store_si128((__m128i*)(dst + i + 8), z2); + _mm_store_si128((__m128i*)(dst + i + 12), z3); + */ + } + } + } + else if( _ksize == 5 ) + { + CV_Error(CV_StsBadArg, "NEON's SymmRowSmallVec_8u32s function not fully implemented (7)"); + /* + __m128i k0 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[0]), 0), + k1 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[1]), 0), + k2 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[2]), 0); + k0 = _mm_packs_epi32(k0, k0); + k1 = _mm_packs_epi32(k1, k1); + k2 = _mm_packs_epi32(k2, k2); + */ + + for( ; i <= width - 16; i += 16, src += 16 ) + { + /* + __m128i x0, x1, x2, y0, y1, t0, t1, z0, z1, z2, z3; + x0 = _mm_loadu_si128((__m128i*)(src + cn)); + x2 = _mm_loadu_si128((__m128i*)(src - cn)); + y0 = _mm_sub_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x2, z)); + x0 = _mm_sub_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x2, z)); + + x2 = _mm_mulhi_epi16(x0, k1); + x0 = _mm_mullo_epi16(x0, k1); + z0 = _mm_unpacklo_epi16(x0, x2); + z1 = _mm_unpackhi_epi16(x0, x2); + y1 = _mm_mulhi_epi16(y0, k1); + y0 = _mm_mullo_epi16(y0, k1); + z2 = _mm_unpacklo_epi16(y0, y1); + z3 = _mm_unpackhi_epi16(y0, y1); + + x0 = _mm_loadu_si128((__m128i*)(src + cn*2)); + x1 = _mm_loadu_si128((__m128i*)(src - cn*2)); + y1 = _mm_sub_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x1, z)); + y0 = _mm_sub_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x1, z)); + + t1 = _mm_mulhi_epi16(y0, k2); + t0 = _mm_mullo_epi16(y0, k2); + y0 = _mm_mullo_epi16(y1, k2); + y1 = _mm_mulhi_epi16(y1, k2); + z0 = _mm_add_epi32(z0, _mm_unpacklo_epi16(t0, t1)); + z1 = _mm_add_epi32(z1, _mm_unpackhi_epi16(t0, t1)); + z2 = _mm_add_epi32(z2, _mm_unpacklo_epi16(y0, y1)); + z3 = _mm_add_epi32(z3, _mm_unpackhi_epi16(y0, y1)); + + _mm_store_si128((__m128i*)(dst + i), z0); + _mm_store_si128((__m128i*)(dst + i + 4), z1); + _mm_store_si128((__m128i*)(dst + i + 8), z2); + _mm_store_si128((__m128i*)(dst + i + 12), z3); + */ + } + } + } + + src -= (_ksize/2)*cn; + kx -= _ksize/2; + for( ; i <= width - 4; i += 4, src += 4 ) + { + CV_Error(CV_StsBadArg, "NEON's SymmRowSmallVec_8u32s function not fully implemented (8)"); + /* + __m128i f, s0 = z, x0, x1; + */ + + for( k = j = 0; k < _ksize; k++, j += cn ) + { + /* + f = _mm_cvtsi32_si128(kx[k]); + f = _mm_shuffle_epi32(f, 0); + f = _mm_packs_epi32(f, f); + + x0 = _mm_cvtsi32_si128(*(const int*)(src + j)); + x0 = _mm_unpacklo_epi8(x0, z); + x1 = _mm_mulhi_epi16(x0, f); + x0 = _mm_mullo_epi16(x0, f); + s0 = _mm_add_epi32(s0, _mm_unpacklo_epi16(x0, x1)); + */ + } + /* + _mm_store_si128((__m128i*)(dst + i), s0); + */ + } + + return i; + } + + Mat kernel; + int symmetryType; + bool smallValues; + }; + #endif + + #pragma mark ANUVIS SymmColumnVec_32s8u + #if USE_SymmColumnVec_32s8u + struct SymmColumnVec_32s8u + { + SymmColumnVec_32s8u() { symmetryType=0; } + SymmColumnVec_32s8u(const Mat& _kernel, int _symmetryType, int _bits, double _delta) + { + symmetryType = _symmetryType; + _kernel.convertTo(kernel, CV_32F, 1./(1 << _bits), 0); + delta = (float)(_delta/(1 << _bits)); + CV_Assert( (symmetryType & (KERNEL_SYMMETRICAL | KERNEL_ASYMMETRICAL)) != 0 ); + } + + int operator()(const uchar** _src, uchar* dst, int width) const + { + #if ANUVIS_TEST + CV_Error( CV_StsBadArg, "NEON's SymmColumnVec_32s8u was called" ); + #endif + + /* + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + */ + + if (!cv::useOptimized()) { + return 0; + } + + int ksize2 = (kernel.rows + kernel.cols - 1)/2; + const float* ky = (const float*)kernel.data + ksize2; + int i = 0, k; + bool symmetrical = (symmetryType & KERNEL_SYMMETRICAL) != 0; + const int** src = (const int**)_src; + + const int32_t** sorc = (const int32_t**)src; + + + + /* + //sse version + const __m128i *S, *S2; + __m128 d4 = _mm_set1_ps(delta); + */ + + + /* + //c version + const int32_t *S,*S2; + int32_t d4 = (int32_t)delta; + */ + + if( symmetrical ) + { + #if ANUVIS_TEST + CV_Error(CV_StsBadArg, "NEON's SymmColumnVec_32s8u function not fully implemented (1)"); + #endif + + #pragma mark USE This comparison for the NEON vs SSE instructions in paper + //c and SSE + //for( ; i <= width - 16; i += 16 ) + for( ; i <= width - 8; i += 8 ) + { + #if ANUVIS_TEST + CV_Error(CV_StsBadArg, "NEON's SymmColumnVec_32s8u function not fully implemented (2)"); + #endif + + //neon version + // + int32x4_t s,r1,r2; + float32_t kn; + + r1 = vdupq_n_s32(0); + r2 = vdupq_n_s32(0); + + for(k = -ksize2; k<=ksize2; k++){ + s = vld1q_s32((const int32_t*)(sorc[k]+i)); + kn = ky[k]; + r1 = vaddq_s32(r1,vcvtq_s32_f32(vmulq_n_f32(vcvtq_f32_s32(s),kn))); + + s = vld1q_s32((const int32_t*)(sorc[k]+i+4)); + //kn = ky[-k]; + + r2 = vaddq_s32(r2,vcvtq_s32_f32(vmulq_n_f32(vcvtq_f32_s32(s),kn))); + + } + //2x32x4sint to 8x8sint + vst1_u8((uint8_t*)(dst+i), (uint8x8_t)vmovn_s16(vcombine_s16(vmovn_s32(r1),vmovn_s32(r2)))); + + //c version + // + /* + int32_t s,r; + float kn; + + for (int j = 0; j < 16; j++) { + + r = 0; + + //for the rest of the filter + for(k = -ksize2; k<=ksize2; k++){ + + s = (*(sorc[k]+i+j)); + kn = ky[k]; + r = r + s*kn; + + } + + dst[i+j] = cv::saturate_cast(r); + + /* + //int32_t f = *ky; + + //int32_t bs0,bs1,bs2; + //uint8_t s0,s1,s2; + + //for a 3x1 column filter + //golden conversion rule: + //*(dst+i+j) = (uchar)((*((*sorc)+i+j))>>8); + + //for a window size 3 + bs0 = (*(sorc[-1]+i+j)); + bs1 = (*(sorc[0]+i+j)); + bs2 = (*(sorc[1]+i+j)); + + //s0 = (uint8_t)(bs0); + //s1 = (uint8_t)(bs1); + //s2 = (uint8_t)(bs2); + + + float k0 = ky[-1]; + float k1 = ky[0]; + float k2 = ky[1]; + + s0 = cv::saturate_cast((bs0*k1)+(bs1*k0+d4)+(bs2*k1)); + //s0 = (s0*(0.251))+(s1*(0.419))+(s2*(0.251)); + + + //char str[40]; + //float f = (ky[2]); + //sprintf(str, "%f", f); + + //CV_Error(CV_StsBadArg, str); + + dst[i+j] = s0; + */ + /* + } + */ + + + + /* + __m128 f = _mm_load_ss(ky); + f = _mm_shuffle_ps(f, f, 0); + __m128 s0, s1, s2, s3; + __m128i x0, x1; + S = (const __m128i*)(src[0] + i); + s0 = _mm_cvtepi32_ps(_mm_load_si128(S)); + s1 = _mm_cvtepi32_ps(_mm_load_si128(S+1)); + s0 = _mm_add_ps(_mm_mul_ps(s0, f), d4); + s1 = _mm_add_ps(_mm_mul_ps(s1, f), d4); + s2 = _mm_cvtepi32_ps(_mm_load_si128(S+2)); + s3 = _mm_cvtepi32_ps(_mm_load_si128(S+3)); + s2 = _mm_add_ps(_mm_mul_ps(s2, f), d4); + s3 = _mm_add_ps(_mm_mul_ps(s3, f), d4); + */ + +// for( k = 1; k <= ksize2; k++ ) +// { +// CV_Error(CV_StsBadArg, "NEON's SymmColumnVec_32s8u function not fully implemented (3)"); + /* + S = (const __m128i*)(src[k] + i); + S2 = (const __m128i*)(src[-k] + i); + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_add_epi32(_mm_load_si128(S), _mm_load_si128(S2)); + x1 = _mm_add_epi32(_mm_load_si128(S+1), _mm_load_si128(S2+1)); + s0 = _mm_add_ps(s0, _mm_mul_ps(_mm_cvtepi32_ps(x0), f)); + s1 = _mm_add_ps(s1, _mm_mul_ps(_mm_cvtepi32_ps(x1), f)); + x0 = _mm_add_epi32(_mm_load_si128(S+2), _mm_load_si128(S2+2)); + x1 = _mm_add_epi32(_mm_load_si128(S+3), _mm_load_si128(S2+3)); + s2 = _mm_add_ps(s2, _mm_mul_ps(_mm_cvtepi32_ps(x0), f)); + s3 = _mm_add_ps(s3, _mm_mul_ps(_mm_cvtepi32_ps(x1), f)); + */ +// } + + /* + x0 = _mm_packs_epi32(_mm_cvtps_epi32(s0), _mm_cvtps_epi32(s1)); + x1 = _mm_packs_epi32(_mm_cvtps_epi32(s2), _mm_cvtps_epi32(s3)); + x0 = _mm_packus_epi16(x0, x1); + _mm_storeu_si128((__m128i*)(dst + i), x0); + */ + } + + for( ; i <= width - 4; i += 4 ) + { + CV_Error(CV_StsBadArg, "NEON's SymmColumnVec_32s8u function not fully implemented (4)"); + /* + __m128 f = _mm_load_ss(ky); + f = _mm_shuffle_ps(f, f, 0); + __m128i x0; + __m128 s0 = _mm_cvtepi32_ps(_mm_load_si128((const __m128i*)(src[0] + i))); + s0 = _mm_add_ps(_mm_mul_ps(s0, f), d4); + */ + + for( k = 1; k <= ksize2; k++ ) + { + /* + S = (const __m128i*)(src[k] + i); + S2 = (const __m128i*)(src[-k] + i); + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_add_epi32(_mm_load_si128(S), _mm_load_si128(S2)); + s0 = _mm_add_ps(s0, _mm_mul_ps(_mm_cvtepi32_ps(x0), f)); + */ + } + + /* + x0 = _mm_cvtps_epi32(s0); + x0 = _mm_packs_epi32(x0, x0); + x0 = _mm_packus_epi16(x0, x0); + *(int*)(dst + i) = _mm_cvtsi128_si32(x0); + */ + } + } + else + { + CV_Error(CV_StsBadArg, "NEON's SymmColumnVec_32s8u function not fully implemented (5)"); + for( ; i <= width - 16; i += 16 ) + { + /* + __m128 f, s0 = d4, s1 = d4, s2 = d4, s3 = d4; + __m128i x0, x1; + */ + + for( k = 1; k <= ksize2; k++ ) + { + /* + S = (const __m128i*)(src[k] + i); + S2 = (const __m128i*)(src[-k] + i); + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_sub_epi32(_mm_load_si128(S), _mm_load_si128(S2)); + x1 = _mm_sub_epi32(_mm_load_si128(S+1), _mm_load_si128(S2+1)); + s0 = _mm_add_ps(s0, _mm_mul_ps(_mm_cvtepi32_ps(x0), f)); + s1 = _mm_add_ps(s1, _mm_mul_ps(_mm_cvtepi32_ps(x1), f)); + x0 = _mm_sub_epi32(_mm_load_si128(S+2), _mm_load_si128(S2+2)); + x1 = _mm_sub_epi32(_mm_load_si128(S+3), _mm_load_si128(S2+3)); + s2 = _mm_add_ps(s2, _mm_mul_ps(_mm_cvtepi32_ps(x0), f)); + s3 = _mm_add_ps(s3, _mm_mul_ps(_mm_cvtepi32_ps(x1), f)); + */ + } + + /* + x0 = _mm_packs_epi32(_mm_cvtps_epi32(s0), _mm_cvtps_epi32(s1)); + x1 = _mm_packs_epi32(_mm_cvtps_epi32(s2), _mm_cvtps_epi32(s3)); + x0 = _mm_packus_epi16(x0, x1); + _mm_storeu_si128((__m128i*)(dst + i), x0); + */ + } + + for( ; i <= width - 4; i += 4 ) + { + CV_Error(CV_StsBadArg, "NEON's SymmColumnVec_32s8u function not fully implemented (6)"); + /* + __m128 f, s0 = d4; + __m128i x0; + */ + + for( k = 1; k <= ksize2; k++ ) + { + /* + S = (const __m128i*)(src[k] + i); + S2 = (const __m128i*)(src[-k] + i); + f = _mm_load_ss(ky+k); + f = _mm_shuffle_ps(f, f, 0); + x0 = _mm_sub_epi32(_mm_load_si128(S), _mm_load_si128(S2)); + s0 = _mm_add_ps(s0, _mm_mul_ps(_mm_cvtepi32_ps(x0), f)); + */ + } + /* + x0 = _mm_cvtps_epi32(s0); + x0 = _mm_packs_epi32(x0, x0); + x0 = _mm_packus_epi16(x0, x0); + *(int*)(dst + i) = _mm_cvtsi128_si32(x0); + */ + } + } + + return i; + } + + int symmetryType; + float delta; + Mat kernel; + }; + #endif + + + #pragma mark ANUVIS SymmColumnSmallVec_32s16s + #if USE_SymmColumnSmallVec_32s16s + struct SymmColumnSmallVec_32s16s + { + SymmColumnSmallVec_32s16s() { symmetryType=0; } + SymmColumnSmallVec_32s16s(const Mat& _kernel, int _symmetryType, int _bits, double _delta) + { + symmetryType = _symmetryType; + _kernel.convertTo(kernel, CV_32F, 1./(1 << _bits), 0); + delta = (float)(_delta/(1 << _bits)); + CV_Assert( (symmetryType & (KERNEL_SYMMETRICAL | KERNEL_ASYMMETRICAL)) != 0 ); + } + + int operator()(const uchar** _src, uchar* _dst, int width) const + { + #if ANUVIS_TEST + CV_Error( CV_StsBadArg, "NEON's SymmColumnSmallVec_32s16s was called" ); + #endif + + /* + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + */ + + if (!cv::useOptimized()) { + return 0; + } + + int ksize2 = (kernel.rows + kernel.cols - 1)/2; + const float* ky = (const float*)kernel.data + ksize2; + int i = 0; + bool symmetrical = (symmetryType & KERNEL_SYMMETRICAL) != 0; + const int** src = (const int**)_src; + const int *S0 = src[-1], *S1 = src[0], *S2 = src[1]; + short* dst = (short*)_dst; + /* + __m128 df4 = _mm_set1_ps(delta); + __m128i d4 = _mm_cvtps_epi32(df4); + */ + + int16x8_t de4 = vdupq_n_s16((int16_t)delta); + int32x4_t d4 = vdupq_n_s32((int32_t)delta); + + if( symmetrical ) + { + if( ky[0] == 2 && ky[1] == 1 ) + { + #if ANUVIS_TEST + CV_Error(CV_StsBadArg, "NEON's SymmColumnSmallVec_32s16s function not fully implemented (1)"); + #endif + + for( ; i <= width - 8; i += 8 ) + { + + int32x4_t s0,s1,s2,s3,s4,s5; + + s0 = vld1q_s32((const int32_t*) (S0 + i)); + s1 = vld1q_s32((const int32_t*) (S0 + i + 4)); + s2 = vld1q_s32((const int32_t*) (S1 + i)); + s3 = vld1q_s32((const int32_t*) (S1 + i + 4)); + s4 = vld1q_s32((const int32_t*) (S2 + i)); + s5 = vld1q_s32((const int32_t*) (S2 + i + 4)); + + s0 = vaddq_s32(s0, vaddq_s32(s4,vaddq_s32(s2,vaddq_s32(s2,d4)))); + s1 = vaddq_s32(s1, vaddq_s32(s5,vaddq_s32(s3,vaddq_s32(s3,d4)))); + + vst1_s16((int16_t*)(dst + i),vmovn_s32(s0)); + vst1_s16((int16_t*)(dst + i + 4),vmovn_s32(s1)); + + //vst1q_s16((int16_t*)(dst + i + 8),s1); + + /* + //neon version + //int16x8_t s0,s1,s2,s3,s4,s5; + int16x8_t s0,s2,s4; + + s0 = vld1q_s16((const int16_t*) (S0 + i)); + //s1 = vld1q_s16((const int16_t*) (S0 + i + 8)); + s2 = vld1q_s16((const int16_t*) (S1 + i)); + //s3 = vld1q_s16((const int16_t*) (S1 + i + 8)); + s4 = vld1q_s16((const int16_t*) (S2 + i)); + //s5 = vld1q_s16((const int16_t*) (S2 + i + 8)); + + s0 = vaddq_s16(s0, vaddq_s16(s4,vaddq_s16(s2,vaddq_s16(s2,d4)))); + //s1 = vaddq_s16(s1, vaddq_s16(s5,vaddq_s16(s3,vaddq_s16(s3,d4)))); + + vst1q_s16((int16_t*)(dst + i),s0); + //vst1q_s16((int16_t*)(dst + i + 8),s1); + */ + + /* + //c version + for (int j = 0; j < 8; j++) { + int s0,s1,s2,s3,s4,s5; + s0 = *(S0 + i + j); + s1 = *(S0 + i + j + 4); + s2 = *(S1 + i + j); + s3 = *(S1 + i + j + 4); + s4 = *(S2 + i + j); + s5 = *(S2 + i + j + 4); + + s0 = s0+s4+s2+s2+(int32_t)delta; + s1 = s1+s5+s3+s3+(int32_t)delta; + + dst[i+j] = s0; + + } + */ + + /* + //SSE version + __m128i s0, s1, s2, s3, s4, s5; + s0 = _mm_load_si128((__m128i*)(S0 + i)); + s1 = _mm_load_si128((__m128i*)(S0 + i + 4)); + s2 = _mm_load_si128((__m128i*)(S1 + i)); + s3 = _mm_load_si128((__m128i*)(S1 + i + 4)); + s4 = _mm_load_si128((__m128i*)(S2 + i)); + s5 = _mm_load_si128((__m128i*)(S2 + i + 4)); + s0 = _mm_add_epi32(s0, _mm_add_epi32(s4, _mm_add_epi32(s2, s2))); + s1 = _mm_add_epi32(s1, _mm_add_epi32(s5, _mm_add_epi32(s3, s3))); + s0 = _mm_add_epi32(s0, d4); + s1 = _mm_add_epi32(s1, d4); + _mm_storeu_si128((__m128i*)(dst + i), _mm_packs_epi32(s0, s1)); + */ + } + } + else if( ky[0] == -2 && ky[1] == 1 ) + { + CV_Error(CV_StsBadArg, "NEON's SymmColumnSmallVec_32s16s function not fully implemented (2)"); + for( ; i <= width - 8; i += 8 ) + { + /* + __m128i s0, s1, s2, s3, s4, s5; + s0 = _mm_load_si128((__m128i*)(S0 + i)); + s1 = _mm_load_si128((__m128i*)(S0 + i + 4)); + s2 = _mm_load_si128((__m128i*)(S1 + i)); + s3 = _mm_load_si128((__m128i*)(S1 + i + 4)); + s4 = _mm_load_si128((__m128i*)(S2 + i)); + s5 = _mm_load_si128((__m128i*)(S2 + i + 4)); + s0 = _mm_add_epi32(s0, _mm_sub_epi32(s4, _mm_add_epi32(s2, s2))); + s1 = _mm_add_epi32(s1, _mm_sub_epi32(s5, _mm_add_epi32(s3, s3))); + s0 = _mm_add_epi32(s0, d4); + s1 = _mm_add_epi32(s1, d4); + _mm_storeu_si128((__m128i*)(dst + i), _mm_packs_epi32(s0, s1)); + */ + } + } + else + { + CV_Error(CV_StsBadArg, "NEON's SymmColumnSmallVec_32s16s function not fully implemented (3)"); + /* + __m128 k0 = _mm_set1_ps(ky[0]), k1 = _mm_set1_ps(ky[1]); + */ + for( ; i <= width - 8; i += 8 ) + { + /* + __m128 s0, s1; + s0 = _mm_cvtepi32_ps(_mm_load_si128((__m128i*)(S1 + i))); + s1 = _mm_cvtepi32_ps(_mm_load_si128((__m128i*)(S1 + i + 4))); + s0 = _mm_add_ps(_mm_mul_ps(s0, k0), df4); + s1 = _mm_add_ps(_mm_mul_ps(s1, k0), df4); + __m128i x0, x1; + x0 = _mm_add_epi32(_mm_load_si128((__m128i*)(S0 + i)), + _mm_load_si128((__m128i*)(S2 + i))); + x1 = _mm_add_epi32(_mm_load_si128((__m128i*)(S0 + i + 4)), + _mm_load_si128((__m128i*)(S2 + i + 4))); + s0 = _mm_add_ps(s0, _mm_mul_ps(_mm_cvtepi32_ps(x0),k1)); + s1 = _mm_add_ps(s1, _mm_mul_ps(_mm_cvtepi32_ps(x1),k1)); + x0 = _mm_packs_epi32(_mm_cvtps_epi32(s0), _mm_cvtps_epi32(s1)); + _mm_storeu_si128((__m128i*)(dst + i), x0); + */ + } + } + } + else + { + if( fabs(ky[1]) == 1 && ky[1] == -ky[-1] ) + { + #if ANUVIS_TEST + CV_Error(CV_StsBadArg, "NEON's SymmColumnSmallVec_32s16s function not fully implemented (4)"); + #endif + + if( ky[1] < 0 ) + std::swap(S0, S2); + for( ; i <= width - 8; i += 8 ) + { + + int32x4_t s0,s1,s2,s3; + + s0 = vld1q_s32((const int32_t*) (S2 + i)); + s1 = vld1q_s32((const int32_t*) (S2 + i + 4)); + s2 = vld1q_s32((const int32_t*) (S0 + i)); + s3 = vld1q_s32((const int32_t*) (S0 + i + 4)); + + s0 = vaddq_s32(vsubq_s32(s0, s2),d4); + s1 = vaddq_s32(vsubq_s32(s1, s3),d4); + + vst1_s16((int16_t*)(dst + i),vmovn_s32(s0)); + vst1_s16((int16_t*)(dst + i + 4),vmovn_s32(s1)); + + /* + //neon version + int16x8_t s0,s2; + + s0 = vld1q_s16((const int16_t*) (S2 + i)); + s2 = vld1q_s16((const int16_t*) (S0 + i)); + + s0 = vaddq_s16(vsubq_s16(s0, s2),de4); + + vst1q_s16((int16_t*)(dst + i),s0); + */ + + /* + //c version + for (int j = 0; j < 8; j++) { + int s0,s1,s2,s3; + s0 = *(S2 + i + j); + s1 = *(S2 + i + j + 4); + s2 = *(S0 + i + j); + s3 = *(S0 + i + j + 4); + + s0 = (s0-s2)+(int32_t)delta; + s1 = (s0-s2)+(int32_t)delta; + + dst[i+j] = s0; + //dst[i+j+4] = s1; + + } + */ + + /* + + //sse version + __m128i s0, s1, s2, s3; + s0 = _mm_load_si128((__m128i*)(S2 + i)); + s1 = _mm_load_si128((__m128i*)(S2 + i + 4)); + s2 = _mm_load_si128((__m128i*)(S0 + i)); + s3 = _mm_load_si128((__m128i*)(S0 + i + 4)); + s0 = _mm_add_epi32(_mm_sub_epi32(s0, s2), d4); + s1 = _mm_add_epi32(_mm_sub_epi32(s1, s3), d4); + _mm_storeu_si128((__m128i*)(dst + i), _mm_packs_epi32(s0, s1)); + */ + } + } + else + { + CV_Error(CV_StsBadArg, "NEON's SymmColumnSmallVec_32s16s function not fully implemented (5)"); + /* + __m128 k1 = _mm_set1_ps(ky[1]); + */ + for( ; i <= width - 8; i += 8 ) + { + /* + __m128 s0 = df4, s1 = df4; + __m128i x0, x1; + x0 = _mm_sub_epi32(_mm_load_si128((__m128i*)(S0 + i)), + _mm_load_si128((__m128i*)(S2 + i))); + x1 = _mm_sub_epi32(_mm_load_si128((__m128i*)(S0 + i + 4)), + _mm_load_si128((__m128i*)(S2 + i + 4))); + s0 = _mm_add_ps(s0, _mm_mul_ps(_mm_cvtepi32_ps(x0),k1)); + s1 = _mm_add_ps(s1, _mm_mul_ps(_mm_cvtepi32_ps(x1),k1)); + x0 = _mm_packs_epi32(_mm_cvtps_epi32(s0), _mm_cvtps_epi32(s1)); + _mm_storeu_si128((__m128i*)(dst + i), x0); + */ + } + } + } + + return i; + + + } + + int symmetryType; + float delta; + Mat kernel; + }; + #endif +#else + +typedef RowNoVec RowVec_8u32s; +typedef RowNoVec RowVec_16s32f; +typedef RowNoVec RowVec_32f; +typedef SymmRowSmallNoVec SymmRowSmallVec_8u32s; +typedef SymmRowSmallNoVec SymmRowSmallVec_32f; +typedef ColumnNoVec SymmColumnVec_32s8u; +typedef ColumnNoVec SymmColumnVec_32f16s; +typedef ColumnNoVec SymmColumnVec_32f; +typedef SymmColumnSmallNoVec SymmColumnSmallVec_32s16s; +typedef SymmColumnSmallNoVec SymmColumnSmallVec_32f; +typedef FilterNoVec FilterVec_8u; +typedef FilterNoVec FilterVec_8u16s; +typedef FilterNoVec FilterVec_32f; + +#endif + + +template struct RowFilter : public BaseRowFilter +{ + RowFilter( const Mat& _kernel, int _anchor, const VecOp& _vecOp=VecOp() ) + { + if( _kernel.isContinuous() ) + kernel = _kernel; + else + _kernel.copyTo(kernel); + anchor = _anchor; + ksize = kernel.rows + kernel.cols - 1; + CV_Assert( kernel.type() == DataType
::type && + (kernel.rows == 1 || kernel.cols == 1)); + vecOp = _vecOp; + } + + void operator()(const uchar* src, uchar* dst, int width, int cn) + { + int _ksize = ksize; + const DT* kx = (const DT*)kernel.data; + const ST* S; + DT* D = (DT*)dst; + int i, k; + + i = vecOp(src, dst, width, cn); + width *= cn; + #if CV_ENABLE_UNROLLED + for( ; i <= width - 4; i += 4 ) + { + S = (const ST*)src + i; + DT f = kx[0]; + DT s0 = f*S[0], s1 = f*S[1], s2 = f*S[2], s3 = f*S[3]; + + for( k = 1; k < _ksize; k++ ) + { + S += cn; + f = kx[k]; + s0 += f*S[0]; s1 += f*S[1]; + s2 += f*S[2]; s3 += f*S[3]; + } + + D[i] = s0; D[i+1] = s1; + D[i+2] = s2; D[i+3] = s3; + } + #endif + for( ; i < width; i++ ) + { + S = (const ST*)src + i; + DT s0 = kx[0]*S[0]; + for( k = 1; k < _ksize; k++ ) + { + S += cn; + s0 += kx[k]*S[0]; + } + D[i] = s0; + } + } + + Mat kernel; + VecOp vecOp; +}; + + +template struct SymmRowSmallFilter : + public RowFilter +{ + SymmRowSmallFilter( const Mat& _kernel, int _anchor, int _symmetryType, + const VecOp& _vecOp = VecOp()) + : RowFilter( _kernel, _anchor, _vecOp ) + { + symmetryType = _symmetryType; + CV_Assert( (symmetryType & (KERNEL_SYMMETRICAL | KERNEL_ASYMMETRICAL)) != 0 && this->ksize <= 5 ); + } + + void operator()(const uchar* src, uchar* dst, int width, int cn) + { + int ksize2 = this->ksize/2, ksize2n = ksize2*cn; + const DT* kx = (const DT*)this->kernel.data + ksize2; + bool symmetrical = (this->symmetryType & KERNEL_SYMMETRICAL) != 0; + DT* D = (DT*)dst; + int i = this->vecOp(src, dst, width, cn), j, k; + const ST* S = (const ST*)src + i + ksize2n; + width *= cn; + + if( symmetrical ) + { + if( this->ksize == 1 && kx[0] == 1 ) + { + for( ; i <= width - 2; i += 2 ) + { + DT s0 = S[i], s1 = S[i+1]; + D[i] = s0; D[i+1] = s1; + } + S += i; + } + else if( this->ksize == 3 ) + { + if( kx[0] == 2 && kx[1] == 1 ) + for( ; i <= width - 2; i += 2, S += 2 ) + { + DT s0 = S[-cn] + S[0]*2 + S[cn], s1 = S[1-cn] + S[1]*2 + S[1+cn]; + D[i] = s0; D[i+1] = s1; + } + else if( kx[0] == -2 && kx[1] == 1 ) + for( ; i <= width - 2; i += 2, S += 2 ) + { + DT s0 = S[-cn] - S[0]*2 + S[cn], s1 = S[1-cn] - S[1]*2 + S[1+cn]; + D[i] = s0; D[i+1] = s1; + } + else + { + DT k0 = kx[0], k1 = kx[1]; + for( ; i <= width - 2; i += 2, S += 2 ) + { + DT s0 = S[0]*k0 + (S[-cn] + S[cn])*k1, s1 = S[1]*k0 + (S[1-cn] + S[1+cn])*k1; + D[i] = s0; D[i+1] = s1; + } + } + } + else if( this->ksize == 5 ) + { + DT k0 = kx[0], k1 = kx[1], k2 = kx[2]; + if( k0 == -2 && k1 == 0 && k2 == 1 ) + for( ; i <= width - 2; i += 2, S += 2 ) + { + DT s0 = -2*S[0] + S[-cn*2] + S[cn*2]; + DT s1 = -2*S[1] + S[1-cn*2] + S[1+cn*2]; + D[i] = s0; D[i+1] = s1; + } + else + for( ; i <= width - 2; i += 2, S += 2 ) + { + DT s0 = S[0]*k0 + (S[-cn] + S[cn])*k1 + (S[-cn*2] + S[cn*2])*k2; + DT s1 = S[1]*k0 + (S[1-cn] + S[1+cn])*k1 + (S[1-cn*2] + S[1+cn*2])*k2; + D[i] = s0; D[i+1] = s1; + } + } + + for( ; i < width; i++, S++ ) + { + DT s0 = kx[0]*S[0]; + for( k = 1, j = cn; k <= ksize2; k++, j += cn ) + s0 += kx[k]*(S[j] + S[-j]); + D[i] = s0; + } + } + else + { + if( this->ksize == 3 ) + { + if( kx[0] == 0 && kx[1] == 1 ) + for( ; i <= width - 2; i += 2, S += 2 ) + { + DT s0 = S[cn] - S[-cn], s1 = S[1+cn] - S[1-cn]; + D[i] = s0; D[i+1] = s1; + } + else + { + DT k1 = kx[1]; + for( ; i <= width - 2; i += 2, S += 2 ) + { + DT s0 = (S[cn] - S[-cn])*k1, s1 = (S[1+cn] - S[1-cn])*k1; + D[i] = s0; D[i+1] = s1; + } + } + } + else if( this->ksize == 5 ) + { + DT k1 = kx[1], k2 = kx[2]; + for( ; i <= width - 2; i += 2, S += 2 ) + { + DT s0 = (S[cn] - S[-cn])*k1 + (S[cn*2] - S[-cn*2])*k2; + DT s1 = (S[1+cn] - S[1-cn])*k1 + (S[1+cn*2] - S[1-cn*2])*k2; + D[i] = s0; D[i+1] = s1; + } + } + + for( ; i < width; i++, S++ ) + { + DT s0 = kx[0]*S[0]; + for( k = 1, j = cn; k <= ksize2; k++, j += cn ) + s0 += kx[k]*(S[j] - S[-j]); + D[i] = s0; + } + } + } + + int symmetryType; +}; + + +template struct ColumnFilter : public BaseColumnFilter +{ + typedef typename CastOp::type1 ST; + typedef typename CastOp::rtype DT; + + ColumnFilter( const Mat& _kernel, int _anchor, + double _delta, const CastOp& _castOp=CastOp(), + const VecOp& _vecOp=VecOp() ) + { + if( _kernel.isContinuous() ) + kernel = _kernel; + else + _kernel.copyTo(kernel); + anchor = _anchor; + ksize = kernel.rows + kernel.cols - 1; + delta = saturate_cast(_delta); + castOp0 = _castOp; + vecOp = _vecOp; + CV_Assert( kernel.type() == DataType::type && + (kernel.rows == 1 || kernel.cols == 1)); + } + + void operator()(const uchar** src, uchar* dst, int dststep, int count, int width) + { + const ST* ky = (const ST*)kernel.data; + ST _delta = delta; + int _ksize = ksize; + int i, k; + CastOp castOp = castOp0; + + for( ; count--; dst += dststep, src++ ) + { + DT* D = (DT*)dst; + i = vecOp(src, dst, width); + #if CV_ENABLE_UNROLLED + for( ; i <= width - 4; i += 4 ) + { + ST f = ky[0]; + const ST* S = (const ST*)src[0] + i; + ST s0 = f*S[0] + _delta, s1 = f*S[1] + _delta, + s2 = f*S[2] + _delta, s3 = f*S[3] + _delta; + + for( k = 1; k < _ksize; k++ ) + { + S = (const ST*)src[k] + i; f = ky[k]; + s0 += f*S[0]; s1 += f*S[1]; + s2 += f*S[2]; s3 += f*S[3]; + } + + D[i] = castOp(s0); D[i+1] = castOp(s1); + D[i+2] = castOp(s2); D[i+3] = castOp(s3); + } + #endif + for( ; i < width; i++ ) + { + ST s0 = ky[0]*((const ST*)src[0])[i] + _delta; + for( k = 1; k < _ksize; k++ ) + s0 += ky[k]*((const ST*)src[k])[i]; + D[i] = castOp(s0); + } + } + } + + Mat kernel; + CastOp castOp0; + VecOp vecOp; + ST delta; +}; + + +template struct SymmColumnFilter : public ColumnFilter +{ + typedef typename CastOp::type1 ST; + typedef typename CastOp::rtype DT; + + SymmColumnFilter( const Mat& _kernel, int _anchor, + double _delta, int _symmetryType, + const CastOp& _castOp=CastOp(), + const VecOp& _vecOp=VecOp()) + : ColumnFilter( _kernel, _anchor, _delta, _castOp, _vecOp ) + { + symmetryType = _symmetryType; + CV_Assert( (symmetryType & (KERNEL_SYMMETRICAL | KERNEL_ASYMMETRICAL)) != 0 ); + } + + void operator()(const uchar** src, uchar* dst, int dststep, int count, int width) + { + int ksize2 = this->ksize/2; + const ST* ky = (const ST*)this->kernel.data + ksize2; + int i, k; + bool symmetrical = (symmetryType & KERNEL_SYMMETRICAL) != 0; + ST _delta = this->delta; + CastOp castOp = this->castOp0; + src += ksize2; + + if( symmetrical ) + { + for( ; count--; dst += dststep, src++ ) + { + DT* D = (DT*)dst; + i = (this->vecOp)(src, dst, width); + #if CV_ENABLE_UNROLLED + for( ; i <= width - 4; i += 4 ) + { + ST f = ky[0]; + const ST* S = (const ST*)src[0] + i, *S2; + ST s0 = f*S[0] + _delta, s1 = f*S[1] + _delta, + s2 = f*S[2] + _delta, s3 = f*S[3] + _delta; + + for( k = 1; k <= ksize2; k++ ) + { + S = (const ST*)src[k] + i; + S2 = (const ST*)src[-k] + i; + f = ky[k]; + s0 += f*(S[0] + S2[0]); + s1 += f*(S[1] + S2[1]); + s2 += f*(S[2] + S2[2]); + s3 += f*(S[3] + S2[3]); + } + + D[i] = castOp(s0); D[i+1] = castOp(s1); + D[i+2] = castOp(s2); D[i+3] = castOp(s3); + } + #endif + for( ; i < width; i++ ) + { + ST s0 = ky[0]*((const ST*)src[0])[i] + _delta; + for( k = 1; k <= ksize2; k++ ) + s0 += ky[k]*(((const ST*)src[k])[i] + ((const ST*)src[-k])[i]); + D[i] = castOp(s0); + } + } + } + else + { + for( ; count--; dst += dststep, src++ ) + { + DT* D = (DT*)dst; + i = this->vecOp(src, dst, width); + #if CV_ENABLE_UNROLLED + for( ; i <= width - 4; i += 4 ) + { + ST f = ky[0]; + const ST *S, *S2; + ST s0 = _delta, s1 = _delta, s2 = _delta, s3 = _delta; + + for( k = 1; k <= ksize2; k++ ) + { + S = (const ST*)src[k] + i; + S2 = (const ST*)src[-k] + i; + f = ky[k]; + s0 += f*(S[0] - S2[0]); + s1 += f*(S[1] - S2[1]); + s2 += f*(S[2] - S2[2]); + s3 += f*(S[3] - S2[3]); + } + + D[i] = castOp(s0); D[i+1] = castOp(s1); + D[i+2] = castOp(s2); D[i+3] = castOp(s3); + } + #endif + for( ; i < width; i++ ) + { + ST s0 = _delta; + for( k = 1; k <= ksize2; k++ ) + s0 += ky[k]*(((const ST*)src[k])[i] - ((const ST*)src[-k])[i]); + D[i] = castOp(s0); + } + } + } + } + + int symmetryType; +}; + + +template +struct SymmColumnSmallFilter : public SymmColumnFilter +{ + typedef typename CastOp::type1 ST; + typedef typename CastOp::rtype DT; + + SymmColumnSmallFilter( const Mat& _kernel, int _anchor, + double _delta, int _symmetryType, + const CastOp& _castOp=CastOp(), + const VecOp& _vecOp=VecOp()) + : SymmColumnFilter( _kernel, _anchor, _delta, _symmetryType, _castOp, _vecOp ) + { + CV_Assert( this->ksize == 3 ); + } + + void operator()(const uchar** src, uchar* dst, int dststep, int count, int width) + { + int ksize2 = this->ksize/2; + const ST* ky = (const ST*)this->kernel.data + ksize2; + int i; + bool symmetrical = (this->symmetryType & KERNEL_SYMMETRICAL) != 0; + bool is_1_2_1 = ky[0] == 1 && ky[1] == 2; + bool is_1_m2_1 = ky[0] == 1 && ky[1] == -2; + bool is_m1_0_1 = ky[1] == 1 || ky[1] == -1; + ST f0 = ky[0], f1 = ky[1]; + ST _delta = this->delta; + CastOp castOp = this->castOp0; + src += ksize2; + + for( ; count--; dst += dststep, src++ ) + { + DT* D = (DT*)dst; + i = (this->vecOp)(src, dst, width); + const ST* S0 = (const ST*)src[-1]; + const ST* S1 = (const ST*)src[0]; + const ST* S2 = (const ST*)src[1]; + + if( symmetrical ) + { + if( is_1_2_1 ) + { + #if CV_ENABLE_UNROLLED + for( ; i <= width - 4; i += 4 ) + { + ST s0 = S0[i] + S1[i]*2 + S2[i] + _delta; + ST s1 = S0[i+1] + S1[i+1]*2 + S2[i+1] + _delta; + D[i] = castOp(s0); + D[i+1] = castOp(s1); + + s0 = S0[i+2] + S1[i+2]*2 + S2[i+2] + _delta; + s1 = S0[i+3] + S1[i+3]*2 + S2[i+3] + _delta; + D[i+2] = castOp(s0); + D[i+3] = castOp(s1); + } + #else + for( ; i < width; i ++ ) + { + ST s0 = S0[i] + S1[i]*2 + S2[i] + _delta; + D[i] = castOp(s0); + } + #endif + } + else if( is_1_m2_1 ) + { + #if CV_ENABLE_UNROLLED + for( ; i <= width - 4; i += 4 ) + { + ST s0 = S0[i] - S1[i]*2 + S2[i] + _delta; + ST s1 = S0[i+1] - S1[i+1]*2 + S2[i+1] + _delta; + D[i] = castOp(s0); + D[i+1] = castOp(s1); + + s0 = S0[i+2] - S1[i+2]*2 + S2[i+2] + _delta; + s1 = S0[i+3] - S1[i+3]*2 + S2[i+3] + _delta; + D[i+2] = castOp(s0); + D[i+3] = castOp(s1); + } + #else + for( ; i < width; i ++ ) + { + ST s0 = S0[i] - S1[i]*2 + S2[i] + _delta; + D[i] = castOp(s0); + } + #endif + } + else + { + #if CV_ENABLE_UNROLLED + for( ; i <= width - 4; i += 4 ) + { + ST s0 = (S0[i] + S2[i])*f1 + S1[i]*f0 + _delta; + ST s1 = (S0[i+1] + S2[i+1])*f1 + S1[i+1]*f0 + _delta; + D[i] = castOp(s0); + D[i+1] = castOp(s1); + + s0 = (S0[i+2] + S2[i+2])*f1 + S1[i+2]*f0 + _delta; + s1 = (S0[i+3] + S2[i+3])*f1 + S1[i+3]*f0 + _delta; + D[i+2] = castOp(s0); + D[i+3] = castOp(s1); + } + #else + for( ; i < width; i ++ ) + { + ST s0 = (S0[i] + S2[i])*f1 + S1[i]*f0 + _delta; + D[i] = castOp(s0); + } + #endif + } + for( ; i < width; i++ ) + D[i] = castOp((S0[i] + S2[i])*f1 + S1[i]*f0 + _delta); + } + else + { + if( is_m1_0_1 ) + { + if( f1 < 0 ) + std::swap(S0, S2); + #if CV_ENABLE_UNROLLED + for( ; i <= width - 4; i += 4 ) + { + ST s0 = S2[i] - S0[i] + _delta; + ST s1 = S2[i+1] - S0[i+1] + _delta; + D[i] = castOp(s0); + D[i+1] = castOp(s1); + + s0 = S2[i+2] - S0[i+2] + _delta; + s1 = S2[i+3] - S0[i+3] + _delta; + D[i+2] = castOp(s0); + D[i+3] = castOp(s1); + } + #else + for( ; i < width; i ++ ) + { + ST s0 = S2[i] - S0[i] + _delta; + D[i] = castOp(s0); + } + #endif + if( f1 < 0 ) + std::swap(S0, S2); + } + else + { + #if CV_ENABLE_UNROLLED + for( ; i <= width - 4; i += 4 ) + { + ST s0 = (S2[i] - S0[i])*f1 + _delta; + ST s1 = (S2[i+1] - S0[i+1])*f1 + _delta; + D[i] = castOp(s0); + D[i+1] = castOp(s1); + + s0 = (S2[i+2] - S0[i+2])*f1 + _delta; + s1 = (S2[i+3] - S0[i+3])*f1 + _delta; + D[i+2] = castOp(s0); + D[i+3] = castOp(s1); + } + #endif + } + + for( ; i < width; i++ ) + D[i] = castOp((S2[i] - S0[i])*f1 + _delta); + } + } + } +}; + +template struct Cast +{ + typedef ST type1; + typedef DT rtype; + + DT operator()(ST val) const { return saturate_cast
(val); } +}; + +template struct FixedPtCast +{ + typedef ST type1; + typedef DT rtype; + enum { SHIFT = bits, DELTA = 1 << (bits-1) }; + + DT operator()(ST val) const { return saturate_cast
((val + DELTA)>>SHIFT); } +}; + +template struct FixedPtCastEx +{ + typedef ST type1; + typedef DT rtype; + + FixedPtCastEx() : SHIFT(0), DELTA(0) {} + FixedPtCastEx(int bits) : SHIFT(bits), DELTA(bits ? 1 << (bits-1) : 0) {} + DT operator()(ST val) const { return saturate_cast
((val + DELTA)>>SHIFT); } + int SHIFT, DELTA; +}; + +} + +cv::Ptr cv::getLinearRowFilter( int srcType, int bufType, + InputArray _kernel, int anchor, + int symmetryType ) +{ + Mat kernel = _kernel.getMat(); + int sdepth = CV_MAT_DEPTH(srcType), ddepth = CV_MAT_DEPTH(bufType); + int cn = CV_MAT_CN(srcType); + CV_Assert( cn == CV_MAT_CN(bufType) && + ddepth >= std::max(sdepth, CV_32S) && + kernel.type() == ddepth ); + int ksize = kernel.rows + kernel.cols - 1; + + if( (symmetryType & (KERNEL_SYMMETRICAL|KERNEL_ASYMMETRICAL)) != 0 && ksize <= 5 ) + { + if( sdepth == CV_8U && ddepth == CV_32S ) + return Ptr(new SymmRowSmallFilter + (kernel, anchor, symmetryType, SymmRowSmallVec_8u32s(kernel, symmetryType))); + if( sdepth == CV_32F && ddepth == CV_32F ) + return Ptr(new SymmRowSmallFilter + (kernel, anchor, symmetryType, SymmRowSmallVec_32f(kernel, symmetryType))); + } + + if( sdepth == CV_8U && ddepth == CV_32S ) + return Ptr(new RowFilter + (kernel, anchor, RowVec_8u32s(kernel))); + if( sdepth == CV_8U && ddepth == CV_32F ) + return Ptr(new RowFilter(kernel, anchor)); + if( sdepth == CV_8U && ddepth == CV_64F ) + return Ptr(new RowFilter(kernel, anchor)); + if( sdepth == CV_16U && ddepth == CV_32F ) + return Ptr(new RowFilter(kernel, anchor)); + if( sdepth == CV_16U && ddepth == CV_64F ) + return Ptr(new RowFilter(kernel, anchor)); + if( sdepth == CV_16S && ddepth == CV_32F ) + return Ptr(new RowFilter + (kernel, anchor, RowVec_16s32f(kernel))); + if( sdepth == CV_16S && ddepth == CV_64F ) + return Ptr(new RowFilter(kernel, anchor)); + if( sdepth == CV_32F && ddepth == CV_32F ) + return Ptr(new RowFilter + (kernel, anchor, RowVec_32f(kernel))); + if( sdepth == CV_32F && ddepth == CV_64F ) + return Ptr(new RowFilter(kernel, anchor)); + if( sdepth == CV_64F && ddepth == CV_64F ) + return Ptr(new RowFilter(kernel, anchor)); + + CV_Error_( CV_StsNotImplemented, + ("Unsupported combination of source format (=%d), and buffer format (=%d)", + srcType, bufType)); + + return Ptr(0); +} + + +cv::Ptr cv::getLinearColumnFilter( int bufType, int dstType, + InputArray _kernel, int anchor, + int symmetryType, double delta, + int bits ) +{ + Mat kernel = _kernel.getMat(); + int sdepth = CV_MAT_DEPTH(bufType), ddepth = CV_MAT_DEPTH(dstType); + int cn = CV_MAT_CN(dstType); + CV_Assert( cn == CV_MAT_CN(bufType) && + sdepth >= std::max(ddepth, CV_32S) && + kernel.type() == sdepth ); + + if( !(symmetryType & (KERNEL_SYMMETRICAL|KERNEL_ASYMMETRICAL)) ) + { + if( ddepth == CV_8U && sdepth == CV_32S ) + return Ptr(new ColumnFilter, ColumnNoVec> + (kernel, anchor, delta, FixedPtCastEx(bits))); + if( ddepth == CV_8U && sdepth == CV_32F ) + return Ptr(new ColumnFilter, ColumnNoVec>(kernel, anchor, delta)); + if( ddepth == CV_8U && sdepth == CV_64F ) + return Ptr(new ColumnFilter, ColumnNoVec>(kernel, anchor, delta)); + if( ddepth == CV_16U && sdepth == CV_32F ) + return Ptr(new ColumnFilter, ColumnNoVec>(kernel, anchor, delta)); + if( ddepth == CV_16U && sdepth == CV_64F ) + return Ptr(new ColumnFilter, ColumnNoVec>(kernel, anchor, delta)); + if( ddepth == CV_16S && sdepth == CV_32F ) + return Ptr(new ColumnFilter, ColumnNoVec>(kernel, anchor, delta)); + if( ddepth == CV_16S && sdepth == CV_64F ) + return Ptr(new ColumnFilter, ColumnNoVec>(kernel, anchor, delta)); + if( ddepth == CV_32F && sdepth == CV_32F ) + return Ptr(new ColumnFilter, ColumnNoVec>(kernel, anchor, delta)); + if( ddepth == CV_64F && sdepth == CV_64F ) + return Ptr(new ColumnFilter, ColumnNoVec>(kernel, anchor, delta)); + } + else + { + int ksize = kernel.rows + kernel.cols - 1; + if( ksize == 3 ) + { + if( ddepth == CV_8U && sdepth == CV_32S ) + return Ptr(new SymmColumnSmallFilter< + FixedPtCastEx, SymmColumnVec_32s8u> + (kernel, anchor, delta, symmetryType, FixedPtCastEx(bits), + SymmColumnVec_32s8u(kernel, symmetryType, bits, delta))); + if( ddepth == CV_16S && sdepth == CV_32S && bits == 0 ) + return Ptr(new SymmColumnSmallFilter, + SymmColumnSmallVec_32s16s>(kernel, anchor, delta, symmetryType, + Cast(), SymmColumnSmallVec_32s16s(kernel, symmetryType, bits, delta))); + if( ddepth == CV_32F && sdepth == CV_32F ) + return Ptr(new SymmColumnSmallFilter< + Cast,SymmColumnSmallVec_32f> + (kernel, anchor, delta, symmetryType, Cast(), + SymmColumnSmallVec_32f(kernel, symmetryType, 0, delta))); + } + if( ddepth == CV_8U && sdepth == CV_32S ) + return Ptr(new SymmColumnFilter, SymmColumnVec_32s8u> + (kernel, anchor, delta, symmetryType, FixedPtCastEx(bits), + SymmColumnVec_32s8u(kernel, symmetryType, bits, delta))); + if( ddepth == CV_8U && sdepth == CV_32F ) + return Ptr(new SymmColumnFilter, ColumnNoVec> + (kernel, anchor, delta, symmetryType)); + if( ddepth == CV_8U && sdepth == CV_64F ) + return Ptr(new SymmColumnFilter, ColumnNoVec> + (kernel, anchor, delta, symmetryType)); + if( ddepth == CV_16U && sdepth == CV_32F ) + return Ptr(new SymmColumnFilter, ColumnNoVec> + (kernel, anchor, delta, symmetryType)); + if( ddepth == CV_16U && sdepth == CV_64F ) + return Ptr(new SymmColumnFilter, ColumnNoVec> + (kernel, anchor, delta, symmetryType)); + if( ddepth == CV_16S && sdepth == CV_32S ) + return Ptr(new SymmColumnFilter, ColumnNoVec> + (kernel, anchor, delta, symmetryType)); + if( ddepth == CV_16S && sdepth == CV_32F ) + return Ptr(new SymmColumnFilter, SymmColumnVec_32f16s> + (kernel, anchor, delta, symmetryType, Cast(), + SymmColumnVec_32f16s(kernel, symmetryType, 0, delta))); + if( ddepth == CV_16S && sdepth == CV_64F ) + return Ptr(new SymmColumnFilter, ColumnNoVec> + (kernel, anchor, delta, symmetryType)); + if( ddepth == CV_32F && sdepth == CV_32F ) + return Ptr(new SymmColumnFilter, SymmColumnVec_32f> + (kernel, anchor, delta, symmetryType, Cast(), + SymmColumnVec_32f(kernel, symmetryType, 0, delta))); + if( ddepth == CV_64F && sdepth == CV_64F ) + return Ptr(new SymmColumnFilter, ColumnNoVec> + (kernel, anchor, delta, symmetryType)); + } + + CV_Error_( CV_StsNotImplemented, + ("Unsupported combination of buffer format (=%d), and destination format (=%d)", + bufType, dstType)); + + return Ptr(0); +} + + +cv::Ptr cv::createSeparableLinearFilter( + int _srcType, int _dstType, + InputArray __rowKernel, InputArray __columnKernel, + Point _anchor, double _delta, + int _rowBorderType, int _columnBorderType, + const Scalar& _borderValue ) +{ + Mat _rowKernel = __rowKernel.getMat(), _columnKernel = __columnKernel.getMat(); + _srcType = CV_MAT_TYPE(_srcType); + _dstType = CV_MAT_TYPE(_dstType); + int sdepth = CV_MAT_DEPTH(_srcType), ddepth = CV_MAT_DEPTH(_dstType); + int cn = CV_MAT_CN(_srcType); + CV_Assert( cn == CV_MAT_CN(_dstType) ); + int rsize = _rowKernel.rows + _rowKernel.cols - 1; + int csize = _columnKernel.rows + _columnKernel.cols - 1; + if( _anchor.x < 0 ) + _anchor.x = rsize/2; + if( _anchor.y < 0 ) + _anchor.y = csize/2; + int rtype = getKernelType(_rowKernel, + _rowKernel.rows == 1 ? Point(_anchor.x, 0) : Point(0, _anchor.x)); + int ctype = getKernelType(_columnKernel, + _columnKernel.rows == 1 ? Point(_anchor.y, 0) : Point(0, _anchor.y)); + Mat rowKernel, columnKernel; + + int bdepth = std::max(CV_32F,std::max(sdepth, ddepth)); + int bits = 0; + + if( sdepth == CV_8U && + ((rtype == KERNEL_SMOOTH+KERNEL_SYMMETRICAL && + ctype == KERNEL_SMOOTH+KERNEL_SYMMETRICAL && + ddepth == CV_8U) || + ((rtype & (KERNEL_SYMMETRICAL+KERNEL_ASYMMETRICAL)) && + (ctype & (KERNEL_SYMMETRICAL+KERNEL_ASYMMETRICAL)) && + (rtype & ctype & KERNEL_INTEGER) && + ddepth == CV_16S)) ) + { + bdepth = CV_32S; + bits = ddepth == CV_8U ? 8 : 0; + _rowKernel.convertTo( rowKernel, CV_32S, 1 << bits ); + _columnKernel.convertTo( columnKernel, CV_32S, 1 << bits ); + bits *= 2; + _delta *= (1 << bits); + } + else + { + if( _rowKernel.type() != bdepth ) + _rowKernel.convertTo( rowKernel, bdepth ); + else + rowKernel = _rowKernel; + if( _columnKernel.type() != bdepth ) + _columnKernel.convertTo( columnKernel, bdepth ); + else + columnKernel = _columnKernel; + } + + int _bufType = CV_MAKETYPE(bdepth, cn); + Ptr _rowFilter = getLinearRowFilter( + _srcType, _bufType, rowKernel, _anchor.x, rtype); + Ptr _columnFilter = getLinearColumnFilter( + _bufType, _dstType, columnKernel, _anchor.y, ctype, _delta, bits ); + + return Ptr( new FilterEngine(Ptr(0), _rowFilter, _columnFilter, + _srcType, _dstType, _bufType, _rowBorderType, _columnBorderType, _borderValue )); +} + + +/****************************************************************************************\ +* Non-separable linear filter * +\****************************************************************************************/ + +namespace cv +{ + +void preprocess2DKernel( const Mat& kernel, vector& coords, vector& coeffs ) +{ + int i, j, k, nz = countNonZero(kernel), ktype = kernel.type(); + if(nz == 0) + nz = 1; + CV_Assert( ktype == CV_8U || ktype == CV_32S || ktype == CV_32F || ktype == CV_64F ); + coords.resize(nz); + coeffs.resize(nz*getElemSize(ktype)); + uchar* _coeffs = &coeffs[0]; + + for( i = k = 0; i < kernel.rows; i++ ) + { + const uchar* krow = kernel.data + kernel.step*i; + for( j = 0; j < kernel.cols; j++ ) + { + if( ktype == CV_8U ) + { + uchar val = krow[j]; + if( val == 0 ) + continue; + coords[k] = Point(j,i); + _coeffs[k++] = val; + } + else if( ktype == CV_32S ) + { + int val = ((const int*)krow)[j]; + if( val == 0 ) + continue; + coords[k] = Point(j,i); + ((int*)_coeffs)[k++] = val; + } + else if( ktype == CV_32F ) + { + float val = ((const float*)krow)[j]; + if( val == 0 ) + continue; + coords[k] = Point(j,i); + ((float*)_coeffs)[k++] = val; + } + else + { + double val = ((const double*)krow)[j]; + if( val == 0 ) + continue; + coords[k] = Point(j,i); + ((double*)_coeffs)[k++] = val; + } + } + } +} + + +template struct Filter2D : public BaseFilter +{ + typedef typename CastOp::type1 KT; + typedef typename CastOp::rtype DT; + + Filter2D( const Mat& _kernel, Point _anchor, + double _delta, const CastOp& _castOp=CastOp(), + const VecOp& _vecOp=VecOp() ) + { + anchor = _anchor; + ksize = _kernel.size(); + delta = saturate_cast(_delta); + castOp0 = _castOp; + vecOp = _vecOp; + CV_Assert( _kernel.type() == DataType::type ); + preprocess2DKernel( _kernel, coords, coeffs ); + ptrs.resize( coords.size() ); + } + + void operator()(const uchar** src, uchar* dst, int dststep, int count, int width, int cn) + { + KT _delta = delta; + const Point* pt = &coords[0]; + const KT* kf = (const KT*)&coeffs[0]; + const ST** kp = (const ST**)&ptrs[0]; + int i, k, nz = (int)coords.size(); + CastOp castOp = castOp0; + + width *= cn; + for( ; count > 0; count--, dst += dststep, src++ ) + { + DT* D = (DT*)dst; + + for( k = 0; k < nz; k++ ) + kp[k] = (const ST*)src[pt[k].y] + pt[k].x*cn; + + i = vecOp((const uchar**)kp, dst, width); + #if CV_ENABLE_UNROLLED + for( ; i <= width - 4; i += 4 ) + { + KT s0 = _delta, s1 = _delta, s2 = _delta, s3 = _delta; + + for( k = 0; k < nz; k++ ) + { + const ST* sptr = kp[k] + i; + KT f = kf[k]; + s0 += f*sptr[0]; + s1 += f*sptr[1]; + s2 += f*sptr[2]; + s3 += f*sptr[3]; + } + + D[i] = castOp(s0); D[i+1] = castOp(s1); + D[i+2] = castOp(s2); D[i+3] = castOp(s3); + } + #endif + for( ; i < width; i++ ) + { + KT s0 = _delta; + for( k = 0; k < nz; k++ ) + s0 += kf[k]*kp[k][i]; + D[i] = castOp(s0); + } + } + } + + vector coords; + vector coeffs; + vector ptrs; + KT delta; + CastOp castOp0; + VecOp vecOp; +}; + +} + +cv::Ptr cv::getLinearFilter(int srcType, int dstType, + InputArray filter_kernel, Point anchor, + double delta, int bits) +{ + Mat _kernel = filter_kernel.getMat(); + int sdepth = CV_MAT_DEPTH(srcType), ddepth = CV_MAT_DEPTH(dstType); + int cn = CV_MAT_CN(srcType), kdepth = _kernel.depth(); + CV_Assert( cn == CV_MAT_CN(dstType) && ddepth >= sdepth ); + + anchor = normalizeAnchor(anchor, _kernel.size()); + + /*if( sdepth == CV_8U && ddepth == CV_8U && kdepth == CV_32S ) + return Ptr(new Filter2D, FilterVec_8u> + (_kernel, anchor, delta, FixedPtCastEx(bits), + FilterVec_8u(_kernel, bits, delta))); + if( sdepth == CV_8U && ddepth == CV_16S && kdepth == CV_32S ) + return Ptr(new Filter2D, FilterVec_8u16s> + (_kernel, anchor, delta, FixedPtCastEx(bits), + FilterVec_8u16s(_kernel, bits, delta)));*/ + + kdepth = sdepth == CV_64F || ddepth == CV_64F ? CV_64F : CV_32F; + Mat kernel; + if( _kernel.type() == kdepth ) + kernel = _kernel; + else + _kernel.convertTo(kernel, kdepth, _kernel.type() == CV_32S ? 1./(1 << bits) : 1.); + + if( sdepth == CV_8U && ddepth == CV_8U ) + return Ptr(new Filter2D, FilterVec_8u> + (kernel, anchor, delta, Cast(), FilterVec_8u(kernel, 0, delta))); + if( sdepth == CV_8U && ddepth == CV_16U ) + return Ptr(new Filter2D, FilterNoVec>(kernel, anchor, delta)); + if( sdepth == CV_8U && ddepth == CV_16S ) + return Ptr(new Filter2D, FilterVec_8u16s> + (kernel, anchor, delta, Cast(), FilterVec_8u16s(kernel, 0, delta))); + if( sdepth == CV_8U && ddepth == CV_32F ) + return Ptr(new Filter2D, FilterNoVec>(kernel, anchor, delta)); + if( sdepth == CV_8U && ddepth == CV_64F ) + return Ptr(new Filter2D, FilterNoVec>(kernel, anchor, delta)); + + if( sdepth == CV_16U && ddepth == CV_16U ) + return Ptr(new Filter2D, FilterNoVec>(kernel, anchor, delta)); + if( sdepth == CV_16U && ddepth == CV_32F ) + return Ptr(new Filter2D, FilterNoVec>(kernel, anchor, delta)); + if( sdepth == CV_16U && ddepth == CV_64F ) + return Ptr(new Filter2D, FilterNoVec>(kernel, anchor, delta)); + + if( sdepth == CV_16S && ddepth == CV_16S ) + return Ptr(new Filter2D, FilterNoVec>(kernel, anchor, delta)); + if( sdepth == CV_16S && ddepth == CV_32F ) + return Ptr(new Filter2D, FilterNoVec>(kernel, anchor, delta)); + if( sdepth == CV_16S && ddepth == CV_64F ) + return Ptr(new Filter2D, FilterNoVec>(kernel, anchor, delta)); + + if( sdepth == CV_32F && ddepth == CV_32F ) + return Ptr(new Filter2D, FilterVec_32f> + (kernel, anchor, delta, Cast(), FilterVec_32f(kernel, 0, delta))); + if( sdepth == CV_64F && ddepth == CV_64F ) + return Ptr(new Filter2D, FilterNoVec>(kernel, anchor, delta)); + + CV_Error_( CV_StsNotImplemented, + ("Unsupported combination of source format (=%d), and destination format (=%d)", + srcType, dstType)); + + return Ptr(0); +} + + +cv::Ptr cv::createLinearFilter( int _srcType, int _dstType, + InputArray filter_kernel, + Point _anchor, double _delta, + int _rowBorderType, int _columnBorderType, + const Scalar& _borderValue ) +{ + Mat _kernel = filter_kernel.getMat(); + _srcType = CV_MAT_TYPE(_srcType); + _dstType = CV_MAT_TYPE(_dstType); + int cn = CV_MAT_CN(_srcType); + CV_Assert( cn == CV_MAT_CN(_dstType) ); + + Mat kernel = _kernel; + int bits = 0; + + /*int sdepth = CV_MAT_DEPTH(_srcType), ddepth = CV_MAT_DEPTH(_dstType); + int ktype = _kernel.depth() == CV_32S ? KERNEL_INTEGER : getKernelType(_kernel, _anchor); + if( sdepth == CV_8U && (ddepth == CV_8U || ddepth == CV_16S) && + _kernel.rows*_kernel.cols <= (1 << 10) ) + { + bits = (ktype & KERNEL_INTEGER) ? 0 : 11; + _kernel.convertTo(kernel, CV_32S, 1 << bits); + }*/ + + Ptr _filter2D = getLinearFilter(_srcType, _dstType, + kernel, _anchor, _delta, bits); + + return Ptr(new FilterEngine(_filter2D, Ptr(0), + Ptr(0), _srcType, _dstType, _srcType, + _rowBorderType, _columnBorderType, _borderValue )); +} + + +void cv::filter2D( InputArray _src, OutputArray _dst, int ddepth, + InputArray _kernel, Point anchor, + double delta, int borderType ) +{ + Mat src = _src.getMat(), kernel = _kernel.getMat(); + + if( ddepth < 0 ) + ddepth = src.depth(); + +#if CV_SSE2 + int dft_filter_size = ((src.depth() == CV_8U && (ddepth == CV_8U || ddepth == CV_16S)) || + (src.depth() == CV_32F && ddepth == CV_32F)) && checkHardwareSupport(CV_CPU_SSE3)? 130 : 50; +#else + int dft_filter_size = 50; +#endif + + _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) ); + Mat dst = _dst.getMat(); + anchor = normalizeAnchor(anchor, kernel.size()); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if( tegra::filter2D(src, dst, kernel, anchor, delta, borderType) ) + return; +#endif + + if( kernel.cols*kernel.rows >= dft_filter_size ) + { + Mat temp; + if( src.data != dst.data ) + temp = dst; + else + temp.create(dst.size(), dst.type()); + crossCorr( src, kernel, temp, src.size(), + CV_MAKETYPE(ddepth, src.channels()), + anchor, delta, borderType ); + if( temp.data != dst.data ) + temp.copyTo(dst); + return; + } + + Ptr f = createLinearFilter(src.type(), dst.type(), kernel, + anchor, delta, borderType & ~BORDER_ISOLATED ); + f->apply(src, dst, Rect(0,0,-1,-1), Point(), (borderType & BORDER_ISOLATED) != 0 ); +} + + +void cv::sepFilter2D( InputArray _src, OutputArray _dst, int ddepth, + InputArray _kernelX, InputArray _kernelY, Point anchor, + double delta, int borderType ) +{ + Mat src = _src.getMat(), kernelX = _kernelX.getMat(), kernelY = _kernelY.getMat(); + + if( ddepth < 0 ) + ddepth = src.depth(); + + _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) ); + Mat dst = _dst.getMat(); + + Ptr f = createSeparableLinearFilter(src.type(), + dst.type(), kernelX, kernelY, anchor, delta, borderType & ~BORDER_ISOLATED ); + f->apply(src, dst, Rect(0,0,-1,-1), Point(), (borderType & BORDER_ISOLATED) != 0 ); +} + + +CV_IMPL void +cvFilter2D( const CvArr* srcarr, CvArr* dstarr, const CvMat* _kernel, CvPoint anchor ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + cv::Mat kernel = cv::cvarrToMat(_kernel); + + CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() ); + + cv::filter2D( src, dst, dst.depth(), kernel, anchor, 0, cv::BORDER_REPLICATE ); +} + +/* End of file. */ diff --git a/imgproc/src/floodfill.cpp b/imgproc/src/floodfill.cpp new file mode 100644 index 0000000..e970a31 --- /dev/null +++ b/imgproc/src/floodfill.cpp @@ -0,0 +1,646 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +typedef struct CvFFillSegment +{ + ushort y; + ushort l; + ushort r; + ushort prevl; + ushort prevr; + short dir; +} +CvFFillSegment; + +#define UP 1 +#define DOWN -1 + +#define ICV_PUSH( Y, L, R, PREV_L, PREV_R, DIR )\ +{ \ + tail->y = (ushort)(Y); \ + tail->l = (ushort)(L); \ + tail->r = (ushort)(R); \ + tail->prevl = (ushort)(PREV_L); \ + tail->prevr = (ushort)(PREV_R); \ + tail->dir = (short)(DIR); \ + if( ++tail >= buffer_end ) \ + tail = buffer; \ +} + + +#define ICV_POP( Y, L, R, PREV_L, PREV_R, DIR ) \ +{ \ + Y = head->y; \ + L = head->l; \ + R = head->r; \ + PREV_L = head->prevl; \ + PREV_R = head->prevr; \ + DIR = head->dir; \ + if( ++head >= buffer_end ) \ + head = buffer; \ +} + +/****************************************************************************************\ +* Simple Floodfill (repainting single-color connected component) * +\****************************************************************************************/ + +template +static void +icvFloodFill_CnIR( uchar* pImage, int step, CvSize roi, CvPoint seed, + _Tp newVal, CvConnectedComp* region, int flags, + CvFFillSegment* buffer, int buffer_size ) +{ + typedef typename cv::DataType<_Tp>::channel_type _CTp; + _Tp* img = (_Tp*)(pImage + step * seed.y); + int i, L, R; + int area = 0; + int XMin, XMax, YMin = seed.y, YMax = seed.y; + int _8_connectivity = (flags & 255) == 8; + CvFFillSegment* buffer_end = buffer + buffer_size, *head = buffer, *tail = buffer; + + L = R = XMin = XMax = seed.x; + + _Tp val0 = img[L]; + img[L] = newVal; + + while( ++R < roi.width && img[R] == val0 ) + img[R] = newVal; + + while( --L >= 0 && img[L] == val0 ) + img[L] = newVal; + + XMax = --R; + XMin = ++L; + ICV_PUSH( seed.y, L, R, R + 1, R, UP ); + + while( head != tail ) + { + int k, YC, PL, PR, dir; + ICV_POP( YC, L, R, PL, PR, dir ); + + int data[][3] = + { + {-dir, L - _8_connectivity, R + _8_connectivity}, + {dir, L - _8_connectivity, PL - 1}, + {dir, PR + 1, R + _8_connectivity} + }; + + if( region ) + { + area += R - L + 1; + + if( XMax < R ) XMax = R; + if( XMin > L ) XMin = L; + if( YMax < YC ) YMax = YC; + if( YMin > YC ) YMin = YC; + } + + for( k = 0; k < 3; k++ ) + { + dir = data[k][0]; + img = (_Tp*)(pImage + (YC + dir) * step); + int left = data[k][1]; + int right = data[k][2]; + + if( (unsigned)(YC + dir) >= (unsigned)roi.height ) + continue; + + for( i = left; i <= right; i++ ) + { + if( (unsigned)i < (unsigned)roi.width && img[i] == val0 ) + { + int j = i; + img[i] = newVal; + while( --j >= 0 && img[j] == val0 ) + img[j] = newVal; + + while( ++i < roi.width && img[i] == val0 ) + img[i] = newVal; + + ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir ); + } + } + } + } + + if( region ) + { + region->area = area; + region->rect.x = XMin; + region->rect.y = YMin; + region->rect.width = XMax - XMin + 1; + region->rect.height = YMax - YMin + 1; + region->value = cv::Scalar(newVal); + } +} + +/****************************************************************************************\ +* Gradient Floodfill * +\****************************************************************************************/ + +struct Diff8uC1 +{ + Diff8uC1(uchar _lo, uchar _up) : lo(_lo), interval(_lo + _up) {} + bool operator()(const uchar* a, const uchar* b) const + { return (unsigned)(a[0] - b[0] + lo) <= interval; } + unsigned lo, interval; +}; + +struct Diff8uC3 +{ + Diff8uC3(cv::Vec3b _lo, cv::Vec3b _up) + { + for( int k = 0; k < 3; k++ ) + lo[k] = _lo[k], interval[k] = _lo[k] + _up[k]; + } + bool operator()(const cv::Vec3b* a, const cv::Vec3b* b) const + { + return (unsigned)(a[0][0] - b[0][0] + lo[0]) <= interval[0] && + (unsigned)(a[0][1] - b[0][1] + lo[1]) <= interval[1] && + (unsigned)(a[0][2] - b[0][2] + lo[2]) <= interval[2]; + } + unsigned lo[3], interval[3]; +}; + +template +struct DiffC1 +{ + DiffC1(_Tp _lo, _Tp _up) : lo(-_lo), up(_up) {} + bool operator()(const _Tp* a, const _Tp* b) const + { + _Tp d = a[0] - b[0]; + return lo <= d && d <= up; + } + _Tp lo, up; +}; + +template +struct DiffC3 +{ + DiffC3(_Tp _lo, _Tp _up) : lo(-_lo), up(_up) {} + bool operator()(const _Tp* a, const _Tp* b) const + { + _Tp d = *a - *b; + return lo[0] <= d[0] && d[0] <= up[0] && + lo[1] <= d[1] && d[1] <= up[1] && + lo[2] <= d[2] && d[2] <= up[2]; + } + _Tp lo, up; +}; + +typedef DiffC1 Diff32sC1; +typedef DiffC3 Diff32sC3; +typedef DiffC1 Diff32fC1; +typedef DiffC3 Diff32fC3; + +static cv::Vec3i& operator += (cv::Vec3i& a, const cv::Vec3b& b) +{ + a[0] += b[0]; + a[1] += b[1]; + a[2] += b[2]; + return a; +} + +template +static void +icvFloodFillGrad_CnIR( uchar* pImage, int step, uchar* pMask, int maskStep, + CvSize /*roi*/, CvPoint seed, _Tp newVal, Diff diff, + CvConnectedComp* region, int flags, + CvFFillSegment* buffer, int buffer_size ) +{ + typedef typename cv::DataType<_Tp>::channel_type _CTp; + _Tp* img = (_Tp*)(pImage + step*seed.y); + uchar* mask = (pMask += maskStep + 1) + maskStep*seed.y; + int i, L, R; + int area = 0; + _WTp sum = _WTp((typename cv::DataType<_Tp>::channel_type)0); + int XMin, XMax, YMin = seed.y, YMax = seed.y; + int _8_connectivity = (flags & 255) == 8; + int fixedRange = flags & CV_FLOODFILL_FIXED_RANGE; + int fillImage = (flags & CV_FLOODFILL_MASK_ONLY) == 0; + uchar newMaskVal = (uchar)(flags & 0xff00 ? flags >> 8 : 1); + CvFFillSegment* buffer_end = buffer + buffer_size, *head = buffer, *tail = buffer; + + L = R = seed.x; + if( mask[L] ) + return; + + mask[L] = newMaskVal; + _Tp val0 = img[L]; + + if( fixedRange ) + { + while( !mask[R + 1] && diff( img + (R+1), &val0 )) + mask[++R] = newMaskVal; + + while( !mask[L - 1] && diff( img + (L-1), &val0 )) + mask[--L] = newMaskVal; + } + else + { + while( !mask[R + 1] && diff( img + (R+1), img + R )) + mask[++R] = newMaskVal; + + while( !mask[L - 1] && diff( img + (L-1), img + L )) + mask[--L] = newMaskVal; + } + + XMax = R; + XMin = L; + ICV_PUSH( seed.y, L, R, R + 1, R, UP ); + + while( head != tail ) + { + int k, YC, PL, PR, dir; + ICV_POP( YC, L, R, PL, PR, dir ); + + int data[][3] = + { + {-dir, L - _8_connectivity, R + _8_connectivity}, + {dir, L - _8_connectivity, PL - 1}, + {dir, PR + 1, R + _8_connectivity} + }; + + unsigned length = (unsigned)(R-L); + + if( region ) + { + area += (int)length + 1; + + if( XMax < R ) XMax = R; + if( XMin > L ) XMin = L; + if( YMax < YC ) YMax = YC; + if( YMin > YC ) YMin = YC; + } + + for( k = 0; k < 3; k++ ) + { + dir = data[k][0]; + img = (_Tp*)(pImage + (YC + dir) * step); + _Tp* img1 = (_Tp*)(pImage + YC * step); + mask = pMask + (YC + dir) * maskStep; + int left = data[k][1]; + int right = data[k][2]; + + if( fixedRange ) + for( i = left; i <= right; i++ ) + { + if( !mask[i] && diff( img + i, &val0 )) + { + int j = i; + mask[i] = newMaskVal; + while( !mask[--j] && diff( img + j, &val0 )) + mask[j] = newMaskVal; + + while( !mask[++i] && diff( img + i, &val0 )) + mask[i] = newMaskVal; + + ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir ); + } + } + else if( !_8_connectivity ) + for( i = left; i <= right; i++ ) + { + if( !mask[i] && diff( img + i, img1 + i )) + { + int j = i; + mask[i] = newMaskVal; + while( !mask[--j] && diff( img + j, img + (j+1) )) + mask[j] = newMaskVal; + + while( !mask[++i] && + (diff( img + i, img + (i-1) ) || + (diff( img + i, img1 + i) && i <= R))) + mask[i] = newMaskVal; + + ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir ); + } + } + else + for( i = left; i <= right; i++ ) + { + int idx; + _Tp val; + + if( !mask[i] && + (((val = img[i], + (unsigned)(idx = i-L-1) <= length) && + diff( &val, img1 + (i-1))) || + ((unsigned)(++idx) <= length && + diff( &val, img1 + i )) || + ((unsigned)(++idx) <= length && + diff( &val, img1 + (i+1) )))) + { + int j = i; + mask[i] = newMaskVal; + while( !mask[--j] && diff( img + j, img + (j+1) )) + mask[j] = newMaskVal; + + while( !mask[++i] && + ((val = img[i], + diff( &val, img + (i-1) )) || + (((unsigned)(idx = i-L-1) <= length && + diff( &val, img1 + (i-1) ))) || + ((unsigned)(++idx) <= length && + diff( &val, img1 + i )) || + ((unsigned)(++idx) <= length && + diff( &val, img1 + (i+1) )))) + mask[i] = newMaskVal; + + ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir ); + } + } + } + + img = (_Tp*)(pImage + YC * step); + if( fillImage ) + for( i = L; i <= R; i++ ) + img[i] = newVal; + else if( region ) + for( i = L; i <= R; i++ ) + sum += img[i]; + } + + if( region ) + { + region->area = area; + region->rect.x = XMin; + region->rect.y = YMin; + region->rect.width = XMax - XMin + 1; + region->rect.height = YMax - YMin + 1; + + if( fillImage ) + region->value = cv::Scalar(newVal); + else + { + double iarea = area ? 1./area : 0; + region->value = cv::Scalar(sum*iarea); + } + } +} + + +/****************************************************************************************\ +* External Functions * +\****************************************************************************************/ + +typedef void (*CvFloodFillFunc)( + void* img, int step, CvSize size, CvPoint seed, void* newval, + CvConnectedComp* comp, int flags, void* buffer, int buffer_size, int cn ); + +typedef void (*CvFloodFillGradFunc)( + void* img, int step, uchar* mask, int maskStep, CvSize size, + CvPoint seed, void* newval, void* d_lw, void* d_up, void* ccomp, + int flags, void* buffer, int buffer_size, int cn ); + +CV_IMPL void +cvFloodFill( CvArr* arr, CvPoint seed_point, + CvScalar newVal, CvScalar lo_diff, CvScalar up_diff, + CvConnectedComp* comp, int flags, CvArr* maskarr ) +{ + cv::Ptr tempMask; + cv::AutoBuffer buffer; + + if( comp ) + memset( comp, 0, sizeof(*comp) ); + + int i, type, depth, cn, is_simple; + int buffer_size, connectivity = flags & 255; + union { + uchar b[4]; + int i[4]; + float f[4]; + double _[4]; + } nv_buf; + nv_buf._[0] = nv_buf._[1] = nv_buf._[2] = nv_buf._[3] = 0; + + struct { cv::Vec3b b; cv::Vec3i i; cv::Vec3f f; } ld_buf, ud_buf; + CvMat stub, *img = cvGetMat(arr, &stub); + CvMat maskstub, *mask = (CvMat*)maskarr; + CvSize size; + + type = CV_MAT_TYPE( img->type ); + depth = CV_MAT_DEPTH(type); + cn = CV_MAT_CN(type); + + if( connectivity == 0 ) + connectivity = 4; + else if( connectivity != 4 && connectivity != 8 ) + CV_Error( CV_StsBadFlag, "Connectivity must be 4, 0(=4) or 8" ); + + is_simple = mask == 0 && (flags & CV_FLOODFILL_MASK_ONLY) == 0; + + for( i = 0; i < cn; i++ ) + { + if( lo_diff.val[i] < 0 || up_diff.val[i] < 0 ) + CV_Error( CV_StsBadArg, "lo_diff and up_diff must be non-negative" ); + is_simple &= fabs(lo_diff.val[i]) < DBL_EPSILON && fabs(up_diff.val[i]) < DBL_EPSILON; + } + + size = cvGetMatSize( img ); + + if( (unsigned)seed_point.x >= (unsigned)size.width || + (unsigned)seed_point.y >= (unsigned)size.height ) + CV_Error( CV_StsOutOfRange, "Seed point is outside of image" ); + + cvScalarToRawData( &newVal, &nv_buf, type, 0 ); + buffer_size = MAX( size.width, size.height )*2; + buffer.allocate( buffer_size ); + + if( is_simple ) + { + /*int elem_size = CV_ELEM_SIZE(type); + const uchar* seed_ptr = img->data.ptr + img->step*seed_point.y + elem_size*seed_point.x; + + // check if the new value is different from the current value at the seed point. + // if they are exactly the same, use the generic version with mask to avoid infinite loops. + for( i = 0; i < elem_size; i++ ) + if( seed_ptr[i] != ((uchar*)nv_buf)[i] ) + break; + + if( i == elem_size ) + return;*/ + + if( type == CV_8UC1 ) + icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point, nv_buf.b[0], + comp, flags, buffer, buffer_size); + else if( type == CV_8UC3 ) + icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point, cv::Vec3b(nv_buf.b), + comp, flags, buffer, buffer_size); + else if( type == CV_32SC1 ) + icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point, nv_buf.i[0], + comp, flags, buffer, buffer_size); + else if( type == CV_32FC1 ) + icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point, nv_buf.f[0], + comp, flags, buffer, buffer_size); + else if( type == CV_32SC3 ) + icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point, cv::Vec3i(nv_buf.i), + comp, flags, buffer, buffer_size); + else if( type == CV_32FC3 ) + icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point, cv::Vec3f(nv_buf.f), + comp, flags, buffer, buffer_size); + else + CV_Error( CV_StsUnsupportedFormat, "" ); + return; + } + + if( !mask ) + { + /* created mask will be 8-byte aligned */ + tempMask = cvCreateMat( size.height + 2, (size.width + 9) & -8, CV_8UC1 ); + mask = tempMask; + } + else + { + mask = cvGetMat( mask, &maskstub ); + if( !CV_IS_MASK_ARR( mask )) + CV_Error( CV_StsBadMask, "" ); + + if( mask->width != size.width + 2 || mask->height != size.height + 2 ) + CV_Error( CV_StsUnmatchedSizes, "mask must be 2 pixel wider " + "and 2 pixel taller than filled image" ); + } + + int width = tempMask ? mask->step : size.width + 2; + uchar* mask_row = mask->data.ptr + mask->step; + memset( mask_row - mask->step, 1, width ); + + for( i = 1; i <= size.height; i++, mask_row += mask->step ) + { + if( tempMask ) + memset( mask_row, 0, width ); + mask_row[0] = mask_row[size.width+1] = (uchar)1; + } + memset( mask_row, 1, width ); + + if( depth == CV_8U ) + for( i = 0; i < cn; i++ ) + { + int t = cvFloor(lo_diff.val[i]); + ld_buf.b[i] = CV_CAST_8U(t); + t = cvFloor(up_diff.val[i]); + ud_buf.b[i] = CV_CAST_8U(t); + } + else if( depth == CV_32S ) + for( i = 0; i < cn; i++ ) + { + int t = cvFloor(lo_diff.val[i]); + ld_buf.i[i] = t; + t = cvFloor(up_diff.val[i]); + ud_buf.i[i] = t; + } + else if( depth == CV_32F ) + for( i = 0; i < cn; i++ ) + { + ld_buf.f[i] = (float)lo_diff.val[i]; + ud_buf.f[i] = (float)up_diff.val[i]; + } + else + CV_Error( CV_StsUnsupportedFormat, "" ); + + if( type == CV_8UC1 ) + icvFloodFillGrad_CnIR( + img->data.ptr, img->step, mask->data.ptr, mask->step, + size, seed_point, nv_buf.b[0], + Diff8uC1(ld_buf.b[0], ud_buf.b[0]), + comp, flags, buffer, buffer_size); + else if( type == CV_8UC3 ) + icvFloodFillGrad_CnIR( + img->data.ptr, img->step, mask->data.ptr, mask->step, + size, seed_point, cv::Vec3b(nv_buf.b), + Diff8uC3(ld_buf.b, ud_buf.b), + comp, flags, buffer, buffer_size); + else if( type == CV_32SC1 ) + icvFloodFillGrad_CnIR( + img->data.ptr, img->step, mask->data.ptr, mask->step, + size, seed_point, nv_buf.i[0], + Diff32sC1(ld_buf.i[0], ud_buf.i[0]), + comp, flags, buffer, buffer_size); + else if( type == CV_32SC3 ) + icvFloodFillGrad_CnIR( + img->data.ptr, img->step, mask->data.ptr, mask->step, + size, seed_point, cv::Vec3i(nv_buf.i), + Diff32sC3(ld_buf.i, ud_buf.i), + comp, flags, buffer, buffer_size); + else if( type == CV_32FC1 ) + icvFloodFillGrad_CnIR( + img->data.ptr, img->step, mask->data.ptr, mask->step, + size, seed_point, nv_buf.f[0], + Diff32fC1(ld_buf.f[0], ud_buf.f[0]), + comp, flags, buffer, buffer_size); + else if( type == CV_32FC3 ) + icvFloodFillGrad_CnIR( + img->data.ptr, img->step, mask->data.ptr, mask->step, + size, seed_point, cv::Vec3f(nv_buf.f), + Diff32fC3(ld_buf.f, ud_buf.f), + comp, flags, buffer, buffer_size); + else + CV_Error(CV_StsUnsupportedFormat, ""); +} + + +int cv::floodFill( InputOutputArray _image, Point seedPoint, + Scalar newVal, Rect* rect, + Scalar loDiff, Scalar upDiff, int flags ) +{ + CvConnectedComp ccomp; + CvMat c_image = _image.getMat(); + cvFloodFill(&c_image, seedPoint, newVal, loDiff, upDiff, &ccomp, flags, 0); + if( rect ) + *rect = ccomp.rect; + return cvRound(ccomp.area); +} + +int cv::floodFill( InputOutputArray _image, InputOutputArray _mask, + Point seedPoint, Scalar newVal, Rect* rect, + Scalar loDiff, Scalar upDiff, int flags ) +{ + CvConnectedComp ccomp; + CvMat c_image = _image.getMat(), c_mask = _mask.getMat(); + cvFloodFill(&c_image, seedPoint, newVal, loDiff, upDiff, &ccomp, flags, c_mask.data.ptr ? &c_mask : 0); + if( rect ) + *rect = ccomp.rect; + return cvRound(ccomp.area); +} + +/* End of file. */ diff --git a/imgproc/src/gabor.cpp b/imgproc/src/gabor.cpp new file mode 100644 index 0000000..4cbbd24 --- /dev/null +++ b/imgproc/src/gabor.cpp @@ -0,0 +1,98 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2012, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +/* + Gabor filters and such. To be greatly extended to have full texture analysis. + For the formulas and the explanation of the parameters see: + http://en.wikipedia.org/wiki/Gabor_filter +*/ + +cv::Mat cv::getGaborKernel( Size ksize, double sigma, double theta, + double lambd, double gamma, double psi, int ktype ) +{ + double sigma_x = sigma; + double sigma_y = sigma/gamma; + int nstds = 3; + int xmin, xmax, ymin, ymax; + double c = cos(theta), s = sin(theta); + + if( ksize.width > 0 ) + xmax = ksize.width/2; + else + xmax = cvRound(std::max(fabs(nstds*sigma_x*c), fabs(nstds*sigma_y*s))); + + if( ksize.height > 0 ) + ymax = ksize.height/2; + else + ymax = cvRound(std::max(fabs(nstds*sigma_x*s), fabs(nstds*sigma_y*c))); + + xmin = -xmax; + ymin = -ymax; + + CV_Assert( ktype == CV_32F || ktype == CV_64F ); + + Mat kernel(ymax - ymin + 1, xmax - xmin + 1, ktype); + double scale = 1/(2*CV_PI*sigma_x*sigma_y); + double ex = -0.5/(sigma_x*sigma_x); + double ey = -0.5/(sigma_y*sigma_y); + double cscale = CV_PI*2/lambd; + + for( int y = ymin; y <= ymax; y++ ) + for( int x = xmin; x <= xmax; x++ ) + { + double xr = x*c + y*s; + double yr = -x*s + y*c; + + double v = scale*exp(ex*xr*xr + ey*yr*yr)*cos(cscale*xr + psi); + if( ktype == CV_32F ) + kernel.at(ymax - y, xmax - x) = (float)v; + else + kernel.at(ymax - y, xmax - x) = v; + } + + return kernel; +} + + +/* End of file. */ diff --git a/imgproc/src/gcgraph.hpp b/imgproc/src/gcgraph.hpp new file mode 100644 index 0000000..59c9744 --- /dev/null +++ b/imgproc/src/gcgraph.hpp @@ -0,0 +1,385 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef _CV_GCGRAPH_H_ +#define _CV_GCGRAPH_H_ + +template class GCGraph +{ +public: + GCGraph(); + GCGraph( unsigned int vtxCount, unsigned int edgeCount ); + ~GCGraph(); + void create( unsigned int vtxCount, unsigned int edgeCount ); + int addVtx(); + void addEdges( int i, int j, TWeight w, TWeight revw ); + void addTermWeights( int i, TWeight sourceW, TWeight sinkW ); + TWeight maxFlow(); + bool inSourceSegment( int i ); +private: + class Vtx + { + public: + Vtx *next; // initialized and used in maxFlow() only + int parent; + int first; + int ts; + int dist; + TWeight weight; + uchar t; + }; + class Edge + { + public: + int dst; + int next; + TWeight weight; + }; + + std::vector vtcs; + std::vector edges; + TWeight flow; +}; + +template +GCGraph::GCGraph() +{ + flow = 0; +} +template +GCGraph::GCGraph( unsigned int vtxCount, unsigned int edgeCount ) +{ + create( vtxCount, edgeCount ); +} +template +GCGraph::~GCGraph() +{ +} +template +void GCGraph::create( unsigned int vtxCount, unsigned int edgeCount ) +{ + vtcs.reserve( vtxCount ); + edges.reserve( edgeCount + 2 ); + flow = 0; +} + +template +int GCGraph::addVtx() +{ + Vtx v; + memset( &v, 0, sizeof(Vtx)); + vtcs.push_back(v); + return (int)vtcs.size() - 1; +} + +template +void GCGraph::addEdges( int i, int j, TWeight w, TWeight revw ) +{ + CV_Assert( i>=0 && i<(int)vtcs.size() ); + CV_Assert( j>=0 && j<(int)vtcs.size() ); + CV_Assert( w>=0 && revw>=0 ); + CV_Assert( i != j ); + + if( !edges.size() ) + edges.resize( 2 ); + + Edge fromI, toI; + fromI.dst = j; + fromI.next = vtcs[i].first; + fromI.weight = w; + vtcs[i].first = (int)edges.size(); + edges.push_back( fromI ); + + toI.dst = i; + toI.next = vtcs[j].first; + toI.weight = revw; + vtcs[j].first = (int)edges.size(); + edges.push_back( toI ); +} + +template +void GCGraph::addTermWeights( int i, TWeight sourceW, TWeight sinkW ) +{ + CV_Assert( i>=0 && i<(int)vtcs.size() ); + + TWeight dw = vtcs[i].weight; + if( dw > 0 ) + sourceW += dw; + else + sinkW -= dw; + flow += (sourceW < sinkW) ? sourceW : sinkW; + vtcs[i].weight = sourceW - sinkW; +} + +template +TWeight GCGraph::maxFlow() +{ + const int TERMINAL = -1, ORPHAN = -2; + Vtx stub, *nilNode = &stub, *first = nilNode, *last = nilNode; + int curr_ts = 0; + stub.next = nilNode; + Vtx *vtxPtr = &vtcs[0]; + Edge *edgePtr = &edges[0]; + + std::vector orphans; + + // initialize the active queue and the graph vertices + for( int i = 0; i < (int)vtcs.size(); i++ ) + { + Vtx* v = vtxPtr + i; + v->ts = 0; + if( v->weight != 0 ) + { + last = last->next = v; + v->dist = 1; + v->parent = TERMINAL; + v->t = v->weight < 0; + } + else + v->parent = 0; + } + first = first->next; + last->next = nilNode; + nilNode->next = 0; + + // run the search-path -> augment-graph -> restore-trees loop + for(;;) + { + Vtx* v, *u; + int e0 = -1, ei = 0, ej = 0; + TWeight minWeight, weight; + uchar vt; + + // grow S & T search trees, find an edge connecting them + while( first != nilNode ) + { + v = first; + if( v->parent ) + { + vt = v->t; + for( ei = v->first; ei != 0; ei = edgePtr[ei].next ) + { + if( edgePtr[ei^vt].weight == 0 ) + continue; + u = vtxPtr+edgePtr[ei].dst; + if( !u->parent ) + { + u->t = vt; + u->parent = ei ^ 1; + u->ts = v->ts; + u->dist = v->dist + 1; + if( !u->next ) + { + u->next = nilNode; + last = last->next = u; + } + continue; + } + + if( u->t != vt ) + { + e0 = ei ^ vt; + break; + } + + if( u->dist > v->dist+1 && u->ts <= v->ts ) + { + // reassign the parent + u->parent = ei ^ 1; + u->ts = v->ts; + u->dist = v->dist + 1; + } + } + if( e0 > 0 ) + break; + } + // exclude the vertex from the active list + first = first->next; + v->next = 0; + } + + if( e0 <= 0 ) + break; + + // find the minimum edge weight along the path + minWeight = edgePtr[e0].weight; + assert( minWeight > 0 ); + // k = 1: source tree, k = 0: destination tree + for( int k = 1; k >= 0; k-- ) + { + for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst ) + { + if( (ei = v->parent) < 0 ) + break; + weight = edgePtr[ei^k].weight; + minWeight = MIN(minWeight, weight); + assert( minWeight > 0 ); + } + weight = fabs(v->weight); + minWeight = MIN(minWeight, weight); + assert( minWeight > 0 ); + } + + // modify weights of the edges along the path and collect orphans + edgePtr[e0].weight -= minWeight; + edgePtr[e0^1].weight += minWeight; + flow += minWeight; + + // k = 1: source tree, k = 0: destination tree + for( int k = 1; k >= 0; k-- ) + { + for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst ) + { + if( (ei = v->parent) < 0 ) + break; + edgePtr[ei^(k^1)].weight += minWeight; + if( (edgePtr[ei^k].weight -= minWeight) == 0 ) + { + orphans.push_back(v); + v->parent = ORPHAN; + } + } + + v->weight = v->weight + minWeight*(1-k*2); + if( v->weight == 0 ) + { + orphans.push_back(v); + v->parent = ORPHAN; + } + } + + // restore the search trees by finding new parents for the orphans + curr_ts++; + while( !orphans.empty() ) + { + Vtx* v2 = orphans.back(); + orphans.pop_back(); + + int d, minDist = INT_MAX; + e0 = 0; + vt = v2->t; + + for( ei = v2->first; ei != 0; ei = edgePtr[ei].next ) + { + if( edgePtr[ei^(vt^1)].weight == 0 ) + continue; + u = vtxPtr+edgePtr[ei].dst; + if( u->t != vt || u->parent == 0 ) + continue; + // compute the distance to the tree root + for( d = 0;; ) + { + if( u->ts == curr_ts ) + { + d += u->dist; + break; + } + ej = u->parent; + d++; + if( ej < 0 ) + { + if( ej == ORPHAN ) + d = INT_MAX-1; + else + { + u->ts = curr_ts; + u->dist = 1; + } + break; + } + u = vtxPtr+edgePtr[ej].dst; + } + + // update the distance + if( ++d < INT_MAX ) + { + if( d < minDist ) + { + minDist = d; + e0 = ei; + } + for( u = vtxPtr+edgePtr[ei].dst; u->ts != curr_ts; u = vtxPtr+edgePtr[u->parent].dst ) + { + u->ts = curr_ts; + u->dist = --d; + } + } + } + + if( (v2->parent = e0) > 0 ) + { + v2->ts = curr_ts; + v2->dist = minDist; + continue; + } + + /* no parent is found */ + v2->ts = 0; + for( ei = v2->first; ei != 0; ei = edgePtr[ei].next ) + { + u = vtxPtr+edgePtr[ei].dst; + ej = u->parent; + if( u->t != vt || !ej ) + continue; + if( edgePtr[ei^(vt^1)].weight && !u->next ) + { + u->next = nilNode; + last = last->next = u; + } + if( ej > 0 && vtxPtr+edgePtr[ej].dst == v2 ) + { + orphans.push_back(u); + u->parent = ORPHAN; + } + } + } + } + return flow; +} + +template +bool GCGraph::inSourceSegment( int i ) +{ + CV_Assert( i>=0 && i<(int)vtcs.size() ); + return vtcs[i].t == 0; +}; + +#endif diff --git a/imgproc/src/geometry.cpp b/imgproc/src/geometry.cpp new file mode 100644 index 0000000..8c82e64 --- /dev/null +++ b/imgproc/src/geometry.cpp @@ -0,0 +1,774 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + + +CV_IMPL CvRect +cvMaxRect( const CvRect* rect1, const CvRect* rect2 ) +{ + if( rect1 && rect2 ) + { + CvRect max_rect; + int a, b; + + max_rect.x = a = rect1->x; + b = rect2->x; + if( max_rect.x > b ) + max_rect.x = b; + + max_rect.width = a += rect1->width; + b += rect2->width; + + if( max_rect.width < b ) + max_rect.width = b; + max_rect.width -= max_rect.x; + + max_rect.y = a = rect1->y; + b = rect2->y; + if( max_rect.y > b ) + max_rect.y = b; + + max_rect.height = a += rect1->height; + b += rect2->height; + + if( max_rect.height < b ) + max_rect.height = b; + max_rect.height -= max_rect.y; + return max_rect; + } + else if( rect1 ) + return *rect1; + else if( rect2 ) + return *rect2; + else + return cvRect(0,0,0,0); +} + + +CV_IMPL void +cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] ) +{ + if( !pt ) + CV_Error( CV_StsNullPtr, "NULL vertex array pointer" ); + cv::RotatedRect(box).points((cv::Point2f*)pt); +} + + +int +icvIntersectLines( double x1, double dx1, double y1, double dy1, + double x2, double dx2, double y2, double dy2, double *t2 ) +{ + double d = dx1 * dy2 - dx2 * dy1; + int result = -1; + + if( d != 0 ) + { + *t2 = ((x2 - x1) * dy1 - (y2 - y1) * dx1) / d; + result = 0; + } + return result; +} + + +void +icvIntersectLines3( double *a0, double *b0, double *c0, + double *a1, double *b1, double *c1, CvPoint2D32f * point ) +{ + double det = a0[0] * b1[0] - a1[0] * b0[0]; + + if( det != 0 ) + { + det = 1. / det; + point->x = (float) ((b0[0] * c1[0] - b1[0] * c0[0]) * det); + point->y = (float) ((a1[0] * c0[0] - a0[0] * c1[0]) * det); + } + else + { + point->x = point->y = FLT_MAX; + } +} + + +CV_IMPL double +cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist ) +{ + double result = 0; + + CvSeqBlock block; + CvContour header; + CvSeq* contour = (CvSeq*)_contour; + CvSeqReader reader; + int i, total, counter = 0; + int is_float; + double min_dist_num = FLT_MAX, min_dist_denom = 1; + CvPoint ip = {0,0}; + + if( !CV_IS_SEQ(contour) ) + { + contour = cvPointSeqFromMat( CV_SEQ_KIND_CURVE + CV_SEQ_FLAG_CLOSED, + _contour, &header, &block ); + } + else if( CV_IS_SEQ_POINT_SET(contour) ) + { + if( contour->header_size == sizeof(CvContour) && !measure_dist ) + { + CvRect r = ((CvContour*)contour)->rect; + if( pt.x < r.x || pt.y < r.y || + pt.x >= r.x + r.width || pt.y >= r.y + r.height ) + return -1; + } + } + else if( CV_IS_SEQ_CHAIN(contour) ) + { + CV_Error( CV_StsBadArg, + "Chains are not supported. Convert them to polygonal representation using cvApproxChains()" ); + } + else + CV_Error( CV_StsBadArg, "Input contour is neither a valid sequence nor a matrix" ); + + total = contour->total; + is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2; + cvStartReadSeq( contour, &reader, -1 ); + + if( !is_float && !measure_dist && (ip.x = cvRound(pt.x)) == pt.x && (ip.y = cvRound(pt.y)) == pt.y ) + { + // the fastest "pure integer" branch + CvPoint v0, v; + CV_READ_SEQ_ELEM( v, reader ); + + for( i = 0; i < total; i++ ) + { + int dist; + v0 = v; + CV_READ_SEQ_ELEM( v, reader ); + + if( (v0.y <= ip.y && v.y <= ip.y) || + (v0.y > ip.y && v.y > ip.y) || + (v0.x < ip.x && v.x < ip.x) ) + { + if( ip.y == v.y && (ip.x == v.x || (ip.y == v0.y && + ((v0.x <= ip.x && ip.x <= v.x) || (v.x <= ip.x && ip.x <= v0.x)))) ) + return 0; + continue; + } + + dist = (ip.y - v0.y)*(v.x - v0.x) - (ip.x - v0.x)*(v.y - v0.y); + if( dist == 0 ) + return 0; + if( v.y < v0.y ) + dist = -dist; + counter += dist > 0; + } + + result = counter % 2 == 0 ? -1 : 1; + } + else + { + CvPoint2D32f v0, v; + CvPoint iv; + + if( is_float ) + { + CV_READ_SEQ_ELEM( v, reader ); + } + else + { + CV_READ_SEQ_ELEM( iv, reader ); + v = cvPointTo32f( iv ); + } + + if( !measure_dist ) + { + for( i = 0; i < total; i++ ) + { + double dist; + v0 = v; + if( is_float ) + { + CV_READ_SEQ_ELEM( v, reader ); + } + else + { + CV_READ_SEQ_ELEM( iv, reader ); + v = cvPointTo32f( iv ); + } + + if( (v0.y <= pt.y && v.y <= pt.y) || + (v0.y > pt.y && v.y > pt.y) || + (v0.x < pt.x && v.x < pt.x) ) + { + if( pt.y == v.y && (pt.x == v.x || (pt.y == v0.y && + ((v0.x <= pt.x && pt.x <= v.x) || (v.x <= pt.x && pt.x <= v0.x)))) ) + return 0; + continue; + } + + dist = (double)(pt.y - v0.y)*(v.x - v0.x) - (double)(pt.x - v0.x)*(v.y - v0.y); + if( dist == 0 ) + return 0; + if( v.y < v0.y ) + dist = -dist; + counter += dist > 0; + } + + result = counter % 2 == 0 ? -1 : 1; + } + else + { + for( i = 0; i < total; i++ ) + { + double dx, dy, dx1, dy1, dx2, dy2, dist_num, dist_denom = 1; + + v0 = v; + if( is_float ) + { + CV_READ_SEQ_ELEM( v, reader ); + } + else + { + CV_READ_SEQ_ELEM( iv, reader ); + v = cvPointTo32f( iv ); + } + + dx = v.x - v0.x; dy = v.y - v0.y; + dx1 = pt.x - v0.x; dy1 = pt.y - v0.y; + dx2 = pt.x - v.x; dy2 = pt.y - v.y; + + if( dx1*dx + dy1*dy <= 0 ) + dist_num = dx1*dx1 + dy1*dy1; + else if( dx2*dx + dy2*dy >= 0 ) + dist_num = dx2*dx2 + dy2*dy2; + else + { + dist_num = (dy1*dx - dx1*dy); + dist_num *= dist_num; + dist_denom = dx*dx + dy*dy; + } + + if( dist_num*min_dist_denom < min_dist_num*dist_denom ) + { + min_dist_num = dist_num; + min_dist_denom = dist_denom; + if( min_dist_num == 0 ) + break; + } + + if( (v0.y <= pt.y && v.y <= pt.y) || + (v0.y > pt.y && v.y > pt.y) || + (v0.x < pt.x && v.x < pt.x) ) + continue; + + dist_num = dy1*dx - dx1*dy; + if( dy < 0 ) + dist_num = -dist_num; + counter += dist_num > 0; + } + + result = sqrt(min_dist_num/min_dist_denom); + if( counter % 2 == 0 ) + result = -result; + } + } + + return result; +} + + +/* + This code is described in "Computational Geometry in C" (Second Edition), + Chapter 7. It is not written to be comprehensible without the + explanation in that book. + + Written by Joseph O'Rourke. + Last modified: December 1997 + Questions to orourke@cs.smith.edu. + -------------------------------------------------------------------- + This code is Copyright 1997 by Joseph O'Rourke. It may be freely + redistributed in its entirety provided that this copyright notice is + not removed. + -------------------------------------------------------------------- + */ + +namespace cv +{ +typedef enum { Pin, Qin, Unknown } tInFlag; + +static int areaSign( Point2f a, Point2f b, Point2f c ) +{ + static const double eps = 1e-5; + double area2 = (b.x - a.x) * (double)(c.y - a.y) - (c.x - a.x ) * (double)(b.y - a.y); + return area2 > eps ? 1 : area2 < -eps ? -1 : 0; +} + +//--------------------------------------------------------------------- +// Returns true iff point c lies on the closed segement ab. +// Assumes it is already known that abc are collinear. +//--------------------------------------------------------------------- +static bool between( Point2f a, Point2f b, Point2f c ) +{ + Point2f ba, ca; + + // If ab not vertical, check betweenness on x; else on y. + if ( a.x != b.x ) + return ((a.x <= c.x) && (c.x <= b.x)) || + ((a.x >= c.x) && (c.x >= b.x)); + else + return ((a.y <= c.y) && (c.y <= b.y)) || + ((a.y >= c.y) && (c.y >= b.y)); +} + +static char parallelInt( Point2f a, Point2f b, Point2f c, Point2f d, Point2f& p, Point2f& q ) +{ + char code = 'e'; + if( areaSign(a, b, c) != 0 ) + code = '0'; + else if( between(a, b, c) && between(a, b, d)) + p = c, q = d; + else if( between(c, d, a) && between(c, d, b)) + p = a, q = b; + else if( between(a, b, c) && between(c, d, b)) + p = c, q = b; + else if( between(a, b, c) && between(c, d, a)) + p = c, q = a; + else if( between(a, b, d) && between(c, d, b)) + p = d, q = b; + else if( between(a, b, d) && between(c, d, a)) + p = d, q = a; + else + code = '0'; + return code; +} + +//--------------------------------------------------------------------- +// segSegInt: Finds the point of intersection p between two closed +// segments ab and cd. Returns p and a char with the following meaning: +// 'e': The segments collinearly overlap, sharing a point. +// 'v': An endpoint (vertex) of one segment is on the other segment, +// but 'e' doesn't hold. +// '1': The segments intersect properly (i.e., they share a point and +// neither 'v' nor 'e' holds). +// '0': The segments do not intersect (i.e., they share no points). +// Note that two collinear segments that share just one point, an endpoint +// of each, returns 'e' rather than 'v' as one might expect. +//--------------------------------------------------------------------- +static char segSegInt( Point2f a, Point2f b, Point2f c, Point2f d, Point2f& p, Point2f& q ) +{ + double s, t; // The two parameters of the parametric eqns. + double num, denom; // Numerator and denoninator of equations. + char code = '?'; // Return char characterizing intersection. + + denom = a.x * (double)( d.y - c.y ) + + b.x * (double)( c.y - d.y ) + + d.x * (double)( b.y - a.y ) + + c.x * (double)( a.y - b.y ); + + // If denom is zero, then segments are parallel: handle separately. + if (denom == 0.0) + return parallelInt(a, b, c, d, p, q); + + num = a.x * (double)( d.y - c.y ) + + c.x * (double)( a.y - d.y ) + + d.x * (double)( c.y - a.y ); + if ( (num == 0.0) || (num == denom) ) code = 'v'; + s = num / denom; + + num = -( a.x * (double)( c.y - b.y ) + + b.x * (double)( a.y - c.y ) + + c.x * (double)( b.y - a.y ) ); + if ( (num == 0.0) || (num == denom) ) code = 'v'; + t = num / denom; + + if ( (0.0 < s) && (s < 1.0) && + (0.0 < t) && (t < 1.0) ) + code = '1'; + else if ( (0.0 > s) || (s > 1.0) || + (0.0 > t) || (t > 1.0) ) + code = '0'; + + p.x = (float)(a.x + s*(b.x - a.x)); + p.y = (float)(a.y + s*(b.y - a.y)); + + return code; +} + +static tInFlag inOut( Point2f p, tInFlag inflag, int aHB, int bHA, Point2f*& result ) +{ + if( p != result[-1] ) + *result++ = p; + // Update inflag. + return aHB > 0 ? Pin : bHA > 0 ? Qin : inflag; +} + +//--------------------------------------------------------------------- +// Advances and prints out an inside vertex if appropriate. +//--------------------------------------------------------------------- +static int advance( int a, int *aa, int n, bool inside, Point2f v, Point2f*& result ) +{ + if( inside && v != result[-1] ) + *result++ = v; + (*aa)++; + return (a+1) % n; +} + +static void addSharedSeg( Point2f p, Point2f q, Point2f*& result ) +{ + if( p != result[-1] ) + *result++ = p; + if( q != result[-1] ) + *result++ = q; +} + + +static int intersectConvexConvex_( const Point2f* P, int n, const Point2f* Q, int m, + Point2f* result, float* _area ) +{ + Point2f* result0 = result; + // P has n vertices, Q has m vertices. + int a=0, b=0; // indices on P and Q (resp.) + Point2f Origin(0,0); + tInFlag inflag=Unknown; // {Pin, Qin, Unknown}: which inside + int aa=0, ba=0; // # advances on a & b indices (after 1st inter.) + bool FirstPoint=true;// Is this the first point? (used to initialize). + Point2f p0; // The first point. + *result++ = Point2f(FLT_MAX, FLT_MAX); + + do + { + // Computations of key variables. + int a1 = (a + n - 1) % n; // a-1, b-1 (resp.) + int b1 = (b + m - 1) % m; + + Point2f A = P[a] - P[a1], B = Q[b] - Q[b1]; // directed edges on P and Q (resp.) + + int cross = areaSign( Origin, A, B ); // sign of z-component of A x B + int aHB = areaSign( Q[b1], Q[b], P[a] ); // a in H(b). + int bHA = areaSign( P[a1], P[a], Q[b] ); // b in H(A); + + // If A & B intersect, update inflag. + Point2f p, q; + int code = segSegInt( P[a1], P[a], Q[b1], Q[b], p, q ); + if( code == '1' || code == 'v' ) + { + if( inflag == Unknown && FirstPoint ) + { + aa = ba = 0; + FirstPoint = false; + p0 = p; + *result++ = p; + } + inflag = inOut( p, inflag, aHB, bHA, result ); + } + + //-----Advance rules----- + + // Special case: A & B overlap and oppositely oriented. + if( code == 'e' && A.ddot(B) < 0 ) + { + addSharedSeg( p, q, result ); + return (int)(result - result0); + } + + // Special case: A & B parallel and separated. + if( cross == 0 && aHB < 0 && bHA < 0 ) + return (int)(result - result0); + + // Special case: A & B collinear. + else if ( cross == 0 && aHB == 0 && bHA == 0 ) { + // Advance but do not output point. + if ( inflag == Pin ) + b = advance( b, &ba, m, inflag == Qin, Q[b], result ); + else + a = advance( a, &aa, n, inflag == Pin, P[a], result ); + } + + // Generic cases. + else if( cross >= 0 ) + { + if( bHA > 0) + a = advance( a, &aa, n, inflag == Pin, P[a], result ); + else + b = advance( b, &ba, m, inflag == Qin, Q[b], result ); + } + else + { + if( aHB > 0) + b = advance( b, &ba, m, inflag == Qin, Q[b], result ); + else + a = advance( a, &aa, n, inflag == Pin, P[a], result ); + } + // Quit when both adv. indices have cycled, or one has cycled twice. + } + while ( ((aa < n) || (ba < m)) && (aa < 2*n) && (ba < 2*m) ); + + // Deal with special cases: not implemented. + if( inflag == Unknown ) + { + // The boundaries of P and Q do not cross. + // ... + } + + int i, nr = (int)(result - result0); + double area = 0; + Point2f prev = result0[nr-1]; + for( i = 1; i < nr; i++ ) + { + result0[i-1] = result0[i]; + area += (double)prev.x*result0[i].y - (double)prev.y*result0[i].x; + prev = result0[i]; + } + + *_area = (float)(area*0.5); + + if( result0[nr-2] == result0[0] && nr > 1 ) + nr--; + return nr-1; +} + +} + +float cv::intersectConvexConvex( InputArray _p1, InputArray _p2, OutputArray _p12, bool handleNested ) +{ + Mat p1 = _p1.getMat(), p2 = _p2.getMat(); + CV_Assert( p1.depth() == CV_32S || p1.depth() == CV_32F ); + CV_Assert( p2.depth() == CV_32S || p2.depth() == CV_32F ); + + int n = p1.checkVector(2, p1.depth(), true); + int m = p2.checkVector(2, p2.depth(), true); + + CV_Assert( n >= 0 && m >= 0 ); + + if( n < 2 || m < 2 ) + { + _p12.release(); + return 0.f; + } + + AutoBuffer _result(n*2 + m*2 + 1); + Point2f *fp1 = _result, *fp2 = fp1 + n; + Point2f* result = fp2 + m; + int orientation = 0; + + for( int k = 1; k <= 2; k++ ) + { + Mat& p = k == 1 ? p1 : p2; + int len = k == 1 ? n : m; + Point2f* dst = k == 1 ? fp1 : fp2; + + Mat temp(p.size(), CV_MAKETYPE(CV_32F, p.channels()), dst); + p.convertTo(temp, CV_32F); + CV_Assert( temp.ptr() == dst ); + Point2f diff0 = dst[0] - dst[len-1]; + for( int i = 1; i < len; i++ ) + { + double s = diff0.cross(dst[i] - dst[i-1]); + if( s != 0 ) + { + if( s < 0 ) + { + orientation++; + flip( temp, temp, temp.rows > 1 ? 0 : 1 ); + } + break; + } + } + } + + float area = 0.f; + int nr = intersectConvexConvex_(fp1, n, fp2, m, result, &area); + if( nr == 0 ) + { + if( !handleNested ) + { + _p12.release(); + return 0.f; + } + + if( pointPolygonTest(_InputArray(fp1, n), fp2[0], false) >= 0 ) + { + result = fp2; + nr = m; + } + else if( pointPolygonTest(_InputArray(fp2, n), fp1[0], false) >= 0 ) + { + result = fp1; + nr = n; + } + else + { + _p12.release(); + return 0.f; + } + area = (float)contourArea(_InputArray(result, nr), false); + } + + if( _p12.needed() ) + { + Mat temp(nr, 1, CV_32FC2, result); + // if both input contours were reflected, + // let's orient the result as the input vectors + if( orientation == 2 ) + flip(temp, temp, 0); + + temp.copyTo(_p12); + } + return (float)fabs(area); +} + +/* +static void testConvConv() +{ + static const int P1[] = + { + 0, 0, + 100, 0, + 100, 100, + 0, 100, + }; + + static const int Q1[] = + { + 100, 80, + 50, 80, + 50, 50, + 100, 50 + }; + + static const int P2[] = + { + 0, 0, + 200, 0, + 200, 100, + 100, 200, + 0, 100 + }; + + static const int Q2[] = + { + 100, 100, + 300, 100, + 300, 200, + 100, 200 + }; + + static const int P3[] = + { + 0, 0, + 100, 0, + 100, 100, + 0, 100 + }; + + static const int Q3[] = + { + 50, 50, + 150, 50, + 150, 150, + 50, 150 + }; + + static const int P4[] = + { + 0, 160, + 50, 80, + 130, 0, + 190, 20, + 240, 100, + 240, 260, + 190, 290, + 130, 320, + 70, 320, + 30, 290 + }; + + static const int Q4[] = + { + 160, -30, + 280, 160, + 160, 320, + 0, 220, + 30, 100 + }; + + static const void* PQs[] = + { + P1, Q1, P2, Q2, P3, Q3, P4, Q4 + }; + + static const int lens[] = + { + CV_DIM(P1), CV_DIM(Q1), + CV_DIM(P2), CV_DIM(Q2), + CV_DIM(P3), CV_DIM(Q3), + CV_DIM(P4), CV_DIM(Q4) + }; + + Mat img(800, 800, CV_8UC3); + + for( int i = 0; i < CV_DIM(PQs)/2; i++ ) + { + Mat Pm = Mat(lens[i*2]/2, 1, CV_32SC2, (void*)PQs[i*2]) + Scalar(100, 100); + Mat Qm = Mat(lens[i*2+1]/2, 1, CV_32SC2, (void*)PQs[i*2+1]) + Scalar(100, 100); + Point* P = Pm.ptr(); + Point* Q = Qm.ptr(); + + flip(Pm, Pm, 0); + flip(Qm, Qm, 0); + + Mat Rm; + intersectConvexConvex(Pm, Qm, Rm); + std::cout << Rm << std::endl << std::endl; + + img = Scalar::all(0); + + polylines(img, Pm, true, Scalar(0,255,0), 1, CV_AA, 0); + polylines(img, Qm, true, Scalar(0,0,255), 1, CV_AA, 0); + Mat temp; + Rm.convertTo(temp, CV_32S, 256); + polylines(img, temp, true, Scalar(128, 255, 255), 3, CV_AA, 8); + + namedWindow("test", 1); + imshow("test", img); + waitKey(); + } +} +*/ + +/* End of file. */ diff --git a/imgproc/src/grabcut.cpp b/imgproc/src/grabcut.cpp new file mode 100644 index 0000000..4fb9b8d --- /dev/null +++ b/imgproc/src/grabcut.cpp @@ -0,0 +1,575 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include "gcgraph.hpp" +#include + +using namespace cv; + +/* +This is implementation of image segmentation algorithm GrabCut described in +"GrabCut — Interactive Foreground Extraction using Iterated Graph Cuts". +Carsten Rother, Vladimir Kolmogorov, Andrew Blake. + */ + +/* + GMM - Gaussian Mixture Model +*/ +class GMM +{ +public: + static const int componentsCount = 5; + + GMM( Mat& _model ); + double operator()( const Vec3d color ) const; + double operator()( int ci, const Vec3d color ) const; + int whichComponent( const Vec3d color ) const; + + void initLearning(); + void addSample( int ci, const Vec3d color ); + void endLearning(); + +private: + void calcInverseCovAndDeterm( int ci ); + Mat model; + double* coefs; + double* mean; + double* cov; + + double inverseCovs[componentsCount][3][3]; + double covDeterms[componentsCount]; + + double sums[componentsCount][3]; + double prods[componentsCount][3][3]; + int sampleCounts[componentsCount]; + int totalSampleCount; +}; + +GMM::GMM( Mat& _model ) +{ + const int modelSize = 3/*mean*/ + 9/*covariance*/ + 1/*component weight*/; + if( _model.empty() ) + { + _model.create( 1, modelSize*componentsCount, CV_64FC1 ); + _model.setTo(Scalar(0)); + } + else if( (_model.type() != CV_64FC1) || (_model.rows != 1) || (_model.cols != modelSize*componentsCount) ) + CV_Error( CV_StsBadArg, "_model must have CV_64FC1 type, rows == 1 and cols == 13*componentsCount" ); + + model = _model; + + coefs = model.ptr(0); + mean = coefs + componentsCount; + cov = mean + 3*componentsCount; + + for( int ci = 0; ci < componentsCount; ci++ ) + if( coefs[ci] > 0 ) + calcInverseCovAndDeterm( ci ); +} + +double GMM::operator()( const Vec3d color ) const +{ + double res = 0; + for( int ci = 0; ci < componentsCount; ci++ ) + res += coefs[ci] * (*this)(ci, color ); + return res; +} + +double GMM::operator()( int ci, const Vec3d color ) const +{ + double res = 0; + if( coefs[ci] > 0 ) + { + CV_Assert( covDeterms[ci] > std::numeric_limits::epsilon() ); + Vec3d diff = color; + double* m = mean + 3*ci; + diff[0] -= m[0]; diff[1] -= m[1]; diff[2] -= m[2]; + double mult = diff[0]*(diff[0]*inverseCovs[ci][0][0] + diff[1]*inverseCovs[ci][1][0] + diff[2]*inverseCovs[ci][2][0]) + + diff[1]*(diff[0]*inverseCovs[ci][0][1] + diff[1]*inverseCovs[ci][1][1] + diff[2]*inverseCovs[ci][2][1]) + + diff[2]*(diff[0]*inverseCovs[ci][0][2] + diff[1]*inverseCovs[ci][1][2] + diff[2]*inverseCovs[ci][2][2]); + res = 1.0f/sqrt(covDeterms[ci]) * exp(-0.5f*mult); + } + return res; +} + +int GMM::whichComponent( const Vec3d color ) const +{ + int k = 0; + double max = 0; + + for( int ci = 0; ci < componentsCount; ci++ ) + { + double p = (*this)( ci, color ); + if( p > max ) + { + k = ci; + max = p; + } + } + return k; +} + +void GMM::initLearning() +{ + for( int ci = 0; ci < componentsCount; ci++) + { + sums[ci][0] = sums[ci][1] = sums[ci][2] = 0; + prods[ci][0][0] = prods[ci][0][1] = prods[ci][0][2] = 0; + prods[ci][1][0] = prods[ci][1][1] = prods[ci][1][2] = 0; + prods[ci][2][0] = prods[ci][2][1] = prods[ci][2][2] = 0; + sampleCounts[ci] = 0; + } + totalSampleCount = 0; +} + +void GMM::addSample( int ci, const Vec3d color ) +{ + sums[ci][0] += color[0]; sums[ci][1] += color[1]; sums[ci][2] += color[2]; + prods[ci][0][0] += color[0]*color[0]; prods[ci][0][1] += color[0]*color[1]; prods[ci][0][2] += color[0]*color[2]; + prods[ci][1][0] += color[1]*color[0]; prods[ci][1][1] += color[1]*color[1]; prods[ci][1][2] += color[1]*color[2]; + prods[ci][2][0] += color[2]*color[0]; prods[ci][2][1] += color[2]*color[1]; prods[ci][2][2] += color[2]*color[2]; + sampleCounts[ci]++; + totalSampleCount++; +} + +void GMM::endLearning() +{ + const double variance = 0.01; + for( int ci = 0; ci < componentsCount; ci++ ) + { + int n = sampleCounts[ci]; + if( n == 0 ) + coefs[ci] = 0; + else + { + coefs[ci] = (double)n/totalSampleCount; + + double* m = mean + 3*ci; + m[0] = sums[ci][0]/n; m[1] = sums[ci][1]/n; m[2] = sums[ci][2]/n; + + double* c = cov + 9*ci; + c[0] = prods[ci][0][0]/n - m[0]*m[0]; c[1] = prods[ci][0][1]/n - m[0]*m[1]; c[2] = prods[ci][0][2]/n - m[0]*m[2]; + c[3] = prods[ci][1][0]/n - m[1]*m[0]; c[4] = prods[ci][1][1]/n - m[1]*m[1]; c[5] = prods[ci][1][2]/n - m[1]*m[2]; + c[6] = prods[ci][2][0]/n - m[2]*m[0]; c[7] = prods[ci][2][1]/n - m[2]*m[1]; c[8] = prods[ci][2][2]/n - m[2]*m[2]; + + double dtrm = c[0]*(c[4]*c[8]-c[5]*c[7]) - c[1]*(c[3]*c[8]-c[5]*c[6]) + c[2]*(c[3]*c[7]-c[4]*c[6]); + if( dtrm <= std::numeric_limits::epsilon() ) + { + // Adds the white noise to avoid singular covariance matrix. + c[0] += variance; + c[4] += variance; + c[8] += variance; + } + + calcInverseCovAndDeterm(ci); + } + } +} + +void GMM::calcInverseCovAndDeterm( int ci ) +{ + if( coefs[ci] > 0 ) + { + double *c = cov + 9*ci; + double dtrm = + covDeterms[ci] = c[0]*(c[4]*c[8]-c[5]*c[7]) - c[1]*(c[3]*c[8]-c[5]*c[6]) + c[2]*(c[3]*c[7]-c[4]*c[6]); + + CV_Assert( dtrm > std::numeric_limits::epsilon() ); + inverseCovs[ci][0][0] = (c[4]*c[8] - c[5]*c[7]) / dtrm; + inverseCovs[ci][1][0] = -(c[3]*c[8] - c[5]*c[6]) / dtrm; + inverseCovs[ci][2][0] = (c[3]*c[7] - c[4]*c[6]) / dtrm; + inverseCovs[ci][0][1] = -(c[1]*c[8] - c[2]*c[7]) / dtrm; + inverseCovs[ci][1][1] = (c[0]*c[8] - c[2]*c[6]) / dtrm; + inverseCovs[ci][2][1] = -(c[0]*c[7] - c[1]*c[6]) / dtrm; + inverseCovs[ci][0][2] = (c[1]*c[5] - c[2]*c[4]) / dtrm; + inverseCovs[ci][1][2] = -(c[0]*c[5] - c[2]*c[3]) / dtrm; + inverseCovs[ci][2][2] = (c[0]*c[4] - c[1]*c[3]) / dtrm; + } +} + +/* + Calculate beta - parameter of GrabCut algorithm. + beta = 1/(2*avg(sqr(||color[i] - color[j]||))) +*/ +static double calcBeta( const Mat& img ) +{ + double beta = 0; + for( int y = 0; y < img.rows; y++ ) + { + for( int x = 0; x < img.cols; x++ ) + { + Vec3d color = img.at(y,x); + if( x>0 ) // left + { + Vec3d diff = color - (Vec3d)img.at(y,x-1); + beta += diff.dot(diff); + } + if( y>0 && x>0 ) // upleft + { + Vec3d diff = color - (Vec3d)img.at(y-1,x-1); + beta += diff.dot(diff); + } + if( y>0 ) // up + { + Vec3d diff = color - (Vec3d)img.at(y-1,x); + beta += diff.dot(diff); + } + if( y>0 && x(y-1,x+1); + beta += diff.dot(diff); + } + } + } + if( beta <= std::numeric_limits::epsilon() ) + beta = 0; + else + beta = 1.f / (2 * beta/(4*img.cols*img.rows - 3*img.cols - 3*img.rows + 2) ); + + return beta; +} + +/* + Calculate weights of noterminal vertices of graph. + beta and gamma - parameters of GrabCut algorithm. + */ +static void calcNWeights( const Mat& img, Mat& leftW, Mat& upleftW, Mat& upW, Mat& uprightW, double beta, double gamma ) +{ + const double gammaDivSqrt2 = gamma / std::sqrt(2.0f); + leftW.create( img.rows, img.cols, CV_64FC1 ); + upleftW.create( img.rows, img.cols, CV_64FC1 ); + upW.create( img.rows, img.cols, CV_64FC1 ); + uprightW.create( img.rows, img.cols, CV_64FC1 ); + for( int y = 0; y < img.rows; y++ ) + { + for( int x = 0; x < img.cols; x++ ) + { + Vec3d color = img.at(y,x); + if( x-1>=0 ) // left + { + Vec3d diff = color - (Vec3d)img.at(y,x-1); + leftW.at(y,x) = gamma * exp(-beta*diff.dot(diff)); + } + else + leftW.at(y,x) = 0; + if( x-1>=0 && y-1>=0 ) // upleft + { + Vec3d diff = color - (Vec3d)img.at(y-1,x-1); + upleftW.at(y,x) = gammaDivSqrt2 * exp(-beta*diff.dot(diff)); + } + else + upleftW.at(y,x) = 0; + if( y-1>=0 ) // up + { + Vec3d diff = color - (Vec3d)img.at(y-1,x); + upW.at(y,x) = gamma * exp(-beta*diff.dot(diff)); + } + else + upW.at(y,x) = 0; + if( x+1=0 ) // upright + { + Vec3d diff = color - (Vec3d)img.at(y-1,x+1); + uprightW.at(y,x) = gammaDivSqrt2 * exp(-beta*diff.dot(diff)); + } + else + uprightW.at(y,x) = 0; + } + } +} + +/* + Check size, type and element values of mask matrix. + */ +static void checkMask( const Mat& img, const Mat& mask ) +{ + if( mask.empty() ) + CV_Error( CV_StsBadArg, "mask is empty" ); + if( mask.type() != CV_8UC1 ) + CV_Error( CV_StsBadArg, "mask must have CV_8UC1 type" ); + if( mask.cols != img.cols || mask.rows != img.rows ) + CV_Error( CV_StsBadArg, "mask must have as many rows and cols as img" ); + for( int y = 0; y < mask.rows; y++ ) + { + for( int x = 0; x < mask.cols; x++ ) + { + uchar val = mask.at(y,x); + if( val!=GC_BGD && val!=GC_FGD && val!=GC_PR_BGD && val!=GC_PR_FGD ) + CV_Error( CV_StsBadArg, "mask element value must be equel" + "GC_BGD or GC_FGD or GC_PR_BGD or GC_PR_FGD" ); + } + } +} + +/* + Initialize mask using rectangular. +*/ +static void initMaskWithRect( Mat& mask, Size imgSize, Rect rect ) +{ + mask.create( imgSize, CV_8UC1 ); + mask.setTo( GC_BGD ); + + rect.x = max(0, rect.x); + rect.y = max(0, rect.y); + rect.width = min(rect.width, imgSize.width-rect.x); + rect.height = min(rect.height, imgSize.height-rect.y); + + (mask(rect)).setTo( Scalar(GC_PR_FGD) ); +} + +/* + Initialize GMM background and foreground models using kmeans algorithm. +*/ +static void initGMMs( const Mat& img, const Mat& mask, GMM& bgdGMM, GMM& fgdGMM ) +{ + const int kMeansItCount = 10; + const int kMeansType = KMEANS_PP_CENTERS; + + Mat bgdLabels, fgdLabels; + vector bgdSamples, fgdSamples; + Point p; + for( p.y = 0; p.y < img.rows; p.y++ ) + { + for( p.x = 0; p.x < img.cols; p.x++ ) + { + if( mask.at(p) == GC_BGD || mask.at(p) == GC_PR_BGD ) + bgdSamples.push_back( (Vec3f)img.at(p) ); + else // GC_FGD | GC_PR_FGD + fgdSamples.push_back( (Vec3f)img.at(p) ); + } + } + CV_Assert( !bgdSamples.empty() && !fgdSamples.empty() ); + Mat _bgdSamples( (int)bgdSamples.size(), 3, CV_32FC1, &bgdSamples[0][0] ); + kmeans( _bgdSamples, GMM::componentsCount, bgdLabels, + TermCriteria( CV_TERMCRIT_ITER, kMeansItCount, 0.0), 0, kMeansType ); + Mat _fgdSamples( (int)fgdSamples.size(), 3, CV_32FC1, &fgdSamples[0][0] ); + kmeans( _fgdSamples, GMM::componentsCount, fgdLabels, + TermCriteria( CV_TERMCRIT_ITER, kMeansItCount, 0.0), 0, kMeansType ); + + bgdGMM.initLearning(); + for( int i = 0; i < (int)bgdSamples.size(); i++ ) + bgdGMM.addSample( bgdLabels.at(i,0), bgdSamples[i] ); + bgdGMM.endLearning(); + + fgdGMM.initLearning(); + for( int i = 0; i < (int)fgdSamples.size(); i++ ) + fgdGMM.addSample( fgdLabels.at(i,0), fgdSamples[i] ); + fgdGMM.endLearning(); +} + +/* + Assign GMMs components for each pixel. +*/ +static void assignGMMsComponents( const Mat& img, const Mat& mask, const GMM& bgdGMM, const GMM& fgdGMM, Mat& compIdxs ) +{ + Point p; + for( p.y = 0; p.y < img.rows; p.y++ ) + { + for( p.x = 0; p.x < img.cols; p.x++ ) + { + Vec3d color = img.at(p); + compIdxs.at(p) = mask.at(p) == GC_BGD || mask.at(p) == GC_PR_BGD ? + bgdGMM.whichComponent(color) : fgdGMM.whichComponent(color); + } + } +} + +/* + Learn GMMs parameters. +*/ +static void learnGMMs( const Mat& img, const Mat& mask, const Mat& compIdxs, GMM& bgdGMM, GMM& fgdGMM ) +{ + bgdGMM.initLearning(); + fgdGMM.initLearning(); + Point p; + for( int ci = 0; ci < GMM::componentsCount; ci++ ) + { + for( p.y = 0; p.y < img.rows; p.y++ ) + { + for( p.x = 0; p.x < img.cols; p.x++ ) + { + if( compIdxs.at(p) == ci ) + { + if( mask.at(p) == GC_BGD || mask.at(p) == GC_PR_BGD ) + bgdGMM.addSample( ci, img.at(p) ); + else + fgdGMM.addSample( ci, img.at(p) ); + } + } + } + } + bgdGMM.endLearning(); + fgdGMM.endLearning(); +} + +/* + Construct GCGraph +*/ +static void constructGCGraph( const Mat& img, const Mat& mask, const GMM& bgdGMM, const GMM& fgdGMM, double lambda, + const Mat& leftW, const Mat& upleftW, const Mat& upW, const Mat& uprightW, + GCGraph& graph ) +{ + int vtxCount = img.cols*img.rows, + edgeCount = 2*(4*img.cols*img.rows - 3*(img.cols + img.rows) + 2); + graph.create(vtxCount, edgeCount); + Point p; + for( p.y = 0; p.y < img.rows; p.y++ ) + { + for( p.x = 0; p.x < img.cols; p.x++) + { + // add node + int vtxIdx = graph.addVtx(); + Vec3b color = img.at(p); + + // set t-weights + double fromSource, toSink; + if( mask.at(p) == GC_PR_BGD || mask.at(p) == GC_PR_FGD ) + { + fromSource = -log( bgdGMM(color) ); + toSink = -log( fgdGMM(color) ); + } + else if( mask.at(p) == GC_BGD ) + { + fromSource = 0; + toSink = lambda; + } + else // GC_FGD + { + fromSource = lambda; + toSink = 0; + } + graph.addTermWeights( vtxIdx, fromSource, toSink ); + + // set n-weights + if( p.x>0 ) + { + double w = leftW.at(p); + graph.addEdges( vtxIdx, vtxIdx-1, w, w ); + } + if( p.x>0 && p.y>0 ) + { + double w = upleftW.at(p); + graph.addEdges( vtxIdx, vtxIdx-img.cols-1, w, w ); + } + if( p.y>0 ) + { + double w = upW.at(p); + graph.addEdges( vtxIdx, vtxIdx-img.cols, w, w ); + } + if( p.x0 ) + { + double w = uprightW.at(p); + graph.addEdges( vtxIdx, vtxIdx-img.cols+1, w, w ); + } + } + } +} + +/* + Estimate segmentation using MaxFlow algorithm +*/ +static void estimateSegmentation( GCGraph& graph, Mat& mask ) +{ + graph.maxFlow(); + Point p; + for( p.y = 0; p.y < mask.rows; p.y++ ) + { + for( p.x = 0; p.x < mask.cols; p.x++ ) + { + if( mask.at(p) == GC_PR_BGD || mask.at(p) == GC_PR_FGD ) + { + if( graph.inSourceSegment( p.y*mask.cols+p.x /*vertex index*/ ) ) + mask.at(p) = GC_PR_FGD; + else + mask.at(p) = GC_PR_BGD; + } + } + } +} + +void cv::grabCut( InputArray _img, InputOutputArray _mask, Rect rect, + InputOutputArray _bgdModel, InputOutputArray _fgdModel, + int iterCount, int mode ) +{ + Mat img = _img.getMat(); + Mat& mask = _mask.getMatRef(); + Mat& bgdModel = _bgdModel.getMatRef(); + Mat& fgdModel = _fgdModel.getMatRef(); + + if( img.empty() ) + CV_Error( CV_StsBadArg, "image is empty" ); + if( img.type() != CV_8UC3 ) + CV_Error( CV_StsBadArg, "image mush have CV_8UC3 type" ); + + GMM bgdGMM( bgdModel ), fgdGMM( fgdModel ); + Mat compIdxs( img.size(), CV_32SC1 ); + + if( mode == GC_INIT_WITH_RECT || mode == GC_INIT_WITH_MASK ) + { + if( mode == GC_INIT_WITH_RECT ) + initMaskWithRect( mask, img.size(), rect ); + else // flag == GC_INIT_WITH_MASK + checkMask( img, mask ); + initGMMs( img, mask, bgdGMM, fgdGMM ); + } + + if( iterCount <= 0) + return; + + if( mode == GC_EVAL ) + checkMask( img, mask ); + + const double gamma = 50; + const double lambda = 9*gamma; + const double beta = calcBeta( img ); + + Mat leftW, upleftW, upW, uprightW; + calcNWeights( img, leftW, upleftW, upW, uprightW, beta, gamma ); + + for( int i = 0; i < iterCount; i++ ) + { + GCGraph graph; + assignGMMsComponents( img, mask, bgdGMM, fgdGMM, compIdxs ); + learnGMMs( img, mask, compIdxs, bgdGMM, fgdGMM ); + constructGCGraph(img, mask, bgdGMM, fgdGMM, lambda, leftW, upleftW, upW, uprightW, graph ); + estimateSegmentation( graph, mask ); + } +} diff --git a/imgproc/src/histogram.cpp b/imgproc/src/histogram.cpp new file mode 100644 index 0000000..edcb240 --- /dev/null +++ b/imgproc/src/histogram.cpp @@ -0,0 +1,2615 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +namespace cv +{ + +template<> void Ptr::delete_obj() +{ cvReleaseHist(&obj); } + + +////////////////// Helper functions ////////////////////// + +static const size_t OUT_OF_RANGE = (size_t)1 << (sizeof(size_t)*8 - 2); + +static void +calcHistLookupTables_8u( const Mat& hist, const SparseMat& shist, + int dims, const float** ranges, const double* uniranges, + bool uniform, bool issparse, vector& _tab ) +{ + const int low = 0, high = 256; + int i, j; + _tab.resize((high-low)*dims); + size_t* tab = &_tab[0]; + + if( uniform ) + { + for( i = 0; i < dims; i++ ) + { + double a = uniranges[i*2]; + double b = uniranges[i*2+1]; + int sz = !issparse ? hist.size[i] : shist.size(i); + size_t step = !issparse ? hist.step[i] : 1; + + for( j = low; j < high; j++ ) + { + int idx = cvFloor(j*a + b); + size_t written_idx; + if( (unsigned)idx < (unsigned)sz ) + written_idx = idx*step; + else + written_idx = OUT_OF_RANGE; + + tab[i*(high - low) + j - low] = written_idx; + } + } + } + else + { + for( i = 0; i < dims; i++ ) + { + int limit = std::min(cvCeil(ranges[i][0]), high); + int idx = -1, sz = !issparse ? hist.size[i] : shist.size(i); + size_t written_idx = OUT_OF_RANGE; + size_t step = !issparse ? hist.step[i] : 1; + + for(j = low;;) + { + for( ; j < limit; j++ ) + tab[i*(high - low) + j - low] = written_idx; + + if( (unsigned)(++idx) < (unsigned)sz ) + { + limit = std::min(cvCeil(ranges[i][idx+1]), high); + written_idx = idx*step; + } + else + { + for( ; j < high; j++ ) + tab[i*(high - low) + j - low] = OUT_OF_RANGE; + break; + } + } + } + } +} + + +static void histPrepareImages( const Mat* images, int nimages, const int* channels, + const Mat& mask, int dims, const int* histSize, + const float** ranges, bool uniform, + vector& ptrs, vector& deltas, + Size& imsize, vector& uniranges ) +{ + int i, j, c; + CV_Assert( channels != 0 || nimages == dims ); + + imsize = images[0].size(); + int depth = images[0].depth(), esz1 = (int)images[0].elemSize1(); + bool isContinuous = true; + + ptrs.resize(dims + 1); + deltas.resize((dims + 1)*2); + + for( i = 0; i < dims; i++ ) + { + if(!channels) + { + j = i; + c = 0; + CV_Assert( images[j].channels() == 1 ); + } + else + { + c = channels[i]; + CV_Assert( c >= 0 ); + for( j = 0; j < nimages; c -= images[j].channels(), j++ ) + if( c < images[j].channels() ) + break; + CV_Assert( j < nimages ); + } + + CV_Assert( images[j].size() == imsize && images[j].depth() == depth ); + if( !images[j].isContinuous() ) + isContinuous = false; + ptrs[i] = images[j].data + c*esz1; + deltas[i*2] = images[j].channels(); + deltas[i*2+1] = (int)(images[j].step/esz1 - imsize.width*deltas[i*2]); + } + + if( mask.data ) + { + CV_Assert( mask.size() == imsize && mask.channels() == 1 ); + isContinuous = isContinuous && mask.isContinuous(); + ptrs[dims] = mask.data; + deltas[dims*2] = 1; + deltas[dims*2 + 1] = (int)(mask.step/mask.elemSize1()); + } + + if( isContinuous ) + { + imsize.width *= imsize.height; + imsize.height = 1; + } + + if( !ranges ) + { + CV_Assert( depth == CV_8U ); + + uniranges.resize( dims*2 ); + for( i = 0; i < dims; i++ ) + { + uniranges[i*2] = histSize[i]/256.; + uniranges[i*2+1] = 0; + } + } + else if( uniform ) + { + uniranges.resize( dims*2 ); + for( i = 0; i < dims; i++ ) + { + CV_Assert( ranges[i] && ranges[i][0] < ranges[i][1] ); + double low = ranges[i][0], high = ranges[i][1]; + double t = histSize[i]/(high - low); + uniranges[i*2] = t; + uniranges[i*2+1] = -t*low; + } + } + else + { + for( i = 0; i < dims; i++ ) + { + size_t n = histSize[i]; + for(size_t k = 0; k < n; k++ ) + CV_Assert( ranges[i][k] < ranges[i][k+1] ); + } + } +} + + +////////////////////////////////// C A L C U L A T E H I S T O G R A M //////////////////////////////////// + +template static void +calcHist_( vector& _ptrs, const vector& _deltas, + Size imsize, Mat& hist, int dims, const float** _ranges, + const double* _uniranges, bool uniform ) +{ + T** ptrs = (T**)&_ptrs[0]; + const int* deltas = &_deltas[0]; + uchar* H = hist.data; + int i, x; + const uchar* mask = _ptrs[dims]; + int mstep = _deltas[dims*2 + 1]; + int size[CV_MAX_DIM]; + size_t hstep[CV_MAX_DIM]; + + for( i = 0; i < dims; i++ ) + { + size[i] = hist.size[i]; + hstep[i] = hist.step[i]; + } + + if( uniform ) + { + const double* uniranges = &_uniranges[0]; + + if( dims == 1 ) + { + double a = uniranges[0], b = uniranges[1]; + int sz = size[0], d0 = deltas[0], step0 = deltas[1]; + const T* p0 = (const T*)ptrs[0]; + + for( ; imsize.height--; p0 += step0, mask += mstep ) + { + if( !mask ) + for( x = 0; x < imsize.width; x++, p0 += d0 ) + { + int idx = cvFloor(*p0*a + b); + if( (unsigned)idx < (unsigned)sz ) + ((int*)H)[idx]++; + } + else + for( x = 0; x < imsize.width; x++, p0 += d0 ) + if( mask[x] ) + { + int idx = cvFloor(*p0*a + b); + if( (unsigned)idx < (unsigned)sz ) + ((int*)H)[idx]++; + } + } + } + else if( dims == 2 ) + { + double a0 = uniranges[0], b0 = uniranges[1], a1 = uniranges[2], b1 = uniranges[3]; + int sz0 = size[0], sz1 = size[1]; + int d0 = deltas[0], step0 = deltas[1], + d1 = deltas[2], step1 = deltas[3]; + size_t hstep0 = hstep[0]; + const T* p0 = (const T*)ptrs[0]; + const T* p1 = (const T*)ptrs[1]; + + for( ; imsize.height--; p0 += step0, p1 += step1, mask += mstep ) + { + if( !mask ) + for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 ) + { + int idx0 = cvFloor(*p0*a0 + b0); + int idx1 = cvFloor(*p1*a1 + b1); + if( (unsigned)idx0 < (unsigned)sz0 && (unsigned)idx1 < (unsigned)sz1 ) + ((int*)(H + hstep0*idx0))[idx1]++; + } + else + for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 ) + if( mask[x] ) + { + int idx0 = cvFloor(*p0*a0 + b0); + int idx1 = cvFloor(*p1*a1 + b1); + if( (unsigned)idx0 < (unsigned)sz0 && (unsigned)idx1 < (unsigned)sz1 ) + ((int*)(H + hstep0*idx0))[idx1]++; + } + } + } + else if( dims == 3 ) + { + double a0 = uniranges[0], b0 = uniranges[1], + a1 = uniranges[2], b1 = uniranges[3], + a2 = uniranges[4], b2 = uniranges[5]; + int sz0 = size[0], sz1 = size[1], sz2 = size[2]; + int d0 = deltas[0], step0 = deltas[1], + d1 = deltas[2], step1 = deltas[3], + d2 = deltas[4], step2 = deltas[5]; + size_t hstep0 = hstep[0], hstep1 = hstep[1]; + const T* p0 = (const T*)ptrs[0]; + const T* p1 = (const T*)ptrs[1]; + const T* p2 = (const T*)ptrs[2]; + + for( ; imsize.height--; p0 += step0, p1 += step1, p2 += step2, mask += mstep ) + { + if( !mask ) + for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 ) + { + int idx0 = cvFloor(*p0*a0 + b0); + int idx1 = cvFloor(*p1*a1 + b1); + int idx2 = cvFloor(*p2*a2 + b2); + if( (unsigned)idx0 < (unsigned)sz0 && + (unsigned)idx1 < (unsigned)sz1 && + (unsigned)idx2 < (unsigned)sz2 ) + ((int*)(H + hstep0*idx0 + hstep1*idx1))[idx2]++; + } + else + for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 ) + if( mask[x] ) + { + int idx0 = cvFloor(*p0*a0 + b0); + int idx1 = cvFloor(*p1*a1 + b1); + int idx2 = cvFloor(*p2*a2 + b2); + if( (unsigned)idx0 < (unsigned)sz0 && + (unsigned)idx1 < (unsigned)sz1 && + (unsigned)idx2 < (unsigned)sz2 ) + ((int*)(H + hstep0*idx0 + hstep1*idx1))[idx2]++; + } + } + } + else + { + for( ; imsize.height--; mask += mstep ) + { + if( !mask ) + for( x = 0; x < imsize.width; x++ ) + { + uchar* Hptr = H; + for( i = 0; i < dims; i++ ) + { + int idx = cvFloor(*ptrs[i]*uniranges[i*2] + uniranges[i*2+1]); + if( (unsigned)idx >= (unsigned)size[i] ) + break; + ptrs[i] += deltas[i*2]; + Hptr += idx*hstep[i]; + } + + if( i == dims ) + ++*((int*)Hptr); + else + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + else + for( x = 0; x < imsize.width; x++ ) + { + uchar* Hptr = H; + i = 0; + if( mask[x] ) + for( ; i < dims; i++ ) + { + int idx = cvFloor(*ptrs[i]*uniranges[i*2] + uniranges[i*2+1]); + if( (unsigned)idx >= (unsigned)size[i] ) + break; + ptrs[i] += deltas[i*2]; + Hptr += idx*hstep[i]; + } + + if( i == dims ) + ++*((int*)Hptr); + else + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + for( i = 0; i < dims; i++ ) + ptrs[i] += deltas[i*2 + 1]; + } + } + } + else + { + // non-uniform histogram + const float* ranges[CV_MAX_DIM]; + for( i = 0; i < dims; i++ ) + ranges[i] = &_ranges[i][0]; + + for( ; imsize.height--; mask += mstep ) + { + for( x = 0; x < imsize.width; x++ ) + { + uchar* Hptr = H; + i = 0; + + if( !mask || mask[x] ) + for( ; i < dims; i++ ) + { + float v = (float)*ptrs[i]; + const float* R = ranges[i]; + int idx = -1, sz = size[i]; + + while( v >= R[idx+1] && ++idx < sz ) + ; // nop + + if( (unsigned)idx >= (unsigned)sz ) + break; + + ptrs[i] += deltas[i*2]; + Hptr += idx*hstep[i]; + } + + if( i == dims ) + ++*((int*)Hptr); + else + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + + for( i = 0; i < dims; i++ ) + ptrs[i] += deltas[i*2 + 1]; + } + } +} + + +static void +calcHist_8u( vector& _ptrs, const vector& _deltas, + Size imsize, Mat& hist, int dims, const float** _ranges, + const double* _uniranges, bool uniform ) +{ + uchar** ptrs = &_ptrs[0]; + const int* deltas = &_deltas[0]; + uchar* H = hist.data; + int x; + const uchar* mask = _ptrs[dims]; + int mstep = _deltas[dims*2 + 1]; + vector _tab; + + calcHistLookupTables_8u( hist, SparseMat(), dims, _ranges, _uniranges, uniform, false, _tab ); + const size_t* tab = &_tab[0]; + + if( dims == 1 ) + { + int d0 = deltas[0], step0 = deltas[1]; + int matH[256] = {0}; + const uchar* p0 = (const uchar*)ptrs[0]; + + for( ; imsize.height--; p0 += step0, mask += mstep ) + { + if( !mask ) + { + if( d0 == 1 ) + { + for( x = 0; x <= imsize.width - 4; x += 4 ) + { + int t0 = p0[x], t1 = p0[x+1]; + matH[t0]++; matH[t1]++; + t0 = p0[x+2]; t1 = p0[x+3]; + matH[t0]++; matH[t1]++; + } + p0 += x; + } + else + for( x = 0; x <= imsize.width - 4; x += 4 ) + { + int t0 = p0[0], t1 = p0[d0]; + matH[t0]++; matH[t1]++; + p0 += d0*2; + t0 = p0[0]; t1 = p0[d0]; + matH[t0]++; matH[t1]++; + p0 += d0*2; + } + + for( ; x < imsize.width; x++, p0 += d0 ) + matH[*p0]++; + } + else + for( x = 0; x < imsize.width; x++, p0 += d0 ) + if( mask[x] ) + matH[*p0]++; + } + + for(int i = 0; i < 256; i++ ) + { + size_t hidx = tab[i]; + if( hidx < OUT_OF_RANGE ) + *(int*)(H + hidx) += matH[i]; + } + } + else if( dims == 2 ) + { + int d0 = deltas[0], step0 = deltas[1], + d1 = deltas[2], step1 = deltas[3]; + const uchar* p0 = (const uchar*)ptrs[0]; + const uchar* p1 = (const uchar*)ptrs[1]; + + for( ; imsize.height--; p0 += step0, p1 += step1, mask += mstep ) + { + if( !mask ) + for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 ) + { + size_t idx = tab[*p0] + tab[*p1 + 256]; + if( idx < OUT_OF_RANGE ) + ++*(int*)(H + idx); + } + else + for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 ) + { + size_t idx; + if( mask[x] && (idx = tab[*p0] + tab[*p1 + 256]) < OUT_OF_RANGE ) + ++*(int*)(H + idx); + } + } + } + else if( dims == 3 ) + { + int d0 = deltas[0], step0 = deltas[1], + d1 = deltas[2], step1 = deltas[3], + d2 = deltas[4], step2 = deltas[5]; + + const uchar* p0 = (const uchar*)ptrs[0]; + const uchar* p1 = (const uchar*)ptrs[1]; + const uchar* p2 = (const uchar*)ptrs[2]; + + for( ; imsize.height--; p0 += step0, p1 += step1, p2 += step2, mask += mstep ) + { + if( !mask ) + for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 ) + { + size_t idx = tab[*p0] + tab[*p1 + 256] + tab[*p2 + 512]; + if( idx < OUT_OF_RANGE ) + ++*(int*)(H + idx); + } + else + for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 ) + { + size_t idx; + if( mask[x] && (idx = tab[*p0] + tab[*p1 + 256] + tab[*p2 + 512]) < OUT_OF_RANGE ) + ++*(int*)(H + idx); + } + } + } + else + { + for( ; imsize.height--; mask += mstep ) + { + if( !mask ) + for( x = 0; x < imsize.width; x++ ) + { + uchar* Hptr = H; + int i = 0; + for( ; i < dims; i++ ) + { + size_t idx = tab[*ptrs[i] + i*256]; + if( idx >= OUT_OF_RANGE ) + break; + Hptr += idx; + ptrs[i] += deltas[i*2]; + } + + if( i == dims ) + ++*((int*)Hptr); + else + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + else + for( x = 0; x < imsize.width; x++ ) + { + uchar* Hptr = H; + int i = 0; + if( mask[x] ) + for( ; i < dims; i++ ) + { + size_t idx = tab[*ptrs[i] + i*256]; + if( idx >= OUT_OF_RANGE ) + break; + Hptr += idx; + ptrs[i] += deltas[i*2]; + } + + if( i == dims ) + ++*((int*)Hptr); + else + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + for(int i = 0; i < dims; i++ ) + ptrs[i] += deltas[i*2 + 1]; + } + } +} + +} + +void cv::calcHist( const Mat* images, int nimages, const int* channels, + InputArray _mask, OutputArray _hist, int dims, const int* histSize, + const float** ranges, bool uniform, bool accumulate ) +{ + Mat mask = _mask.getMat(); + + CV_Assert(dims > 0 && histSize); + + uchar* histdata = _hist.getMat().data; + _hist.create(dims, histSize, CV_32F); + Mat hist = _hist.getMat(), ihist = hist; + ihist.flags = (ihist.flags & ~CV_MAT_TYPE_MASK)|CV_32S; + + if( !accumulate || histdata != hist.data ) + hist = Scalar(0.); + else + hist.convertTo(ihist, CV_32S); + + vector ptrs; + vector deltas; + vector uniranges; + Size imsize; + + CV_Assert( !mask.data || mask.type() == CV_8UC1 ); + histPrepareImages( images, nimages, channels, mask, dims, hist.size, ranges, + uniform, ptrs, deltas, imsize, uniranges ); + const double* _uniranges = uniform ? &uniranges[0] : 0; + + int depth = images[0].depth(); + + if( depth == CV_8U ) + calcHist_8u(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform ); + else if( depth == CV_16U ) + calcHist_(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform ); + else if( depth == CV_32F ) + calcHist_(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform ); + else + CV_Error(CV_StsUnsupportedFormat, ""); + + ihist.convertTo(hist, CV_32F); +} + + +namespace cv +{ + +template static void +calcSparseHist_( vector& _ptrs, const vector& _deltas, + Size imsize, SparseMat& hist, int dims, const float** _ranges, + const double* _uniranges, bool uniform ) +{ + T** ptrs = (T**)&_ptrs[0]; + const int* deltas = &_deltas[0]; + int i, x; + const uchar* mask = _ptrs[dims]; + int mstep = _deltas[dims*2 + 1]; + const int* size = hist.hdr->size; + int idx[CV_MAX_DIM]; + + if( uniform ) + { + const double* uniranges = &_uniranges[0]; + + for( ; imsize.height--; mask += mstep ) + { + for( x = 0; x < imsize.width; x++ ) + { + i = 0; + if( !mask || mask[x] ) + for( ; i < dims; i++ ) + { + idx[i] = cvFloor(*ptrs[i]*uniranges[i*2] + uniranges[i*2+1]); + if( (unsigned)idx[i] >= (unsigned)size[i] ) + break; + ptrs[i] += deltas[i*2]; + } + + if( i == dims ) + ++*(int*)hist.ptr(idx, true); + else + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + for( i = 0; i < dims; i++ ) + ptrs[i] += deltas[i*2 + 1]; + } + } + else + { + // non-uniform histogram + const float* ranges[CV_MAX_DIM]; + for( i = 0; i < dims; i++ ) + ranges[i] = &_ranges[i][0]; + + for( ; imsize.height--; mask += mstep ) + { + for( x = 0; x < imsize.width; x++ ) + { + i = 0; + + if( !mask || mask[x] ) + for( ; i < dims; i++ ) + { + float v = (float)*ptrs[i]; + const float* R = ranges[i]; + int j = -1, sz = size[i]; + + while( v >= R[j+1] && ++j < sz ) + ; // nop + + if( (unsigned)j >= (unsigned)sz ) + break; + ptrs[i] += deltas[i*2]; + idx[i] = j; + } + + if( i == dims ) + ++*(int*)hist.ptr(idx, true); + else + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + + for( i = 0; i < dims; i++ ) + ptrs[i] += deltas[i*2 + 1]; + } + } +} + + +static void +calcSparseHist_8u( vector& _ptrs, const vector& _deltas, + Size imsize, SparseMat& hist, int dims, const float** _ranges, + const double* _uniranges, bool uniform ) +{ + uchar** ptrs = (uchar**)&_ptrs[0]; + const int* deltas = &_deltas[0]; + int x; + const uchar* mask = _ptrs[dims]; + int mstep = _deltas[dims*2 + 1]; + int idx[CV_MAX_DIM]; + vector _tab; + + calcHistLookupTables_8u( Mat(), hist, dims, _ranges, _uniranges, uniform, true, _tab ); + const size_t* tab = &_tab[0]; + + for( ; imsize.height--; mask += mstep ) + { + for( x = 0; x < imsize.width; x++ ) + { + int i = 0; + if( !mask || mask[x] ) + for( ; i < dims; i++ ) + { + size_t hidx = tab[*ptrs[i] + i*256]; + if( hidx >= OUT_OF_RANGE ) + break; + ptrs[i] += deltas[i*2]; + idx[i] = (int)hidx; + } + + if( i == dims ) + ++*(int*)hist.ptr(idx,true); + else + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + for(int i = 0; i < dims; i++ ) + ptrs[i] += deltas[i*2 + 1]; + } +} + + +static void calcHist( const Mat* images, int nimages, const int* channels, + const Mat& mask, SparseMat& hist, int dims, const int* histSize, + const float** ranges, bool uniform, bool accumulate, bool keepInt ) +{ + size_t i, N; + + if( !accumulate ) + hist.create(dims, histSize, CV_32F); + else + { + SparseMatIterator it = hist.begin(); + for( i = 0, N = hist.nzcount(); i < N; i++, ++it ) + { + Cv32suf* val = (Cv32suf*)it.ptr; + val->i = cvRound(val->f); + } + } + + vector ptrs; + vector deltas; + vector uniranges; + Size imsize; + + CV_Assert( !mask.data || mask.type() == CV_8UC1 ); + histPrepareImages( images, nimages, channels, mask, dims, hist.hdr->size, ranges, + uniform, ptrs, deltas, imsize, uniranges ); + const double* _uniranges = uniform ? &uniranges[0] : 0; + + int depth = images[0].depth(); + if( depth == CV_8U ) + calcSparseHist_8u(ptrs, deltas, imsize, hist, dims, ranges, _uniranges, uniform ); + else if( depth == CV_16U ) + calcSparseHist_(ptrs, deltas, imsize, hist, dims, ranges, _uniranges, uniform ); + else if( depth == CV_32F ) + calcSparseHist_(ptrs, deltas, imsize, hist, dims, ranges, _uniranges, uniform ); + else + CV_Error(CV_StsUnsupportedFormat, ""); + + if( !keepInt ) + { + SparseMatIterator it = hist.begin(); + for( i = 0, N = hist.nzcount(); i < N; i++, ++it ) + { + Cv32suf* val = (Cv32suf*)it.ptr; + val->f = (float)val->i; + } + } +} + +} + +void cv::calcHist( const Mat* images, int nimages, const int* channels, + InputArray _mask, SparseMat& hist, int dims, const int* histSize, + const float** ranges, bool uniform, bool accumulate ) +{ + Mat mask = _mask.getMat(); + calcHist( images, nimages, channels, mask, hist, dims, histSize, + ranges, uniform, accumulate, false ); +} + + +void cv::calcHist( InputArrayOfArrays images, const vector& channels, + InputArray mask, OutputArray hist, + const vector& histSize, + const vector& ranges, + bool accumulate ) +{ + int i, dims = (int)histSize.size(), rsz = (int)ranges.size(), csz = (int)channels.size(); + int nimages = (int)images.total(); + + CV_Assert(nimages > 0 && dims > 0); + CV_Assert(rsz == dims*2 || (rsz == 0 && images.depth(0) == CV_8U)); + CV_Assert(csz == 0 || csz == dims); + float* _ranges[CV_MAX_DIM]; + if( rsz > 0 ) + { + for( i = 0; i < rsz/2; i++ ) + _ranges[i] = (float*)&ranges[i*2]; + } + + AutoBuffer buf(nimages); + for( i = 0; i < nimages; i++ ) + buf[i] = images.getMat(i); + + calcHist(&buf[0], nimages, csz ? &channels[0] : 0, + mask, hist, dims, &histSize[0], rsz ? (const float**)_ranges : 0, + true, accumulate); +} + + +/////////////////////////////////////// B A C K P R O J E C T //////////////////////////////////// + +namespace cv +{ + +template static void +calcBackProj_( vector& _ptrs, const vector& _deltas, + Size imsize, const Mat& hist, int dims, const float** _ranges, + const double* _uniranges, float scale, bool uniform ) +{ + T** ptrs = (T**)&_ptrs[0]; + const int* deltas = &_deltas[0]; + uchar* H = hist.data; + int i, x; + BT* bproj = (BT*)_ptrs[dims]; + int bpstep = _deltas[dims*2 + 1]; + int size[CV_MAX_DIM]; + size_t hstep[CV_MAX_DIM]; + + for( i = 0; i < dims; i++ ) + { + size[i] = hist.size[i]; + hstep[i] = hist.step[i]; + } + + if( uniform ) + { + const double* uniranges = &_uniranges[0]; + + if( dims == 1 ) + { + double a = uniranges[0], b = uniranges[1]; + int sz = size[0], d0 = deltas[0], step0 = deltas[1]; + const T* p0 = (const T*)ptrs[0]; + + for( ; imsize.height--; p0 += step0, bproj += bpstep ) + { + for( x = 0; x < imsize.width; x++, p0 += d0 ) + { + int idx = cvFloor(*p0*a + b); + bproj[x] = (unsigned)idx < (unsigned)sz ? saturate_cast(((float*)H)[idx]*scale) : 0; + } + } + } + else if( dims == 2 ) + { + double a0 = uniranges[0], b0 = uniranges[1], + a1 = uniranges[2], b1 = uniranges[3]; + int sz0 = size[0], sz1 = size[1]; + int d0 = deltas[0], step0 = deltas[1], + d1 = deltas[2], step1 = deltas[3]; + size_t hstep0 = hstep[0]; + const T* p0 = (const T*)ptrs[0]; + const T* p1 = (const T*)ptrs[1]; + + for( ; imsize.height--; p0 += step0, p1 += step1, bproj += bpstep ) + { + for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 ) + { + int idx0 = cvFloor(*p0*a0 + b0); + int idx1 = cvFloor(*p1*a1 + b1); + bproj[x] = (unsigned)idx0 < (unsigned)sz0 && + (unsigned)idx1 < (unsigned)sz1 ? + saturate_cast(((float*)(H + hstep0*idx0))[idx1]*scale) : 0; + } + } + } + else if( dims == 3 ) + { + double a0 = uniranges[0], b0 = uniranges[1], + a1 = uniranges[2], b1 = uniranges[3], + a2 = uniranges[4], b2 = uniranges[5]; + int sz0 = size[0], sz1 = size[1], sz2 = size[2]; + int d0 = deltas[0], step0 = deltas[1], + d1 = deltas[2], step1 = deltas[3], + d2 = deltas[4], step2 = deltas[5]; + size_t hstep0 = hstep[0], hstep1 = hstep[1]; + const T* p0 = (const T*)ptrs[0]; + const T* p1 = (const T*)ptrs[1]; + const T* p2 = (const T*)ptrs[2]; + + for( ; imsize.height--; p0 += step0, p1 += step1, p2 += step2, bproj += bpstep ) + { + for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 ) + { + int idx0 = cvFloor(*p0*a0 + b0); + int idx1 = cvFloor(*p1*a1 + b1); + int idx2 = cvFloor(*p2*a2 + b2); + bproj[x] = (unsigned)idx0 < (unsigned)sz0 && + (unsigned)idx1 < (unsigned)sz1 && + (unsigned)idx2 < (unsigned)sz2 ? + saturate_cast(((float*)(H + hstep0*idx0 + hstep1*idx1))[idx2]*scale) : 0; + } + } + } + else + { + for( ; imsize.height--; bproj += bpstep ) + { + for( x = 0; x < imsize.width; x++ ) + { + uchar* Hptr = H; + for( i = 0; i < dims; i++ ) + { + int idx = cvFloor(*ptrs[i]*uniranges[i*2] + uniranges[i*2+1]); + if( (unsigned)idx >= (unsigned)size[i] || (_ranges && *ptrs[i] >= _ranges[i][1])) + break; + ptrs[i] += deltas[i*2]; + Hptr += idx*hstep[i]; + } + + if( i == dims ) + bproj[x] = saturate_cast(*(float*)Hptr*scale); + else + { + bproj[x] = 0; + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + } + for( i = 0; i < dims; i++ ) + ptrs[i] += deltas[i*2 + 1]; + } + } + } + else + { + // non-uniform histogram + const float* ranges[CV_MAX_DIM]; + for( i = 0; i < dims; i++ ) + ranges[i] = &_ranges[i][0]; + + for( ; imsize.height--; bproj += bpstep ) + { + for( x = 0; x < imsize.width; x++ ) + { + uchar* Hptr = H; + for( i = 0; i < dims; i++ ) + { + float v = (float)*ptrs[i]; + const float* R = ranges[i]; + int idx = -1, sz = size[i]; + + while( v >= R[idx+1] && ++idx < sz ) + ; // nop + + if( (unsigned)idx >= (unsigned)sz ) + break; + + ptrs[i] += deltas[i*2]; + Hptr += idx*hstep[i]; + } + + if( i == dims ) + bproj[x] = saturate_cast(*(float*)Hptr*scale); + else + { + bproj[x] = 0; + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + } + + for( i = 0; i < dims; i++ ) + ptrs[i] += deltas[i*2 + 1]; + } + } +} + + +static void +calcBackProj_8u( vector& _ptrs, const vector& _deltas, + Size imsize, const Mat& hist, int dims, const float** _ranges, + const double* _uniranges, float scale, bool uniform ) +{ + uchar** ptrs = &_ptrs[0]; + const int* deltas = &_deltas[0]; + uchar* H = hist.data; + int i, x; + uchar* bproj = _ptrs[dims]; + int bpstep = _deltas[dims*2 + 1]; + vector _tab; + + calcHistLookupTables_8u( hist, SparseMat(), dims, _ranges, _uniranges, uniform, false, _tab ); + const size_t* tab = &_tab[0]; + + if( dims == 1 ) + { + int d0 = deltas[0], step0 = deltas[1]; + uchar matH[256] = {0}; + const uchar* p0 = (const uchar*)ptrs[0]; + + for( i = 0; i < 256; i++ ) + { + size_t hidx = tab[i]; + if( hidx < OUT_OF_RANGE ) + matH[i] = saturate_cast(*(float*)(H + hidx)*scale); + } + + for( ; imsize.height--; p0 += step0, bproj += bpstep ) + { + if( d0 == 1 ) + { + for( x = 0; x <= imsize.width - 4; x += 4 ) + { + uchar t0 = matH[p0[x]], t1 = matH[p0[x+1]]; + bproj[x] = t0; bproj[x+1] = t1; + t0 = matH[p0[x+2]]; t1 = matH[p0[x+3]]; + bproj[x+2] = t0; bproj[x+3] = t1; + } + p0 += x; + } + else + for( x = 0; x <= imsize.width - 4; x += 4 ) + { + uchar t0 = matH[p0[0]], t1 = matH[p0[d0]]; + bproj[x] = t0; bproj[x+1] = t1; + p0 += d0*2; + t0 = matH[p0[0]]; t1 = matH[p0[d0]]; + bproj[x+2] = t0; bproj[x+3] = t1; + p0 += d0*2; + } + + for( ; x < imsize.width; x++, p0 += d0 ) + bproj[x] = matH[*p0]; + } + } + else if( dims == 2 ) + { + int d0 = deltas[0], step0 = deltas[1], + d1 = deltas[2], step1 = deltas[3]; + const uchar* p0 = (const uchar*)ptrs[0]; + const uchar* p1 = (const uchar*)ptrs[1]; + + for( ; imsize.height--; p0 += step0, p1 += step1, bproj += bpstep ) + { + for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 ) + { + size_t idx = tab[*p0] + tab[*p1 + 256]; + bproj[x] = idx < OUT_OF_RANGE ? saturate_cast(*(float*)(H + idx)*scale) : 0; + } + } + } + else if( dims == 3 ) + { + int d0 = deltas[0], step0 = deltas[1], + d1 = deltas[2], step1 = deltas[3], + d2 = deltas[4], step2 = deltas[5]; + const uchar* p0 = (const uchar*)ptrs[0]; + const uchar* p1 = (const uchar*)ptrs[1]; + const uchar* p2 = (const uchar*)ptrs[2]; + + for( ; imsize.height--; p0 += step0, p1 += step1, p2 += step2, bproj += bpstep ) + { + for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 ) + { + size_t idx = tab[*p0] + tab[*p1 + 256] + tab[*p2 + 512]; + bproj[x] = idx < OUT_OF_RANGE ? saturate_cast(*(float*)(H + idx)*scale) : 0; + } + } + } + else + { + for( ; imsize.height--; bproj += bpstep ) + { + for( x = 0; x < imsize.width; x++ ) + { + uchar* Hptr = H; + for( i = 0; i < dims; i++ ) + { + size_t idx = tab[*ptrs[i] + i*256]; + if( idx >= OUT_OF_RANGE ) + break; + ptrs[i] += deltas[i*2]; + Hptr += idx; + } + + if( i == dims ) + bproj[x] = saturate_cast(*(float*)Hptr*scale); + else + { + bproj[x] = 0; + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + } + for( i = 0; i < dims; i++ ) + ptrs[i] += deltas[i*2 + 1]; + } + } +} + +} + +void cv::calcBackProject( const Mat* images, int nimages, const int* channels, + InputArray _hist, OutputArray _backProject, + const float** ranges, double scale, bool uniform ) +{ + Mat hist = _hist.getMat(); + vector ptrs; + vector deltas; + vector uniranges; + Size imsize; + int dims = hist.dims == 2 && hist.size[1] == 1 ? 1 : hist.dims; + + CV_Assert( dims > 0 && hist.data ); + _backProject.create( images[0].size(), images[0].depth() ); + Mat backProject = _backProject.getMat(); + histPrepareImages( images, nimages, channels, backProject, dims, hist.size, ranges, + uniform, ptrs, deltas, imsize, uniranges ); + const double* _uniranges = uniform ? &uniranges[0] : 0; + + int depth = images[0].depth(); + if( depth == CV_8U ) + calcBackProj_8u(ptrs, deltas, imsize, hist, dims, ranges, _uniranges, (float)scale, uniform); + else if( depth == CV_16U ) + calcBackProj_(ptrs, deltas, imsize, hist, dims, ranges, _uniranges, (float)scale, uniform ); + else if( depth == CV_32F ) + calcBackProj_(ptrs, deltas, imsize, hist, dims, ranges, _uniranges, (float)scale, uniform ); + else + CV_Error(CV_StsUnsupportedFormat, ""); +} + + +namespace cv +{ + +template static void +calcSparseBackProj_( vector& _ptrs, const vector& _deltas, + Size imsize, const SparseMat& hist, int dims, const float** _ranges, + const double* _uniranges, float scale, bool uniform ) +{ + T** ptrs = (T**)&_ptrs[0]; + const int* deltas = &_deltas[0]; + int i, x; + BT* bproj = (BT*)_ptrs[dims]; + int bpstep = _deltas[dims*2 + 1]; + const int* size = hist.hdr->size; + int idx[CV_MAX_DIM]; + const SparseMat_& hist_ = (const SparseMat_&)hist; + + if( uniform ) + { + const double* uniranges = &_uniranges[0]; + for( ; imsize.height--; bproj += bpstep ) + { + for( x = 0; x < imsize.width; x++ ) + { + for( i = 0; i < dims; i++ ) + { + idx[i] = cvFloor(*ptrs[i]*uniranges[i*2] + uniranges[i*2+1]); + if( (unsigned)idx[i] >= (unsigned)size[i] ) + break; + ptrs[i] += deltas[i*2]; + } + + if( i == dims ) + bproj[x] = saturate_cast(hist_(idx)*scale); + else + { + bproj[x] = 0; + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + } + for( i = 0; i < dims; i++ ) + ptrs[i] += deltas[i*2 + 1]; + } + } + else + { + // non-uniform histogram + const float* ranges[CV_MAX_DIM]; + for( i = 0; i < dims; i++ ) + ranges[i] = &_ranges[i][0]; + + for( ; imsize.height--; bproj += bpstep ) + { + for( x = 0; x < imsize.width; x++ ) + { + for( i = 0; i < dims; i++ ) + { + float v = (float)*ptrs[i]; + const float* R = ranges[i]; + int j = -1, sz = size[i]; + + while( v >= R[j+1] && ++j < sz ) + ; // nop + + if( (unsigned)j >= (unsigned)sz ) + break; + idx[i] = j; + ptrs[i] += deltas[i*2]; + } + + if( i == dims ) + bproj[x] = saturate_cast(hist_(idx)*scale); + else + { + bproj[x] = 0; + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + } + + for( i = 0; i < dims; i++ ) + ptrs[i] += deltas[i*2 + 1]; + } + } +} + + +static void +calcSparseBackProj_8u( vector& _ptrs, const vector& _deltas, + Size imsize, const SparseMat& hist, int dims, const float** _ranges, + const double* _uniranges, float scale, bool uniform ) +{ + uchar** ptrs = &_ptrs[0]; + const int* deltas = &_deltas[0]; + int i, x; + uchar* bproj = _ptrs[dims]; + int bpstep = _deltas[dims*2 + 1]; + vector _tab; + int idx[CV_MAX_DIM]; + + calcHistLookupTables_8u( Mat(), hist, dims, _ranges, _uniranges, uniform, true, _tab ); + const size_t* tab = &_tab[0]; + + for( ; imsize.height--; bproj += bpstep ) + { + for( x = 0; x < imsize.width; x++ ) + { + for( i = 0; i < dims; i++ ) + { + size_t hidx = tab[*ptrs[i] + i*256]; + if( hidx >= OUT_OF_RANGE ) + break; + idx[i] = (int)hidx; + ptrs[i] += deltas[i*2]; + } + + if( i == dims ) + bproj[x] = saturate_cast(hist.value(idx)*scale); + else + { + bproj[x] = 0; + for( ; i < dims; i++ ) + ptrs[i] += deltas[i*2]; + } + } + for( i = 0; i < dims; i++ ) + ptrs[i] += deltas[i*2 + 1]; + } +} + +} + +void cv::calcBackProject( const Mat* images, int nimages, const int* channels, + const SparseMat& hist, OutputArray _backProject, + const float** ranges, double scale, bool uniform ) +{ + vector ptrs; + vector deltas; + vector uniranges; + Size imsize; + int dims = hist.dims(); + + CV_Assert( dims > 0 ); + _backProject.create( images[0].size(), images[0].depth() ); + Mat backProject = _backProject.getMat(); + histPrepareImages( images, nimages, channels, backProject, + dims, hist.hdr->size, ranges, + uniform, ptrs, deltas, imsize, uniranges ); + const double* _uniranges = uniform ? &uniranges[0] : 0; + + int depth = images[0].depth(); + if( depth == CV_8U ) + calcSparseBackProj_8u(ptrs, deltas, imsize, hist, dims, ranges, + _uniranges, (float)scale, uniform); + else if( depth == CV_16U ) + calcSparseBackProj_(ptrs, deltas, imsize, hist, dims, ranges, + _uniranges, (float)scale, uniform ); + else if( depth == CV_32F ) + calcSparseBackProj_(ptrs, deltas, imsize, hist, dims, ranges, + _uniranges, (float)scale, uniform ); + else + CV_Error(CV_StsUnsupportedFormat, ""); +} + + +void cv::calcBackProject( InputArrayOfArrays images, const vector& channels, + InputArray hist, OutputArray dst, + const vector& ranges, + double scale ) +{ + Mat H0 = hist.getMat(), H; + int hcn = H0.channels(); + if( hcn > 1 ) + { + CV_Assert( H0.isContinuous() ); + int hsz[CV_CN_MAX+1]; + memcpy(hsz, &H0.size[0], H0.dims*sizeof(hsz[0])); + hsz[H0.dims] = hcn; + H = Mat(H0.dims+1, hsz, H0.depth(), H0.data); + } + else + H = H0; + bool _1d = H.rows == 1 || H.cols == 1; + int i, dims = H.dims, rsz = (int)ranges.size(), csz = (int)channels.size(); + int nimages = (int)images.total(); + CV_Assert(nimages > 0); + CV_Assert(rsz == dims*2 || (rsz == 2 && _1d) || (rsz == 0 && images.depth(0) == CV_8U)); + CV_Assert(csz == 0 || csz == dims || (csz == 1 && _1d)); + float* _ranges[CV_MAX_DIM]; + if( rsz > 0 ) + { + for( i = 0; i < rsz/2; i++ ) + _ranges[i] = (float*)&ranges[i*2]; + } + + AutoBuffer buf(nimages); + for( i = 0; i < nimages; i++ ) + buf[i] = images.getMat(i); + + calcBackProject(&buf[0], nimages, csz ? &channels[0] : 0, + hist, dst, rsz ? (const float**)_ranges : 0, scale, true); +} + + +////////////////// C O M P A R E H I S T O G R A M S //////////////////////// + +double cv::compareHist( InputArray _H1, InputArray _H2, int method ) +{ + Mat H1 = _H1.getMat(), H2 = _H2.getMat(); + const Mat* arrays[] = {&H1, &H2, 0}; + Mat planes[2]; + NAryMatIterator it(arrays, planes); + double result = 0; + int j, len = (int)it.size; + + CV_Assert( H1.type() == H2.type() && H1.type() == CV_32F ); + + double s1 = 0, s2 = 0, s11 = 0, s12 = 0, s22 = 0; + + CV_Assert( it.planes[0].isContinuous() && it.planes[1].isContinuous() ); + + for( size_t i = 0; i < it.nplanes; i++, ++it ) + { + const float* h1 = (const float*)it.planes[0].data; + const float* h2 = (const float*)it.planes[1].data; + len = it.planes[0].rows*it.planes[0].cols; + + if( method == CV_COMP_CHISQR ) + { + for( j = 0; j < len; j++ ) + { + double a = h1[j] - h2[j]; + double b = h1[j]; + if( fabs(b) > DBL_EPSILON ) + result += a*a/b; + } + } + else if( method == CV_COMP_CORREL ) + { + for( j = 0; j < len; j++ ) + { + double a = h1[j]; + double b = h2[j]; + + s12 += a*b; + s1 += a; + s11 += a*a; + s2 += b; + s22 += b*b; + } + } + else if( method == CV_COMP_INTERSECT ) + { + for( j = 0; j < len; j++ ) + result += std::min(h1[j], h2[j]); + } + else if( method == CV_COMP_BHATTACHARYYA ) + { + for( j = 0; j < len; j++ ) + { + double a = h1[j]; + double b = h2[j]; + result += std::sqrt(a*b); + s1 += a; + s2 += b; + } + } + else + CV_Error( CV_StsBadArg, "Unknown comparison method" ); + } + + if( method == CV_COMP_CORREL ) + { + size_t total = H1.total(); + double scale = 1./total; + double num = s12 - s1*s2*scale; + double denom2 = (s11 - s1*s1*scale)*(s22 - s2*s2*scale); + result = std::abs(denom2) > DBL_EPSILON ? num/std::sqrt(denom2) : 1.; + } + else if( method == CV_COMP_BHATTACHARYYA ) + { + s1 *= s2; + s1 = fabs(s1) > FLT_EPSILON ? 1./std::sqrt(s1) : 1.; + result = std::sqrt(std::max(1. - result*s1, 0.)); + } + + return result; +} + + +double cv::compareHist( const SparseMat& H1, const SparseMat& H2, int method ) +{ + double result = 0; + int i, dims = H1.dims(); + + CV_Assert( dims > 0 && dims == H2.dims() && H1.type() == H2.type() && H1.type() == CV_32F ); + for( i = 0; i < dims; i++ ) + CV_Assert( H1.size(i) == H2.size(i) ); + + const SparseMat *PH1 = &H1, *PH2 = &H2; + if( PH1->nzcount() > PH2->nzcount() && method != CV_COMP_CHISQR ) + std::swap(PH1, PH2); + + SparseMatConstIterator it = PH1->begin(); + int N1 = (int)PH1->nzcount(), N2 = (int)PH2->nzcount(); + + if( method == CV_COMP_CHISQR ) + { + for( i = 0; i < N1; i++, ++it ) + { + float v1 = it.value(); + const SparseMat::Node* node = it.node(); + float v2 = PH2->value(node->idx, (size_t*)&node->hashval); + double a = v1 - v2; + double b = v1; + if( fabs(b) > DBL_EPSILON ) + result += a*a/b; + } + } + else if( method == CV_COMP_CORREL ) + { + double s1 = 0, s2 = 0, s11 = 0, s12 = 0, s22 = 0; + + for( i = 0; i < N1; i++, ++it ) + { + double v1 = it.value(); + const SparseMat::Node* node = it.node(); + s12 += v1*PH2->value(node->idx, (size_t*)&node->hashval); + s1 += v1; + s11 += v1*v1; + } + + it = PH2->begin(); + for( i = 0; i < N2; i++, ++it ) + { + double v2 = it.value(); + s2 += v2; + s22 += v2*v2; + } + + size_t total = 1; + for( i = 0; i < H1.dims(); i++ ) + total *= H1.size(i); + double scale = 1./total; + double num = s12 - s1*s2*scale; + double denom2 = (s11 - s1*s1*scale)*(s22 - s2*s2*scale); + result = std::abs(denom2) > DBL_EPSILON ? num/std::sqrt(denom2) : 1.; + } + else if( method == CV_COMP_INTERSECT ) + { + for( i = 0; i < N1; i++, ++it ) + { + float v1 = it.value(); + const SparseMat::Node* node = it.node(); + float v2 = PH2->value(node->idx, (size_t*)&node->hashval); + if( v2 ) + result += std::min(v1, v2); + } + } + else if( method == CV_COMP_BHATTACHARYYA ) + { + double s1 = 0, s2 = 0; + + for( i = 0; i < N1; i++, ++it ) + { + double v1 = it.value(); + const SparseMat::Node* node = it.node(); + double v2 = PH2->value(node->idx, (size_t*)&node->hashval); + result += std::sqrt(v1*v2); + s1 += v1; + } + + it = PH2->begin(); + for( i = 0; i < N2; i++, ++it ) + s2 += it.value(); + + s1 *= s2; + s1 = fabs(s1) > FLT_EPSILON ? 1./std::sqrt(s1) : 1.; + result = std::sqrt(std::max(1. - result*s1, 0.)); + } + else + CV_Error( CV_StsBadArg, "Unknown comparison method" ); + + return result; +} + + +const int CV_HIST_DEFAULT_TYPE = CV_32F; + +/* Creates new histogram */ +CvHistogram * +cvCreateHist( int dims, int *sizes, CvHistType type, float** ranges, int uniform ) +{ + CvHistogram *hist = 0; + + if( (unsigned)dims > CV_MAX_DIM ) + CV_Error( CV_BadOrder, "Number of dimensions is out of range" ); + + if( !sizes ) + CV_Error( CV_HeaderIsNull, "Null pointer" ); + + hist = (CvHistogram *)cvAlloc( sizeof( CvHistogram )); + hist->type = CV_HIST_MAGIC_VAL + ((int)type & 1); + if (uniform) hist->type|= CV_HIST_UNIFORM_FLAG; + hist->thresh2 = 0; + hist->bins = 0; + if( type == CV_HIST_ARRAY ) + { + hist->bins = cvInitMatNDHeader( &hist->mat, dims, sizes, + CV_HIST_DEFAULT_TYPE ); + cvCreateData( hist->bins ); + } + else if( type == CV_HIST_SPARSE ) + hist->bins = cvCreateSparseMat( dims, sizes, CV_HIST_DEFAULT_TYPE ); + else + CV_Error( CV_StsBadArg, "Invalid histogram type" ); + + if( ranges ) + cvSetHistBinRanges( hist, ranges, uniform ); + + return hist; +} + + +/* Creates histogram wrapping header for given array */ +CV_IMPL CvHistogram* +cvMakeHistHeaderForArray( int dims, int *sizes, CvHistogram *hist, + float *data, float **ranges, int uniform ) +{ + if( !hist ) + CV_Error( CV_StsNullPtr, "Null histogram header pointer" ); + + if( !data ) + CV_Error( CV_StsNullPtr, "Null data pointer" ); + + hist->thresh2 = 0; + hist->type = CV_HIST_MAGIC_VAL; + hist->bins = cvInitMatNDHeader( &hist->mat, dims, sizes, CV_HIST_DEFAULT_TYPE, data ); + + if( ranges ) + { + if( !uniform ) + CV_Error( CV_StsBadArg, "Only uniform bin ranges can be used here " + "(to avoid memory allocation)" ); + cvSetHistBinRanges( hist, ranges, uniform ); + } + + return hist; +} + + +CV_IMPL void +cvReleaseHist( CvHistogram **hist ) +{ + if( !hist ) + CV_Error( CV_StsNullPtr, "" ); + + if( *hist ) + { + CvHistogram* temp = *hist; + + if( !CV_IS_HIST(temp)) + CV_Error( CV_StsBadArg, "Invalid histogram header" ); + *hist = 0; + + if( CV_IS_SPARSE_HIST( temp )) + cvReleaseSparseMat( (CvSparseMat**)&temp->bins ); + else + { + cvReleaseData( temp->bins ); + temp->bins = 0; + } + + if( temp->thresh2 ) + cvFree( &temp->thresh2 ); + cvFree( &temp ); + } +} + +CV_IMPL void +cvClearHist( CvHistogram *hist ) +{ + if( !CV_IS_HIST(hist) ) + CV_Error( CV_StsBadArg, "Invalid histogram header" ); + cvZero( hist->bins ); +} + + +// Clears histogram bins that are below than threshold +CV_IMPL void +cvThreshHist( CvHistogram* hist, double thresh ) +{ + if( !CV_IS_HIST(hist) ) + CV_Error( CV_StsBadArg, "Invalid histogram header" ); + + if( !CV_IS_SPARSE_MAT(hist->bins) ) + { + CvMat mat; + cvGetMat( hist->bins, &mat, 0, 1 ); + cvThreshold( &mat, &mat, thresh, 0, CV_THRESH_TOZERO ); + } + else + { + CvSparseMat* mat = (CvSparseMat*)hist->bins; + CvSparseMatIterator iterator; + CvSparseNode *node; + + for( node = cvInitSparseMatIterator( mat, &iterator ); + node != 0; node = cvGetNextSparseNode( &iterator )) + { + float* val = (float*)CV_NODE_VAL( mat, node ); + if( *val <= thresh ) + *val = 0; + } + } +} + + +// Normalizes histogram (make sum of the histogram bins == factor) +CV_IMPL void +cvNormalizeHist( CvHistogram* hist, double factor ) +{ + double sum = 0; + + if( !CV_IS_HIST(hist) ) + CV_Error( CV_StsBadArg, "Invalid histogram header" ); + + if( !CV_IS_SPARSE_HIST(hist) ) + { + CvMat mat; + cvGetMat( hist->bins, &mat, 0, 1 ); + sum = cvSum( &mat ).val[0]; + if( fabs(sum) < DBL_EPSILON ) + sum = 1; + cvScale( &mat, &mat, factor/sum, 0 ); + } + else + { + CvSparseMat* mat = (CvSparseMat*)hist->bins; + CvSparseMatIterator iterator; + CvSparseNode *node; + float scale; + + for( node = cvInitSparseMatIterator( mat, &iterator ); + node != 0; node = cvGetNextSparseNode( &iterator )) + { + sum += *(float*)CV_NODE_VAL(mat,node); + } + + if( fabs(sum) < DBL_EPSILON ) + sum = 1; + scale = (float)(factor/sum); + + for( node = cvInitSparseMatIterator( mat, &iterator ); + node != 0; node = cvGetNextSparseNode( &iterator )) + { + *(float*)CV_NODE_VAL(mat,node) *= scale; + } + } +} + + +// Retrieves histogram global min, max and their positions +CV_IMPL void +cvGetMinMaxHistValue( const CvHistogram* hist, + float *value_min, float* value_max, + int* idx_min, int* idx_max ) +{ + double minVal, maxVal; + int dims, size[CV_MAX_DIM]; + + if( !CV_IS_HIST(hist) ) + CV_Error( CV_StsBadArg, "Invalid histogram header" ); + + dims = cvGetDims( hist->bins, size ); + + if( !CV_IS_SPARSE_HIST(hist) ) + { + CvMat mat; + CvPoint minPt, maxPt; + + cvGetMat( hist->bins, &mat, 0, 1 ); + cvMinMaxLoc( &mat, &minVal, &maxVal, &minPt, &maxPt ); + + if( dims == 1 ) + { + if( idx_min ) + *idx_min = minPt.y + minPt.x; + if( idx_max ) + *idx_max = maxPt.y + maxPt.x; + } + else if( dims == 2 ) + { + if( idx_min ) + idx_min[0] = minPt.y, idx_min[1] = minPt.x; + if( idx_max ) + idx_max[0] = maxPt.y, idx_max[1] = maxPt.x; + } + else if( idx_min || idx_max ) + { + int imin = minPt.y*mat.cols + minPt.x; + int imax = maxPt.y*mat.cols + maxPt.x; + + for(int i = dims - 1; i >= 0; i-- ) + { + if( idx_min ) + { + int t = imin / size[i]; + idx_min[i] = imin - t*size[i]; + imin = t; + } + + if( idx_max ) + { + int t = imax / size[i]; + idx_max[i] = imax - t*size[i]; + imax = t; + } + } + } + } + else + { + CvSparseMat* mat = (CvSparseMat*)hist->bins; + CvSparseMatIterator iterator; + CvSparseNode *node; + int minv = INT_MAX; + int maxv = INT_MIN; + CvSparseNode* minNode = 0; + CvSparseNode* maxNode = 0; + const int *_idx_min = 0, *_idx_max = 0; + Cv32suf m; + + for( node = cvInitSparseMatIterator( mat, &iterator ); + node != 0; node = cvGetNextSparseNode( &iterator )) + { + int value = *(int*)CV_NODE_VAL(mat,node); + value = CV_TOGGLE_FLT(value); + if( value < minv ) + { + minv = value; + minNode = node; + } + + if( value > maxv ) + { + maxv = value; + maxNode = node; + } + } + + if( minNode ) + { + _idx_min = CV_NODE_IDX(mat,minNode); + _idx_max = CV_NODE_IDX(mat,maxNode); + m.i = CV_TOGGLE_FLT(minv); minVal = m.f; + m.i = CV_TOGGLE_FLT(maxv); maxVal = m.f; + } + else + { + minVal = maxVal = 0; + } + + for(int i = 0; i < dims; i++ ) + { + if( idx_min ) + idx_min[i] = _idx_min ? _idx_min[i] : -1; + if( idx_max ) + idx_max[i] = _idx_max ? _idx_max[i] : -1; + } + } + + if( value_min ) + *value_min = (float)minVal; + + if( value_max ) + *value_max = (float)maxVal; +} + + +// Compares two histograms using one of a few methods +CV_IMPL double +cvCompareHist( const CvHistogram* hist1, + const CvHistogram* hist2, + int method ) +{ + int i; + int size1[CV_MAX_DIM], size2[CV_MAX_DIM], total = 1; + + if( !CV_IS_HIST(hist1) || !CV_IS_HIST(hist2) ) + CV_Error( CV_StsBadArg, "Invalid histogram header[s]" ); + + if( CV_IS_SPARSE_MAT(hist1->bins) != CV_IS_SPARSE_MAT(hist2->bins)) + CV_Error(CV_StsUnmatchedFormats, "One of histograms is sparse and other is not"); + + if( !CV_IS_SPARSE_MAT(hist1->bins) ) + { + cv::Mat H1((const CvMatND*)hist1->bins), H2((const CvMatND*)hist2->bins); + return cv::compareHist(H1, H2, method); + } + + int dims1 = cvGetDims( hist1->bins, size1 ); + int dims2 = cvGetDims( hist2->bins, size2 ); + + if( dims1 != dims2 ) + CV_Error( CV_StsUnmatchedSizes, + "The histograms have different numbers of dimensions" ); + + for( i = 0; i < dims1; i++ ) + { + if( size1[i] != size2[i] ) + CV_Error( CV_StsUnmatchedSizes, "The histograms have different sizes" ); + total *= size1[i]; + } + + double result = 0; + CvSparseMat* mat1 = (CvSparseMat*)(hist1->bins); + CvSparseMat* mat2 = (CvSparseMat*)(hist2->bins); + CvSparseMatIterator iterator; + CvSparseNode *node1, *node2; + + if( mat1->heap->active_count > mat2->heap->active_count && method != CV_COMP_CHISQR ) + { + CvSparseMat* t; + CV_SWAP( mat1, mat2, t ); + } + + if( method == CV_COMP_CHISQR ) + { + for( node1 = cvInitSparseMatIterator( mat1, &iterator ); + node1 != 0; node1 = cvGetNextSparseNode( &iterator )) + { + double v1 = *(float*)CV_NODE_VAL(mat1,node1); + uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1), 0, 0, &node1->hashval ); + double v2 = node2_data ? *(float*)node2_data : 0.f; + double a = v1 - v2; + double b = v1; + if( fabs(b) > DBL_EPSILON ) + result += a*a/b; + } + } + else if( method == CV_COMP_CORREL ) + { + double s1 = 0, s11 = 0; + double s2 = 0, s22 = 0; + double s12 = 0; + double num, denom2, scale = 1./total; + + for( node1 = cvInitSparseMatIterator( mat1, &iterator ); + node1 != 0; node1 = cvGetNextSparseNode( &iterator )) + { + double v1 = *(float*)CV_NODE_VAL(mat1,node1); + uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1), + 0, 0, &node1->hashval ); + if( node2_data ) + { + double v2 = *(float*)node2_data; + s12 += v1*v2; + } + s1 += v1; + s11 += v1*v1; + } + + for( node2 = cvInitSparseMatIterator( mat2, &iterator ); + node2 != 0; node2 = cvGetNextSparseNode( &iterator )) + { + double v2 = *(float*)CV_NODE_VAL(mat2,node2); + s2 += v2; + s22 += v2*v2; + } + + num = s12 - s1*s2*scale; + denom2 = (s11 - s1*s1*scale)*(s22 - s2*s2*scale); + result = fabs(denom2) > DBL_EPSILON ? num/sqrt(denom2) : 1; + } + else if( method == CV_COMP_INTERSECT ) + { + for( node1 = cvInitSparseMatIterator( mat1, &iterator ); + node1 != 0; node1 = cvGetNextSparseNode( &iterator )) + { + float v1 = *(float*)CV_NODE_VAL(mat1,node1); + uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1), + 0, 0, &node1->hashval ); + if( node2_data ) + { + float v2 = *(float*)node2_data; + if( v1 <= v2 ) + result += v1; + else + result += v2; + } + } + } + else if( method == CV_COMP_BHATTACHARYYA ) + { + double s1 = 0, s2 = 0; + + for( node1 = cvInitSparseMatIterator( mat1, &iterator ); + node1 != 0; node1 = cvGetNextSparseNode( &iterator )) + { + double v1 = *(float*)CV_NODE_VAL(mat1,node1); + uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1), + 0, 0, &node1->hashval ); + s1 += v1; + if( node2_data ) + { + double v2 = *(float*)node2_data; + result += sqrt(v1 * v2); + } + } + + for( node1 = cvInitSparseMatIterator( mat2, &iterator ); + node1 != 0; node1 = cvGetNextSparseNode( &iterator )) + { + double v2 = *(float*)CV_NODE_VAL(mat2,node1); + s2 += v2; + } + + s1 *= s2; + s1 = fabs(s1) > FLT_EPSILON ? 1./sqrt(s1) : 1.; + result = 1. - result*s1; + result = sqrt(MAX(result,0.)); + } + else + CV_Error( CV_StsBadArg, "Unknown comparison method" ); + + return result; +} + +// copies one histogram to another +CV_IMPL void +cvCopyHist( const CvHistogram* src, CvHistogram** _dst ) +{ + int eq = 0; + int is_sparse; + int i, dims1, dims2; + int size1[CV_MAX_DIM], size2[CV_MAX_DIM], total = 1; + float* ranges[CV_MAX_DIM]; + float** thresh = 0; + CvHistogram* dst; + + if( !_dst ) + CV_Error( CV_StsNullPtr, "Destination double pointer is NULL" ); + + dst = *_dst; + + if( !CV_IS_HIST(src) || (dst && !CV_IS_HIST(dst)) ) + CV_Error( CV_StsBadArg, "Invalid histogram header[s]" ); + + is_sparse = CV_IS_SPARSE_MAT(src->bins); + dims1 = cvGetDims( src->bins, size1 ); + for( i = 0; i < dims1; i++ ) + total *= size1[i]; + + if( dst && is_sparse == CV_IS_SPARSE_MAT(dst->bins)) + { + dims2 = cvGetDims( dst->bins, size2 ); + + if( dims1 == dims2 ) + { + for( i = 0; i < dims1; i++ ) + if( size1[i] != size2[i] ) + break; + } + + eq = i == dims1; + } + + if( !eq ) + { + cvReleaseHist( _dst ); + dst = cvCreateHist( dims1, size1, !is_sparse ? CV_HIST_ARRAY : CV_HIST_SPARSE, 0, 0 ); + *_dst = dst; + } + + if( CV_HIST_HAS_RANGES( src )) + { + if( CV_IS_UNIFORM_HIST( src )) + { + for( i = 0; i < dims1; i++ ) + ranges[i] = (float*)src->thresh[i]; + thresh = ranges; + } + else + thresh = src->thresh2; + cvSetHistBinRanges( dst, thresh, CV_IS_UNIFORM_HIST(src)); + } + + cvCopy( src->bins, dst->bins ); +} + + +// Sets a value range for every histogram bin +CV_IMPL void +cvSetHistBinRanges( CvHistogram* hist, float** ranges, int uniform ) +{ + int dims, size[CV_MAX_DIM], total = 0; + int i, j; + + if( !ranges ) + CV_Error( CV_StsNullPtr, "NULL ranges pointer" ); + + if( !CV_IS_HIST(hist) ) + CV_Error( CV_StsBadArg, "Invalid histogram header" ); + + dims = cvGetDims( hist->bins, size ); + for( i = 0; i < dims; i++ ) + total += size[i]+1; + + if( uniform ) + { + for( i = 0; i < dims; i++ ) + { + if( !ranges[i] ) + CV_Error( CV_StsNullPtr, "One of elements is NULL" ); + hist->thresh[i][0] = ranges[i][0]; + hist->thresh[i][1] = ranges[i][1]; + } + + hist->type |= CV_HIST_UNIFORM_FLAG + CV_HIST_RANGES_FLAG; + } + else + { + float* dim_ranges; + + if( !hist->thresh2 ) + { + hist->thresh2 = (float**)cvAlloc( + dims*sizeof(hist->thresh2[0])+ + total*sizeof(hist->thresh2[0][0])); + } + dim_ranges = (float*)(hist->thresh2 + dims); + + for( i = 0; i < dims; i++ ) + { + float val0 = -FLT_MAX; + + if( !ranges[i] ) + CV_Error( CV_StsNullPtr, "One of elements is NULL" ); + + for( j = 0; j <= size[i]; j++ ) + { + float val = ranges[i][j]; + if( val <= val0 ) + CV_Error(CV_StsOutOfRange, "Bin ranges should go in ascenting order"); + val0 = dim_ranges[j] = val; + } + + hist->thresh2[i] = dim_ranges; + dim_ranges += size[i] + 1; + } + + hist->type |= CV_HIST_RANGES_FLAG; + hist->type &= ~CV_HIST_UNIFORM_FLAG; + } +} + + +CV_IMPL void +cvCalcArrHist( CvArr** img, CvHistogram* hist, int accumulate, const CvArr* mask ) +{ + if( !CV_IS_HIST(hist)) + CV_Error( CV_StsBadArg, "Bad histogram pointer" ); + + if( !img ) + CV_Error( CV_StsNullPtr, "Null double array pointer" ); + + int size[CV_MAX_DIM]; + int i, dims = cvGetDims( hist->bins, size); + bool uniform = CV_IS_UNIFORM_HIST(hist); + + cv::vector images(dims); + for( i = 0; i < dims; i++ ) + images[i] = cv::cvarrToMat(img[i]); + + cv::Mat _mask; + if( mask ) + _mask = cv::cvarrToMat(mask); + + const float* uranges[CV_MAX_DIM] = {0}; + const float** ranges = 0; + + if( hist->type & CV_HIST_RANGES_FLAG ) + { + ranges = (const float**)hist->thresh2; + if( uniform ) + { + for( i = 0; i < dims; i++ ) + uranges[i] = &hist->thresh[i][0]; + ranges = uranges; + } + } + + if( !CV_IS_SPARSE_HIST(hist) ) + { + cv::Mat H((const CvMatND*)hist->bins); + cv::calcHist( &images[0], (int)images.size(), 0, _mask, + H, cvGetDims(hist->bins), H.size, ranges, uniform, accumulate != 0 ); + } + else + { + CvSparseMat* sparsemat = (CvSparseMat*)hist->bins; + + if( !accumulate ) + cvZero( hist->bins ); + cv::SparseMat sH(sparsemat); + cv::calcHist( &images[0], (int)images.size(), 0, _mask, sH, sH.dims(), + sH.dims() > 0 ? sH.hdr->size : 0, ranges, uniform, accumulate != 0, true ); + + if( accumulate ) + cvZero( sparsemat ); + + cv::SparseMatConstIterator it = sH.begin(); + int nz = (int)sH.nzcount(); + for( i = 0; i < nz; i++, ++it ) + *(float*)cvPtrND(sparsemat, it.node()->idx, 0, -2) = (float)*(const int*)it.ptr; + } +} + + +CV_IMPL void +cvCalcArrBackProject( CvArr** img, CvArr* dst, const CvHistogram* hist ) +{ + if( !CV_IS_HIST(hist)) + CV_Error( CV_StsBadArg, "Bad histogram pointer" ); + + if( !img ) + CV_Error( CV_StsNullPtr, "Null double array pointer" ); + + int size[CV_MAX_DIM]; + int i, dims = cvGetDims( hist->bins, size ); + + bool uniform = CV_IS_UNIFORM_HIST(hist); + const float* uranges[CV_MAX_DIM] = {0}; + const float** ranges = 0; + + if( hist->type & CV_HIST_RANGES_FLAG ) + { + ranges = (const float**)hist->thresh2; + if( uniform ) + { + for( i = 0; i < dims; i++ ) + uranges[i] = &hist->thresh[i][0]; + ranges = uranges; + } + } + + cv::vector images(dims); + for( i = 0; i < dims; i++ ) + images[i] = cv::cvarrToMat(img[i]); + + cv::Mat _dst = cv::cvarrToMat(dst); + + CV_Assert( _dst.size() == images[0].size() && _dst.depth() == images[0].depth() ); + + if( !CV_IS_SPARSE_HIST(hist) ) + { + cv::Mat H((const CvMatND*)hist->bins); + cv::calcBackProject( &images[0], (int)images.size(), + 0, H, _dst, ranges, 1, uniform ); + } + else + { + cv::SparseMat sH((const CvSparseMat*)hist->bins); + cv::calcBackProject( &images[0], (int)images.size(), + 0, sH, _dst, ranges, 1, uniform ); + } +} + + +////////////////////// B A C K P R O J E C T P A T C H ///////////////////////// + +CV_IMPL void +cvCalcArrBackProjectPatch( CvArr** arr, CvArr* dst, CvSize patch_size, CvHistogram* hist, + int method, double norm_factor ) +{ + CvHistogram* model = 0; + + IplImage imgstub[CV_MAX_DIM], *img[CV_MAX_DIM]; + IplROI roi; + CvMat dststub, *dstmat; + int i, dims; + int x, y; + CvSize size; + + if( !CV_IS_HIST(hist)) + CV_Error( CV_StsBadArg, "Bad histogram pointer" ); + + if( !arr ) + CV_Error( CV_StsNullPtr, "Null double array pointer" ); + + if( norm_factor <= 0 ) + CV_Error( CV_StsOutOfRange, + "Bad normalization factor (set it to 1.0 if unsure)" ); + + if( patch_size.width <= 0 || patch_size.height <= 0 ) + CV_Error( CV_StsBadSize, "The patch width and height must be positive" ); + + dims = cvGetDims( hist->bins ); + cvNormalizeHist( hist, norm_factor ); + + for( i = 0; i < dims; i++ ) + { + CvMat stub, *mat; + mat = cvGetMat( arr[i], &stub, 0, 0 ); + img[i] = cvGetImage( mat, &imgstub[i] ); + img[i]->roi = &roi; + } + + dstmat = cvGetMat( dst, &dststub, 0, 0 ); + if( CV_MAT_TYPE( dstmat->type ) != CV_32FC1 ) + CV_Error( CV_StsUnsupportedFormat, "Resultant image must have 32fC1 type" ); + + if( dstmat->cols != img[0]->width - patch_size.width + 1 || + dstmat->rows != img[0]->height - patch_size.height + 1 ) + CV_Error( CV_StsUnmatchedSizes, + "The output map must be (W-w+1 x H-h+1), " + "where the input images are (W x H) each and the patch is (w x h)" ); + + cvCopyHist( hist, &model ); + + size = cvGetMatSize(dstmat); + roi.coi = 0; + roi.width = patch_size.width; + roi.height = patch_size.height; + + for( y = 0; y < size.height; y++ ) + { + for( x = 0; x < size.width; x++ ) + { + double result; + roi.xOffset = x; + roi.yOffset = y; + + cvCalcHist( img, model ); + cvNormalizeHist( model, norm_factor ); + result = cvCompareHist( model, hist, method ); + CV_MAT_ELEM( *dstmat, float, y, x ) = (float)result; + } + } + + cvReleaseHist( &model ); +} + + +// Calculates Bayes probabilistic histograms +CV_IMPL void +cvCalcBayesianProb( CvHistogram** src, int count, CvHistogram** dst ) +{ + int i; + + if( !src || !dst ) + CV_Error( CV_StsNullPtr, "NULL histogram array pointer" ); + + if( count < 2 ) + CV_Error( CV_StsOutOfRange, "Too small number of histograms" ); + + for( i = 0; i < count; i++ ) + { + if( !CV_IS_HIST(src[i]) || !CV_IS_HIST(dst[i]) ) + CV_Error( CV_StsBadArg, "Invalid histogram header" ); + + if( !CV_IS_MATND(src[i]->bins) || !CV_IS_MATND(dst[i]->bins) ) + CV_Error( CV_StsBadArg, "The function supports dense histograms only" ); + } + + cvZero( dst[0]->bins ); + // dst[0] = src[0] + ... + src[count-1] + for( i = 0; i < count; i++ ) + cvAdd( src[i]->bins, dst[0]->bins, dst[0]->bins ); + + cvDiv( 0, dst[0]->bins, dst[0]->bins ); + + // dst[i] = src[i]*(1/dst[0]) + for( i = count - 1; i >= 0; i-- ) + cvMul( src[i]->bins, dst[0]->bins, dst[i]->bins ); +} + + +CV_IMPL void +cvCalcProbDensity( const CvHistogram* hist, const CvHistogram* hist_mask, + CvHistogram* hist_dens, double scale ) +{ + if( scale <= 0 ) + CV_Error( CV_StsOutOfRange, "scale must be positive" ); + + if( !CV_IS_HIST(hist) || !CV_IS_HIST(hist_mask) || !CV_IS_HIST(hist_dens) ) + CV_Error( CV_StsBadArg, "Invalid histogram pointer[s]" ); + + { + CvArr* arrs[] = { hist->bins, hist_mask->bins, hist_dens->bins }; + CvMatND stubs[3]; + CvNArrayIterator iterator; + + cvInitNArrayIterator( 3, arrs, 0, stubs, &iterator ); + + if( CV_MAT_TYPE(iterator.hdr[0]->type) != CV_32FC1 ) + CV_Error( CV_StsUnsupportedFormat, "All histograms must have 32fC1 type" ); + + do + { + const float* srcdata = (const float*)(iterator.ptr[0]); + const float* maskdata = (const float*)(iterator.ptr[1]); + float* dstdata = (float*)(iterator.ptr[2]); + int i; + + for( i = 0; i < iterator.size.width; i++ ) + { + float s = srcdata[i]; + float m = maskdata[i]; + if( s > FLT_EPSILON ) + if( m <= s ) + dstdata[i] = (float)(m*scale/s); + else + dstdata[i] = (float)scale; + else + dstdata[i] = (float)0; + } + } + while( cvNextNArraySlice( &iterator )); + } +} + + +CV_IMPL void cvEqualizeHist( const CvArr* srcarr, CvArr* dstarr ) +{ + CvMat sstub, *src = cvGetMat(srcarr, &sstub); + CvMat dstub, *dst = cvGetMat(dstarr, &dstub); + + CV_Assert( CV_ARE_SIZES_EQ(src, dst) && CV_ARE_TYPES_EQ(src, dst) && + CV_MAT_TYPE(src->type) == CV_8UC1 ); + CvSize size = cvGetMatSize(src); + if( CV_IS_MAT_CONT(src->type & dst->type) ) + { + size.width *= size.height; + size.height = 1; + } + int x, y; + const int hist_sz = 256; + int hist[hist_sz]; + memset(hist, 0, sizeof(hist)); + + for( y = 0; y < size.height; y++ ) + { + const uchar* sptr = src->data.ptr + src->step*y; + for( x = 0; x < size.width; x++ ) + hist[sptr[x]]++; + } + + float scale = 255.f/(size.width*size.height); + int sum = 0; + uchar lut[hist_sz+1]; + + for( int i = 0; i < hist_sz; i++ ) + { + sum += hist[i]; + int val = cvRound(sum*scale); + lut[i] = CV_CAST_8U(val); + } + + lut[0] = 0; + for( y = 0; y < size.height; y++ ) + { + const uchar* sptr = src->data.ptr + src->step*y; + uchar* dptr = dst->data.ptr + dst->step*y; + for( x = 0; x < size.width; x++ ) + dptr[x] = lut[sptr[x]]; + } +} + + +void cv::equalizeHist( InputArray _src, OutputArray _dst ) +{ + Mat src = _src.getMat(); + _dst.create( src.size(), src.type() ); + Mat dst = _dst.getMat(); + CvMat _csrc = src, _cdst = dst; + cvEqualizeHist( &_csrc, &_cdst ); +} + +/* Implementation of RTTI and Generic Functions for CvHistogram */ +#define CV_TYPE_NAME_HIST "opencv-hist" + +static int icvIsHist( const void * ptr ) +{ + return CV_IS_HIST( ((CvHistogram*)ptr) ); +} + +static CvHistogram * icvCloneHist( const CvHistogram * src ) +{ + CvHistogram * dst=NULL; + cvCopyHist(src, &dst); + return dst; +} + +static void *icvReadHist( CvFileStorage * fs, CvFileNode * node ) +{ + CvHistogram * h = 0; + int type = 0; + int is_uniform = 0; + int have_ranges = 0; + + h = (CvHistogram *)cvAlloc( sizeof(CvHistogram) ); + + type = cvReadIntByName( fs, node, "type", 0 ); + is_uniform = cvReadIntByName( fs, node, "is_uniform", 0 ); + have_ranges = cvReadIntByName( fs, node, "have_ranges", 0 ); + h->type = CV_HIST_MAGIC_VAL | type | + (is_uniform ? CV_HIST_UNIFORM_FLAG : 0) | + (have_ranges ? CV_HIST_RANGES_FLAG : 0); + + if(type == CV_HIST_ARRAY) + { + // read histogram bins + CvMatND* mat = (CvMatND*)cvReadByName( fs, node, "mat" ); + int i, sizes[CV_MAX_DIM]; + + if(!CV_IS_MATND(mat)) + CV_Error( CV_StsError, "Expected CvMatND"); + + for(i=0; idims; i++) + sizes[i] = mat->dim[i].size; + + cvInitMatNDHeader( &(h->mat), mat->dims, sizes, mat->type, mat->data.ptr ); + h->bins = &(h->mat); + + // take ownership of refcount pointer as well + h->mat.refcount = mat->refcount; + + // increase refcount so freeing temp header doesn't free data + cvIncRefData( mat ); + + // free temporary header + cvReleaseMatND( &mat ); + } + else + { + h->bins = cvReadByName( fs, node, "bins" ); + if(!CV_IS_SPARSE_MAT(h->bins)){ + CV_Error( CV_StsError, "Unknown Histogram type"); + } + } + + // read thresholds + if(have_ranges) + { + int i, dims, size[CV_MAX_DIM], total = 0; + CvSeqReader reader; + CvFileNode * thresh_node; + + dims = cvGetDims( h->bins, size ); + for( i = 0; i < dims; i++ ) + total += size[i]+1; + + thresh_node = cvGetFileNodeByName( fs, node, "thresh" ); + if(!thresh_node) + CV_Error( CV_StsError, "'thresh' node is missing"); + cvStartReadRawData( fs, thresh_node, &reader ); + + if(is_uniform) + { + for(i=0; ithresh[i], "f" ); + h->thresh2 = NULL; + } + else + { + float* dim_ranges; + h->thresh2 = (float**)cvAlloc( + dims*sizeof(h->thresh2[0])+ + total*sizeof(h->thresh2[0][0])); + dim_ranges = (float*)(h->thresh2 + dims); + for(i=0; i < dims; i++) + { + h->thresh2[i] = dim_ranges; + cvReadRawDataSlice( fs, &reader, size[i]+1, dim_ranges, "f" ); + dim_ranges += size[i] + 1; + } + } + } + + return h; +} + +static void icvWriteHist( CvFileStorage* fs, const char* name, + const void* struct_ptr, CvAttrList /*attributes*/ ) +{ + const CvHistogram * hist = (const CvHistogram *) struct_ptr; + int sizes[CV_MAX_DIM]; + int dims; + int i; + int is_uniform, have_ranges; + + cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_HIST ); + + is_uniform = (CV_IS_UNIFORM_HIST(hist) ? 1 : 0); + have_ranges = (hist->type & CV_HIST_RANGES_FLAG ? 1 : 0); + + cvWriteInt( fs, "type", (hist->type & 1) ); + cvWriteInt( fs, "is_uniform", is_uniform ); + cvWriteInt( fs, "have_ranges", have_ranges ); + if(!CV_IS_SPARSE_HIST(hist)) + cvWrite( fs, "mat", &(hist->mat) ); + else + cvWrite( fs, "bins", hist->bins ); + + // write thresholds + if(have_ranges){ + dims = cvGetDims( hist->bins, sizes ); + cvStartWriteStruct( fs, "thresh", CV_NODE_SEQ + CV_NODE_FLOW ); + if(is_uniform){ + for(i=0; ithresh[i], 2, "f" ); + } + } + else{ + for(i=0; ithresh2[i], sizes[i]+1, "f" ); + } + } + cvEndWriteStruct( fs ); + } + + cvEndWriteStruct( fs ); +} + + +CvType hist_type( CV_TYPE_NAME_HIST, icvIsHist, (CvReleaseFunc)cvReleaseHist, + icvReadHist, icvWriteHist, (CvCloneFunc)icvCloneHist ); + +/* End of file. */ + diff --git a/imgproc/src/hough.cpp b/imgproc/src/hough.cpp new file mode 100644 index 0000000..6b5c2e4 --- /dev/null +++ b/imgproc/src/hough.cpp @@ -0,0 +1,1143 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include "_list.h" + +#define halfPi ((float)(CV_PI*0.5)) +#define Pi ((float)CV_PI) +#define a0 0 /*-4.172325e-7f*/ /*(-(float)0x7)/((float)0x1000000); */ +#define a1 1.000025f /*((float)0x1922253)/((float)0x1000000)*2/Pi; */ +#define a2 -2.652905e-4f /*(-(float)0x2ae6)/((float)0x1000000)*4/(Pi*Pi); */ +#define a3 -0.165624f /*(-(float)0xa45511)/((float)0x1000000)*8/(Pi*Pi*Pi); */ +#define a4 -1.964532e-3f /*(-(float)0x30fd3)/((float)0x1000000)*16/(Pi*Pi*Pi*Pi); */ +#define a5 1.02575e-2f /*((float)0x191cac)/((float)0x1000000)*32/(Pi*Pi*Pi*Pi*Pi); */ +#define a6 -9.580378e-4f /*(-(float)0x3af27)/((float)0x1000000)*64/(Pi*Pi*Pi*Pi*Pi*Pi); */ + +#define _sin(x) ((((((a6*(x) + a5)*(x) + a4)*(x) + a3)*(x) + a2)*(x) + a1)*(x) + a0) +#define _cos(x) _sin(halfPi - (x)) + +/****************************************************************************************\ +* Classical Hough Transform * +\****************************************************************************************/ + +typedef struct CvLinePolar +{ + float rho; + float angle; +} +CvLinePolar; + +/*=====================================================================================*/ + +#define hough_cmp_gt(l1,l2) (aux[l1] > aux[l2]) + +static CV_IMPLEMENT_QSORT_EX( icvHoughSortDescent32s, int, hough_cmp_gt, const int* ) + +/* +Here image is an input raster; +step is it's step; size characterizes it's ROI; +rho and theta are discretization steps (in pixels and radians correspondingly). +threshold is the minimum number of pixels in the feature for it +to be a candidate for line. lines is the output +array of (rho, theta) pairs. linesMax is the buffer size (number of pairs). +Functions return the actual number of found lines. +*/ +static void +icvHoughLinesStandard( const CvMat* img, float rho, float theta, + int threshold, CvSeq *lines, int linesMax ) +{ + cv::AutoBuffer _accum, _sort_buf; + cv::AutoBuffer _tabSin, _tabCos; + + const uchar* image; + int step, width, height; + int numangle, numrho; + int total = 0; + int i, j; + float irho = 1 / rho; + double scale; + + CV_Assert( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 ); + + image = img->data.ptr; + step = img->step; + width = img->cols; + height = img->rows; + + numangle = cvRound(CV_PI / theta); + numrho = cvRound(((width + height) * 2 + 1) / rho); + + _accum.allocate((numangle+2) * (numrho+2)); + _sort_buf.allocate(numangle * numrho); + _tabSin.allocate(numangle); + _tabCos.allocate(numangle); + int *accum = _accum, *sort_buf = _sort_buf; + float *tabSin = _tabSin, *tabCos = _tabCos; + + memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) ); + + float ang = 0; + for(int n = 0; n < numangle; ang += theta, n++ ) + { + tabSin[n] = (float)(sin(ang) * irho); + tabCos[n] = (float)(cos(ang) * irho); + } + + // stage 1. fill accumulator + for( i = 0; i < height; i++ ) + for( j = 0; j < width; j++ ) + { + if( image[i * step + j] != 0 ) + for(int n = 0; n < numangle; n++ ) + { + int r = cvRound( j * tabCos[n] + i * tabSin[n] ); + r += (numrho - 1) / 2; + accum[(n+1) * (numrho+2) + r+1]++; + } + } + + // stage 2. find local maximums + for(int r = 0; r < numrho; r++ ) + for(int n = 0; n < numangle; n++ ) + { + int base = (n+1) * (numrho+2) + r+1; + if( accum[base] > threshold && + accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] && + accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] ) + sort_buf[total++] = base; + } + + // stage 3. sort the detected lines by accumulator value + icvHoughSortDescent32s( sort_buf, total, accum ); + + // stage 4. store the first min(total,linesMax) lines to the output buffer + linesMax = MIN(linesMax, total); + scale = 1./(numrho+2); + for( i = 0; i < linesMax; i++ ) + { + CvLinePolar line; + int idx = sort_buf[i]; + int n = cvFloor(idx*scale) - 1; + int r = idx - (n+1)*(numrho+2) - 1; + line.rho = (r - (numrho - 1)*0.5f) * rho; + line.angle = n * theta; + cvSeqPush( lines, &line ); + } +} + + +/****************************************************************************************\ +* Multi-Scale variant of Classical Hough Transform * +\****************************************************************************************/ + +//DECLARE_AND_IMPLEMENT_LIST( _index, h_ ); +IMPLEMENT_LIST( _index, h_ ) + +static void +icvHoughLinesSDiv( const CvMat* img, + float rho, float theta, int threshold, + int srn, int stn, + CvSeq* lines, int linesMax ) +{ + std::vector _caccum, _buffer; + std::vector _sinTable; + std::vector _x, _y; + float* sinTable; + int *x, *y; + uchar *caccum, *buffer; + _CVLIST* list = 0; + +#define _POINT(row, column)\ + (image_src[(row)*step+(column)]) + + uchar *mcaccum = 0; + int rn, tn; /* number of rho and theta discrete values */ + int index, i; + int ri, ti, ti1, ti0; + int row, col; + float r, t; /* Current rho and theta */ + float rv; /* Some temporary rho value */ + float irho; + float itheta; + float srho, stheta; + float isrho, istheta; + + const uchar* image_src; + int w, h, step; + int fn = 0; + float xc, yc; + + const float d2r = (float)(Pi / 180); + int sfn = srn * stn; + int fi; + int count; + int cmax = 0; + + CVPOS pos; + _index *pindex; + _index vi; + + CV_Assert( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 ); + CV_Assert( linesMax > 0 && rho > 0 && theta > 0 ); + + threshold = MIN( threshold, 255 ); + + image_src = img->data.ptr; + step = img->step; + w = img->cols; + h = img->rows; + + irho = 1 / rho; + itheta = 1 / theta; + srho = rho / srn; + stheta = theta / stn; + isrho = 1 / srho; + istheta = 1 / stheta; + + rn = cvFloor( sqrt( (double)w * w + (double)h * h ) * irho ); + tn = cvFloor( 2 * Pi * itheta ); + + list = h_create_list__index( linesMax < 1000 ? linesMax : 1000 ); + vi.value = threshold; + vi.rho = -1; + h_add_head__index( list, &vi ); + + /* Precalculating sin */ + _sinTable.resize( 5 * tn * stn ); + sinTable = &_sinTable[0]; + + for( index = 0; index < 5 * tn * stn; index++ ) + sinTable[index] = (float)cos( stheta * index * 0.2f ); + + _caccum.resize(rn * tn); + caccum = &_caccum[0]; + memset( caccum, 0, rn * tn * sizeof( caccum[0] )); + + /* Counting all feature pixels */ + for( row = 0; row < h; row++ ) + for( col = 0; col < w; col++ ) + fn += _POINT( row, col ) != 0; + + _x.resize(fn); + _y.resize(fn); + x = &_x[0]; + y = &_y[0]; + + /* Full Hough Transform (it's accumulator update part) */ + fi = 0; + for( row = 0; row < h; row++ ) + { + for( col = 0; col < w; col++ ) + { + if( _POINT( row, col )) + { + int halftn; + float r0; + float scale_factor; + int iprev = -1; + float phi, phi1; + float theta_it; /* Value of theta for iterating */ + + /* Remember the feature point */ + x[fi] = col; + y[fi] = row; + fi++; + + yc = (float) row + 0.5f; + xc = (float) col + 0.5f; + + /* Update the accumulator */ + t = (float) fabs( cvFastArctan( yc, xc ) * d2r ); + r = (float) sqrt( (double)xc * xc + (double)yc * yc ); + r0 = r * irho; + ti0 = cvFloor( (t + Pi / 2) * itheta ); + + caccum[ti0]++; + + theta_it = rho / r; + theta_it = theta_it < theta ? theta_it : theta; + scale_factor = theta_it * itheta; + halftn = cvFloor( Pi / theta_it ); + for( ti1 = 1, phi = theta_it - halfPi, phi1 = (theta_it + t) * itheta; + ti1 < halftn; ti1++, phi += theta_it, phi1 += scale_factor ) + { + rv = r0 * _cos( phi ); + i = cvFloor( rv ) * tn; + i += cvFloor( phi1 ); + assert( i >= 0 ); + assert( i < rn * tn ); + caccum[i] = (uchar) (caccum[i] + ((i ^ iprev) != 0)); + iprev = i; + if( cmax < caccum[i] ) + cmax = caccum[i]; + } + } + } + } + + /* Starting additional analysis */ + count = 0; + for( ri = 0; ri < rn; ri++ ) + { + for( ti = 0; ti < tn; ti++ ) + { + if( caccum[ri * tn + ti] > threshold ) + { + count++; + } + } + } + + if( count * 100 > rn * tn ) + { + icvHoughLinesStandard( img, rho, theta, threshold, lines, linesMax ); + return; + } + + _buffer.resize(srn * stn + 2); + buffer = &_buffer[0]; + mcaccum = buffer + 1; + + count = 0; + for( ri = 0; ri < rn; ri++ ) + { + for( ti = 0; ti < tn; ti++ ) + { + if( caccum[ri * tn + ti] > threshold ) + { + count++; + memset( mcaccum, 0, sfn * sizeof( uchar )); + + for( index = 0; index < fn; index++ ) + { + int ti2; + float r0; + + yc = (float) y[index] + 0.5f; + xc = (float) x[index] + 0.5f; + + /* Update the accumulator */ + t = (float) fabs( cvFastArctan( yc, xc ) * d2r ); + r = (float) sqrt( (double)xc * xc + (double)yc * yc ) * isrho; + ti0 = cvFloor( (t + Pi * 0.5f) * istheta ); + ti2 = (ti * stn - ti0) * 5; + r0 = (float) ri *srn; + + for( ti1 = 0 /*, phi = ti*theta - Pi/2 - t */ ; ti1 < stn; ti1++, ti2 += 5 + /*phi += stheta */ ) + { + /*rv = r*_cos(phi) - r0; */ + rv = r * sinTable[(int) (abs( ti2 ))] - r0; + i = cvFloor( rv ) * stn + ti1; + + i = CV_IMAX( i, -1 ); + i = CV_IMIN( i, sfn ); + mcaccum[i]++; + assert( i >= -1 ); + assert( i <= sfn ); + } + } + + /* Find peaks in maccum... */ + for( index = 0; index < sfn; index++ ) + { + i = 0; + pos = h_get_tail_pos__index( list ); + if( h_get_prev__index( &pos )->value < mcaccum[index] ) + { + vi.value = mcaccum[index]; + vi.rho = index / stn * srho + ri * rho; + vi.theta = index % stn * stheta + ti * theta - halfPi; + while( h_is_pos__index( pos )) + { + if( h_get__index( pos )->value > mcaccum[index] ) + { + h_insert_after__index( list, pos, &vi ); + if( h_get_count__index( list ) > linesMax ) + { + h_remove_tail__index( list ); + } + break; + } + h_get_prev__index( &pos ); + } + if( !h_is_pos__index( pos )) + { + h_add_head__index( list, &vi ); + if( h_get_count__index( list ) > linesMax ) + { + h_remove_tail__index( list ); + } + } + } + } + } + } + } + + pos = h_get_head_pos__index( list ); + if( h_get_count__index( list ) == 1 ) + { + if( h_get__index( pos )->rho < 0 ) + { + h_clear_list__index( list ); + } + } + else + { + while( h_is_pos__index( pos )) + { + CvLinePolar line; + pindex = h_get__index( pos ); + if( pindex->rho < 0 ) + { + /* This should be the last element... */ + h_get_next__index( &pos ); + assert( !h_is_pos__index( pos )); + break; + } + line.rho = pindex->rho; + line.angle = pindex->theta; + cvSeqPush( lines, &line ); + + if( lines->total >= linesMax ) + break; + h_get_next__index( &pos ); + } + } + + h_destroy_list__index(list); +} + + +/****************************************************************************************\ +* Probabilistic Hough Transform * +\****************************************************************************************/ + +static void +icvHoughLinesProbabilistic( CvMat* image, + float rho, float theta, int threshold, + int lineLength, int lineGap, + CvSeq *lines, int linesMax ) +{ + cv::Mat accum, mask; + cv::vector trigtab; + cv::MemStorage storage(cvCreateMemStorage(0)); + + CvSeq* seq; + CvSeqWriter writer; + int width, height; + int numangle, numrho; + float ang; + int r, n, count; + CvPoint pt; + float irho = 1 / rho; + CvRNG rng = cvRNG(-1); + const float* ttab; + uchar* mdata0; + + CV_Assert( CV_IS_MAT(image) && CV_MAT_TYPE(image->type) == CV_8UC1 ); + + width = image->cols; + height = image->rows; + + numangle = cvRound(CV_PI / theta); + numrho = cvRound(((width + height) * 2 + 1) / rho); + + accum.create( numangle, numrho, CV_32SC1 ); + mask.create( height, width, CV_8UC1 ); + trigtab.resize(numangle*2); + accum = cv::Scalar(0); + + for( ang = 0, n = 0; n < numangle; ang += theta, n++ ) + { + trigtab[n*2] = (float)(cos(ang) * irho); + trigtab[n*2+1] = (float)(sin(ang) * irho); + } + ttab = &trigtab[0]; + mdata0 = mask.data; + + cvStartWriteSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage, &writer ); + + // stage 1. collect non-zero image points + for( pt.y = 0, count = 0; pt.y < height; pt.y++ ) + { + const uchar* data = image->data.ptr + pt.y*image->step; + uchar* mdata = mdata0 + pt.y*width; + for( pt.x = 0; pt.x < width; pt.x++ ) + { + if( data[pt.x] ) + { + mdata[pt.x] = (uchar)1; + CV_WRITE_SEQ_ELEM( pt, writer ); + } + else + mdata[pt.x] = 0; + } + } + + seq = cvEndWriteSeq( &writer ); + count = seq->total; + + // stage 2. process all the points in random order + for( ; count > 0; count-- ) + { + // choose random point out of the remaining ones + int idx = cvRandInt(&rng) % count; + int max_val = threshold-1, max_n = 0; + CvPoint* point = (CvPoint*)cvGetSeqElem( seq, idx ); + CvPoint line_end[2] = {{0,0}, {0,0}}; + float a, b; + int* adata = (int*)accum.data; + int i, j, k, x0, y0, dx0, dy0, xflag; + int good_line; + const int shift = 16; + + i = point->y; + j = point->x; + + // "remove" it by overriding it with the last element + *point = *(CvPoint*)cvGetSeqElem( seq, count-1 ); + + // check if it has been excluded already (i.e. belongs to some other line) + if( !mdata0[i*width + j] ) + continue; + + // update accumulator, find the most probable line + for( n = 0; n < numangle; n++, adata += numrho ) + { + r = cvRound( j * ttab[n*2] + i * ttab[n*2+1] ); + r += (numrho - 1) / 2; + int val = ++adata[r]; + if( max_val < val ) + { + max_val = val; + max_n = n; + } + } + + // if it is too "weak" candidate, continue with another point + if( max_val < threshold ) + continue; + + // from the current point walk in each direction + // along the found line and extract the line segment + a = -ttab[max_n*2+1]; + b = ttab[max_n*2]; + x0 = j; + y0 = i; + if( fabs(a) > fabs(b) ) + { + xflag = 1; + dx0 = a > 0 ? 1 : -1; + dy0 = cvRound( b*(1 << shift)/fabs(a) ); + y0 = (y0 << shift) + (1 << (shift-1)); + } + else + { + xflag = 0; + dy0 = b > 0 ? 1 : -1; + dx0 = cvRound( a*(1 << shift)/fabs(b) ); + x0 = (x0 << shift) + (1 << (shift-1)); + } + + for( k = 0; k < 2; k++ ) + { + int gap = 0, x = x0, y = y0, dx = dx0, dy = dy0; + + if( k > 0 ) + dx = -dx, dy = -dy; + + // walk along the line using fixed-point arithmetics, + // stop at the image border or in case of too big gap + for( ;; x += dx, y += dy ) + { + uchar* mdata; + int i1, j1; + + if( xflag ) + { + j1 = x; + i1 = y >> shift; + } + else + { + j1 = x >> shift; + i1 = y; + } + + if( j1 < 0 || j1 >= width || i1 < 0 || i1 >= height ) + break; + + mdata = mdata0 + i1*width + j1; + + // for each non-zero point: + // update line end, + // clear the mask element + // reset the gap + if( *mdata ) + { + gap = 0; + line_end[k].y = i1; + line_end[k].x = j1; + } + else if( ++gap > lineGap ) + break; + } + } + + good_line = abs(line_end[1].x - line_end[0].x) >= lineLength || + abs(line_end[1].y - line_end[0].y) >= lineLength; + + for( k = 0; k < 2; k++ ) + { + int x = x0, y = y0, dx = dx0, dy = dy0; + + if( k > 0 ) + dx = -dx, dy = -dy; + + // walk along the line using fixed-point arithmetics, + // stop at the image border or in case of too big gap + for( ;; x += dx, y += dy ) + { + uchar* mdata; + int i1, j1; + + if( xflag ) + { + j1 = x; + i1 = y >> shift; + } + else + { + j1 = x >> shift; + i1 = y; + } + + mdata = mdata0 + i1*width + j1; + + // for each non-zero point: + // update line end, + // clear the mask element + // reset the gap + if( *mdata ) + { + if( good_line ) + { + adata = (int*)accum.data; + for( n = 0; n < numangle; n++, adata += numrho ) + { + r = cvRound( j1 * ttab[n*2] + i1 * ttab[n*2+1] ); + r += (numrho - 1) / 2; + adata[r]--; + } + } + *mdata = 0; + } + + if( i1 == line_end[k].y && j1 == line_end[k].x ) + break; + } + } + + if( good_line ) + { + CvRect lr = { line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y }; + cvSeqPush( lines, &lr ); + if( lines->total >= linesMax ) + return; + } + } +} + +/* Wrapper function for standard hough transform */ +CV_IMPL CvSeq* +cvHoughLines2( CvArr* src_image, void* lineStorage, int method, + double rho, double theta, int threshold, + double param1, double param2 ) +{ + CvSeq* result = 0; + + CvMat stub, *img = (CvMat*)src_image; + CvMat* mat = 0; + CvSeq* lines = 0; + CvSeq lines_header; + CvSeqBlock lines_block; + int lineType, elemSize; + int linesMax = INT_MAX; + int iparam1, iparam2; + + img = cvGetMat( img, &stub ); + + if( !CV_IS_MASK_ARR(img)) + CV_Error( CV_StsBadArg, "The source image must be 8-bit, single-channel" ); + + if( !lineStorage ) + CV_Error( CV_StsNullPtr, "NULL destination" ); + + if( rho <= 0 || theta <= 0 || threshold <= 0 ) + CV_Error( CV_StsOutOfRange, "rho, theta and threshold must be positive" ); + + if( method != CV_HOUGH_PROBABILISTIC ) + { + lineType = CV_32FC2; + elemSize = sizeof(float)*2; + } + else + { + lineType = CV_32SC4; + elemSize = sizeof(int)*4; + } + + if( CV_IS_STORAGE( lineStorage )) + { + lines = cvCreateSeq( lineType, sizeof(CvSeq), elemSize, (CvMemStorage*)lineStorage ); + } + else if( CV_IS_MAT( lineStorage )) + { + mat = (CvMat*)lineStorage; + + if( !CV_IS_MAT_CONT( mat->type ) || (mat->rows != 1 && mat->cols != 1) ) + CV_Error( CV_StsBadArg, + "The destination matrix should be continuous and have a single row or a single column" ); + + if( CV_MAT_TYPE( mat->type ) != lineType ) + CV_Error( CV_StsBadArg, + "The destination matrix data type is inappropriate, see the manual" ); + + lines = cvMakeSeqHeaderForArray( lineType, sizeof(CvSeq), elemSize, mat->data.ptr, + mat->rows + mat->cols - 1, &lines_header, &lines_block ); + linesMax = lines->total; + cvClearSeq( lines ); + } + else + CV_Error( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" ); + + iparam1 = cvRound(param1); + iparam2 = cvRound(param2); + + switch( method ) + { + case CV_HOUGH_STANDARD: + icvHoughLinesStandard( img, (float)rho, + (float)theta, threshold, lines, linesMax ); + break; + case CV_HOUGH_MULTI_SCALE: + icvHoughLinesSDiv( img, (float)rho, (float)theta, + threshold, iparam1, iparam2, lines, linesMax ); + break; + case CV_HOUGH_PROBABILISTIC: + icvHoughLinesProbabilistic( img, (float)rho, (float)theta, + threshold, iparam1, iparam2, lines, linesMax ); + break; + default: + CV_Error( CV_StsBadArg, "Unrecognized method id" ); + } + + if( mat ) + { + if( mat->cols > mat->rows ) + mat->cols = lines->total; + else + mat->rows = lines->total; + } + else + result = lines; + + return result; +} + + +/****************************************************************************************\ +* Circle Detection * +\****************************************************************************************/ + +static void +icvHoughCirclesGradient( CvMat* img, float dp, float min_dist, + int min_radius, int max_radius, + int canny_threshold, int acc_threshold, + CvSeq* circles, int circles_max ) +{ + const int SHIFT = 10, ONE = 1 << SHIFT; + cv::Ptr dx, dy; + cv::Ptr edges, accum, dist_buf; + std::vector sort_buf; + cv::Ptr storage; + + int x, y, i, j, k, center_count, nz_count; + float min_radius2 = (float)min_radius*min_radius; + float max_radius2 = (float)max_radius*max_radius; + int rows, cols, arows, acols; + int astep, *adata; + float* ddata; + CvSeq *nz, *centers; + float idp, dr; + CvSeqReader reader; + + edges = cvCreateMat( img->rows, img->cols, CV_8UC1 ); + cvCanny( img, edges, MAX(canny_threshold/2,1), canny_threshold, 3 ); + + dx = cvCreateMat( img->rows, img->cols, CV_16SC1 ); + dy = cvCreateMat( img->rows, img->cols, CV_16SC1 ); + cvSobel( img, dx, 1, 0, 3 ); + cvSobel( img, dy, 0, 1, 3 ); + + if( dp < 1.f ) + dp = 1.f; + idp = 1.f/dp; + accum = cvCreateMat( cvCeil(img->rows*idp)+2, cvCeil(img->cols*idp)+2, CV_32SC1 ); + cvZero(accum); + + storage = cvCreateMemStorage(); + nz = cvCreateSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage ); + centers = cvCreateSeq( CV_32SC1, sizeof(CvSeq), sizeof(int), storage ); + + rows = img->rows; + cols = img->cols; + arows = accum->rows - 2; + acols = accum->cols - 2; + adata = accum->data.i; + astep = accum->step/sizeof(adata[0]); + // Accumulate circle evidence for each edge pixel + for( y = 0; y < rows; y++ ) + { + const uchar* edges_row = edges->data.ptr + y*edges->step; + const short* dx_row = (const short*)(dx->data.ptr + y*dx->step); + const short* dy_row = (const short*)(dy->data.ptr + y*dy->step); + + for( x = 0; x < cols; x++ ) + { + float vx, vy; + int sx, sy, x0, y0, x1, y1, r; + CvPoint pt; + + vx = dx_row[x]; + vy = dy_row[x]; + + if( !edges_row[x] || (vx == 0 && vy == 0) ) + continue; + + float mag = sqrt(vx*vx+vy*vy); + assert( mag >= 1 ); + sx = cvRound((vx*idp)*ONE/mag); + sy = cvRound((vy*idp)*ONE/mag); + + x0 = cvRound((x*idp)*ONE); + y0 = cvRound((y*idp)*ONE); + // Step from min_radius to max_radius in both directions of the gradient + for(int k1 = 0; k1 < 2; k1++ ) + { + x1 = x0 + min_radius * sx; + y1 = y0 + min_radius * sy; + + for( r = min_radius; r <= max_radius; x1 += sx, y1 += sy, r++ ) + { + int x2 = x1 >> SHIFT, y2 = y1 >> SHIFT; + if( (unsigned)x2 >= (unsigned)acols || + (unsigned)y2 >= (unsigned)arows ) + break; + adata[y2*astep + x2]++; + } + + sx = -sx; sy = -sy; + } + + pt.x = x; pt.y = y; + cvSeqPush( nz, &pt ); + } + } + + nz_count = nz->total; + if( !nz_count ) + return; + //Find possible circle centers + for( y = 1; y < arows - 1; y++ ) + { + for( x = 1; x < acols - 1; x++ ) + { + int base = y*(acols+2) + x; + if( adata[base] > acc_threshold && + adata[base] > adata[base-1] && adata[base] > adata[base+1] && + adata[base] > adata[base-acols-2] && adata[base] > adata[base+acols+2] ) + cvSeqPush(centers, &base); + } + } + + center_count = centers->total; + if( !center_count ) + return; + + sort_buf.resize( MAX(center_count,nz_count) ); + cvCvtSeqToArray( centers, &sort_buf[0] ); + + icvHoughSortDescent32s( &sort_buf[0], center_count, adata ); + cvClearSeq( centers ); + cvSeqPushMulti( centers, &sort_buf[0], center_count ); + + dist_buf = cvCreateMat( 1, nz_count, CV_32FC1 ); + ddata = dist_buf->data.fl; + + dr = dp; + min_dist = MAX( min_dist, dp ); + min_dist *= min_dist; + // For each found possible center + // Estimate radius and check support + for( i = 0; i < centers->total; i++ ) + { + int ofs = *(int*)cvGetSeqElem( centers, i ); + y = ofs/(acols+2); + x = ofs - (y)*(acols+2); + //Calculate circle's center in pixels + float cx = (float)((x + 0.5f)*dp), cy = (float)(( y + 0.5f )*dp); + float start_dist, dist_sum; + float r_best = 0; + int max_count = 0; + // Check distance with previously detected circles + for( j = 0; j < circles->total; j++ ) + { + float* c = (float*)cvGetSeqElem( circles, j ); + if( (c[0] - cx)*(c[0] - cx) + (c[1] - cy)*(c[1] - cy) < min_dist ) + break; + } + + if( j < circles->total ) + continue; + // Estimate best radius + cvStartReadSeq( nz, &reader ); + for( j = k = 0; j < nz_count; j++ ) + { + CvPoint pt; + float _dx, _dy, _r2; + CV_READ_SEQ_ELEM( pt, reader ); + _dx = cx - pt.x; _dy = cy - pt.y; + _r2 = _dx*_dx + _dy*_dy; + if(min_radius2 <= _r2 && _r2 <= max_radius2 ) + { + ddata[k] = _r2; + sort_buf[k] = k; + k++; + } + } + + int nz_count1 = k, start_idx = nz_count1 - 1; + if( nz_count1 == 0 ) + continue; + dist_buf->cols = nz_count1; + cvPow( dist_buf, dist_buf, 0.5 ); + icvHoughSortDescent32s( &sort_buf[0], nz_count1, (int*)ddata ); + + dist_sum = start_dist = ddata[sort_buf[nz_count1-1]]; + for( j = nz_count1 - 2; j >= 0; j-- ) + { + float d = ddata[sort_buf[j]]; + + if( d > max_radius ) + break; + + if( d - start_dist > dr ) + { + float r_cur = ddata[sort_buf[(j + start_idx)/2]]; + if( (start_idx - j)*r_best >= max_count*r_cur || + (r_best < FLT_EPSILON && start_idx - j >= max_count) ) + { + r_best = r_cur; + max_count = start_idx - j; + } + start_dist = d; + start_idx = j; + dist_sum = 0; + } + dist_sum += d; + } + // Check if the circle has enough support + if( max_count > acc_threshold ) + { + float c[3]; + c[0] = cx; + c[1] = cy; + c[2] = (float)r_best; + cvSeqPush( circles, c ); + if( circles->total > circles_max ) + return; + } + } +} + +CV_IMPL CvSeq* +cvHoughCircles( CvArr* src_image, void* circle_storage, + int method, double dp, double min_dist, + double param1, double param2, + int min_radius, int max_radius ) +{ + CvSeq* result = 0; + + CvMat stub, *img = (CvMat*)src_image; + CvMat* mat = 0; + CvSeq* circles = 0; + CvSeq circles_header; + CvSeqBlock circles_block; + int circles_max = INT_MAX; + int canny_threshold = cvRound(param1); + int acc_threshold = cvRound(param2); + + img = cvGetMat( img, &stub ); + + if( !CV_IS_MASK_ARR(img)) + CV_Error( CV_StsBadArg, "The source image must be 8-bit, single-channel" ); + + if( !circle_storage ) + CV_Error( CV_StsNullPtr, "NULL destination" ); + + if( dp <= 0 || min_dist <= 0 || canny_threshold <= 0 || acc_threshold <= 0 ) + CV_Error( CV_StsOutOfRange, "dp, min_dist, canny_threshold and acc_threshold must be all positive numbers" ); + + min_radius = MAX( min_radius, 0 ); + if( max_radius <= 0 ) + max_radius = MAX( img->rows, img->cols ); + else if( max_radius <= min_radius ) + max_radius = min_radius + 2; + + if( CV_IS_STORAGE( circle_storage )) + { + circles = cvCreateSeq( CV_32FC3, sizeof(CvSeq), + sizeof(float)*3, (CvMemStorage*)circle_storage ); + } + else if( CV_IS_MAT( circle_storage )) + { + mat = (CvMat*)circle_storage; + + if( !CV_IS_MAT_CONT( mat->type ) || (mat->rows != 1 && mat->cols != 1) || + CV_MAT_TYPE(mat->type) != CV_32FC3 ) + CV_Error( CV_StsBadArg, + "The destination matrix should be continuous and have a single row or a single column" ); + + circles = cvMakeSeqHeaderForArray( CV_32FC3, sizeof(CvSeq), sizeof(float)*3, + mat->data.ptr, mat->rows + mat->cols - 1, &circles_header, &circles_block ); + circles_max = circles->total; + cvClearSeq( circles ); + } + else + CV_Error( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" ); + + switch( method ) + { + case CV_HOUGH_GRADIENT: + icvHoughCirclesGradient( img, (float)dp, (float)min_dist, + min_radius, max_radius, canny_threshold, + acc_threshold, circles, circles_max ); + break; + default: + CV_Error( CV_StsBadArg, "Unrecognized method id" ); + } + + if( mat ) + { + if( mat->cols > mat->rows ) + mat->cols = circles->total; + else + mat->rows = circles->total; + } + else + result = circles; + + return result; +} + + +namespace cv +{ + +const int STORAGE_SIZE = 1 << 12; + +static void seqToMat(const CvSeq* seq, OutputArray _arr) +{ + if( seq && seq->total > 0 ) + { + _arr.create(1, seq->total, seq->flags, -1, true); + Mat arr = _arr.getMat(); + cvCvtSeqToArray(seq, arr.data); + } + else + _arr.release(); +} + +} + +void cv::HoughLines( InputArray _image, OutputArray _lines, + double rho, double theta, int threshold, + double srn, double stn ) +{ + Ptr storage = cvCreateMemStorage(STORAGE_SIZE); + Mat image = _image.getMat(); + CvMat c_image = image; + CvSeq* seq = cvHoughLines2( &c_image, storage, srn == 0 && stn == 0 ? + CV_HOUGH_STANDARD : CV_HOUGH_MULTI_SCALE, + rho, theta, threshold, srn, stn ); + seqToMat(seq, _lines); +} + +void cv::HoughLinesP( InputArray _image, OutputArray _lines, + double rho, double theta, int threshold, + double minLineLength, double maxGap ) +{ + Ptr storage = cvCreateMemStorage(STORAGE_SIZE); + Mat image = _image.getMat(); + CvMat c_image = image; + CvSeq* seq = cvHoughLines2( &c_image, storage, CV_HOUGH_PROBABILISTIC, + rho, theta, threshold, minLineLength, maxGap ); + seqToMat(seq, _lines); +} + +void cv::HoughCircles( InputArray _image, OutputArray _circles, + int method, double dp, double min_dist, + double param1, double param2, + int minRadius, int maxRadius ) +{ + Ptr storage = cvCreateMemStorage(STORAGE_SIZE); + Mat image = _image.getMat(); + CvMat c_image = image; + CvSeq* seq = cvHoughCircles( &c_image, storage, method, + dp, min_dist, param1, param2, minRadius, maxRadius ); + seqToMat(seq, _circles); +} + +/* End of file. */ diff --git a/imgproc/src/imgwarp.cpp b/imgproc/src/imgwarp.cpp new file mode 100644 index 0000000..cbe9e29 --- /dev/null +++ b/imgproc/src/imgwarp.cpp @@ -0,0 +1,4024 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +/* //////////////////////////////////////////////////////////////////// +// +// Geometrical transforms on images and matrices: rotation, zoom etc. +// +// */ + +#include "precomp.hpp" + +namespace cv +{ + +/************** interpolation formulas and tables ***************/ + +const int INTER_RESIZE_COEF_BITS=11; +const int INTER_RESIZE_COEF_SCALE=1 << INTER_RESIZE_COEF_BITS; + +const int INTER_REMAP_COEF_BITS=15; +const int INTER_REMAP_COEF_SCALE=1 << INTER_REMAP_COEF_BITS; + +static uchar NNDeltaTab_i[INTER_TAB_SIZE2][2]; + +static float BilinearTab_f[INTER_TAB_SIZE2][2][2]; +static short BilinearTab_i[INTER_TAB_SIZE2][2][2]; + +#if CV_SSE2 +static short BilinearTab_iC4_buf[INTER_TAB_SIZE2+2][2][8]; +static short (*BilinearTab_iC4)[2][8] = (short (*)[2][8])alignPtr(BilinearTab_iC4_buf, 16); +#endif + +static float BicubicTab_f[INTER_TAB_SIZE2][4][4]; +static short BicubicTab_i[INTER_TAB_SIZE2][4][4]; + +static float Lanczos4Tab_f[INTER_TAB_SIZE2][8][8]; +static short Lanczos4Tab_i[INTER_TAB_SIZE2][8][8]; + +static inline void interpolateLinear( float x, float* coeffs ) +{ + coeffs[0] = 1.f - x; + coeffs[1] = x; +} + +static inline void interpolateCubic( float x, float* coeffs ) +{ + const float A = -0.75f; + + coeffs[0] = ((A*(x + 1) - 5*A)*(x + 1) + 8*A)*(x + 1) - 4*A; + coeffs[1] = ((A + 2)*x - (A + 3))*x*x + 1; + coeffs[2] = ((A + 2)*(1 - x) - (A + 3))*(1 - x)*(1 - x) + 1; + coeffs[3] = 1.f - coeffs[0] - coeffs[1] - coeffs[2]; +} + +static inline void interpolateLanczos4( float x, float* coeffs ) +{ + static const double s45 = 0.70710678118654752440084436210485; + static const double cs[][2]= + {{1, 0}, {-s45, -s45}, {0, 1}, {s45, -s45}, {-1, 0}, {s45, s45}, {0, -1}, {-s45, s45}}; + + if( x < FLT_EPSILON ) + { + for( int i = 0; i < 8; i++ ) + coeffs[i] = 0; + coeffs[3] = 1; + return; + } + + float sum = 0; + double y0=-(x+3)*CV_PI*0.25, s0 = sin(y0), c0=cos(y0); + for(int i = 0; i < 8; i++ ) + { + double y = -(x+3-i)*CV_PI*0.25; + coeffs[i] = (float)((cs[i][0]*s0 + cs[i][1]*c0)/(y*y)); + sum += coeffs[i]; + } + + sum = 1.f/sum; + for(int i = 0; i < 8; i++ ) + coeffs[i] *= sum; +} + +static void initInterTab1D(int method, float* tab, int tabsz) +{ + float scale = 1.f/tabsz; + if( method == INTER_LINEAR ) + { + for( int i = 0; i < tabsz; i++, tab += 2 ) + interpolateLinear( i*scale, tab ); + } + else if( method == INTER_CUBIC ) + { + for( int i = 0; i < tabsz; i++, tab += 4 ) + interpolateCubic( i*scale, tab ); + } + else if( method == INTER_LANCZOS4 ) + { + for( int i = 0; i < tabsz; i++, tab += 8 ) + interpolateLanczos4( i*scale, tab ); + } + else + CV_Error( CV_StsBadArg, "Unknown interpolation method" ); +} + + +static const void* initInterTab2D( int method, bool fixpt ) +{ + static bool inittab[INTER_MAX+1] = {false}; + float* tab = 0; + short* itab = 0; + int ksize = 0; + if( method == INTER_LINEAR ) + tab = BilinearTab_f[0][0], itab = BilinearTab_i[0][0], ksize=2; + else if( method == INTER_CUBIC ) + tab = BicubicTab_f[0][0], itab = BicubicTab_i[0][0], ksize=4; + else if( method == INTER_LANCZOS4 ) + tab = Lanczos4Tab_f[0][0], itab = Lanczos4Tab_i[0][0], ksize=8; + else + CV_Error( CV_StsBadArg, "Unknown/unsupported interpolation type" ); + + if( !inittab[method] ) + { + AutoBuffer _tab(8*INTER_TAB_SIZE); + int i, j, k1, k2; + initInterTab1D(method, _tab, INTER_TAB_SIZE); + for( i = 0; i < INTER_TAB_SIZE; i++ ) + for( j = 0; j < INTER_TAB_SIZE; j++, tab += ksize*ksize, itab += ksize*ksize ) + { + int isum = 0; + NNDeltaTab_i[i*INTER_TAB_SIZE+j][0] = j < INTER_TAB_SIZE/2; + NNDeltaTab_i[i*INTER_TAB_SIZE+j][1] = i < INTER_TAB_SIZE/2; + + for( k1 = 0; k1 < ksize; k1++ ) + { + float vy = _tab[i*ksize + k1]; + for( k2 = 0; k2 < ksize; k2++ ) + { + float v = vy*_tab[j*ksize + k2]; + tab[k1*ksize + k2] = v; + isum += itab[k1*ksize + k2] = saturate_cast(v*INTER_REMAP_COEF_SCALE); + } + } + + if( isum != INTER_REMAP_COEF_SCALE ) + { + int diff = isum - INTER_REMAP_COEF_SCALE; + int ksize2 = ksize/2, Mk1=ksize2, Mk2=ksize2, mk1=ksize2, mk2=ksize2; + for( k1 = ksize2; k1 < ksize2+2; k1++ ) + for( k2 = ksize2; k2 < ksize2+2; k2++ ) + { + if( itab[k1*ksize+k2] < itab[mk1*ksize+mk2] ) + mk1 = k1, mk2 = k2; + else if( itab[k1*ksize+k2] > itab[Mk1*ksize+Mk2] ) + Mk1 = k1, Mk2 = k2; + } + if( diff < 0 ) + itab[Mk1*ksize + Mk2] = (short)(itab[Mk1*ksize + Mk2] - diff); + else + itab[mk1*ksize + mk2] = (short)(itab[mk1*ksize + mk2] - diff); + } + } + tab -= INTER_TAB_SIZE2*ksize*ksize; + itab -= INTER_TAB_SIZE2*ksize*ksize; +#if CV_SSE2 + if( method == INTER_LINEAR ) + { + for( i = 0; i < INTER_TAB_SIZE2; i++ ) + for( j = 0; j < 4; j++ ) + { + BilinearTab_iC4[i][0][j*2] = BilinearTab_i[i][0][0]; + BilinearTab_iC4[i][0][j*2+1] = BilinearTab_i[i][0][1]; + BilinearTab_iC4[i][1][j*2] = BilinearTab_i[i][1][0]; + BilinearTab_iC4[i][1][j*2+1] = BilinearTab_i[i][1][1]; + } + } +#endif + inittab[method] = true; + } + return fixpt ? (const void*)itab : (const void*)tab; +} + + +template struct Cast +{ + typedef ST type1; + typedef DT rtype; + + DT operator()(ST val) const { return saturate_cast
(val); } +}; + +template struct FixedPtCast +{ + typedef ST type1; + typedef DT rtype; + enum { SHIFT = bits, DELTA = 1 << (bits-1) }; + + DT operator()(ST val) const { return saturate_cast
((val + DELTA)>>SHIFT); } +}; + +/****************************************************************************************\ +* Resize * +\****************************************************************************************/ + +class resizeNNInvoker : + public ParallelLoopBody +{ +public: + resizeNNInvoker(const Mat& _src, Mat &_dst, int *_x_ofs, int _pix_size4, double _ify) : + ParallelLoopBody(), src(_src), dst(_dst), x_ofs(_x_ofs), pix_size4(_pix_size4), + ify(_ify) + { + } + + virtual void operator() (const Range& range) const + { + Size ssize = src.size(), dsize = dst.size(); + int y, x, pix_size = (int)src.elemSize(); + + for( y = range.start; y < range.end; y++ ) + { + uchar* D = dst.data + dst.step*y; + int sy = std::min(cvFloor(y*ify), ssize.height-1); + const uchar* S = src.data + src.step*sy; + + switch( pix_size ) + { + case 1: + for( x = 0; x <= dsize.width - 2; x += 2 ) + { + uchar t0 = S[x_ofs[x]]; + uchar t1 = S[x_ofs[x+1]]; + D[x] = t0; + D[x+1] = t1; + } + + for( ; x < dsize.width; x++ ) + D[x] = S[x_ofs[x]]; + break; + case 2: + for( x = 0; x < dsize.width; x++ ) + *(ushort*)(D + x*2) = *(ushort*)(S + x_ofs[x]); + break; + case 3: + for( x = 0; x < dsize.width; x++, D += 3 ) + { + const uchar* _tS = S + x_ofs[x]; + D[0] = _tS[0]; D[1] = _tS[1]; D[2] = _tS[2]; + } + break; + case 4: + for( x = 0; x < dsize.width; x++ ) + *(int*)(D + x*4) = *(int*)(S + x_ofs[x]); + break; + case 6: + for( x = 0; x < dsize.width; x++, D += 6 ) + { + const ushort* _tS = (const ushort*)(S + x_ofs[x]); + ushort* _tD = (ushort*)D; + _tD[0] = _tS[0]; _tD[1] = _tS[1]; _tD[2] = _tS[2]; + } + break; + case 8: + for( x = 0; x < dsize.width; x++, D += 8 ) + { + const int* _tS = (const int*)(S + x_ofs[x]); + int* _tD = (int*)D; + _tD[0] = _tS[0]; _tD[1] = _tS[1]; + } + break; + case 12: + for( x = 0; x < dsize.width; x++, D += 12 ) + { + const int* _tS = (const int*)(S + x_ofs[x]); + int* _tD = (int*)D; + _tD[0] = _tS[0]; _tD[1] = _tS[1]; _tD[2] = _tS[2]; + } + break; + default: + for( x = 0; x < dsize.width; x++, D += pix_size ) + { + const int* _tS = (const int*)(S + x_ofs[x]); + int* _tD = (int*)D; + for( int k = 0; k < pix_size4; k++ ) + _tD[k] = _tS[k]; + } + } + } + } + +private: + const Mat src; + Mat dst; + int* x_ofs, pix_size4; + double ify; + + resizeNNInvoker(const resizeNNInvoker&); + resizeNNInvoker& operator=(const resizeNNInvoker&); +}; + +static void +resizeNN( const Mat& src, Mat& dst, double fx, double fy ) +{ + Size ssize = src.size(), dsize = dst.size(); + AutoBuffer _x_ofs(dsize.width); + int* x_ofs = _x_ofs; + int pix_size = (int)src.elemSize(); + int pix_size4 = (int)(pix_size / sizeof(int)); + double ifx = 1./fx, ify = 1./fy; + int x; + + for( x = 0; x < dsize.width; x++ ) + { + int sx = cvFloor(x*ifx); + x_ofs[x] = std::min(sx, ssize.width-1)*pix_size; + } + + Range range(0, dsize.height); + resizeNNInvoker invoker(src, dst, x_ofs, pix_size4, ify); + parallel_for_(range, invoker); +} + + +struct VResizeNoVec +{ + int operator()(const uchar**, uchar*, const uchar*, int ) const { return 0; } +}; + +struct HResizeNoVec +{ + int operator()(const uchar**, uchar**, int, const int*, + const uchar*, int, int, int, int, int) const { return 0; } +}; + +#if CV_SSE2 + +struct VResizeLinearVec_32s8u +{ + int operator()(const uchar** _src, uchar* dst, const uchar* _beta, int width ) const + { + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + const int** src = (const int**)_src; + const short* beta = (const short*)_beta; + const int *S0 = src[0], *S1 = src[1]; + int x = 0; + __m128i b0 = _mm_set1_epi16(beta[0]), b1 = _mm_set1_epi16(beta[1]); + __m128i delta = _mm_set1_epi16(2); + + if( (((size_t)S0|(size_t)S1)&15) == 0 ) + for( ; x <= width - 16; x += 16 ) + { + __m128i x0, x1, x2, y0, y1, y2; + x0 = _mm_load_si128((const __m128i*)(S0 + x)); + x1 = _mm_load_si128((const __m128i*)(S0 + x + 4)); + y0 = _mm_load_si128((const __m128i*)(S1 + x)); + y1 = _mm_load_si128((const __m128i*)(S1 + x + 4)); + x0 = _mm_packs_epi32(_mm_srai_epi32(x0, 4), _mm_srai_epi32(x1, 4)); + y0 = _mm_packs_epi32(_mm_srai_epi32(y0, 4), _mm_srai_epi32(y1, 4)); + + x1 = _mm_load_si128((const __m128i*)(S0 + x + 8)); + x2 = _mm_load_si128((const __m128i*)(S0 + x + 12)); + y1 = _mm_load_si128((const __m128i*)(S1 + x + 8)); + y2 = _mm_load_si128((const __m128i*)(S1 + x + 12)); + x1 = _mm_packs_epi32(_mm_srai_epi32(x1, 4), _mm_srai_epi32(x2, 4)); + y1 = _mm_packs_epi32(_mm_srai_epi32(y1, 4), _mm_srai_epi32(y2, 4)); + + x0 = _mm_adds_epi16(_mm_mulhi_epi16( x0, b0 ), _mm_mulhi_epi16( y0, b1 )); + x1 = _mm_adds_epi16(_mm_mulhi_epi16( x1, b0 ), _mm_mulhi_epi16( y1, b1 )); + + x0 = _mm_srai_epi16(_mm_adds_epi16(x0, delta), 2); + x1 = _mm_srai_epi16(_mm_adds_epi16(x1, delta), 2); + _mm_storeu_si128( (__m128i*)(dst + x), _mm_packus_epi16(x0, x1)); + } + else + for( ; x <= width - 16; x += 16 ) + { + __m128i x0, x1, x2, y0, y1, y2; + x0 = _mm_loadu_si128((const __m128i*)(S0 + x)); + x1 = _mm_loadu_si128((const __m128i*)(S0 + x + 4)); + y0 = _mm_loadu_si128((const __m128i*)(S1 + x)); + y1 = _mm_loadu_si128((const __m128i*)(S1 + x + 4)); + x0 = _mm_packs_epi32(_mm_srai_epi32(x0, 4), _mm_srai_epi32(x1, 4)); + y0 = _mm_packs_epi32(_mm_srai_epi32(y0, 4), _mm_srai_epi32(y1, 4)); + + x1 = _mm_loadu_si128((const __m128i*)(S0 + x + 8)); + x2 = _mm_loadu_si128((const __m128i*)(S0 + x + 12)); + y1 = _mm_loadu_si128((const __m128i*)(S1 + x + 8)); + y2 = _mm_loadu_si128((const __m128i*)(S1 + x + 12)); + x1 = _mm_packs_epi32(_mm_srai_epi32(x1, 4), _mm_srai_epi32(x2, 4)); + y1 = _mm_packs_epi32(_mm_srai_epi32(y1, 4), _mm_srai_epi32(y2, 4)); + + x0 = _mm_adds_epi16(_mm_mulhi_epi16( x0, b0 ), _mm_mulhi_epi16( y0, b1 )); + x1 = _mm_adds_epi16(_mm_mulhi_epi16( x1, b0 ), _mm_mulhi_epi16( y1, b1 )); + + x0 = _mm_srai_epi16(_mm_adds_epi16(x0, delta), 2); + x1 = _mm_srai_epi16(_mm_adds_epi16(x1, delta), 2); + _mm_storeu_si128( (__m128i*)(dst + x), _mm_packus_epi16(x0, x1)); + } + + for( ; x < width - 4; x += 4 ) + { + __m128i x0, y0; + x0 = _mm_srai_epi32(_mm_loadu_si128((const __m128i*)(S0 + x)), 4); + y0 = _mm_srai_epi32(_mm_loadu_si128((const __m128i*)(S1 + x)), 4); + x0 = _mm_packs_epi32(x0, x0); + y0 = _mm_packs_epi32(y0, y0); + x0 = _mm_adds_epi16(_mm_mulhi_epi16(x0, b0), _mm_mulhi_epi16(y0, b1)); + x0 = _mm_srai_epi16(_mm_adds_epi16(x0, delta), 2); + x0 = _mm_packus_epi16(x0, x0); + *(int*)(dst + x) = _mm_cvtsi128_si32(x0); + } + + return x; + } +}; + + +template struct VResizeLinearVec_32f16 +{ + int operator()(const uchar** _src, uchar* _dst, const uchar* _beta, int width ) const + { + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + const float** src = (const float**)_src; + const float* beta = (const float*)_beta; + const float *S0 = src[0], *S1 = src[1]; + ushort* dst = (ushort*)_dst; + int x = 0; + + __m128 b0 = _mm_set1_ps(beta[0]), b1 = _mm_set1_ps(beta[1]); + __m128i preshift = _mm_set1_epi32(shiftval); + __m128i postshift = _mm_set1_epi16((short)shiftval); + + if( (((size_t)S0|(size_t)S1)&15) == 0 ) + for( ; x <= width - 16; x += 16 ) + { + __m128 x0, x1, y0, y1; + __m128i t0, t1, t2; + x0 = _mm_load_ps(S0 + x); + x1 = _mm_load_ps(S0 + x + 4); + y0 = _mm_load_ps(S1 + x); + y1 = _mm_load_ps(S1 + x + 4); + + x0 = _mm_add_ps(_mm_mul_ps(x0, b0), _mm_mul_ps(y0, b1)); + x1 = _mm_add_ps(_mm_mul_ps(x1, b0), _mm_mul_ps(y1, b1)); + t0 = _mm_add_epi32(_mm_cvtps_epi32(x0), preshift); + t2 = _mm_add_epi32(_mm_cvtps_epi32(x1), preshift); + t0 = _mm_add_epi16(_mm_packs_epi32(t0, t2), postshift); + + x0 = _mm_load_ps(S0 + x + 8); + x1 = _mm_load_ps(S0 + x + 12); + y0 = _mm_load_ps(S1 + x + 8); + y1 = _mm_load_ps(S1 + x + 12); + + x0 = _mm_add_ps(_mm_mul_ps(x0, b0), _mm_mul_ps(y0, b1)); + x1 = _mm_add_ps(_mm_mul_ps(x1, b0), _mm_mul_ps(y1, b1)); + t1 = _mm_add_epi32(_mm_cvtps_epi32(x0), preshift); + t2 = _mm_add_epi32(_mm_cvtps_epi32(x1), preshift); + t1 = _mm_add_epi16(_mm_packs_epi32(t1, t2), postshift); + + _mm_storeu_si128( (__m128i*)(dst + x), t0); + _mm_storeu_si128( (__m128i*)(dst + x + 8), t1); + } + else + for( ; x <= width - 16; x += 16 ) + { + __m128 x0, x1, y0, y1; + __m128i t0, t1, t2; + x0 = _mm_loadu_ps(S0 + x); + x1 = _mm_loadu_ps(S0 + x + 4); + y0 = _mm_loadu_ps(S1 + x); + y1 = _mm_loadu_ps(S1 + x + 4); + + x0 = _mm_add_ps(_mm_mul_ps(x0, b0), _mm_mul_ps(y0, b1)); + x1 = _mm_add_ps(_mm_mul_ps(x1, b0), _mm_mul_ps(y1, b1)); + t0 = _mm_add_epi32(_mm_cvtps_epi32(x0), preshift); + t2 = _mm_add_epi32(_mm_cvtps_epi32(x1), preshift); + t0 = _mm_add_epi16(_mm_packs_epi32(t0, t2), postshift); + + x0 = _mm_loadu_ps(S0 + x + 8); + x1 = _mm_loadu_ps(S0 + x + 12); + y0 = _mm_loadu_ps(S1 + x + 8); + y1 = _mm_loadu_ps(S1 + x + 12); + + x0 = _mm_add_ps(_mm_mul_ps(x0, b0), _mm_mul_ps(y0, b1)); + x1 = _mm_add_ps(_mm_mul_ps(x1, b0), _mm_mul_ps(y1, b1)); + t1 = _mm_add_epi32(_mm_cvtps_epi32(x0), preshift); + t2 = _mm_add_epi32(_mm_cvtps_epi32(x1), preshift); + t1 = _mm_add_epi16(_mm_packs_epi32(t1, t2), postshift); + + _mm_storeu_si128( (__m128i*)(dst + x), t0); + _mm_storeu_si128( (__m128i*)(dst + x + 8), t1); + } + + for( ; x < width - 4; x += 4 ) + { + __m128 x0, y0; + __m128i t0; + x0 = _mm_loadu_ps(S0 + x); + y0 = _mm_loadu_ps(S1 + x); + + x0 = _mm_add_ps(_mm_mul_ps(x0, b0), _mm_mul_ps(y0, b1)); + t0 = _mm_add_epi32(_mm_cvtps_epi32(x0), preshift); + t0 = _mm_add_epi16(_mm_packs_epi32(t0, t0), postshift); + _mm_storel_epi64( (__m128i*)(dst + x), t0); + } + + return x; + } +}; + +typedef VResizeLinearVec_32f16 VResizeLinearVec_32f16u; +typedef VResizeLinearVec_32f16<0> VResizeLinearVec_32f16s; + +struct VResizeLinearVec_32f +{ + int operator()(const uchar** _src, uchar* _dst, const uchar* _beta, int width ) const + { + if( !checkHardwareSupport(CV_CPU_SSE) ) + return 0; + + const float** src = (const float**)_src; + const float* beta = (const float*)_beta; + const float *S0 = src[0], *S1 = src[1]; + float* dst = (float*)_dst; + int x = 0; + + __m128 b0 = _mm_set1_ps(beta[0]), b1 = _mm_set1_ps(beta[1]); + + if( (((size_t)S0|(size_t)S1)&15) == 0 ) + for( ; x <= width - 8; x += 8 ) + { + __m128 x0, x1, y0, y1; + x0 = _mm_load_ps(S0 + x); + x1 = _mm_load_ps(S0 + x + 4); + y0 = _mm_load_ps(S1 + x); + y1 = _mm_load_ps(S1 + x + 4); + + x0 = _mm_add_ps(_mm_mul_ps(x0, b0), _mm_mul_ps(y0, b1)); + x1 = _mm_add_ps(_mm_mul_ps(x1, b0), _mm_mul_ps(y1, b1)); + + _mm_storeu_ps( dst + x, x0); + _mm_storeu_ps( dst + x + 4, x1); + } + else + for( ; x <= width - 8; x += 8 ) + { + __m128 x0, x1, y0, y1; + x0 = _mm_loadu_ps(S0 + x); + x1 = _mm_loadu_ps(S0 + x + 4); + y0 = _mm_loadu_ps(S1 + x); + y1 = _mm_loadu_ps(S1 + x + 4); + + x0 = _mm_add_ps(_mm_mul_ps(x0, b0), _mm_mul_ps(y0, b1)); + x1 = _mm_add_ps(_mm_mul_ps(x1, b0), _mm_mul_ps(y1, b1)); + + _mm_storeu_ps( dst + x, x0); + _mm_storeu_ps( dst + x + 4, x1); + } + + return x; + } +}; + + +struct VResizeCubicVec_32s8u +{ + int operator()(const uchar** _src, uchar* dst, const uchar* _beta, int width ) const + { + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + const int** src = (const int**)_src; + const short* beta = (const short*)_beta; + const int *S0 = src[0], *S1 = src[1], *S2 = src[2], *S3 = src[3]; + int x = 0; + float scale = 1.f/(INTER_RESIZE_COEF_SCALE*INTER_RESIZE_COEF_SCALE); + __m128 b0 = _mm_set1_ps(beta[0]*scale), b1 = _mm_set1_ps(beta[1]*scale), + b2 = _mm_set1_ps(beta[2]*scale), b3 = _mm_set1_ps(beta[3]*scale); + + if( (((size_t)S0|(size_t)S1|(size_t)S2|(size_t)S3)&15) == 0 ) + for( ; x <= width - 8; x += 8 ) + { + __m128i x0, x1, y0, y1; + __m128 s0, s1, f0, f1; + x0 = _mm_load_si128((const __m128i*)(S0 + x)); + x1 = _mm_load_si128((const __m128i*)(S0 + x + 4)); + y0 = _mm_load_si128((const __m128i*)(S1 + x)); + y1 = _mm_load_si128((const __m128i*)(S1 + x + 4)); + + s0 = _mm_mul_ps(_mm_cvtepi32_ps(x0), b0); + s1 = _mm_mul_ps(_mm_cvtepi32_ps(x1), b0); + f0 = _mm_mul_ps(_mm_cvtepi32_ps(y0), b1); + f1 = _mm_mul_ps(_mm_cvtepi32_ps(y1), b1); + s0 = _mm_add_ps(s0, f0); + s1 = _mm_add_ps(s1, f1); + + x0 = _mm_load_si128((const __m128i*)(S2 + x)); + x1 = _mm_load_si128((const __m128i*)(S2 + x + 4)); + y0 = _mm_load_si128((const __m128i*)(S3 + x)); + y1 = _mm_load_si128((const __m128i*)(S3 + x + 4)); + + f0 = _mm_mul_ps(_mm_cvtepi32_ps(x0), b2); + f1 = _mm_mul_ps(_mm_cvtepi32_ps(x1), b2); + s0 = _mm_add_ps(s0, f0); + s1 = _mm_add_ps(s1, f1); + f0 = _mm_mul_ps(_mm_cvtepi32_ps(y0), b3); + f1 = _mm_mul_ps(_mm_cvtepi32_ps(y1), b3); + s0 = _mm_add_ps(s0, f0); + s1 = _mm_add_ps(s1, f1); + + x0 = _mm_cvtps_epi32(s0); + x1 = _mm_cvtps_epi32(s1); + + x0 = _mm_packs_epi32(x0, x1); + _mm_storel_epi64( (__m128i*)(dst + x), _mm_packus_epi16(x0, x0)); + } + else + for( ; x <= width - 8; x += 8 ) + { + __m128i x0, x1, y0, y1; + __m128 s0, s1, f0, f1; + x0 = _mm_loadu_si128((const __m128i*)(S0 + x)); + x1 = _mm_loadu_si128((const __m128i*)(S0 + x + 4)); + y0 = _mm_loadu_si128((const __m128i*)(S1 + x)); + y1 = _mm_loadu_si128((const __m128i*)(S1 + x + 4)); + + s0 = _mm_mul_ps(_mm_cvtepi32_ps(x0), b0); + s1 = _mm_mul_ps(_mm_cvtepi32_ps(x1), b0); + f0 = _mm_mul_ps(_mm_cvtepi32_ps(y0), b1); + f1 = _mm_mul_ps(_mm_cvtepi32_ps(y1), b1); + s0 = _mm_add_ps(s0, f0); + s1 = _mm_add_ps(s1, f1); + + x0 = _mm_loadu_si128((const __m128i*)(S2 + x)); + x1 = _mm_loadu_si128((const __m128i*)(S2 + x + 4)); + y0 = _mm_loadu_si128((const __m128i*)(S3 + x)); + y1 = _mm_loadu_si128((const __m128i*)(S3 + x + 4)); + + f0 = _mm_mul_ps(_mm_cvtepi32_ps(x0), b2); + f1 = _mm_mul_ps(_mm_cvtepi32_ps(x1), b2); + s0 = _mm_add_ps(s0, f0); + s1 = _mm_add_ps(s1, f1); + f0 = _mm_mul_ps(_mm_cvtepi32_ps(y0), b3); + f1 = _mm_mul_ps(_mm_cvtepi32_ps(y1), b3); + s0 = _mm_add_ps(s0, f0); + s1 = _mm_add_ps(s1, f1); + + x0 = _mm_cvtps_epi32(s0); + x1 = _mm_cvtps_epi32(s1); + + x0 = _mm_packs_epi32(x0, x1); + _mm_storel_epi64( (__m128i*)(dst + x), _mm_packus_epi16(x0, x0)); + } + + return x; + } +}; + + +template struct VResizeCubicVec_32f16 +{ + int operator()(const uchar** _src, uchar* _dst, const uchar* _beta, int width ) const + { + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + const float** src = (const float**)_src; + const float* beta = (const float*)_beta; + const float *S0 = src[0], *S1 = src[1], *S2 = src[2], *S3 = src[3]; + ushort* dst = (ushort*)_dst; + int x = 0; + __m128 b0 = _mm_set1_ps(beta[0]), b1 = _mm_set1_ps(beta[1]), + b2 = _mm_set1_ps(beta[2]), b3 = _mm_set1_ps(beta[3]); + __m128i preshift = _mm_set1_epi32(shiftval); + __m128i postshift = _mm_set1_epi16((short)shiftval); + + for( ; x <= width - 8; x += 8 ) + { + __m128 x0, x1, y0, y1, s0, s1; + __m128i t0, t1; + x0 = _mm_loadu_ps(S0 + x); + x1 = _mm_loadu_ps(S0 + x + 4); + y0 = _mm_loadu_ps(S1 + x); + y1 = _mm_loadu_ps(S1 + x + 4); + + s0 = _mm_mul_ps(x0, b0); + s1 = _mm_mul_ps(x1, b0); + y0 = _mm_mul_ps(y0, b1); + y1 = _mm_mul_ps(y1, b1); + s0 = _mm_add_ps(s0, y0); + s1 = _mm_add_ps(s1, y1); + + x0 = _mm_loadu_ps(S2 + x); + x1 = _mm_loadu_ps(S2 + x + 4); + y0 = _mm_loadu_ps(S3 + x); + y1 = _mm_loadu_ps(S3 + x + 4); + + x0 = _mm_mul_ps(x0, b2); + x1 = _mm_mul_ps(x1, b2); + y0 = _mm_mul_ps(y0, b3); + y1 = _mm_mul_ps(y1, b3); + s0 = _mm_add_ps(s0, x0); + s1 = _mm_add_ps(s1, x1); + s0 = _mm_add_ps(s0, y0); + s1 = _mm_add_ps(s1, y1); + + t0 = _mm_add_epi32(_mm_cvtps_epi32(s0), preshift); + t1 = _mm_add_epi32(_mm_cvtps_epi32(s1), preshift); + + t0 = _mm_add_epi16(_mm_packs_epi32(t0, t1), postshift); + _mm_storeu_si128( (__m128i*)(dst + x), t0); + } + + return x; + } +}; + +typedef VResizeCubicVec_32f16 VResizeCubicVec_32f16u; +typedef VResizeCubicVec_32f16<0> VResizeCubicVec_32f16s; + +struct VResizeCubicVec_32f +{ + int operator()(const uchar** _src, uchar* _dst, const uchar* _beta, int width ) const + { + if( !checkHardwareSupport(CV_CPU_SSE) ) + return 0; + + const float** src = (const float**)_src; + const float* beta = (const float*)_beta; + const float *S0 = src[0], *S1 = src[1], *S2 = src[2], *S3 = src[3]; + float* dst = (float*)_dst; + int x = 0; + __m128 b0 = _mm_set1_ps(beta[0]), b1 = _mm_set1_ps(beta[1]), + b2 = _mm_set1_ps(beta[2]), b3 = _mm_set1_ps(beta[3]); + + for( ; x <= width - 8; x += 8 ) + { + __m128 x0, x1, y0, y1, s0, s1; + x0 = _mm_loadu_ps(S0 + x); + x1 = _mm_loadu_ps(S0 + x + 4); + y0 = _mm_loadu_ps(S1 + x); + y1 = _mm_loadu_ps(S1 + x + 4); + + s0 = _mm_mul_ps(x0, b0); + s1 = _mm_mul_ps(x1, b0); + y0 = _mm_mul_ps(y0, b1); + y1 = _mm_mul_ps(y1, b1); + s0 = _mm_add_ps(s0, y0); + s1 = _mm_add_ps(s1, y1); + + x0 = _mm_loadu_ps(S2 + x); + x1 = _mm_loadu_ps(S2 + x + 4); + y0 = _mm_loadu_ps(S3 + x); + y1 = _mm_loadu_ps(S3 + x + 4); + + x0 = _mm_mul_ps(x0, b2); + x1 = _mm_mul_ps(x1, b2); + y0 = _mm_mul_ps(y0, b3); + y1 = _mm_mul_ps(y1, b3); + s0 = _mm_add_ps(s0, x0); + s1 = _mm_add_ps(s1, x1); + s0 = _mm_add_ps(s0, y0); + s1 = _mm_add_ps(s1, y1); + + _mm_storeu_ps( dst + x, s0); + _mm_storeu_ps( dst + x + 4, s1); + } + + return x; + } +}; + +#else + +typedef VResizeNoVec VResizeLinearVec_32s8u; +typedef VResizeNoVec VResizeLinearVec_32f16u; +typedef VResizeNoVec VResizeLinearVec_32f16s; +typedef VResizeNoVec VResizeLinearVec_32f; + +typedef VResizeNoVec VResizeCubicVec_32s8u; +typedef VResizeNoVec VResizeCubicVec_32f16u; +typedef VResizeNoVec VResizeCubicVec_32f16s; +typedef VResizeNoVec VResizeCubicVec_32f; + +#endif + +typedef HResizeNoVec HResizeLinearVec_8u32s; +typedef HResizeNoVec HResizeLinearVec_16u32f; +typedef HResizeNoVec HResizeLinearVec_16s32f; +typedef HResizeNoVec HResizeLinearVec_32f; +typedef HResizeNoVec HResizeLinearVec_64f; + + +template +struct HResizeLinear +{ + typedef T value_type; + typedef WT buf_type; + typedef AT alpha_type; + + void operator()(const T** src, WT** dst, int count, + const int* xofs, const AT* alpha, + int swidth, int dwidth, int cn, int xmin, int xmax ) const + { + int dx, k; + VecOp vecOp; + + int dx0 = vecOp((const uchar**)src, (uchar**)dst, count, + xofs, (const uchar*)alpha, swidth, dwidth, cn, xmin, xmax ); + + for( k = 0; k <= count - 2; k++ ) + { + const T *S0 = src[k], *S1 = src[k+1]; + WT *D0 = dst[k], *D1 = dst[k+1]; + for( dx = dx0; dx < xmax; dx++ ) + { + int sx = xofs[dx]; + WT a0 = alpha[dx*2], a1 = alpha[dx*2+1]; + WT t0 = S0[sx]*a0 + S0[sx + cn]*a1; + WT t1 = S1[sx]*a0 + S1[sx + cn]*a1; + D0[dx] = t0; D1[dx] = t1; + } + + for( ; dx < dwidth; dx++ ) + { + int sx = xofs[dx]; + D0[dx] = WT(S0[sx]*ONE); D1[dx] = WT(S1[sx]*ONE); + } + } + + for( ; k < count; k++ ) + { + const T *S = src[k]; + WT *D = dst[k]; + for( dx = 0; dx < xmax; dx++ ) + { + int sx = xofs[dx]; + D[dx] = S[sx]*alpha[dx*2] + S[sx+cn]*alpha[dx*2+1]; + } + + for( ; dx < dwidth; dx++ ) + D[dx] = WT(S[xofs[dx]]*ONE); + } + } +}; + + +template +struct VResizeLinear +{ + typedef T value_type; + typedef WT buf_type; + typedef AT alpha_type; + + void operator()(const WT** src, T* dst, const AT* beta, int width ) const + { + WT b0 = beta[0], b1 = beta[1]; + const WT *S0 = src[0], *S1 = src[1]; + CastOp castOp; + VecOp vecOp; + + int x = vecOp((const uchar**)src, (uchar*)dst, (const uchar*)beta, width); + #if CV_ENABLE_UNROLLED + for( ; x <= width - 4; x += 4 ) + { + WT t0, t1; + t0 = S0[x]*b0 + S1[x]*b1; + t1 = S0[x+1]*b0 + S1[x+1]*b1; + dst[x] = castOp(t0); dst[x+1] = castOp(t1); + t0 = S0[x+2]*b0 + S1[x+2]*b1; + t1 = S0[x+3]*b0 + S1[x+3]*b1; + dst[x+2] = castOp(t0); dst[x+3] = castOp(t1); + } + #endif + for( ; x < width; x++ ) + dst[x] = castOp(S0[x]*b0 + S1[x]*b1); + } +}; + +template<> +struct VResizeLinear, VResizeLinearVec_32s8u> +{ + typedef uchar value_type; + typedef int buf_type; + typedef short alpha_type; + + void operator()(const buf_type** src, value_type* dst, const alpha_type* beta, int width ) const + { + alpha_type b0 = beta[0], b1 = beta[1]; + const buf_type *S0 = src[0], *S1 = src[1]; + VResizeLinearVec_32s8u vecOp; + + int x = vecOp((const uchar**)src, (uchar*)dst, (const uchar*)beta, width); + #if CV_ENABLE_UNROLLED + for( ; x <= width - 4; x += 4 ) + { + dst[x+0] = uchar(( ((b0 * (S0[x+0] >> 4)) >> 16) + ((b1 * (S1[x+0] >> 4)) >> 16) + 2)>>2); + dst[x+1] = uchar(( ((b0 * (S0[x+1] >> 4)) >> 16) + ((b1 * (S1[x+1] >> 4)) >> 16) + 2)>>2); + dst[x+2] = uchar(( ((b0 * (S0[x+2] >> 4)) >> 16) + ((b1 * (S1[x+2] >> 4)) >> 16) + 2)>>2); + dst[x+3] = uchar(( ((b0 * (S0[x+3] >> 4)) >> 16) + ((b1 * (S1[x+3] >> 4)) >> 16) + 2)>>2); + } + #endif + for( ; x < width; x++ ) + dst[x] = uchar(( ((b0 * (S0[x] >> 4)) >> 16) + ((b1 * (S1[x] >> 4)) >> 16) + 2)>>2); + } +}; + + +template +struct HResizeCubic +{ + typedef T value_type; + typedef WT buf_type; + typedef AT alpha_type; + + void operator()(const T** src, WT** dst, int count, + const int* xofs, const AT* alpha, + int swidth, int dwidth, int cn, int xmin, int xmax ) const + { + for( int k = 0; k < count; k++ ) + { + const T *S = src[k]; + WT *D = dst[k]; + int dx = 0, limit = xmin; + for(;;) + { + for( ; dx < limit; dx++, alpha += 4 ) + { + int j, sx = xofs[dx] - cn; + WT v = 0; + for( j = 0; j < 4; j++ ) + { + int sxj = sx + j*cn; + if( (unsigned)sxj >= (unsigned)swidth ) + { + while( sxj < 0 ) + sxj += cn; + while( sxj >= swidth ) + sxj -= cn; + } + v += S[sxj]*alpha[j]; + } + D[dx] = v; + } + if( limit == dwidth ) + break; + for( ; dx < xmax; dx++, alpha += 4 ) + { + int sx = xofs[dx]; + D[dx] = S[sx-cn]*alpha[0] + S[sx]*alpha[1] + + S[sx+cn]*alpha[2] + S[sx+cn*2]*alpha[3]; + } + limit = dwidth; + } + alpha -= dwidth*4; + } + } +}; + + +template +struct VResizeCubic +{ + typedef T value_type; + typedef WT buf_type; + typedef AT alpha_type; + + void operator()(const WT** src, T* dst, const AT* beta, int width ) const + { + WT b0 = beta[0], b1 = beta[1], b2 = beta[2], b3 = beta[3]; + const WT *S0 = src[0], *S1 = src[1], *S2 = src[2], *S3 = src[3]; + CastOp castOp; + VecOp vecOp; + + int x = vecOp((const uchar**)src, (uchar*)dst, (const uchar*)beta, width); + for( ; x < width; x++ ) + dst[x] = castOp(S0[x]*b0 + S1[x]*b1 + S2[x]*b2 + S3[x]*b3); + } +}; + + +template +struct HResizeLanczos4 +{ + typedef T value_type; + typedef WT buf_type; + typedef AT alpha_type; + + void operator()(const T** src, WT** dst, int count, + const int* xofs, const AT* alpha, + int swidth, int dwidth, int cn, int xmin, int xmax ) const + { + for( int k = 0; k < count; k++ ) + { + const T *S = src[k]; + WT *D = dst[k]; + int dx = 0, limit = xmin; + for(;;) + { + for( ; dx < limit; dx++, alpha += 8 ) + { + int j, sx = xofs[dx] - cn*3; + WT v = 0; + for( j = 0; j < 8; j++ ) + { + int sxj = sx + j*cn; + if( (unsigned)sxj >= (unsigned)swidth ) + { + while( sxj < 0 ) + sxj += cn; + while( sxj >= swidth ) + sxj -= cn; + } + v += S[sxj]*alpha[j]; + } + D[dx] = v; + } + if( limit == dwidth ) + break; + for( ; dx < xmax; dx++, alpha += 8 ) + { + int sx = xofs[dx]; + D[dx] = S[sx-cn*3]*alpha[0] + S[sx-cn*2]*alpha[1] + + S[sx-cn]*alpha[2] + S[sx]*alpha[3] + + S[sx+cn]*alpha[4] + S[sx+cn*2]*alpha[5] + + S[sx+cn*3]*alpha[6] + S[sx+cn*4]*alpha[7]; + } + limit = dwidth; + } + alpha -= dwidth*8; + } + } +}; + + +template +struct VResizeLanczos4 +{ + typedef T value_type; + typedef WT buf_type; + typedef AT alpha_type; + + void operator()(const WT** src, T* dst, const AT* beta, int width ) const + { + CastOp castOp; + VecOp vecOp; + int k, x = vecOp((const uchar**)src, (uchar*)dst, (const uchar*)beta, width); + #if CV_ENABLE_UNROLLED + for( ; x <= width - 4; x += 4 ) + { + WT b = beta[0]; + const WT* S = src[0]; + WT s0 = S[x]*b, s1 = S[x+1]*b, s2 = S[x+2]*b, s3 = S[x+3]*b; + + for( k = 1; k < 8; k++ ) + { + b = beta[k]; S = src[k]; + s0 += S[x]*b; s1 += S[x+1]*b; + s2 += S[x+2]*b; s3 += S[x+3]*b; + } + + dst[x] = castOp(s0); dst[x+1] = castOp(s1); + dst[x+2] = castOp(s2); dst[x+3] = castOp(s3); + } + #endif + for( ; x < width; x++ ) + { + dst[x] = castOp(src[0][x]*beta[0] + src[1][x]*beta[1] + + src[2][x]*beta[2] + src[3][x]*beta[3] + src[4][x]*beta[4] + + src[5][x]*beta[5] + src[6][x]*beta[6] + src[7][x]*beta[7]); + } + } +}; + + +static inline int clip(int x, int a, int b) +{ + return x >= a ? (x < b ? x : b-1) : a; +} + +static const int MAX_ESIZE=16; + +template +class resizeGeneric_Invoker : + public ParallelLoopBody +{ +public: + typedef typename HResize::value_type T; + typedef typename HResize::buf_type WT; + typedef typename HResize::alpha_type AT; + + resizeGeneric_Invoker(const Mat& _src, Mat &_dst, const int *_xofs, const int *_yofs, + const AT* _alpha, const AT* __beta, const Size& _ssize, const Size &_dsize, + int _ksize, int _xmin, int _xmax) : + ParallelLoopBody(), src(_src), dst(_dst), xofs(_xofs), yofs(_yofs), + alpha(_alpha), _beta(__beta), ssize(_ssize), dsize(_dsize), + ksize(_ksize), xmin(_xmin), xmax(_xmax) + { + } + + virtual void operator() (const Range& range) const + { + int dy, cn = src.channels(); + HResize hresize; + VResize vresize; + + int bufstep = (int)alignSize(dsize.width, 16); + AutoBuffer _buffer(bufstep*ksize); + const T* srows[MAX_ESIZE]={0}; + WT* rows[MAX_ESIZE]={0}; + int prev_sy[MAX_ESIZE]; + + for(int k = 0; k < ksize; k++ ) + { + prev_sy[k] = -1; + rows[k] = (WT*)_buffer + bufstep*k; + } + + const AT* beta = _beta + ksize * range.start; + + for( dy = range.start; dy < range.end; dy++, beta += ksize ) + { + int sy0 = yofs[dy], k0=ksize, k1=0, ksize2 = ksize/2; + + for(int k = 0; k < ksize; k++ ) + { + int sy = clip(sy0 - ksize2 + 1 + k, 0, ssize.height); + for( k1 = std::max(k1, k); k1 < ksize; k1++ ) + { + if( sy == prev_sy[k1] ) // if the sy-th row has been computed already, reuse it. + { + if( k1 > k ) + memcpy( rows[k], rows[k1], bufstep*sizeof(rows[0][0]) ); + break; + } + } + if( k1 == ksize ) + k0 = std::min(k0, k); // remember the first row that needs to be computed + srows[k] = (T*)(src.data + src.step*sy); + prev_sy[k] = sy; + } + + if( k0 < ksize ) + hresize( (const T**)(srows + k0), (WT**)(rows + k0), ksize - k0, xofs, (const AT*)(alpha), + ssize.width, dsize.width, cn, xmin, xmax ); + vresize( (const WT**)rows, (T*)(dst.data + dst.step*dy), beta, dsize.width ); + } + } + +private: + const Mat src; + Mat dst; + const int* xofs, *yofs; + const AT* alpha, *_beta; + const Size ssize, dsize; + const int ksize, xmin, xmax; + + resizeGeneric_Invoker(const resizeGeneric_Invoker&); + resizeGeneric_Invoker& operator=(const resizeGeneric_Invoker&); +}; + +template +static void resizeGeneric_( const Mat& src, Mat& dst, + const int* xofs, const void* _alpha, + const int* yofs, const void* _beta, + int xmin, int xmax, int ksize ) +{ + typedef typename HResize::value_type T; + typedef typename HResize::buf_type WT; + typedef typename HResize::alpha_type AT; + + const AT* beta = (const AT*)_beta; + Size ssize = src.size(), dsize = dst.size(); + int cn = src.channels(); + ssize.width *= cn; + dsize.width *= cn; + xmin *= cn; + xmax *= cn; + // image resize is a separable operation. In case of not too strong + + Range range(0, dsize.height); + resizeGeneric_Invoker invoker(src, dst, xofs, yofs, (const AT*)_alpha, beta, + ssize, dsize, ksize, xmin, xmax); + parallel_for_(range, invoker); +} + +template +struct ResizeAreaFastNoVec +{ + ResizeAreaFastNoVec(int /*_scale_x*/, int /*_scale_y*/, + int /*_cn*/, int /*_step*//*, const int**/ /*_ofs*/) { } + int operator() (const T* /*S*/, T* /*D*/, int /*w*/) const { return 0; } +}; + +template +struct ResizeAreaFast_2x2_8u +{ + ResizeAreaFast_2x2_8u(int _scale_x, int _scale_y, int _cn, int _step/*, const int* _ofs*/) : + scale_x(_scale_x), scale_y(_scale_y), cn(_cn), step(_step)/*, ofs(_ofs)*/ + { + fast_mode = scale_x == 2 && scale_y == 2 && (cn == 1 || cn == 3 || cn == 4); + } + + int operator() (const T* S, T* D, int w) const + { + if( !fast_mode ) + return 0; + + const T* nextS = S + step; + int dx = 0; + + if (cn == 1) + for( ; dx < w; ++dx ) + { + int index = dx*2; + D[dx] = (S[index] + S[index+1] + nextS[index] + nextS[index+1] + 2) >> 2; + } + else if (cn == 3) + for( ; dx < w; dx += 3 ) + { + int index = dx*2; + D[dx] = (S[index] + S[index+3] + nextS[index] + nextS[index+3] + 2) >> 2; + D[dx+1] = (S[index+1] + S[index+4] + nextS[index+1] + nextS[index+4] + 2) >> 2; + D[dx+2] = (S[index+2] + S[index+5] + nextS[index+2] + nextS[index+5] + 2) >> 2; + } + else + { + assert(cn == 4); + for( ; dx < w; dx += 4 ) + { + int index = dx*2; + D[dx] = (S[index] + S[index+3] + nextS[index] + nextS[index+3] + 2) >> 2; + D[dx+1] = (S[index+1] + S[index+4] + nextS[index+1] + nextS[index+4] + 2) >> 2; + D[dx+2] = (S[index+2] + S[index+5] + nextS[index+2] + nextS[index+5] + 2) >> 2; + D[dx+3] = (S[index+3] + S[index+6] + nextS[index+3] + nextS[index+6] + 2) >> 2; + } + } + + return dx; + } + +private: + const int scale_x, scale_y; + const int cn; + bool fast_mode; + const int step; + + ResizeAreaFast_2x2_8u(const ResizeAreaFast_2x2_8u&); + ResizeAreaFast_2x2_8u& operator=(const ResizeAreaFast_2x2_8u&); +}; + +template +class resizeAreaFast_Invoker : + public ParallelLoopBody +{ +public: + resizeAreaFast_Invoker(const Mat &_src, Mat &_dst, + int _scale_x, int _scale_y, const int* _ofs, const int* _xofs) : + ParallelLoopBody(), src(_src), dst(_dst), scale_x(_scale_x), + scale_y(_scale_y), ofs(_ofs), xofs(_xofs) + { + } + + virtual void operator() (const Range& range) const + { + Size ssize = src.size(), dsize = dst.size(); + int cn = src.channels(); + int area = scale_x*scale_y; + float scale = 1.f/(area); + int dwidth1 = (ssize.width/scale_x)*cn; + dsize.width *= cn; + ssize.width *= cn; + int dy, dx, k = 0; + + VecOp vop(scale_x, scale_y, src.channels(), (int)src.step/*, area_ofs*/); + + for( dy = range.start; dy < range.end; dy++ ) + { + T* D = (T*)(dst.data + dst.step*dy); + int sy0 = dy*scale_y; + int w = sy0 + scale_y <= ssize.height ? dwidth1 : 0; + + if( sy0 >= ssize.height ) + { + for( dx = 0; dx < dsize.width; dx++ ) + D[dx] = 0; + continue; + } + + dx = vop((const T*)(src.data + src.step * sy0), D, w); + for( ; dx < w; dx++ ) + { + const T* S = (const T*)(src.data + src.step * sy0) + xofs[dx]; + WT sum = 0; + k = 0; + #if CV_ENABLE_UNROLLED + for( ; k <= area - 4; k += 4 ) + sum += S[ofs[k]] + S[ofs[k+1]] + S[ofs[k+2]] + S[ofs[k+3]]; + #endif + for( ; k < area; k++ ) + sum += S[ofs[k]]; + + D[dx] = saturate_cast(sum * scale); + } + + for( ; dx < dsize.width; dx++ ) + { + WT sum = 0; + int count = 0, sx0 = xofs[dx]; + if( sx0 >= ssize.width ) + D[dx] = 0; + + for( int sy = 0; sy < scale_y; sy++ ) + { + if( sy0 + sy >= ssize.height ) + break; + const T* S = (const T*)(src.data + src.step*(sy0 + sy)) + sx0; + for( int sx = 0; sx < scale_x*cn; sx += cn ) + { + if( sx0 + sx >= ssize.width ) + break; + sum += S[sx]; + count++; + } + } + + D[dx] = saturate_cast((float)sum/count); + } + } + } + +private: + const Mat src; + Mat dst; + const int scale_x, scale_y; + const int *ofs, *xofs; + + resizeAreaFast_Invoker(const resizeAreaFast_Invoker&); + resizeAreaFast_Invoker& operator=(const resizeAreaFast_Invoker&); +}; + +template +static void resizeAreaFast_( const Mat& src, Mat& dst, const int* ofs, const int* xofs, + int scale_x, int scale_y ) +{ + Range range(0, dst.rows); + resizeAreaFast_Invoker invoker(src, dst, scale_x, + scale_y, ofs, xofs); + parallel_for_(range, invoker); +} + +struct DecimateAlpha +{ + int si, di; + float alpha; +}; + +template +class resizeArea_Invoker : + public ParallelLoopBody +{ +public: + resizeArea_Invoker(const Mat& _src, Mat& _dst, const DecimateAlpha* _xofs, + int _xofs_count, double _scale_y_ +#ifdef HAVE_TBB + , const int* _yofs, const int* _cur_dy_ofs +#endif + ) : + ParallelLoopBody(), src(_src), dst(_dst), xofs(_xofs), + xofs_count(_xofs_count), scale_y_(_scale_y_) +#ifdef HAVE_TBB + , yofs(_yofs), cur_dy_ofs(_cur_dy_ofs) +#endif + { + } + + virtual void operator() (const Range& range) const + { + Size ssize = src.size(), dsize = dst.size(); + int cn = src.channels(); + dsize.width *= cn; + AutoBuffer _buffer(dsize.width*2); + WT *buf = _buffer, *sum = buf + dsize.width; + int k, sy, dx, cur_dy = 0, num = sizeof(WT) * dsize.width; + WT scale_y = (WT)scale_y_; + + CV_Assert( cn <= 4 ); + memset(buf, 0, num * 2); + +#ifdef HAVE_TBB + sy = yofs[range.start]; + cur_dy = cur_dy_ofs[sy]; + for( ; sy < range.start; sy++ ) + { + const T* S = (const T*)(src.data + src.step * sy); + memset(buf, 0, num); + + if( cn == 1 ) + for( k = 0; k < xofs_count; k++ ) + { + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + buf[dxn] += S[xofs[k].si]*alpha; + } + else if( cn == 2 ) + for( k = 0; k < xofs_count; k++ ) + { + int sxn = xofs[k].si; + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + WT t0 = buf[dxn] + S[sxn]*alpha; + WT t1 = buf[dxn+1] + S[sxn+1]*alpha; + buf[dxn] = t0; buf[dxn+1] = t1; + } + else if( cn == 3 ) + for( k = 0; k < xofs_count; k++ ) + { + int sxn = xofs[k].si; + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + + WT t0 = buf[dxn] + S[sxn]*alpha; + WT t1 = buf[dxn+1] + S[sxn+1]*alpha; + WT t2 = buf[dxn+2] + S[sxn+2]*alpha; + + buf[dxn] = t0; buf[dxn+1] = t1; buf[dxn+2] = t2; + } + else + for( k = 0; k < xofs_count; k++ ) + { + int sxn = xofs[k].si; + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + + WT t0 = buf[dxn] + S[sxn]*alpha; + WT t1 = buf[dxn+1] + S[sxn+1]*alpha; + + buf[dxn] = t0; buf[dxn+1] = t1; + + t0 = buf[dxn+2] + S[sxn+2]*alpha; + t1 = buf[dxn+3] + S[sxn+3]*alpha; + + buf[dxn+2] = t0; buf[dxn+3] = t1; + } + + if( (cur_dy + 1)*scale_y <= sy + 1 || sy == ssize.height - 1 ) + { + WT beta = std::max(sy + 1 - (cur_dy + 1) * scale_y, (WT)0); + if( fabs(beta) < 1e-3 ) + { + if(cur_dy >= dsize.height) + break; + memset(sum, 0, num); + } + else + for( dx = 0; dx < dsize.width; dx++ ) + sum[dx] = buf[dx] * beta; + cur_dy++; + } + else + { + for( dx = 0; dx <= dsize.width - 2; dx += 2 ) + { + WT t0 = sum[dx] + buf[dx]; + WT t1 = sum[dx+1] + buf[dx+1]; + sum[dx] = t0; sum[dx+1] = t1; + } + for( ; dx < dsize.width; dx++ ) + sum[dx] += buf[dx]; + } + } +#endif + + for( sy = range.start; sy < range.end; sy++ ) + { + const T* S = (const T*)(src.data + src.step * sy); + memset(buf, 0, num); + + if( cn == 1 ) + for( k = 0; k < xofs_count; k++ ) + { + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + buf[dxn] += S[xofs[k].si]*alpha; + } + else if( cn == 2 ) + for( k = 0; k < xofs_count; k++ ) + { + int sxn = xofs[k].si; + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + WT t0 = buf[dxn] + S[sxn]*alpha; + WT t1 = buf[dxn+1] + S[sxn+1]*alpha; + buf[dxn] = t0; buf[dxn+1] = t1; + } + else if( cn == 3 ) + for( k = 0; k < xofs_count; k++ ) + { + int sxn = xofs[k].si; + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + + WT t0 = buf[dxn] + S[sxn]*alpha; + WT t1 = buf[dxn+1] + S[sxn+1]*alpha; + WT t2 = buf[dxn+2] + S[sxn+2]*alpha; + + buf[dxn] = t0; buf[dxn+1] = t1; buf[dxn+2] = t2; + } + else + for( k = 0; k < xofs_count; k++ ) + { + int sxn = xofs[k].si; + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + + WT t0 = buf[dxn] + S[sxn]*alpha; + WT t1 = buf[dxn+1] + S[sxn+1]*alpha; + + buf[dxn] = t0; buf[dxn+1] = t1; + + t0 = buf[dxn+2] + S[sxn+2]*alpha; + t1 = buf[dxn+3] + S[sxn+3]*alpha; + + buf[dxn+2] = t0; buf[dxn+3] = t1; + } + + if( (cur_dy + 1)*scale_y <= sy + 1 || sy == ssize.height - 1 ) + { + WT beta = std::max(sy + 1 - (cur_dy + 1) * scale_y, (WT)0); + T* D = (T*)(dst.data + dst.step*cur_dy); + if( fabs(beta) < 1e-3 ) + { + if(cur_dy >= dsize.height) + return; + for( dx = 0; dx < dsize.width; dx++ ) + D[dx] = saturate_cast((sum[dx] + buf[dx]) / min(scale_y, src.rows - cur_dy * scale_y)); + memset(sum, 0, num); + } + else + { + WT beta1 = 1 - beta; + for( dx = 0; dx < dsize.width; dx++ ) + { + D[dx] = saturate_cast((sum[dx] + buf[dx] * beta1)/ min(scale_y, src.rows - cur_dy * scale_y)); + sum[dx] = buf[dx] * beta; + } + } + cur_dy++; + } + else + { + for( dx = 0; dx <= dsize.width - 2; dx += 2 ) + { + WT t0 = sum[dx] + buf[dx]; + WT t1 = sum[dx+1] + buf[dx+1]; + sum[dx] = t0; sum[dx+1] = t1; + } + for( ; dx < dsize.width; dx++ ) + sum[dx] += buf[dx]; + } + } + } + +private: + const Mat src; + Mat dst; + const DecimateAlpha* xofs; + const int xofs_count; + const double scale_y_; +#ifdef HAVE_TBB + const int *yofs, *cur_dy_ofs; +#endif + resizeArea_Invoker(const resizeArea_Invoker&); + resizeArea_Invoker& operator=(const resizeArea_Invoker&); +}; + +template +static void resizeArea_( const Mat& src, Mat& dst, const DecimateAlpha* xofs, int xofs_count, double scale_y_) +{ +#ifdef HAVE_TBB + Size ssize = src.size(), dsize = dst.size(); + AutoBuffer _yofs(2 * ssize.height); + int *yofs = _yofs, *cur_dy_ofs = _yofs + ssize.height; + int index = 0, cur_dy = 0, sy; + + for( sy = 0; sy < ssize.height; sy++ ) + { + bool reset = false; + cur_dy_ofs[sy] = cur_dy; + if( (cur_dy + 1)*scale_y_ <= sy + 1 || sy == ssize.height - 1 ) + { + WT beta = (WT)std::max(sy + 1 - (cur_dy+1)*scale_y_, 0.); + if( fabs(beta) < 1e-3 ) + { + if(cur_dy >= dsize.height) + break; + reset = true; + } + cur_dy++; + } + yofs[sy] = index; + if (reset) + index = sy + 1; + } +#endif + + Range range(0, src.rows); + resizeArea_Invoker invoker(src, dst, xofs, xofs_count, scale_y_ +#ifdef HAVE_TBB + , yofs, cur_dy_ofs +#endif + ); + parallel_for_(range, invoker); +} + + +typedef void (*ResizeFunc)( const Mat& src, Mat& dst, + const int* xofs, const void* alpha, + const int* yofs, const void* beta, + int xmin, int xmax, int ksize ); + +typedef void (*ResizeAreaFastFunc)( const Mat& src, Mat& dst, + const int* ofs, const int *xofs, + int scale_x, int scale_y ); + +typedef void (*ResizeAreaFunc)( const Mat& src, Mat& dst, + const DecimateAlpha* xofs, int xofs_count, + double scale_y_); + +} + + +////////////////////////////////////////////////////////////////////////////////////////// + +void cv::resize( InputArray _src, OutputArray _dst, Size dsize, + double inv_scale_x, double inv_scale_y, int interpolation ) +{ + static ResizeFunc linear_tab[] = + { + resizeGeneric_< + HResizeLinear, + VResizeLinear, + VResizeLinearVec_32s8u> >, + 0, + resizeGeneric_< + HResizeLinear, + VResizeLinear, + VResizeLinearVec_32f16u> >, + resizeGeneric_< + HResizeLinear, + VResizeLinear, + VResizeLinearVec_32f16s> >, + 0, + resizeGeneric_< + HResizeLinear, + VResizeLinear, + VResizeLinearVec_32f> >, + resizeGeneric_< + HResizeLinear, + VResizeLinear, + VResizeNoVec> >, + 0 + }; + + static ResizeFunc cubic_tab[] = + { + resizeGeneric_< + HResizeCubic, + VResizeCubic, + VResizeCubicVec_32s8u> >, + 0, + resizeGeneric_< + HResizeCubic, + VResizeCubic, + VResizeCubicVec_32f16u> >, + resizeGeneric_< + HResizeCubic, + VResizeCubic, + VResizeCubicVec_32f16s> >, + 0, + resizeGeneric_< + HResizeCubic, + VResizeCubic, + VResizeCubicVec_32f> >, + resizeGeneric_< + HResizeCubic, + VResizeCubic, + VResizeNoVec> >, + 0 + }; + + static ResizeFunc lanczos4_tab[] = + { + resizeGeneric_, + VResizeLanczos4, + VResizeNoVec> >, + 0, + resizeGeneric_, + VResizeLanczos4, + VResizeNoVec> >, + resizeGeneric_, + VResizeLanczos4, + VResizeNoVec> >, + 0, + resizeGeneric_, + VResizeLanczos4, + VResizeNoVec> >, + resizeGeneric_, + VResizeLanczos4, + VResizeNoVec> >, + 0 + }; + + static ResizeAreaFastFunc areafast_tab[] = + { + resizeAreaFast_ >, + 0, + resizeAreaFast_ >, + resizeAreaFast_ >, + 0, + resizeAreaFast_ >, + resizeAreaFast_ >, + 0 + }; + + static ResizeAreaFunc area_tab[] = + { + resizeArea_, 0, resizeArea_, + resizeArea_, 0, resizeArea_, + resizeArea_, 0 + }; + + Mat src = _src.getMat(); + Size ssize = src.size(); + + CV_Assert( ssize.area() > 0 ); + CV_Assert( dsize.area() || (inv_scale_x > 0 && inv_scale_y > 0) ); + if( !dsize.area() ) + { + dsize = Size(saturate_cast(src.cols*inv_scale_x), + saturate_cast(src.rows*inv_scale_y)); + CV_Assert( dsize.area() ); + } + else + { + inv_scale_x = (double)dsize.width/src.cols; + inv_scale_y = (double)dsize.height/src.rows; + } + _dst.create(dsize, src.type()); + Mat dst = _dst.getMat(); + + +#ifdef HAVE_TEGRA_OPTIMIZATION + if (tegra::resize(src, dst, inv_scale_x, inv_scale_y, interpolation)) + return; +#endif + + int depth = src.depth(), cn = src.channels(); + double scale_x = 1./inv_scale_x, scale_y = 1./inv_scale_y; + int k, sx, sy, dx, dy; + + if( interpolation == INTER_NEAREST ) + { + resizeNN( src, dst, inv_scale_x, inv_scale_y ); + return; + } + + { + int iscale_x = saturate_cast(scale_x); + int iscale_y = saturate_cast(scale_y); + + bool is_area_fast = std::abs(scale_x - iscale_x) < DBL_EPSILON && + std::abs(scale_y - iscale_y) < DBL_EPSILON; + + // in case of scale_x && scale_y is equal to 2 + // INTER_AREA (fast) also is equal to INTER_LINEAR + if ( interpolation == INTER_LINEAR && + scale_x >= 1 && scale_y >= 1 && is_area_fast) + interpolation = INTER_AREA; + + // true "area" interpolation is only implemented for the case (scale_x <= 1 && scale_y <= 1). + // In other cases it is emulated using some variant of bilinear interpolation + if( interpolation == INTER_AREA && scale_x >= 1 && scale_y >= 1 ) + { + if( is_area_fast ) + { + int area = iscale_x*iscale_y; + size_t srcstep = src.step / src.elemSize1(); + AutoBuffer _ofs(area + dsize.width*cn); + int* ofs = _ofs; + int* xofs = ofs + area; + ResizeAreaFastFunc func = areafast_tab[depth]; + CV_Assert( func != 0 ); + + for( sy = 0, k = 0; sy < iscale_y; sy++ ) + for( sx = 0; sx < iscale_x; sx++ ) + ofs[k++] = (int)(sy*srcstep + sx*cn); + + for( dx = 0; dx < dsize.width; dx++ ) + { + int j = dx * cn; + sx = iscale_x * j; + for( k = 0; k < cn; k++ ) + xofs[j + k] = sx + k; + } + + func( src, dst, ofs, xofs, iscale_x, iscale_y ); + return; + } + + ResizeAreaFunc func = area_tab[depth]; + CV_Assert( func != 0 && cn <= 4 ); + + AutoBuffer _xofs(ssize.width*2); + DecimateAlpha* xofs = _xofs; + + for( dx = 0, k = 0; dx < dsize.width; dx++ ) + { + double fsx1 = dx*scale_x; + double fsx2 = fsx1 + scale_x; + int sx1 = cvCeil(fsx1), sx2 = cvFloor(fsx2); + sx1 = std::min(sx1, ssize.width-1); + sx2 = std::min(sx2, ssize.width-1); + + if( sx1 > fsx1 ) + { + assert( k < ssize.width*2 ); + xofs[k].di = dx*cn; + xofs[k].si = (sx1-1)*cn; + xofs[k++].alpha = (float)((sx1 - fsx1) / min(scale_x, src.cols - fsx1)); + } + + for( sx = sx1; sx < sx2; sx++ ) + { + assert( k < ssize.width*2 ); + xofs[k].di = dx*cn; + xofs[k].si = sx*cn; + xofs[k++].alpha = float(1.0 / min(scale_x, src.cols - fsx1)); + } + + if( fsx2 - sx2 > 1e-3 ) + { + assert( k < ssize.width*2 ); + xofs[k].di = dx*cn; + xofs[k].si = sx2*cn; + xofs[k++].alpha = (float)(min(fsx2 - sx2, 1.) / min(scale_x, src.cols - fsx1)); + } + } + + func( src, dst, xofs, k, scale_y); + return; + } + } + + int xmin = 0, xmax = dsize.width, width = dsize.width*cn; + bool area_mode = interpolation == INTER_AREA; + bool fixpt = depth == CV_8U; + float fx, fy; + ResizeFunc func=0; + int ksize=0, ksize2; + if( interpolation == INTER_CUBIC ) + ksize = 4, func = cubic_tab[depth]; + else if( interpolation == INTER_LANCZOS4 ) + ksize = 8, func = lanczos4_tab[depth]; + else if( interpolation == INTER_LINEAR || interpolation == INTER_AREA ) + ksize = 2, func = linear_tab[depth]; + else + CV_Error( CV_StsBadArg, "Unknown interpolation method" ); + ksize2 = ksize/2; + + CV_Assert( func != 0 ); + + AutoBuffer _buffer((width + dsize.height)*(sizeof(int) + sizeof(float)*ksize)); + int* xofs = (int*)(uchar*)_buffer; + int* yofs = xofs + width; + float* alpha = (float*)(yofs + dsize.height); + short* ialpha = (short*)alpha; + float* beta = alpha + width*ksize; + short* ibeta = ialpha + width*ksize; + float cbuf[MAX_ESIZE]; + + for( dx = 0; dx < dsize.width; dx++ ) + { + if( !area_mode ) + { + fx = (float)((dx+0.5)*scale_x - 0.5); + sx = cvFloor(fx); + fx -= sx; + } + else + { + sx = cvFloor(dx*scale_x); + fx = (float)((dx+1) - (sx+1)*inv_scale_x); + fx = fx <= 0 ? 0.f : fx - cvFloor(fx); + } + + if( sx < ksize2-1 ) + { + xmin = dx+1; + if( sx < 0 ) + fx = 0, sx = 0; + } + + if( sx + ksize2 >= ssize.width ) + { + xmax = std::min( xmax, dx ); + if( sx >= ssize.width-1 ) + fx = 0, sx = ssize.width-1; + } + + for( k = 0, sx *= cn; k < cn; k++ ) + xofs[dx*cn + k] = sx + k; + + if( interpolation == INTER_CUBIC ) + interpolateCubic( fx, cbuf ); + else if( interpolation == INTER_LANCZOS4 ) + interpolateLanczos4( fx, cbuf ); + else + { + cbuf[0] = 1.f - fx; + cbuf[1] = fx; + } + if( fixpt ) + { + for( k = 0; k < ksize; k++ ) + ialpha[dx*cn*ksize + k] = saturate_cast(cbuf[k]*INTER_RESIZE_COEF_SCALE); + for( ; k < cn*ksize; k++ ) + ialpha[dx*cn*ksize + k] = ialpha[dx*cn*ksize + k - ksize]; + } + else + { + for( k = 0; k < ksize; k++ ) + alpha[dx*cn*ksize + k] = cbuf[k]; + for( ; k < cn*ksize; k++ ) + alpha[dx*cn*ksize + k] = alpha[dx*cn*ksize + k - ksize]; + } + } + + for( dy = 0; dy < dsize.height; dy++ ) + { + if( !area_mode ) + { + fy = (float)((dy+0.5)*scale_y - 0.5); + sy = cvFloor(fy); + fy -= sy; + } + else + { + sy = cvFloor(dy*scale_y); + fy = (float)((dy+1) - (sy+1)*inv_scale_y); + fy = fy <= 0 ? 0.f : fy - cvFloor(fy); + } + + yofs[dy] = sy; + if( interpolation == INTER_CUBIC ) + interpolateCubic( fy, cbuf ); + else if( interpolation == INTER_LANCZOS4 ) + interpolateLanczos4( fy, cbuf ); + else + { + cbuf[0] = 1.f - fy; + cbuf[1] = fy; + } + + if( fixpt ) + { + for( k = 0; k < ksize; k++ ) + ibeta[dy*ksize + k] = saturate_cast(cbuf[k]*INTER_RESIZE_COEF_SCALE); + } + else + { + for( k = 0; k < ksize; k++ ) + beta[dy*ksize + k] = cbuf[k]; + } + } + + func( src, dst, xofs, fixpt ? (void*)ialpha : (void*)alpha, yofs, + fixpt ? (void*)ibeta : (void*)beta, xmin, xmax, ksize ); +} + + +/****************************************************************************************\ +* General warping (affine, perspective, remap) * +\****************************************************************************************/ + +namespace cv +{ + +template +static void remapNearest( const Mat& _src, Mat& _dst, const Mat& _xy, + int borderType, const Scalar& _borderValue ) +{ + Size ssize = _src.size(), dsize = _dst.size(); + int cn = _src.channels(); + const T* S0 = (const T*)_src.data; + size_t sstep = _src.step/sizeof(S0[0]); + Scalar_ cval(saturate_cast(_borderValue[0]), + saturate_cast(_borderValue[1]), + saturate_cast(_borderValue[2]), + saturate_cast(_borderValue[3])); + int dx, dy; + + unsigned width1 = ssize.width, height1 = ssize.height; + + if( _dst.isContinuous() && _xy.isContinuous() ) + { + dsize.width *= dsize.height; + dsize.height = 1; + } + + for( dy = 0; dy < dsize.height; dy++ ) + { + T* D = (T*)(_dst.data + _dst.step*dy); + const short* XY = (const short*)(_xy.data + _xy.step*dy); + + if( cn == 1 ) + { + for( dx = 0; dx < dsize.width; dx++ ) + { + int sx = XY[dx*2], sy = XY[dx*2+1]; + if( (unsigned)sx < width1 && (unsigned)sy < height1 ) + D[dx] = S0[sy*sstep + sx]; + else + { + if( borderType == BORDER_REPLICATE ) + { + sx = clip(sx, 0, ssize.width); + sy = clip(sy, 0, ssize.height); + D[dx] = S0[sy*sstep + sx]; + } + else if( borderType == BORDER_CONSTANT ) + D[dx] = cval[0]; + else if( borderType != BORDER_TRANSPARENT ) + { + sx = borderInterpolate(sx, ssize.width, borderType); + sy = borderInterpolate(sy, ssize.height, borderType); + D[dx] = S0[sy*sstep + sx]; + } + } + } + } + else + { + for( dx = 0; dx < dsize.width; dx++, D += cn ) + { + int sx = XY[dx*2], sy = XY[dx*2+1], k; + const T *S; + if( (unsigned)sx < width1 && (unsigned)sy < height1 ) + { + if( cn == 3 ) + { + S = S0 + sy*sstep + sx*3; + D[0] = S[0], D[1] = S[1], D[2] = S[2]; + } + else if( cn == 4 ) + { + S = S0 + sy*sstep + sx*4; + D[0] = S[0], D[1] = S[1], D[2] = S[2], D[3] = S[3]; + } + else + { + S = S0 + sy*sstep + sx*cn; + for( k = 0; k < cn; k++ ) + D[k] = S[k]; + } + } + else if( borderType != BORDER_TRANSPARENT ) + { + if( borderType == BORDER_REPLICATE ) + { + sx = clip(sx, 0, ssize.width); + sy = clip(sy, 0, ssize.height); + S = S0 + sy*sstep + sx*cn; + } + else if( borderType == BORDER_CONSTANT ) + S = &cval[0]; + else + { + sx = borderInterpolate(sx, ssize.width, borderType); + sy = borderInterpolate(sy, ssize.height, borderType); + S = S0 + sy*sstep + sx*cn; + } + for( k = 0; k < cn; k++ ) + D[k] = S[k]; + } + } + } + } +} + + +struct RemapNoVec +{ + int operator()( const Mat&, void*, const short*, const ushort*, + const void*, int ) const { return 0; } +}; + +#if CV_SSE2 + +struct RemapVec_8u +{ + int operator()( const Mat& _src, void* _dst, const short* XY, + const ushort* FXY, const void* _wtab, int width ) const + { + int cn = _src.channels(); + + if( (cn != 1 && cn != 3 && cn != 4) || !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + const uchar *S0 = _src.data, *S1 = _src.data + _src.step; + const short* wtab = cn == 1 ? (const short*)_wtab : &BilinearTab_iC4[0][0][0]; + uchar* D = (uchar*)_dst; + int x = 0, sstep = (int)_src.step; + __m128i delta = _mm_set1_epi32(INTER_REMAP_COEF_SCALE/2); + __m128i xy2ofs = _mm_set1_epi32(cn + (sstep << 16)); + __m128i z = _mm_setzero_si128(); + int CV_DECL_ALIGNED(16) iofs0[4], iofs1[4]; + + if( cn == 1 ) + { + for( ; x <= width - 8; x += 8 ) + { + __m128i xy0 = _mm_loadu_si128( (const __m128i*)(XY + x*2)); + __m128i xy1 = _mm_loadu_si128( (const __m128i*)(XY + x*2 + 8)); + __m128i v0, v1, v2, v3, a0, a1, b0, b1; + unsigned i0, i1; + + xy0 = _mm_madd_epi16( xy0, xy2ofs ); + xy1 = _mm_madd_epi16( xy1, xy2ofs ); + _mm_store_si128( (__m128i*)iofs0, xy0 ); + _mm_store_si128( (__m128i*)iofs1, xy1 ); + + i0 = *(ushort*)(S0 + iofs0[0]) + (*(ushort*)(S0 + iofs0[1]) << 16); + i1 = *(ushort*)(S0 + iofs0[2]) + (*(ushort*)(S0 + iofs0[3]) << 16); + v0 = _mm_unpacklo_epi32(_mm_cvtsi32_si128(i0), _mm_cvtsi32_si128(i1)); + i0 = *(ushort*)(S1 + iofs0[0]) + (*(ushort*)(S1 + iofs0[1]) << 16); + i1 = *(ushort*)(S1 + iofs0[2]) + (*(ushort*)(S1 + iofs0[3]) << 16); + v1 = _mm_unpacklo_epi32(_mm_cvtsi32_si128(i0), _mm_cvtsi32_si128(i1)); + v0 = _mm_unpacklo_epi8(v0, z); + v1 = _mm_unpacklo_epi8(v1, z); + + a0 = _mm_unpacklo_epi32(_mm_loadl_epi64((__m128i*)(wtab+FXY[x]*4)), + _mm_loadl_epi64((__m128i*)(wtab+FXY[x+1]*4))); + a1 = _mm_unpacklo_epi32(_mm_loadl_epi64((__m128i*)(wtab+FXY[x+2]*4)), + _mm_loadl_epi64((__m128i*)(wtab+FXY[x+3]*4))); + b0 = _mm_unpacklo_epi64(a0, a1); + b1 = _mm_unpackhi_epi64(a0, a1); + v0 = _mm_madd_epi16(v0, b0); + v1 = _mm_madd_epi16(v1, b1); + v0 = _mm_add_epi32(_mm_add_epi32(v0, v1), delta); + + i0 = *(ushort*)(S0 + iofs1[0]) + (*(ushort*)(S0 + iofs1[1]) << 16); + i1 = *(ushort*)(S0 + iofs1[2]) + (*(ushort*)(S0 + iofs1[3]) << 16); + v2 = _mm_unpacklo_epi32(_mm_cvtsi32_si128(i0), _mm_cvtsi32_si128(i1)); + i0 = *(ushort*)(S1 + iofs1[0]) + (*(ushort*)(S1 + iofs1[1]) << 16); + i1 = *(ushort*)(S1 + iofs1[2]) + (*(ushort*)(S1 + iofs1[3]) << 16); + v3 = _mm_unpacklo_epi32(_mm_cvtsi32_si128(i0), _mm_cvtsi32_si128(i1)); + v2 = _mm_unpacklo_epi8(v2, z); + v3 = _mm_unpacklo_epi8(v3, z); + + a0 = _mm_unpacklo_epi32(_mm_loadl_epi64((__m128i*)(wtab+FXY[x+4]*4)), + _mm_loadl_epi64((__m128i*)(wtab+FXY[x+5]*4))); + a1 = _mm_unpacklo_epi32(_mm_loadl_epi64((__m128i*)(wtab+FXY[x+6]*4)), + _mm_loadl_epi64((__m128i*)(wtab+FXY[x+7]*4))); + b0 = _mm_unpacklo_epi64(a0, a1); + b1 = _mm_unpackhi_epi64(a0, a1); + v2 = _mm_madd_epi16(v2, b0); + v3 = _mm_madd_epi16(v3, b1); + v2 = _mm_add_epi32(_mm_add_epi32(v2, v3), delta); + + v0 = _mm_srai_epi32(v0, INTER_REMAP_COEF_BITS); + v2 = _mm_srai_epi32(v2, INTER_REMAP_COEF_BITS); + v0 = _mm_packus_epi16(_mm_packs_epi32(v0, v2), z); + _mm_storel_epi64( (__m128i*)(D + x), v0 ); + } + } + else if( cn == 3 ) + { + for( ; x <= width - 5; x += 4, D += 12 ) + { + __m128i xy0 = _mm_loadu_si128( (const __m128i*)(XY + x*2)); + __m128i u0, v0, u1, v1; + + xy0 = _mm_madd_epi16( xy0, xy2ofs ); + _mm_store_si128( (__m128i*)iofs0, xy0 ); + const __m128i *w0, *w1; + w0 = (const __m128i*)(wtab + FXY[x]*16); + w1 = (const __m128i*)(wtab + FXY[x+1]*16); + + u0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S0 + iofs0[0])), + _mm_cvtsi32_si128(*(int*)(S0 + iofs0[0] + 3))); + v0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S1 + iofs0[0])), + _mm_cvtsi32_si128(*(int*)(S1 + iofs0[0] + 3))); + u1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S0 + iofs0[1])), + _mm_cvtsi32_si128(*(int*)(S0 + iofs0[1] + 3))); + v1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S1 + iofs0[1])), + _mm_cvtsi32_si128(*(int*)(S1 + iofs0[1] + 3))); + u0 = _mm_unpacklo_epi8(u0, z); + v0 = _mm_unpacklo_epi8(v0, z); + u1 = _mm_unpacklo_epi8(u1, z); + v1 = _mm_unpacklo_epi8(v1, z); + u0 = _mm_add_epi32(_mm_madd_epi16(u0, w0[0]), _mm_madd_epi16(v0, w0[1])); + u1 = _mm_add_epi32(_mm_madd_epi16(u1, w1[0]), _mm_madd_epi16(v1, w1[1])); + u0 = _mm_srai_epi32(_mm_add_epi32(u0, delta), INTER_REMAP_COEF_BITS); + u1 = _mm_srai_epi32(_mm_add_epi32(u1, delta), INTER_REMAP_COEF_BITS); + u0 = _mm_slli_si128(u0, 4); + u0 = _mm_packs_epi32(u0, u1); + u0 = _mm_packus_epi16(u0, u0); + _mm_storel_epi64((__m128i*)D, _mm_srli_si128(u0,1)); + + w0 = (const __m128i*)(wtab + FXY[x+2]*16); + w1 = (const __m128i*)(wtab + FXY[x+3]*16); + + u0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S0 + iofs0[2])), + _mm_cvtsi32_si128(*(int*)(S0 + iofs0[2] + 3))); + v0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S1 + iofs0[2])), + _mm_cvtsi32_si128(*(int*)(S1 + iofs0[2] + 3))); + u1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S0 + iofs0[3])), + _mm_cvtsi32_si128(*(int*)(S0 + iofs0[3] + 3))); + v1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S1 + iofs0[3])), + _mm_cvtsi32_si128(*(int*)(S1 + iofs0[3] + 3))); + u0 = _mm_unpacklo_epi8(u0, z); + v0 = _mm_unpacklo_epi8(v0, z); + u1 = _mm_unpacklo_epi8(u1, z); + v1 = _mm_unpacklo_epi8(v1, z); + u0 = _mm_add_epi32(_mm_madd_epi16(u0, w0[0]), _mm_madd_epi16(v0, w0[1])); + u1 = _mm_add_epi32(_mm_madd_epi16(u1, w1[0]), _mm_madd_epi16(v1, w1[1])); + u0 = _mm_srai_epi32(_mm_add_epi32(u0, delta), INTER_REMAP_COEF_BITS); + u1 = _mm_srai_epi32(_mm_add_epi32(u1, delta), INTER_REMAP_COEF_BITS); + u0 = _mm_slli_si128(u0, 4); + u0 = _mm_packs_epi32(u0, u1); + u0 = _mm_packus_epi16(u0, u0); + _mm_storel_epi64((__m128i*)(D + 6), _mm_srli_si128(u0,1)); + } + } + else if( cn == 4 ) + { + for( ; x <= width - 4; x += 4, D += 16 ) + { + __m128i xy0 = _mm_loadu_si128( (const __m128i*)(XY + x*2)); + __m128i u0, v0, u1, v1; + + xy0 = _mm_madd_epi16( xy0, xy2ofs ); + _mm_store_si128( (__m128i*)iofs0, xy0 ); + const __m128i *w0, *w1; + w0 = (const __m128i*)(wtab + FXY[x]*16); + w1 = (const __m128i*)(wtab + FXY[x+1]*16); + + u0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S0 + iofs0[0])), + _mm_cvtsi32_si128(*(int*)(S0 + iofs0[0] + 4))); + v0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S1 + iofs0[0])), + _mm_cvtsi32_si128(*(int*)(S1 + iofs0[0] + 4))); + u1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S0 + iofs0[1])), + _mm_cvtsi32_si128(*(int*)(S0 + iofs0[1] + 4))); + v1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S1 + iofs0[1])), + _mm_cvtsi32_si128(*(int*)(S1 + iofs0[1] + 4))); + u0 = _mm_unpacklo_epi8(u0, z); + v0 = _mm_unpacklo_epi8(v0, z); + u1 = _mm_unpacklo_epi8(u1, z); + v1 = _mm_unpacklo_epi8(v1, z); + u0 = _mm_add_epi32(_mm_madd_epi16(u0, w0[0]), _mm_madd_epi16(v0, w0[1])); + u1 = _mm_add_epi32(_mm_madd_epi16(u1, w1[0]), _mm_madd_epi16(v1, w1[1])); + u0 = _mm_srai_epi32(_mm_add_epi32(u0, delta), INTER_REMAP_COEF_BITS); + u1 = _mm_srai_epi32(_mm_add_epi32(u1, delta), INTER_REMAP_COEF_BITS); + u0 = _mm_packs_epi32(u0, u1); + u0 = _mm_packus_epi16(u0, u0); + _mm_storel_epi64((__m128i*)D, u0); + + w0 = (const __m128i*)(wtab + FXY[x+2]*16); + w1 = (const __m128i*)(wtab + FXY[x+3]*16); + + u0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S0 + iofs0[2])), + _mm_cvtsi32_si128(*(int*)(S0 + iofs0[2] + 4))); + v0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S1 + iofs0[2])), + _mm_cvtsi32_si128(*(int*)(S1 + iofs0[2] + 4))); + u1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S0 + iofs0[3])), + _mm_cvtsi32_si128(*(int*)(S0 + iofs0[3] + 4))); + v1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(int*)(S1 + iofs0[3])), + _mm_cvtsi32_si128(*(int*)(S1 + iofs0[3] + 4))); + u0 = _mm_unpacklo_epi8(u0, z); + v0 = _mm_unpacklo_epi8(v0, z); + u1 = _mm_unpacklo_epi8(u1, z); + v1 = _mm_unpacklo_epi8(v1, z); + u0 = _mm_add_epi32(_mm_madd_epi16(u0, w0[0]), _mm_madd_epi16(v0, w0[1])); + u1 = _mm_add_epi32(_mm_madd_epi16(u1, w1[0]), _mm_madd_epi16(v1, w1[1])); + u0 = _mm_srai_epi32(_mm_add_epi32(u0, delta), INTER_REMAP_COEF_BITS); + u1 = _mm_srai_epi32(_mm_add_epi32(u1, delta), INTER_REMAP_COEF_BITS); + u0 = _mm_packs_epi32(u0, u1); + u0 = _mm_packus_epi16(u0, u0); + _mm_storel_epi64((__m128i*)(D + 8), u0); + } + } + + return x; + } +}; + +#else + +typedef RemapNoVec RemapVec_8u; + +#endif + + +template +static void remapBilinear( const Mat& _src, Mat& _dst, const Mat& _xy, + const Mat& _fxy, const void* _wtab, + int borderType, const Scalar& _borderValue ) +{ + typedef typename CastOp::rtype T; + typedef typename CastOp::type1 WT; + Size ssize = _src.size(), dsize = _dst.size(); + int cn = _src.channels(); + const AT* wtab = (const AT*)_wtab; + const T* S0 = (const T*)_src.data; + size_t sstep = _src.step/sizeof(S0[0]); + Scalar_ cval(saturate_cast(_borderValue[0]), + saturate_cast(_borderValue[1]), + saturate_cast(_borderValue[2]), + saturate_cast(_borderValue[3])); + int dx, dy; + CastOp castOp; + VecOp vecOp; + + unsigned width1 = std::max(ssize.width-1, 0), height1 = std::max(ssize.height-1, 0); + CV_Assert( cn <= 4 && ssize.area() > 0 ); +#if CV_SSE2 + if( _src.type() == CV_8UC3 ) + width1 = std::max(ssize.width-2, 0); +#endif + + for( dy = 0; dy < dsize.height; dy++ ) + { + T* D = (T*)(_dst.data + _dst.step*dy); + const short* XY = (const short*)(_xy.data + _xy.step*dy); + const ushort* FXY = (const ushort*)(_fxy.data + _fxy.step*dy); + int X0 = 0; + bool prevInlier = false; + + for( dx = 0; dx <= dsize.width; dx++ ) + { + bool curInlier = dx < dsize.width ? + (unsigned)XY[dx*2] < width1 && + (unsigned)XY[dx*2+1] < height1 : !prevInlier; + if( curInlier == prevInlier ) + continue; + + int X1 = dx; + dx = X0; + X0 = X1; + prevInlier = curInlier; + + if( !curInlier ) + { + int len = vecOp( _src, D, XY + dx*2, FXY + dx, wtab, X1 - dx ); + D += len*cn; + dx += len; + + if( cn == 1 ) + { + for( ; dx < X1; dx++, D++ ) + { + int sx = XY[dx*2], sy = XY[dx*2+1]; + const AT* w = wtab + FXY[dx]*4; + const T* S = S0 + sy*sstep + sx; + *D = castOp(WT(S[0]*w[0] + S[1]*w[1] + S[sstep]*w[2] + S[sstep+1]*w[3])); + } + } + else if( cn == 2 ) + for( ; dx < X1; dx++, D += 2 ) + { + int sx = XY[dx*2], sy = XY[dx*2+1]; + const AT* w = wtab + FXY[dx]*4; + const T* S = S0 + sy*sstep + sx*2; + WT t0 = S[0]*w[0] + S[2]*w[1] + S[sstep]*w[2] + S[sstep+2]*w[3]; + WT t1 = S[1]*w[0] + S[3]*w[1] + S[sstep+1]*w[2] + S[sstep+3]*w[3]; + D[0] = castOp(t0); D[1] = castOp(t1); + } + else if( cn == 3 ) + for( ; dx < X1; dx++, D += 3 ) + { + int sx = XY[dx*2], sy = XY[dx*2+1]; + const AT* w = wtab + FXY[dx]*4; + const T* S = S0 + sy*sstep + sx*3; + WT t0 = S[0]*w[0] + S[3]*w[1] + S[sstep]*w[2] + S[sstep+3]*w[3]; + WT t1 = S[1]*w[0] + S[4]*w[1] + S[sstep+1]*w[2] + S[sstep+4]*w[3]; + WT t2 = S[2]*w[0] + S[5]*w[1] + S[sstep+2]*w[2] + S[sstep+5]*w[3]; + D[0] = castOp(t0); D[1] = castOp(t1); D[2] = castOp(t2); + } + else + for( ; dx < X1; dx++, D += 4 ) + { + int sx = XY[dx*2], sy = XY[dx*2+1]; + const AT* w = wtab + FXY[dx]*4; + const T* S = S0 + sy*sstep + sx*4; + WT t0 = S[0]*w[0] + S[4]*w[1] + S[sstep]*w[2] + S[sstep+4]*w[3]; + WT t1 = S[1]*w[0] + S[5]*w[1] + S[sstep+1]*w[2] + S[sstep+5]*w[3]; + D[0] = castOp(t0); D[1] = castOp(t1); + t0 = S[2]*w[0] + S[6]*w[1] + S[sstep+2]*w[2] + S[sstep+6]*w[3]; + t1 = S[3]*w[0] + S[7]*w[1] + S[sstep+3]*w[2] + S[sstep+7]*w[3]; + D[2] = castOp(t0); D[3] = castOp(t1); + } + } + else + { + if( borderType == BORDER_TRANSPARENT && cn != 3 ) + { + D += (X1 - dx)*cn; + dx = X1; + continue; + } + + if( cn == 1 ) + for( ; dx < X1; dx++, D++ ) + { + int sx = XY[dx*2], sy = XY[dx*2+1]; + if( borderType == BORDER_CONSTANT && + (sx >= ssize.width || sx+1 < 0 || + sy >= ssize.height || sy+1 < 0) ) + { + D[0] = cval[0]; + } + else + { + int sx0, sx1, sy0, sy1; + T v0, v1, v2, v3; + const AT* w = wtab + FXY[dx]*4; + if( borderType == BORDER_REPLICATE ) + { + sx0 = clip(sx, 0, ssize.width); + sx1 = clip(sx+1, 0, ssize.width); + sy0 = clip(sy, 0, ssize.height); + sy1 = clip(sy+1, 0, ssize.height); + v0 = S0[sy0*sstep + sx0]; + v1 = S0[sy0*sstep + sx1]; + v2 = S0[sy1*sstep + sx0]; + v3 = S0[sy1*sstep + sx1]; + } + else + { + sx0 = borderInterpolate(sx, ssize.width, borderType); + sx1 = borderInterpolate(sx+1, ssize.width, borderType); + sy0 = borderInterpolate(sy, ssize.height, borderType); + sy1 = borderInterpolate(sy+1, ssize.height, borderType); + v0 = sx0 >= 0 && sy0 >= 0 ? S0[sy0*sstep + sx0] : cval[0]; + v1 = sx1 >= 0 && sy0 >= 0 ? S0[sy0*sstep + sx1] : cval[0]; + v2 = sx0 >= 0 && sy1 >= 0 ? S0[sy1*sstep + sx0] : cval[0]; + v3 = sx1 >= 0 && sy1 >= 0 ? S0[sy1*sstep + sx1] : cval[0]; + } + D[0] = castOp(WT(v0*w[0] + v1*w[1] + v2*w[2] + v3*w[3])); + } + } + else + for( ; dx < X1; dx++, D += cn ) + { + int sx = XY[dx*2], sy = XY[dx*2+1], k; + if( borderType == BORDER_CONSTANT && + (sx >= ssize.width || sx+1 < 0 || + sy >= ssize.height || sy+1 < 0) ) + { + for( k = 0; k < cn; k++ ) + D[k] = cval[k]; + } + else + { + int sx0, sx1, sy0, sy1; + const T *v0, *v1, *v2, *v3; + const AT* w = wtab + FXY[dx]*4; + if( borderType == BORDER_REPLICATE ) + { + sx0 = clip(sx, 0, ssize.width); + sx1 = clip(sx+1, 0, ssize.width); + sy0 = clip(sy, 0, ssize.height); + sy1 = clip(sy+1, 0, ssize.height); + v0 = S0 + sy0*sstep + sx0*cn; + v1 = S0 + sy0*sstep + sx1*cn; + v2 = S0 + sy1*sstep + sx0*cn; + v3 = S0 + sy1*sstep + sx1*cn; + } + else if( borderType == BORDER_TRANSPARENT && + ((unsigned)sx >= (unsigned)(ssize.width-1) || + (unsigned)sy >= (unsigned)(ssize.height-1))) + continue; + else + { + sx0 = borderInterpolate(sx, ssize.width, borderType); + sx1 = borderInterpolate(sx+1, ssize.width, borderType); + sy0 = borderInterpolate(sy, ssize.height, borderType); + sy1 = borderInterpolate(sy+1, ssize.height, borderType); + v0 = sx0 >= 0 && sy0 >= 0 ? S0 + sy0*sstep + sx0*cn : &cval[0]; + v1 = sx1 >= 0 && sy0 >= 0 ? S0 + sy0*sstep + sx1*cn : &cval[0]; + v2 = sx0 >= 0 && sy1 >= 0 ? S0 + sy1*sstep + sx0*cn : &cval[0]; + v3 = sx1 >= 0 && sy1 >= 0 ? S0 + sy1*sstep + sx1*cn : &cval[0]; + } + for( k = 0; k < cn; k++ ) + D[k] = castOp(WT(v0[k]*w[0] + v1[k]*w[1] + v2[k]*w[2] + v3[k]*w[3])); + } + } + } + } + } +} + + +template +static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy, + const Mat& _fxy, const void* _wtab, + int borderType, const Scalar& _borderValue ) +{ + typedef typename CastOp::rtype T; + typedef typename CastOp::type1 WT; + Size ssize = _src.size(), dsize = _dst.size(); + int cn = _src.channels(); + const AT* wtab = (const AT*)_wtab; + const T* S0 = (const T*)_src.data; + size_t sstep = _src.step/sizeof(S0[0]); + Scalar_ cval(saturate_cast(_borderValue[0]), + saturate_cast(_borderValue[1]), + saturate_cast(_borderValue[2]), + saturate_cast(_borderValue[3])); + int dx, dy; + CastOp castOp; + int borderType1 = borderType != BORDER_TRANSPARENT ? borderType : BORDER_REFLECT_101; + + unsigned width1 = std::max(ssize.width-3, 0), height1 = std::max(ssize.height-3, 0); + + if( _dst.isContinuous() && _xy.isContinuous() && _fxy.isContinuous() ) + { + dsize.width *= dsize.height; + dsize.height = 1; + } + + for( dy = 0; dy < dsize.height; dy++ ) + { + T* D = (T*)(_dst.data + _dst.step*dy); + const short* XY = (const short*)(_xy.data + _xy.step*dy); + const ushort* FXY = (const ushort*)(_fxy.data + _fxy.step*dy); + + for( dx = 0; dx < dsize.width; dx++, D += cn ) + { + int sx = XY[dx*2]-1, sy = XY[dx*2+1]-1; + const AT* w = wtab + FXY[dx]*16; + int i, k; + if( (unsigned)sx < width1 && (unsigned)sy < height1 ) + { + const T* S = S0 + sy*sstep + sx*cn; + for( k = 0; k < cn; k++ ) + { + WT sum = S[0]*w[0] + S[cn]*w[1] + S[cn*2]*w[2] + S[cn*3]*w[3]; + S += sstep; + sum += S[0]*w[4] + S[cn]*w[5] + S[cn*2]*w[6] + S[cn*3]*w[7]; + S += sstep; + sum += S[0]*w[8] + S[cn]*w[9] + S[cn*2]*w[10] + S[cn*3]*w[11]; + S += sstep; + sum += S[0]*w[12] + S[cn]*w[13] + S[cn*2]*w[14] + S[cn*3]*w[15]; + S += 1 - sstep*3; + D[k] = castOp(sum); + } + } + else + { + int x[4], y[4]; + if( borderType == BORDER_TRANSPARENT && + ((unsigned)(sx+1) >= (unsigned)ssize.width || + (unsigned)(sy+1) >= (unsigned)ssize.height) ) + continue; + + if( borderType1 == BORDER_CONSTANT && + (sx >= ssize.width || sx+4 <= 0 || + sy >= ssize.height || sy+4 <= 0)) + { + for( k = 0; k < cn; k++ ) + D[k] = cval[k]; + continue; + } + + for( i = 0; i < 4; i++ ) + { + x[i] = borderInterpolate(sx + i, ssize.width, borderType1)*cn; + y[i] = borderInterpolate(sy + i, ssize.height, borderType1); + } + + for( k = 0; k < cn; k++, S0++, w -= 16 ) + { + WT cv = cval[k], sum = cv*ONE; + for( i = 0; i < 4; i++, w += 4 ) + { + int yi = y[i]; + const T* S = S0 + yi*sstep; + if( yi < 0 ) + continue; + if( x[0] >= 0 ) + sum += (S[x[0]] - cv)*w[0]; + if( x[1] >= 0 ) + sum += (S[x[1]] - cv)*w[1]; + if( x[2] >= 0 ) + sum += (S[x[2]] - cv)*w[2]; + if( x[3] >= 0 ) + sum += (S[x[3]] - cv)*w[3]; + } + D[k] = castOp(sum); + } + S0 -= cn; + } + } + } +} + + +template +static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy, + const Mat& _fxy, const void* _wtab, + int borderType, const Scalar& _borderValue ) +{ + typedef typename CastOp::rtype T; + typedef typename CastOp::type1 WT; + Size ssize = _src.size(), dsize = _dst.size(); + int cn = _src.channels(); + const AT* wtab = (const AT*)_wtab; + const T* S0 = (const T*)_src.data; + size_t sstep = _src.step/sizeof(S0[0]); + Scalar_ cval(saturate_cast(_borderValue[0]), + saturate_cast(_borderValue[1]), + saturate_cast(_borderValue[2]), + saturate_cast(_borderValue[3])); + int dx, dy; + CastOp castOp; + int borderType1 = borderType != BORDER_TRANSPARENT ? borderType : BORDER_REFLECT_101; + + unsigned width1 = std::max(ssize.width-7, 0), height1 = std::max(ssize.height-7, 0); + + if( _dst.isContinuous() && _xy.isContinuous() && _fxy.isContinuous() ) + { + dsize.width *= dsize.height; + dsize.height = 1; + } + + for( dy = 0; dy < dsize.height; dy++ ) + { + T* D = (T*)(_dst.data + _dst.step*dy); + const short* XY = (const short*)(_xy.data + _xy.step*dy); + const ushort* FXY = (const ushort*)(_fxy.data + _fxy.step*dy); + + for( dx = 0; dx < dsize.width; dx++, D += cn ) + { + int sx = XY[dx*2]-3, sy = XY[dx*2+1]-3; + const AT* w = wtab + FXY[dx]*64; + const T* S = S0 + sy*sstep + sx*cn; + int i, k; + if( (unsigned)sx < width1 && (unsigned)sy < height1 ) + { + for( k = 0; k < cn; k++ ) + { + WT sum = 0; + for( int r = 0; r < 8; r++, S += sstep, w += 8 ) + sum += S[0]*w[0] + S[cn]*w[1] + S[cn*2]*w[2] + S[cn*3]*w[3] + + S[cn*4]*w[4] + S[cn*5]*w[5] + S[cn*6]*w[6] + S[cn*7]*w[7]; + w -= 64; + S -= sstep*8 - 1; + D[k] = castOp(sum); + } + } + else + { + int x[8], y[8]; + if( borderType == BORDER_TRANSPARENT && + ((unsigned)(sx+3) >= (unsigned)ssize.width || + (unsigned)(sy+3) >= (unsigned)ssize.height) ) + continue; + + if( borderType1 == BORDER_CONSTANT && + (sx >= ssize.width || sx+8 <= 0 || + sy >= ssize.height || sy+8 <= 0)) + { + for( k = 0; k < cn; k++ ) + D[k] = cval[k]; + continue; + } + + for( i = 0; i < 8; i++ ) + { + x[i] = borderInterpolate(sx + i, ssize.width, borderType1)*cn; + y[i] = borderInterpolate(sy + i, ssize.height, borderType1); + } + + for( k = 0; k < cn; k++, S0++, w -= 64 ) + { + WT cv = cval[k], sum = cv*ONE; + for( i = 0; i < 8; i++, w += 8 ) + { + int yi = y[i]; + const T* S1 = S0 + yi*sstep; + if( yi < 0 ) + continue; + if( x[0] >= 0 ) + sum += (S1[x[0]] - cv)*w[0]; + if( x[1] >= 0 ) + sum += (S1[x[1]] - cv)*w[1]; + if( x[2] >= 0 ) + sum += (S1[x[2]] - cv)*w[2]; + if( x[3] >= 0 ) + sum += (S1[x[3]] - cv)*w[3]; + if( x[4] >= 0 ) + sum += (S1[x[4]] - cv)*w[4]; + if( x[5] >= 0 ) + sum += (S1[x[5]] - cv)*w[5]; + if( x[6] >= 0 ) + sum += (S1[x[6]] - cv)*w[6]; + if( x[7] >= 0 ) + sum += (S1[x[7]] - cv)*w[7]; + } + D[k] = castOp(sum); + } + S0 -= cn; + } + } + } +} + + +typedef void (*RemapNNFunc)(const Mat& _src, Mat& _dst, const Mat& _xy, + int borderType, const Scalar& _borderValue ); + +typedef void (*RemapFunc)(const Mat& _src, Mat& _dst, const Mat& _xy, + const Mat& _fxy, const void* _wtab, + int borderType, const Scalar& _borderValue); + +class remapInvoker : + public ParallelLoopBody +{ +public: + remapInvoker(const Mat& _src, Mat _dst, const Mat& _map1, const Mat& _map2, const Mat *_m1, + const Mat *_m2, int _interpolation, int _borderType, const Scalar &_borderValue, + int _planar_input, RemapNNFunc _nnfunc, RemapFunc _ifunc, const void *_ctab) : + ParallelLoopBody(), src(_src), dst(_dst), map1(_map1), map2(_map2), m1(_m1), m2(_m2), + interpolation(_interpolation), borderType(_borderType), borderValue(_borderValue), + planar_input(_planar_input), nnfunc(_nnfunc), ifunc(_ifunc), ctab(_ctab) + { + } + + virtual void operator() (const Range& range) const + { + int x, y, x1, y1; + const int buf_size = 1 << 14; + int brows0 = std::min(128, dst.rows), map_depth = map1.depth(); + int bcols0 = std::min(buf_size/brows0, dst.cols); + brows0 = std::min(buf_size/bcols0, dst.rows); + #if CV_SSE2 + bool useSIMD = checkHardwareSupport(CV_CPU_SSE2); + #endif + + Mat _bufxy(brows0, bcols0, CV_16SC2), _bufa; + if( !nnfunc ) + _bufa.create(brows0, bcols0, CV_16UC1); + + for( y = range.start; y < range.end; y += brows0 ) + { + for( x = 0; x < dst.cols; x += bcols0 ) + { + int brows = std::min(brows0, range.end - y); + int bcols = std::min(bcols0, dst.cols - x); + Mat dpart(dst, Rect(x, y, bcols, brows)); + Mat bufxy(_bufxy, Rect(0, 0, bcols, brows)); + + if( nnfunc ) + { + if( map1.type() == CV_16SC2 && !map2.data ) // the data is already in the right format + bufxy = map1(Rect(x, y, bcols, brows)); + else if( map_depth != CV_32F ) + { + for( y1 = 0; y1 < brows; y1++ ) + { + short* XY = (short*)(bufxy.data + bufxy.step*y1); + const short* sXY = (const short*)(m1->data + m1->step*(y+y1)) + x*2; + const ushort* sA = (const ushort*)(m2->data + m2->step*(y+y1)) + x; + + for( x1 = 0; x1 < bcols; x1++ ) + { + int a = sA[x1] & (INTER_TAB_SIZE2-1); + XY[x1*2] = sXY[x1*2] + NNDeltaTab_i[a][0]; + XY[x1*2+1] = sXY[x1*2+1] + NNDeltaTab_i[a][1]; + } + } + } + else if( !planar_input ) + map1(Rect(x, y, bcols, brows)).convertTo(bufxy, bufxy.depth()); + else + { + for( y1 = 0; y1 < brows; y1++ ) + { + short* XY = (short*)(bufxy.data + bufxy.step*y1); + const float* sX = (const float*)(map1.data + map1.step*(y+y1)) + x; + const float* sY = (const float*)(map2.data + map2.step*(y+y1)) + x; + x1 = 0; + + #if CV_SSE2 + if( useSIMD ) + { + for( ; x1 <= bcols - 8; x1 += 8 ) + { + __m128 fx0 = _mm_loadu_ps(sX + x1); + __m128 fx1 = _mm_loadu_ps(sX + x1 + 4); + __m128 fy0 = _mm_loadu_ps(sY + x1); + __m128 fy1 = _mm_loadu_ps(sY + x1 + 4); + __m128i ix0 = _mm_cvtps_epi32(fx0); + __m128i ix1 = _mm_cvtps_epi32(fx1); + __m128i iy0 = _mm_cvtps_epi32(fy0); + __m128i iy1 = _mm_cvtps_epi32(fy1); + ix0 = _mm_packs_epi32(ix0, ix1); + iy0 = _mm_packs_epi32(iy0, iy1); + ix1 = _mm_unpacklo_epi16(ix0, iy0); + iy1 = _mm_unpackhi_epi16(ix0, iy0); + _mm_storeu_si128((__m128i*)(XY + x1*2), ix1); + _mm_storeu_si128((__m128i*)(XY + x1*2 + 8), iy1); + } + } + #endif + + for( ; x1 < bcols; x1++ ) + { + XY[x1*2] = saturate_cast(sX[x1]); + XY[x1*2+1] = saturate_cast(sY[x1]); + } + } + } + nnfunc( src, dpart, bufxy, borderType, borderValue ); + continue; + } + + Mat bufa(_bufa, Rect(0, 0, bcols, brows)); + for( y1 = 0; y1 < brows; y1++ ) + { + short* XY = (short*)(bufxy.data + bufxy.step*y1); + ushort* A = (ushort*)(bufa.data + bufa.step*y1); + + if( (map1.type() == CV_16SC2 && (map2.type() == CV_16UC1 || map2.type() == CV_16SC1)) || + (map2.type() == CV_16SC2 && (map1.type() == CV_16UC1 || map1.type() == CV_16SC1)) ) + { + bufxy = m1->operator()(Rect(x, y, bcols, brows)); + bufa = m2->operator()(Rect(x, y, bcols, brows)); + } + else if( planar_input ) + { + const float* sX = (const float*)(map1.data + map1.step*(y+y1)) + x; + const float* sY = (const float*)(map2.data + map2.step*(y+y1)) + x; + + x1 = 0; + #if CV_SSE2 + if( useSIMD ) + { + __m128 scale = _mm_set1_ps((float)INTER_TAB_SIZE); + __m128i mask = _mm_set1_epi32(INTER_TAB_SIZE-1); + for( ; x1 <= bcols - 8; x1 += 8 ) + { + __m128 fx0 = _mm_loadu_ps(sX + x1); + __m128 fx1 = _mm_loadu_ps(sX + x1 + 4); + __m128 fy0 = _mm_loadu_ps(sY + x1); + __m128 fy1 = _mm_loadu_ps(sY + x1 + 4); + __m128i ix0 = _mm_cvtps_epi32(_mm_mul_ps(fx0, scale)); + __m128i ix1 = _mm_cvtps_epi32(_mm_mul_ps(fx1, scale)); + __m128i iy0 = _mm_cvtps_epi32(_mm_mul_ps(fy0, scale)); + __m128i iy1 = _mm_cvtps_epi32(_mm_mul_ps(fy1, scale)); + __m128i mx0 = _mm_and_si128(ix0, mask); + __m128i mx1 = _mm_and_si128(ix1, mask); + __m128i my0 = _mm_and_si128(iy0, mask); + __m128i my1 = _mm_and_si128(iy1, mask); + mx0 = _mm_packs_epi32(mx0, mx1); + my0 = _mm_packs_epi32(my0, my1); + my0 = _mm_slli_epi16(my0, INTER_BITS); + mx0 = _mm_or_si128(mx0, my0); + _mm_storeu_si128((__m128i*)(A + x1), mx0); + ix0 = _mm_srai_epi32(ix0, INTER_BITS); + ix1 = _mm_srai_epi32(ix1, INTER_BITS); + iy0 = _mm_srai_epi32(iy0, INTER_BITS); + iy1 = _mm_srai_epi32(iy1, INTER_BITS); + ix0 = _mm_packs_epi32(ix0, ix1); + iy0 = _mm_packs_epi32(iy0, iy1); + ix1 = _mm_unpacklo_epi16(ix0, iy0); + iy1 = _mm_unpackhi_epi16(ix0, iy0); + _mm_storeu_si128((__m128i*)(XY + x1*2), ix1); + _mm_storeu_si128((__m128i*)(XY + x1*2 + 8), iy1); + } + } + #endif + + for( ; x1 < bcols; x1++ ) + { + int sx = cvRound(sX[x1]*INTER_TAB_SIZE); + int sy = cvRound(sY[x1]*INTER_TAB_SIZE); + int v = (sy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (sx & (INTER_TAB_SIZE-1)); + XY[x1*2] = (short)(sx >> INTER_BITS); + XY[x1*2+1] = (short)(sy >> INTER_BITS); + A[x1] = (ushort)v; + } + } + else + { + const float* sXY = (const float*)(map1.data + map1.step*(y+y1)) + x*2; + + for( x1 = 0; x1 < bcols; x1++ ) + { + int sx = cvRound(sXY[x1*2]*INTER_TAB_SIZE); + int sy = cvRound(sXY[x1*2+1]*INTER_TAB_SIZE); + int v = (sy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (sx & (INTER_TAB_SIZE-1)); + XY[x1*2] = (short)(sx >> INTER_BITS); + XY[x1*2+1] = (short)(sy >> INTER_BITS); + A[x1] = (ushort)v; + } + } + } + ifunc(src, dpart, bufxy, bufa, ctab, borderType, borderValue); + } + } + } + +private: + const Mat src; + Mat dst; + const Mat map1, map2, *m1, *m2; + int interpolation, borderType; + const Scalar borderValue; + int planar_input; + RemapNNFunc nnfunc; + RemapFunc ifunc; + const void *ctab; + + remapInvoker(const remapInvoker&); + remapInvoker& operator=(const remapInvoker&); +}; + +} + +void cv::remap( InputArray _src, OutputArray _dst, + InputArray _map1, InputArray _map2, + int interpolation, int borderType, const Scalar& borderValue ) +{ + static RemapNNFunc nn_tab[] = + { + remapNearest, remapNearest, remapNearest, remapNearest, + remapNearest, remapNearest, remapNearest, 0 + }; + + static RemapFunc linear_tab[] = + { + remapBilinear, RemapVec_8u, short>, 0, + remapBilinear, RemapNoVec, float>, + remapBilinear, RemapNoVec, float>, 0, + remapBilinear, RemapNoVec, float>, + remapBilinear, RemapNoVec, float>, 0 + }; + + static RemapFunc cubic_tab[] = + { + remapBicubic, short, INTER_REMAP_COEF_SCALE>, 0, + remapBicubic, float, 1>, + remapBicubic, float, 1>, 0, + remapBicubic, float, 1>, + remapBicubic, float, 1>, 0 + }; + + static RemapFunc lanczos4_tab[] = + { + remapLanczos4, short, INTER_REMAP_COEF_SCALE>, 0, + remapLanczos4, float, 1>, + remapLanczos4, float, 1>, 0, + remapLanczos4, float, 1>, + remapLanczos4, float, 1>, 0 + }; + + Mat src = _src.getMat(), map1 = _map1.getMat(), map2 = _map2.getMat(); + + CV_Assert( map1.size().area() > 0 ); + CV_Assert( !map2.data || (map2.size() == map1.size())); + + _dst.create( map1.size(), src.type() ); + Mat dst = _dst.getMat(); + if( dst.data == src.data ) + src = src.clone(); + + int depth = src.depth(); + RemapNNFunc nnfunc = 0; + RemapFunc ifunc = 0; + const void* ctab = 0; + bool fixpt = depth == CV_8U; + bool planar_input = false; + + if( interpolation == INTER_NEAREST ) + { + nnfunc = nn_tab[depth]; + CV_Assert( nnfunc != 0 ); + } + else + { + if( interpolation == INTER_AREA ) + interpolation = INTER_LINEAR; + + if( interpolation == INTER_LINEAR ) + ifunc = linear_tab[depth]; + else if( interpolation == INTER_CUBIC ) + ifunc = cubic_tab[depth]; + else if( interpolation == INTER_LANCZOS4 ) + ifunc = lanczos4_tab[depth]; + else + CV_Error( CV_StsBadArg, "Unknown interpolation method" ); + CV_Assert( ifunc != 0 ); + ctab = initInterTab2D( interpolation, fixpt ); + } + + const Mat *m1 = &map1, *m2 = &map2; + + if( (map1.type() == CV_16SC2 && (map2.type() == CV_16UC1 || map2.type() == CV_16SC1)) || + (map2.type() == CV_16SC2 && (map1.type() == CV_16UC1 || map1.type() == CV_16SC1)) ) + { + if( map1.type() != CV_16SC2 ) + std::swap(m1, m2); + } + else + { + CV_Assert( ((map1.type() == CV_32FC2 || map1.type() == CV_16SC2) && !map2.data) || + (map1.type() == CV_32FC1 && map2.type() == CV_32FC1) ); + planar_input = map1.channels() == 1; + } + + Range range(0, dst.rows); + remapInvoker invoker(src, dst, map1, map2, m1, m2, interpolation, + borderType, borderValue, planar_input, nnfunc, ifunc, + ctab); + parallel_for_(range, invoker); +} + + +void cv::convertMaps( InputArray _map1, InputArray _map2, + OutputArray _dstmap1, OutputArray _dstmap2, + int dstm1type, bool nninterpolate ) +{ + Mat map1 = _map1.getMat(), map2 = _map2.getMat(), dstmap1, dstmap2; + Size size = map1.size(); + const Mat *m1 = &map1, *m2 = &map2; + int m1type = m1->type(), m2type = m2->type(); + + CV_Assert( (m1type == CV_16SC2 && (nninterpolate || m2type == CV_16UC1 || m2type == CV_16SC1)) || + (m2type == CV_16SC2 && (nninterpolate || m1type == CV_16UC1 || m1type == CV_16SC1)) || + (m1type == CV_32FC1 && m2type == CV_32FC1) || + (m1type == CV_32FC2 && !m2->data) ); + + if( m2type == CV_16SC2 ) + { + std::swap( m1, m2 ); + std::swap( m1type, m2type ); + } + + if( dstm1type <= 0 ) + dstm1type = m1type == CV_16SC2 ? CV_32FC2 : CV_16SC2; + CV_Assert( dstm1type == CV_16SC2 || dstm1type == CV_32FC1 || dstm1type == CV_32FC2 ); + _dstmap1.create( size, dstm1type ); + dstmap1 = _dstmap1.getMat(); + + if( !nninterpolate && dstm1type != CV_32FC2 ) + { + _dstmap2.create( size, dstm1type == CV_16SC2 ? CV_16UC1 : CV_32FC1 ); + dstmap2 = _dstmap2.getMat(); + } + else + _dstmap2.release(); + + if( m1type == dstm1type || (nninterpolate && + ((m1type == CV_16SC2 && dstm1type == CV_32FC2) || + (m1type == CV_32FC2 && dstm1type == CV_16SC2))) ) + { + m1->convertTo( dstmap1, dstmap1.type() ); + if( dstmap2.data && dstmap2.type() == m2->type() ) + m2->copyTo( dstmap2 ); + return; + } + + if( m1type == CV_32FC1 && dstm1type == CV_32FC2 ) + { + Mat vdata[] = { *m1, *m2 }; + merge( vdata, 2, dstmap1 ); + return; + } + + if( m1type == CV_32FC2 && dstm1type == CV_32FC1 ) + { + Mat mv[] = { dstmap1, dstmap2 }; + split( *m1, mv ); + return; + } + + if( m1->isContinuous() && (!m2->data || m2->isContinuous()) && + dstmap1.isContinuous() && (!dstmap2.data || dstmap2.isContinuous()) ) + { + size.width *= size.height; + size.height = 1; + } + + const float scale = 1.f/INTER_TAB_SIZE; + int x, y; + for( y = 0; y < size.height; y++ ) + { + const float* src1f = (const float*)(m1->data + m1->step*y); + const float* src2f = (const float*)(m2->data + m2->step*y); + const short* src1 = (const short*)src1f; + const ushort* src2 = (const ushort*)src2f; + + float* dst1f = (float*)(dstmap1.data + dstmap1.step*y); + float* dst2f = (float*)(dstmap2.data + dstmap2.step*y); + short* dst1 = (short*)dst1f; + ushort* dst2 = (ushort*)dst2f; + + if( m1type == CV_32FC1 && dstm1type == CV_16SC2 ) + { + if( nninterpolate ) + for( x = 0; x < size.width; x++ ) + { + dst1[x*2] = saturate_cast(src1f[x]); + dst1[x*2+1] = saturate_cast(src2f[x]); + } + else + for( x = 0; x < size.width; x++ ) + { + int ix = saturate_cast(src1f[x]*INTER_TAB_SIZE); + int iy = saturate_cast(src2f[x]*INTER_TAB_SIZE); + dst1[x*2] = (short)(ix >> INTER_BITS); + dst1[x*2+1] = (short)(iy >> INTER_BITS); + dst2[x] = (ushort)((iy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (ix & (INTER_TAB_SIZE-1))); + } + } + else if( m1type == CV_32FC2 && dstm1type == CV_16SC2 ) + { + if( nninterpolate ) + for( x = 0; x < size.width; x++ ) + { + dst1[x*2] = saturate_cast(src1f[x*2]); + dst1[x*2+1] = saturate_cast(src1f[x*2+1]); + } + else + for( x = 0; x < size.width; x++ ) + { + int ix = saturate_cast(src1f[x*2]*INTER_TAB_SIZE); + int iy = saturate_cast(src1f[x*2+1]*INTER_TAB_SIZE); + dst1[x*2] = (short)(ix >> INTER_BITS); + dst1[x*2+1] = (short)(iy >> INTER_BITS); + dst2[x] = (ushort)((iy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (ix & (INTER_TAB_SIZE-1))); + } + } + else if( m1type == CV_16SC2 && dstm1type == CV_32FC1 ) + { + for( x = 0; x < size.width; x++ ) + { + int fxy = src2 ? src2[x] : 0; + dst1f[x] = src1[x*2] + (fxy & (INTER_TAB_SIZE-1))*scale; + dst2f[x] = src1[x*2+1] + (fxy >> INTER_BITS)*scale; + } + } + else if( m1type == CV_16SC2 && dstm1type == CV_32FC2 ) + { + for( x = 0; x < size.width; x++ ) + { + int fxy = src2 ? src2[x] : 0; + dst1f[x*2] = src1[x*2] + (fxy & (INTER_TAB_SIZE-1))*scale; + dst1f[x*2+1] = src1[x*2+1] + (fxy >> INTER_BITS)*scale; + } + } + else + CV_Error( CV_StsNotImplemented, "Unsupported combination of input/output matrices" ); + } +} + + +namespace cv +{ + +class warpAffineInvoker : + public ParallelLoopBody +{ +public: + warpAffineInvoker(const Mat &_src, Mat &_dst, int _interpolation, int _borderType, + const Scalar &_borderValue, int *_adelta, int *_bdelta, double *_M) : + ParallelLoopBody(), src(_src), dst(_dst), interpolation(_interpolation), + borderType(_borderType), borderValue(_borderValue), adelta(_adelta), bdelta(_bdelta), + M(_M) + { + } + + virtual void operator() (const Range& range) const + { + const int BLOCK_SZ = 64; + short XY[BLOCK_SZ*BLOCK_SZ*2], A[BLOCK_SZ*BLOCK_SZ]; + const int AB_BITS = MAX(10, (int)INTER_BITS); + const int AB_SCALE = 1 << AB_BITS; + int round_delta = interpolation == INTER_NEAREST ? AB_SCALE/2 : AB_SCALE/INTER_TAB_SIZE/2, x, y, x1, y1; + #if CV_SSE2 + bool useSIMD = checkHardwareSupport(CV_CPU_SSE2); + #endif + + int bh0 = std::min(BLOCK_SZ/2, dst.rows); + int bw0 = std::min(BLOCK_SZ*BLOCK_SZ/bh0, dst.cols); + bh0 = std::min(BLOCK_SZ*BLOCK_SZ/bw0, dst.rows); + + for( y = range.start; y < range.end; y += bh0 ) + { + for( x = 0; x < dst.cols; x += bw0 ) + { + int bw = std::min( bw0, dst.cols - x); + int bh = std::min( bh0, range.end - y); + + Mat _XY(bh, bw, CV_16SC2, XY), matA; + Mat dpart(dst, Rect(x, y, bw, bh)); + + for( y1 = 0; y1 < bh; y1++ ) + { + short* xy = XY + y1*bw*2; + int X0 = saturate_cast((M[1]*(y + y1) + M[2])*AB_SCALE) + round_delta; + int Y0 = saturate_cast((M[4]*(y + y1) + M[5])*AB_SCALE) + round_delta; + + if( interpolation == INTER_NEAREST ) + for( x1 = 0; x1 < bw; x1++ ) + { + int X = (X0 + adelta[x+x1]) >> AB_BITS; + int Y = (Y0 + bdelta[x+x1]) >> AB_BITS; + xy[x1*2] = saturate_cast(X); + xy[x1*2+1] = saturate_cast(Y); + } + else + { + short* alpha = A + y1*bw; + x1 = 0; + #if CV_SSE2 + if( useSIMD ) + { + __m128i fxy_mask = _mm_set1_epi32(INTER_TAB_SIZE - 1); + __m128i XX = _mm_set1_epi32(X0), YY = _mm_set1_epi32(Y0); + for( ; x1 <= bw - 8; x1 += 8 ) + { + __m128i tx0, tx1, ty0, ty1; + tx0 = _mm_add_epi32(_mm_loadu_si128((const __m128i*)(adelta + x + x1)), XX); + ty0 = _mm_add_epi32(_mm_loadu_si128((const __m128i*)(bdelta + x + x1)), YY); + tx1 = _mm_add_epi32(_mm_loadu_si128((const __m128i*)(adelta + x + x1 + 4)), XX); + ty1 = _mm_add_epi32(_mm_loadu_si128((const __m128i*)(bdelta + x + x1 + 4)), YY); + + tx0 = _mm_srai_epi32(tx0, AB_BITS - INTER_BITS); + ty0 = _mm_srai_epi32(ty0, AB_BITS - INTER_BITS); + tx1 = _mm_srai_epi32(tx1, AB_BITS - INTER_BITS); + ty1 = _mm_srai_epi32(ty1, AB_BITS - INTER_BITS); + + __m128i fx_ = _mm_packs_epi32(_mm_and_si128(tx0, fxy_mask), + _mm_and_si128(tx1, fxy_mask)); + __m128i fy_ = _mm_packs_epi32(_mm_and_si128(ty0, fxy_mask), + _mm_and_si128(ty1, fxy_mask)); + tx0 = _mm_packs_epi32(_mm_srai_epi32(tx0, INTER_BITS), + _mm_srai_epi32(tx1, INTER_BITS)); + ty0 = _mm_packs_epi32(_mm_srai_epi32(ty0, INTER_BITS), + _mm_srai_epi32(ty1, INTER_BITS)); + fx_ = _mm_adds_epi16(fx_, _mm_slli_epi16(fy_, INTER_BITS)); + + _mm_storeu_si128((__m128i*)(xy + x1*2), _mm_unpacklo_epi16(tx0, ty0)); + _mm_storeu_si128((__m128i*)(xy + x1*2 + 8), _mm_unpackhi_epi16(tx0, ty0)); + _mm_storeu_si128((__m128i*)(alpha + x1), fx_); + } + } + #endif + for( ; x1 < bw; x1++ ) + { + int X = (X0 + adelta[x+x1]) >> (AB_BITS - INTER_BITS); + int Y = (Y0 + bdelta[x+x1]) >> (AB_BITS - INTER_BITS); + xy[x1*2] = saturate_cast(X >> INTER_BITS); + xy[x1*2+1] = saturate_cast(Y >> INTER_BITS); + alpha[x1] = (short)((Y & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + + (X & (INTER_TAB_SIZE-1))); + } + } + } + + if( interpolation == INTER_NEAREST ) + remap( src, dpart, _XY, Mat(), interpolation, borderType, borderValue ); + else + { + Mat _matA(bh, bw, CV_16U, A); + remap( src, dpart, _XY, _matA, interpolation, borderType, borderValue ); + } + } + } + } + +private: + const Mat src; + Mat dst; + int interpolation, borderType; + const Scalar borderValue; + int *adelta, *bdelta; + double *M; + + warpAffineInvoker(const warpAffineInvoker&); + warpAffineInvoker& operator=(const warpAffineInvoker&); +}; + +} + + +void cv::warpAffine( InputArray _src, OutputArray _dst, + InputArray _M0, Size dsize, + int flags, int borderType, const Scalar& borderValue ) +{ + Mat src = _src.getMat(), M0 = _M0.getMat(); + _dst.create( dsize.area() == 0 ? src.size() : dsize, src.type() ); + Mat dst = _dst.getMat(); + CV_Assert( src.cols > 0 && src.rows > 0 ); + if( dst.data == src.data ) + src = src.clone(); + + double M[6]; + Mat matM(2, 3, CV_64F, M); + int interpolation = flags & INTER_MAX; + if( interpolation == INTER_AREA ) + interpolation = INTER_LINEAR; + + CV_Assert( (M0.type() == CV_32F || M0.type() == CV_64F) && M0.rows == 2 && M0.cols == 3 ); + M0.convertTo(matM, matM.type()); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if( tegra::warpAffine(src, dst, M, flags, borderType, borderValue) ) + return; +#endif + + if( !(flags & WARP_INVERSE_MAP) ) + { + double D = M[0]*M[4] - M[1]*M[3]; + D = D != 0 ? 1./D : 0; + double A11 = M[4]*D, A22=M[0]*D; + M[0] = A11; M[1] *= -D; + M[3] *= -D; M[4] = A22; + double b1 = -M[0]*M[2] - M[1]*M[5]; + double b2 = -M[3]*M[2] - M[4]*M[5]; + M[2] = b1; M[5] = b2; + } + + int x; + AutoBuffer _abdelta(dst.cols*2); + int* adelta = &_abdelta[0], *bdelta = adelta + dst.cols; + const int AB_BITS = MAX(10, (int)INTER_BITS); + const int AB_SCALE = 1 << AB_BITS; + + for( x = 0; x < dst.cols; x++ ) + { + adelta[x] = saturate_cast(M[0]*x*AB_SCALE); + bdelta[x] = saturate_cast(M[3]*x*AB_SCALE); + } + + Range range(0, dst.rows); + warpAffineInvoker invoker(src, dst, interpolation, borderType, + borderValue, adelta, bdelta, M); + parallel_for_(range, invoker); +} + + +namespace cv +{ + +class warpPerspectiveInvoker : + public ParallelLoopBody +{ +public: + + warpPerspectiveInvoker(const Mat &_src, Mat &_dst, double *_M, int _interpolation, + int _borderType, const Scalar &_borderValue) : + ParallelLoopBody(), src(_src), dst(_dst), M(_M), interpolation(_interpolation), + borderType(_borderType), borderValue(_borderValue) + { + } + + virtual void operator() (const Range& range) const + { + const int BLOCK_SZ = 32; + short XY[BLOCK_SZ*BLOCK_SZ*2], A[BLOCK_SZ*BLOCK_SZ]; + int x, y, x1, y1, width = dst.cols, height = dst.rows; + + int bh0 = std::min(BLOCK_SZ/2, height); + int bw0 = std::min(BLOCK_SZ*BLOCK_SZ/bh0, width); + bh0 = std::min(BLOCK_SZ*BLOCK_SZ/bw0, height); + + for( y = range.start; y < range.end; y += bh0 ) + { + for( x = 0; x < width; x += bw0 ) + { + int bw = std::min( bw0, width - x); + int bh = std::min( bh0, range.end - y); // height + + Mat _XY(bh, bw, CV_16SC2, XY), matA; + Mat dpart(dst, Rect(x, y, bw, bh)); + + for( y1 = 0; y1 < bh; y1++ ) + { + short* xy = XY + y1*bw*2; + double X0 = M[0]*x + M[1]*(y + y1) + M[2]; + double Y0 = M[3]*x + M[4]*(y + y1) + M[5]; + double W0 = M[6]*x + M[7]*(y + y1) + M[8]; + + if( interpolation == INTER_NEAREST ) + for( x1 = 0; x1 < bw; x1++ ) + { + double W = W0 + M[6]*x1; + W = W ? 1./W : 0; + double fX = std::max((double)INT_MIN, std::min((double)INT_MAX, (X0 + M[0]*x1)*W)); + double fY = std::max((double)INT_MIN, std::min((double)INT_MAX, (Y0 + M[3]*x1)*W)); + int X = saturate_cast(fX); + int Y = saturate_cast(fY); + + xy[x1*2] = saturate_cast(X); + xy[x1*2+1] = saturate_cast(Y); + } + else + { + short* alpha = A + y1*bw; + for( x1 = 0; x1 < bw; x1++ ) + { + double W = W0 + M[6]*x1; + W = W ? INTER_TAB_SIZE/W : 0; + double fX = std::max((double)INT_MIN, std::min((double)INT_MAX, (X0 + M[0]*x1)*W)); + double fY = std::max((double)INT_MIN, std::min((double)INT_MAX, (Y0 + M[3]*x1)*W)); + int X = saturate_cast(fX); + int Y = saturate_cast(fY); + + xy[x1*2] = saturate_cast(X >> INTER_BITS); + xy[x1*2+1] = saturate_cast(Y >> INTER_BITS); + alpha[x1] = (short)((Y & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + + (X & (INTER_TAB_SIZE-1))); + } + } + } + + if( interpolation == INTER_NEAREST ) + remap( src, dpart, _XY, Mat(), interpolation, borderType, borderValue ); + else + { + Mat _matA(bh, bw, CV_16U, A); + remap( src, dpart, _XY, _matA, interpolation, borderType, borderValue ); + } + } + } + } + +private: + const Mat src; + Mat dst; + double* M; + int interpolation, borderType; + const Scalar borderValue; + warpPerspectiveInvoker(const warpPerspectiveInvoker&); + warpPerspectiveInvoker& operator=(const warpPerspectiveInvoker&); +}; + +} + +void cv::warpPerspective( InputArray _src, OutputArray _dst, InputArray _M0, + Size dsize, int flags, int borderType, const Scalar& borderValue ) +{ + Mat src = _src.getMat(), M0 = _M0.getMat(); + _dst.create( dsize.area() == 0 ? src.size() : dsize, src.type() ); + Mat dst = _dst.getMat(); + + CV_Assert( src.cols > 0 && src.rows > 0 ); + if( dst.data == src.data ) + src = src.clone(); + + double M[9]; + Mat matM(3, 3, CV_64F, M); + int interpolation = flags & INTER_MAX; + if( interpolation == INTER_AREA ) + interpolation = INTER_LINEAR; + + CV_Assert( (M0.type() == CV_32F || M0.type() == CV_64F) && M0.rows == 3 && M0.cols == 3 ); + M0.convertTo(matM, matM.type()); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if( tegra::warpPerspective(src, dst, M, flags, borderType, borderValue) ) + return; +#endif + + if( !(flags & WARP_INVERSE_MAP) ) + invert(matM, matM); + + Range range(0, dst.rows); + warpPerspectiveInvoker invoker(src, dst, M, interpolation, borderType, borderValue); + parallel_for_(range, invoker); +} + + +cv::Mat cv::getRotationMatrix2D( Point2f center, double angle, double scale ) +{ + angle *= CV_PI/180; + double alpha = cos(angle)*scale; + double beta = sin(angle)*scale; + + Mat M(2, 3, CV_64F); + double* m = (double*)M.data; + + m[0] = alpha; + m[1] = beta; + m[2] = (1-alpha)*center.x - beta*center.y; + m[3] = -beta; + m[4] = alpha; + m[5] = beta*center.x + (1-alpha)*center.y; + + return M; +} + +/* Calculates coefficients of perspective transformation + * which maps (xi,yi) to (ui,vi), (i=1,2,3,4): + * + * c00*xi + c01*yi + c02 + * ui = --------------------- + * c20*xi + c21*yi + c22 + * + * c10*xi + c11*yi + c12 + * vi = --------------------- + * c20*xi + c21*yi + c22 + * + * Coefficients are calculated by solving linear system: + * / x0 y0 1 0 0 0 -x0*u0 -y0*u0 \ /c00\ /u0\ + * | x1 y1 1 0 0 0 -x1*u1 -y1*u1 | |c01| |u1| + * | x2 y2 1 0 0 0 -x2*u2 -y2*u2 | |c02| |u2| + * | x3 y3 1 0 0 0 -x3*u3 -y3*u3 |.|c10|=|u3|, + * | 0 0 0 x0 y0 1 -x0*v0 -y0*v0 | |c11| |v0| + * | 0 0 0 x1 y1 1 -x1*v1 -y1*v1 | |c12| |v1| + * | 0 0 0 x2 y2 1 -x2*v2 -y2*v2 | |c20| |v2| + * \ 0 0 0 x3 y3 1 -x3*v3 -y3*v3 / \c21/ \v3/ + * + * where: + * cij - matrix coefficients, c22 = 1 + */ +cv::Mat cv::getPerspectiveTransform( const Point2f src[], const Point2f dst[] ) +{ + Mat M(3, 3, CV_64F), X(8, 1, CV_64F, M.data); + double a[8][8], b[8]; + Mat A(8, 8, CV_64F, a), B(8, 1, CV_64F, b); + + for( int i = 0; i < 4; ++i ) + { + a[i][0] = a[i+4][3] = src[i].x; + a[i][1] = a[i+4][4] = src[i].y; + a[i][2] = a[i+4][5] = 1; + a[i][3] = a[i][4] = a[i][5] = + a[i+4][0] = a[i+4][1] = a[i+4][2] = 0; + a[i][6] = -src[i].x*dst[i].x; + a[i][7] = -src[i].y*dst[i].x; + a[i+4][6] = -src[i].x*dst[i].y; + a[i+4][7] = -src[i].y*dst[i].y; + b[i] = dst[i].x; + b[i+4] = dst[i].y; + } + + solve( A, B, X, DECOMP_SVD ); + ((double*)M.data)[8] = 1.; + + return M; +} + +/* Calculates coefficients of affine transformation + * which maps (xi,yi) to (ui,vi), (i=1,2,3): + * + * ui = c00*xi + c01*yi + c02 + * + * vi = c10*xi + c11*yi + c12 + * + * Coefficients are calculated by solving linear system: + * / x0 y0 1 0 0 0 \ /c00\ /u0\ + * | x1 y1 1 0 0 0 | |c01| |u1| + * | x2 y2 1 0 0 0 | |c02| |u2| + * | 0 0 0 x0 y0 1 | |c10| |v0| + * | 0 0 0 x1 y1 1 | |c11| |v1| + * \ 0 0 0 x2 y2 1 / |c12| |v2| + * + * where: + * cij - matrix coefficients + */ + +cv::Mat cv::getAffineTransform( const Point2f src[], const Point2f dst[] ) +{ + Mat M(2, 3, CV_64F), X(6, 1, CV_64F, M.data); + double a[6*6], b[6]; + Mat A(6, 6, CV_64F, a), B(6, 1, CV_64F, b); + + for( int i = 0; i < 3; i++ ) + { + int j = i*12; + int k = i*12+6; + a[j] = a[k+3] = src[i].x; + a[j+1] = a[k+4] = src[i].y; + a[j+2] = a[k+5] = 1; + a[j+3] = a[j+4] = a[j+5] = 0; + a[k] = a[k+1] = a[k+2] = 0; + b[i*2] = dst[i].x; + b[i*2+1] = dst[i].y; + } + + solve( A, B, X ); + return M; +} + +void cv::invertAffineTransform(InputArray _matM, OutputArray __iM) +{ + Mat matM = _matM.getMat(); + CV_Assert(matM.rows == 2 && matM.cols == 3); + __iM.create(2, 3, matM.type()); + Mat _iM = __iM.getMat(); + + if( matM.type() == CV_32F ) + { + const float* M = (const float*)matM.data; + float* iM = (float*)_iM.data; + int step = (int)(matM.step/sizeof(M[0])), istep = (int)(_iM.step/sizeof(iM[0])); + + double D = M[0]*M[step+1] - M[1]*M[step]; + D = D != 0 ? 1./D : 0; + double A11 = M[step+1]*D, A22 = M[0]*D, A12 = -M[1]*D, A21 = -M[step]*D; + double b1 = -A11*M[2] - A12*M[step+2]; + double b2 = -A21*M[2] - A22*M[step+2]; + + iM[0] = (float)A11; iM[1] = (float)A12; iM[2] = (float)b1; + iM[istep] = (float)A21; iM[istep+1] = (float)A22; iM[istep+2] = (float)b2; + } + else if( matM.type() == CV_64F ) + { + const double* M = (const double*)matM.data; + double* iM = (double*)_iM.data; + int step = (int)(matM.step/sizeof(M[0])), istep = (int)(_iM.step/sizeof(iM[0])); + + double D = M[0]*M[step+1] - M[1]*M[step]; + D = D != 0 ? 1./D : 0; + double A11 = M[step+1]*D, A22 = M[0]*D, A12 = -M[1]*D, A21 = -M[step]*D; + double b1 = -A11*M[2] - A12*M[step+2]; + double b2 = -A21*M[2] - A22*M[step+2]; + + iM[0] = A11; iM[1] = A12; iM[2] = b1; + iM[istep] = A21; iM[istep+1] = A22; iM[istep+2] = b2; + } + else + CV_Error( CV_StsUnsupportedFormat, "" ); +} + +cv::Mat cv::getPerspectiveTransform(InputArray _src, InputArray _dst) +{ + Mat src = _src.getMat(), dst = _dst.getMat(); + CV_Assert(src.checkVector(2, CV_32F) == 4 && dst.checkVector(2, CV_32F) == 4); + return getPerspectiveTransform((const Point2f*)src.data, (const Point2f*)dst.data); +} + +cv::Mat cv::getAffineTransform(InputArray _src, InputArray _dst) +{ + Mat src = _src.getMat(), dst = _dst.getMat(); + CV_Assert(src.checkVector(2, CV_32F) == 3 && dst.checkVector(2, CV_32F) == 3); + return getAffineTransform((const Point2f*)src.data, (const Point2f*)dst.data); +} + +CV_IMPL void +cvResize( const CvArr* srcarr, CvArr* dstarr, int method ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + CV_Assert( src.type() == dst.type() ); + cv::resize( src, dst, dst.size(), (double)dst.cols/src.cols, + (double)dst.rows/src.rows, method ); +} + + +CV_IMPL void +cvWarpAffine( const CvArr* srcarr, CvArr* dstarr, const CvMat* marr, + int flags, CvScalar fillval ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + cv::Mat matrix = cv::cvarrToMat(marr); + CV_Assert( src.type() == dst.type() ); + cv::warpAffine( src, dst, matrix, dst.size(), flags, + (flags & CV_WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT, + fillval ); +} + +CV_IMPL void +cvWarpPerspective( const CvArr* srcarr, CvArr* dstarr, const CvMat* marr, + int flags, CvScalar fillval ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + cv::Mat matrix = cv::cvarrToMat(marr); + CV_Assert( src.type() == dst.type() ); + cv::warpPerspective( src, dst, matrix, dst.size(), flags, + (flags & CV_WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT, + fillval ); +} + +CV_IMPL void +cvRemap( const CvArr* srcarr, CvArr* dstarr, + const CvArr* _mapx, const CvArr* _mapy, + int flags, CvScalar fillval ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), dst0 = dst; + cv::Mat mapx = cv::cvarrToMat(_mapx), mapy = cv::cvarrToMat(_mapy); + CV_Assert( src.type() == dst.type() && dst.size() == mapx.size() ); + cv::remap( src, dst, mapx, mapy, flags & cv::INTER_MAX, + (flags & CV_WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT, + fillval ); + CV_Assert( dst0.data == dst.data ); +} + + +CV_IMPL CvMat* +cv2DRotationMatrix( CvPoint2D32f center, double angle, + double scale, CvMat* matrix ) +{ + cv::Mat M0 = cv::cvarrToMat(matrix), M = cv::getRotationMatrix2D(center, angle, scale); + CV_Assert( M.size() == M.size() ); + M.convertTo(M0, M0.type()); + return matrix; +} + + +CV_IMPL CvMat* +cvGetPerspectiveTransform( const CvPoint2D32f* src, + const CvPoint2D32f* dst, + CvMat* matrix ) +{ + cv::Mat M0 = cv::cvarrToMat(matrix), + M = cv::getPerspectiveTransform((const cv::Point2f*)src, (const cv::Point2f*)dst); + CV_Assert( M.size() == M.size() ); + M.convertTo(M0, M0.type()); + return matrix; +} + + +CV_IMPL CvMat* +cvGetAffineTransform( const CvPoint2D32f* src, + const CvPoint2D32f* dst, + CvMat* matrix ) +{ + cv::Mat M0 = cv::cvarrToMat(matrix), + M = cv::getAffineTransform((const cv::Point2f*)src, (const cv::Point2f*)dst); + CV_Assert( M.size() == M0.size() ); + M.convertTo(M0, M0.type()); + return matrix; +} + + +CV_IMPL void +cvConvertMaps( const CvArr* arr1, const CvArr* arr2, CvArr* dstarr1, CvArr* dstarr2 ) +{ + cv::Mat map1 = cv::cvarrToMat(arr1), map2; + cv::Mat dstmap1 = cv::cvarrToMat(dstarr1), dstmap2; + + if( arr2 ) + map2 = cv::cvarrToMat(arr2); + if( dstarr2 ) + { + dstmap2 = cv::cvarrToMat(dstarr2); + if( dstmap2.type() == CV_16SC1 ) + dstmap2 = cv::Mat(dstmap2.size(), CV_16UC1, dstmap2.data, dstmap2.step); + } + + cv::convertMaps( map1, map2, dstmap1, dstmap2, dstmap1.type(), false ); +} + +/****************************************************************************************\ +* Log-Polar Transform * +\****************************************************************************************/ + +/* now it is done via Remap; more correct implementation should use + some super-sampling technique outside of the "fovea" circle */ +CV_IMPL void +cvLogPolar( const CvArr* srcarr, CvArr* dstarr, + CvPoint2D32f center, double M, int flags ) +{ + cv::Ptr mapx, mapy; + + CvMat srcstub, *src = cvGetMat(srcarr, &srcstub); + CvMat dststub, *dst = cvGetMat(dstarr, &dststub); + CvSize ssize, dsize; + + if( !CV_ARE_TYPES_EQ( src, dst )) + CV_Error( CV_StsUnmatchedFormats, "" ); + + if( M <= 0 ) + CV_Error( CV_StsOutOfRange, "M should be >0" ); + + ssize = cvGetMatSize(src); + dsize = cvGetMatSize(dst); + + mapx = cvCreateMat( dsize.height, dsize.width, CV_32F ); + mapy = cvCreateMat( dsize.height, dsize.width, CV_32F ); + + if( !(flags & CV_WARP_INVERSE_MAP) ) + { + int phi, rho; + cv::AutoBuffer _exp_tab(dsize.width); + double* exp_tab = _exp_tab; + + for( rho = 0; rho < dst->width; rho++ ) + exp_tab[rho] = std::exp(rho/M); + + for( phi = 0; phi < dsize.height; phi++ ) + { + double cp = cos(phi*2*CV_PI/dsize.height); + double sp = sin(phi*2*CV_PI/dsize.height); + float* mx = (float*)(mapx->data.ptr + phi*mapx->step); + float* my = (float*)(mapy->data.ptr + phi*mapy->step); + + for( rho = 0; rho < dsize.width; rho++ ) + { + double r = exp_tab[rho]; + double x = r*cp + center.x; + double y = r*sp + center.y; + + mx[rho] = (float)x; + my[rho] = (float)y; + } + } + } + else + { + int x, y; + CvMat bufx, bufy, bufp, bufa; + double ascale = ssize.height/(2*CV_PI); + cv::AutoBuffer _buf(4*dsize.width); + float* buf = _buf; + + bufx = cvMat( 1, dsize.width, CV_32F, buf ); + bufy = cvMat( 1, dsize.width, CV_32F, buf + dsize.width ); + bufp = cvMat( 1, dsize.width, CV_32F, buf + dsize.width*2 ); + bufa = cvMat( 1, dsize.width, CV_32F, buf + dsize.width*3 ); + + for( x = 0; x < dsize.width; x++ ) + bufx.data.fl[x] = (float)x - center.x; + + for( y = 0; y < dsize.height; y++ ) + { + float* mx = (float*)(mapx->data.ptr + y*mapx->step); + float* my = (float*)(mapy->data.ptr + y*mapy->step); + + for( x = 0; x < dsize.width; x++ ) + bufy.data.fl[x] = (float)y - center.y; + +#if 1 + cvCartToPolar( &bufx, &bufy, &bufp, &bufa ); + + for( x = 0; x < dsize.width; x++ ) + bufp.data.fl[x] += 1.f; + + cvLog( &bufp, &bufp ); + + for( x = 0; x < dsize.width; x++ ) + { + double rho = bufp.data.fl[x]*M; + double phi = bufa.data.fl[x]*ascale; + + mx[x] = (float)rho; + my[x] = (float)phi; + } +#else + for( x = 0; x < dsize.width; x++ ) + { + double xx = bufx.data.fl[x]; + double yy = bufy.data.fl[x]; + + double p = log(sqrt(xx*xx + yy*yy) + 1.)*M; + double a = atan2(yy,xx); + if( a < 0 ) + a = 2*CV_PI + a; + a *= ascale; + + mx[x] = (float)p; + my[x] = (float)a; + } +#endif + } + } + + cvRemap( src, dst, mapx, mapy, flags, cvScalarAll(0) ); +} + + +/**************************************************************************************** + Linear-Polar Transform + J.L. Blanco, Apr 2009 + ****************************************************************************************/ +CV_IMPL +void cvLinearPolar( const CvArr* srcarr, CvArr* dstarr, + CvPoint2D32f center, double maxRadius, int flags ) +{ + cv::Ptr mapx, mapy; + + CvMat srcstub, *src = (CvMat*)srcarr; + CvMat dststub, *dst = (CvMat*)dstarr; + CvSize ssize, dsize; + + src = cvGetMat( srcarr, &srcstub,0,0 ); + dst = cvGetMat( dstarr, &dststub,0,0 ); + + if( !CV_ARE_TYPES_EQ( src, dst )) + CV_Error( CV_StsUnmatchedFormats, "" ); + + ssize.width = src->cols; + ssize.height = src->rows; + dsize.width = dst->cols; + dsize.height = dst->rows; + + mapx = cvCreateMat( dsize.height, dsize.width, CV_32F ); + mapy = cvCreateMat( dsize.height, dsize.width, CV_32F ); + + if( !(flags & CV_WARP_INVERSE_MAP) ) + { + int phi, rho; + + for( phi = 0; phi < dsize.height; phi++ ) + { + double cp = cos(phi*2*CV_PI/dsize.height); + double sp = sin(phi*2*CV_PI/dsize.height); + float* mx = (float*)(mapx->data.ptr + phi*mapx->step); + float* my = (float*)(mapy->data.ptr + phi*mapy->step); + + for( rho = 0; rho < dsize.width; rho++ ) + { + double r = maxRadius*(rho+1)/dsize.width; + double x = r*cp + center.x; + double y = r*sp + center.y; + + mx[rho] = (float)x; + my[rho] = (float)y; + } + } + } + else + { + int x, y; + CvMat bufx, bufy, bufp, bufa; + const double ascale = ssize.height/(2*CV_PI); + const double pscale = ssize.width/maxRadius; + + cv::AutoBuffer _buf(4*dsize.width); + float* buf = _buf; + + bufx = cvMat( 1, dsize.width, CV_32F, buf ); + bufy = cvMat( 1, dsize.width, CV_32F, buf + dsize.width ); + bufp = cvMat( 1, dsize.width, CV_32F, buf + dsize.width*2 ); + bufa = cvMat( 1, dsize.width, CV_32F, buf + dsize.width*3 ); + + for( x = 0; x < dsize.width; x++ ) + bufx.data.fl[x] = (float)x - center.x; + + for( y = 0; y < dsize.height; y++ ) + { + float* mx = (float*)(mapx->data.ptr + y*mapx->step); + float* my = (float*)(mapy->data.ptr + y*mapy->step); + + for( x = 0; x < dsize.width; x++ ) + bufy.data.fl[x] = (float)y - center.y; + + cvCartToPolar( &bufx, &bufy, &bufp, &bufa, 0 ); + + for( x = 0; x < dsize.width; x++ ) + bufp.data.fl[x] += 1.f; + + for( x = 0; x < dsize.width; x++ ) + { + double rho = bufp.data.fl[x]*pscale; + double phi = bufa.data.fl[x]*ascale; + mx[x] = (float)rho; + my[x] = (float)phi; + } + } + } + + cvRemap( src, dst, mapx, mapy, flags, cvScalarAll(0) ); +} + + +/* End of file. */ diff --git a/imgproc/src/linefit.cpp b/imgproc/src/linefit.cpp new file mode 100644 index 0000000..1d237cb --- /dev/null +++ b/imgproc/src/linefit.cpp @@ -0,0 +1,719 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +static const double eps = 1e-6; + +static CvStatus +icvFitLine2D_wods( CvPoint2D32f * points, int _count, float *weights, float *line ) +{ + double x = 0, y = 0, x2 = 0, y2 = 0, xy = 0, w = 0; + double dx2, dy2, dxy; + int i; + int count = _count; + float t; + + /* Calculating the average of x and y... */ + + if( weights == 0 ) + { + for( i = 0; i < count; i += 1 ) + { + x += points[i].x; + y += points[i].y; + x2 += points[i].x * points[i].x; + y2 += points[i].y * points[i].y; + xy += points[i].x * points[i].y; + } + w = (float) count; + } + else + { + for( i = 0; i < count; i += 1 ) + { + x += weights[i] * points[i].x; + y += weights[i] * points[i].y; + x2 += weights[i] * points[i].x * points[i].x; + y2 += weights[i] * points[i].y * points[i].y; + xy += weights[i] * points[i].x * points[i].y; + w += weights[i]; + } + } + + x /= w; + y /= w; + x2 /= w; + y2 /= w; + xy /= w; + + dx2 = x2 - x * x; + dy2 = y2 - y * y; + dxy = xy - x * y; + + t = (float) atan2( 2 * dxy, dx2 - dy2 ) / 2; + line[0] = (float) cos( t ); + line[1] = (float) sin( t ); + + line[2] = (float) x; + line[3] = (float) y; + + return CV_NO_ERR; +} + +static CvStatus +icvFitLine3D_wods( CvPoint3D32f * points, int count, float *weights, float *line ) +{ + int i; + float w0 = 0; + float x0 = 0, y0 = 0, z0 = 0; + float x2 = 0, y2 = 0, z2 = 0, xy = 0, yz = 0, xz = 0; + float dx2, dy2, dz2, dxy, dxz, dyz; + float *v; + float n; + float det[9], evc[9], evl[3]; + + memset( evl, 0, 3*sizeof(evl[0])); + memset( evc, 0, 9*sizeof(evl[0])); + + if( weights ) + { + for( i = 0; i < count; i++ ) + { + float x = points[i].x; + float y = points[i].y; + float z = points[i].z; + float w = weights[i]; + + + x2 += x * x * w; + xy += x * y * w; + xz += x * z * w; + y2 += y * y * w; + yz += y * z * w; + z2 += z * z * w; + x0 += x * w; + y0 += y * w; + z0 += z * w; + w0 += w; + } + } + else + { + for( i = 0; i < count; i++ ) + { + float x = points[i].x; + float y = points[i].y; + float z = points[i].z; + + x2 += x * x; + xy += x * y; + xz += x * z; + y2 += y * y; + yz += y * z; + z2 += z * z; + x0 += x; + y0 += y; + z0 += z; + } + w0 = (float) count; + } + + x2 /= w0; + xy /= w0; + xz /= w0; + y2 /= w0; + yz /= w0; + z2 /= w0; + + x0 /= w0; + y0 /= w0; + z0 /= w0; + + dx2 = x2 - x0 * x0; + dxy = xy - x0 * y0; + dxz = xz - x0 * z0; + dy2 = y2 - y0 * y0; + dyz = yz - y0 * z0; + dz2 = z2 - z0 * z0; + + det[0] = dz2 + dy2; + det[1] = -dxy; + det[2] = -dxz; + det[3] = det[1]; + det[4] = dx2 + dz2; + det[5] = -dyz; + det[6] = det[2]; + det[7] = det[5]; + det[8] = dy2 + dx2; + + /* Searching for a eigenvector of det corresponding to the minimal eigenvalue */ +#if 1 + { + CvMat _det = cvMat( 3, 3, CV_32F, det ); + CvMat _evc = cvMat( 3, 3, CV_32F, evc ); + CvMat _evl = cvMat( 3, 1, CV_32F, evl ); + cvEigenVV( &_det, &_evc, &_evl, 0 ); + i = evl[0] < evl[1] ? (evl[0] < evl[2] ? 0 : 2) : (evl[1] < evl[2] ? 1 : 2); + } +#else + { + CvMat _det = cvMat( 3, 3, CV_32F, det ); + CvMat _evc = cvMat( 3, 3, CV_32F, evc ); + CvMat _evl = cvMat( 1, 3, CV_32F, evl ); + + cvSVD( &_det, &_evl, &_evc, 0, CV_SVD_MODIFY_A+CV_SVD_U_T ); + } + i = 2; +#endif + v = &evc[i * 3]; + n = (float) sqrt( (double)v[0] * v[0] + (double)v[1] * v[1] + (double)v[2] * v[2] ); + n = (float)MAX(n, eps); + line[0] = v[0] / n; + line[1] = v[1] / n; + line[2] = v[2] / n; + line[3] = x0; + line[4] = y0; + line[5] = z0; + + return CV_NO_ERR; +} + +static double +icvCalcDist2D( CvPoint2D32f * points, int count, float *_line, float *dist ) +{ + int j; + float px = _line[2], py = _line[3]; + float nx = _line[1], ny = -_line[0]; + double sum_dist = 0.; + + for( j = 0; j < count; j++ ) + { + float x, y; + + x = points[j].x - px; + y = points[j].y - py; + + dist[j] = (float) fabs( nx * x + ny * y ); + sum_dist += dist[j]; + } + + return sum_dist; +} + +static double +icvCalcDist3D( CvPoint3D32f * points, int count, float *_line, float *dist ) +{ + int j; + float px = _line[3], py = _line[4], pz = _line[5]; + float vx = _line[0], vy = _line[1], vz = _line[2]; + double sum_dist = 0.; + + for( j = 0; j < count; j++ ) + { + float x, y, z; + double p1, p2, p3; + + x = points[j].x - px; + y = points[j].y - py; + z = points[j].z - pz; + + p1 = vy * z - vz * y; + p2 = vz * x - vx * z; + p3 = vx * y - vy * x; + + dist[j] = (float) sqrt( p1*p1 + p2*p2 + p3*p3 ); + sum_dist += dist[j]; + } + + return sum_dist; +} + +static void +icvWeightL1( float *d, int count, float *w ) +{ + int i; + + for( i = 0; i < count; i++ ) + { + double t = fabs( (double) d[i] ); + w[i] = (float)(1. / MAX(t, eps)); + } +} + +static void +icvWeightL12( float *d, int count, float *w ) +{ + int i; + + for( i = 0; i < count; i++ ) + { + w[i] = 1.0f / (float) sqrt( 1 + (double) (d[i] * d[i] * 0.5) ); + } +} + + +static void +icvWeightHuber( float *d, int count, float *w, float _c ) +{ + int i; + const float c = _c <= 0 ? 1.345f : _c; + + for( i = 0; i < count; i++ ) + { + if( d[i] < c ) + w[i] = 1.0f; + else + w[i] = c/d[i]; + } +} + + +static void +icvWeightFair( float *d, int count, float *w, float _c ) +{ + int i; + const float c = _c == 0 ? 1 / 1.3998f : 1 / _c; + + for( i = 0; i < count; i++ ) + { + w[i] = 1 / (1 + d[i] * c); + } +} + +static void +icvWeightWelsch( float *d, int count, float *w, float _c ) +{ + int i; + const float c = _c == 0 ? 1 / 2.9846f : 1 / _c; + + for( i = 0; i < count; i++ ) + { + w[i] = (float) exp( -d[i] * d[i] * c * c ); + } +} + + +/* Takes an array of 2D points, type of distance (including user-defined +distance specified by callbacks, fills the array of four floats with line +parameters A, B, C, D, where (A, B) is the normalized direction vector, +(C, D) is the point that belongs to the line. */ + +static CvStatus icvFitLine2D( CvPoint2D32f * points, int count, int dist, + float _param, float reps, float aeps, float *line ) +{ + double EPS = count*FLT_EPSILON; + void (*calc_weights) (float *, int, float *) = 0; + void (*calc_weights_param) (float *, int, float *, float) = 0; + float *w; /* weights */ + float *r; /* square distances */ + int i, j, k; + float _line[6], _lineprev[6]; + float rdelta = reps != 0 ? reps : 1.0f; + float adelta = aeps != 0 ? aeps : 0.01f; + double min_err = DBL_MAX, err = 0; + CvRNG rng = cvRNG(-1); + + memset( line, 0, 4*sizeof(line[0]) ); + + switch (dist) + { + case CV_DIST_L2: + return icvFitLine2D_wods( points, count, 0, line ); + + case CV_DIST_L1: + calc_weights = icvWeightL1; + break; + + case CV_DIST_L12: + calc_weights = icvWeightL12; + break; + + case CV_DIST_FAIR: + calc_weights_param = icvWeightFair; + break; + + case CV_DIST_WELSCH: + calc_weights_param = icvWeightWelsch; + break; + + case CV_DIST_HUBER: + calc_weights_param = icvWeightHuber; + break; + + /*case CV_DIST_USER: + calc_weights = (void ( * )(float *, int, float *)) _PFP.fp; + break;*/ + + default: + return CV_BADFACTOR_ERR; + } + + w = (float *) cvAlloc( count * sizeof( float )); + r = (float *) cvAlloc( count * sizeof( float )); + + for( k = 0; k < 20; k++ ) + { + int first = 1; + for( i = 0; i < count; i++ ) + w[i] = 0.f; + + for( i = 0; i < MIN(count,10); ) + { + j = cvRandInt(&rng) % count; + if( w[j] < FLT_EPSILON ) + { + w[j] = 1.f; + i++; + } + } + + icvFitLine2D_wods( points, count, w, _line ); + for( i = 0; i < 30; i++ ) + { + double sum_w = 0; + + if( first ) + { + first = 0; + } + else + { + double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1]; + t = MAX(t,-1.); + t = MIN(t,1.); + if( fabs(acos(t)) < adelta ) + { + float x, y, d; + + x = (float) fabs( _line[2] - _lineprev[2] ); + y = (float) fabs( _line[3] - _lineprev[3] ); + + d = x > y ? x : y; + if( d < rdelta ) + break; + } + } + /* calculate distances */ + err = icvCalcDist2D( points, count, _line, r ); + if( err < EPS ) + break; + + /* calculate weights */ + if( calc_weights ) + calc_weights( r, count, w ); + else + calc_weights_param( r, count, w, _param ); + + for( j = 0; j < count; j++ ) + sum_w += w[j]; + + if( fabs(sum_w) > FLT_EPSILON ) + { + sum_w = 1./sum_w; + for( j = 0; j < count; j++ ) + w[j] = (float)(w[j]*sum_w); + } + else + { + for( j = 0; j < count; j++ ) + w[j] = 1.f; + } + + /* save the line parameters */ + memcpy( _lineprev, _line, 4 * sizeof( float )); + + /* Run again... */ + icvFitLine2D_wods( points, count, w, _line ); + } + + if( err < min_err ) + { + min_err = err; + memcpy( line, _line, 4 * sizeof(line[0])); + if( err < EPS ) + break; + } + } + + cvFree( &w ); + cvFree( &r ); + return CV_OK; +} + + +/* Takes an array of 3D points, type of distance (including user-defined +distance specified by callbacks, fills the array of four floats with line +parameters A, B, C, D, E, F, where (A, B, C) is the normalized direction vector, +(D, E, F) is the point that belongs to the line. */ + +static CvStatus +icvFitLine3D( CvPoint3D32f * points, int count, int dist, + float _param, float reps, float aeps, float *line ) +{ + double EPS = count*FLT_EPSILON; + void (*calc_weights) (float *, int, float *) = 0; + void (*calc_weights_param) (float *, int, float *, float) = 0; + float *w; /* weights */ + float *r; /* square distances */ + int i, j, k; + float _line[6]={0,0,0,0,0,0}, _lineprev[6]={0,0,0,0,0,0}; + float rdelta = reps != 0 ? reps : 1.0f; + float adelta = aeps != 0 ? aeps : 0.01f; + double min_err = DBL_MAX, err = 0; + CvRNG rng = cvRNG(-1); + + switch (dist) + { + case CV_DIST_L2: + return icvFitLine3D_wods( points, count, 0, line ); + + case CV_DIST_L1: + calc_weights = icvWeightL1; + break; + + case CV_DIST_L12: + calc_weights = icvWeightL12; + break; + + case CV_DIST_FAIR: + calc_weights_param = icvWeightFair; + break; + + case CV_DIST_WELSCH: + calc_weights_param = icvWeightWelsch; + break; + + case CV_DIST_HUBER: + calc_weights_param = icvWeightHuber; + break; + + /*case CV_DIST_USER: + _PFP.p = param; + calc_weights = (void ( * )(float *, int, float *)) _PFP.fp; + break;*/ + + default: + return CV_BADFACTOR_ERR; + } + + w = (float *) cvAlloc( count * sizeof( float )); + r = (float *) cvAlloc( count * sizeof( float )); + + for( k = 0; k < 20; k++ ) + { + int first = 1; + for( i = 0; i < count; i++ ) + w[i] = 0.f; + + for( i = 0; i < MIN(count,10); ) + { + j = cvRandInt(&rng) % count; + if( w[j] < FLT_EPSILON ) + { + w[j] = 1.f; + i++; + } + } + + icvFitLine3D_wods( points, count, w, _line ); + for( i = 0; i < 30; i++ ) + { + double sum_w = 0; + + if( first ) + { + first = 0; + } + else + { + double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1] + _line[2] * _lineprev[2]; + t = MAX(t,-1.); + t = MIN(t,1.); + if( fabs(acos(t)) < adelta ) + { + float x, y, z, ax, ay, az, dx, dy, dz, d; + + x = _line[3] - _lineprev[3]; + y = _line[4] - _lineprev[4]; + z = _line[5] - _lineprev[5]; + ax = _line[0] - _lineprev[0]; + ay = _line[1] - _lineprev[1]; + az = _line[2] - _lineprev[2]; + dx = (float) fabs( y * az - z * ay ); + dy = (float) fabs( z * ax - x * az ); + dz = (float) fabs( x * ay - y * ax ); + + d = dx > dy ? (dx > dz ? dx : dz) : (dy > dz ? dy : dz); + if( d < rdelta ) + break; + } + } + /* calculate distances */ + if( icvCalcDist3D( points, count, _line, r ) < FLT_EPSILON*count ) + break; + + /* calculate weights */ + if( calc_weights ) + calc_weights( r, count, w ); + else + calc_weights_param( r, count, w, _param ); + + for( j = 0; j < count; j++ ) + sum_w += w[j]; + + if( fabs(sum_w) > FLT_EPSILON ) + { + sum_w = 1./sum_w; + for( j = 0; j < count; j++ ) + w[j] = (float)(w[j]*sum_w); + } + else + { + for( j = 0; j < count; j++ ) + w[j] = 1.f; + } + + /* save the line parameters */ + memcpy( _lineprev, _line, 6 * sizeof( float )); + + /* Run again... */ + icvFitLine3D_wods( points, count, w, _line ); + } + + if( err < min_err ) + { + min_err = err; + memcpy( line, _line, 6 * sizeof(line[0])); + if( err < EPS ) + break; + } + } + + // Return... + cvFree( &w ); + cvFree( &r ); + return CV_OK; +} + + +CV_IMPL void +cvFitLine( const CvArr* array, int dist, double param, + double reps, double aeps, float *line ) +{ + cv::AutoBuffer buffer; + + schar* points = 0; + union { CvContour contour; CvSeq seq; } header; + CvSeqBlock block; + CvSeq* ptseq = (CvSeq*)array; + int type; + + if( !line ) + CV_Error( CV_StsNullPtr, "NULL pointer to line parameters" ); + + if( CV_IS_SEQ(ptseq) ) + { + type = CV_SEQ_ELTYPE(ptseq); + if( ptseq->total == 0 ) + CV_Error( CV_StsBadSize, "The sequence has no points" ); + if( (type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) || + CV_ELEM_SIZE(type) != ptseq->elem_size ) + CV_Error( CV_StsUnsupportedFormat, + "Input sequence must consist of 2d points or 3d points" ); + } + else + { + CvMat* mat = (CvMat*)array; + type = CV_MAT_TYPE(mat->type); + if( !CV_IS_MAT(mat)) + CV_Error( CV_StsBadArg, "Input array is not a sequence nor matrix" ); + + if( !CV_IS_MAT_CONT(mat->type) || + (type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) || + (mat->width != 1 && mat->height != 1)) + CV_Error( CV_StsBadArg, + "Input array must be 1d continuous array of 2d or 3d points" ); + + ptseq = cvMakeSeqHeaderForArray( + CV_SEQ_KIND_GENERIC|type, sizeof(CvContour), CV_ELEM_SIZE(type), mat->data.ptr, + mat->width + mat->height - 1, &header.seq, &block ); + } + + if( reps < 0 || aeps < 0 ) + CV_Error( CV_StsOutOfRange, "Both reps and aeps must be non-negative" ); + + if( CV_MAT_DEPTH(type) == CV_32F && ptseq->first->next == ptseq->first ) + { + /* no need to copy data in this case */ + points = ptseq->first->data; + } + else + { + buffer.allocate(ptseq->total*CV_ELEM_SIZE(type)); + points = buffer; + cvCvtSeqToArray( ptseq, points, CV_WHOLE_SEQ ); + + if( CV_MAT_DEPTH(type) != CV_32F ) + { + int i, total = ptseq->total*CV_MAT_CN(type); + assert( CV_MAT_DEPTH(type) == CV_32S ); + + for( i = 0; i < total; i++ ) + ((float*)points)[i] = (float)((int*)points)[i]; + } + } + + if( dist == CV_DIST_USER ) + CV_Error( CV_StsBadArg, "User-defined distance is not allowed" ); + + if( CV_MAT_CN(type) == 2 ) + { + IPPI_CALL( icvFitLine2D( (CvPoint2D32f*)points, ptseq->total, + dist, (float)param, (float)reps, (float)aeps, line )); + } + else + { + IPPI_CALL( icvFitLine3D( (CvPoint3D32f*)points, ptseq->total, + dist, (float)param, (float)reps, (float)aeps, line )); + } +} + +/* End of file. */ diff --git a/imgproc/src/matchcontours.cpp b/imgproc/src/matchcontours.cpp new file mode 100644 index 0000000..00e544f --- /dev/null +++ b/imgproc/src/matchcontours.cpp @@ -0,0 +1,198 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +/*F/////////////////////////////////////////////////////////////////////////////////////// +// Name: cvMatchContours +// Purpose: +// Calculates matching of the two contours +// Context: +// Parameters: +// contour_1 - pointer to the first input contour object. +// contour_2 - pointer to the second input contour object. +// method - method for the matching calculation +// (now CV_IPPI_CONTOURS_MATCH_I1, CV_CONTOURS_MATCH_I2 or +// CV_CONTOURS_MATCH_I3 only ) +// rezult - output calculated measure +// +//F*/ +CV_IMPL double +cvMatchShapes( const void* contour1, const void* contour2, + int method, double /*parameter*/ ) +{ + CvMoments moments; + CvHuMoments huMoments; + double ma[7], mb[7]; + int i, sma, smb; + double eps = 1.e-5; + double mmm; + double result = 0; + + if( !contour1 || !contour2 ) + CV_Error( CV_StsNullPtr, "" ); + + // calculate moments of the first shape + cvMoments( contour1, &moments ); + cvGetHuMoments( &moments, &huMoments ); + + ma[0] = huMoments.hu1; + ma[1] = huMoments.hu2; + ma[2] = huMoments.hu3; + ma[3] = huMoments.hu4; + ma[4] = huMoments.hu5; + ma[5] = huMoments.hu6; + ma[6] = huMoments.hu7; + + + // calculate moments of the second shape + cvMoments( contour2, &moments ); + cvGetHuMoments( &moments, &huMoments ); + + mb[0] = huMoments.hu1; + mb[1] = huMoments.hu2; + mb[2] = huMoments.hu3; + mb[3] = huMoments.hu4; + mb[4] = huMoments.hu5; + mb[5] = huMoments.hu6; + mb[6] = huMoments.hu7; + + switch (method) + { + case 1: + { + for( i = 0; i < 7; i++ ) + { + double ama = fabs( ma[i] ); + double amb = fabs( mb[i] ); + + if( ma[i] > 0 ) + sma = 1; + else if( ma[i] < 0 ) + sma = -1; + else + sma = 0; + if( mb[i] > 0 ) + smb = 1; + else if( mb[i] < 0 ) + smb = -1; + else + smb = 0; + + if( ama > eps && amb > eps ) + { + ama = 1. / (sma * log10( ama )); + amb = 1. / (smb * log10( amb )); + result += fabs( -ama + amb ); + } + } + break; + } + + case 2: + { + for( i = 0; i < 7; i++ ) + { + double ama = fabs( ma[i] ); + double amb = fabs( mb[i] ); + + if( ma[i] > 0 ) + sma = 1; + else if( ma[i] < 0 ) + sma = -1; + else + sma = 0; + if( mb[i] > 0 ) + smb = 1; + else if( mb[i] < 0 ) + smb = -1; + else + smb = 0; + + if( ama > eps && amb > eps ) + { + ama = sma * log10( ama ); + amb = smb * log10( amb ); + result += fabs( -ama + amb ); + } + } + break; + } + + case 3: + { + for( i = 0; i < 7; i++ ) + { + double ama = fabs( ma[i] ); + double amb = fabs( mb[i] ); + + if( ma[i] > 0 ) + sma = 1; + else if( ma[i] < 0 ) + sma = -1; + else + sma = 0; + if( mb[i] > 0 ) + smb = 1; + else if( mb[i] < 0 ) + smb = -1; + else + smb = 0; + + if( ama > eps && amb > eps ) + { + ama = sma * log10( ama ); + amb = smb * log10( amb ); + mmm = fabs( (ama - amb) / ama ); + if( result < mmm ) + result = mmm; + } + } + break; + } + default: + CV_Error( CV_StsBadArg, "Unknown comparison method" ); + } + + return result; +} + + +/* End of file. */ diff --git a/imgproc/src/moments.cpp b/imgproc/src/moments.cpp new file mode 100644 index 0000000..784a61b --- /dev/null +++ b/imgproc/src/moments.cpp @@ -0,0 +1,651 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +// The function calculates center of gravity and the central second order moments +static void icvCompleteMomentState( CvMoments* moments ) +{ + double cx = 0, cy = 0; + double mu20, mu11, mu02; + + assert( moments != 0 ); + moments->inv_sqrt_m00 = 0; + + if( fabs(moments->m00) > DBL_EPSILON ) + { + double inv_m00 = 1. / moments->m00; + cx = moments->m10 * inv_m00; + cy = moments->m01 * inv_m00; + moments->inv_sqrt_m00 = std::sqrt( fabs(inv_m00) ); + } + + // mu20 = m20 - m10*cx + mu20 = moments->m20 - moments->m10 * cx; + // mu11 = m11 - m10*cy + mu11 = moments->m11 - moments->m10 * cy; + // mu02 = m02 - m01*cy + mu02 = moments->m02 - moments->m01 * cy; + + moments->mu20 = mu20; + moments->mu11 = mu11; + moments->mu02 = mu02; + + // mu30 = m30 - cx*(3*mu20 + cx*m10) + moments->mu30 = moments->m30 - cx * (3 * mu20 + cx * moments->m10); + mu11 += mu11; + // mu21 = m21 - cx*(2*mu11 + cx*m01) - cy*mu20 + moments->mu21 = moments->m21 - cx * (mu11 + cx * moments->m01) - cy * mu20; + // mu12 = m12 - cy*(2*mu11 + cy*m10) - cx*mu02 + moments->mu12 = moments->m12 - cy * (mu11 + cy * moments->m10) - cx * mu02; + // mu03 = m03 - cy*(3*mu02 + cy*m01) + moments->mu03 = moments->m03 - cy * (3 * mu02 + cy * moments->m01); +} + + +static void icvContourMoments( CvSeq* contour, CvMoments* moments ) +{ + int is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2; + + if( contour->total ) + { + CvSeqReader reader; + double a00, a10, a01, a20, a11, a02, a30, a21, a12, a03; + double xi, yi, xi2, yi2, xi_1, yi_1, xi_12, yi_12, dxy, xii_1, yii_1; + int lpt = contour->total; + + a00 = a10 = a01 = a20 = a11 = a02 = a30 = a21 = a12 = a03 = 0; + + cvStartReadSeq( contour, &reader, 0 ); + + if( !is_float ) + { + xi_1 = ((CvPoint*)(reader.ptr))->x; + yi_1 = ((CvPoint*)(reader.ptr))->y; + } + else + { + xi_1 = ((CvPoint2D32f*)(reader.ptr))->x; + yi_1 = ((CvPoint2D32f*)(reader.ptr))->y; + } + CV_NEXT_SEQ_ELEM( contour->elem_size, reader ); + + xi_12 = xi_1 * xi_1; + yi_12 = yi_1 * yi_1; + + while( lpt-- > 0 ) + { + if( !is_float ) + { + xi = ((CvPoint*)(reader.ptr))->x; + yi = ((CvPoint*)(reader.ptr))->y; + } + else + { + xi = ((CvPoint2D32f*)(reader.ptr))->x; + yi = ((CvPoint2D32f*)(reader.ptr))->y; + } + CV_NEXT_SEQ_ELEM( contour->elem_size, reader ); + + xi2 = xi * xi; + yi2 = yi * yi; + dxy = xi_1 * yi - xi * yi_1; + xii_1 = xi_1 + xi; + yii_1 = yi_1 + yi; + + a00 += dxy; + a10 += dxy * xii_1; + a01 += dxy * yii_1; + a20 += dxy * (xi_1 * xii_1 + xi2); + a11 += dxy * (xi_1 * (yii_1 + yi_1) + xi * (yii_1 + yi)); + a02 += dxy * (yi_1 * yii_1 + yi2); + a30 += dxy * xii_1 * (xi_12 + xi2); + a03 += dxy * yii_1 * (yi_12 + yi2); + a21 += + dxy * (xi_12 * (3 * yi_1 + yi) + 2 * xi * xi_1 * yii_1 + + xi2 * (yi_1 + 3 * yi)); + a12 += + dxy * (yi_12 * (3 * xi_1 + xi) + 2 * yi * yi_1 * xii_1 + + yi2 * (xi_1 + 3 * xi)); + + xi_1 = xi; + yi_1 = yi; + xi_12 = xi2; + yi_12 = yi2; + } + + double db1_2, db1_6, db1_12, db1_24, db1_20, db1_60; + + if( fabs(a00) > FLT_EPSILON ) + { + if( a00 > 0 ) + { + db1_2 = 0.5; + db1_6 = 0.16666666666666666666666666666667; + db1_12 = 0.083333333333333333333333333333333; + db1_24 = 0.041666666666666666666666666666667; + db1_20 = 0.05; + db1_60 = 0.016666666666666666666666666666667; + } + else + { + db1_2 = -0.5; + db1_6 = -0.16666666666666666666666666666667; + db1_12 = -0.083333333333333333333333333333333; + db1_24 = -0.041666666666666666666666666666667; + db1_20 = -0.05; + db1_60 = -0.016666666666666666666666666666667; + } + + // spatial moments + moments->m00 = a00 * db1_2; + moments->m10 = a10 * db1_6; + moments->m01 = a01 * db1_6; + moments->m20 = a20 * db1_12; + moments->m11 = a11 * db1_24; + moments->m02 = a02 * db1_12; + moments->m30 = a30 * db1_20; + moments->m21 = a21 * db1_60; + moments->m12 = a12 * db1_60; + moments->m03 = a03 * db1_20; + + icvCompleteMomentState( moments ); + } + } +} + + +/****************************************************************************************\ +* Spatial Raster Moments * +\****************************************************************************************/ + +template +static void momentsInTile( const cv::Mat& img, double* moments ) +{ + cv::Size size = img.size(); + int x, y; + MT mom[10] = {0,0,0,0,0,0,0,0,0,0}; + + for( y = 0; y < size.height; y++ ) + { + const T* ptr = (const T*)(img.data + y*img.step); + WT x0 = 0, x1 = 0, x2 = 0; + MT x3 = 0; + + for( x = 0; x < size.width; x++ ) + { + WT p = ptr[x]; + WT xp = x * p, xxp; + + x0 += p; + x1 += xp; + xxp = xp * x; + x2 += xxp; + x3 += xxp * x; + } + + WT py = y * x0, sy = y*y; + + mom[9] += ((MT)py) * sy; // m03 + mom[8] += ((MT)x1) * sy; // m12 + mom[7] += ((MT)x2) * y; // m21 + mom[6] += x3; // m30 + mom[5] += x0 * sy; // m02 + mom[4] += x1 * y; // m11 + mom[3] += x2; // m20 + mom[2] += py; // m01 + mom[1] += x1; // m10 + mom[0] += x0; // m00 + } + + for( x = 0; x < 10; x++ ) + moments[x] = (double)mom[x]; +} + + +#if CV_SSE2 + +template<> void momentsInTile( const cv::Mat& img, double* moments ) +{ + typedef uchar T; + typedef int WT; + typedef int MT; + cv::Size size = img.size(); + int y; + MT mom[10] = {0,0,0,0,0,0,0,0,0,0}; + bool useSIMD = cv::checkHardwareSupport(CV_CPU_SSE2); + + for( y = 0; y < size.height; y++ ) + { + const T* ptr = img.ptr(y); + int x0 = 0, x1 = 0, x2 = 0, x3 = 0, x = 0; + + if( useSIMD ) + { + __m128i qx_init = _mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7); + __m128i dx = _mm_set1_epi16(8); + __m128i z = _mm_setzero_si128(), qx0 = z, qx1 = z, qx2 = z, qx3 = z, qx = qx_init; + + for( ; x <= size.width - 8; x += 8 ) + { + __m128i p = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(ptr + x)), z); + qx0 = _mm_add_epi32(qx0, _mm_sad_epu8(p, z)); + __m128i px = _mm_mullo_epi16(p, qx); + __m128i sx = _mm_mullo_epi16(qx, qx); + qx1 = _mm_add_epi32(qx1, _mm_madd_epi16(p, qx)); + qx2 = _mm_add_epi32(qx2, _mm_madd_epi16(p, sx)); + qx3 = _mm_add_epi32(qx3, _mm_madd_epi16(px, sx)); + + qx = _mm_add_epi16(qx, dx); + } + int CV_DECL_ALIGNED(16) buf[4]; + _mm_store_si128((__m128i*)buf, qx0); + x0 = buf[0] + buf[1] + buf[2] + buf[3]; + _mm_store_si128((__m128i*)buf, qx1); + x1 = buf[0] + buf[1] + buf[2] + buf[3]; + _mm_store_si128((__m128i*)buf, qx2); + x2 = buf[0] + buf[1] + buf[2] + buf[3]; + _mm_store_si128((__m128i*)buf, qx3); + x3 = buf[0] + buf[1] + buf[2] + buf[3]; + } + + for( ; x < size.width; x++ ) + { + WT p = ptr[x]; + WT xp = x * p, xxp; + + x0 += p; + x1 += xp; + xxp = xp * x; + x2 += xxp; + x3 += xxp * x; + } + + WT py = y * x0, sy = y*y; + + mom[9] += ((MT)py) * sy; // m03 + mom[8] += ((MT)x1) * sy; // m12 + mom[7] += ((MT)x2) * y; // m21 + mom[6] += x3; // m30 + mom[5] += x0 * sy; // m02 + mom[4] += x1 * y; // m11 + mom[3] += x2; // m20 + mom[2] += py; // m01 + mom[1] += x1; // m10 + mom[0] += x0; // m00 + } + + for(int x = 0; x < 10; x++ ) + moments[x] = (double)mom[x]; +} + +#endif + +typedef void (*CvMomentsInTileFunc)(const cv::Mat& img, double* moments); + +CV_IMPL void cvMoments( const void* array, CvMoments* moments, int binary ) +{ + const int TILE_SIZE = 32; + int type, depth, cn, coi = 0; + CvMat stub, *mat = (CvMat*)array; + CvMomentsInTileFunc func = 0; + CvContour contourHeader; + CvSeq* contour = 0; + CvSeqBlock block; + double buf[TILE_SIZE*TILE_SIZE]; + uchar nzbuf[TILE_SIZE*TILE_SIZE]; + + if( CV_IS_SEQ( array )) + { + contour = (CvSeq*)array; + if( !CV_IS_SEQ_POINT_SET( contour )) + CV_Error( CV_StsBadArg, "The passed sequence is not a valid contour" ); + } + + if( !moments ) + CV_Error( CV_StsNullPtr, "" ); + + memset( moments, 0, sizeof(*moments)); + + if( !contour ) + { + mat = cvGetMat( mat, &stub, &coi ); + type = CV_MAT_TYPE( mat->type ); + + if( type == CV_32SC2 || type == CV_32FC2 ) + { + contour = cvPointSeqFromMat( + CV_SEQ_KIND_CURVE | CV_SEQ_FLAG_CLOSED, + mat, &contourHeader, &block ); + } + } + + if( contour ) + { + icvContourMoments( contour, moments ); + return; + } + + type = CV_MAT_TYPE( mat->type ); + depth = CV_MAT_DEPTH( type ); + cn = CV_MAT_CN( type ); + + cv::Size size = cvGetMatSize( mat ); + + if( cn > 1 && coi == 0 ) + CV_Error( CV_StsBadArg, "Invalid image type" ); + + if( size.width <= 0 || size.height <= 0 ) + return; + + if( binary || depth == CV_8U ) + func = momentsInTile; + else if( depth == CV_16U ) + func = momentsInTile; + else if( depth == CV_16S ) + func = momentsInTile; + else if( depth == CV_32F ) + func = momentsInTile; + else if( depth == CV_64F ) + func = momentsInTile; + else + CV_Error( CV_StsUnsupportedFormat, "" ); + + cv::Mat src0(mat); + + for( int y = 0; y < size.height; y += TILE_SIZE ) + { + cv::Size tileSize; + tileSize.height = std::min(TILE_SIZE, size.height - y); + + for( int x = 0; x < size.width; x += TILE_SIZE ) + { + tileSize.width = std::min(TILE_SIZE, size.width - x); + cv::Mat src(src0, cv::Rect(x, y, tileSize.width, tileSize.height)); + + if( coi > 0 ) + { + cv::Mat tmp(tileSize, depth, buf); + int pairs[] = {coi-1, 0}; + cv::mixChannels(&src, 1, &tmp, 1, pairs, 1); + src = tmp; + } + if( binary ) + { + cv::Mat tmp(tileSize, CV_8U, nzbuf); + cv::compare( src, 0, tmp, CV_CMP_NE ); + src = tmp; + } + + double mom[10]; + func( src, mom ); + + if(binary) + { + double s = 1./255; + for( int k = 0; k < 10; k++ ) + mom[k] *= s; + } + + double xm = x * mom[0], ym = y * mom[0]; + + // accumulate moments computed in each tile + + // + m00 ( = m00' ) + moments->m00 += mom[0]; + + // + m10 ( = m10' + x*m00' ) + moments->m10 += mom[1] + xm; + + // + m01 ( = m01' + y*m00' ) + moments->m01 += mom[2] + ym; + + // + m20 ( = m20' + 2*x*m10' + x*x*m00' ) + moments->m20 += mom[3] + x * (mom[1] * 2 + xm); + + // + m11 ( = m11' + x*m01' + y*m10' + x*y*m00' ) + moments->m11 += mom[4] + x * (mom[2] + ym) + y * mom[1]; + + // + m02 ( = m02' + 2*y*m01' + y*y*m00' ) + moments->m02 += mom[5] + y * (mom[2] * 2 + ym); + + // + m30 ( = m30' + 3*x*m20' + 3*x*x*m10' + x*x*x*m00' ) + moments->m30 += mom[6] + x * (3. * mom[3] + x * (3. * mom[1] + xm)); + + // + m21 ( = m21' + x*(2*m11' + 2*y*m10' + x*m01' + x*y*m00') + y*m20') + moments->m21 += mom[7] + x * (2 * (mom[4] + y * mom[1]) + x * (mom[2] + ym)) + y * mom[3]; + + // + m12 ( = m12' + y*(2*m11' + 2*x*m01' + y*m10' + x*y*m00') + x*m02') + moments->m12 += mom[8] + y * (2 * (mom[4] + x * mom[2]) + y * (mom[1] + xm)) + x * mom[5]; + + // + m03 ( = m03' + 3*y*m02' + 3*y*y*m01' + y*y*y*m00' ) + moments->m03 += mom[9] + y * (3. * mom[5] + y * (3. * mom[2] + ym)); + } + } + + icvCompleteMomentState( moments ); +} + + +CV_IMPL void cvGetHuMoments( CvMoments * mState, CvHuMoments * HuState ) +{ + if( !mState || !HuState ) + CV_Error( CV_StsNullPtr, "" ); + + double m00s = mState->inv_sqrt_m00, m00 = m00s * m00s, s2 = m00 * m00, s3 = s2 * m00s; + + double nu20 = mState->mu20 * s2, + nu11 = mState->mu11 * s2, + nu02 = mState->mu02 * s2, + nu30 = mState->mu30 * s3, + nu21 = mState->mu21 * s3, nu12 = mState->mu12 * s3, nu03 = mState->mu03 * s3; + + double t0 = nu30 + nu12; + double t1 = nu21 + nu03; + + double q0 = t0 * t0, q1 = t1 * t1; + + double n4 = 4 * nu11; + double s = nu20 + nu02; + double d = nu20 - nu02; + + HuState->hu1 = s; + HuState->hu2 = d * d + n4 * nu11; + HuState->hu4 = q0 + q1; + HuState->hu6 = d * (q0 - q1) + n4 * t0 * t1; + + t0 *= q0 - 3 * q1; + t1 *= 3 * q0 - q1; + + q0 = nu30 - 3 * nu12; + q1 = 3 * nu21 - nu03; + + HuState->hu3 = q0 * q0 + q1 * q1; + HuState->hu5 = q0 * t0 + q1 * t1; + HuState->hu7 = q1 * t0 - q0 * t1; +} + + +CV_IMPL double cvGetSpatialMoment( CvMoments * moments, int x_order, int y_order ) +{ + int order = x_order + y_order; + + if( !moments ) + CV_Error( CV_StsNullPtr, "" ); + if( (x_order | y_order) < 0 || order > 3 ) + CV_Error( CV_StsOutOfRange, "" ); + + return (&(moments->m00))[order + (order >> 1) + (order > 2) * 2 + y_order]; +} + + +CV_IMPL double cvGetCentralMoment( CvMoments * moments, int x_order, int y_order ) +{ + int order = x_order + y_order; + + if( !moments ) + CV_Error( CV_StsNullPtr, "" ); + if( (x_order | y_order) < 0 || order > 3 ) + CV_Error( CV_StsOutOfRange, "" ); + + return order >= 2 ? (&(moments->m00))[4 + order * 3 + y_order] : + order == 0 ? moments->m00 : 0; +} + + +CV_IMPL double cvGetNormalizedCentralMoment( CvMoments * moments, int x_order, int y_order ) +{ + int order = x_order + y_order; + + double mu = cvGetCentralMoment( moments, x_order, y_order ); + double m00s = moments->inv_sqrt_m00; + + while( --order >= 0 ) + mu *= m00s; + return mu * m00s * m00s; +} + + +namespace cv +{ + +Moments::Moments() +{ + m00 = m10 = m01 = m20 = m11 = m02 = m30 = m21 = m12 = m03 = + mu20 = mu11 = mu02 = mu30 = mu21 = mu12 = mu03 = + nu20 = nu11 = nu02 = nu30 = nu21 = nu12 = nu03 = 0.; +} + +Moments::Moments( double _m00, double _m10, double _m01, double _m20, double _m11, + double _m02, double _m30, double _m21, double _m12, double _m03 ) +{ + m00 = _m00; m10 = _m10; m01 = _m01; + m20 = _m20; m11 = _m11; m02 = _m02; + m30 = _m30; m21 = _m21; m12 = _m12; m03 = _m03; + + double cx = 0, cy = 0, inv_m00 = 0; + if( std::abs(m00) > DBL_EPSILON ) + { + inv_m00 = 1./m00; + cx = m10*inv_m00; cy = m01*inv_m00; + } + + mu20 = m20 - m10*cx; + mu11 = m11 - m10*cy; + mu02 = m02 - m01*cy; + + mu30 = m30 - cx*(3*mu20 + cx*m10); + mu21 = m21 - cx*(2*mu11 + cx*m01) - cy*mu20; + mu12 = m12 - cy*(2*mu11 + cy*m10) - cx*mu02; + mu03 = m03 - cy*(3*mu02 + cy*m01); + + double inv_sqrt_m00 = std::sqrt(std::abs(inv_m00)); + double s2 = inv_m00*inv_m00, s3 = s2*inv_sqrt_m00; + + nu20 = mu20*s2; nu11 = mu11*s2; nu02 = mu02*s2; + nu30 = mu30*s3; nu21 = mu21*s3; nu12 = mu12*s3; nu03 = mu03*s3; +} + +Moments::Moments( const CvMoments& m ) +{ + *this = Moments(m.m00, m.m10, m.m01, m.m20, m.m11, m.m02, m.m30, m.m21, m.m12, m.m03); +} + +Moments::operator CvMoments() const +{ + CvMoments m; + m.m00 = m00; m.m10 = m10; m.m01 = m01; + m.m20 = m20; m.m11 = m11; m.m02 = m02; + m.m30 = m30; m.m21 = m21; m.m12 = m12; m.m03 = m03; + m.mu20 = mu20; m.mu11 = mu11; m.mu02 = mu02; + m.mu30 = mu30; m.mu21 = mu21; m.mu12 = mu12; m.mu03 = mu03; + double am00 = std::abs(m00); + m.inv_sqrt_m00 = am00 > DBL_EPSILON ? 1./std::sqrt(am00) : 0; + + return m; +} + +} + +cv::Moments cv::moments( InputArray _array, bool binaryImage ) +{ + CvMoments om; + Mat arr = _array.getMat(); + CvMat c_array = arr; + cvMoments(&c_array, &om, binaryImage); + return om; +} + +void cv::HuMoments( const Moments& m, double hu[7] ) +{ + double t0 = m.nu30 + m.nu12; + double t1 = m.nu21 + m.nu03; + + double q0 = t0 * t0, q1 = t1 * t1; + + double n4 = 4 * m.nu11; + double s = m.nu20 + m.nu02; + double d = m.nu20 - m.nu02; + + hu[0] = s; + hu[1] = d * d + n4 * m.nu11; + hu[3] = q0 + q1; + hu[5] = d * (q0 - q1) + n4 * t0 * t1; + + t0 *= q0 - 3 * q1; + t1 *= 3 * q0 - q1; + + q0 = m.nu30 - 3 * m.nu12; + q1 = 3 * m.nu21 - m.nu03; + + hu[2] = q0 * q0 + q1 * q1; + hu[4] = q0 * t0 + q1 * t1; + hu[6] = q1 * t0 - q0 * t1; +} + +void cv::HuMoments( const Moments& m, OutputArray _hu ) +{ + _hu.create(7, 1, CV_64F); + Mat hu = _hu.getMat(); + CV_Assert( hu.isContinuous() ); + HuMoments(m, (double*)hu.data); +} + +/* End of file. */ diff --git a/imgproc/src/morph.cpp b/imgproc/src/morph.cpp new file mode 100644 index 0000000..801a2cd --- /dev/null +++ b/imgproc/src/morph.cpp @@ -0,0 +1,1370 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" +#include +#include + +/****************************************************************************************\ + Basic Morphological Operations: Erosion & Dilation +\****************************************************************************************/ + +namespace cv +{ + +template struct MinOp +{ + typedef T type1; + typedef T type2; + typedef T rtype; + T operator ()(T a, T b) const { return std::min(a, b); } +}; + +template struct MaxOp +{ + typedef T type1; + typedef T type2; + typedef T rtype; + T operator ()(T a, T b) const { return std::max(a, b); } +}; + +#undef CV_MIN_8U +#undef CV_MAX_8U +#define CV_MIN_8U(a,b) ((a) - CV_FAST_CAST_8U((a) - (b))) +#define CV_MAX_8U(a,b) ((a) + CV_FAST_CAST_8U((b) - (a))) + +template<> inline uchar MinOp::operator ()(uchar a, uchar b) const { return CV_MIN_8U(a, b); } +template<> inline uchar MaxOp::operator ()(uchar a, uchar b) const { return CV_MAX_8U(a, b); } + +struct MorphRowNoVec +{ + MorphRowNoVec(int, int) {} + int operator()(const uchar*, uchar*, int, int) const { return 0; } +}; + +struct MorphColumnNoVec +{ + MorphColumnNoVec(int, int) {} + int operator()(const uchar**, uchar*, int, int, int) const { return 0; } +}; + +struct MorphNoVec +{ + int operator()(uchar**, int, uchar*, int) const { return 0; } +}; + +#if CV_SSE2 + +template struct MorphRowIVec +{ + enum { ESZ = VecUpdate::ESZ }; + + MorphRowIVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {} + int operator()(const uchar* src, uchar* dst, int width, int cn) const + { + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + cn *= ESZ; + int i, k, _ksize = ksize*cn; + width = (width & -4)*cn; + VecUpdate updateOp; + + for( i = 0; i <= width - 16; i += 16 ) + { + __m128i s = _mm_loadu_si128((const __m128i*)(src + i)); + for( k = cn; k < _ksize; k += cn ) + { + __m128i x = _mm_loadu_si128((const __m128i*)(src + i + k)); + s = updateOp(s, x); + } + _mm_storeu_si128((__m128i*)(dst + i), s); + } + + for( ; i < width; i += 4 ) + { + __m128i s = _mm_cvtsi32_si128(*(const int*)(src + i)); + for( k = cn; k < _ksize; k += cn ) + { + __m128i x = _mm_cvtsi32_si128(*(const int*)(src + i + k)); + s = updateOp(s, x); + } + *(int*)(dst + i) = _mm_cvtsi128_si32(s); + } + + return i/ESZ; + } + + int ksize, anchor; +}; + + +template struct MorphRowFVec +{ + MorphRowFVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {} + int operator()(const uchar* src, uchar* dst, int width, int cn) const + { + if( !checkHardwareSupport(CV_CPU_SSE) ) + return 0; + + int i, k, _ksize = ksize*cn; + width = (width & -4)*cn; + VecUpdate updateOp; + + for( i = 0; i < width; i += 4 ) + { + __m128 s = _mm_loadu_ps((const float*)src + i); + for( k = cn; k < _ksize; k += cn ) + { + __m128 x = _mm_loadu_ps((const float*)src + i + k); + s = updateOp(s, x); + } + _mm_storeu_ps((float*)dst + i, s); + } + + return i; + } + + int ksize, anchor; +}; + + +template struct MorphColumnIVec +{ + enum { ESZ = VecUpdate::ESZ }; + + MorphColumnIVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {} + int operator()(const uchar** src, uchar* dst, int dststep, int count, int width) const + { + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + int i = 0, k, _ksize = ksize; + width *= ESZ; + VecUpdate updateOp; + + for( i = 0; i < count + ksize - 1; i++ ) + CV_Assert( ((size_t)src[i] & 15) == 0 ); + + for( ; _ksize > 1 && count > 1; count -= 2, dst += dststep*2, src += 2 ) + { + for( i = 0; i <= width - 32; i += 32 ) + { + const uchar* sptr = src[1] + i; + __m128i s0 = _mm_load_si128((const __m128i*)sptr); + __m128i s1 = _mm_load_si128((const __m128i*)(sptr + 16)); + __m128i x0, x1; + + for( k = 2; k < _ksize; k++ ) + { + sptr = src[k] + i; + x0 = _mm_load_si128((const __m128i*)sptr); + x1 = _mm_load_si128((const __m128i*)(sptr + 16)); + s0 = updateOp(s0, x0); + s1 = updateOp(s1, x1); + } + + sptr = src[0] + i; + x0 = _mm_load_si128((const __m128i*)sptr); + x1 = _mm_load_si128((const __m128i*)(sptr + 16)); + _mm_storeu_si128((__m128i*)(dst + i), updateOp(s0, x0)); + _mm_storeu_si128((__m128i*)(dst + i + 16), updateOp(s1, x1)); + + sptr = src[k] + i; + x0 = _mm_load_si128((const __m128i*)sptr); + x1 = _mm_load_si128((const __m128i*)(sptr + 16)); + _mm_storeu_si128((__m128i*)(dst + dststep + i), updateOp(s0, x0)); + _mm_storeu_si128((__m128i*)(dst + dststep + i + 16), updateOp(s1, x1)); + } + + for( ; i <= width - 8; i += 8 ) + { + __m128i s0 = _mm_loadl_epi64((const __m128i*)(src[1] + i)), x0; + + for( k = 2; k < _ksize; k++ ) + { + x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i)); + s0 = updateOp(s0, x0); + } + + x0 = _mm_loadl_epi64((const __m128i*)(src[0] + i)); + _mm_storel_epi64((__m128i*)(dst + i), updateOp(s0, x0)); + x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i)); + _mm_storel_epi64((__m128i*)(dst + dststep + i), updateOp(s0, x0)); + } + } + + for( ; count > 0; count--, dst += dststep, src++ ) + { + for( i = 0; i <= width - 32; i += 32 ) + { + const uchar* sptr = src[0] + i; + __m128i s0 = _mm_load_si128((const __m128i*)sptr); + __m128i s1 = _mm_load_si128((const __m128i*)(sptr + 16)); + __m128i x0, x1; + + for( k = 1; k < _ksize; k++ ) + { + sptr = src[k] + i; + x0 = _mm_load_si128((const __m128i*)sptr); + x1 = _mm_load_si128((const __m128i*)(sptr + 16)); + s0 = updateOp(s0, x0); + s1 = updateOp(s1, x1); + } + _mm_storeu_si128((__m128i*)(dst + i), s0); + _mm_storeu_si128((__m128i*)(dst + i + 16), s1); + } + + for( ; i <= width - 8; i += 8 ) + { + __m128i s0 = _mm_loadl_epi64((const __m128i*)(src[0] + i)), x0; + + for( k = 1; k < _ksize; k++ ) + { + x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i)); + s0 = updateOp(s0, x0); + } + _mm_storel_epi64((__m128i*)(dst + i), s0); + } + } + + return i/ESZ; + } + + int ksize, anchor; +}; + + +template struct MorphColumnFVec +{ + MorphColumnFVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {} + int operator()(const uchar** _src, uchar* _dst, int dststep, int count, int width) const + { + if( !checkHardwareSupport(CV_CPU_SSE) ) + return 0; + + int i = 0, k, _ksize = ksize; + VecUpdate updateOp; + + for( i = 0; i < count + ksize - 1; i++ ) + CV_Assert( ((size_t)_src[i] & 15) == 0 ); + + const float** src = (const float**)_src; + float* dst = (float*)_dst; + dststep /= sizeof(dst[0]); + + for( ; _ksize > 1 && count > 1; count -= 2, dst += dststep*2, src += 2 ) + { + for( i = 0; i <= width - 16; i += 16 ) + { + const float* sptr = src[1] + i; + __m128 s0 = _mm_load_ps(sptr); + __m128 s1 = _mm_load_ps(sptr + 4); + __m128 s2 = _mm_load_ps(sptr + 8); + __m128 s3 = _mm_load_ps(sptr + 12); + __m128 x0, x1, x2, x3; + + for( k = 2; k < _ksize; k++ ) + { + sptr = src[k] + i; + x0 = _mm_load_ps(sptr); + x1 = _mm_load_ps(sptr + 4); + s0 = updateOp(s0, x0); + s1 = updateOp(s1, x1); + x2 = _mm_load_ps(sptr + 8); + x3 = _mm_load_ps(sptr + 12); + s2 = updateOp(s2, x2); + s3 = updateOp(s3, x3); + } + + sptr = src[0] + i; + x0 = _mm_load_ps(sptr); + x1 = _mm_load_ps(sptr + 4); + x2 = _mm_load_ps(sptr + 8); + x3 = _mm_load_ps(sptr + 12); + _mm_storeu_ps(dst + i, updateOp(s0, x0)); + _mm_storeu_ps(dst + i + 4, updateOp(s1, x1)); + _mm_storeu_ps(dst + i + 8, updateOp(s2, x2)); + _mm_storeu_ps(dst + i + 12, updateOp(s3, x3)); + + sptr = src[k] + i; + x0 = _mm_load_ps(sptr); + x1 = _mm_load_ps(sptr + 4); + x2 = _mm_load_ps(sptr + 8); + x3 = _mm_load_ps(sptr + 12); + _mm_storeu_ps(dst + dststep + i, updateOp(s0, x0)); + _mm_storeu_ps(dst + dststep + i + 4, updateOp(s1, x1)); + _mm_storeu_ps(dst + dststep + i + 8, updateOp(s2, x2)); + _mm_storeu_ps(dst + dststep + i + 12, updateOp(s3, x3)); + } + + for( ; i <= width - 4; i += 4 ) + { + __m128 s0 = _mm_load_ps(src[1] + i), x0; + + for( k = 2; k < _ksize; k++ ) + { + x0 = _mm_load_ps(src[k] + i); + s0 = updateOp(s0, x0); + } + + x0 = _mm_load_ps(src[0] + i); + _mm_storeu_ps(dst + i, updateOp(s0, x0)); + x0 = _mm_load_ps(src[k] + i); + _mm_storeu_ps(dst + dststep + i, updateOp(s0, x0)); + } + } + + for( ; count > 0; count--, dst += dststep, src++ ) + { + for( i = 0; i <= width - 16; i += 16 ) + { + const float* sptr = src[0] + i; + __m128 s0 = _mm_load_ps(sptr); + __m128 s1 = _mm_load_ps(sptr + 4); + __m128 s2 = _mm_load_ps(sptr + 8); + __m128 s3 = _mm_load_ps(sptr + 12); + __m128 x0, x1, x2, x3; + + for( k = 1; k < _ksize; k++ ) + { + sptr = src[k] + i; + x0 = _mm_load_ps(sptr); + x1 = _mm_load_ps(sptr + 4); + s0 = updateOp(s0, x0); + s1 = updateOp(s1, x1); + x2 = _mm_load_ps(sptr + 8); + x3 = _mm_load_ps(sptr + 12); + s2 = updateOp(s2, x2); + s3 = updateOp(s3, x3); + } + _mm_storeu_ps(dst + i, s0); + _mm_storeu_ps(dst + i + 4, s1); + _mm_storeu_ps(dst + i + 8, s2); + _mm_storeu_ps(dst + i + 12, s3); + } + + for( i = 0; i <= width - 4; i += 4 ) + { + __m128 s0 = _mm_load_ps(src[0] + i), x0; + for( k = 1; k < _ksize; k++ ) + { + x0 = _mm_load_ps(src[k] + i); + s0 = updateOp(s0, x0); + } + _mm_storeu_ps(dst + i, s0); + } + } + + return i; + } + + int ksize, anchor; +}; + + +template struct MorphIVec +{ + enum { ESZ = VecUpdate::ESZ }; + + int operator()(uchar** src, int nz, uchar* dst, int width) const + { + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + int i, k; + width *= ESZ; + VecUpdate updateOp; + + for( i = 0; i <= width - 32; i += 32 ) + { + const uchar* sptr = src[0] + i; + __m128i s0 = _mm_loadu_si128((const __m128i*)sptr); + __m128i s1 = _mm_loadu_si128((const __m128i*)(sptr + 16)); + __m128i x0, x1; + + for( k = 1; k < nz; k++ ) + { + sptr = src[k] + i; + x0 = _mm_loadu_si128((const __m128i*)sptr); + x1 = _mm_loadu_si128((const __m128i*)(sptr + 16)); + s0 = updateOp(s0, x0); + s1 = updateOp(s1, x1); + } + _mm_storeu_si128((__m128i*)(dst + i), s0); + _mm_storeu_si128((__m128i*)(dst + i + 16), s1); + } + + for( ; i <= width - 8; i += 8 ) + { + __m128i s0 = _mm_loadl_epi64((const __m128i*)(src[0] + i)), x0; + + for( k = 1; k < nz; k++ ) + { + x0 = _mm_loadl_epi64((const __m128i*)(src[k] + i)); + s0 = updateOp(s0, x0); + } + _mm_storel_epi64((__m128i*)(dst + i), s0); + } + + return i/ESZ; + } +}; + + +template struct MorphFVec +{ + int operator()(uchar** _src, int nz, uchar* _dst, int width) const + { + if( !checkHardwareSupport(CV_CPU_SSE) ) + return 0; + + const float** src = (const float**)_src; + float* dst = (float*)_dst; + int i, k; + VecUpdate updateOp; + + for( i = 0; i <= width - 16; i += 16 ) + { + const float* sptr = src[0] + i; + __m128 s0 = _mm_loadu_ps(sptr); + __m128 s1 = _mm_loadu_ps(sptr + 4); + __m128 s2 = _mm_loadu_ps(sptr + 8); + __m128 s3 = _mm_loadu_ps(sptr + 12); + __m128 x0, x1, x2, x3; + + for( k = 1; k < nz; k++ ) + { + sptr = src[k] + i; + x0 = _mm_loadu_ps(sptr); + x1 = _mm_loadu_ps(sptr + 4); + x2 = _mm_loadu_ps(sptr + 8); + x3 = _mm_loadu_ps(sptr + 12); + s0 = updateOp(s0, x0); + s1 = updateOp(s1, x1); + s2 = updateOp(s2, x2); + s3 = updateOp(s3, x3); + } + _mm_storeu_ps(dst + i, s0); + _mm_storeu_ps(dst + i + 4, s1); + _mm_storeu_ps(dst + i + 8, s2); + _mm_storeu_ps(dst + i + 12, s3); + } + + for( ; i <= width - 4; i += 4 ) + { + __m128 s0 = _mm_loadu_ps(src[0] + i), x0; + + for( k = 1; k < nz; k++ ) + { + x0 = _mm_loadu_ps(src[k] + i); + s0 = updateOp(s0, x0); + } + _mm_storeu_ps(dst + i, s0); + } + + for( ; i < width; i++ ) + { + __m128 s0 = _mm_load_ss(src[0] + i), x0; + + for( k = 1; k < nz; k++ ) + { + x0 = _mm_load_ss(src[k] + i); + s0 = updateOp(s0, x0); + } + _mm_store_ss(dst + i, s0); + } + + return i; + } +}; + +struct VMin8u +{ + enum { ESZ = 1 }; + __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_min_epu8(a,b); } +}; +struct VMax8u +{ + enum { ESZ = 1 }; + __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_max_epu8(a,b); } +}; +struct VMin16u +{ + enum { ESZ = 2 }; + __m128i operator()(const __m128i& a, const __m128i& b) const + { return _mm_subs_epu16(a,_mm_subs_epu16(a,b)); } +}; +struct VMax16u +{ + enum { ESZ = 2 }; + __m128i operator()(const __m128i& a, const __m128i& b) const + { return _mm_adds_epu16(_mm_subs_epu16(a,b), b); } +}; +struct VMin16s +{ + enum { ESZ = 2 }; + __m128i operator()(const __m128i& a, const __m128i& b) const + { return _mm_min_epi16(a, b); } +}; +struct VMax16s +{ + enum { ESZ = 2 }; + __m128i operator()(const __m128i& a, const __m128i& b) const + { return _mm_max_epi16(a, b); } +}; +struct VMin32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_min_ps(a,b); }}; +struct VMax32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_max_ps(a,b); }}; + +typedef MorphRowIVec ErodeRowVec8u; +typedef MorphRowIVec DilateRowVec8u; +typedef MorphRowIVec ErodeRowVec16u; +typedef MorphRowIVec DilateRowVec16u; +typedef MorphRowIVec ErodeRowVec16s; +typedef MorphRowIVec DilateRowVec16s; +typedef MorphRowFVec ErodeRowVec32f; +typedef MorphRowFVec DilateRowVec32f; + +typedef MorphColumnIVec ErodeColumnVec8u; +typedef MorphColumnIVec DilateColumnVec8u; +typedef MorphColumnIVec ErodeColumnVec16u; +typedef MorphColumnIVec DilateColumnVec16u; +typedef MorphColumnIVec ErodeColumnVec16s; +typedef MorphColumnIVec DilateColumnVec16s; +typedef MorphColumnFVec ErodeColumnVec32f; +typedef MorphColumnFVec DilateColumnVec32f; + +typedef MorphIVec ErodeVec8u; +typedef MorphIVec DilateVec8u; +typedef MorphIVec ErodeVec16u; +typedef MorphIVec DilateVec16u; +typedef MorphIVec ErodeVec16s; +typedef MorphIVec DilateVec16s; +typedef MorphFVec ErodeVec32f; +typedef MorphFVec DilateVec32f; + +#else + +#ifdef HAVE_TEGRA_OPTIMIZATION +using tegra::ErodeRowVec8u; +using tegra::DilateRowVec8u; + +using tegra::ErodeColumnVec8u; +using tegra::DilateColumnVec8u; +#else +typedef MorphRowNoVec ErodeRowVec8u; +typedef MorphRowNoVec DilateRowVec8u; + +typedef MorphColumnNoVec ErodeColumnVec8u; +typedef MorphColumnNoVec DilateColumnVec8u; +#endif + +typedef MorphRowNoVec ErodeRowVec16u; +typedef MorphRowNoVec DilateRowVec16u; +typedef MorphRowNoVec ErodeRowVec16s; +typedef MorphRowNoVec DilateRowVec16s; +typedef MorphRowNoVec ErodeRowVec32f; +typedef MorphRowNoVec DilateRowVec32f; + +typedef MorphColumnNoVec ErodeColumnVec16u; +typedef MorphColumnNoVec DilateColumnVec16u; +typedef MorphColumnNoVec ErodeColumnVec16s; +typedef MorphColumnNoVec DilateColumnVec16s; +typedef MorphColumnNoVec ErodeColumnVec32f; +typedef MorphColumnNoVec DilateColumnVec32f; + +typedef MorphNoVec ErodeVec8u; +typedef MorphNoVec DilateVec8u; +typedef MorphNoVec ErodeVec16u; +typedef MorphNoVec DilateVec16u; +typedef MorphNoVec ErodeVec16s; +typedef MorphNoVec DilateVec16s; +typedef MorphNoVec ErodeVec32f; +typedef MorphNoVec DilateVec32f; + +#endif + +typedef MorphRowNoVec ErodeRowVec64f; +typedef MorphRowNoVec DilateRowVec64f; +typedef MorphColumnNoVec ErodeColumnVec64f; +typedef MorphColumnNoVec DilateColumnVec64f; +typedef MorphNoVec ErodeVec64f; +typedef MorphNoVec DilateVec64f; + + +template struct MorphRowFilter : public BaseRowFilter +{ + typedef typename Op::rtype T; + + MorphRowFilter( int _ksize, int _anchor ) : vecOp(_ksize, _anchor) + { + ksize = _ksize; + anchor = _anchor; + } + + void operator()(const uchar* src, uchar* dst, int width, int cn) + { + int i, j, k, _ksize = ksize*cn; + const T* S = (const T*)src; + Op op; + T* D = (T*)dst; + + if( _ksize == cn ) + { + for( i = 0; i < width*cn; i++ ) + D[i] = S[i]; + return; + } + + int i0 = vecOp(src, dst, width, cn); + width *= cn; + + for( k = 0; k < cn; k++, S++, D++ ) + { + for( i = i0; i <= width - cn*2; i += cn*2 ) + { + const T* s = S + i; + T m = s[cn]; + for( j = cn*2; j < _ksize; j += cn ) + m = op(m, s[j]); + D[i] = op(m, s[0]); + D[i+cn] = op(m, s[j]); + } + + for( ; i < width; i += cn ) + { + const T* s = S + i; + T m = s[0]; + for( j = cn; j < _ksize; j += cn ) + m = op(m, s[j]); + D[i] = m; + } + } + } + + VecOp vecOp; +}; + + +template struct MorphColumnFilter : public BaseColumnFilter +{ + typedef typename Op::rtype T; + + MorphColumnFilter( int _ksize, int _anchor ) : vecOp(_ksize, _anchor) + { + ksize = _ksize; + anchor = _anchor; + } + + void operator()(const uchar** _src, uchar* dst, int dststep, int count, int width) + { + int i, k, _ksize = ksize; + const T** src = (const T**)_src; + T* D = (T*)dst; + Op op; + + int i0 = vecOp(_src, dst, dststep, count, width); + dststep /= sizeof(D[0]); + + for( ; _ksize > 1 && count > 1; count -= 2, D += dststep*2, src += 2 ) + { + i = i0; + #if CV_ENABLE_UNROLLED + for( ; i <= width - 4; i += 4 ) + { + const T* sptr = src[1] + i; + T s0 = sptr[0], s1 = sptr[1], s2 = sptr[2], s3 = sptr[3]; + + for( k = 2; k < _ksize; k++ ) + { + sptr = src[k] + i; + s0 = op(s0, sptr[0]); s1 = op(s1, sptr[1]); + s2 = op(s2, sptr[2]); s3 = op(s3, sptr[3]); + } + + sptr = src[0] + i; + D[i] = op(s0, sptr[0]); + D[i+1] = op(s1, sptr[1]); + D[i+2] = op(s2, sptr[2]); + D[i+3] = op(s3, sptr[3]); + + sptr = src[k] + i; + D[i+dststep] = op(s0, sptr[0]); + D[i+dststep+1] = op(s1, sptr[1]); + D[i+dststep+2] = op(s2, sptr[2]); + D[i+dststep+3] = op(s3, sptr[3]); + } + #endif + for( ; i < width; i++ ) + { + T s0 = src[1][i]; + + for( k = 2; k < _ksize; k++ ) + s0 = op(s0, src[k][i]); + + D[i] = op(s0, src[0][i]); + D[i+dststep] = op(s0, src[k][i]); + } + } + + for( ; count > 0; count--, D += dststep, src++ ) + { + i = i0; + #if CV_ENABLE_UNROLLED + for( ; i <= width - 4; i += 4 ) + { + const T* sptr = src[0] + i; + T s0 = sptr[0], s1 = sptr[1], s2 = sptr[2], s3 = sptr[3]; + + for( k = 1; k < _ksize; k++ ) + { + sptr = src[k] + i; + s0 = op(s0, sptr[0]); s1 = op(s1, sptr[1]); + s2 = op(s2, sptr[2]); s3 = op(s3, sptr[3]); + } + + D[i] = s0; D[i+1] = s1; + D[i+2] = s2; D[i+3] = s3; + } + #endif + for( ; i < width; i++ ) + { + T s0 = src[0][i]; + for( k = 1; k < _ksize; k++ ) + s0 = op(s0, src[k][i]); + D[i] = s0; + } + } + } + + VecOp vecOp; +}; + + +template struct MorphFilter : BaseFilter +{ + typedef typename Op::rtype T; + + MorphFilter( const Mat& _kernel, Point _anchor ) + { + anchor = _anchor; + ksize = _kernel.size(); + CV_Assert( _kernel.type() == CV_8U ); + + vector coeffs; // we do not really the values of non-zero + // kernel elements, just their locations + preprocess2DKernel( _kernel, coords, coeffs ); + ptrs.resize( coords.size() ); + } + + void operator()(const uchar** src, uchar* dst, int dststep, int count, int width, int cn) + { + const Point* pt = &coords[0]; + const T** kp = (const T**)&ptrs[0]; + int i, k, nz = (int)coords.size(); + Op op; + + width *= cn; + for( ; count > 0; count--, dst += dststep, src++ ) + { + T* D = (T*)dst; + + for( k = 0; k < nz; k++ ) + kp[k] = (const T*)src[pt[k].y] + pt[k].x*cn; + + i = vecOp(&ptrs[0], nz, dst, width); + #if CV_ENABLE_UNROLLED + for( ; i <= width - 4; i += 4 ) + { + const T* sptr = kp[0] + i; + T s0 = sptr[0], s1 = sptr[1], s2 = sptr[2], s3 = sptr[3]; + + for( k = 1; k < nz; k++ ) + { + sptr = kp[k] + i; + s0 = op(s0, sptr[0]); s1 = op(s1, sptr[1]); + s2 = op(s2, sptr[2]); s3 = op(s3, sptr[3]); + } + + D[i] = s0; D[i+1] = s1; + D[i+2] = s2; D[i+3] = s3; + } + #endif + for( ; i < width; i++ ) + { + T s0 = kp[0][i]; + for( k = 1; k < nz; k++ ) + s0 = op(s0, kp[k][i]); + D[i] = s0; + } + } + } + + vector coords; + vector ptrs; + VecOp vecOp; +}; + +} + +/////////////////////////////////// External Interface ///////////////////////////////////// + +cv::Ptr cv::getMorphologyRowFilter(int op, int type, int ksize, int anchor) +{ + int depth = CV_MAT_DEPTH(type); + if( anchor < 0 ) + anchor = ksize/2; + CV_Assert( op == MORPH_ERODE || op == MORPH_DILATE ); + if( op == MORPH_ERODE ) + { + if( depth == CV_8U ) + return Ptr(new MorphRowFilter, + ErodeRowVec8u>(ksize, anchor)); + if( depth == CV_16U ) + return Ptr(new MorphRowFilter, + ErodeRowVec16u>(ksize, anchor)); + if( depth == CV_16S ) + return Ptr(new MorphRowFilter, + ErodeRowVec16s>(ksize, anchor)); + if( depth == CV_32F ) + return Ptr(new MorphRowFilter, + ErodeRowVec32f>(ksize, anchor)); + if( depth == CV_64F ) + return Ptr(new MorphRowFilter, + ErodeRowVec64f>(ksize, anchor)); + } + else + { + if( depth == CV_8U ) + return Ptr(new MorphRowFilter, + DilateRowVec8u>(ksize, anchor)); + if( depth == CV_16U ) + return Ptr(new MorphRowFilter, + DilateRowVec16u>(ksize, anchor)); + if( depth == CV_16S ) + return Ptr(new MorphRowFilter, + DilateRowVec16s>(ksize, anchor)); + if( depth == CV_32F ) + return Ptr(new MorphRowFilter, + DilateRowVec32f>(ksize, anchor)); + if( depth == CV_64F ) + return Ptr(new MorphRowFilter, + DilateRowVec64f>(ksize, anchor)); + } + + CV_Error_( CV_StsNotImplemented, ("Unsupported data type (=%d)", type)); + return Ptr(0); +} + +cv::Ptr cv::getMorphologyColumnFilter(int op, int type, int ksize, int anchor) +{ + int depth = CV_MAT_DEPTH(type); + if( anchor < 0 ) + anchor = ksize/2; + CV_Assert( op == MORPH_ERODE || op == MORPH_DILATE ); + if( op == MORPH_ERODE ) + { + if( depth == CV_8U ) + return Ptr(new MorphColumnFilter, + ErodeColumnVec8u>(ksize, anchor)); + if( depth == CV_16U ) + return Ptr(new MorphColumnFilter, + ErodeColumnVec16u>(ksize, anchor)); + if( depth == CV_16S ) + return Ptr(new MorphColumnFilter, + ErodeColumnVec16s>(ksize, anchor)); + if( depth == CV_32F ) + return Ptr(new MorphColumnFilter, + ErodeColumnVec32f>(ksize, anchor)); + if( depth == CV_64F ) + return Ptr(new MorphColumnFilter, + ErodeColumnVec64f>(ksize, anchor)); + } + else + { + if( depth == CV_8U ) + return Ptr(new MorphColumnFilter, + DilateColumnVec8u>(ksize, anchor)); + if( depth == CV_16U ) + return Ptr(new MorphColumnFilter, + DilateColumnVec16u>(ksize, anchor)); + if( depth == CV_16S ) + return Ptr(new MorphColumnFilter, + DilateColumnVec16s>(ksize, anchor)); + if( depth == CV_32F ) + return Ptr(new MorphColumnFilter, + DilateColumnVec32f>(ksize, anchor)); + if( depth == CV_64F ) + return Ptr(new MorphColumnFilter, + DilateColumnVec64f>(ksize, anchor)); + } + + CV_Error_( CV_StsNotImplemented, ("Unsupported data type (=%d)", type)); + return Ptr(0); +} + + +cv::Ptr cv::getMorphologyFilter(int op, int type, InputArray _kernel, Point anchor) +{ + Mat kernel = _kernel.getMat(); + int depth = CV_MAT_DEPTH(type); + anchor = normalizeAnchor(anchor, kernel.size()); + CV_Assert( op == MORPH_ERODE || op == MORPH_DILATE ); + if( op == MORPH_ERODE ) + { + if( depth == CV_8U ) + return Ptr(new MorphFilter, ErodeVec8u>(kernel, anchor)); + if( depth == CV_16U ) + return Ptr(new MorphFilter, ErodeVec16u>(kernel, anchor)); + if( depth == CV_16S ) + return Ptr(new MorphFilter, ErodeVec16s>(kernel, anchor)); + if( depth == CV_32F ) + return Ptr(new MorphFilter, ErodeVec32f>(kernel, anchor)); + if( depth == CV_64F ) + return Ptr(new MorphFilter, ErodeVec64f>(kernel, anchor)); + } + else + { + if( depth == CV_8U ) + return Ptr(new MorphFilter, DilateVec8u>(kernel, anchor)); + if( depth == CV_16U ) + return Ptr(new MorphFilter, DilateVec16u>(kernel, anchor)); + if( depth == CV_16S ) + return Ptr(new MorphFilter, DilateVec16s>(kernel, anchor)); + if( depth == CV_32F ) + return Ptr(new MorphFilter, DilateVec32f>(kernel, anchor)); + if( depth == CV_64F ) + return Ptr(new MorphFilter, DilateVec64f>(kernel, anchor)); + } + + CV_Error_( CV_StsNotImplemented, ("Unsupported data type (=%d)", type)); + return Ptr(0); +} + + +cv::Ptr cv::createMorphologyFilter( int op, int type, InputArray _kernel, + Point anchor, int _rowBorderType, int _columnBorderType, + const Scalar& _borderValue ) +{ + Mat kernel = _kernel.getMat(); + anchor = normalizeAnchor(anchor, kernel.size()); + + Ptr rowFilter; + Ptr columnFilter; + Ptr filter2D; + + if( countNonZero(kernel) == kernel.rows*kernel.cols ) + { + // rectangular structuring element + rowFilter = getMorphologyRowFilter(op, type, kernel.cols, anchor.x); + columnFilter = getMorphologyColumnFilter(op, type, kernel.rows, anchor.y); + } + else + filter2D = getMorphologyFilter(op, type, kernel, anchor); + + Scalar borderValue = _borderValue; + if( (_rowBorderType == BORDER_CONSTANT || _columnBorderType == BORDER_CONSTANT) && + borderValue == morphologyDefaultBorderValue() ) + { + int depth = CV_MAT_DEPTH(type); + CV_Assert( depth == CV_8U || depth == CV_16U || depth == CV_16S || + depth == CV_32F || depth == CV_64F ); + if( op == MORPH_ERODE ) + borderValue = Scalar::all( depth == CV_8U ? (double)UCHAR_MAX : + depth == CV_16U ? (double)USHRT_MAX : + depth == CV_16S ? (double)SHRT_MAX : + depth == CV_32F ? (double)FLT_MAX : DBL_MAX); + else + borderValue = Scalar::all( depth == CV_8U || depth == CV_16U ? + 0. : + depth == CV_16S ? (double)SHRT_MIN : + depth == CV_32F ? (double)-FLT_MAX : -DBL_MAX); + } + + return Ptr(new FilterEngine(filter2D, rowFilter, columnFilter, + type, type, type, _rowBorderType, _columnBorderType, borderValue )); +} + + +cv::Mat cv::getStructuringElement(int shape, Size ksize, Point anchor) +{ + int i, j; + int r = 0, c = 0; + double inv_r2 = 0; + + CV_Assert( shape == MORPH_RECT || shape == MORPH_CROSS || shape == MORPH_ELLIPSE ); + + anchor = normalizeAnchor(anchor, ksize); + + if( ksize == Size(1,1) ) + shape = MORPH_RECT; + + if( shape == MORPH_ELLIPSE ) + { + r = ksize.height/2; + c = ksize.width/2; + inv_r2 = r ? 1./((double)r*r) : 0; + } + + Mat elem(ksize, CV_8U); + + for( i = 0; i < ksize.height; i++ ) + { + uchar* ptr = elem.data + i*elem.step; + int j1 = 0, j2 = 0; + + if( shape == MORPH_RECT || (shape == MORPH_CROSS && i == anchor.y) ) + j2 = ksize.width; + else if( shape == MORPH_CROSS ) + j1 = anchor.x, j2 = j1 + 1; + else + { + int dy = i - r; + if( std::abs(dy) <= r ) + { + int dx = saturate_cast(c*std::sqrt((r*r - dy*dy)*inv_r2)); + j1 = std::max( c - dx, 0 ); + j2 = std::min( c + dx + 1, ksize.width ); + } + } + + for( j = 0; j < j1; j++ ) + ptr[j] = 0; + for( ; j < j2; j++ ) + ptr[j] = 1; + for( ; j < ksize.width; j++ ) + ptr[j] = 0; + } + + return elem; +} + +namespace cv +{ + +class MorphologyRunner +{ +public: + MorphologyRunner(Mat _src, Mat _dst, int _nStripes, int _iterations, + int _op, Mat _kernel, Point _anchor, + int _rowBorderType, int _columnBorderType, const Scalar& _borderValue) : + borderValue(_borderValue) + { + src = _src; + dst = _dst; + + nStripes = _nStripes; + iterations = _iterations; + + op = _op; + kernel = _kernel; + anchor = _anchor; + rowBorderType = _rowBorderType; + columnBorderType = _columnBorderType; + } + + void operator () ( const BlockedRange& range ) const + { + int row0 = min(cvRound(range.begin() * src.rows / nStripes), src.rows); + int row1 = min(cvRound(range.end() * src.rows / nStripes), src.rows); + + /*if(0) + printf("Size = (%d, %d), range[%d,%d), row0 = %d, row1 = %d\n", + src.rows, src.cols, range.begin(), range.end(), row0, row1);*/ + + Mat srcStripe = src.rowRange(row0, row1); + Mat dstStripe = dst.rowRange(row0, row1); + + Ptr f = createMorphologyFilter(op, src.type(), kernel, anchor, + rowBorderType, columnBorderType, borderValue ); + + f->apply( srcStripe, dstStripe ); + for( int i = 1; i < iterations; i++ ) + f->apply( dstStripe, dstStripe ); + } + +private: + Mat src; + Mat dst; + int nStripes; + int iterations; + + int op; + Mat kernel; + Point anchor; + int rowBorderType; + int columnBorderType; + Scalar borderValue; +}; + +static void morphOp( int op, InputArray _src, OutputArray _dst, + InputArray _kernel, + Point anchor, int iterations, + int borderType, const Scalar& borderValue ) +{ + Mat src = _src.getMat(), kernel = _kernel.getMat(); + Size ksize = kernel.data ? kernel.size() : Size(3,3); + anchor = normalizeAnchor(anchor, ksize); + + CV_Assert( anchor.inside(Rect(0, 0, ksize.width, ksize.height)) ); + + _dst.create( src.size(), src.type() ); + Mat dst = _dst.getMat(); + + if( iterations == 0 || kernel.rows*kernel.cols == 1 ) + { + src.copyTo(dst); + return; + } + + if( !kernel.data ) + { + kernel = getStructuringElement(MORPH_RECT, Size(1+iterations*2,1+iterations*2)); + anchor = Point(iterations, iterations); + iterations = 1; + } + else if( iterations > 1 && countNonZero(kernel) == kernel.rows*kernel.cols ) + { + anchor = Point(anchor.x*iterations, anchor.y*iterations); + kernel = getStructuringElement(MORPH_RECT, + Size(ksize.width + iterations*(ksize.width-1), + ksize.height + iterations*(ksize.height-1)), + anchor); + iterations = 1; + } + + int nStripes = 1; +#if defined HAVE_TBB && defined HAVE_TEGRA_OPTIMIZATION + if (src.data != dst.data && iterations == 1 && //NOTE: threads are not used for inplace processing + (borderType & BORDER_ISOLATED) == 0 && //TODO: check border types + src.rows >= 64 ) //NOTE: just heuristics + nStripes = 4; +#endif + + parallel_for(BlockedRange(0, nStripes), + MorphologyRunner(src, dst, nStripes, iterations, op, kernel, anchor, borderType, borderType, borderValue)); + + //Ptr f = createMorphologyFilter(op, src.type(), + // kernel, anchor, borderType, borderType, borderValue ); + + //f->apply( src, dst ); + //for( int i = 1; i < iterations; i++ ) + // f->apply( dst, dst ); +} + +template<> void Ptr::delete_obj() +{ cvReleaseStructuringElement(&obj); } + +} + +void cv::erode( InputArray src, OutputArray dst, InputArray kernel, + Point anchor, int iterations, + int borderType, const Scalar& borderValue ) +{ + morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType, borderValue ); +} + + +void cv::dilate( InputArray src, OutputArray dst, InputArray kernel, + Point anchor, int iterations, + int borderType, const Scalar& borderValue ) +{ + morphOp( MORPH_DILATE, src, dst, kernel, anchor, iterations, borderType, borderValue ); +} + + +void cv::morphologyEx( InputArray _src, OutputArray _dst, int op, + InputArray kernel, Point anchor, int iterations, + int borderType, const Scalar& borderValue ) +{ + Mat src = _src.getMat(), temp; + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + + switch( op ) + { + case MORPH_ERODE: + erode( src, dst, kernel, anchor, iterations, borderType, borderValue ); + break; + case MORPH_DILATE: + dilate( src, dst, kernel, anchor, iterations, borderType, borderValue ); + break; + case MORPH_OPEN: + erode( src, dst, kernel, anchor, iterations, borderType, borderValue ); + dilate( dst, dst, kernel, anchor, iterations, borderType, borderValue ); + break; + case CV_MOP_CLOSE: + dilate( src, dst, kernel, anchor, iterations, borderType, borderValue ); + erode( dst, dst, kernel, anchor, iterations, borderType, borderValue ); + break; + case CV_MOP_GRADIENT: + erode( src, temp, kernel, anchor, iterations, borderType, borderValue ); + dilate( src, dst, kernel, anchor, iterations, borderType, borderValue ); + dst -= temp; + break; + case CV_MOP_TOPHAT: + if( src.data != dst.data ) + temp = dst; + erode( src, temp, kernel, anchor, iterations, borderType, borderValue ); + dilate( temp, temp, kernel, anchor, iterations, borderType, borderValue ); + dst = src - temp; + break; + case CV_MOP_BLACKHAT: + if( src.data != dst.data ) + temp = dst; + dilate( src, temp, kernel, anchor, iterations, borderType, borderValue ); + erode( temp, temp, kernel, anchor, iterations, borderType, borderValue ); + dst = temp - src; + break; + default: + CV_Error( CV_StsBadArg, "unknown morphological operation" ); + } +} + +CV_IMPL IplConvKernel * +cvCreateStructuringElementEx( int cols, int rows, + int anchorX, int anchorY, + int shape, int *values ) +{ + cv::Size ksize = cv::Size(cols, rows); + cv::Point anchor = cv::Point(anchorX, anchorY); + CV_Assert( cols > 0 && rows > 0 && anchor.inside(cv::Rect(0,0,cols,rows)) && + (shape != CV_SHAPE_CUSTOM || values != 0)); + + int i, size = rows * cols; + int element_size = sizeof(IplConvKernel) + size*sizeof(int); + IplConvKernel *element = (IplConvKernel*)cvAlloc(element_size + 32); + + element->nCols = cols; + element->nRows = rows; + element->anchorX = anchorX; + element->anchorY = anchorY; + element->nShiftR = shape < CV_SHAPE_ELLIPSE ? shape : CV_SHAPE_CUSTOM; + element->values = (int*)(element + 1); + + if( shape == CV_SHAPE_CUSTOM ) + { + for( i = 0; i < size; i++ ) + element->values[i] = values[i]; + } + else + { + cv::Mat elem = cv::getStructuringElement(shape, ksize, anchor); + for( i = 0; i < size; i++ ) + element->values[i] = elem.data[i]; + } + + return element; +} + + +CV_IMPL void +cvReleaseStructuringElement( IplConvKernel ** element ) +{ + if( !element ) + CV_Error( CV_StsNullPtr, "" ); + cvFree( element ); +} + + +static void convertConvKernel( const IplConvKernel* src, cv::Mat& dst, cv::Point& anchor ) +{ + if(!src) + { + anchor = cv::Point(1,1); + dst.release(); + return; + } + anchor = cv::Point(src->anchorX, src->anchorY); + dst.create(src->nRows, src->nCols, CV_8U); + + int i, size = src->nRows*src->nCols; + for( i = 0; i < size; i++ ) + dst.data[i] = (uchar)src->values[i]; +} + + +CV_IMPL void +cvErode( const CvArr* srcarr, CvArr* dstarr, IplConvKernel* element, int iterations ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), kernel; + CV_Assert( src.size() == dst.size() && src.type() == dst.type() ); + cv::Point anchor; + convertConvKernel( element, kernel, anchor ); + cv::erode( src, dst, kernel, anchor, iterations, cv::BORDER_REPLICATE ); +} + + +CV_IMPL void +cvDilate( const CvArr* srcarr, CvArr* dstarr, IplConvKernel* element, int iterations ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), kernel; + CV_Assert( src.size() == dst.size() && src.type() == dst.type() ); + cv::Point anchor; + convertConvKernel( element, kernel, anchor ); + cv::dilate( src, dst, kernel, anchor, iterations, cv::BORDER_REPLICATE ); +} + + +CV_IMPL void +cvMorphologyEx( const void* srcarr, void* dstarr, void*, + IplConvKernel* element, int op, int iterations ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), kernel; + CV_Assert( src.size() == dst.size() && src.type() == dst.type() ); + cv::Point anchor; + IplConvKernel* temp_element = NULL; + if (!element) + { + temp_element = cvCreateStructuringElementEx(3, 3, 1, 1, CV_SHAPE_RECT); + } else { + temp_element = element; + } + convertConvKernel( temp_element, kernel, anchor ); + if (!element) + { + cvReleaseStructuringElement(&temp_element); + } + cv::morphologyEx( src, dst, op, kernel, anchor, iterations, cv::BORDER_REPLICATE ); +} + +/* End of file. */ diff --git a/imgproc/src/phasecorr.cpp b/imgproc/src/phasecorr.cpp new file mode 100644 index 0000000..3b6c2eb --- /dev/null +++ b/imgproc/src/phasecorr.cpp @@ -0,0 +1,611 @@ +/********************************************************************* + * Software License Agreement (BSD License) + * + * Copyright (c) 2008-2011, William Lucas + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the Willow Garage nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 + * COPYRIGHT OWNER OR CONTRIBUTORS 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. + *********************************************************************/ + +#include "precomp.hpp" +#include + +namespace cv +{ + +static void magSpectrums( InputArray _src, OutputArray _dst) +{ + Mat src = _src.getMat(); + int depth = src.depth(), cn = src.channels(), type = src.type(); + int rows = src.rows, cols = src.cols; + int j, k; + + CV_Assert( type == CV_32FC1 || type == CV_32FC2 || type == CV_64FC1 || type == CV_64FC2 ); + + if(src.depth() == CV_32F) + _dst.create( src.rows, src.cols, CV_32FC1 ); + else + _dst.create( src.rows, src.cols, CV_64FC1 ); + + Mat dst = _dst.getMat(); + dst.setTo(0);//Mat elements are not equal to zero by default! + + bool is_1d = (rows == 1 || (cols == 1 && src.isContinuous() && dst.isContinuous())); + + if( is_1d ) + cols = cols + rows - 1, rows = 1; + + int ncols = cols*cn; + int j0 = cn == 1; + int j1 = ncols - (cols % 2 == 0 && cn == 1); + + if( depth == CV_32F ) + { + const float* dataSrc = (const float*)src.data; + float* dataDst = (float*)dst.data; + + size_t stepSrc = src.step/sizeof(dataSrc[0]); + size_t stepDst = dst.step/sizeof(dataDst[0]); + + if( !is_1d && cn == 1 ) + { + for( k = 0; k < (cols % 2 ? 1 : 2); k++ ) + { + if( k == 1 ) + dataSrc += cols - 1, dataDst += cols - 1; + dataDst[0] = dataSrc[0]*dataSrc[0]; + if( rows % 2 == 0 ) + dataDst[(rows-1)*stepDst] = dataSrc[(rows-1)*stepSrc]*dataSrc[(rows-1)*stepSrc]; + + for( j = 1; j <= rows - 2; j += 2 ) + { + dataDst[j*stepDst] = (float)std::sqrt((double)dataSrc[j*stepSrc]*dataSrc[j*stepSrc] + + (double)dataSrc[(j+1)*stepSrc]*dataSrc[(j+1)*stepSrc]); + } + + if( k == 1 ) + dataSrc -= cols - 1, dataDst -= cols - 1; + } + } + + for( ; rows--; dataSrc += stepSrc, dataDst += stepDst ) + { + if( is_1d && cn == 1 ) + { + dataDst[0] = dataSrc[0]*dataSrc[0]; + if( cols % 2 == 0 ) + dataDst[j1] = dataSrc[j1]*dataSrc[j1]; + } + + for( j = j0; j < j1; j += 2 ) + { + dataDst[j] = (float)std::sqrt((double)dataSrc[j]*dataSrc[j] + (double)dataSrc[j+1]*dataSrc[j+1]); + } + } + } + else + { + const double* dataSrc = (const double*)src.data; + double* dataDst = (double*)dst.data; + + size_t stepSrc = src.step/sizeof(dataSrc[0]); + size_t stepDst = dst.step/sizeof(dataDst[0]); + + if( !is_1d && cn == 1 ) + { + for( k = 0; k < (cols % 2 ? 1 : 2); k++ ) + { + if( k == 1 ) + dataSrc += cols - 1, dataDst += cols - 1; + dataDst[0] = dataSrc[0]*dataSrc[0]; + if( rows % 2 == 0 ) + dataDst[(rows-1)*stepDst] = dataSrc[(rows-1)*stepSrc]*dataSrc[(rows-1)*stepSrc]; + + for( j = 1; j <= rows - 2; j += 2 ) + { + dataDst[j*stepDst] = std::sqrt(dataSrc[j*stepSrc]*dataSrc[j*stepSrc] + + dataSrc[(j+1)*stepSrc]*dataSrc[(j+1)*stepSrc]); + } + + if( k == 1 ) + dataSrc -= cols - 1, dataDst -= cols - 1; + } + } + + for( ; rows--; dataSrc += stepSrc, dataDst += stepDst ) + { + if( is_1d && cn == 1 ) + { + dataDst[0] = dataSrc[0]*dataSrc[0]; + if( cols % 2 == 0 ) + dataDst[j1] = dataSrc[j1]*dataSrc[j1]; + } + + for( j = j0; j < j1; j += 2 ) + { + dataDst[j] = std::sqrt(dataSrc[j]*dataSrc[j] + dataSrc[j+1]*dataSrc[j+1]); + } + } + } +} + +static void divSpectrums( InputArray _srcA, InputArray _srcB, OutputArray _dst, int flags, bool conjB) +{ + Mat srcA = _srcA.getMat(), srcB = _srcB.getMat(); + int depth = srcA.depth(), cn = srcA.channels(), type = srcA.type(); + int rows = srcA.rows, cols = srcA.cols; + int j, k; + + CV_Assert( type == srcB.type() && srcA.size() == srcB.size() ); + CV_Assert( type == CV_32FC1 || type == CV_32FC2 || type == CV_64FC1 || type == CV_64FC2 ); + + _dst.create( srcA.rows, srcA.cols, type ); + Mat dst = _dst.getMat(); + + bool is_1d = (flags & DFT_ROWS) || (rows == 1 || (cols == 1 && + srcA.isContinuous() && srcB.isContinuous() && dst.isContinuous())); + + if( is_1d && !(flags & DFT_ROWS) ) + cols = cols + rows - 1, rows = 1; + + int ncols = cols*cn; + int j0 = cn == 1; + int j1 = ncols - (cols % 2 == 0 && cn == 1); + + if( depth == CV_32F ) + { + const float* dataA = (const float*)srcA.data; + const float* dataB = (const float*)srcB.data; + float* dataC = (float*)dst.data; + float eps = FLT_EPSILON; // prevent div0 problems + + size_t stepA = srcA.step/sizeof(dataA[0]); + size_t stepB = srcB.step/sizeof(dataB[0]); + size_t stepC = dst.step/sizeof(dataC[0]); + + if( !is_1d && cn == 1 ) + { + for( k = 0; k < (cols % 2 ? 1 : 2); k++ ) + { + if( k == 1 ) + dataA += cols - 1, dataB += cols - 1, dataC += cols - 1; + dataC[0] = dataA[0] / (dataB[0] + eps); + if( rows % 2 == 0 ) + dataC[(rows-1)*stepC] = dataA[(rows-1)*stepA] / (dataB[(rows-1)*stepB] + eps); + if( !conjB ) + for( j = 1; j <= rows - 2; j += 2 ) + { + double denom = (double)dataB[j*stepB]*dataB[j*stepB] + + (double)dataB[(j+1)*stepB]*dataB[(j+1)*stepB] + (double)eps; + + double re = (double)dataA[j*stepA]*dataB[j*stepB] + + (double)dataA[(j+1)*stepA]*dataB[(j+1)*stepB]; + + double im = (double)dataA[(j+1)*stepA]*dataB[j*stepB] - + (double)dataA[j*stepA]*dataB[(j+1)*stepB]; + + dataC[j*stepC] = (float)(re / denom); + dataC[(j+1)*stepC] = (float)(im / denom); + } + else + for( j = 1; j <= rows - 2; j += 2 ) + { + + double denom = (double)dataB[j*stepB]*dataB[j*stepB] + + (double)dataB[(j+1)*stepB]*dataB[(j+1)*stepB] + (double)eps; + + double re = (double)dataA[j*stepA]*dataB[j*stepB] - + (double)dataA[(j+1)*stepA]*dataB[(j+1)*stepB]; + + double im = (double)dataA[(j+1)*stepA]*dataB[j*stepB] + + (double)dataA[j*stepA]*dataB[(j+1)*stepB]; + + dataC[j*stepC] = (float)(re / denom); + dataC[(j+1)*stepC] = (float)(im / denom); + } + if( k == 1 ) + dataA -= cols - 1, dataB -= cols - 1, dataC -= cols - 1; + } + } + + for( ; rows--; dataA += stepA, dataB += stepB, dataC += stepC ) + { + if( is_1d && cn == 1 ) + { + dataC[0] = dataA[0] / (dataB[0] + eps); + if( cols % 2 == 0 ) + dataC[j1] = dataA[j1] / (dataB[j1] + eps); + } + + if( !conjB ) + for( j = j0; j < j1; j += 2 ) + { + double denom = (double)(dataB[j]*dataB[j] + dataB[j+1]*dataB[j+1] + eps); + double re = (double)(dataA[j]*dataB[j] + dataA[j+1]*dataB[j+1]); + double im = (double)(dataA[j+1]*dataB[j] - dataA[j]*dataB[j+1]); + dataC[j] = (float)(re / denom); + dataC[j+1] = (float)(im / denom); + } + else + for( j = j0; j < j1; j += 2 ) + { + double denom = (double)(dataB[j]*dataB[j] + dataB[j+1]*dataB[j+1] + eps); + double re = (double)(dataA[j]*dataB[j] - dataA[j+1]*dataB[j+1]); + double im = (double)(dataA[j+1]*dataB[j] + dataA[j]*dataB[j+1]); + dataC[j] = (float)(re / denom); + dataC[j+1] = (float)(im / denom); + } + } + } + else + { + const double* dataA = (const double*)srcA.data; + const double* dataB = (const double*)srcB.data; + double* dataC = (double*)dst.data; + double eps = DBL_EPSILON; // prevent div0 problems + + size_t stepA = srcA.step/sizeof(dataA[0]); + size_t stepB = srcB.step/sizeof(dataB[0]); + size_t stepC = dst.step/sizeof(dataC[0]); + + if( !is_1d && cn == 1 ) + { + for( k = 0; k < (cols % 2 ? 1 : 2); k++ ) + { + if( k == 1 ) + dataA += cols - 1, dataB += cols - 1, dataC += cols - 1; + dataC[0] = dataA[0] / (dataB[0] + eps); + if( rows % 2 == 0 ) + dataC[(rows-1)*stepC] = dataA[(rows-1)*stepA] / (dataB[(rows-1)*stepB] + eps); + if( !conjB ) + for( j = 1; j <= rows - 2; j += 2 ) + { + double denom = dataB[j*stepB]*dataB[j*stepB] + + dataB[(j+1)*stepB]*dataB[(j+1)*stepB] + eps; + + double re = dataA[j*stepA]*dataB[j*stepB] + + dataA[(j+1)*stepA]*dataB[(j+1)*stepB]; + + double im = dataA[(j+1)*stepA]*dataB[j*stepB] - + dataA[j*stepA]*dataB[(j+1)*stepB]; + + dataC[j*stepC] = re / denom; + dataC[(j+1)*stepC] = im / denom; + } + else + for( j = 1; j <= rows - 2; j += 2 ) + { + double denom = dataB[j*stepB]*dataB[j*stepB] + + dataB[(j+1)*stepB]*dataB[(j+1)*stepB] + eps; + + double re = dataA[j*stepA]*dataB[j*stepB] - + dataA[(j+1)*stepA]*dataB[(j+1)*stepB]; + + double im = dataA[(j+1)*stepA]*dataB[j*stepB] + + dataA[j*stepA]*dataB[(j+1)*stepB]; + + dataC[j*stepC] = re / denom; + dataC[(j+1)*stepC] = im / denom; + } + if( k == 1 ) + dataA -= cols - 1, dataB -= cols - 1, dataC -= cols - 1; + } + } + + for( ; rows--; dataA += stepA, dataB += stepB, dataC += stepC ) + { + if( is_1d && cn == 1 ) + { + dataC[0] = dataA[0] / (dataB[0] + eps); + if( cols % 2 == 0 ) + dataC[j1] = dataA[j1] / (dataB[j1] + eps); + } + + if( !conjB ) + for( j = j0; j < j1; j += 2 ) + { + double denom = dataB[j]*dataB[j] + dataB[j+1]*dataB[j+1] + eps; + double re = dataA[j]*dataB[j] + dataA[j+1]*dataB[j+1]; + double im = dataA[j+1]*dataB[j] - dataA[j]*dataB[j+1]; + dataC[j] = re / denom; + dataC[j+1] = im / denom; + } + else + for( j = j0; j < j1; j += 2 ) + { + double denom = dataB[j]*dataB[j] + dataB[j+1]*dataB[j+1] + eps; + double re = dataA[j]*dataB[j] - dataA[j+1]*dataB[j+1]; + double im = dataA[j+1]*dataB[j] + dataA[j]*dataB[j+1]; + dataC[j] = re / denom; + dataC[j+1] = im / denom; + } + } + } + +} + +static void fftShift(InputOutputArray _out) +{ + Mat out = _out.getMat(); + + if(out.rows == 1 && out.cols == 1) + { + // trivially shifted. + return; + } + + vector planes; + split(out, planes); + + int xMid = out.cols >> 1; + int yMid = out.rows >> 1; + + bool is_1d = xMid == 0 || yMid == 0; + + if(is_1d) + { + xMid = xMid + yMid; + + for(size_t i = 0; i < planes.size(); i++) + { + Mat tmp; + Mat half0(planes[i], Rect(0, 0, xMid, 1)); + Mat half1(planes[i], Rect(xMid, 0, xMid, 1)); + + half0.copyTo(tmp); + half1.copyTo(half0); + tmp.copyTo(half1); + } + } + else + { + for(size_t i = 0; i < planes.size(); i++) + { + // perform quadrant swaps... + Mat tmp; + Mat q0(planes[i], Rect(0, 0, xMid, yMid)); + Mat q1(planes[i], Rect(xMid, 0, xMid, yMid)); + Mat q2(planes[i], Rect(0, yMid, xMid, yMid)); + Mat q3(planes[i], Rect(xMid, yMid, xMid, yMid)); + + q0.copyTo(tmp); + q3.copyTo(q0); + tmp.copyTo(q3); + + q1.copyTo(tmp); + q2.copyTo(q1); + tmp.copyTo(q2); + } + } + + merge(planes, out); +} + +static Point2d weightedCentroid(InputArray _src, cv::Point peakLocation, cv::Size weightBoxSize, double* response) +{ + Mat src = _src.getMat(); + + int type = src.type(); + CV_Assert( type == CV_32FC1 || type == CV_64FC1 ); + + int minr = peakLocation.y - (weightBoxSize.height >> 1); + int maxr = peakLocation.y + (weightBoxSize.height >> 1); + int minc = peakLocation.x - (weightBoxSize.width >> 1); + int maxc = peakLocation.x + (weightBoxSize.width >> 1); + + Point2d centroid; + double sumIntensity = 0.0; + + // clamp the values to min and max if needed. + if(minr < 0) + { + minr = 0; + } + + if(minc < 0) + { + minc = 0; + } + + if(maxr > src.rows - 1) + { + maxr = src.rows - 1; + } + + if(maxc > src.cols - 1) + { + maxc = src.cols - 1; + } + + if(type == CV_32FC1) + { + const float* dataIn = (const float*)src.data; + dataIn += minr*src.cols; + for(int y = minr; y <= maxr; y++) + { + for(int x = minc; x <= maxc; x++) + { + centroid.x += (double)x*dataIn[x]; + centroid.y += (double)y*dataIn[x]; + sumIntensity += (double)dataIn[x]; + } + + dataIn += src.cols; + } + } + else + { + const double* dataIn = (const double*)src.data; + dataIn += minr*src.cols; + for(int y = minr; y <= maxr; y++) + { + for(int x = minc; x <= maxc; x++) + { + centroid.x += (double)x*dataIn[x]; + centroid.y += (double)y*dataIn[x]; + sumIntensity += dataIn[x]; + } + + dataIn += src.cols; + } + } + + if(response) + *response = sumIntensity; + + sumIntensity += DBL_EPSILON; // prevent div0 problems... + + centroid.x /= sumIntensity; + centroid.y /= sumIntensity; + + return centroid; +} + +} + +cv::Point2d cv::phaseCorrelate(InputArray _src1, InputArray _src2, InputArray _window, double* response) +{ + Mat src1 = _src1.getMat(); + Mat src2 = _src2.getMat(); + Mat window = _window.getMat(); + + CV_Assert( src1.type() == src2.type()); + CV_Assert( src1.type() == CV_32FC1 || src1.type() == CV_64FC1 ); + CV_Assert( src1.size == src2.size); + + if(!window.empty()) + { + CV_Assert( src1.type() == window.type()); + CV_Assert( src1.size == window.size); + } + + int M = getOptimalDFTSize(src1.rows); + int N = getOptimalDFTSize(src1.cols); + + Mat padded1, padded2, paddedWin; + + if(M != src1.rows || N != src1.cols) + { + copyMakeBorder(src1, padded1, 0, M - src1.rows, 0, N - src1.cols, BORDER_CONSTANT, Scalar::all(0)); + copyMakeBorder(src2, padded2, 0, M - src2.rows, 0, N - src2.cols, BORDER_CONSTANT, Scalar::all(0)); + + if(!window.empty()) + { + copyMakeBorder(window, paddedWin, 0, M - window.rows, 0, N - window.cols, BORDER_CONSTANT, Scalar::all(0)); + } + } + else + { + padded1 = src1; + padded2 = src2; + paddedWin = window; + } + + Mat FFT1, FFT2, P, Pm, C; + + // perform window multiplication if available + if(!paddedWin.empty()) + { + // apply window to both images before proceeding... + multiply(paddedWin, padded1, padded1); + multiply(paddedWin, padded2, padded2); + } + + // execute phase correlation equation + // Reference: http://en.wikipedia.org/wiki/Phase_correlation + dft(padded1, FFT1, DFT_REAL_OUTPUT); + dft(padded2, FFT2, DFT_REAL_OUTPUT); + + mulSpectrums(FFT1, FFT2, P, 0, true); + + magSpectrums(P, Pm); + divSpectrums(P, Pm, C, 0, false); // FF* / |FF*| (phase correlation equation completed here...) + + idft(C, C); // gives us the nice peak shift location... + + fftShift(C); // shift the energy to the center of the frame. + + // locate the highest peak + Point peakLoc; + minMaxLoc(C, NULL, NULL, NULL, &peakLoc); + + // get the phase shift with sub-pixel accuracy, 5x5 window seems about right here... + Point2d t; + t = weightedCentroid(C, peakLoc, Size(5, 5), response); + + // max response is M*N (not exactly, might be slightly larger due to rounding errors) + if(response) + *response /= M*N; + + // adjust shift relative to image center... + Point2d center((double)padded1.cols / 2.0, (double)padded1.rows / 2.0); + + return (center - t); +} + + +void cv::createHanningWindow(OutputArray _dst, cv::Size winSize, int type) +{ + CV_Assert( type == CV_32FC1 || type == CV_64FC1 ); + + _dst.create(winSize, type); + Mat dst = _dst.getMat(); + + int rows = dst.rows; + int cols = dst.cols; + + if(dst.depth() == CV_32F) + { + for(int i = 0; i < rows; i++) + { + float* dstData = dst.ptr(i); + double wr = 0.5 * (1.0f - cos(2.0f * CV_PI * (double)i / (double)(rows - 1))); + for(int j = 0; j < cols; j++) + { + double wc = 0.5 * (1.0f - cos(2.0f * CV_PI * (double)j / (double)(cols - 1))); + dstData[j] = (float)(wr * wc); + } + } + } + else + { + for(int i = 0; i < rows; i++) + { + double* dstData = dst.ptr(i); + double wr = 0.5 * (1.0 - cos(2.0 * CV_PI * (double)i / (double)(rows - 1))); + for(int j = 0; j < cols; j++) + { + double wc = 0.5 * (1.0 - cos(2.0 * CV_PI * (double)j / (double)(cols - 1))); + dstData[j] = wr * wc; + } + } + } + + // perform batch sqrt for SSE performance gains + cv::sqrt(dst, dst); +} diff --git a/imgproc/src/precomp.cpp b/imgproc/src/precomp.cpp new file mode 100644 index 0000000..3e0ec42 --- /dev/null +++ b/imgproc/src/precomp.cpp @@ -0,0 +1,44 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +/* End of file. */ diff --git a/imgproc/src/precomp.hpp b/imgproc/src/precomp.hpp new file mode 100644 index 0000000..fef5f75 --- /dev/null +++ b/imgproc/src/precomp.hpp @@ -0,0 +1,156 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#ifndef __OPENCV_PRECOMP_H__ +#define __OPENCV_PRECOMP_H__ + +#ifdef HAVE_CVCONFIG_H +#include "cvconfig.h" +#endif + +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/imgproc/imgproc_c.h" +#include "opencv2/core/internal.hpp" +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_TEGRA_OPTIMIZATION +#include "opencv2/imgproc/imgproc_tegra.hpp" +#else +#define GET_OPTIMIZED(func) (func) +#endif + +/* helper tables */ +extern const uchar icvSaturate8u_cv[]; +#define CV_FAST_CAST_8U(t) (assert(-256 <= (t) || (t) <= 512), icvSaturate8u_cv[(t)+256]) +#define CV_CALC_MIN_8U(a,b) (a) -= CV_FAST_CAST_8U((a) - (b)) +#define CV_CALC_MAX_8U(a,b) (a) += CV_FAST_CAST_8U((b) - (a)) + +// -256.f ... 511.f +extern const float icv8x32fTab_cv[]; +#define CV_8TO32F(x) icv8x32fTab_cv[(x)+256] + +// (-128.f)^2 ... (255.f)^2 +extern const float icv8x32fSqrTab[]; +#define CV_8TO32F_SQR(x) icv8x32fSqrTab[(x)+128] + +namespace cv +{ + +static inline Point normalizeAnchor( Point anchor, Size ksize ) +{ + if( anchor.x == -1 ) + anchor.x = ksize.width/2; + if( anchor.y == -1 ) + anchor.y = ksize.height/2; + CV_Assert( anchor.inside(Rect(0, 0, ksize.width, ksize.height)) ); + return anchor; +} + +void preprocess2DKernel( const Mat& kernel, vector& coords, vector& coeffs ); +void crossCorr( const Mat& src, const Mat& templ, Mat& dst, + Size corrsize, int ctype, + Point anchor=Point(0,0), double delta=0, + int borderType=BORDER_REFLECT_101 ); + +} + +typedef struct CvPyramid +{ + uchar **ptr; + CvSize *sz; + double *rate; + int *step; + uchar *state; + int level; +} +CvPyramid; + +#define CV_COPY( dst, src, len, idx ) \ + for( (idx) = 0; (idx) < (len); (idx)++) (dst)[idx] = (src)[idx] + +#define CV_SET( dst, val, len, idx ) \ + for( (idx) = 0; (idx) < (len); (idx)++) (dst)[idx] = (val) + +/* performs convolution of 2d floating-point array with 3x1, 1x3 or separable 3x3 mask */ +void icvSepConvSmall3_32f( float* src, int src_step, float* dst, int dst_step, + CvSize src_size, const float* kx, const float* ky, float* buffer ); + +#undef CV_CALC_MIN +#define CV_CALC_MIN(a, b) if((a) > (b)) (a) = (b) + +#undef CV_CALC_MAX +#define CV_CALC_MAX(a, b) if((a) < (b)) (a) = (b) + +CvStatus CV_STDCALL +icvCopyReplicateBorder_8u( const uchar* src, int srcstep, CvSize srcroi, + uchar* dst, int dststep, CvSize dstroi, + int left, int right, int cn, const uchar* value = 0 ); + +CvStatus CV_STDCALL icvGetRectSubPix_8u_C1R +( const uchar* src, int src_step, CvSize src_size, + uchar* dst, int dst_step, CvSize win_size, CvPoint2D32f center ); +CvStatus CV_STDCALL icvGetRectSubPix_8u32f_C1R +( const uchar* src, int src_step, CvSize src_size, + float* dst, int dst_step, CvSize win_size, CvPoint2D32f center ); +CvStatus CV_STDCALL icvGetRectSubPix_32f_C1R +( const float* src, int src_step, CvSize src_size, + float* dst, int dst_step, CvSize win_size, CvPoint2D32f center ); + +CvStatus CV_STDCALL icvGetQuadrangleSubPix_8u_C1R +( const uchar* src, int src_step, CvSize src_size, + uchar* dst, int dst_step, CvSize win_size, const float *matrix ); +CvStatus CV_STDCALL icvGetQuadrangleSubPix_8u32f_C1R +( const uchar* src, int src_step, CvSize src_size, + float* dst, int dst_step, CvSize win_size, const float *matrix ); +CvStatus CV_STDCALL icvGetQuadrangleSubPix_32f_C1R +( const float* src, int src_step, CvSize src_size, + float* dst, int dst_step, CvSize win_size, const float *matrix ); + +#include "_geom.h" + +#endif /*__OPENCV_CV_INTERNAL_H_*/ diff --git a/imgproc/src/pyramids.cpp b/imgproc/src/pyramids.cpp new file mode 100644 index 0000000..81462a6 --- /dev/null +++ b/imgproc/src/pyramids.cpp @@ -0,0 +1,581 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +namespace cv +{ + +template struct FixPtCast +{ + typedef int type1; + typedef T rtype; + rtype operator ()(type1 arg) const { return (T)((arg + (1 << (shift-1))) >> shift); } +}; + +template struct FltCast +{ + typedef T type1; + typedef T rtype; + rtype operator ()(type1 arg) const { return arg*(T)(1./(1 << shift)); } +}; + +template struct NoVec +{ + int operator()(T1**, T2*, int, int) const { return 0; } +}; + +#if CV_SSE2 + +struct PyrDownVec_32s8u +{ + int operator()(int** src, uchar* dst, int, int width) const + { + if( !checkHardwareSupport(CV_CPU_SSE2) ) + return 0; + + int x = 0; + const int *row0 = src[0], *row1 = src[1], *row2 = src[2], *row3 = src[3], *row4 = src[4]; + __m128i delta = _mm_set1_epi16(128); + + for( ; x <= width - 16; x += 16 ) + { + __m128i r0, r1, r2, r3, r4, t0, t1; + r0 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row0 + x)), + _mm_load_si128((const __m128i*)(row0 + x + 4))); + r1 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row1 + x)), + _mm_load_si128((const __m128i*)(row1 + x + 4))); + r2 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row2 + x)), + _mm_load_si128((const __m128i*)(row2 + x + 4))); + r3 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row3 + x)), + _mm_load_si128((const __m128i*)(row3 + x + 4))); + r4 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row4 + x)), + _mm_load_si128((const __m128i*)(row4 + x + 4))); + r0 = _mm_add_epi16(r0, r4); + r1 = _mm_add_epi16(_mm_add_epi16(r1, r3), r2); + r0 = _mm_add_epi16(r0, _mm_add_epi16(r2, r2)); + t0 = _mm_add_epi16(r0, _mm_slli_epi16(r1, 2)); + r0 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row0 + x + 8)), + _mm_load_si128((const __m128i*)(row0 + x + 12))); + r1 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row1 + x + 8)), + _mm_load_si128((const __m128i*)(row1 + x + 12))); + r2 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row2 + x + 8)), + _mm_load_si128((const __m128i*)(row2 + x + 12))); + r3 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row3 + x + 8)), + _mm_load_si128((const __m128i*)(row3 + x + 12))); + r4 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row4 + x + 8)), + _mm_load_si128((const __m128i*)(row4 + x + 12))); + r0 = _mm_add_epi16(r0, r4); + r1 = _mm_add_epi16(_mm_add_epi16(r1, r3), r2); + r0 = _mm_add_epi16(r0, _mm_add_epi16(r2, r2)); + t1 = _mm_add_epi16(r0, _mm_slli_epi16(r1, 2)); + t0 = _mm_srli_epi16(_mm_add_epi16(t0, delta), 8); + t1 = _mm_srli_epi16(_mm_add_epi16(t1, delta), 8); + _mm_storeu_si128((__m128i*)(dst + x), _mm_packus_epi16(t0, t1)); + } + + for( ; x <= width - 4; x += 4 ) + { + __m128i r0, r1, r2, r3, r4, z = _mm_setzero_si128(); + r0 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row0 + x)), z); + r1 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row1 + x)), z); + r2 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row2 + x)), z); + r3 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row3 + x)), z); + r4 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row4 + x)), z); + r0 = _mm_add_epi16(r0, r4); + r1 = _mm_add_epi16(_mm_add_epi16(r1, r3), r2); + r0 = _mm_add_epi16(r0, _mm_add_epi16(r2, r2)); + r0 = _mm_add_epi16(r0, _mm_slli_epi16(r1, 2)); + r0 = _mm_srli_epi16(_mm_add_epi16(r0, delta), 8); + *(int*)(dst + x) = _mm_cvtsi128_si32(_mm_packus_epi16(r0, r0)); + } + + return x; + } +}; + +struct PyrDownVec_32f +{ + int operator()(float** src, float* dst, int, int width) const + { + if( !checkHardwareSupport(CV_CPU_SSE) ) + return 0; + + int x = 0; + const float *row0 = src[0], *row1 = src[1], *row2 = src[2], *row3 = src[3], *row4 = src[4]; + __m128 _4 = _mm_set1_ps(4.f), _scale = _mm_set1_ps(1.f/256); + for( ; x <= width - 8; x += 8 ) + { + __m128 r0, r1, r2, r3, r4, t0, t1; + r0 = _mm_load_ps(row0 + x); + r1 = _mm_load_ps(row1 + x); + r2 = _mm_load_ps(row2 + x); + r3 = _mm_load_ps(row3 + x); + r4 = _mm_load_ps(row4 + x); + r0 = _mm_add_ps(r0, r4); + r1 = _mm_add_ps(_mm_add_ps(r1, r3), r2); + r0 = _mm_add_ps(r0, _mm_add_ps(r2, r2)); + t0 = _mm_add_ps(r0, _mm_mul_ps(r1, _4)); + + r0 = _mm_load_ps(row0 + x + 4); + r1 = _mm_load_ps(row1 + x + 4); + r2 = _mm_load_ps(row2 + x + 4); + r3 = _mm_load_ps(row3 + x + 4); + r4 = _mm_load_ps(row4 + x + 4); + r0 = _mm_add_ps(r0, r4); + r1 = _mm_add_ps(_mm_add_ps(r1, r3), r2); + r0 = _mm_add_ps(r0, _mm_add_ps(r2, r2)); + t1 = _mm_add_ps(r0, _mm_mul_ps(r1, _4)); + + t0 = _mm_mul_ps(t0, _scale); + t1 = _mm_mul_ps(t1, _scale); + + _mm_storeu_ps(dst + x, t0); + _mm_storeu_ps(dst + x + 4, t1); + } + + return x; + } +}; + +#else + +typedef NoVec PyrDownVec_32s8u; +typedef NoVec PyrDownVec_32f; + +#endif + +template void +pyrDown_( const Mat& _src, Mat& _dst, int borderType ) +{ + const int PD_SZ = 5; + typedef typename CastOp::type1 WT; + typedef typename CastOp::rtype T; + + Size ssize = _src.size(), dsize = _dst.size(); + int cn = _src.channels(); + int bufstep = (int)alignSize(dsize.width*cn, 16); + AutoBuffer _buf(bufstep*PD_SZ + 16); + WT* buf = alignPtr((WT*)_buf, 16); + int tabL[CV_CN_MAX*(PD_SZ+2)], tabR[CV_CN_MAX*(PD_SZ+2)]; + AutoBuffer _tabM(dsize.width*cn); + int* tabM = _tabM; + WT* rows[PD_SZ]; + CastOp castOp; + VecOp vecOp; + + CV_Assert( std::abs(dsize.width*2 - ssize.width) <= 2 && + std::abs(dsize.height*2 - ssize.height) <= 2 ); + int k, x, sy0 = -PD_SZ/2, sy = sy0, width0 = std::min((ssize.width-PD_SZ/2-1)/2 + 1, dsize.width); + + for( x = 0; x <= PD_SZ+1; x++ ) + { + int sx0 = borderInterpolate(x - PD_SZ/2, ssize.width, borderType)*cn; + int sx1 = borderInterpolate(x + width0*2 - PD_SZ/2, ssize.width, borderType)*cn; + for( k = 0; k < cn; k++ ) + { + tabL[x*cn + k] = sx0 + k; + tabR[x*cn + k] = sx1 + k; + } + } + + ssize.width *= cn; + dsize.width *= cn; + width0 *= cn; + + for( x = 0; x < dsize.width; x++ ) + tabM[x] = (x/cn)*2*cn + x % cn; + + for( int y = 0; y < dsize.height; y++ ) + { + T* dst = (T*)(_dst.data + _dst.step*y); + WT *row0, *row1, *row2, *row3, *row4; + + // fill the ring buffer (horizontal convolution and decimation) + for( ; sy <= y*2 + 2; sy++ ) + { + WT* row = buf + ((sy - sy0) % PD_SZ)*bufstep; + int _sy = borderInterpolate(sy, ssize.height, borderType); + const T* src = (const T*)(_src.data + _src.step*_sy); + int limit = cn; + const int* tab = tabL; + + for( x = 0;;) + { + for( ; x < limit; x++ ) + { + row[x] = src[tab[x+cn*2]]*6 + (src[tab[x+cn]] + src[tab[x+cn*3]])*4 + + src[tab[x]] + src[tab[x+cn*4]]; + } + + if( x == dsize.width ) + break; + + if( cn == 1 ) + { + for( ; x < width0; x++ ) + row[x] = src[x*2]*6 + (src[x*2 - 1] + src[x*2 + 1])*4 + + src[x*2 - 2] + src[x*2 + 2]; + } + else if( cn == 3 ) + { + for( ; x < width0; x += 3 ) + { + const T* s = src + x*2; + WT t0 = s[0]*6 + (s[-3] + s[3])*4 + s[-6] + s[6]; + WT t1 = s[1]*6 + (s[-2] + s[4])*4 + s[-5] + s[7]; + WT t2 = s[2]*6 + (s[-1] + s[5])*4 + s[-4] + s[8]; + row[x] = t0; row[x+1] = t1; row[x+2] = t2; + } + } + else if( cn == 4 ) + { + for( ; x < width0; x += 4 ) + { + const T* s = src + x*2; + WT t0 = s[0]*6 + (s[-4] + s[4])*4 + s[-8] + s[8]; + WT t1 = s[1]*6 + (s[-3] + s[5])*4 + s[-7] + s[9]; + row[x] = t0; row[x+1] = t1; + t0 = s[2]*6 + (s[-2] + s[6])*4 + s[-6] + s[10]; + t1 = s[3]*6 + (s[-1] + s[7])*4 + s[-5] + s[11]; + row[x+2] = t0; row[x+3] = t1; + } + } + else + { + for( ; x < width0; x++ ) + { + int sx = tabM[x]; + row[x] = src[sx]*6 + (src[sx - cn] + src[sx + cn])*4 + + src[sx - cn*2] + src[sx + cn*2]; + } + } + + limit = dsize.width; + tab = tabR - x; + } + } + + // do vertical convolution and decimation and write the result to the destination image + for( k = 0; k < PD_SZ; k++ ) + rows[k] = buf + ((y*2 - PD_SZ/2 + k - sy0) % PD_SZ)*bufstep; + row0 = rows[0]; row1 = rows[1]; row2 = rows[2]; row3 = rows[3]; row4 = rows[4]; + + x = vecOp(rows, dst, (int)_dst.step, dsize.width); + for( ; x < dsize.width; x++ ) + dst[x] = castOp(row2[x]*6 + (row1[x] + row3[x])*4 + row0[x] + row4[x]); + } +} + + +template void +pyrUp_( const Mat& _src, Mat& _dst, int) +{ + const int PU_SZ = 3; + typedef typename CastOp::type1 WT; + typedef typename CastOp::rtype T; + + Size ssize = _src.size(), dsize = _dst.size(); + int cn = _src.channels(); + int bufstep = (int)alignSize((dsize.width+1)*cn, 16); + AutoBuffer _buf(bufstep*PU_SZ + 16); + WT* buf = alignPtr((WT*)_buf, 16); + AutoBuffer _dtab(ssize.width*cn); + int* dtab = _dtab; + WT* rows[PU_SZ]; + CastOp castOp; + VecOp vecOp; + + CV_Assert( std::abs(dsize.width - ssize.width*2) == dsize.width % 2 && + std::abs(dsize.height - ssize.height*2) == dsize.height % 2); + int k, x, sy0 = -PU_SZ/2, sy = sy0, width0 = ssize.width - 1; + + ssize.width *= cn; + dsize.width *= cn; + width0 *= cn; + + for( x = 0; x < ssize.width; x++ ) + dtab[x] = (x/cn)*2*cn + x % cn; + + for( int y = 0; y < ssize.height; y++ ) + { + T* dst0 = (T*)(_dst.data + _dst.step*y*2); + T* dst1 = (T*)(_dst.data + _dst.step*(y*2+1)); + WT *row0, *row1, *row2; + + if( y*2+1 >= dsize.height ) + dst1 = dst0; + + // fill the ring buffer (horizontal convolution and decimation) + for( ; sy <= y + 1; sy++ ) + { + WT* row = buf + ((sy - sy0) % PU_SZ)*bufstep; + int _sy = borderInterpolate(sy*2, dsize.height, BORDER_REFLECT_101)/2; + const T* src = (const T*)(_src.data + _src.step*_sy); + + if( ssize.width == cn ) + { + for( x = 0; x < cn; x++ ) + row[x] = row[x + cn] = src[x]*8; + continue; + } + + for( x = 0; x < cn; x++ ) + { + int dx = dtab[x]; + WT t0 = src[x]*6 + src[x + cn]*2; + WT t1 = (src[x] + src[x + cn])*4; + row[dx] = t0; row[dx + cn] = t1; + dx = dtab[ssize.width - cn + x]; + int sx = ssize.width - cn + x; + t0 = src[sx - cn] + src[sx]*7; + t1 = src[sx]*8; + row[dx] = t0; row[dx + cn] = t1; + } + + for( x = cn; x < ssize.width - cn; x++ ) + { + int dx = dtab[x]; + WT t0 = src[x-cn] + src[x]*6 + src[x+cn]; + WT t1 = (src[x] + src[x+cn])*4; + row[dx] = t0; + row[dx+cn] = t1; + } + } + + // do vertical convolution and decimation and write the result to the destination image + for( k = 0; k < PU_SZ; k++ ) + rows[k] = buf + ((y - PU_SZ/2 + k - sy0) % PU_SZ)*bufstep; + row0 = rows[0]; row1 = rows[1]; row2 = rows[2]; + + x = vecOp(rows, dst0, (int)_dst.step, dsize.width); + for( ; x < dsize.width; x++ ) + { + T t1 = castOp((row1[x] + row2[x])*4); + T t0 = castOp(row0[x] + row1[x]*6 + row2[x]); + dst1[x] = t1; dst0[x] = t0; + } + } +} + +typedef void (*PyrFunc)(const Mat&, Mat&, int); + +} + +void cv::pyrDown( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType ) +{ + Mat src = _src.getMat(); + Size dsz = _dsz == Size() ? Size((src.cols + 1)/2, (src.rows + 1)/2) : _dsz; + _dst.create( dsz, src.type() ); + Mat dst = _dst.getMat(); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if(borderType == BORDER_DEFAULT && tegra::pyrDown(src, dst)) + return; +#endif + + int depth = src.depth(); + PyrFunc func = 0; + if( depth == CV_8U ) + func = pyrDown_, PyrDownVec_32s8u>; + else if( depth == CV_16S ) + func = pyrDown_, NoVec >; + else if( depth == CV_16U ) + func = pyrDown_, NoVec >; + else if( depth == CV_32F ) + func = pyrDown_, PyrDownVec_32f>; + else if( depth == CV_64F ) + func = pyrDown_, NoVec >; + else + CV_Error( CV_StsUnsupportedFormat, "" ); + + func( src, dst, borderType ); +} + +void cv::pyrUp( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType ) +{ + Mat src = _src.getMat(); + Size dsz = _dsz == Size() ? Size(src.cols*2, src.rows*2) : _dsz; + _dst.create( dsz, src.type() ); + Mat dst = _dst.getMat(); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if(borderType == BORDER_DEFAULT && tegra::pyrUp(src, dst)) + return; +#endif + + int depth = src.depth(); + PyrFunc func = 0; + if( depth == CV_8U ) + func = pyrUp_, NoVec >; + else if( depth == CV_16S ) + func = pyrUp_, NoVec >; + else if( depth == CV_16U ) + func = pyrUp_, NoVec >; + else if( depth == CV_32F ) + func = pyrUp_, NoVec >; + else if( depth == CV_64F ) + func = pyrUp_, NoVec >; + else + CV_Error( CV_StsUnsupportedFormat, "" ); + + func( src, dst, borderType ); +} + +void cv::buildPyramid( InputArray _src, OutputArrayOfArrays _dst, int maxlevel, int borderType ) +{ + Mat src = _src.getMat(); + _dst.create( maxlevel + 1, 1, 0 ); + _dst.getMatRef(0) = src; + for( int i = 1; i <= maxlevel; i++ ) + pyrDown( _dst.getMatRef(i-1), _dst.getMatRef(i), Size(), borderType ); +} + +CV_IMPL void cvPyrDown( const void* srcarr, void* dstarr, int _filter ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + CV_Assert( _filter == CV_GAUSSIAN_5x5 && src.type() == dst.type()); + cv::pyrDown( src, dst, dst.size() ); +} + +CV_IMPL void cvPyrUp( const void* srcarr, void* dstarr, int _filter ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + + CV_Assert( _filter == CV_GAUSSIAN_5x5 && src.type() == dst.type()); + cv::pyrUp( src, dst, dst.size() ); +} + + +CV_IMPL void +cvReleasePyramid( CvMat*** _pyramid, int extra_layers ) +{ + if( !_pyramid ) + CV_Error( CV_StsNullPtr, "" ); + + if( *_pyramid ) + for( int i = 0; i <= extra_layers; i++ ) + cvReleaseMat( &(*_pyramid)[i] ); + + cvFree( _pyramid ); +} + + +CV_IMPL CvMat** +cvCreatePyramid( const CvArr* srcarr, int extra_layers, double rate, + const CvSize* layer_sizes, CvArr* bufarr, + int calc, int filter ) +{ + const float eps = 0.1f; + uchar* ptr = 0; + + CvMat stub, *src = cvGetMat( srcarr, &stub ); + + if( extra_layers < 0 ) + CV_Error( CV_StsOutOfRange, "The number of extra layers must be non negative" ); + + int i, layer_step, elem_size = CV_ELEM_SIZE(src->type); + CvSize layer_size, size = cvGetMatSize(src); + + if( bufarr ) + { + CvMat bstub, *buf; + int bufsize = 0; + + buf = cvGetMat( bufarr, &bstub ); + bufsize = buf->rows*buf->cols*CV_ELEM_SIZE(buf->type); + layer_size = size; + for( i = 1; i <= extra_layers; i++ ) + { + if( !layer_sizes ) + { + layer_size.width = cvRound(layer_size.width*rate+eps); + layer_size.height = cvRound(layer_size.height*rate+eps); + } + else + layer_size = layer_sizes[i-1]; + layer_step = layer_size.width*elem_size; + bufsize -= layer_step*layer_size.height; + } + + if( bufsize < 0 ) + CV_Error( CV_StsOutOfRange, "The buffer is too small to fit the pyramid" ); + ptr = buf->data.ptr; + } + + CvMat** pyramid = (CvMat**)cvAlloc( (extra_layers+1)*sizeof(pyramid[0]) ); + memset( pyramid, 0, (extra_layers+1)*sizeof(pyramid[0]) ); + + pyramid[0] = cvCreateMatHeader( size.height, size.width, src->type ); + cvSetData( pyramid[0], src->data.ptr, src->step ); + layer_size = size; + + for( i = 1; i <= extra_layers; i++ ) + { + if( !layer_sizes ) + { + layer_size.width = cvRound(layer_size.width*rate + eps); + layer_size.height = cvRound(layer_size.height*rate + eps); + } + else + layer_size = layer_sizes[i]; + + if( bufarr ) + { + pyramid[i] = cvCreateMatHeader( layer_size.height, layer_size.width, src->type ); + layer_step = layer_size.width*elem_size; + cvSetData( pyramid[i], ptr, layer_step ); + ptr += layer_step*layer_size.height; + } + else + pyramid[i] = cvCreateMat( layer_size.height, layer_size.width, src->type ); + + if( calc ) + cvPyrDown( pyramid[i-1], pyramid[i], filter ); + //cvResize( pyramid[i-1], pyramid[i], CV_INTER_LINEAR ); + } + + return pyramid; +} + +/* End of file. */ diff --git a/imgproc/src/rotcalipers.cpp b/imgproc/src/rotcalipers.cpp new file mode 100644 index 0000000..2171ec1 --- /dev/null +++ b/imgproc/src/rotcalipers.cpp @@ -0,0 +1,441 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +typedef struct +{ + int bottom; + int left; + float height; + float width; + float base_a; + float base_b; +} +icvMinAreaState; + +#define CV_CALIPERS_MAXHEIGHT 0 +#define CV_CALIPERS_MINAREARECT 1 +#define CV_CALIPERS_MAXDIST 2 + +/*F/////////////////////////////////////////////////////////////////////////////////////// +// Name: icvRotatingCalipers +// Purpose: +// Rotating calipers algorithm with some applications +// +// Context: +// Parameters: +// points - convex hull vertices ( any orientation ) +// n - number of vertices +// mode - concrete application of algorithm +// can be CV_CALIPERS_MAXDIST or +// CV_CALIPERS_MINAREARECT +// left, bottom, right, top - indexes of extremal points +// out - output info. +// In case CV_CALIPERS_MAXDIST it points to float value - +// maximal height of polygon. +// In case CV_CALIPERS_MINAREARECT +// ((CvPoint2D32f*)out)[0] - corner +// ((CvPoint2D32f*)out)[1] - vector1 +// ((CvPoint2D32f*)out)[0] - corner2 +// +// ^ +// | +// vector2 | +// | +// |____________\ +// corner / +// vector1 +// +// Returns: +// Notes: +//F*/ + +/* we will use usual cartesian coordinates */ +static void +icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out ) +{ + float minarea = FLT_MAX; + float max_dist = 0; + char buffer[32] = {}; + int i, k; + CvPoint2D32f* vect = (CvPoint2D32f*)cvAlloc( n * sizeof(vect[0]) ); + float* inv_vect_length = (float*)cvAlloc( n * sizeof(inv_vect_length[0]) ); + int left = 0, bottom = 0, right = 0, top = 0; + int seq[4] = { -1, -1, -1, -1 }; + + /* rotating calipers sides will always have coordinates + (a,b) (-b,a) (-a,-b) (b, -a) + */ + /* this is a first base bector (a,b) initialized by (1,0) */ + float orientation = 0; + float base_a; + float base_b = 0; + + float left_x, right_x, top_y, bottom_y; + CvPoint2D32f pt0 = points[0]; + + left_x = right_x = pt0.x; + top_y = bottom_y = pt0.y; + + for( i = 0; i < n; i++ ) + { + double dx, dy; + + if( pt0.x < left_x ) + left_x = pt0.x, left = i; + + if( pt0.x > right_x ) + right_x = pt0.x, right = i; + + if( pt0.y > top_y ) + top_y = pt0.y, top = i; + + if( pt0.y < bottom_y ) + bottom_y = pt0.y, bottom = i; + + CvPoint2D32f pt = points[(i+1) & (i+1 < n ? -1 : 0)]; + + dx = pt.x - pt0.x; + dy = pt.y - pt0.y; + + vect[i].x = (float)dx; + vect[i].y = (float)dy; + inv_vect_length[i] = (float)(1./sqrt(dx*dx + dy*dy)); + + pt0 = pt; + } + + //cvbInvSqrt( inv_vect_length, inv_vect_length, n ); + + /* find convex hull orientation */ + { + double ax = vect[n-1].x; + double ay = vect[n-1].y; + + for( i = 0; i < n; i++ ) + { + double bx = vect[i].x; + double by = vect[i].y; + + double convexity = ax * by - ay * bx; + + if( convexity != 0 ) + { + orientation = (convexity > 0) ? 1.f : (-1.f); + break; + } + ax = bx; + ay = by; + } + assert( orientation != 0 ); + } + base_a = orientation; + +/*****************************************************************************************/ +/* init calipers position */ + seq[0] = bottom; + seq[1] = right; + seq[2] = top; + seq[3] = left; +/*****************************************************************************************/ +/* Main loop - evaluate angles and rotate calipers */ + + /* all of edges will be checked while rotating calipers by 90 degrees */ + for( k = 0; k < n; k++ ) + { + /* sinus of minimal angle */ + /*float sinus;*/ + + /* compute cosine of angle between calipers side and polygon edge */ + /* dp - dot product */ + float dp0 = base_a * vect[seq[0]].x + base_b * vect[seq[0]].y; + float dp1 = -base_b * vect[seq[1]].x + base_a * vect[seq[1]].y; + float dp2 = -base_a * vect[seq[2]].x - base_b * vect[seq[2]].y; + float dp3 = base_b * vect[seq[3]].x - base_a * vect[seq[3]].y; + + float cosalpha = dp0 * inv_vect_length[seq[0]]; + float maxcos = cosalpha; + + /* number of calipers edges, that has minimal angle with edge */ + int main_element = 0; + + /* choose minimal angle */ + cosalpha = dp1 * inv_vect_length[seq[1]]; + maxcos = (cosalpha > maxcos) ? (main_element = 1, cosalpha) : maxcos; + cosalpha = dp2 * inv_vect_length[seq[2]]; + maxcos = (cosalpha > maxcos) ? (main_element = 2, cosalpha) : maxcos; + cosalpha = dp3 * inv_vect_length[seq[3]]; + maxcos = (cosalpha > maxcos) ? (main_element = 3, cosalpha) : maxcos; + + /*rotate calipers*/ + { + //get next base + int pindex = seq[main_element]; + float lead_x = vect[pindex].x*inv_vect_length[pindex]; + float lead_y = vect[pindex].y*inv_vect_length[pindex]; + switch( main_element ) + { + case 0: + base_a = lead_x; + base_b = lead_y; + break; + case 1: + base_a = lead_y; + base_b = -lead_x; + break; + case 2: + base_a = -lead_x; + base_b = -lead_y; + break; + case 3: + base_a = -lead_y; + base_b = lead_x; + break; + default: assert(0); + } + } + /* change base point of main edge */ + seq[main_element] += 1; + seq[main_element] = (seq[main_element] == n) ? 0 : seq[main_element]; + + + switch (mode) + { + case CV_CALIPERS_MAXHEIGHT: + { + /* now main element lies on edge alligned to calipers side */ + + /* find opposite element i.e. transform */ + /* 0->2, 1->3, 2->0, 3->1 */ + int opposite_el = main_element ^ 2; + + float dx = points[seq[opposite_el]].x - points[seq[main_element]].x; + float dy = points[seq[opposite_el]].y - points[seq[main_element]].y; + float dist; + + if( main_element & 1 ) + dist = (float)fabs(dx * base_a + dy * base_b); + else + dist = (float)fabs(dx * (-base_b) + dy * base_a); + + if( dist > max_dist ) + max_dist = dist; + + break; + } + case CV_CALIPERS_MINAREARECT: + /* find area of rectangle */ + { + float height; + float area; + + /* find vector left-right */ + float dx = points[seq[1]].x - points[seq[3]].x; + float dy = points[seq[1]].y - points[seq[3]].y; + + /* dotproduct */ + float width = dx * base_a + dy * base_b; + + /* find vector left-right */ + dx = points[seq[2]].x - points[seq[0]].x; + dy = points[seq[2]].y - points[seq[0]].y; + + /* dotproduct */ + height = -dx * base_b + dy * base_a; + + area = width * height; + if( area <= minarea ) + { + float *buf = (float *) buffer; + + minarea = area; + /* leftist point */ + ((int *) buf)[0] = seq[3]; + buf[1] = base_a; + buf[2] = width; + buf[3] = base_b; + buf[4] = height; + /* bottom point */ + ((int *) buf)[5] = seq[0]; + buf[6] = area; + } + break; + } + } /*switch */ + } /* for */ + + switch (mode) + { + case CV_CALIPERS_MINAREARECT: + { + float *buf = (float *) buffer; + + float A1 = buf[1]; + float B1 = buf[3]; + + float A2 = -buf[3]; + float B2 = buf[1]; + + float C1 = A1 * points[((int *) buf)[0]].x + points[((int *) buf)[0]].y * B1; + float C2 = A2 * points[((int *) buf)[5]].x + points[((int *) buf)[5]].y * B2; + + float idet = 1.f / (A1 * B2 - A2 * B1); + + float px = (C1 * B2 - C2 * B1) * idet; + float py = (A1 * C2 - A2 * C1) * idet; + + out[0] = px; + out[1] = py; + + out[2] = A1 * buf[2]; + out[3] = B1 * buf[2]; + + out[4] = A2 * buf[4]; + out[5] = B2 * buf[4]; + } + break; + case CV_CALIPERS_MAXHEIGHT: + { + out[0] = max_dist; + } + break; + } + + cvFree( &vect ); + cvFree( &inv_vect_length ); +} + + +CV_IMPL CvBox2D +cvMinAreaRect2( const CvArr* array, CvMemStorage* storage ) +{ + cv::Ptr temp_storage; + CvBox2D box; + cv::AutoBuffer _points; + CvPoint2D32f* points; + + memset(&box, 0, sizeof(box)); + + int i, n; + CvSeqReader reader; + CvContour contour_header; + CvSeqBlock block; + CvSeq* ptseq = (CvSeq*)array; + CvPoint2D32f out[3]; + + if( CV_IS_SEQ(ptseq) ) + { + if( !CV_IS_SEQ_POINT_SET(ptseq) && + (CV_SEQ_KIND(ptseq) != CV_SEQ_KIND_CURVE || + CV_SEQ_ELTYPE(ptseq) != CV_SEQ_ELTYPE_PPOINT )) + CV_Error( CV_StsUnsupportedFormat, + "Input sequence must consist of 2d points or pointers to 2d points" ); + if( !storage ) + storage = ptseq->storage; + } + else + { + ptseq = cvPointSeqFromMat( CV_SEQ_KIND_GENERIC, array, &contour_header, &block ); + } + + if( storage ) + { + temp_storage = cvCreateChildMemStorage( storage ); + } + else + { + temp_storage = cvCreateMemStorage(1 << 10); + } + + ptseq = cvConvexHull2( ptseq, temp_storage, CV_CLOCKWISE, 1 ); + n = ptseq->total; + + _points.allocate(n); + points = _points; + cvStartReadSeq( ptseq, &reader ); + + if( CV_SEQ_ELTYPE( ptseq ) == CV_32SC2 ) + { + for( i = 0; i < n; i++ ) + { + CvPoint pt; + CV_READ_SEQ_ELEM( pt, reader ); + points[i].x = (float)pt.x; + points[i].y = (float)pt.y; + } + } + else + { + for( i = 0; i < n; i++ ) + { + CV_READ_SEQ_ELEM( points[i], reader ); + } + } + + if( n > 2 ) + { + icvRotatingCalipers( points, n, CV_CALIPERS_MINAREARECT, (float*)out ); + box.center.x = out[0].x + (out[1].x + out[2].x)*0.5f; + box.center.y = out[0].y + (out[1].y + out[2].y)*0.5f; + box.size.width = (float)sqrt((double)out[1].x*out[1].x + (double)out[1].y*out[1].y); + box.size.height = (float)sqrt((double)out[2].x*out[2].x + (double)out[2].y*out[2].y); + box.angle = (float)atan2( (double)out[1].y, (double)out[1].x ); + } + else if( n == 2 ) + { + box.center.x = (points[0].x + points[1].x)*0.5f; + box.center.y = (points[0].y + points[1].y)*0.5f; + double dx = points[1].x - points[0].x; + double dy = points[1].y - points[0].y; + box.size.width = (float)sqrt(dx*dx + dy*dy); + box.size.height = 0; + box.angle = (float)atan2( dy, dx ); + } + else + { + if( n == 1 ) + box.center = points[0]; + } + + box.angle = (float)(box.angle*180/CV_PI); + return box; +} + diff --git a/imgproc/src/samplers.cpp b/imgproc/src/samplers.cpp new file mode 100644 index 0000000..636c9a9 --- /dev/null +++ b/imgproc/src/samplers.cpp @@ -0,0 +1,882 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +/**************************************************************************************\ +* line samplers * +\**************************************************************************************/ + +CV_IMPL int +cvSampleLine( const void* img, CvPoint pt1, CvPoint pt2, + void* _buffer, int connectivity ) +{ + int count = -1; + + int i, coi = 0, pix_size; + CvMat stub, *mat = cvGetMat( img, &stub, &coi ); + CvLineIterator iterator; + uchar* buffer = (uchar*)_buffer; + + if( coi != 0 ) + CV_Error( CV_BadCOI, "" ); + + if( !buffer ) + CV_Error( CV_StsNullPtr, "" ); + + count = cvInitLineIterator( mat, pt1, pt2, &iterator, connectivity ); + + pix_size = CV_ELEM_SIZE(mat->type); + for( i = 0; i < count; i++ ) + { + for( int j = 0; j < pix_size; j++ ) + buffer[j] = iterator.ptr[j]; + buffer += pix_size; + CV_NEXT_LINE_POINT( iterator ); + } + + return count; +} + + +static const void* +icvAdjustRect( const void* srcptr, int src_step, int pix_size, + CvSize src_size, CvSize win_size, + CvPoint ip, CvRect* pRect ) +{ + CvRect rect; + const char* src = (const char*)srcptr; + + if( ip.x >= 0 ) + { + src += ip.x*pix_size; + rect.x = 0; + } + else + { + rect.x = -ip.x; + if( rect.x > win_size.width ) + rect.x = win_size.width; + } + + if( ip.x + win_size.width < src_size.width ) + rect.width = win_size.width; + else + { + rect.width = src_size.width - ip.x - 1; + if( rect.width < 0 ) + { + src += rect.width*pix_size; + rect.width = 0; + } + assert( rect.width <= win_size.width ); + } + + if( ip.y >= 0 ) + { + src += ip.y * src_step; + rect.y = 0; + } + else + rect.y = -ip.y; + + if( ip.y + win_size.height < src_size.height ) + rect.height = win_size.height; + else + { + rect.height = src_size.height - ip.y - 1; + if( rect.height < 0 ) + { + src += rect.height*src_step; + rect.height = 0; + } + } + + *pRect = rect; + return src - rect.x*pix_size; +} + + +#define ICV_DEF_GET_RECT_SUB_PIX_FUNC( flavor, srctype, dsttype, worktype, \ + cast_macro, scale_macro, cast_macro2 )\ +CvStatus CV_STDCALL icvGetRectSubPix_##flavor##_C1R \ +( const srctype* src, int src_step, CvSize src_size, \ + dsttype* dst, int dst_step, CvSize win_size, CvPoint2D32f center ) \ +{ \ + CvPoint ip; \ + worktype a11, a12, a21, a22, b1, b2; \ + float a, b; \ + int i, j; \ + \ + center.x -= (win_size.width-1)*0.5f; \ + center.y -= (win_size.height-1)*0.5f; \ + \ + ip.x = cvFloor( center.x ); \ + ip.y = cvFloor( center.y ); \ + \ + a = center.x - ip.x; \ + b = center.y - ip.y; \ + a11 = scale_macro((1.f-a)*(1.f-b)); \ + a12 = scale_macro(a*(1.f-b)); \ + a21 = scale_macro((1.f-a)*b); \ + a22 = scale_macro(a*b); \ + b1 = scale_macro(1.f - b); \ + b2 = scale_macro(b); \ + \ + src_step /= sizeof(src[0]); \ + dst_step /= sizeof(dst[0]); \ + \ + if( 0 <= ip.x && ip.x + win_size.width < src_size.width && \ + 0 <= ip.y && ip.y + win_size.height < src_size.height ) \ + { \ + /* extracted rectangle is totally inside the image */ \ + src += ip.y * src_step + ip.x; \ + \ + for( i = 0; i < win_size.height; i++, src += src_step, \ + dst += dst_step ) \ + { \ + for( j = 0; j <= win_size.width - 2; j += 2 ) \ + { \ + worktype s0 = cast_macro(src[j])*a11 + \ + cast_macro(src[j+1])*a12 + \ + cast_macro(src[j+src_step])*a21 + \ + cast_macro(src[j+src_step+1])*a22; \ + worktype s1 = cast_macro(src[j+1])*a11 + \ + cast_macro(src[j+2])*a12 + \ + cast_macro(src[j+src_step+1])*a21 + \ + cast_macro(src[j+src_step+2])*a22; \ + \ + dst[j] = (dsttype)cast_macro2(s0); \ + dst[j+1] = (dsttype)cast_macro2(s1); \ + } \ + \ + for( ; j < win_size.width; j++ ) \ + { \ + worktype s0 = cast_macro(src[j])*a11 + \ + cast_macro(src[j+1])*a12 + \ + cast_macro(src[j+src_step])*a21 + \ + cast_macro(src[j+src_step+1])*a22; \ + \ + dst[j] = (dsttype)cast_macro2(s0); \ + } \ + } \ + } \ + else \ + { \ + CvRect r; \ + \ + src = (const srctype*)icvAdjustRect( src, src_step*sizeof(*src), \ + sizeof(*src), src_size, win_size,ip, &r); \ + \ + for( i = 0; i < win_size.height; i++, dst += dst_step ) \ + { \ + const srctype *src2 = src + src_step; \ + \ + if( i < r.y || i >= r.height ) \ + src2 -= src_step; \ + \ + for( j = 0; j < r.x; j++ ) \ + { \ + worktype s0 = cast_macro(src[r.x])*b1 + \ + cast_macro(src2[r.x])*b2; \ + \ + dst[j] = (dsttype)cast_macro2(s0); \ + } \ + \ + for( ; j < r.width; j++ ) \ + { \ + worktype s0 = cast_macro(src[j])*a11 + \ + cast_macro(src[j+1])*a12 + \ + cast_macro(src2[j])*a21 + \ + cast_macro(src2[j+1])*a22; \ + \ + dst[j] = (dsttype)cast_macro2(s0); \ + } \ + \ + for( ; j < win_size.width; j++ ) \ + { \ + worktype s0 = cast_macro(src[r.width])*b1 + \ + cast_macro(src2[r.width])*b2; \ + \ + dst[j] = (dsttype)cast_macro2(s0); \ + } \ + \ + if( i < r.height ) \ + src = src2; \ + } \ + } \ + \ + return CV_OK; \ +} + + +#define ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( flavor, srctype, dsttype, worktype, \ + cast_macro, scale_macro, mul_macro )\ +static CvStatus CV_STDCALL icvGetRectSubPix_##flavor##_C3R \ +( const srctype* src, int src_step, CvSize src_size, \ + dsttype* dst, int dst_step, CvSize win_size, CvPoint2D32f center ) \ +{ \ + CvPoint ip; \ + worktype a, b; \ + int i, j; \ + \ + center.x -= (win_size.width-1)*0.5f; \ + center.y -= (win_size.height-1)*0.5f; \ + \ + ip.x = cvFloor( center.x ); \ + ip.y = cvFloor( center.y ); \ + \ + a = scale_macro( center.x - ip.x ); \ + b = scale_macro( center.y - ip.y ); \ + \ + src_step /= sizeof( src[0] ); \ + dst_step /= sizeof( dst[0] ); \ + \ + if( 0 <= ip.x && ip.x + win_size.width < src_size.width && \ + 0 <= ip.y && ip.y + win_size.height < src_size.height ) \ + { \ + /* extracted rectangle is totally inside the image */ \ + src += ip.y * src_step + ip.x*3; \ + \ + for( i = 0; i < win_size.height; i++, src += src_step, \ + dst += dst_step ) \ + { \ + for( j = 0; j < win_size.width; j++ ) \ + { \ + worktype s0 = cast_macro(src[j*3]); \ + worktype s1 = cast_macro(src[j*3 + src_step]); \ + s0 += mul_macro( a, (cast_macro(src[j*3+3]) - s0)); \ + s1 += mul_macro( a, (cast_macro(src[j*3+3+src_step]) - s1));\ + dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ + \ + s0 = cast_macro(src[j*3+1]); \ + s1 = cast_macro(src[j*3+1 + src_step]); \ + s0 += mul_macro( a, (cast_macro(src[j*3+4]) - s0)); \ + s1 += mul_macro( a, (cast_macro(src[j*3+4+src_step]) - s1));\ + dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ + \ + s0 = cast_macro(src[j*3+2]); \ + s1 = cast_macro(src[j*3+2 + src_step]); \ + s0 += mul_macro( a, (cast_macro(src[j*3+5]) - s0)); \ + s1 += mul_macro( a, (cast_macro(src[j*3+5+src_step]) - s1));\ + dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ + } \ + } \ + } \ + else \ + { \ + CvRect r; \ + \ + src = (const srctype*)icvAdjustRect( src, src_step*sizeof(*src), \ + sizeof(*src)*3, src_size, win_size, ip, &r ); \ + \ + for( i = 0; i < win_size.height; i++, dst += dst_step ) \ + { \ + const srctype *src2 = src + src_step; \ + \ + if( i < r.y || i >= r.height ) \ + src2 -= src_step; \ + \ + for( j = 0; j < r.x; j++ ) \ + { \ + worktype s0 = cast_macro(src[r.x*3]); \ + worktype s1 = cast_macro(src2[r.x*3]); \ + dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ + \ + s0 = cast_macro(src[r.x*3+1]); \ + s1 = cast_macro(src2[r.x*3+1]); \ + dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ + \ + s0 = cast_macro(src[r.x*3+2]); \ + s1 = cast_macro(src2[r.x*3+2]); \ + dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ + } \ + \ + for( ; j < r.width; j++ ) \ + { \ + worktype s0 = cast_macro(src[j*3]); \ + worktype s1 = cast_macro(src2[j*3]); \ + s0 += mul_macro( a, (cast_macro(src[j*3 + 3]) - s0)); \ + s1 += mul_macro( a, (cast_macro(src2[j*3 + 3]) - s1)); \ + dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ + \ + s0 = cast_macro(src[j*3+1]); \ + s1 = cast_macro(src2[j*3+1]); \ + s0 += mul_macro( a, (cast_macro(src[j*3 + 4]) - s0)); \ + s1 += mul_macro( a, (cast_macro(src2[j*3 + 4]) - s1)); \ + dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ + \ + s0 = cast_macro(src[j*3+2]); \ + s1 = cast_macro(src2[j*3+2]); \ + s0 += mul_macro( a, (cast_macro(src[j*3 + 5]) - s0)); \ + s1 += mul_macro( a, (cast_macro(src2[j*3 + 5]) - s1)); \ + dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ + } \ + \ + for( ; j < win_size.width; j++ ) \ + { \ + worktype s0 = cast_macro(src[r.width*3]); \ + worktype s1 = cast_macro(src2[r.width*3]); \ + dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ + \ + s0 = cast_macro(src[r.width*3+1]); \ + s1 = cast_macro(src2[r.width*3+1]); \ + dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ + \ + s0 = cast_macro(src[r.width*3+2]); \ + s1 = cast_macro(src2[r.width*3+2]); \ + dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ + } \ + \ + if( i < r.height ) \ + src = src2; \ + } \ + } \ + \ + return CV_OK; \ +} + + + +CvStatus CV_STDCALL icvGetRectSubPix_8u32f_C1R +( const uchar* src, int src_step, CvSize src_size, + float* dst, int dst_step, CvSize win_size, CvPoint2D32f center ) +{ + CvPoint ip; + float a12, a22, b1, b2; + float a, b; + double s = 0; + int i, j; + + center.x -= (win_size.width-1)*0.5f; + center.y -= (win_size.height-1)*0.5f; + + ip.x = cvFloor( center.x ); + ip.y = cvFloor( center.y ); + + if( win_size.width <= 0 || win_size.height <= 0 ) + return CV_BADRANGE_ERR; + + a = center.x - ip.x; + b = center.y - ip.y; + a = MAX(a,0.0001f); + a12 = a*(1.f-b); + a22 = a*b; + b1 = 1.f - b; + b2 = b; + s = (1. - a)/a; + + src_step /= sizeof(src[0]); + dst_step /= sizeof(dst[0]); + + if( 0 <= ip.x && ip.x + win_size.width < src_size.width && + 0 <= ip.y && ip.y + win_size.height < src_size.height ) + { + // extracted rectangle is totally inside the image + src += ip.y * src_step + ip.x; + +#if 0 + if( icvCopySubpix_8u32f_C1R_p && + icvCopySubpix_8u32f_C1R_p( src, src_step, dst, + dst_step*sizeof(dst[0]), win_size, a, b ) >= 0 ) + return CV_OK; +#endif + + for( ; win_size.height--; src += src_step, dst += dst_step ) + { + float prev = (1 - a)*(b1*CV_8TO32F(src[0]) + b2*CV_8TO32F(src[src_step])); + for( j = 0; j < win_size.width; j++ ) + { + float t = a12*CV_8TO32F(src[j+1]) + a22*CV_8TO32F(src[j+1+src_step]); + dst[j] = prev + t; + prev = (float)(t*s); + } + } + } + else + { + CvRect r; + + src = (const uchar*)icvAdjustRect( src, src_step*sizeof(*src), + sizeof(*src), src_size, win_size,ip, &r); + + for( i = 0; i < win_size.height; i++, dst += dst_step ) + { + const uchar *src2 = src + src_step; + + if( i < r.y || i >= r.height ) + src2 -= src_step; + + for( j = 0; j < r.x; j++ ) + { + float s0 = CV_8TO32F(src[r.x])*b1 + + CV_8TO32F(src2[r.x])*b2; + + dst[j] = (float)(s0); + } + + if( j < r.width ) + { + float prev = (1 - a)*(b1*CV_8TO32F(src[j]) + b2*CV_8TO32F(src2[j])); + + for( ; j < r.width; j++ ) + { + float t = a12*CV_8TO32F(src[j+1]) + a22*CV_8TO32F(src2[j+1]); + dst[j] = prev + t; + prev = (float)(t*s); + } + } + + for( ; j < win_size.width; j++ ) + { + float s0 = CV_8TO32F(src[r.width])*b1 + + CV_8TO32F(src2[r.width])*b2; + + dst[j] = (float)(s0); + } + + if( i < r.height ) + src = src2; + } + } + + return CV_OK; +} + + + +#define ICV_SHIFT 16 +#define ICV_SCALE(x) cvRound((x)*(1 << ICV_SHIFT)) +#define ICV_MUL_SCALE(x,y) (((x)*(y) + (1 << (ICV_SHIFT-1))) >> ICV_SHIFT) +#define ICV_DESCALE(x) (((x)+(1 << (ICV_SHIFT-1))) >> ICV_SHIFT) + +/*icvCopySubpix_8u_C1R_t icvCopySubpix_8u_C1R_p = 0; +icvCopySubpix_8u32f_C1R_t icvCopySubpix_8u32f_C1R_p = 0; +icvCopySubpix_32f_C1R_t icvCopySubpix_32f_C1R_p = 0;*/ + +ICV_DEF_GET_RECT_SUB_PIX_FUNC( 8u, uchar, uchar, int, CV_NOP, ICV_SCALE, ICV_DESCALE ) +//ICV_DEF_GET_RECT_SUB_PIX_FUNC( 8u32f, uchar, float, float, CV_8TO32F, CV_NOP, CV_NOP ) +ICV_DEF_GET_RECT_SUB_PIX_FUNC( 32f, float, float, float, CV_NOP, CV_NOP, CV_NOP ) + +ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( 8u, uchar, uchar, int, CV_NOP, ICV_SCALE, ICV_MUL_SCALE ) +ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( 8u32f, uchar, float, float, CV_8TO32F, CV_NOP, CV_MUL ) +ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( 32f, float, float, float, CV_NOP, CV_NOP, CV_MUL ) + + +#define ICV_DEF_INIT_SUBPIX_TAB( FUNCNAME, FLAG ) \ +static void icvInit##FUNCNAME##FLAG##Table( CvFuncTable* tab ) \ +{ \ + tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u_##FLAG; \ + tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f_##FLAG; \ + \ + tab->fn_2d[1] = (void*)icv##FUNCNAME##_8u32f_##FLAG; \ +} + + +ICV_DEF_INIT_SUBPIX_TAB( GetRectSubPix, C1R ) +ICV_DEF_INIT_SUBPIX_TAB( GetRectSubPix, C3R ) + +typedef CvStatus (CV_STDCALL *CvGetRectSubPixFunc)( const void* src, int src_step, + CvSize src_size, void* dst, + int dst_step, CvSize win_size, + CvPoint2D32f center ); + +CV_IMPL void +cvGetRectSubPix( const void* srcarr, void* dstarr, CvPoint2D32f center ) +{ + static CvFuncTable gr_tab[2]; + static int inittab = 0; + + CvMat srcstub, *src = (CvMat*)srcarr; + CvMat dststub, *dst = (CvMat*)dstarr; + CvSize src_size, dst_size; + CvGetRectSubPixFunc func; + int cn, src_step, dst_step; + + if( !inittab ) + { + icvInitGetRectSubPixC1RTable( gr_tab + 0 ); + icvInitGetRectSubPixC3RTable( gr_tab + 1 ); + inittab = 1; + } + + if( !CV_IS_MAT(src)) + src = cvGetMat( src, &srcstub ); + + if( !CV_IS_MAT(dst)) + dst = cvGetMat( dst, &dststub ); + + cn = CV_MAT_CN( src->type ); + + if( (cn != 1 && cn != 3) || !CV_ARE_CNS_EQ( src, dst )) + CV_Error( CV_StsUnsupportedFormat, "" ); + + src_size = cvGetMatSize( src ); + dst_size = cvGetMatSize( dst ); + src_step = src->step ? src->step : CV_STUB_STEP; + dst_step = dst->step ? dst->step : CV_STUB_STEP; + + //if( dst_size.width > src_size.width || dst_size.height > src_size.height ) + // CV_ERROR( CV_StsBadSize, "destination ROI must be smaller than source ROI" ); + + if( CV_ARE_DEPTHS_EQ( src, dst )) + { + func = (CvGetRectSubPixFunc)(gr_tab[cn != 1].fn_2d[CV_MAT_DEPTH(src->type)]); + } + else + { + if( CV_MAT_DEPTH( src->type ) != CV_8U || CV_MAT_DEPTH( dst->type ) != CV_32F ) + CV_Error( CV_StsUnsupportedFormat, "" ); + + func = (CvGetRectSubPixFunc)(gr_tab[cn != 1].fn_2d[1]); + } + + if( !func ) + CV_Error( CV_StsUnsupportedFormat, "" ); + + IPPI_CALL( func( src->data.ptr, src_step, src_size, + dst->data.ptr, dst_step, dst_size, center )); +} + + +#define ICV_32F8U(x) ((uchar)cvRound(x)) + +#define ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( flavor, srctype, dsttype, \ + worktype, cast_macro, cvt ) \ +CvStatus CV_STDCALL \ +icvGetQuadrangleSubPix_##flavor##_C1R \ +( const srctype * src, int src_step, CvSize src_size, \ + dsttype *dst, int dst_step, CvSize win_size, const float *matrix ) \ +{ \ + int x, y; \ + double dx = (win_size.width - 1)*0.5; \ + double dy = (win_size.height - 1)*0.5; \ + double A11 = matrix[0], A12 = matrix[1], A13 = matrix[2]-A11*dx-A12*dy; \ + double A21 = matrix[3], A22 = matrix[4], A23 = matrix[5]-A21*dx-A22*dy; \ + \ + src_step /= sizeof(srctype); \ + dst_step /= sizeof(dsttype); \ + \ + for( y = 0; y < win_size.height; y++, dst += dst_step ) \ + { \ + double xs = A12*y + A13; \ + double ys = A22*y + A23; \ + double xe = A11*(win_size.width-1) + A12*y + A13; \ + double ye = A21*(win_size.width-1) + A22*y + A23; \ + \ + if( (unsigned)(cvFloor(xs)-1) < (unsigned)(src_size.width - 3) && \ + (unsigned)(cvFloor(ys)-1) < (unsigned)(src_size.height - 3) && \ + (unsigned)(cvFloor(xe)-1) < (unsigned)(src_size.width - 3) && \ + (unsigned)(cvFloor(ye)-1) < (unsigned)(src_size.height - 3)) \ + { \ + for( x = 0; x < win_size.width; x++ ) \ + { \ + int ixs = cvFloor( xs ); \ + int iys = cvFloor( ys ); \ + const srctype *ptr = src + src_step*iys + ixs; \ + double a = xs - ixs, b = ys - iys, a1 = 1.f - a; \ + worktype p0 = cvt(ptr[0])*a1 + cvt(ptr[1])*a; \ + worktype p1 = cvt(ptr[src_step])*a1 + cvt(ptr[src_step+1])*a;\ + xs += A11; \ + ys += A21; \ + \ + dst[x] = cast_macro(p0 + b * (p1 - p0)); \ + } \ + } \ + else \ + { \ + for( x = 0; x < win_size.width; x++ ) \ + { \ + int ixs = cvFloor( xs ), iys = cvFloor( ys ); \ + double a = xs - ixs, b = ys - iys, a1 = 1.f - a; \ + const srctype *ptr0, *ptr1; \ + worktype p0, p1; \ + xs += A11; ys += A21; \ + \ + if( (unsigned)iys < (unsigned)(src_size.height-1) ) \ + ptr0 = src + src_step*iys, ptr1 = ptr0 + src_step; \ + else \ + ptr0 = ptr1 = src + (iys < 0 ? 0 : src_size.height-1)*src_step; \ + \ + if( (unsigned)ixs < (unsigned)(src_size.width-1) ) \ + { \ + p0 = cvt(ptr0[ixs])*a1 + cvt(ptr0[ixs+1])*a; \ + p1 = cvt(ptr1[ixs])*a1 + cvt(ptr1[ixs+1])*a; \ + } \ + else \ + { \ + ixs = ixs < 0 ? 0 : src_size.width - 1; \ + p0 = cvt(ptr0[ixs]); p1 = cvt(ptr1[ixs]); \ + } \ + dst[x] = cast_macro(p0 + b * (p1 - p0)); \ + } \ + } \ + } \ + \ + return CV_OK; \ +} + + +#define ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( flavor, srctype, dsttype, \ + worktype, cast_macro, cvt ) \ +static CvStatus CV_STDCALL \ +icvGetQuadrangleSubPix_##flavor##_C3R \ +( const srctype * src, int src_step, CvSize src_size, \ + dsttype *dst, int dst_step, CvSize win_size, const float *matrix ) \ +{ \ + int x, y; \ + double dx = (win_size.width - 1)*0.5; \ + double dy = (win_size.height - 1)*0.5; \ + double A11 = matrix[0], A12 = matrix[1], A13 = matrix[2]-A11*dx-A12*dy; \ + double A21 = matrix[3], A22 = matrix[4], A23 = matrix[5]-A21*dx-A22*dy; \ + \ + src_step /= sizeof(srctype); \ + dst_step /= sizeof(dsttype); \ + \ + for( y = 0; y < win_size.height; y++, dst += dst_step ) \ + { \ + double xs = A12*y + A13; \ + double ys = A22*y + A23; \ + double xe = A11*(win_size.width-1) + A12*y + A13; \ + double ye = A21*(win_size.width-1) + A22*y + A23; \ + \ + if( (unsigned)(cvFloor(xs)-1) < (unsigned)(src_size.width - 3) && \ + (unsigned)(cvFloor(ys)-1) < (unsigned)(src_size.height - 3) && \ + (unsigned)(cvFloor(xe)-1) < (unsigned)(src_size.width - 3) && \ + (unsigned)(cvFloor(ye)-1) < (unsigned)(src_size.height - 3)) \ + { \ + for( x = 0; x < win_size.width; x++ ) \ + { \ + int ixs = cvFloor( xs ); \ + int iys = cvFloor( ys ); \ + const srctype *ptr = src + src_step*iys + ixs*3; \ + double a = xs - ixs, b = ys - iys, a1 = 1.f - a; \ + worktype p0, p1; \ + xs += A11; \ + ys += A21; \ + \ + p0 = cvt(ptr[0])*a1 + cvt(ptr[3])*a; \ + p1 = cvt(ptr[src_step])*a1 + cvt(ptr[src_step+3])*a; \ + dst[x*3] = cast_macro(p0 + b * (p1 - p0)); \ + \ + p0 = cvt(ptr[1])*a1 + cvt(ptr[4])*a; \ + p1 = cvt(ptr[src_step+1])*a1 + cvt(ptr[src_step+4])*a; \ + dst[x*3+1] = cast_macro(p0 + b * (p1 - p0)); \ + \ + p0 = cvt(ptr[2])*a1 + cvt(ptr[5])*a; \ + p1 = cvt(ptr[src_step+2])*a1 + cvt(ptr[src_step+5])*a; \ + dst[x*3+2] = cast_macro(p0 + b * (p1 - p0)); \ + } \ + } \ + else \ + { \ + for( x = 0; x < win_size.width; x++ ) \ + { \ + int ixs = cvFloor(xs), iys = cvFloor(ys); \ + double a = xs - ixs, b = ys - iys; \ + const srctype *ptr0, *ptr1; \ + xs += A11; ys += A21; \ + \ + if( (unsigned)iys < (unsigned)(src_size.height-1) ) \ + ptr0 = src + src_step*iys, ptr1 = ptr0 + src_step; \ + else \ + ptr0 = ptr1 = src + (iys < 0 ? 0 : src_size.height-1)*src_step; \ + \ + if( (unsigned)ixs < (unsigned)(src_size.width - 1) ) \ + { \ + double a1 = 1.f - a; \ + worktype p0, p1; \ + ptr0 += ixs*3; ptr1 += ixs*3; \ + p0 = cvt(ptr0[0])*a1 + cvt(ptr0[3])*a; \ + p1 = cvt(ptr1[0])*a1 + cvt(ptr1[3])*a; \ + dst[x*3] = cast_macro(p0 + b * (p1 - p0)); \ + \ + p0 = cvt(ptr0[1])*a1 + cvt(ptr0[4])*a; \ + p1 = cvt(ptr1[1])*a1 + cvt(ptr1[4])*a; \ + dst[x*3+1] = cast_macro(p0 + b * (p1 - p0)); \ + \ + p0 = cvt(ptr0[2])*a1 + cvt(ptr0[5])*a; \ + p1 = cvt(ptr1[2])*a1 + cvt(ptr1[5])*a; \ + dst[x*3+2] = cast_macro(p0 + b * (p1 - p0)); \ + } \ + else \ + { \ + double b1 = 1.f - b; \ + ixs = ixs < 0 ? 0 : src_size.width - 1; \ + ptr0 += ixs*3; ptr1 += ixs*3; \ + \ + dst[x*3] = cast_macro(cvt(ptr0[0])*b1 + cvt(ptr1[0])*b);\ + dst[x*3+1]=cast_macro(cvt(ptr0[1])*b1 + cvt(ptr1[1])*b);\ + dst[x*3+2]=cast_macro(cvt(ptr0[2])*b1 + cvt(ptr1[2])*b);\ + } \ + } \ + } \ + } \ + \ + return CV_OK; \ +} + + +/*#define srctype uchar +#define dsttype uchar +#define worktype float +#define cvt CV_8TO32F +#define cast_macro ICV_32F8U + +#undef srctype +#undef dsttype +#undef worktype +#undef cvt +#undef cast_macro*/ + +ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( 8u, uchar, uchar, double, ICV_32F8U, CV_8TO32F ) +ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( 32f, float, float, double, CV_CAST_32F, CV_NOP ) +ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( 8u32f, uchar, float, double, CV_CAST_32F, CV_8TO32F ) + +ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( 8u, uchar, uchar, double, ICV_32F8U, CV_8TO32F ) +ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( 32f, float, float, double, CV_CAST_32F, CV_NOP ) +ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( 8u32f, uchar, float, double, CV_CAST_32F, CV_8TO32F ) + +ICV_DEF_INIT_SUBPIX_TAB( GetQuadrangleSubPix, C1R ) +ICV_DEF_INIT_SUBPIX_TAB( GetQuadrangleSubPix, C3R ) + +typedef CvStatus (CV_STDCALL *CvGetQuadrangleSubPixFunc)( + const void* src, int src_step, + CvSize src_size, void* dst, + int dst_step, CvSize win_size, + const float* matrix ); + +CV_IMPL void +cvGetQuadrangleSubPix( const void* srcarr, void* dstarr, const CvMat* mat ) +{ + static CvFuncTable gq_tab[2]; + static int inittab = 0; + + CvMat srcstub, *src = (CvMat*)srcarr; + CvMat dststub, *dst = (CvMat*)dstarr; + CvSize src_size, dst_size; + CvGetQuadrangleSubPixFunc func; + float m[6]; + int k, cn; + + if( !inittab ) + { + icvInitGetQuadrangleSubPixC1RTable( gq_tab + 0 ); + icvInitGetQuadrangleSubPixC3RTable( gq_tab + 1 ); + inittab = 1; + } + + if( !CV_IS_MAT(src)) + src = cvGetMat( src, &srcstub ); + + if( !CV_IS_MAT(dst)) + dst = cvGetMat( dst, &dststub ); + + if( !CV_IS_MAT(mat)) + CV_Error( CV_StsBadArg, "map matrix is not valid" ); + + cn = CV_MAT_CN( src->type ); + + if( (cn != 1 && cn != 3) || !CV_ARE_CNS_EQ( src, dst )) + CV_Error( CV_StsUnsupportedFormat, "" ); + + src_size = cvGetMatSize( src ); + dst_size = cvGetMatSize( dst ); + + /*if( dst_size.width > src_size.width || dst_size.height > src_size.height ) + CV_ERROR( CV_StsBadSize, "destination ROI must not be larger than source ROI" );*/ + + if( mat->rows != 2 || mat->cols != 3 ) + CV_Error( CV_StsBadArg, + "Transformation matrix must be 2x3" ); + + if( CV_MAT_TYPE( mat->type ) == CV_32FC1 ) + { + for( k = 0; k < 3; k++ ) + { + m[k] = mat->data.fl[k]; + m[3 + k] = ((float*)(mat->data.ptr + mat->step))[k]; + } + } + else if( CV_MAT_TYPE( mat->type ) == CV_64FC1 ) + { + for( k = 0; k < 3; k++ ) + { + m[k] = (float)mat->data.db[k]; + m[3 + k] = (float)((double*)(mat->data.ptr + mat->step))[k]; + } + } + else + CV_Error( CV_StsUnsupportedFormat, + "The transformation matrix should have 32fC1 or 64fC1 type" ); + + if( CV_ARE_DEPTHS_EQ( src, dst )) + { + func = (CvGetQuadrangleSubPixFunc)(gq_tab[cn != 1].fn_2d[CV_MAT_DEPTH(src->type)]); + } + else + { + if( CV_MAT_DEPTH( src->type ) != CV_8U || CV_MAT_DEPTH( dst->type ) != CV_32F ) + CV_Error( CV_StsUnsupportedFormat, "" ); + + func = (CvGetQuadrangleSubPixFunc)(gq_tab[cn != 1].fn_2d[1]); + } + + if( !func ) + CV_Error( CV_StsUnsupportedFormat, "" ); + + IPPI_CALL( func( src->data.ptr, src->step, src_size, + dst->data.ptr, dst->step, dst_size, m )); +} + + +void cv::getRectSubPix( InputArray _image, Size patchSize, Point2f center, + OutputArray _patch, int patchType ) +{ + Mat image = _image.getMat(); + _patch.create(patchSize, patchType < 0 ? image.type() : + CV_MAKETYPE(CV_MAT_DEPTH(patchType),image.channels())); + Mat patch = _patch.getMat(); + CvMat _cimage = image, _cpatch = patch; + cvGetRectSubPix(&_cimage, &_cpatch, center); +} + +/* End of file. */ diff --git a/imgproc/src/segmentation.cpp b/imgproc/src/segmentation.cpp new file mode 100644 index 0000000..7fbb039 --- /dev/null +++ b/imgproc/src/segmentation.cpp @@ -0,0 +1,541 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +/****************************************************************************************\ +* Watershed * +\****************************************************************************************/ + +typedef struct CvWSNode +{ + struct CvWSNode* next; + int mask_ofs; + int img_ofs; +} +CvWSNode; + +typedef struct CvWSQueue +{ + CvWSNode* first; + CvWSNode* last; +} +CvWSQueue; + +static CvWSNode* +icvAllocWSNodes( CvMemStorage* storage ) +{ + CvWSNode* n = 0; + + int i, count = (storage->block_size - sizeof(CvMemBlock))/sizeof(*n) - 1; + + n = (CvWSNode*)cvMemStorageAlloc( storage, count*sizeof(*n) ); + for( i = 0; i < count-1; i++ ) + n[i].next = n + i + 1; + n[count-1].next = 0; + + return n; +} + + +CV_IMPL void +cvWatershed( const CvArr* srcarr, CvArr* dstarr ) +{ + const int IN_QUEUE = -2; + const int WSHED = -1; + const int NQ = 256; + cv::Ptr storage; + + CvMat sstub, *src; + CvMat dstub, *dst; + CvSize size; + CvWSNode* free_node = 0, *node; + CvWSQueue q[NQ]; + int active_queue; + int i, j; + int db, dg, dr; + int* mask; + uchar* img; + int mstep, istep; + int subs_tab[513]; + + // MAX(a,b) = b + MAX(a-b,0) + #define ws_max(a,b) ((b) + subs_tab[(a)-(b)+NQ]) + // MIN(a,b) = a - MAX(a-b,0) + #define ws_min(a,b) ((a) - subs_tab[(a)-(b)+NQ]) + + #define ws_push(idx,mofs,iofs) \ + { \ + if( !free_node ) \ + free_node = icvAllocWSNodes( storage );\ + node = free_node; \ + free_node = free_node->next;\ + node->next = 0; \ + node->mask_ofs = mofs; \ + node->img_ofs = iofs; \ + if( q[idx].last ) \ + q[idx].last->next=node; \ + else \ + q[idx].first = node; \ + q[idx].last = node; \ + } + + #define ws_pop(idx,mofs,iofs) \ + { \ + node = q[idx].first; \ + q[idx].first = node->next; \ + if( !node->next ) \ + q[idx].last = 0; \ + node->next = free_node; \ + free_node = node; \ + mofs = node->mask_ofs; \ + iofs = node->img_ofs; \ + } + + #define c_diff(ptr1,ptr2,diff) \ + { \ + db = abs((ptr1)[0] - (ptr2)[0]);\ + dg = abs((ptr1)[1] - (ptr2)[1]);\ + dr = abs((ptr1)[2] - (ptr2)[2]);\ + diff = ws_max(db,dg); \ + diff = ws_max(diff,dr); \ + assert( 0 <= diff && diff <= 255 ); \ + } + + src = cvGetMat( srcarr, &sstub ); + dst = cvGetMat( dstarr, &dstub ); + + if( CV_MAT_TYPE(src->type) != CV_8UC3 ) + CV_Error( CV_StsUnsupportedFormat, "Only 8-bit, 3-channel input images are supported" ); + + if( CV_MAT_TYPE(dst->type) != CV_32SC1 ) + CV_Error( CV_StsUnsupportedFormat, + "Only 32-bit, 1-channel output images are supported" ); + + if( !CV_ARE_SIZES_EQ( src, dst )) + CV_Error( CV_StsUnmatchedSizes, "The input and output images must have the same size" ); + + size = cvGetMatSize(src); + storage = cvCreateMemStorage(); + + istep = src->step; + img = src->data.ptr; + mstep = dst->step / sizeof(mask[0]); + mask = dst->data.i; + + memset( q, 0, NQ*sizeof(q[0]) ); + + for( i = 0; i < 256; i++ ) + subs_tab[i] = 0; + for( i = 256; i <= 512; i++ ) + subs_tab[i] = i - 256; + + // draw a pixel-wide border of dummy "watershed" (i.e. boundary) pixels + for( j = 0; j < size.width; j++ ) + mask[j] = mask[j + mstep*(size.height-1)] = WSHED; + + // initial phase: put all the neighbor pixels of each marker to the ordered queue - + // determine the initial boundaries of the basins + for( i = 1; i < size.height-1; i++ ) + { + img += istep; mask += mstep; + mask[0] = mask[size.width-1] = WSHED; + + for( j = 1; j < size.width-1; j++ ) + { + int* m = mask + j; + if( m[0] < 0 ) m[0] = 0; + if( m[0] == 0 && (m[-1] > 0 || m[1] > 0 || m[-mstep] > 0 || m[mstep] > 0) ) + { + uchar* ptr = img + j*3; + int idx = 256, t; + if( m[-1] > 0 ) + c_diff( ptr, ptr - 3, idx ); + if( m[1] > 0 ) + { + c_diff( ptr, ptr + 3, t ); + idx = ws_min( idx, t ); + } + if( m[-mstep] > 0 ) + { + c_diff( ptr, ptr - istep, t ); + idx = ws_min( idx, t ); + } + if( m[mstep] > 0 ) + { + c_diff( ptr, ptr + istep, t ); + idx = ws_min( idx, t ); + } + assert( 0 <= idx && idx <= 255 ); + ws_push( idx, i*mstep + j, i*istep + j*3 ); + m[0] = IN_QUEUE; + } + } + } + + // find the first non-empty queue + for( i = 0; i < NQ; i++ ) + if( q[i].first ) + break; + + // if there is no markers, exit immediately + if( i == NQ ) + return; + + active_queue = i; + img = src->data.ptr; + mask = dst->data.i; + + // recursively fill the basins + for(;;) + { + int mofs, iofs; + int lab = 0, t; + int* m; + uchar* ptr; + + if( q[active_queue].first == 0 ) + { + for( i = active_queue+1; i < NQ; i++ ) + if( q[i].first ) + break; + if( i == NQ ) + break; + active_queue = i; + } + + ws_pop( active_queue, mofs, iofs ); + + m = mask + mofs; + ptr = img + iofs; + t = m[-1]; + if( t > 0 ) lab = t; + t = m[1]; + if( t > 0 ) + { + if( lab == 0 ) lab = t; + else if( t != lab ) lab = WSHED; + } + t = m[-mstep]; + if( t > 0 ) + { + if( lab == 0 ) lab = t; + else if( t != lab ) lab = WSHED; + } + t = m[mstep]; + if( t > 0 ) + { + if( lab == 0 ) lab = t; + else if( t != lab ) lab = WSHED; + } + assert( lab != 0 ); + m[0] = lab; + if( lab == WSHED ) + continue; + + if( m[-1] == 0 ) + { + c_diff( ptr, ptr - 3, t ); + ws_push( t, mofs - 1, iofs - 3 ); + active_queue = ws_min( active_queue, t ); + m[-1] = IN_QUEUE; + } + if( m[1] == 0 ) + { + c_diff( ptr, ptr + 3, t ); + ws_push( t, mofs + 1, iofs + 3 ); + active_queue = ws_min( active_queue, t ); + m[1] = IN_QUEUE; + } + if( m[-mstep] == 0 ) + { + c_diff( ptr, ptr - istep, t ); + ws_push( t, mofs - mstep, iofs - istep ); + active_queue = ws_min( active_queue, t ); + m[-mstep] = IN_QUEUE; + } + if( m[mstep] == 0 ) + { + c_diff( ptr, ptr + istep, t ); + ws_push( t, mofs + mstep, iofs + istep ); + active_queue = ws_min( active_queue, t ); + m[mstep] = IN_QUEUE; + } + } +} + + +void cv::watershed( InputArray _src, InputOutputArray markers ) +{ + Mat src = _src.getMat(); + CvMat c_src = _src.getMat(), c_markers = markers.getMat(); + cvWatershed( &c_src, &c_markers ); +} + + +/****************************************************************************************\ +* Meanshift * +\****************************************************************************************/ + +CV_IMPL void +cvPyrMeanShiftFiltering( const CvArr* srcarr, CvArr* dstarr, + double sp0, double sr, int max_level, + CvTermCriteria termcrit ) +{ + const int cn = 3; + const int MAX_LEVELS = 8; + + if( (unsigned)max_level > (unsigned)MAX_LEVELS ) + CV_Error( CV_StsOutOfRange, "The number of pyramid levels is too large or negative" ); + + std::vector src_pyramid(max_level+1); + std::vector dst_pyramid(max_level+1); + cv::Mat mask0; + int i, j, level; + //uchar* submask = 0; + + #define cdiff(ofs0) (tab[c0-dptr[ofs0]+255] + \ + tab[c1-dptr[(ofs0)+1]+255] + tab[c2-dptr[(ofs0)+2]+255] >= isr22) + + double sr2 = sr * sr; + int isr2 = cvRound(sr2), isr22 = MAX(isr2,16); + int tab[768]; + cv::Mat src0 = cv::cvarrToMat(srcarr); + cv::Mat dst0 = cv::cvarrToMat(dstarr); + + if( src0.type() != CV_8UC3 ) + CV_Error( CV_StsUnsupportedFormat, "Only 8-bit, 3-channel images are supported" ); + + if( src0.type() != dst0.type() ) + CV_Error( CV_StsUnmatchedFormats, "The input and output images must have the same type" ); + + if( src0.size() != dst0.size() ) + CV_Error( CV_StsUnmatchedSizes, "The input and output images must have the same size" ); + + if( !(termcrit.type & CV_TERMCRIT_ITER) ) + termcrit.max_iter = 5; + termcrit.max_iter = MAX(termcrit.max_iter,1); + termcrit.max_iter = MIN(termcrit.max_iter,100); + if( !(termcrit.type & CV_TERMCRIT_EPS) ) + termcrit.epsilon = 1.f; + termcrit.epsilon = MAX(termcrit.epsilon, 0.f); + + for( i = 0; i < 768; i++ ) + tab[i] = (i - 255)*(i - 255); + + // 1. construct pyramid + src_pyramid[0] = src0; + dst_pyramid[0] = dst0; + for( level = 1; level <= max_level; level++ ) + { + src_pyramid[level].create( (src_pyramid[level-1].rows+1)/2, + (src_pyramid[level-1].cols+1)/2, src_pyramid[level-1].type() ); + dst_pyramid[level].create( src_pyramid[level].rows, + src_pyramid[level].cols, src_pyramid[level].type() ); + cv::pyrDown( src_pyramid[level-1], src_pyramid[level], src_pyramid[level].size() ); + //CV_CALL( cvResize( src_pyramid[level-1], src_pyramid[level], CV_INTER_AREA )); + } + + mask0.create(src0.rows, src0.cols, CV_8UC1); + //CV_CALL( submask = (uchar*)cvAlloc( (sp+2)*(sp+2) )); + + // 2. apply meanshift, starting from the pyramid top (i.e. the smallest layer) + for( level = max_level; level >= 0; level-- ) + { + cv::Mat src = src_pyramid[level]; + cv::Size size = src.size(); + uchar* sptr = src.data; + int sstep = (int)src.step; + uchar* mask = 0; + int mstep = 0; + uchar* dptr; + int dstep; + float sp = (float)(sp0 / (1 << level)); + sp = MAX( sp, 1 ); + + if( level < max_level ) + { + cv::Size size1 = dst_pyramid[level+1].size(); + cv::Mat m( size.height, size.width, CV_8UC1, mask0.data ); + dstep = (int)dst_pyramid[level+1].step; + dptr = dst_pyramid[level+1].data + dstep + cn; + mstep = (int)m.step; + mask = m.data + mstep; + //cvResize( dst_pyramid[level+1], dst_pyramid[level], CV_INTER_CUBIC ); + cv::pyrUp( dst_pyramid[level+1], dst_pyramid[level], dst_pyramid[level].size() ); + m.setTo(cv::Scalar::all(0)); + + for( i = 1; i < size1.height-1; i++, dptr += dstep - (size1.width-2)*3, mask += mstep*2 ) + { + for( j = 1; j < size1.width-1; j++, dptr += cn ) + { + int c0 = dptr[0], c1 = dptr[1], c2 = dptr[2]; + mask[j*2 - 1] = cdiff(-3) || cdiff(3) || cdiff(-dstep-3) || cdiff(-dstep) || + cdiff(-dstep+3) || cdiff(dstep-3) || cdiff(dstep) || cdiff(dstep+3); + } + } + + cv::dilate( m, m, cv::Mat() ); + mask = m.data; + } + + dptr = dst_pyramid[level].data; + dstep = (int)dst_pyramid[level].step; + + for( i = 0; i < size.height; i++, sptr += sstep - size.width*3, + dptr += dstep - size.width*3, + mask += mstep ) + { + for( j = 0; j < size.width; j++, sptr += 3, dptr += 3 ) + { + int x0 = j, y0 = i, x1, y1, iter; + int c0, c1, c2; + + if( mask && !mask[j] ) + continue; + + c0 = sptr[0], c1 = sptr[1], c2 = sptr[2]; + + // iterate meanshift procedure + for( iter = 0; iter < termcrit.max_iter; iter++ ) + { + uchar* ptr; + int x, y, count = 0; + int minx, miny, maxx, maxy; + int s0 = 0, s1 = 0, s2 = 0, sx = 0, sy = 0; + double icount; + int stop_flag; + + //mean shift: process pixels in window (p-sigmaSp)x(p+sigmaSp) + minx = cvRound(x0 - sp); minx = MAX(minx, 0); + miny = cvRound(y0 - sp); miny = MAX(miny, 0); + maxx = cvRound(x0 + sp); maxx = MIN(maxx, size.width-1); + maxy = cvRound(y0 + sp); maxy = MIN(maxy, size.height-1); + ptr = sptr + (miny - i)*sstep + (minx - j)*3; + + for( y = miny; y <= maxy; y++, ptr += sstep - (maxx-minx+1)*3 ) + { + int row_count = 0; + x = minx; + #if CV_ENABLE_UNROLLED + for( ; x + 3 <= maxx; x += 4, ptr += 12 ) + { + int t0 = ptr[0], t1 = ptr[1], t2 = ptr[2]; + if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 ) + { + s0 += t0; s1 += t1; s2 += t2; + sx += x; row_count++; + } + t0 = ptr[3], t1 = ptr[4], t2 = ptr[5]; + if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 ) + { + s0 += t0; s1 += t1; s2 += t2; + sx += x+1; row_count++; + } + t0 = ptr[6], t1 = ptr[7], t2 = ptr[8]; + if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 ) + { + s0 += t0; s1 += t1; s2 += t2; + sx += x+2; row_count++; + } + t0 = ptr[9], t1 = ptr[10], t2 = ptr[11]; + if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 ) + { + s0 += t0; s1 += t1; s2 += t2; + sx += x+3; row_count++; + } + } + #endif + for( ; x <= maxx; x++, ptr += 3 ) + { + int t0 = ptr[0], t1 = ptr[1], t2 = ptr[2]; + if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 ) + { + s0 += t0; s1 += t1; s2 += t2; + sx += x; row_count++; + } + } + count += row_count; + sy += y*row_count; + } + + if( count == 0 ) + break; + + icount = 1./count; + x1 = cvRound(sx*icount); + y1 = cvRound(sy*icount); + s0 = cvRound(s0*icount); + s1 = cvRound(s1*icount); + s2 = cvRound(s2*icount); + + stop_flag = (x0 == x1 && y0 == y1) || abs(x1-x0) + abs(y1-y0) + + tab[s0 - c0 + 255] + tab[s1 - c1 + 255] + + tab[s2 - c2 + 255] <= termcrit.epsilon; + + x0 = x1; y0 = y1; + c0 = s0; c1 = s1; c2 = s2; + + if( stop_flag ) + break; + } + + dptr[0] = (uchar)c0; + dptr[1] = (uchar)c1; + dptr[2] = (uchar)c2; + } + } + } +} + +void cv::pyrMeanShiftFiltering( InputArray _src, OutputArray _dst, + double sp, double sr, int maxLevel, + TermCriteria termcrit ) +{ + Mat src = _src.getMat(); + + if( src.empty() ) + return; + + _dst.create( src.size(), src.type() ); + CvMat c_src = src, c_dst = _dst.getMat(); + cvPyrMeanShiftFiltering( &c_src, &c_dst, sp, sr, maxLevel, termcrit ); +} diff --git a/imgproc/src/shapedescr.cpp b/imgproc/src/shapedescr.cpp new file mode 100644 index 0000000..9a27b9f --- /dev/null +++ b/imgproc/src/shapedescr.cpp @@ -0,0 +1,1186 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +/* calculates length of a curve (e.g. contour perimeter) */ +CV_IMPL double +cvArcLength( const void *array, CvSlice slice, int is_closed ) +{ + double perimeter = 0; + + int i, j = 0, count; + const int N = 16; + float buf[N]; + CvMat buffer = cvMat( 1, N, CV_32F, buf ); + CvSeqReader reader; + CvContour contour_header; + CvSeq* contour = 0; + CvSeqBlock block; + + if( CV_IS_SEQ( array )) + { + contour = (CvSeq*)array; + if( !CV_IS_SEQ_POLYLINE( contour )) + CV_Error( CV_StsBadArg, "Unsupported sequence type" ); + if( is_closed < 0 ) + is_closed = CV_IS_SEQ_CLOSED( contour ); + } + else + { + is_closed = is_closed > 0; + contour = cvPointSeqFromMat( + CV_SEQ_KIND_CURVE | (is_closed ? CV_SEQ_FLAG_CLOSED : 0), + array, &contour_header, &block ); + } + + if( contour->total > 1 ) + { + int is_float = CV_SEQ_ELTYPE( contour ) == CV_32FC2; + + cvStartReadSeq( contour, &reader, 0 ); + cvSetSeqReaderPos( &reader, slice.start_index ); + count = cvSliceLength( slice, contour ); + + count -= !is_closed && count == contour->total; + + /* scroll the reader by 1 point */ + reader.prev_elem = reader.ptr; + CV_NEXT_SEQ_ELEM( sizeof(CvPoint), reader ); + + for( i = 0; i < count; i++ ) + { + float dx, dy; + + if( !is_float ) + { + CvPoint* pt = (CvPoint*)reader.ptr; + CvPoint* prev_pt = (CvPoint*)reader.prev_elem; + + dx = (float)pt->x - (float)prev_pt->x; + dy = (float)pt->y - (float)prev_pt->y; + } + else + { + CvPoint2D32f* pt = (CvPoint2D32f*)reader.ptr; + CvPoint2D32f* prev_pt = (CvPoint2D32f*)reader.prev_elem; + + dx = pt->x - prev_pt->x; + dy = pt->y - prev_pt->y; + } + + reader.prev_elem = reader.ptr; + CV_NEXT_SEQ_ELEM( contour->elem_size, reader ); + // Bugfix by Axel at rubico.com 2010-03-22, affects closed slices only + // wraparound not handled by CV_NEXT_SEQ_ELEM + if( is_closed && i == count - 2 ) + cvSetSeqReaderPos( &reader, slice.start_index ); + + buffer.data.fl[j] = dx * dx + dy * dy; + if( ++j == N || i == count - 1 ) + { + buffer.cols = j; + cvPow( &buffer, &buffer, 0.5 ); + for( ; j > 0; j-- ) + perimeter += buffer.data.fl[j-1]; + } + } + } + + return perimeter; +} + + +static CvStatus +icvFindCircle( CvPoint2D32f pt0, CvPoint2D32f pt1, + CvPoint2D32f pt2, CvPoint2D32f * center, float *radius ) +{ + double x1 = (pt0.x + pt1.x) * 0.5; + double dy1 = pt0.x - pt1.x; + double x2 = (pt1.x + pt2.x) * 0.5; + double dy2 = pt1.x - pt2.x; + double y1 = (pt0.y + pt1.y) * 0.5; + double dx1 = pt1.y - pt0.y; + double y2 = (pt1.y + pt2.y) * 0.5; + double dx2 = pt2.y - pt1.y; + double t = 0; + + CvStatus result = CV_OK; + + if( icvIntersectLines( x1, dx1, y1, dy1, x2, dx2, y2, dy2, &t ) >= 0 ) + { + center->x = (float) (x2 + dx2 * t); + center->y = (float) (y2 + dy2 * t); + *radius = (float) icvDistanceL2_32f( *center, pt0 ); + } + else + { + center->x = center->y = 0.f; + radius = 0; + result = CV_NOTDEFINED_ERR; + } + + return result; +} + + +CV_INLINE double icvIsPtInCircle( CvPoint2D32f pt, CvPoint2D32f center, float radius ) +{ + double dx = pt.x - center.x; + double dy = pt.y - center.y; + return (double)radius*radius - dx*dx - dy*dy; +} + + +static int +icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float *_radius ) +{ + int shuffles[4][4] = { {0, 1, 2, 3}, {0, 1, 3, 2}, {2, 3, 0, 1}, {2, 3, 1, 0} }; + + int idxs[4] = { 0, 1, 2, 3 }; + int i, j, k = 1, mi = 0; + float max_dist = 0; + CvPoint2D32f center; + CvPoint2D32f min_center; + float radius, min_radius = FLT_MAX; + CvPoint2D32f res_pts[4]; + + center = min_center = pts[0]; + radius = 1.f; + + for( i = 0; i < 4; i++ ) + for( j = i + 1; j < 4; j++ ) + { + float dist = icvDistanceL2_32f( pts[i], pts[j] ); + + if( max_dist < dist ) + { + max_dist = dist; + idxs[0] = i; + idxs[1] = j; + } + } + + if( max_dist == 0 ) + goto function_exit; + + k = 2; + for( i = 0; i < 4; i++ ) + { + for( j = 0; j < k; j++ ) + if( i == idxs[j] ) + break; + if( j == k ) + idxs[k++] = i; + } + + center = cvPoint2D32f( (pts[idxs[0]].x + pts[idxs[1]].x)*0.5f, + (pts[idxs[0]].y + pts[idxs[1]].y)*0.5f ); + radius = (float)(icvDistanceL2_32f( pts[idxs[0]], center )*1.03); + if( radius < 1.f ) + radius = 1.f; + + if( icvIsPtInCircle( pts[idxs[2]], center, radius ) >= 0 && + icvIsPtInCircle( pts[idxs[3]], center, radius ) >= 0 ) + { + k = 2; //rand()%2+2; + } + else + { + mi = -1; + for( i = 0; i < 4; i++ ) + { + if( icvFindCircle( pts[shuffles[i][0]], pts[shuffles[i][1]], + pts[shuffles[i][2]], ¢er, &radius ) >= 0 ) + { + radius *= 1.03f; + if( radius < 2.f ) + radius = 2.f; + + if( icvIsPtInCircle( pts[shuffles[i][3]], center, radius ) >= 0 && + min_radius > radius ) + { + min_radius = radius; + min_center = center; + mi = i; + } + } + } + assert( mi >= 0 ); + if( mi < 0 ) + mi = 0; + k = 3; + center = min_center; + radius = min_radius; + for( i = 0; i < 4; i++ ) + idxs[i] = shuffles[mi][i]; + } + + function_exit: + + *_center = center; + *_radius = radius; + + /* reorder output points */ + for( i = 0; i < 4; i++ ) + res_pts[i] = pts[idxs[i]]; + + for( i = 0; i < 4; i++ ) + { + pts[i] = res_pts[i]; + assert( icvIsPtInCircle( pts[i], center, radius ) >= 0 ); + } + + return k; +} + + +CV_IMPL int +cvMinEnclosingCircle( const void* array, CvPoint2D32f * _center, float *_radius ) +{ + const int max_iters = 100; + const float eps = FLT_EPSILON*2; + CvPoint2D32f center = { 0, 0 }; + float radius = 0; + int result = 0; + + if( _center ) + _center->x = _center->y = 0.f; + if( _radius ) + *_radius = 0; + + CvSeqReader reader; + int k, count; + CvPoint2D32f pts[8]; + CvContour contour_header; + CvSeqBlock block; + CvSeq* sequence = 0; + int is_float; + + if( !_center || !_radius ) + CV_Error( CV_StsNullPtr, "Null center or radius pointers" ); + + if( CV_IS_SEQ(array) ) + { + sequence = (CvSeq*)array; + if( !CV_IS_SEQ_POINT_SET( sequence )) + CV_Error( CV_StsBadArg, "The passed sequence is not a valid contour" ); + } + else + { + sequence = cvPointSeqFromMat( + CV_SEQ_KIND_GENERIC, array, &contour_header, &block ); + } + + if( sequence->total <= 0 ) + CV_Error( CV_StsBadSize, "" ); + + cvStartReadSeq( sequence, &reader, 0 ); + + count = sequence->total; + is_float = CV_SEQ_ELTYPE(sequence) == CV_32FC2; + + if( !is_float ) + { + CvPoint *pt_left, *pt_right, *pt_top, *pt_bottom; + CvPoint pt; + pt_left = pt_right = pt_top = pt_bottom = (CvPoint *)(reader.ptr); + CV_READ_SEQ_ELEM( pt, reader ); + + for(int i = 1; i < count; i++ ) + { + CvPoint* pt_ptr = (CvPoint*)reader.ptr; + CV_READ_SEQ_ELEM( pt, reader ); + + if( pt.x < pt_left->x ) + pt_left = pt_ptr; + if( pt.x > pt_right->x ) + pt_right = pt_ptr; + if( pt.y < pt_top->y ) + pt_top = pt_ptr; + if( pt.y > pt_bottom->y ) + pt_bottom = pt_ptr; + } + + pts[0] = cvPointTo32f( *pt_left ); + pts[1] = cvPointTo32f( *pt_right ); + pts[2] = cvPointTo32f( *pt_top ); + pts[3] = cvPointTo32f( *pt_bottom ); + } + else + { + CvPoint2D32f *pt_left, *pt_right, *pt_top, *pt_bottom; + CvPoint2D32f pt; + pt_left = pt_right = pt_top = pt_bottom = (CvPoint2D32f *) (reader.ptr); + CV_READ_SEQ_ELEM( pt, reader ); + + for(int i = 1; i < count; i++ ) + { + CvPoint2D32f* pt_ptr = (CvPoint2D32f*)reader.ptr; + CV_READ_SEQ_ELEM( pt, reader ); + + if( pt.x < pt_left->x ) + pt_left = pt_ptr; + if( pt.x > pt_right->x ) + pt_right = pt_ptr; + if( pt.y < pt_top->y ) + pt_top = pt_ptr; + if( pt.y > pt_bottom->y ) + pt_bottom = pt_ptr; + } + + pts[0] = *pt_left; + pts[1] = *pt_right; + pts[2] = *pt_top; + pts[3] = *pt_bottom; + } + + for( k = 0; k < max_iters; k++ ) + { + double min_delta = 0, delta; + CvPoint2D32f ptfl, farAway = { 0, 0}; + /*only for first iteration because the alg is repared at the loop's foot*/ + if(k==0) + icvFindEnslosingCicle4pts_32f( pts, ¢er, &radius ); + + cvStartReadSeq( sequence, &reader, 0 ); + + for(int i = 0; i < count; i++ ) + { + if( !is_float ) + { + ptfl.x = (float)((CvPoint*)reader.ptr)->x; + ptfl.y = (float)((CvPoint*)reader.ptr)->y; + } + else + { + ptfl = *(CvPoint2D32f*)reader.ptr; + } + CV_NEXT_SEQ_ELEM( sequence->elem_size, reader ); + + delta = icvIsPtInCircle( ptfl, center, radius ); + if( delta < min_delta ) + { + min_delta = delta; + farAway = ptfl; + } + } + result = min_delta >= 0; + if( result ) + break; + + CvPoint2D32f ptsCopy[4]; + /* find good replacement partner for the point which is at most far away, + starting with the one that lays in the actual circle (i=3) */ + for(int i = 3; i >=0; i-- ) + { + for(int j = 0; j < 4; j++ ) + { + ptsCopy[j]=(i != j)? pts[j]: farAway; + } + + icvFindEnslosingCicle4pts_32f(ptsCopy, ¢er, &radius ); + if( icvIsPtInCircle( pts[i], center, radius )>=0){ // replaced one again in the new circle? + pts[i] = farAway; + break; + } + } + } + + if( !result ) + { + cvStartReadSeq( sequence, &reader, 0 ); + radius = 0.f; + + for(int i = 0; i < count; i++ ) + { + CvPoint2D32f ptfl; + float t, dx, dy; + + if( !is_float ) + { + ptfl.x = (float)((CvPoint*)reader.ptr)->x; + ptfl.y = (float)((CvPoint*)reader.ptr)->y; + } + else + { + ptfl = *(CvPoint2D32f*)reader.ptr; + } + + CV_NEXT_SEQ_ELEM( sequence->elem_size, reader ); + dx = center.x - ptfl.x; + dy = center.y - ptfl.y; + t = dx*dx + dy*dy; + radius = MAX(radius,t); + } + + radius = (float)(sqrt(radius)*(1 + eps)); + result = 1; + } + + *_center = center; + *_radius = radius; + + return result; +} + + +/* area of a whole sequence */ +static CvStatus +icvContourArea( const CvSeq* contour, double *area ) +{ + if( contour->total ) + { + CvSeqReader reader; + int lpt = contour->total; + double a00 = 0, xi_1, yi_1; + int is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2; + + cvStartReadSeq( contour, &reader, 0 ); + + if( !is_float ) + { + xi_1 = ((CvPoint*)(reader.ptr))->x; + yi_1 = ((CvPoint*)(reader.ptr))->y; + } + else + { + xi_1 = ((CvPoint2D32f*)(reader.ptr))->x; + yi_1 = ((CvPoint2D32f*)(reader.ptr))->y; + } + CV_NEXT_SEQ_ELEM( contour->elem_size, reader ); + + while( lpt-- > 0 ) + { + double dxy, xi, yi; + + if( !is_float ) + { + xi = ((CvPoint*)(reader.ptr))->x; + yi = ((CvPoint*)(reader.ptr))->y; + } + else + { + xi = ((CvPoint2D32f*)(reader.ptr))->x; + yi = ((CvPoint2D32f*)(reader.ptr))->y; + } + CV_NEXT_SEQ_ELEM( contour->elem_size, reader ); + + dxy = xi_1 * yi - xi * yi_1; + a00 += dxy; + xi_1 = xi; + yi_1 = yi; + } + + *area = a00 * 0.5; + } + else + *area = 0; + + return CV_OK; +} + + +/****************************************************************************************\ + + copy data from one buffer to other buffer + +\****************************************************************************************/ + +static CvStatus +icvMemCopy( double **buf1, double **buf2, double **buf3, int *b_max ) +{ + int bb; + + if( (*buf1 == NULL && *buf2 == NULL) || *buf3 == NULL ) + return CV_NULLPTR_ERR; + + bb = *b_max; + if( *buf2 == NULL ) + { + *b_max = 2 * (*b_max); + *buf2 = (double *)cvAlloc( (*b_max) * sizeof( double )); + + if( *buf2 == NULL ) + return CV_OUTOFMEM_ERR; + + memcpy( *buf2, *buf3, bb * sizeof( double )); + + *buf3 = *buf2; + cvFree( buf1 ); + *buf1 = NULL; + } + else + { + *b_max = 2 * (*b_max); + *buf1 = (double *) cvAlloc( (*b_max) * sizeof( double )); + + if( *buf1 == NULL ) + return CV_OUTOFMEM_ERR; + + memcpy( *buf1, *buf3, bb * sizeof( double )); + + *buf3 = *buf1; + cvFree( buf2 ); + *buf2 = NULL; + } + return CV_OK; +} + + +/* area of a contour sector */ +static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area ) +{ + CvPoint pt; /* pointer to points */ + CvPoint pt_s, pt_e; /* first and last points */ + CvSeqReader reader; /* points reader of contour */ + + int p_max = 2, p_ind; + int lpt, flag, i; + double a00; /* unnormalized moments m00 */ + double xi, yi, xi_1, yi_1, x0, y0, dxy, sk, sk1, t; + double x_s, y_s, nx, ny, dx, dy, du, dv; + double eps = 1.e-5; + double *p_are1, *p_are2, *p_are; + + assert( contour != NULL ); + + if( contour == NULL ) + return CV_NULLPTR_ERR; + + if( !CV_IS_SEQ_POINT_SET( contour )) + return CV_BADFLAG_ERR; + + lpt = cvSliceLength( slice, contour ); + /*if( n2 >= n1 ) + lpt = n2 - n1 + 1; + else + lpt = contour->total - n1 + n2 + 1;*/ + + if( contour->total && lpt > 2 ) + { + a00 = x0 = y0 = xi_1 = yi_1 = 0; + sk1 = 0; + flag = 0; + dxy = 0; + p_are1 = (double *) cvAlloc( p_max * sizeof( double )); + + if( p_are1 == NULL ) + return CV_OUTOFMEM_ERR; + + p_are = p_are1; + p_are2 = NULL; + + cvStartReadSeq( contour, &reader, 0 ); + cvSetSeqReaderPos( &reader, slice.start_index ); + CV_READ_SEQ_ELEM( pt_s, reader ); + p_ind = 0; + cvSetSeqReaderPos( &reader, slice.end_index ); + CV_READ_SEQ_ELEM( pt_e, reader ); + +/* normal coefficients */ + nx = pt_s.y - pt_e.y; + ny = pt_e.x - pt_s.x; + cvSetSeqReaderPos( &reader, slice.start_index ); + + while( lpt-- > 0 ) + { + CV_READ_SEQ_ELEM( pt, reader ); + + if( flag == 0 ) + { + xi_1 = (double) pt.x; + yi_1 = (double) pt.y; + x0 = xi_1; + y0 = yi_1; + sk1 = 0; + flag = 1; + } + else + { + xi = (double) pt.x; + yi = (double) pt.y; + +/**************** edges intersection examination **************************/ + sk = nx * (xi - pt_s.x) + ny * (yi - pt_s.y); + if( (fabs( sk ) < eps && lpt > 0) || sk * sk1 < -eps ) + { + if( fabs( sk ) < eps ) + { + dxy = xi_1 * yi - xi * yi_1; + a00 = a00 + dxy; + dxy = xi * y0 - x0 * yi; + a00 = a00 + dxy; + + if( p_ind >= p_max ) + icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); + + p_are[p_ind] = a00 / 2.; + p_ind++; + a00 = 0; + sk1 = 0; + x0 = xi; + y0 = yi; + dxy = 0; + } + else + { +/* define intersection point */ + dv = yi - yi_1; + du = xi - xi_1; + dx = ny; + dy = -nx; + if( fabs( du ) > eps ) + t = ((yi_1 - pt_s.y) * du + dv * (pt_s.x - xi_1)) / + (du * dy - dx * dv); + else + t = (xi_1 - pt_s.x) / dx; + if( t > eps && t < 1 - eps ) + { + x_s = pt_s.x + t * dx; + y_s = pt_s.y + t * dy; + dxy = xi_1 * y_s - x_s * yi_1; + a00 += dxy; + dxy = x_s * y0 - x0 * y_s; + a00 += dxy; + if( p_ind >= p_max ) + icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); + + p_are[p_ind] = a00 / 2.; + p_ind++; + + a00 = 0; + sk1 = 0; + x0 = x_s; + y0 = y_s; + dxy = x_s * yi - xi * y_s; + } + } + } + else + dxy = xi_1 * yi - xi * yi_1; + + a00 += dxy; + xi_1 = xi; + yi_1 = yi; + sk1 = sk; + + } + } + + xi = x0; + yi = y0; + dxy = xi_1 * yi - xi * yi_1; + + a00 += dxy; + + if( p_ind >= p_max ) + icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); + + p_are[p_ind] = a00 / 2.; + p_ind++; + +/* common area calculation */ + *area = 0; + for( i = 0; i < p_ind; i++ ) + (*area) += fabs( p_are[i] ); + + if( p_are1 != NULL ) + cvFree( &p_are1 ); + else if( p_are2 != NULL ) + cvFree( &p_are2 ); + + return CV_OK; + } + else + return CV_BADSIZE_ERR; +} + + +/* external contour area function */ +CV_IMPL double +cvContourArea( const void *array, CvSlice slice, int oriented ) +{ + double area = 0; + + CvContour contour_header; + CvSeq* contour = 0; + CvSeqBlock block; + + if( CV_IS_SEQ( array )) + { + contour = (CvSeq*)array; + if( !CV_IS_SEQ_POLYLINE( contour )) + CV_Error( CV_StsBadArg, "Unsupported sequence type" ); + } + else + { + contour = cvPointSeqFromMat( CV_SEQ_KIND_CURVE, array, &contour_header, &block ); + } + + if( cvSliceLength( slice, contour ) == contour->total ) + { + IPPI_CALL( icvContourArea( contour, &area )); + } + else + { + if( CV_SEQ_ELTYPE( contour ) != CV_32SC2 ) + CV_Error( CV_StsUnsupportedFormat, + "Only curves with integer coordinates are supported in case of contour slice" ); + IPPI_CALL( icvContourSecArea( contour, slice, &area )); + } + + return oriented ? area : fabs(area); +} + + +CV_IMPL CvBox2D +cvFitEllipse2( const CvArr* array ) +{ + CvBox2D box; + cv::AutoBuffer Ad, bd; + memset( &box, 0, sizeof(box)); + + CvContour contour_header; + CvSeq* ptseq = 0; + CvSeqBlock block; + int n; + + if( CV_IS_SEQ( array )) + { + ptseq = (CvSeq*)array; + if( !CV_IS_SEQ_POINT_SET( ptseq )) + CV_Error( CV_StsBadArg, "Unsupported sequence type" ); + } + else + { + ptseq = cvPointSeqFromMat(CV_SEQ_KIND_GENERIC, array, &contour_header, &block); + } + + n = ptseq->total; + if( n < 5 ) + CV_Error( CV_StsBadSize, "Number of points should be >= 5" ); + + /* + * New fitellipse algorithm, contributed by Dr. Daniel Weiss + */ + CvPoint2D32f c = {0,0}; + double gfp[5], rp[5], t; + CvMat A, b, x; + const double min_eps = 1e-6; + int i, is_float; + CvSeqReader reader; + + Ad.allocate(n*5); + bd.allocate(n); + + // first fit for parameters A - E + A = cvMat( n, 5, CV_64F, Ad ); + b = cvMat( n, 1, CV_64F, bd ); + x = cvMat( 5, 1, CV_64F, gfp ); + + cvStartReadSeq( ptseq, &reader ); + is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2; + + for( i = 0; i < n; i++ ) + { + CvPoint2D32f p; + if( is_float ) + p = *(CvPoint2D32f*)(reader.ptr); + else + { + p.x = (float)((int*)reader.ptr)[0]; + p.y = (float)((int*)reader.ptr)[1]; + } + CV_NEXT_SEQ_ELEM( sizeof(p), reader ); + c.x += p.x; + c.y += p.y; + } + c.x /= n; + c.y /= n; + + for( i = 0; i < n; i++ ) + { + CvPoint2D32f p; + if( is_float ) + p = *(CvPoint2D32f*)(reader.ptr); + else + { + p.x = (float)((int*)reader.ptr)[0]; + p.y = (float)((int*)reader.ptr)[1]; + } + CV_NEXT_SEQ_ELEM( sizeof(p), reader ); + p.x -= c.x; + p.y -= c.y; + + bd[i] = 10000.0; // 1.0? + Ad[i*5] = -(double)p.x * p.x; // A - C signs inverted as proposed by APP + Ad[i*5 + 1] = -(double)p.y * p.y; + Ad[i*5 + 2] = -(double)p.x * p.y; + Ad[i*5 + 3] = p.x; + Ad[i*5 + 4] = p.y; + } + + cvSolve( &A, &b, &x, CV_SVD ); + + // now use general-form parameters A - E to find the ellipse center: + // differentiate general form wrt x/y to get two equations for cx and cy + A = cvMat( 2, 2, CV_64F, Ad ); + b = cvMat( 2, 1, CV_64F, bd ); + x = cvMat( 2, 1, CV_64F, rp ); + Ad[0] = 2 * gfp[0]; + Ad[1] = Ad[2] = gfp[2]; + Ad[3] = 2 * gfp[1]; + bd[0] = gfp[3]; + bd[1] = gfp[4]; + cvSolve( &A, &b, &x, CV_SVD ); + + // re-fit for parameters A - C with those center coordinates + A = cvMat( n, 3, CV_64F, Ad ); + b = cvMat( n, 1, CV_64F, bd ); + x = cvMat( 3, 1, CV_64F, gfp ); + for( i = 0; i < n; i++ ) + { + CvPoint2D32f p; + if( is_float ) + p = *(CvPoint2D32f*)(reader.ptr); + else + { + p.x = (float)((int*)reader.ptr)[0]; + p.y = (float)((int*)reader.ptr)[1]; + } + CV_NEXT_SEQ_ELEM( sizeof(p), reader ); + p.x -= c.x; + p.y -= c.y; + bd[i] = 1.0; + Ad[i * 3] = (p.x - rp[0]) * (p.x - rp[0]); + Ad[i * 3 + 1] = (p.y - rp[1]) * (p.y - rp[1]); + Ad[i * 3 + 2] = (p.x - rp[0]) * (p.y - rp[1]); + } + cvSolve(&A, &b, &x, CV_SVD); + + // store angle and radii + rp[4] = -0.5 * atan2(gfp[2], gfp[1] - gfp[0]); // convert from APP angle usage + t = sin(-2.0 * rp[4]); + if( fabs(t) > fabs(gfp[2])*min_eps ) + t = gfp[2]/t; + else + t = gfp[1] - gfp[0]; + rp[2] = fabs(gfp[0] + gfp[1] - t); + if( rp[2] > min_eps ) + rp[2] = sqrt(2.0 / rp[2]); + rp[3] = fabs(gfp[0] + gfp[1] + t); + if( rp[3] > min_eps ) + rp[3] = sqrt(2.0 / rp[3]); + + box.center.x = (float)rp[0] + c.x; + box.center.y = (float)rp[1] + c.y; + box.size.width = (float)(rp[2]*2); + box.size.height = (float)(rp[3]*2); + if( box.size.width > box.size.height ) + { + float tmp; + CV_SWAP( box.size.width, box.size.height, tmp ); + box.angle = (float)(90 + rp[4]*180/CV_PI); + } + if( box.angle < -180 ) + box.angle += 360; + if( box.angle > 360 ) + box.angle -= 360; + + return box; +} + + +/* Calculates bounding rectagnle of a point set or retrieves already calculated */ +CV_IMPL CvRect +cvBoundingRect( CvArr* array, int update ) +{ + CvSeqReader reader; + CvRect rect = { 0, 0, 0, 0 }; + CvContour contour_header; + CvSeq* ptseq = 0; + CvSeqBlock block; + + CvMat stub, *mat = 0; + int xmin = 0, ymin = 0, xmax = -1, ymax = -1, i, j, k; + int calculate = update; + + if( CV_IS_SEQ( array )) + { + ptseq = (CvSeq*)array; + if( !CV_IS_SEQ_POINT_SET( ptseq )) + CV_Error( CV_StsBadArg, "Unsupported sequence type" ); + + if( ptseq->header_size < (int)sizeof(CvContour)) + { + update = 0; + calculate = 1; + } + } + else + { + mat = cvGetMat( array, &stub ); + if( CV_MAT_TYPE(mat->type) == CV_32SC2 || + CV_MAT_TYPE(mat->type) == CV_32FC2 ) + { + ptseq = cvPointSeqFromMat(CV_SEQ_KIND_GENERIC, mat, &contour_header, &block); + mat = 0; + } + else if( CV_MAT_TYPE(mat->type) != CV_8UC1 && + CV_MAT_TYPE(mat->type) != CV_8SC1 ) + CV_Error( CV_StsUnsupportedFormat, + "The image/matrix format is not supported by the function" ); + update = 0; + calculate = 1; + } + + if( !calculate ) + return ((CvContour*)ptseq)->rect; + + if( mat ) + { + CvSize size = cvGetMatSize(mat); + xmin = size.width; + ymin = -1; + + for( i = 0; i < size.height; i++ ) + { + uchar* _ptr = mat->data.ptr + i*mat->step; + uchar* ptr = (uchar*)cvAlignPtr(_ptr, 4); + int have_nz = 0, k_min, offset = (int)(ptr - _ptr); + j = 0; + offset = MIN(offset, size.width); + for( ; j < offset; j++ ) + if( _ptr[j] ) + { + have_nz = 1; + break; + } + if( j < offset ) + { + if( j < xmin ) + xmin = j; + if( j > xmax ) + xmax = j; + } + if( offset < size.width ) + { + xmin -= offset; + xmax -= offset; + size.width -= offset; + j = 0; + for( ; j <= xmin - 4; j += 4 ) + if( *((int*)(ptr+j)) ) + break; + for( ; j < xmin; j++ ) + if( ptr[j] ) + { + xmin = j; + if( j > xmax ) + xmax = j; + have_nz = 1; + break; + } + k_min = MAX(j-1, xmax); + k = size.width - 1; + for( ; k > k_min && (k&3) != 3; k-- ) + if( ptr[k] ) + break; + if( k > k_min && (k&3) == 3 ) + { + for( ; k > k_min+3; k -= 4 ) + if( *((int*)(ptr+k-3)) ) + break; + } + for( ; k > k_min; k-- ) + if( ptr[k] ) + { + xmax = k; + have_nz = 1; + break; + } + if( !have_nz ) + { + j &= ~3; + for( ; j <= k - 3; j += 4 ) + if( *((int*)(ptr+j)) ) + break; + for( ; j <= k; j++ ) + if( ptr[j] ) + { + have_nz = 1; + break; + } + } + xmin += offset; + xmax += offset; + size.width += offset; + } + if( have_nz ) + { + if( ymin < 0 ) + ymin = i; + ymax = i; + } + } + + if( xmin >= size.width ) + xmin = ymin = 0; + } + else if( ptseq->total ) + { + int is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2; + cvStartReadSeq( ptseq, &reader, 0 ); + CvPoint pt; + CV_READ_SEQ_ELEM( pt, reader ); + #if CV_SSE4_2 + if(cv::checkHardwareSupport(CV_CPU_SSE4_2)) + { + if( !is_float ) + { + __m128i minval, maxval; + minval = maxval = _mm_loadl_epi64((const __m128i*)(&pt)); //min[0]=pt.x, min[1]=pt.y + + for( i = 1; i < ptseq->total; i++) + { + __m128i ptXY = _mm_loadl_epi64((const __m128i*)(reader.ptr)); + CV_NEXT_SEQ_ELEM(sizeof(pt), reader); + minval = _mm_min_epi32(ptXY, minval); + maxval = _mm_max_epi32(ptXY, maxval); + } + xmin = _mm_cvtsi128_si32(minval); + ymin = _mm_cvtsi128_si32(_mm_srli_si128(minval, 4)); + xmax = _mm_cvtsi128_si32(maxval); + ymax = _mm_cvtsi128_si32(_mm_srli_si128(maxval, 4)); + } + else + { + __m128 minvalf, maxvalf, z = _mm_setzero_ps(), ptXY = _mm_setzero_ps(); + minvalf = maxvalf = _mm_loadl_pi(z, (const __m64*)(&pt)); + + for( i = 1; i < ptseq->total; i++ ) + { + ptXY = _mm_loadl_pi(ptXY, (const __m64*)reader.ptr); + CV_NEXT_SEQ_ELEM(sizeof(pt), reader); + + minvalf = _mm_min_ps(minvalf, ptXY); + maxvalf = _mm_max_ps(maxvalf, ptXY); + } + + float xyminf[2], xymaxf[2]; + _mm_storel_pi((__m64*)xyminf, minvalf); + _mm_storel_pi((__m64*)xymaxf, maxvalf); + xmin = cvFloor(xyminf[0]); + ymin = cvFloor(xyminf[1]); + xmax = cvFloor(xymaxf[0]); + ymax = cvFloor(xymaxf[1]); + } + } + else + #endif + { + if( !is_float ) + { + xmin = xmax = pt.x; + ymin = ymax = pt.y; + + for( i = 1; i < ptseq->total; i++ ) + { + CV_READ_SEQ_ELEM( pt, reader ); + + if( xmin > pt.x ) + xmin = pt.x; + + if( xmax < pt.x ) + xmax = pt.x; + + if( ymin > pt.y ) + ymin = pt.y; + + if( ymax < pt.y ) + ymax = pt.y; + } + } + else + { + Cv32suf v; + // init values + xmin = xmax = CV_TOGGLE_FLT(pt.x); + ymin = ymax = CV_TOGGLE_FLT(pt.y); + + for( i = 1; i < ptseq->total; i++ ) + { + CV_READ_SEQ_ELEM( pt, reader ); + pt.x = CV_TOGGLE_FLT(pt.x); + pt.y = CV_TOGGLE_FLT(pt.y); + + if( xmin > pt.x ) + xmin = pt.x; + + if( xmax < pt.x ) + xmax = pt.x; + + if( ymin > pt.y ) + ymin = pt.y; + + if( ymax < pt.y ) + ymax = pt.y; + } + + v.i = CV_TOGGLE_FLT(xmin); xmin = cvFloor(v.f); + v.i = CV_TOGGLE_FLT(ymin); ymin = cvFloor(v.f); + // because right and bottom sides of the bounding rectangle are not inclusive + // (note +1 in width and height calculation below), cvFloor is used here instead of cvCeil + v.i = CV_TOGGLE_FLT(xmax); xmax = cvFloor(v.f); + v.i = CV_TOGGLE_FLT(ymax); ymax = cvFloor(v.f); + } + } + rect.x = xmin; + rect.y = ymin; + rect.width = xmax - xmin + 1; + rect.height = ymax - ymin + 1; + } + if( update ) + ((CvContour*)ptseq)->rect = rect; + return rect; +} + +/* End of file. */ diff --git a/imgproc/src/smooth.cpp b/imgproc/src/smooth.cpp new file mode 100644 index 0000000..7b3fd6e --- /dev/null +++ b/imgproc/src/smooth.cpp @@ -0,0 +1,1828 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +/* + * This file includes the code, contributed by Simon Perreault + * (the function icvMedianBlur_8u_O1) + * + * Constant-time median filtering -- http://nomis80.org/ctmf.html + * Copyright (C) 2006 Simon Perreault + * + * Contact: + * Laboratoire de vision et systemes numeriques + * Pavillon Adrien-Pouliot + * Universite Laval + * Sainte-Foy, Quebec, Canada + * G1K 7P4 + * + * perreaul@gel.ulaval.ca + */ + +namespace cv +{ + +/****************************************************************************************\ + Box Filter +\****************************************************************************************/ + +template struct RowSum : public BaseRowFilter +{ + RowSum( int _ksize, int _anchor ) + { + ksize = _ksize; + anchor = _anchor; + } + + void operator()(const uchar* src, uchar* dst, int width, int cn) + { + const T* S = (const T*)src; + ST* D = (ST*)dst; + int i = 0, k, ksz_cn = ksize*cn; + + width = (width - 1)*cn; + for( k = 0; k < cn; k++, S++, D++ ) + { + ST s = 0; + for( i = 0; i < ksz_cn; i += cn ) + s += S[i]; + D[0] = s; + for( i = 0; i < width; i += cn ) + { + s += S[i + ksz_cn] - S[i]; + D[i+cn] = s; + } + } + } +}; + + +template struct ColumnSum : public BaseColumnFilter +{ + ColumnSum( int _ksize, int _anchor, double _scale ) + { + ksize = _ksize; + anchor = _anchor; + scale = _scale; + sumCount = 0; + } + + void reset() { sumCount = 0; } + + void operator()(const uchar** src, uchar* dst, int dststep, int count, int width) + { + int i; + ST* SUM; + bool haveScale = scale != 1; + double _scale = scale; + + if( width != (int)sum.size() ) + { + sum.resize(width); + sumCount = 0; + } + + SUM = &sum[0]; + if( sumCount == 0 ) + { + for( i = 0; i < width; i++ ) + SUM[i] = 0; + for( ; sumCount < ksize - 1; sumCount++, src++ ) + { + const ST* Sp = (const ST*)src[0]; + for( i = 0; i <= width - 2; i += 2 ) + { + ST s0 = SUM[i] + Sp[i], s1 = SUM[i+1] + Sp[i+1]; + SUM[i] = s0; SUM[i+1] = s1; + } + + for( ; i < width; i++ ) + SUM[i] += Sp[i]; + } + } + else + { + CV_Assert( sumCount == ksize-1 ); + src += ksize-1; + } + + for( ; count--; src++ ) + { + const ST* Sp = (const ST*)src[0]; + const ST* Sm = (const ST*)src[1-ksize]; + T* D = (T*)dst; + if( haveScale ) + { + for( i = 0; i <= width - 2; i += 2 ) + { + ST s0 = SUM[i] + Sp[i], s1 = SUM[i+1] + Sp[i+1]; + D[i] = saturate_cast(s0*_scale); + D[i+1] = saturate_cast(s1*_scale); + s0 -= Sm[i]; s1 -= Sm[i+1]; + SUM[i] = s0; SUM[i+1] = s1; + } + + for( ; i < width; i++ ) + { + ST s0 = SUM[i] + Sp[i]; + D[i] = saturate_cast(s0*_scale); + SUM[i] = s0 - Sm[i]; + } + } + else + { + for( i = 0; i <= width - 2; i += 2 ) + { + ST s0 = SUM[i] + Sp[i], s1 = SUM[i+1] + Sp[i+1]; + D[i] = saturate_cast(s0); + D[i+1] = saturate_cast(s1); + s0 -= Sm[i]; s1 -= Sm[i+1]; + SUM[i] = s0; SUM[i+1] = s1; + } + + for( ; i < width; i++ ) + { + ST s0 = SUM[i] + Sp[i]; + D[i] = saturate_cast(s0); + SUM[i] = s0 - Sm[i]; + } + } + dst += dststep; + } + } + + double scale; + int sumCount; + vector sum; +}; + + +} + +cv::Ptr cv::getRowSumFilter(int srcType, int sumType, int ksize, int anchor) +{ + int sdepth = CV_MAT_DEPTH(srcType), ddepth = CV_MAT_DEPTH(sumType); + CV_Assert( CV_MAT_CN(sumType) == CV_MAT_CN(srcType) ); + + if( anchor < 0 ) + anchor = ksize/2; + + if( sdepth == CV_8U && ddepth == CV_32S ) + return Ptr(new RowSum(ksize, anchor)); + if( sdepth == CV_8U && ddepth == CV_64F ) + return Ptr(new RowSum(ksize, anchor)); + if( sdepth == CV_16U && ddepth == CV_32S ) + return Ptr(new RowSum(ksize, anchor)); + if( sdepth == CV_16U && ddepth == CV_64F ) + return Ptr(new RowSum(ksize, anchor)); + if( sdepth == CV_16S && ddepth == CV_32S ) + return Ptr(new RowSum(ksize, anchor)); + if( sdepth == CV_32S && ddepth == CV_32S ) + return Ptr(new RowSum(ksize, anchor)); + if( sdepth == CV_16S && ddepth == CV_64F ) + return Ptr(new RowSum(ksize, anchor)); + if( sdepth == CV_32F && ddepth == CV_64F ) + return Ptr(new RowSum(ksize, anchor)); + if( sdepth == CV_64F && ddepth == CV_64F ) + return Ptr(new RowSum(ksize, anchor)); + + CV_Error_( CV_StsNotImplemented, + ("Unsupported combination of source format (=%d), and buffer format (=%d)", + srcType, sumType)); + + return Ptr(0); +} + + +cv::Ptr cv::getColumnSumFilter(int sumType, int dstType, int ksize, + int anchor, double scale) +{ + int sdepth = CV_MAT_DEPTH(sumType), ddepth = CV_MAT_DEPTH(dstType); + CV_Assert( CV_MAT_CN(sumType) == CV_MAT_CN(dstType) ); + + if( anchor < 0 ) + anchor = ksize/2; + + if( ddepth == CV_8U && sdepth == CV_32S ) + return Ptr(new ColumnSum(ksize, anchor, scale)); + if( ddepth == CV_8U && sdepth == CV_64F ) + return Ptr(new ColumnSum(ksize, anchor, scale)); + if( ddepth == CV_16U && sdepth == CV_32S ) + return Ptr(new ColumnSum(ksize, anchor, scale)); + if( ddepth == CV_16U && sdepth == CV_64F ) + return Ptr(new ColumnSum(ksize, anchor, scale)); + if( ddepth == CV_16S && sdepth == CV_32S ) + return Ptr(new ColumnSum(ksize, anchor, scale)); + if( ddepth == CV_16S && sdepth == CV_64F ) + return Ptr(new ColumnSum(ksize, anchor, scale)); + if( ddepth == CV_32S && sdepth == CV_32S ) + return Ptr(new ColumnSum(ksize, anchor, scale)); + if( ddepth == CV_32F && sdepth == CV_32S ) + return Ptr(new ColumnSum(ksize, anchor, scale)); + if( ddepth == CV_32F && sdepth == CV_64F ) + return Ptr(new ColumnSum(ksize, anchor, scale)); + if( ddepth == CV_64F && sdepth == CV_32S ) + return Ptr(new ColumnSum(ksize, anchor, scale)); + if( ddepth == CV_64F && sdepth == CV_64F ) + return Ptr(new ColumnSum(ksize, anchor, scale)); + + CV_Error_( CV_StsNotImplemented, + ("Unsupported combination of sum format (=%d), and destination format (=%d)", + sumType, dstType)); + + return Ptr(0); +} + + +cv::Ptr cv::createBoxFilter( int srcType, int dstType, Size ksize, + Point anchor, bool normalize, int borderType ) +{ + int sdepth = CV_MAT_DEPTH(srcType); + int cn = CV_MAT_CN(srcType), sumType = CV_64F; + if( sdepth <= CV_32S && (!normalize || + ksize.width*ksize.height <= (sdepth == CV_8U ? (1<<23) : + sdepth == CV_16U ? (1 << 15) : (1 << 16))) ) + sumType = CV_32S; + sumType = CV_MAKETYPE( sumType, cn ); + + Ptr rowFilter = getRowSumFilter(srcType, sumType, ksize.width, anchor.x ); + Ptr columnFilter = getColumnSumFilter(sumType, + dstType, ksize.height, anchor.y, normalize ? 1./(ksize.width*ksize.height) : 1); + + return Ptr(new FilterEngine(Ptr(0), rowFilter, columnFilter, + srcType, dstType, sumType, borderType )); +} + + +void cv::boxFilter( InputArray _src, OutputArray _dst, int ddepth, + Size ksize, Point anchor, + bool normalize, int borderType ) +{ + Mat src = _src.getMat(); + int sdepth = src.depth(), cn = src.channels(); + if( ddepth < 0 ) + ddepth = sdepth; + _dst.create( src.size(), CV_MAKETYPE(ddepth, cn) ); + Mat dst = _dst.getMat(); + if( borderType != BORDER_CONSTANT && normalize ) + { + if( src.rows == 1 ) + ksize.height = 1; + if( src.cols == 1 ) + ksize.width = 1; + } +#ifdef HAVE_TEGRA_OPTIMIZATION + if ( tegra::box(src, dst, ksize, anchor, normalize, borderType) ) + return; +#endif + + Ptr f = createBoxFilter( src.type(), dst.type(), + ksize, anchor, normalize, borderType ); + f->apply( src, dst ); +} + +void cv::blur( InputArray src, OutputArray dst, + Size ksize, Point anchor, int borderType ) +{ + boxFilter( src, dst, -1, ksize, anchor, true, borderType ); +} + +/****************************************************************************************\ + Gaussian Blur +\****************************************************************************************/ + +cv::Mat cv::getGaussianKernel( int n, double sigma, int ktype ) +{ + const int SMALL_GAUSSIAN_SIZE = 7; + static const float small_gaussian_tab[][SMALL_GAUSSIAN_SIZE] = + { + {1.f}, + {0.25f, 0.5f, 0.25f}, + {0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f}, + {0.03125f, 0.109375f, 0.21875f, 0.28125f, 0.21875f, 0.109375f, 0.03125f} + }; + + const float* fixed_kernel = n % 2 == 1 && n <= SMALL_GAUSSIAN_SIZE && sigma <= 0 ? + small_gaussian_tab[n>>1] : 0; + + CV_Assert( ktype == CV_32F || ktype == CV_64F ); + Mat kernel(n, 1, ktype); + float* cf = (float*)kernel.data; + double* cd = (double*)kernel.data; + + double sigmaX = sigma > 0 ? sigma : ((n-1)*0.5 - 1)*0.3 + 0.8; + double scale2X = -0.5/(sigmaX*sigmaX); + double sum = 0; + + int i; + for( i = 0; i < n; i++ ) + { + double x = i - (n-1)*0.5; + double t = fixed_kernel ? (double)fixed_kernel[i] : std::exp(scale2X*x*x); + if( ktype == CV_32F ) + { + cf[i] = (float)t; + sum += cf[i]; + } + else + { + cd[i] = t; + sum += cd[i]; + } + } + + sum = 1./sum; + for( i = 0; i < n; i++ ) + { + if( ktype == CV_32F ) + cf[i] = (float)(cf[i]*sum); + else + cd[i] *= sum; + } + + return kernel; +} + + +cv::Ptr cv::createGaussianFilter( int type, Size ksize, + double sigma1, double sigma2, + int borderType ) +{ + int depth = CV_MAT_DEPTH(type); + if( sigma2 <= 0 ) + sigma2 = sigma1; + + // automatic detection of kernel size from sigma + if( ksize.width <= 0 && sigma1 > 0 ) + ksize.width = cvRound(sigma1*(depth == CV_8U ? 3 : 4)*2 + 1)|1; + if( ksize.height <= 0 && sigma2 > 0 ) + ksize.height = cvRound(sigma2*(depth == CV_8U ? 3 : 4)*2 + 1)|1; + + CV_Assert( ksize.width > 0 && ksize.width % 2 == 1 && + ksize.height > 0 && ksize.height % 2 == 1 ); + + sigma1 = std::max( sigma1, 0. ); + sigma2 = std::max( sigma2, 0. ); + + Mat kx = getGaussianKernel( ksize.width, sigma1, std::max(depth, CV_32F) ); + Mat ky; + if( ksize.height == ksize.width && std::abs(sigma1 - sigma2) < DBL_EPSILON ) + ky = kx; + else + ky = getGaussianKernel( ksize.height, sigma2, std::max(depth, CV_32F) ); + + return createSeparableLinearFilter( type, type, kx, ky, Point(-1,-1), 0, borderType ); +} + + +void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize, + double sigma1, double sigma2, + int borderType ) +{ + Mat src = _src.getMat(); + _dst.create( src.size(), src.type() ); + Mat dst = _dst.getMat(); + + if( borderType != BORDER_CONSTANT ) + { + if( src.rows == 1 ) + ksize.height = 1; + if( src.cols == 1 ) + ksize.width = 1; + } + + if( ksize.width == 1 && ksize.height == 1 ) + { + src.copyTo(dst); + return; + } + +#ifdef HAVE_TEGRA_OPTIMIZATION + if(sigma1 == 0 && sigma2 == 0 && tegra::gaussian(src, dst, ksize, borderType)) + return; +#endif + + Ptr f = createGaussianFilter( src.type(), ksize, sigma1, sigma2, borderType ); + f->apply( src, dst ); +} + + +/****************************************************************************************\ + Median Filter +\****************************************************************************************/ + +namespace cv +{ +typedef ushort HT; + +/** + * This structure represents a two-tier histogram. The first tier (known as the + * "coarse" level) is 4 bit wide and the second tier (known as the "fine" level) + * is 8 bit wide. Pixels inserted in the fine level also get inserted into the + * coarse bucket designated by the 4 MSBs of the fine bucket value. + * + * The structure is aligned on 16 bits, which is a prerequisite for SIMD + * instructions. Each bucket is 16 bit wide, which means that extra care must be + * taken to prevent overflow. + */ +typedef struct +{ + HT coarse[16]; + HT fine[16][16]; +} Histogram; + + +#if CV_SSE2 +#define MEDIAN_HAVE_SIMD 1 + +static inline void histogram_add_simd( const HT x[16], HT y[16] ) +{ + const __m128i* rx = (const __m128i*)x; + __m128i* ry = (__m128i*)y; + __m128i r0 = _mm_add_epi16(_mm_load_si128(ry+0),_mm_load_si128(rx+0)); + __m128i r1 = _mm_add_epi16(_mm_load_si128(ry+1),_mm_load_si128(rx+1)); + _mm_store_si128(ry+0, r0); + _mm_store_si128(ry+1, r1); +} + +static inline void histogram_sub_simd( const HT x[16], HT y[16] ) +{ + const __m128i* rx = (const __m128i*)x; + __m128i* ry = (__m128i*)y; + __m128i r0 = _mm_sub_epi16(_mm_load_si128(ry+0),_mm_load_si128(rx+0)); + __m128i r1 = _mm_sub_epi16(_mm_load_si128(ry+1),_mm_load_si128(rx+1)); + _mm_store_si128(ry+0, r0); + _mm_store_si128(ry+1, r1); +} + +#else +#define MEDIAN_HAVE_SIMD 0 +#endif + + +static inline void histogram_add( const HT x[16], HT y[16] ) +{ + int i; + for( i = 0; i < 16; ++i ) + y[i] = (HT)(y[i] + x[i]); +} + +static inline void histogram_sub( const HT x[16], HT y[16] ) +{ + int i; + for( i = 0; i < 16; ++i ) + y[i] = (HT)(y[i] - x[i]); +} + +static inline void histogram_muladd( int a, const HT x[16], + HT y[16] ) +{ + for( int i = 0; i < 16; ++i ) + y[i] = (HT)(y[i] + a * x[i]); +} + +static void +medianBlur_8u_O1( const Mat& _src, Mat& _dst, int ksize ) +{ +/** + * HOP is short for Histogram OPeration. This macro makes an operation \a op on + * histogram \a h for pixel value \a x. It takes care of handling both levels. + */ +#define HOP(h,x,op) \ + h.coarse[x>>4] op, \ + *((HT*)h.fine + x) op + +#define COP(c,j,x,op) \ + h_coarse[ 16*(n*c+j) + (x>>4) ] op, \ + h_fine[ 16 * (n*(16*c+(x>>4)) + j) + (x & 0xF) ] op + + int cn = _dst.channels(), m = _dst.rows, r = (ksize-1)/2; + size_t sstep = _src.step, dstep = _dst.step; + Histogram CV_DECL_ALIGNED(16) H[4]; + HT CV_DECL_ALIGNED(16) luc[4][16]; + + int STRIPE_SIZE = std::min( _dst.cols, 512/cn ); + + vector _h_coarse(1 * 16 * (STRIPE_SIZE + 2*r) * cn + 16); + vector _h_fine(16 * 16 * (STRIPE_SIZE + 2*r) * cn + 16); + HT* h_coarse = alignPtr(&_h_coarse[0], 16); + HT* h_fine = alignPtr(&_h_fine[0], 16); +#if MEDIAN_HAVE_SIMD + volatile bool useSIMD = checkHardwareSupport(CV_CPU_SSE2); +#endif + + for( int x = 0; x < _dst.cols; x += STRIPE_SIZE ) + { + int i, j, k, c, n = std::min(_dst.cols - x, STRIPE_SIZE) + r*2; + const uchar* src = _src.data + x*cn; + uchar* dst = _dst.data + (x - r)*cn; + + memset( h_coarse, 0, 16*n*cn*sizeof(h_coarse[0]) ); + memset( h_fine, 0, 16*16*n*cn*sizeof(h_fine[0]) ); + + // First row initialization + for( c = 0; c < cn; c++ ) + { + for( j = 0; j < n; j++ ) + COP( c, j, src[cn*j+c], += (cv::HT)(r+2) ); + + for( i = 1; i < r; i++ ) + { + const uchar* p = src + sstep*std::min(i, m-1); + for ( j = 0; j < n; j++ ) + COP( c, j, p[cn*j+c], ++ ); + } + } + + for( i = 0; i < m; i++ ) + { + const uchar* p0 = src + sstep * std::max( 0, i-r-1 ); + const uchar* p1 = src + sstep * std::min( m-1, i+r ); + + memset( H, 0, cn*sizeof(H[0]) ); + memset( luc, 0, cn*sizeof(luc[0]) ); + for( c = 0; c < cn; c++ ) + { + // Update column histograms for the entire row. + for( j = 0; j < n; j++ ) + { + COP( c, j, p0[j*cn + c], -- ); + COP( c, j, p1[j*cn + c], ++ ); + } + + // First column initialization + for( k = 0; k < 16; ++k ) + histogram_muladd( 2*r+1, &h_fine[16*n*(16*c+k)], &H[c].fine[k][0] ); + + #if MEDIAN_HAVE_SIMD + if( useSIMD ) + { + for( j = 0; j < 2*r; ++j ) + histogram_add_simd( &h_coarse[16*(n*c+j)], H[c].coarse ); + + for( j = r; j < n-r; j++ ) + { + int t = 2*r*r + 2*r, b, sum = 0; + HT* segment; + + histogram_add_simd( &h_coarse[16*(n*c + std::min(j+r,n-1))], H[c].coarse ); + + // Find median at coarse level + for ( k = 0; k < 16 ; ++k ) + { + sum += H[c].coarse[k]; + if ( sum > t ) + { + sum -= H[c].coarse[k]; + break; + } + } + assert( k < 16 ); + + /* Update corresponding histogram segment */ + if ( luc[c][k] <= j-r ) + { + memset( &H[c].fine[k], 0, 16 * sizeof(HT) ); + for ( luc[c][k] = cv::HT(j-r); luc[c][k] < MIN(j+r+1,n); ++luc[c][k] ) + histogram_add_simd( &h_fine[16*(n*(16*c+k)+luc[c][k])], H[c].fine[k] ); + + if ( luc[c][k] < j+r+1 ) + { + histogram_muladd( j+r+1 - n, &h_fine[16*(n*(16*c+k)+(n-1))], &H[c].fine[k][0] ); + luc[c][k] = (HT)(j+r+1); + } + } + else + { + for ( ; luc[c][k] < j+r+1; ++luc[c][k] ) + { + histogram_sub_simd( &h_fine[16*(n*(16*c+k)+MAX(luc[c][k]-2*r-1,0))], H[c].fine[k] ); + histogram_add_simd( &h_fine[16*(n*(16*c+k)+MIN(luc[c][k],n-1))], H[c].fine[k] ); + } + } + + histogram_sub_simd( &h_coarse[16*(n*c+MAX(j-r,0))], H[c].coarse ); + + /* Find median in segment */ + segment = H[c].fine[k]; + for ( b = 0; b < 16 ; b++ ) + { + sum += segment[b]; + if ( sum > t ) + { + dst[dstep*i+cn*j+c] = (uchar)(16*k + b); + break; + } + } + assert( b < 16 ); + } + } + else + #endif + { + for( j = 0; j < 2*r; ++j ) + histogram_add( &h_coarse[16*(n*c+j)], H[c].coarse ); + + for( j = r; j < n-r; j++ ) + { + int t = 2*r*r + 2*r, b, sum = 0; + HT* segment; + + histogram_add( &h_coarse[16*(n*c + std::min(j+r,n-1))], H[c].coarse ); + + // Find median at coarse level + for ( k = 0; k < 16 ; ++k ) + { + sum += H[c].coarse[k]; + if ( sum > t ) + { + sum -= H[c].coarse[k]; + break; + } + } + assert( k < 16 ); + + /* Update corresponding histogram segment */ + if ( luc[c][k] <= j-r ) + { + memset( &H[c].fine[k], 0, 16 * sizeof(HT) ); + for ( luc[c][k] = cv::HT(j-r); luc[c][k] < MIN(j+r+1,n); ++luc[c][k] ) + histogram_add( &h_fine[16*(n*(16*c+k)+luc[c][k])], H[c].fine[k] ); + + if ( luc[c][k] < j+r+1 ) + { + histogram_muladd( j+r+1 - n, &h_fine[16*(n*(16*c+k)+(n-1))], &H[c].fine[k][0] ); + luc[c][k] = (HT)(j+r+1); + } + } + else + { + for ( ; luc[c][k] < j+r+1; ++luc[c][k] ) + { + histogram_sub( &h_fine[16*(n*(16*c+k)+MAX(luc[c][k]-2*r-1,0))], H[c].fine[k] ); + histogram_add( &h_fine[16*(n*(16*c+k)+MIN(luc[c][k],n-1))], H[c].fine[k] ); + } + } + + histogram_sub( &h_coarse[16*(n*c+MAX(j-r,0))], H[c].coarse ); + + /* Find median in segment */ + segment = H[c].fine[k]; + for ( b = 0; b < 16 ; b++ ) + { + sum += segment[b]; + if ( sum > t ) + { + dst[dstep*i+cn*j+c] = (uchar)(16*k + b); + break; + } + } + assert( b < 16 ); + } + } + } + } + } + +#undef HOP +#undef COP +} + +static void +medianBlur_8u_Om( const Mat& _src, Mat& _dst, int m ) +{ + #define N 16 + int zone0[4][N]; + int zone1[4][N*N]; + int x, y; + int n2 = m*m/2; + Size size = _dst.size(); + const uchar* src = _src.data; + uchar* dst = _dst.data; + int src_step = (int)_src.step, dst_step = (int)_dst.step; + int cn = _src.channels(); + const uchar* src_max = src + size.height*src_step; + + #define UPDATE_ACC01( pix, cn, op ) \ + { \ + int p = (pix); \ + zone1[cn][p] op; \ + zone0[cn][p >> 4] op; \ + } + + //CV_Assert( size.height >= nx && size.width >= nx ); + for( x = 0; x < size.width; x++, src += cn, dst += cn ) + { + uchar* dst_cur = dst; + const uchar* src_top = src; + const uchar* src_bottom = src; + int k, c; + int src_step1 = src_step, dst_step1 = dst_step; + + if( x % 2 != 0 ) + { + src_bottom = src_top += src_step*(size.height-1); + dst_cur += dst_step*(size.height-1); + src_step1 = -src_step1; + dst_step1 = -dst_step1; + } + + // init accumulator + memset( zone0, 0, sizeof(zone0[0])*cn ); + memset( zone1, 0, sizeof(zone1[0])*cn ); + + for( y = 0; y <= m/2; y++ ) + { + for( c = 0; c < cn; c++ ) + { + if( y > 0 ) + { + for( k = 0; k < m*cn; k += cn ) + UPDATE_ACC01( src_bottom[k+c], c, ++ ); + } + else + { + for( k = 0; k < m*cn; k += cn ) + UPDATE_ACC01( src_bottom[k+c], c, += m/2+1 ); + } + } + + if( (src_step1 > 0 && y < size.height-1) || + (src_step1 < 0 && size.height-y-1 > 0) ) + src_bottom += src_step1; + } + + for( y = 0; y < size.height; y++, dst_cur += dst_step1 ) + { + // find median + for( c = 0; c < cn; c++ ) + { + int s = 0; + for( k = 0; ; k++ ) + { + int t = s + zone0[c][k]; + if( t > n2 ) break; + s = t; + } + + for( k *= N; ;k++ ) + { + s += zone1[c][k]; + if( s > n2 ) break; + } + + dst_cur[c] = (uchar)k; + } + + if( y+1 == size.height ) + break; + + if( cn == 1 ) + { + for( k = 0; k < m; k++ ) + { + int p = src_top[k]; + int q = src_bottom[k]; + zone1[0][p]--; + zone0[0][p>>4]--; + zone1[0][q]++; + zone0[0][q>>4]++; + } + } + else if( cn == 3 ) + { + for( k = 0; k < m*3; k += 3 ) + { + UPDATE_ACC01( src_top[k], 0, -- ); + UPDATE_ACC01( src_top[k+1], 1, -- ); + UPDATE_ACC01( src_top[k+2], 2, -- ); + + UPDATE_ACC01( src_bottom[k], 0, ++ ); + UPDATE_ACC01( src_bottom[k+1], 1, ++ ); + UPDATE_ACC01( src_bottom[k+2], 2, ++ ); + } + } + else + { + assert( cn == 4 ); + for( k = 0; k < m*4; k += 4 ) + { + UPDATE_ACC01( src_top[k], 0, -- ); + UPDATE_ACC01( src_top[k+1], 1, -- ); + UPDATE_ACC01( src_top[k+2], 2, -- ); + UPDATE_ACC01( src_top[k+3], 3, -- ); + + UPDATE_ACC01( src_bottom[k], 0, ++ ); + UPDATE_ACC01( src_bottom[k+1], 1, ++ ); + UPDATE_ACC01( src_bottom[k+2], 2, ++ ); + UPDATE_ACC01( src_bottom[k+3], 3, ++ ); + } + } + + if( (src_step1 > 0 && src_bottom + src_step1 < src_max) || + (src_step1 < 0 && src_bottom + src_step1 >= src) ) + src_bottom += src_step1; + + if( y >= m/2 ) + src_top += src_step1; + } + } +#undef N +#undef UPDATE_ACC +} + + +struct MinMax8u +{ + typedef uchar value_type; + typedef int arg_type; + enum { SIZE = 1 }; + arg_type load(const uchar* ptr) { return *ptr; } + void store(uchar* ptr, arg_type val) { *ptr = (uchar)val; } + void operator()(arg_type& a, arg_type& b) const + { + int t = CV_FAST_CAST_8U(a - b); + b += t; a -= t; + } +}; + +struct MinMax16u +{ + typedef ushort value_type; + typedef int arg_type; + enum { SIZE = 1 }; + arg_type load(const ushort* ptr) { return *ptr; } + void store(ushort* ptr, arg_type val) { *ptr = (ushort)val; } + void operator()(arg_type& a, arg_type& b) const + { + arg_type t = a; + a = std::min(a, b); + b = std::max(b, t); + } +}; + +struct MinMax16s +{ + typedef short value_type; + typedef int arg_type; + enum { SIZE = 1 }; + arg_type load(const short* ptr) { return *ptr; } + void store(short* ptr, arg_type val) { *ptr = (short)val; } + void operator()(arg_type& a, arg_type& b) const + { + arg_type t = a; + a = std::min(a, b); + b = std::max(b, t); + } +}; + +struct MinMax32f +{ + typedef float value_type; + typedef float arg_type; + enum { SIZE = 1 }; + arg_type load(const float* ptr) { return *ptr; } + void store(float* ptr, arg_type val) { *ptr = val; } + void operator()(arg_type& a, arg_type& b) const + { + arg_type t = a; + a = std::min(a, b); + b = std::max(b, t); + } +}; + +#if CV_SSE2 + +struct MinMaxVec8u +{ + typedef uchar value_type; + typedef __m128i arg_type; + enum { SIZE = 16 }; + arg_type load(const uchar* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } + void store(uchar* ptr, arg_type val) { _mm_storeu_si128((__m128i*)ptr, val); } + void operator()(arg_type& a, arg_type& b) const + { + arg_type t = a; + a = _mm_min_epu8(a, b); + b = _mm_max_epu8(b, t); + } +}; + + +struct MinMaxVec16u +{ + typedef ushort value_type; + typedef __m128i arg_type; + enum { SIZE = 8 }; + arg_type load(const ushort* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } + void store(ushort* ptr, arg_type val) { _mm_storeu_si128((__m128i*)ptr, val); } + void operator()(arg_type& a, arg_type& b) const + { + arg_type t = _mm_subs_epu16(a, b); + a = _mm_subs_epu16(a, t); + b = _mm_adds_epu16(b, t); + } +}; + + +struct MinMaxVec16s +{ + typedef short value_type; + typedef __m128i arg_type; + enum { SIZE = 8 }; + arg_type load(const short* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } + void store(short* ptr, arg_type val) { _mm_storeu_si128((__m128i*)ptr, val); } + void operator()(arg_type& a, arg_type& b) const + { + arg_type t = a; + a = _mm_min_epi16(a, b); + b = _mm_max_epi16(b, t); + } +}; + + +struct MinMaxVec32f +{ + typedef float value_type; + typedef __m128 arg_type; + enum { SIZE = 4 }; + arg_type load(const float* ptr) { return _mm_loadu_ps(ptr); } + void store(float* ptr, arg_type val) { _mm_storeu_ps(ptr, val); } + void operator()(arg_type& a, arg_type& b) const + { + arg_type t = a; + a = _mm_min_ps(a, b); + b = _mm_max_ps(b, t); + } +}; + + +#else + +typedef MinMax8u MinMaxVec8u; +typedef MinMax16u MinMaxVec16u; +typedef MinMax16s MinMaxVec16s; +typedef MinMax32f MinMaxVec32f; + +#endif + +template +static void +medianBlur_SortNet( const Mat& _src, Mat& _dst, int m ) +{ + typedef typename Op::value_type T; + typedef typename Op::arg_type WT; + typedef typename VecOp::arg_type VT; + + const T* src = (const T*)_src.data; + T* dst = (T*)_dst.data; + int sstep = (int)(_src.step/sizeof(T)); + int dstep = (int)(_dst.step/sizeof(T)); + Size size = _dst.size(); + int i, j, k, cn = _src.channels(); + Op op; + VecOp vop; + volatile bool useSIMD = checkHardwareSupport(CV_CPU_SSE2); + + if( m == 3 ) + { + if( size.width == 1 || size.height == 1 ) + { + int len = size.width + size.height - 1; + int sdelta = size.height == 1 ? cn : sstep; + int sdelta0 = size.height == 1 ? 0 : sstep - cn; + int ddelta = size.height == 1 ? cn : dstep; + + for( i = 0; i < len; i++, src += sdelta0, dst += ddelta ) + for( j = 0; j < cn; j++, src++ ) + { + WT p0 = src[i > 0 ? -sdelta : 0]; + WT p1 = src[0]; + WT p2 = src[i < len - 1 ? sdelta : 0]; + + op(p0, p1); op(p1, p2); op(p0, p1); + dst[j] = (T)p1; + } + return; + } + + size.width *= cn; + for( i = 0; i < size.height; i++, dst += dstep ) + { + const T* row0 = src + std::max(i - 1, 0)*sstep; + const T* row1 = src + i*sstep; + const T* row2 = src + std::min(i + 1, size.height-1)*sstep; + int limit = useSIMD ? cn : size.width; + + for(j = 0;; ) + { + for( ; j < limit; j++ ) + { + int j0 = j >= cn ? j - cn : j; + int j2 = j < size.width - cn ? j + cn : j; + WT p0 = row0[j0], p1 = row0[j], p2 = row0[j2]; + WT p3 = row1[j0], p4 = row1[j], p5 = row1[j2]; + WT p6 = row2[j0], p7 = row2[j], p8 = row2[j2]; + + op(p1, p2); op(p4, p5); op(p7, p8); op(p0, p1); + op(p3, p4); op(p6, p7); op(p1, p2); op(p4, p5); + op(p7, p8); op(p0, p3); op(p5, p8); op(p4, p7); + op(p3, p6); op(p1, p4); op(p2, p5); op(p4, p7); + op(p4, p2); op(p6, p4); op(p4, p2); + dst[j] = (T)p4; + } + + if( limit == size.width ) + break; + + for( ; j <= size.width - VecOp::SIZE - cn; j += VecOp::SIZE ) + { + VT p0 = vop.load(row0+j-cn), p1 = vop.load(row0+j), p2 = vop.load(row0+j+cn); + VT p3 = vop.load(row1+j-cn), p4 = vop.load(row1+j), p5 = vop.load(row1+j+cn); + VT p6 = vop.load(row2+j-cn), p7 = vop.load(row2+j), p8 = vop.load(row2+j+cn); + + vop(p1, p2); vop(p4, p5); vop(p7, p8); vop(p0, p1); + vop(p3, p4); vop(p6, p7); vop(p1, p2); vop(p4, p5); + vop(p7, p8); vop(p0, p3); vop(p5, p8); vop(p4, p7); + vop(p3, p6); vop(p1, p4); vop(p2, p5); vop(p4, p7); + vop(p4, p2); vop(p6, p4); vop(p4, p2); + vop.store(dst+j, p4); + } + + limit = size.width; + } + } + } + else if( m == 5 ) + { + if( size.width == 1 || size.height == 1 ) + { + int len = size.width + size.height - 1; + int sdelta = size.height == 1 ? cn : sstep; + int sdelta0 = size.height == 1 ? 0 : sstep - cn; + int ddelta = size.height == 1 ? cn : dstep; + + for( i = 0; i < len; i++, src += sdelta0, dst += ddelta ) + for( j = 0; j < cn; j++, src++ ) + { + int i1 = i > 0 ? -sdelta : 0; + int i0 = i > 1 ? -sdelta*2 : i1; + int i3 = i < len-1 ? sdelta : 0; + int i4 = i < len-2 ? sdelta*2 : i3; + WT p0 = src[i0], p1 = src[i1], p2 = src[0], p3 = src[i3], p4 = src[i4]; + + op(p0, p1); op(p3, p4); op(p2, p3); op(p3, p4); op(p0, p2); + op(p2, p4); op(p1, p3); op(p1, p2); + dst[j] = (T)p2; + } + return; + } + + size.width *= cn; + for( i = 0; i < size.height; i++, dst += dstep ) + { + const T* row[5]; + row[0] = src + std::max(i - 2, 0)*sstep; + row[1] = src + std::max(i - 1, 0)*sstep; + row[2] = src + i*sstep; + row[3] = src + std::min(i + 1, size.height-1)*sstep; + row[4] = src + std::min(i + 2, size.height-1)*sstep; + int limit = useSIMD ? cn*2 : size.width; + + for(j = 0;; ) + { + for( ; j < limit; j++ ) + { + WT p[25]; + int j1 = j >= cn ? j - cn : j; + int j0 = j >= cn*2 ? j - cn*2 : j1; + int j3 = j < size.width - cn ? j + cn : j; + int j4 = j < size.width - cn*2 ? j + cn*2 : j3; + for( k = 0; k < 5; k++ ) + { + const T* rowk = row[k]; + p[k*5] = rowk[j0]; p[k*5+1] = rowk[j1]; + p[k*5+2] = rowk[j]; p[k*5+3] = rowk[j3]; + p[k*5+4] = rowk[j4]; + } + + op(p[1], p[2]); op(p[0], p[1]); op(p[1], p[2]); op(p[4], p[5]); op(p[3], p[4]); + op(p[4], p[5]); op(p[0], p[3]); op(p[2], p[5]); op(p[2], p[3]); op(p[1], p[4]); + op(p[1], p[2]); op(p[3], p[4]); op(p[7], p[8]); op(p[6], p[7]); op(p[7], p[8]); + op(p[10], p[11]); op(p[9], p[10]); op(p[10], p[11]); op(p[6], p[9]); op(p[8], p[11]); + op(p[8], p[9]); op(p[7], p[10]); op(p[7], p[8]); op(p[9], p[10]); op(p[0], p[6]); + op(p[4], p[10]); op(p[4], p[6]); op(p[2], p[8]); op(p[2], p[4]); op(p[6], p[8]); + op(p[1], p[7]); op(p[5], p[11]); op(p[5], p[7]); op(p[3], p[9]); op(p[3], p[5]); + op(p[7], p[9]); op(p[1], p[2]); op(p[3], p[4]); op(p[5], p[6]); op(p[7], p[8]); + op(p[9], p[10]); op(p[13], p[14]); op(p[12], p[13]); op(p[13], p[14]); op(p[16], p[17]); + op(p[15], p[16]); op(p[16], p[17]); op(p[12], p[15]); op(p[14], p[17]); op(p[14], p[15]); + op(p[13], p[16]); op(p[13], p[14]); op(p[15], p[16]); op(p[19], p[20]); op(p[18], p[19]); + op(p[19], p[20]); op(p[21], p[22]); op(p[23], p[24]); op(p[21], p[23]); op(p[22], p[24]); + op(p[22], p[23]); op(p[18], p[21]); op(p[20], p[23]); op(p[20], p[21]); op(p[19], p[22]); + op(p[22], p[24]); op(p[19], p[20]); op(p[21], p[22]); op(p[23], p[24]); op(p[12], p[18]); + op(p[16], p[22]); op(p[16], p[18]); op(p[14], p[20]); op(p[20], p[24]); op(p[14], p[16]); + op(p[18], p[20]); op(p[22], p[24]); op(p[13], p[19]); op(p[17], p[23]); op(p[17], p[19]); + op(p[15], p[21]); op(p[15], p[17]); op(p[19], p[21]); op(p[13], p[14]); op(p[15], p[16]); + op(p[17], p[18]); op(p[19], p[20]); op(p[21], p[22]); op(p[23], p[24]); op(p[0], p[12]); + op(p[8], p[20]); op(p[8], p[12]); op(p[4], p[16]); op(p[16], p[24]); op(p[12], p[16]); + op(p[2], p[14]); op(p[10], p[22]); op(p[10], p[14]); op(p[6], p[18]); op(p[6], p[10]); + op(p[10], p[12]); op(p[1], p[13]); op(p[9], p[21]); op(p[9], p[13]); op(p[5], p[17]); + op(p[13], p[17]); op(p[3], p[15]); op(p[11], p[23]); op(p[11], p[15]); op(p[7], p[19]); + op(p[7], p[11]); op(p[11], p[13]); op(p[11], p[12]); + dst[j] = (T)p[12]; + } + + if( limit == size.width ) + break; + + for( ; j <= size.width - VecOp::SIZE - cn*2; j += VecOp::SIZE ) + { + VT p[25]; + for( k = 0; k < 5; k++ ) + { + const T* rowk = row[k]; + p[k*5] = vop.load(rowk+j-cn*2); p[k*5+1] = vop.load(rowk+j-cn); + p[k*5+2] = vop.load(rowk+j); p[k*5+3] = vop.load(rowk+j+cn); + p[k*5+4] = vop.load(rowk+j+cn*2); + } + + vop(p[1], p[2]); vop(p[0], p[1]); vop(p[1], p[2]); vop(p[4], p[5]); vop(p[3], p[4]); + vop(p[4], p[5]); vop(p[0], p[3]); vop(p[2], p[5]); vop(p[2], p[3]); vop(p[1], p[4]); + vop(p[1], p[2]); vop(p[3], p[4]); vop(p[7], p[8]); vop(p[6], p[7]); vop(p[7], p[8]); + vop(p[10], p[11]); vop(p[9], p[10]); vop(p[10], p[11]); vop(p[6], p[9]); vop(p[8], p[11]); + vop(p[8], p[9]); vop(p[7], p[10]); vop(p[7], p[8]); vop(p[9], p[10]); vop(p[0], p[6]); + vop(p[4], p[10]); vop(p[4], p[6]); vop(p[2], p[8]); vop(p[2], p[4]); vop(p[6], p[8]); + vop(p[1], p[7]); vop(p[5], p[11]); vop(p[5], p[7]); vop(p[3], p[9]); vop(p[3], p[5]); + vop(p[7], p[9]); vop(p[1], p[2]); vop(p[3], p[4]); vop(p[5], p[6]); vop(p[7], p[8]); + vop(p[9], p[10]); vop(p[13], p[14]); vop(p[12], p[13]); vop(p[13], p[14]); vop(p[16], p[17]); + vop(p[15], p[16]); vop(p[16], p[17]); vop(p[12], p[15]); vop(p[14], p[17]); vop(p[14], p[15]); + vop(p[13], p[16]); vop(p[13], p[14]); vop(p[15], p[16]); vop(p[19], p[20]); vop(p[18], p[19]); + vop(p[19], p[20]); vop(p[21], p[22]); vop(p[23], p[24]); vop(p[21], p[23]); vop(p[22], p[24]); + vop(p[22], p[23]); vop(p[18], p[21]); vop(p[20], p[23]); vop(p[20], p[21]); vop(p[19], p[22]); + vop(p[22], p[24]); vop(p[19], p[20]); vop(p[21], p[22]); vop(p[23], p[24]); vop(p[12], p[18]); + vop(p[16], p[22]); vop(p[16], p[18]); vop(p[14], p[20]); vop(p[20], p[24]); vop(p[14], p[16]); + vop(p[18], p[20]); vop(p[22], p[24]); vop(p[13], p[19]); vop(p[17], p[23]); vop(p[17], p[19]); + vop(p[15], p[21]); vop(p[15], p[17]); vop(p[19], p[21]); vop(p[13], p[14]); vop(p[15], p[16]); + vop(p[17], p[18]); vop(p[19], p[20]); vop(p[21], p[22]); vop(p[23], p[24]); vop(p[0], p[12]); + vop(p[8], p[20]); vop(p[8], p[12]); vop(p[4], p[16]); vop(p[16], p[24]); vop(p[12], p[16]); + vop(p[2], p[14]); vop(p[10], p[22]); vop(p[10], p[14]); vop(p[6], p[18]); vop(p[6], p[10]); + vop(p[10], p[12]); vop(p[1], p[13]); vop(p[9], p[21]); vop(p[9], p[13]); vop(p[5], p[17]); + vop(p[13], p[17]); vop(p[3], p[15]); vop(p[11], p[23]); vop(p[11], p[15]); vop(p[7], p[19]); + vop(p[7], p[11]); vop(p[11], p[13]); vop(p[11], p[12]); + vop.store(dst+j, p[12]); + } + + limit = size.width; + } + } + } +} + +} + +void cv::medianBlur( InputArray _src0, OutputArray _dst, int ksize ) +{ + Mat src0 = _src0.getMat(); + _dst.create( src0.size(), src0.type() ); + Mat dst = _dst.getMat(); + + if( ksize <= 1 ) + { + src0.copyTo(dst); + return; + } + + CV_Assert( ksize % 2 == 1 ); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if (tegra::medianBlur(src0, dst, ksize)) + return; +#endif + + bool useSortNet = ksize == 3 || (ksize == 5 +#if !CV_SSE2 + && src0.depth() > CV_8U +#endif + ); + + Mat src; + if( useSortNet ) + { + if( dst.data != src0.data ) + src = src0; + else + src0.copyTo(src); + + if( src.depth() == CV_8U ) + medianBlur_SortNet( src, dst, ksize ); + else if( src.depth() == CV_16U ) + medianBlur_SortNet( src, dst, ksize ); + else if( src.depth() == CV_16S ) + medianBlur_SortNet( src, dst, ksize ); + else if( src.depth() == CV_32F ) + medianBlur_SortNet( src, dst, ksize ); + else + CV_Error(CV_StsUnsupportedFormat, ""); + + return; + } + else + { + cv::copyMakeBorder( src0, src, 0, 0, ksize/2, ksize/2, BORDER_REPLICATE ); + + int cn = src0.channels(); + CV_Assert( src.depth() == CV_8U && (cn == 1 || cn == 3 || cn == 4) ); + + double img_size_mp = (double)(src0.total())/(1 << 20); + if( ksize <= 3 + (img_size_mp < 1 ? 12 : img_size_mp < 4 ? 6 : 2)*(MEDIAN_HAVE_SIMD && checkHardwareSupport(CV_CPU_SSE2) ? 1 : 3)) + medianBlur_8u_Om( src, dst, ksize ); + else + medianBlur_8u_O1( src, dst, ksize ); + } +} + +/****************************************************************************************\ + Bilateral Filtering +\****************************************************************************************/ + +namespace cv +{ + +class BilateralFilter_8u_Invoker : + public ParallelLoopBody +{ +public: + BilateralFilter_8u_Invoker(Mat& _dest, const Mat& _temp, int _radius, int _maxk, + int* _space_ofs, float *_space_weight, float *_color_weight) : + temp(&_temp), dest(&_dest), radius(_radius), + maxk(_maxk), space_ofs(_space_ofs), space_weight(_space_weight), color_weight(_color_weight) + { + } + + virtual void operator() (const Range& range) const + { + int i, j, cn = dest->channels(), k; + Size size = dest->size(); + #if CV_SSE3 + int CV_DECL_ALIGNED(16) buf[4]; + float CV_DECL_ALIGNED(16) bufSum[4]; + static const int CV_DECL_ALIGNED(16) bufSignMask[] = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }; + bool haveSSE3 = checkHardwareSupport(CV_CPU_SSE3); + #endif + + for( i = range.start; i < range.end; i++ ) + { + const uchar* sptr = temp->ptr(i+radius) + radius*cn; + uchar* dptr = dest->ptr(i); + + if( cn == 1 ) + { + for( j = 0; j < size.width; j++ ) + { + float sum = 0, wsum = 0; + int val0 = sptr[j]; + k = 0; + #if CV_SSE3 + if( haveSSE3 ) + { + __m128 _val0 = _mm_set1_ps(static_cast(val0)); + const __m128 _signMask = _mm_load_ps((const float*)bufSignMask); + + for( ; k <= maxk - 4; k += 4 ) + { + __m128 _valF = _mm_set_ps(sptr[j + space_ofs[k+3]], sptr[j + space_ofs[k+2]], + sptr[j + space_ofs[k+1]], sptr[j + space_ofs[k]]); + + __m128 _val = _mm_andnot_ps(_signMask, _mm_sub_ps(_valF, _val0)); + _mm_store_si128((__m128i*)buf, _mm_cvtps_epi32(_val)); + + __m128 _cw = _mm_set_ps(color_weight[buf[3]],color_weight[buf[2]], + color_weight[buf[1]],color_weight[buf[0]]); + __m128 _sw = _mm_loadu_ps(space_weight+k); + __m128 _w = _mm_mul_ps(_cw, _sw); + _cw = _mm_mul_ps(_w, _valF); + + _sw = _mm_hadd_ps(_w, _cw); + _sw = _mm_hadd_ps(_sw, _sw); + _mm_storel_pi((__m64*)bufSum, _sw); + + sum += bufSum[1]; + wsum += bufSum[0]; + } + } + #endif + for( ; k < maxk; k++ ) + { + int val = sptr[j + space_ofs[k]]; + float w = space_weight[k]*color_weight[std::abs(val - val0)]; + sum += val*w; + wsum += w; + } + // overflow is not possible here => there is no need to use CV_CAST_8U + dptr[j] = (uchar)cvRound(sum/wsum); + } + } + else + { + assert( cn == 3 ); + for( j = 0; j < size.width*3; j += 3 ) + { + float sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0; + int b0 = sptr[j], g0 = sptr[j+1], r0 = sptr[j+2]; + k = 0; + #if CV_SSE3 + if( haveSSE3 ) + { + const __m128 _b0 = _mm_set1_ps(static_cast(b0)); + const __m128 _g0 = _mm_set1_ps(static_cast(g0)); + const __m128 _r0 = _mm_set1_ps(static_cast(r0)); + const __m128 _signMask = _mm_load_ps((const float*)bufSignMask); + + for( ; k <= maxk - 4; k += 4 ) + { + const uchar* sptr_k = sptr + j + space_ofs[k]; + const uchar* sptr_k1 = sptr + j + space_ofs[k+1]; + const uchar* sptr_k2 = sptr + j + space_ofs[k+2]; + const uchar* sptr_k3 = sptr + j + space_ofs[k+3]; + + __m128 _b = _mm_set_ps(sptr_k3[0],sptr_k2[0],sptr_k1[0],sptr_k[0]); + __m128 _g = _mm_set_ps(sptr_k3[1],sptr_k2[1],sptr_k1[1],sptr_k[1]); + __m128 _r = _mm_set_ps(sptr_k3[2],sptr_k2[2],sptr_k1[2],sptr_k[2]); + + __m128 bt = _mm_andnot_ps(_signMask, _mm_sub_ps(_b,_b0)); + __m128 gt = _mm_andnot_ps(_signMask, _mm_sub_ps(_g,_g0)); + __m128 rt = _mm_andnot_ps(_signMask, _mm_sub_ps(_r,_r0)); + + bt =_mm_add_ps(rt, _mm_add_ps(bt, gt)); + _mm_store_si128((__m128i*)buf, _mm_cvtps_epi32(bt)); + + __m128 _w = _mm_set_ps(color_weight[buf[3]],color_weight[buf[2]], + color_weight[buf[1]],color_weight[buf[0]]); + __m128 _sw = _mm_loadu_ps(space_weight+k); + + _w = _mm_mul_ps(_w,_sw); + _b = _mm_mul_ps(_b, _w); + _g = _mm_mul_ps(_g, _w); + _r = _mm_mul_ps(_r, _w); + + _w = _mm_hadd_ps(_w, _b); + _g = _mm_hadd_ps(_g, _r); + + _w = _mm_hadd_ps(_w, _g); + _mm_store_ps(bufSum, _w); + + wsum += bufSum[0]; + sum_b += bufSum[1]; + sum_g += bufSum[2]; + sum_r += bufSum[3]; + } + } + #endif + + for( ; k < maxk; k++ ) + { + const uchar* sptr_k = sptr + j + space_ofs[k]; + int b = sptr_k[0], g = sptr_k[1], r = sptr_k[2]; + float w = space_weight[k]*color_weight[std::abs(b - b0) + + std::abs(g - g0) + std::abs(r - r0)]; + sum_b += b*w; sum_g += g*w; sum_r += r*w; + wsum += w; + } + wsum = 1.f/wsum; + b0 = cvRound(sum_b*wsum); + g0 = cvRound(sum_g*wsum); + r0 = cvRound(sum_r*wsum); + dptr[j] = (uchar)b0; dptr[j+1] = (uchar)g0; dptr[j+2] = (uchar)r0; + } + } + } + } + +private: + const Mat *temp; + Mat *dest; + int radius, maxk, *space_ofs; + float *space_weight, *color_weight; +}; + +static void +bilateralFilter_8u( const Mat& src, Mat& dst, int d, + double sigma_color, double sigma_space, + int borderType ) +{ + + int cn = src.channels(); + int i, j, maxk, radius; + Size size = src.size(); + + CV_Assert( (src.type() == CV_8UC1 || src.type() == CV_8UC3) && + src.type() == dst.type() && src.size() == dst.size() && + src.data != dst.data ); + + if( sigma_color <= 0 ) + sigma_color = 1; + if( sigma_space <= 0 ) + sigma_space = 1; + + double gauss_color_coeff = -0.5/(sigma_color*sigma_color); + double gauss_space_coeff = -0.5/(sigma_space*sigma_space); + + if( d <= 0 ) + radius = cvRound(sigma_space*1.5); + else + radius = d/2; + radius = MAX(radius, 1); + d = radius*2 + 1; + + Mat temp; + copyMakeBorder( src, temp, radius, radius, radius, radius, borderType ); + + vector _color_weight(cn*256); + vector _space_weight(d*d); + vector _space_ofs(d*d); + float* color_weight = &_color_weight[0]; + float* space_weight = &_space_weight[0]; + int* space_ofs = &_space_ofs[0]; + + // initialize color-related bilateral filter coefficients + + for( i = 0; i < 256*cn; i++ ) + color_weight[i] = (float)std::exp(i*i*gauss_color_coeff); + + // initialize space-related bilateral filter coefficients + for( i = -radius, maxk = 0; i <= radius; i++ ) + { + j = -radius; + + for( ;j <= radius; j++ ) + { + double r = std::sqrt((double)i*i + (double)j*j); + if( r > radius ) + continue; + space_weight[maxk] = (float)std::exp(r*r*gauss_space_coeff); + space_ofs[maxk++] = (int)(i*temp.step + j*cn); + } + } + + BilateralFilter_8u_Invoker body(dst, temp, radius, maxk, space_ofs, space_weight, color_weight); + parallel_for_(Range(0, size.height), body); +} + + +class BilateralFilter_32f_Invoker : + public ParallelLoopBody +{ +public: + + BilateralFilter_32f_Invoker(int _cn, int _radius, int _maxk, int *_space_ofs, + const Mat& _temp, Mat& _dest, float _scale_index, float *_space_weight, float *_expLUT) : + cn(_cn), radius(_radius), maxk(_maxk), space_ofs(_space_ofs), + temp(&_temp), dest(&_dest), scale_index(_scale_index), space_weight(_space_weight), expLUT(_expLUT) + { + } + + virtual void operator() (const Range& range) const + { + int i, j, k; + Size size = dest->size(); + #if CV_SSE3 + int CV_DECL_ALIGNED(16) idxBuf[4]; + float CV_DECL_ALIGNED(16) bufSum32[4]; + static const int CV_DECL_ALIGNED(16) bufSignMask[] = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }; + bool haveSSE3 = checkHardwareSupport(CV_CPU_SSE3); + #endif + + for( i = range.start; i < range.end; i++ ) + { + const float* sptr = temp->ptr(i+radius) + radius*cn; + float* dptr = dest->ptr(i); + + if( cn == 1 ) + { + for( j = 0; j < size.width; j++ ) + { + float sum = 0, wsum = 0; + float val0 = sptr[j]; + k = 0; + #if CV_SSE3 + if( haveSSE3 ) + { + const __m128 _val0 = _mm_set1_ps(sptr[j]); + const __m128 _scale_index = _mm_set1_ps(scale_index); + const __m128 _signMask = _mm_load_ps((const float*)bufSignMask); + + for( ; k <= maxk - 4 ; k += 4 ) + { + __m128 _sw = _mm_loadu_ps(space_weight + k); + __m128 _val = _mm_set_ps(sptr[j + space_ofs[k+3]], sptr[j + space_ofs[k+2]], + sptr[j + space_ofs[k+1]], sptr[j + space_ofs[k]]); + __m128 _alpha = _mm_mul_ps(_mm_andnot_ps( _signMask, _mm_sub_ps(_val,_val0)), _scale_index); + + __m128i _idx = _mm_cvtps_epi32(_alpha); + _mm_store_si128((__m128i*)idxBuf, _idx); + _alpha = _mm_sub_ps(_alpha, _mm_cvtepi32_ps(_idx)); + + __m128 _explut = _mm_set_ps(expLUT[idxBuf[3]], expLUT[idxBuf[2]], + expLUT[idxBuf[1]], expLUT[idxBuf[0]]); + __m128 _explut1 = _mm_set_ps(expLUT[idxBuf[3]+1], expLUT[idxBuf[2]+1], + expLUT[idxBuf[1]+1], expLUT[idxBuf[0]+1]); + + __m128 _w = _mm_mul_ps(_sw, _mm_add_ps(_explut, _mm_mul_ps(_alpha, _mm_sub_ps(_explut1, _explut)))); + _val = _mm_mul_ps(_w, _val); + + _sw = _mm_hadd_ps(_w, _val); + _sw = _mm_hadd_ps(_sw, _sw); + _mm_storel_pi((__m64*)bufSum32, _sw); + + sum += bufSum32[1]; + wsum += bufSum32[0]; + } + } + #endif + + for( ; k < maxk; k++ ) + { + float val = sptr[j + space_ofs[k]]; + float alpha = (float)(std::abs(val - val0)*scale_index); + int idx = cvFloor(alpha); + alpha -= idx; + float w = space_weight[k]*(expLUT[idx] + alpha*(expLUT[idx+1] - expLUT[idx])); + sum += val*w; + wsum += w; + } + dptr[j] = (float)(sum/wsum); + } + } + else + { + assert( cn == 3 ); + for( j = 0; j < size.width*3; j += 3 ) + { + float sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0; + float b0 = sptr[j], g0 = sptr[j+1], r0 = sptr[j+2]; + k = 0; + #if CV_SSE3 + if( haveSSE3 ) + { + const __m128 _b0 = _mm_set1_ps(b0); + const __m128 _g0 = _mm_set1_ps(g0); + const __m128 _r0 = _mm_set1_ps(r0); + const __m128 _scale_index = _mm_set1_ps(scale_index); + const __m128 _signMask = _mm_load_ps((const float*)bufSignMask); + + for( ; k <= maxk-4; k += 4 ) + { + __m128 _sw = _mm_loadu_ps(space_weight + k); + + const float* sptr_k = sptr + j + space_ofs[k]; + const float* sptr_k1 = sptr + j + space_ofs[k+1]; + const float* sptr_k2 = sptr + j + space_ofs[k+2]; + const float* sptr_k3 = sptr + j + space_ofs[k+3]; + + __m128 _b = _mm_set_ps(sptr_k3[0], sptr_k2[0], sptr_k1[0], sptr_k[0]); + __m128 _g = _mm_set_ps(sptr_k3[1], sptr_k2[1], sptr_k1[1], sptr_k[1]); + __m128 _r = _mm_set_ps(sptr_k3[2], sptr_k2[2], sptr_k1[2], sptr_k[2]); + + __m128 _bt = _mm_andnot_ps(_signMask,_mm_sub_ps(_b,_b0)); + __m128 _gt = _mm_andnot_ps(_signMask,_mm_sub_ps(_g,_g0)); + __m128 _rt = _mm_andnot_ps(_signMask,_mm_sub_ps(_r,_r0)); + + __m128 _alpha = _mm_mul_ps(_scale_index, _mm_add_ps(_rt,_mm_add_ps(_bt, _gt))); + + __m128i _idx = _mm_cvtps_epi32(_alpha); + _mm_store_si128((__m128i*)idxBuf, _idx); + _alpha = _mm_sub_ps(_alpha, _mm_cvtepi32_ps(_idx)); + + __m128 _explut = _mm_set_ps(expLUT[idxBuf[3]], expLUT[idxBuf[2]], expLUT[idxBuf[1]], expLUT[idxBuf[0]]); + __m128 _explut1 = _mm_set_ps(expLUT[idxBuf[3]+1], expLUT[idxBuf[2]+1], expLUT[idxBuf[1]+1], expLUT[idxBuf[0]+1]); + + __m128 _w = _mm_mul_ps(_sw, _mm_add_ps(_explut, _mm_mul_ps(_alpha, _mm_sub_ps(_explut1, _explut)))); + + _b = _mm_mul_ps(_b, _w); + _g = _mm_mul_ps(_g, _w); + _r = _mm_mul_ps(_r, _w); + + _w = _mm_hadd_ps(_w, _b); + _g = _mm_hadd_ps(_g, _r); + + _w = _mm_hadd_ps(_w, _g); + _mm_store_ps(bufSum32, _w); + + wsum += bufSum32[0]; + sum_b += bufSum32[1]; + sum_g += bufSum32[2]; + sum_r += bufSum32[3]; + } + + } + #endif + + for(; k < maxk; k++ ) + { + const float* sptr_k = sptr + j + space_ofs[k]; + float b = sptr_k[0], g = sptr_k[1], r = sptr_k[2]; + float alpha = (float)((std::abs(b - b0) + + std::abs(g - g0) + std::abs(r - r0))*scale_index); + int idx = cvFloor(alpha); + alpha -= idx; + float w = space_weight[k]*(expLUT[idx] + alpha*(expLUT[idx+1] - expLUT[idx])); + sum_b += b*w; sum_g += g*w; sum_r += r*w; + wsum += w; + } + wsum = 1.f/wsum; + b0 = sum_b*wsum; + g0 = sum_g*wsum; + r0 = sum_r*wsum; + dptr[j] = b0; dptr[j+1] = g0; dptr[j+2] = r0; + } + } + } + } + +private: + int cn, radius, maxk, *space_ofs; + const Mat* temp; + Mat *dest; + float scale_index, *space_weight, *expLUT; +}; + + +static void +bilateralFilter_32f( const Mat& src, Mat& dst, int d, + double sigma_color, double sigma_space, + int borderType ) +{ + int cn = src.channels(); + int i, j, maxk, radius; + double minValSrc=-1, maxValSrc=1; + const int kExpNumBinsPerChannel = 1 << 12; + int kExpNumBins = 0; + float lastExpVal = 1.f; + float len, scale_index; + Size size = src.size(); + + CV_Assert( (src.type() == CV_32FC1 || src.type() == CV_32FC3) && + src.type() == dst.type() && src.size() == dst.size() && + src.data != dst.data ); + + if( sigma_color <= 0 ) + sigma_color = 1; + if( sigma_space <= 0 ) + sigma_space = 1; + + double gauss_color_coeff = -0.5/(sigma_color*sigma_color); + double gauss_space_coeff = -0.5/(sigma_space*sigma_space); + + if( d <= 0 ) + radius = cvRound(sigma_space*1.5); + else + radius = d/2; + radius = MAX(radius, 1); + d = radius*2 + 1; + // compute the min/max range for the input image (even if multichannel) + + minMaxLoc( src.reshape(1), &minValSrc, &maxValSrc ); + if(std::abs(minValSrc - maxValSrc) < FLT_EPSILON) + { + src.copyTo(dst); + return; + } + + // temporary copy of the image with borders for easy processing + Mat temp; + copyMakeBorder( src, temp, radius, radius, radius, radius, borderType ); + const double insteadNaNValue = -5. * sigma_color; + patchNaNs( temp, insteadNaNValue ); // this replacement of NaNs makes the assumption that depth values are nonnegative + // TODO: make insteadNaNValue avalible in the outside function interface to control the cases breaking the assumption + // allocate lookup tables + vector _space_weight(d*d); + vector _space_ofs(d*d); + float* space_weight = &_space_weight[0]; + int* space_ofs = &_space_ofs[0]; + + // assign a length which is slightly more than needed + len = (float)(maxValSrc - minValSrc) * cn; + kExpNumBins = kExpNumBinsPerChannel * cn; + vector _expLUT(kExpNumBins+2); + float* expLUT = &_expLUT[0]; + + scale_index = kExpNumBins/len; + + // initialize the exp LUT + for( i = 0; i < kExpNumBins+2; i++ ) + { + if( lastExpVal > 0.f ) + { + double val = i / scale_index; + expLUT[i] = (float)std::exp(val * val * gauss_color_coeff); + lastExpVal = expLUT[i]; + } + else + expLUT[i] = 0.f; + } + + // initialize space-related bilateral filter coefficients + for( i = -radius, maxk = 0; i <= radius; i++ ) + for( j = -radius; j <= radius; j++ ) + { + double r = std::sqrt((double)i*i + (double)j*j); + if( r > radius ) + continue; + space_weight[maxk] = (float)std::exp(r*r*gauss_space_coeff); + space_ofs[maxk++] = (int)(i*(temp.step/sizeof(float)) + j*cn); + } + + // parallel_for usage + + BilateralFilter_32f_Invoker body(cn, radius, maxk, space_ofs, temp, dst, scale_index, space_weight, expLUT); + parallel_for_(Range(0, size.height), body); +} + +} + +void cv::bilateralFilter( InputArray _src, OutputArray _dst, int d, + double sigmaColor, double sigmaSpace, + int borderType ) +{ + Mat src = _src.getMat(); + _dst.create( src.size(), src.type() ); + Mat dst = _dst.getMat(); + + if( src.depth() == CV_8U ) + bilateralFilter_8u( src, dst, d, sigmaColor, sigmaSpace, borderType ); + else if( src.depth() == CV_32F ) + bilateralFilter_32f( src, dst, d, sigmaColor, sigmaSpace, borderType ); + else + CV_Error( CV_StsUnsupportedFormat, + "Bilateral filtering is only implemented for 8u and 32f images" ); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +CV_IMPL void +cvSmooth( const void* srcarr, void* dstarr, int smooth_type, + int param1, int param2, double param3, double param4 ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst0 = cv::cvarrToMat(dstarr), dst = dst0; + + CV_Assert( dst.size() == src.size() && + (smooth_type == CV_BLUR_NO_SCALE || dst.type() == src.type()) ); + + if( param2 <= 0 ) + param2 = param1; + + if( smooth_type == CV_BLUR || smooth_type == CV_BLUR_NO_SCALE ) + cv::boxFilter( src, dst, dst.depth(), cv::Size(param1, param2), cv::Point(-1,-1), + smooth_type == CV_BLUR, cv::BORDER_REPLICATE ); + else if( smooth_type == CV_GAUSSIAN ) + cv::GaussianBlur( src, dst, cv::Size(param1, param2), param3, param4, cv::BORDER_REPLICATE ); + else if( smooth_type == CV_MEDIAN ) + cv::medianBlur( src, dst, param1 ); + else + cv::bilateralFilter( src, dst, param1, param3, param4, cv::BORDER_REPLICATE ); + + if( dst.data != dst0.data ) + CV_Error( CV_StsUnmatchedFormats, "The destination image does not have the proper type" ); +} + +/* End of file. */ diff --git a/imgproc/src/subdivision2d.cpp b/imgproc/src/subdivision2d.cpp new file mode 100644 index 0000000..2cfc489 --- /dev/null +++ b/imgproc/src/subdivision2d.cpp @@ -0,0 +1,827 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "precomp.hpp" + +namespace cv +{ + +int Subdiv2D::nextEdge(int edge) const +{ + CV_DbgAssert((size_t)(edge >> 2) < qedges.size()); + return qedges[edge >> 2].next[edge & 3]; +} + +int Subdiv2D::rotateEdge(int edge, int rotate) const +{ + return (edge & ~3) + ((edge + rotate) & 3); +} + +int Subdiv2D::symEdge(int edge) const +{ + return edge ^ 2; +} + +int Subdiv2D::getEdge(int edge, int nextEdgeType) const +{ + CV_DbgAssert((size_t)(edge >> 2) < qedges.size()); + edge = qedges[edge >> 2].next[(edge + nextEdgeType) & 3]; + return (edge & ~3) + ((edge + (nextEdgeType >> 4)) & 3); +} + +int Subdiv2D::edgeOrg(int edge, CV_OUT Point2f* orgpt) const +{ + CV_DbgAssert((size_t)(edge >> 2) < qedges.size()); + int vidx = qedges[edge >> 2].pt[edge & 3]; + if( orgpt ) + { + CV_DbgAssert((size_t)vidx < vtx.size()); + *orgpt = vtx[vidx].pt; + } + return vidx; +} + +int Subdiv2D::edgeDst(int edge, CV_OUT Point2f* dstpt) const +{ + CV_DbgAssert((size_t)(edge >> 2) < qedges.size()); + int vidx = qedges[edge >> 2].pt[(edge + 2) & 3]; + if( dstpt ) + { + CV_DbgAssert((size_t)vidx < vtx.size()); + *dstpt = vtx[vidx].pt; + } + return vidx; +} + + +Point2f Subdiv2D::getVertex(int vertex, CV_OUT int* firstEdge) const +{ + CV_DbgAssert((size_t)vertex < vtx.size()); + if( firstEdge ) + *firstEdge = vtx[vertex].firstEdge; + return vtx[vertex].pt; +} + + +Subdiv2D::Subdiv2D() +{ + validGeometry = false; + freeQEdge = 0; + freePoint = 0; + recentEdge = 0; +} + +Subdiv2D::Subdiv2D(Rect rect) +{ + validGeometry = false; + freeQEdge = 0; + freePoint = 0; + recentEdge = 0; + + initDelaunay(rect); +} + + +Subdiv2D::QuadEdge::QuadEdge() +{ + next[0] = next[1] = next[2] = next[3] = 0; + pt[0] = pt[1] = pt[2] = pt[3] = 0; +} + +Subdiv2D::QuadEdge::QuadEdge(int edgeidx) +{ + CV_DbgAssert((edgeidx & 3) == 0); + next[0] = edgeidx; + next[1] = edgeidx+3; + next[2] = edgeidx+2; + next[3] = edgeidx+1; + + pt[0] = pt[1] = pt[2] = pt[3] = 0; +} + +bool Subdiv2D::QuadEdge::isfree() const +{ + return next[0] <= 0; +} + +Subdiv2D::Vertex::Vertex() +{ + firstEdge = 0; + type = -1; +} + +Subdiv2D::Vertex::Vertex(Point2f _pt, bool _isvirtual, int _firstEdge) +{ + firstEdge = _firstEdge; + type = (int)_isvirtual; + pt = _pt; +} + +bool Subdiv2D::Vertex::isvirtual() const +{ + return type > 0; +} + +bool Subdiv2D::Vertex::isfree() const +{ + return type < 0; +} + +void Subdiv2D::splice( int edgeA, int edgeB ) +{ + int& a_next = qedges[edgeA >> 2].next[edgeA & 3]; + int& b_next = qedges[edgeB >> 2].next[edgeB & 3]; + int a_rot = rotateEdge(a_next, 1); + int b_rot = rotateEdge(b_next, 1); + int& a_rot_next = qedges[a_rot >> 2].next[a_rot & 3]; + int& b_rot_next = qedges[b_rot >> 2].next[b_rot & 3]; + std::swap(a_next, b_next); + std::swap(a_rot_next, b_rot_next); +} + +void Subdiv2D::setEdgePoints(int edge, int orgPt, int dstPt) +{ + qedges[edge >> 2].pt[edge & 3] = orgPt; + qedges[edge >> 2].pt[(edge + 2) & 3] = dstPt; + vtx[orgPt].firstEdge = edge; + vtx[dstPt].firstEdge = edge ^ 2; +} + +int Subdiv2D::connectEdges( int edgeA, int edgeB ) +{ + int edge = newEdge(); + + splice(edge, getEdge(edgeA, NEXT_AROUND_LEFT)); + splice(symEdge(edge), edgeB); + + setEdgePoints(edge, edgeDst(edgeA), edgeOrg(edgeB)); + return edge; +} + +void Subdiv2D::swapEdges( int edge ) +{ + int sedge = symEdge(edge); + int a = getEdge(edge, PREV_AROUND_ORG); + int b = getEdge(sedge, PREV_AROUND_ORG); + + splice(edge, a); + splice(sedge, b); + + setEdgePoints(edge, edgeDst(a), edgeDst(b)); + + splice(edge, getEdge(a, NEXT_AROUND_LEFT)); + splice(sedge, getEdge(b, NEXT_AROUND_LEFT)); +} + +static double triangleArea( Point2f a, Point2f b, Point2f c ) +{ + return ((double)b.x - a.x) * ((double)c.y - a.y) - ((double)b.y - a.y) * ((double)c.x - a.x); +} + +int Subdiv2D::isRightOf(Point2f pt, int edge) const +{ + Point2f org, dst; + edgeOrg(edge, &org); + edgeDst(edge, &dst); + double cw_area = triangleArea( pt, dst, org ); + + return (cw_area > 0) - (cw_area < 0); +} + +int Subdiv2D::newEdge() +{ + if( freeQEdge <= 0 ) + { + qedges.push_back(QuadEdge()); + freeQEdge = (int)(qedges.size()-1); + } + int edge = freeQEdge*4; + freeQEdge = qedges[edge >> 2].next[1]; + qedges[edge >> 2] = QuadEdge(edge); + return edge; +} + +void Subdiv2D::deleteEdge(int edge) +{ + CV_DbgAssert((size_t)(edge >> 2) < (size_t)qedges.size()); + splice( edge, getEdge(edge, PREV_AROUND_ORG) ); + int sedge = symEdge(edge); + splice(sedge, getEdge(sedge, PREV_AROUND_ORG) ); + + edge >>= 2; + qedges[edge].next[0] = 0; + qedges[edge].next[1] = freeQEdge; + freeQEdge = edge; +} + +int Subdiv2D::newPoint(Point2f pt, bool isvirtual, int firstEdge) +{ + if( freePoint == 0 ) + { + vtx.push_back(Vertex()); + freePoint = (int)(vtx.size()-1); + } + int vidx = freePoint; + freePoint = vtx[vidx].firstEdge; + vtx[vidx] = Vertex(pt, isvirtual, firstEdge); + + return vidx; +} + +void Subdiv2D::deletePoint(int vidx) +{ + CV_DbgAssert( (size_t)vidx < vtx.size() ); + vtx[vidx].firstEdge = freePoint; + vtx[vidx].type = -1; + freePoint = vidx; +} + +int Subdiv2D::locate(Point2f pt, int& _edge, int& _vertex) +{ + int vertex = 0; + + int i, maxEdges = (int)(qedges.size() * 4); + + if( qedges.size() < (size_t)4 ) + CV_Error( CV_StsError, "Subdivision is empty" ); + + if( pt.x < topLeft.x || pt.y < topLeft.y || pt.x >= bottomRight.x || pt.y >= bottomRight.y ) + CV_Error( CV_StsOutOfRange, "" ); + + int edge = recentEdge; + CV_Assert(edge > 0); + + int location = PTLOC_ERROR; + + int right_of_curr = isRightOf(pt, edge); + if( right_of_curr > 0 ) + { + edge = symEdge(edge); + right_of_curr = -right_of_curr; + } + + for( i = 0; i < maxEdges; i++ ) + { + int onext_edge = nextEdge( edge ); + int dprev_edge = getEdge( edge, PREV_AROUND_DST ); + + int right_of_onext = isRightOf( pt, onext_edge ); + int right_of_dprev = isRightOf( pt, dprev_edge ); + + if( right_of_dprev > 0 ) + { + if( right_of_onext > 0 || (right_of_onext == 0 && right_of_curr == 0) ) + { + location = PTLOC_INSIDE; + break; + } + else + { + right_of_curr = right_of_onext; + edge = onext_edge; + } + } + else + { + if( right_of_onext > 0 ) + { + if( right_of_dprev == 0 && right_of_curr == 0 ) + { + location = PTLOC_INSIDE; + break; + } + else + { + right_of_curr = right_of_dprev; + edge = dprev_edge; + } + } + else if( right_of_curr == 0 && + isRightOf( vtx[edgeDst(onext_edge)].pt, edge ) >= 0 ) + { + edge = symEdge( edge ); + } + else + { + right_of_curr = right_of_onext; + edge = onext_edge; + } + } + } + + recentEdge = edge; + + if( location == PTLOC_INSIDE ) + { + Point2f org_pt, dst_pt; + edgeOrg(edge, &org_pt); + edgeDst(edge, &dst_pt); + + double t1 = fabs( pt.x - org_pt.x ); + t1 += fabs( pt.y - org_pt.y ); + double t2 = fabs( pt.x - dst_pt.x ); + t2 += fabs( pt.y - dst_pt.y ); + double t3 = fabs( org_pt.x - dst_pt.x ); + t3 += fabs( org_pt.y - dst_pt.y ); + + if( t1 < FLT_EPSILON ) + { + location = PTLOC_VERTEX; + vertex = edgeOrg( edge ); + edge = 0; + } + else if( t2 < FLT_EPSILON ) + { + location = PTLOC_VERTEX; + vertex = edgeDst( edge ); + edge = 0; + } + else if( (t1 < t3 || t2 < t3) && + fabs( triangleArea( pt, org_pt, dst_pt )) < FLT_EPSILON ) + { + location = PTLOC_ON_EDGE; + vertex = 0; + } + } + + if( location == PTLOC_ERROR ) + { + edge = 0; + vertex = 0; + } + + _edge = edge; + _vertex = vertex; + + return location; +} + + +inline int +isPtInCircle3( Point2f pt, Point2f a, Point2f b, Point2f c) +{ + const double eps = FLT_EPSILON*0.125; + double val = ((double)a.x * a.x + (double)a.y * a.y) * triangleArea( b, c, pt ); + val -= ((double)b.x * b.x + (double)b.y * b.y) * triangleArea( a, c, pt ); + val += ((double)c.x * c.x + (double)c.y * c.y) * triangleArea( a, b, pt ); + val -= ((double)pt.x * pt.x + (double)pt.y * pt.y) * triangleArea( a, b, c ); + + return val > eps ? 1 : val < -eps ? -1 : 0; +} + + +int Subdiv2D::insert(Point2f pt) +{ + int curr_point = 0, curr_edge = 0, deleted_edge = 0; + int location = locate( pt, curr_edge, curr_point ); + + if( location == PTLOC_ERROR ) + CV_Error( CV_StsBadSize, "" ); + + if( location == PTLOC_OUTSIDE_RECT ) + CV_Error( CV_StsOutOfRange, "" ); + + if( location == PTLOC_VERTEX ) + return curr_point; + + if( location == PTLOC_ON_EDGE ) + { + deleted_edge = curr_edge; + recentEdge = curr_edge = getEdge( curr_edge, PREV_AROUND_ORG ); + deleteEdge(deleted_edge); + } + else if( location == PTLOC_INSIDE ) + ; + else + CV_Error_(CV_StsError, ("Subdiv2D::locate returned invalid location = %d", location) ); + + assert( curr_edge != 0 ); + validGeometry = false; + + curr_point = newPoint(pt, false); + int base_edge = newEdge(); + int first_point = edgeOrg(curr_edge); + setEdgePoints(base_edge, first_point, curr_point); + splice(base_edge, curr_edge); + + do + { + base_edge = connectEdges( curr_edge, symEdge(base_edge) ); + curr_edge = getEdge(base_edge, PREV_AROUND_ORG); + } + while( edgeDst(curr_edge) != first_point ); + + curr_edge = getEdge( base_edge, PREV_AROUND_ORG ); + + int i, max_edges = (int)(qedges.size()*4); + + for( i = 0; i < max_edges; i++ ) + { + int temp_dst = 0, curr_org = 0, curr_dst = 0; + int temp_edge = getEdge( curr_edge, PREV_AROUND_ORG ); + + temp_dst = edgeDst( temp_edge ); + curr_org = edgeOrg( curr_edge ); + curr_dst = edgeDst( curr_edge ); + + if( isRightOf( vtx[temp_dst].pt, curr_edge ) > 0 && + isPtInCircle3( vtx[curr_org].pt, vtx[temp_dst].pt, + vtx[curr_dst].pt, vtx[curr_point].pt ) < 0 ) + { + swapEdges( curr_edge ); + curr_edge = getEdge( curr_edge, PREV_AROUND_ORG ); + } + else if( curr_org == first_point ) + break; + else + curr_edge = getEdge( nextEdge( curr_edge ), PREV_AROUND_LEFT ); + } + + return curr_point; +} + +void Subdiv2D::insert(const vector& ptvec) +{ + for( size_t i = 0; i < ptvec.size(); i++ ) + insert(ptvec[i]); +} + +void Subdiv2D::initDelaunay( Rect rect ) +{ + float big_coord = 3.f * MAX( rect.width, rect.height ); + float rx = (float)rect.x; + float ry = (float)rect.y; + + vtx.clear(); + qedges.clear(); + + recentEdge = 0; + validGeometry = false; + + topLeft = Point2f( rx, ry ); + bottomRight = Point2f( rx + rect.width, ry + rect.height ); + + Point2f ppA( rx + big_coord, ry ); + Point2f ppB( rx, ry + big_coord ); + Point2f ppC( rx - big_coord, ry - big_coord ); + + vtx.push_back(Vertex()); + qedges.push_back(QuadEdge()); + + freeQEdge = 0; + freePoint = 0; + + int pA = newPoint(ppA, false); + int pB = newPoint(ppB, false); + int pC = newPoint(ppC, false); + + int edge_AB = newEdge(); + int edge_BC = newEdge(); + int edge_CA = newEdge(); + + setEdgePoints( edge_AB, pA, pB ); + setEdgePoints( edge_BC, pB, pC ); + setEdgePoints( edge_CA, pC, pA ); + + splice( edge_AB, symEdge( edge_CA )); + splice( edge_BC, symEdge( edge_AB )); + splice( edge_CA, symEdge( edge_BC )); + + recentEdge = edge_AB; +} + + +void Subdiv2D::clearVoronoi() +{ + size_t i, total = qedges.size(); + + for( i = 0; i < total; i++ ) + qedges[i].pt[1] = qedges[i].pt[3] = 0; + + total = vtx.size(); + for( i = 0; i < total; i++ ) + { + if( vtx[i].isvirtual() ) + deletePoint((int)i); + } + + validGeometry = false; +} + + +static Point2f computeVoronoiPoint(Point2f org0, Point2f dst0, Point2f org1, Point2f dst1) +{ + double a0 = dst0.x - org0.x; + double b0 = dst0.y - org0.y; + double c0 = -0.5*(a0 * (dst0.x + org0.x) + b0 * (dst0.y + org0.y)); + + double a1 = dst1.x - org1.x; + double b1 = dst1.y - org1.y; + double c1 = -0.5*(a1 * (dst1.x + org1.x) + b1 * (dst1.y + org1.y)); + + double det = a0 * b1 - a1 * b0; + + if( det != 0 ) + { + det = 1. / det; + return Point2f((float) ((b0 * c1 - b1 * c0) * det), + (float) ((a1 * c0 - a0 * c1) * det)); + } + + return Point2f(FLT_MAX, FLT_MAX); +} + + +void Subdiv2D::calcVoronoi() +{ + // check if it is already calculated + if( validGeometry ) + return; + + clearVoronoi(); + int i, total = (int)qedges.size(); + + // loop through all quad-edges, except for the first 3 (#1, #2, #3 - 0 is reserved for "NULL" pointer) + for( i = 4; i < total; i++ ) + { + QuadEdge& quadedge = qedges[i]; + + if( quadedge.isfree() ) + continue; + + int edge0 = (int)(i*4); + Point2f org0, dst0, org1, dst1; + + if( !quadedge.pt[3] ) + { + int edge1 = getEdge( edge0, NEXT_AROUND_LEFT ); + int edge2 = getEdge( edge1, NEXT_AROUND_LEFT ); + + edgeOrg(edge0, &org0); + edgeDst(edge0, &dst0); + edgeOrg(edge1, &org1); + edgeDst(edge1, &dst1); + + Point2f virt_point = computeVoronoiPoint(org0, dst0, org1, dst1); + + if( fabs( virt_point.x ) < FLT_MAX * 0.5 && + fabs( virt_point.y ) < FLT_MAX * 0.5 ) + { + quadedge.pt[3] = qedges[edge1 >> 2].pt[3 - (edge1 & 2)] = + qedges[edge2 >> 2].pt[3 - (edge2 & 2)] = newPoint(virt_point, true); + } + } + + if( !quadedge.pt[1] ) + { + int edge1 = getEdge( edge0, NEXT_AROUND_RIGHT ); + int edge2 = getEdge( edge1, NEXT_AROUND_RIGHT ); + + edgeOrg(edge0, &org0); + edgeDst(edge0, &dst0); + edgeOrg(edge1, &org1); + edgeDst(edge1, &dst1); + + Point2f virt_point = computeVoronoiPoint(org0, dst0, org1, dst1); + + if( fabs( virt_point.x ) < FLT_MAX * 0.5 && + fabs( virt_point.y ) < FLT_MAX * 0.5 ) + { + quadedge.pt[1] = qedges[edge1 >> 2].pt[1 + (edge1 & 2)] = + qedges[edge2 >> 2].pt[1 + (edge2 & 2)] = newPoint(virt_point, true); + } + } + } + + validGeometry = true; +} + + +static int +isRightOf2( const Point2f& pt, const Point2f& org, const Point2f& diff ) +{ + double cw_area = ((double)org.x - pt.x)*diff.y - ((double)org.y - pt.y)*diff.x; + return (cw_area > 0) - (cw_area < 0); +} + + +int Subdiv2D::findNearest(Point2f pt, Point2f* nearestPt) +{ + if( !validGeometry ) + calcVoronoi(); + + int vertex = 0, edge = 0; + int loc = locate( pt, edge, vertex ); + + if( loc != PTLOC_ON_EDGE && loc != PTLOC_INSIDE ) + return vertex; + + vertex = 0; + + Point2f start; + edgeOrg(edge, &start); + Point2f diff = pt - start; + + edge = rotateEdge(edge, 1); + + int i, total = (int)vtx.size(); + + for( i = 0; i < total; i++ ) + { + Point2f t; + + for(;;) + { + CV_Assert( edgeDst(edge, &t) > 0 ); + if( isRightOf2( t, start, diff ) >= 0 ) + break; + + edge = getEdge( edge, NEXT_AROUND_LEFT ); + } + + for(;;) + { + CV_Assert( edgeOrg( edge, &t ) > 0 ); + + if( isRightOf2( t, start, diff ) < 0 ) + break; + + edge = getEdge( edge, PREV_AROUND_LEFT ); + } + + Point2f tempDiff; + edgeDst(edge, &tempDiff); + edgeOrg(edge, &t); + tempDiff -= t; + + if( isRightOf2( pt, t, tempDiff ) >= 0 ) + { + vertex = edgeOrg(rotateEdge( edge, 3 )); + break; + } + + edge = symEdge( edge ); + } + + if( nearestPt && vertex > 0 ) + *nearestPt = vtx[vertex].pt; + + return vertex; +} + +void Subdiv2D::getEdgeList(vector& edgeList) const +{ + edgeList.clear(); + + for( size_t i = 4; i < qedges.size(); i++ ) + { + if( qedges[i].isfree() ) + continue; + if( qedges[i].pt[0] > 0 && qedges[i].pt[2] > 0 ) + { + Point2f org = vtx[qedges[i].pt[0]].pt; + Point2f dst = vtx[qedges[i].pt[2]].pt; + edgeList.push_back(Vec4f(org.x, org.y, dst.x, dst.y)); + } + } +} + +void Subdiv2D::getTriangleList(vector& triangleList) const +{ + triangleList.clear(); + int i, total = (int)(qedges.size()*4); + vector edgemask(total, false); + + for( i = 4; i < total; i += 2 ) + { + if( edgemask[i] ) + continue; + Point2f a, b, c; + int edge = i; + edgeOrg(edge, &a); + edgemask[edge] = true; + edge = getEdge(edge, NEXT_AROUND_LEFT); + edgeOrg(edge, &b); + edgemask[edge] = true; + edge = getEdge(edge, NEXT_AROUND_LEFT); + edgeOrg(edge, &c); + edgemask[edge] = true; + triangleList.push_back(Vec6f(a.x, a.y, b.x, b.y, c.x, c.y)); + } +} + +void Subdiv2D::getVoronoiFacetList(const vector& idx, + CV_OUT vector >& facetList, + CV_OUT vector& facetCenters) +{ + calcVoronoi(); + facetList.clear(); + facetCenters.clear(); + + vector buf; + + size_t i, total; + if( idx.empty() ) + i = 4, total = vtx.size(); + else + i = 0, total = idx.size(); + + for( ; i < total; i++ ) + { + int k = idx.empty() ? (int)i : idx[i]; + + if( vtx[k].isfree() || vtx[k].isvirtual() ) + continue; + int edge = rotateEdge(vtx[k].firstEdge, 1), t = edge; + + // gather points + buf.clear(); + do + { + buf.push_back(vtx[edgeOrg(t)].pt); + t = getEdge( t, NEXT_AROUND_LEFT ); + } + while( t != edge ); + + facetList.push_back(buf); + facetCenters.push_back(vtx[k].pt); + } +} + + +void Subdiv2D::checkSubdiv() const +{ + int i, j, total = (int)qedges.size(); + + for( i = 0; i < total; i++ ) + { + const QuadEdge& qe = qedges[i]; + + if( qe.isfree() ) + continue; + + for( j = 0; j < 4; j++ ) + { + int e = (int)(i*4 + j); + int o_next = nextEdge(e); + int o_prev = getEdge(e, PREV_AROUND_ORG ); + int d_prev = getEdge(e, PREV_AROUND_DST ); + int d_next = getEdge(e, NEXT_AROUND_DST ); + + // check points + CV_Assert( edgeOrg(e) == edgeOrg(o_next)); + CV_Assert( edgeOrg(e) == edgeOrg(o_prev)); + CV_Assert( edgeDst(e) == edgeDst(d_next)); + CV_Assert( edgeDst(e) == edgeDst(d_prev)); + + if( j % 2 == 0 ) + { + CV_Assert( edgeDst(o_next) == edgeOrg(d_prev)); + CV_Assert( edgeDst(o_prev) == edgeOrg(d_next)); + CV_Assert( getEdge(getEdge(getEdge(e,NEXT_AROUND_LEFT),NEXT_AROUND_LEFT),NEXT_AROUND_LEFT) == e ); + CV_Assert( getEdge(getEdge(getEdge(e,NEXT_AROUND_RIGHT),NEXT_AROUND_RIGHT),NEXT_AROUND_RIGHT) == e); + } + } + } +} + +} + +/* End of file. */ diff --git a/imgproc/src/sumpixels.cpp b/imgproc/src/sumpixels.cpp new file mode 100644 index 0000000..b441970 --- /dev/null +++ b/imgproc/src/sumpixels.cpp @@ -0,0 +1,309 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +namespace cv +{ + +template +void integral_( const T* src, size_t _srcstep, ST* sum, size_t _sumstep, + QT* sqsum, size_t _sqsumstep, ST* tilted, size_t _tiltedstep, + Size size, int cn ) +{ + int x, y, k; + + int srcstep = (int)(_srcstep/sizeof(T)); + int sumstep = (int)(_sumstep/sizeof(ST)); + int tiltedstep = (int)(_tiltedstep/sizeof(ST)); + int sqsumstep = (int)(_sqsumstep/sizeof(QT)); + + size.width *= cn; + + memset( sum, 0, (size.width+cn)*sizeof(sum[0])); + sum += sumstep + cn; + + if( sqsum ) + { + memset( sqsum, 0, (size.width+cn)*sizeof(sqsum[0])); + sqsum += sqsumstep + cn; + } + + if( tilted ) + { + memset( tilted, 0, (size.width+cn)*sizeof(tilted[0])); + tilted += tiltedstep + cn; + } + + if( sqsum == 0 && tilted == 0 ) + { + for( y = 0; y < size.height; y++, src += srcstep - cn, sum += sumstep - cn ) + { + for( k = 0; k < cn; k++, src++, sum++ ) + { + ST s = sum[-cn] = 0; + for( x = 0; x < size.width; x += cn ) + { + s += src[x]; + sum[x] = sum[x - sumstep] + s; + } + } + } + } + else if( tilted == 0 ) + { + for( y = 0; y < size.height; y++, src += srcstep - cn, + sum += sumstep - cn, sqsum += sqsumstep - cn ) + { + for( k = 0; k < cn; k++, src++, sum++, sqsum++ ) + { + ST s = sum[-cn] = 0; + QT sq = sqsum[-cn] = 0; + for( x = 0; x < size.width; x += cn ) + { + T it = src[x]; + s += it; + sq += (QT)it*it; + ST t = sum[x - sumstep] + s; + QT tq = sqsum[x - sqsumstep] + sq; + sum[x] = t; + sqsum[x] = tq; + } + } + } + } + else + { + AutoBuffer _buf(size.width+cn); + ST* buf = _buf; + ST s; + QT sq; + for( k = 0; k < cn; k++, src++, sum++, tilted++, buf++ ) + { + sum[-cn] = tilted[-cn] = 0; + + for( x = 0, s = 0, sq = 0; x < size.width; x += cn ) + { + T it = src[x]; + buf[x] = tilted[x] = it; + s += it; + sq += (QT)it*it; + sum[x] = s; + if( sqsum ) + sqsum[x] = sq; + } + + if( size.width == cn ) + buf[cn] = 0; + + if( sqsum ) + { + sqsum[-cn] = 0; + sqsum++; + } + } + + for( y = 1; y < size.height; y++ ) + { + src += srcstep - cn; + sum += sumstep - cn; + tilted += tiltedstep - cn; + buf += -cn; + + if( sqsum ) + sqsum += sqsumstep - cn; + + for( k = 0; k < cn; k++, src++, sum++, tilted++, buf++ ) + { + T it = src[0]; + ST t0 = s = it; + QT tq0 = sq = (QT)it*it; + + sum[-cn] = 0; + if( sqsum ) + sqsum[-cn] = 0; + tilted[-cn] = tilted[-tiltedstep]; + + sum[0] = sum[-sumstep] + t0; + if( sqsum ) + sqsum[0] = sqsum[-sqsumstep] + tq0; + tilted[0] = tilted[-tiltedstep] + t0 + buf[cn]; + + for( x = cn; x < size.width - cn; x += cn ) + { + ST t1 = buf[x]; + buf[x - cn] = t1 + t0; + t0 = it = src[x]; + tq0 = (QT)it*it; + s += t0; + sq += tq0; + sum[x] = sum[x - sumstep] + s; + if( sqsum ) + sqsum[x] = sqsum[x - sqsumstep] + sq; + t1 += buf[x + cn] + t0 + tilted[x - tiltedstep - cn]; + tilted[x] = t1; + } + + if( size.width > cn ) + { + ST t1 = buf[x]; + buf[x - cn] = t1 + t0; + t0 = it = src[x]; + tq0 = (QT)it*it; + s += t0; + sq += tq0; + sum[x] = sum[x - sumstep] + s; + if( sqsum ) + sqsum[x] = sqsum[x - sqsumstep] + sq; + tilted[x] = t0 + t1 + tilted[x - tiltedstep - cn]; + buf[x] = t0; + } + + if( sqsum ) + sqsum++; + } + } + } +} + + +#define DEF_INTEGRAL_FUNC(suffix, T, ST, QT) \ +static void integral_##suffix( T* src, size_t srcstep, ST* sum, size_t sumstep, QT* sqsum, size_t sqsumstep, \ + ST* tilted, size_t tiltedstep, Size size, int cn ) \ +{ integral_(src, srcstep, sum, sumstep, sqsum, sqsumstep, tilted, tiltedstep, size, cn); } + +DEF_INTEGRAL_FUNC(8u32s, uchar, int, double) +DEF_INTEGRAL_FUNC(8u32f, uchar, float, double) +DEF_INTEGRAL_FUNC(8u64f, uchar, double, double) +DEF_INTEGRAL_FUNC(32f, float, float, double) +DEF_INTEGRAL_FUNC(32f64f, float, double, double) +DEF_INTEGRAL_FUNC(64f, double, double, double) + +typedef void (*IntegralFunc)(const uchar* src, size_t srcstep, uchar* sum, size_t sumstep, + uchar* sqsum, size_t sqsumstep, uchar* tilted, size_t tstep, + Size size, int cn ); + +} + + +void cv::integral( InputArray _src, OutputArray _sum, OutputArray _sqsum, OutputArray _tilted, int sdepth ) +{ + Mat src = _src.getMat(), sum, sqsum, tilted; + int depth = src.depth(), cn = src.channels(); + Size isize(src.cols + 1, src.rows+1); + + if( sdepth <= 0 ) + sdepth = depth == CV_8U ? CV_32S : CV_64F; + sdepth = CV_MAT_DEPTH(sdepth); + _sum.create( isize, CV_MAKETYPE(sdepth, cn) ); + sum = _sum.getMat(); + + if( _tilted.needed() ) + { + _tilted.create( isize, CV_MAKETYPE(sdepth, cn) ); + tilted = _tilted.getMat(); + } + + if( _sqsum.needed() ) + { + _sqsum.create( isize, CV_MAKETYPE(CV_64F, cn) ); + sqsum = _sqsum.getMat(); + } + + IntegralFunc func = 0; + + if( depth == CV_8U && sdepth == CV_32S ) + func = (IntegralFunc)GET_OPTIMIZED(integral_8u32s); + else if( depth == CV_8U && sdepth == CV_32F ) + func = (IntegralFunc)integral_8u32f; + else if( depth == CV_8U && sdepth == CV_64F ) + func = (IntegralFunc)integral_8u64f; + else if( depth == CV_32F && sdepth == CV_32F ) + func = (IntegralFunc)integral_32f; + else if( depth == CV_32F && sdepth == CV_64F ) + func = (IntegralFunc)integral_32f64f; + else if( depth == CV_64F && sdepth == CV_64F ) + func = (IntegralFunc)integral_64f; + else + CV_Error( CV_StsUnsupportedFormat, "" ); + + func( src.data, src.step, sum.data, sum.step, sqsum.data, sqsum.step, + tilted.data, tilted.step, src.size(), cn ); +} + +void cv::integral( InputArray src, OutputArray sum, int sdepth ) +{ + integral( src, sum, noArray(), noArray(), sdepth ); +} + +void cv::integral( InputArray src, OutputArray sum, OutputArray sqsum, int sdepth ) +{ + integral( src, sum, sqsum, noArray(), sdepth ); +} + + +CV_IMPL void +cvIntegral( const CvArr* image, CvArr* sumImage, + CvArr* sumSqImage, CvArr* tiltedSumImage ) +{ + cv::Mat src = cv::cvarrToMat(image), sum = cv::cvarrToMat(sumImage), sum0 = sum; + cv::Mat sqsum0, sqsum, tilted0, tilted; + cv::Mat *psqsum = 0, *ptilted = 0; + + if( sumSqImage ) + { + sqsum0 = sqsum = cv::cvarrToMat(sumSqImage); + psqsum = &sqsum; + } + + if( tiltedSumImage ) + { + tilted0 = tilted = cv::cvarrToMat(tiltedSumImage); + ptilted = &tilted; + } + cv::integral( src, sum, psqsum ? cv::_OutputArray(*psqsum) : cv::_OutputArray(), + ptilted ? cv::_OutputArray(*ptilted) : cv::_OutputArray(), sum.depth() ); + + CV_Assert( sum.data == sum0.data && sqsum.data == sqsum0.data && tilted.data == tilted0.data ); +} + +/* End of file. */ diff --git a/imgproc/src/tables.cpp b/imgproc/src/tables.cpp new file mode 100644 index 0000000..20acf88 --- /dev/null +++ b/imgproc/src/tables.cpp @@ -0,0 +1,214 @@ +/* //////////////////////////////////////////////////////////////////// +// +// CvMat helper tables +// +// */ + +#include "precomp.hpp" + +const float icv8x32fTab_cv[] = +{ + -256.f, -255.f, -254.f, -253.f, -252.f, -251.f, -250.f, -249.f, + -248.f, -247.f, -246.f, -245.f, -244.f, -243.f, -242.f, -241.f, + -240.f, -239.f, -238.f, -237.f, -236.f, -235.f, -234.f, -233.f, + -232.f, -231.f, -230.f, -229.f, -228.f, -227.f, -226.f, -225.f, + -224.f, -223.f, -222.f, -221.f, -220.f, -219.f, -218.f, -217.f, + -216.f, -215.f, -214.f, -213.f, -212.f, -211.f, -210.f, -209.f, + -208.f, -207.f, -206.f, -205.f, -204.f, -203.f, -202.f, -201.f, + -200.f, -199.f, -198.f, -197.f, -196.f, -195.f, -194.f, -193.f, + -192.f, -191.f, -190.f, -189.f, -188.f, -187.f, -186.f, -185.f, + -184.f, -183.f, -182.f, -181.f, -180.f, -179.f, -178.f, -177.f, + -176.f, -175.f, -174.f, -173.f, -172.f, -171.f, -170.f, -169.f, + -168.f, -167.f, -166.f, -165.f, -164.f, -163.f, -162.f, -161.f, + -160.f, -159.f, -158.f, -157.f, -156.f, -155.f, -154.f, -153.f, + -152.f, -151.f, -150.f, -149.f, -148.f, -147.f, -146.f, -145.f, + -144.f, -143.f, -142.f, -141.f, -140.f, -139.f, -138.f, -137.f, + -136.f, -135.f, -134.f, -133.f, -132.f, -131.f, -130.f, -129.f, + -128.f, -127.f, -126.f, -125.f, -124.f, -123.f, -122.f, -121.f, + -120.f, -119.f, -118.f, -117.f, -116.f, -115.f, -114.f, -113.f, + -112.f, -111.f, -110.f, -109.f, -108.f, -107.f, -106.f, -105.f, + -104.f, -103.f, -102.f, -101.f, -100.f, -99.f, -98.f, -97.f, + -96.f, -95.f, -94.f, -93.f, -92.f, -91.f, -90.f, -89.f, + -88.f, -87.f, -86.f, -85.f, -84.f, -83.f, -82.f, -81.f, + -80.f, -79.f, -78.f, -77.f, -76.f, -75.f, -74.f, -73.f, + -72.f, -71.f, -70.f, -69.f, -68.f, -67.f, -66.f, -65.f, + -64.f, -63.f, -62.f, -61.f, -60.f, -59.f, -58.f, -57.f, + -56.f, -55.f, -54.f, -53.f, -52.f, -51.f, -50.f, -49.f, + -48.f, -47.f, -46.f, -45.f, -44.f, -43.f, -42.f, -41.f, + -40.f, -39.f, -38.f, -37.f, -36.f, -35.f, -34.f, -33.f, + -32.f, -31.f, -30.f, -29.f, -28.f, -27.f, -26.f, -25.f, + -24.f, -23.f, -22.f, -21.f, -20.f, -19.f, -18.f, -17.f, + -16.f, -15.f, -14.f, -13.f, -12.f, -11.f, -10.f, -9.f, + -8.f, -7.f, -6.f, -5.f, -4.f, -3.f, -2.f, -1.f, + 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, + 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f, + 16.f, 17.f, 18.f, 19.f, 20.f, 21.f, 22.f, 23.f, + 24.f, 25.f, 26.f, 27.f, 28.f, 29.f, 30.f, 31.f, + 32.f, 33.f, 34.f, 35.f, 36.f, 37.f, 38.f, 39.f, + 40.f, 41.f, 42.f, 43.f, 44.f, 45.f, 46.f, 47.f, + 48.f, 49.f, 50.f, 51.f, 52.f, 53.f, 54.f, 55.f, + 56.f, 57.f, 58.f, 59.f, 60.f, 61.f, 62.f, 63.f, + 64.f, 65.f, 66.f, 67.f, 68.f, 69.f, 70.f, 71.f, + 72.f, 73.f, 74.f, 75.f, 76.f, 77.f, 78.f, 79.f, + 80.f, 81.f, 82.f, 83.f, 84.f, 85.f, 86.f, 87.f, + 88.f, 89.f, 90.f, 91.f, 92.f, 93.f, 94.f, 95.f, + 96.f, 97.f, 98.f, 99.f, 100.f, 101.f, 102.f, 103.f, + 104.f, 105.f, 106.f, 107.f, 108.f, 109.f, 110.f, 111.f, + 112.f, 113.f, 114.f, 115.f, 116.f, 117.f, 118.f, 119.f, + 120.f, 121.f, 122.f, 123.f, 124.f, 125.f, 126.f, 127.f, + 128.f, 129.f, 130.f, 131.f, 132.f, 133.f, 134.f, 135.f, + 136.f, 137.f, 138.f, 139.f, 140.f, 141.f, 142.f, 143.f, + 144.f, 145.f, 146.f, 147.f, 148.f, 149.f, 150.f, 151.f, + 152.f, 153.f, 154.f, 155.f, 156.f, 157.f, 158.f, 159.f, + 160.f, 161.f, 162.f, 163.f, 164.f, 165.f, 166.f, 167.f, + 168.f, 169.f, 170.f, 171.f, 172.f, 173.f, 174.f, 175.f, + 176.f, 177.f, 178.f, 179.f, 180.f, 181.f, 182.f, 183.f, + 184.f, 185.f, 186.f, 187.f, 188.f, 189.f, 190.f, 191.f, + 192.f, 193.f, 194.f, 195.f, 196.f, 197.f, 198.f, 199.f, + 200.f, 201.f, 202.f, 203.f, 204.f, 205.f, 206.f, 207.f, + 208.f, 209.f, 210.f, 211.f, 212.f, 213.f, 214.f, 215.f, + 216.f, 217.f, 218.f, 219.f, 220.f, 221.f, 222.f, 223.f, + 224.f, 225.f, 226.f, 227.f, 228.f, 229.f, 230.f, 231.f, + 232.f, 233.f, 234.f, 235.f, 236.f, 237.f, 238.f, 239.f, + 240.f, 241.f, 242.f, 243.f, 244.f, 245.f, 246.f, 247.f, + 248.f, 249.f, 250.f, 251.f, 252.f, 253.f, 254.f, 255.f, + 256.f, 257.f, 258.f, 259.f, 260.f, 261.f, 262.f, 263.f, + 264.f, 265.f, 266.f, 267.f, 268.f, 269.f, 270.f, 271.f, + 272.f, 273.f, 274.f, 275.f, 276.f, 277.f, 278.f, 279.f, + 280.f, 281.f, 282.f, 283.f, 284.f, 285.f, 286.f, 287.f, + 288.f, 289.f, 290.f, 291.f, 292.f, 293.f, 294.f, 295.f, + 296.f, 297.f, 298.f, 299.f, 300.f, 301.f, 302.f, 303.f, + 304.f, 305.f, 306.f, 307.f, 308.f, 309.f, 310.f, 311.f, + 312.f, 313.f, 314.f, 315.f, 316.f, 317.f, 318.f, 319.f, + 320.f, 321.f, 322.f, 323.f, 324.f, 325.f, 326.f, 327.f, + 328.f, 329.f, 330.f, 331.f, 332.f, 333.f, 334.f, 335.f, + 336.f, 337.f, 338.f, 339.f, 340.f, 341.f, 342.f, 343.f, + 344.f, 345.f, 346.f, 347.f, 348.f, 349.f, 350.f, 351.f, + 352.f, 353.f, 354.f, 355.f, 356.f, 357.f, 358.f, 359.f, + 360.f, 361.f, 362.f, 363.f, 364.f, 365.f, 366.f, 367.f, + 368.f, 369.f, 370.f, 371.f, 372.f, 373.f, 374.f, 375.f, + 376.f, 377.f, 378.f, 379.f, 380.f, 381.f, 382.f, 383.f, + 384.f, 385.f, 386.f, 387.f, 388.f, 389.f, 390.f, 391.f, + 392.f, 393.f, 394.f, 395.f, 396.f, 397.f, 398.f, 399.f, + 400.f, 401.f, 402.f, 403.f, 404.f, 405.f, 406.f, 407.f, + 408.f, 409.f, 410.f, 411.f, 412.f, 413.f, 414.f, 415.f, + 416.f, 417.f, 418.f, 419.f, 420.f, 421.f, 422.f, 423.f, + 424.f, 425.f, 426.f, 427.f, 428.f, 429.f, 430.f, 431.f, + 432.f, 433.f, 434.f, 435.f, 436.f, 437.f, 438.f, 439.f, + 440.f, 441.f, 442.f, 443.f, 444.f, 445.f, 446.f, 447.f, + 448.f, 449.f, 450.f, 451.f, 452.f, 453.f, 454.f, 455.f, + 456.f, 457.f, 458.f, 459.f, 460.f, 461.f, 462.f, 463.f, + 464.f, 465.f, 466.f, 467.f, 468.f, 469.f, 470.f, 471.f, + 472.f, 473.f, 474.f, 475.f, 476.f, 477.f, 478.f, 479.f, + 480.f, 481.f, 482.f, 483.f, 484.f, 485.f, 486.f, 487.f, + 488.f, 489.f, 490.f, 491.f, 492.f, 493.f, 494.f, 495.f, + 496.f, 497.f, 498.f, 499.f, 500.f, 501.f, 502.f, 503.f, + 504.f, 505.f, 506.f, 507.f, 508.f, 509.f, 510.f, 511.f, +}; + +const float icv8x32fSqrTab[] = +{ + 16384.f, 16129.f, 15876.f, 15625.f, 15376.f, 15129.f, 14884.f, 14641.f, + 14400.f, 14161.f, 13924.f, 13689.f, 13456.f, 13225.f, 12996.f, 12769.f, + 12544.f, 12321.f, 12100.f, 11881.f, 11664.f, 11449.f, 11236.f, 11025.f, + 10816.f, 10609.f, 10404.f, 10201.f, 10000.f, 9801.f, 9604.f, 9409.f, + 9216.f, 9025.f, 8836.f, 8649.f, 8464.f, 8281.f, 8100.f, 7921.f, + 7744.f, 7569.f, 7396.f, 7225.f, 7056.f, 6889.f, 6724.f, 6561.f, + 6400.f, 6241.f, 6084.f, 5929.f, 5776.f, 5625.f, 5476.f, 5329.f, + 5184.f, 5041.f, 4900.f, 4761.f, 4624.f, 4489.f, 4356.f, 4225.f, + 4096.f, 3969.f, 3844.f, 3721.f, 3600.f, 3481.f, 3364.f, 3249.f, + 3136.f, 3025.f, 2916.f, 2809.f, 2704.f, 2601.f, 2500.f, 2401.f, + 2304.f, 2209.f, 2116.f, 2025.f, 1936.f, 1849.f, 1764.f, 1681.f, + 1600.f, 1521.f, 1444.f, 1369.f, 1296.f, 1225.f, 1156.f, 1089.f, + 1024.f, 961.f, 900.f, 841.f, 784.f, 729.f, 676.f, 625.f, + 576.f, 529.f, 484.f, 441.f, 400.f, 361.f, 324.f, 289.f, + 256.f, 225.f, 196.f, 169.f, 144.f, 121.f, 100.f, 81.f, + 64.f, 49.f, 36.f, 25.f, 16.f, 9.f, 4.f, 1.f, + 0.f, 1.f, 4.f, 9.f, 16.f, 25.f, 36.f, 49.f, + 64.f, 81.f, 100.f, 121.f, 144.f, 169.f, 196.f, 225.f, + 256.f, 289.f, 324.f, 361.f, 400.f, 441.f, 484.f, 529.f, + 576.f, 625.f, 676.f, 729.f, 784.f, 841.f, 900.f, 961.f, + 1024.f, 1089.f, 1156.f, 1225.f, 1296.f, 1369.f, 1444.f, 1521.f, + 1600.f, 1681.f, 1764.f, 1849.f, 1936.f, 2025.f, 2116.f, 2209.f, + 2304.f, 2401.f, 2500.f, 2601.f, 2704.f, 2809.f, 2916.f, 3025.f, + 3136.f, 3249.f, 3364.f, 3481.f, 3600.f, 3721.f, 3844.f, 3969.f, + 4096.f, 4225.f, 4356.f, 4489.f, 4624.f, 4761.f, 4900.f, 5041.f, + 5184.f, 5329.f, 5476.f, 5625.f, 5776.f, 5929.f, 6084.f, 6241.f, + 6400.f, 6561.f, 6724.f, 6889.f, 7056.f, 7225.f, 7396.f, 7569.f, + 7744.f, 7921.f, 8100.f, 8281.f, 8464.f, 8649.f, 8836.f, 9025.f, + 9216.f, 9409.f, 9604.f, 9801.f, 10000.f, 10201.f, 10404.f, 10609.f, + 10816.f, 11025.f, 11236.f, 11449.f, 11664.f, 11881.f, 12100.f, 12321.f, + 12544.f, 12769.f, 12996.f, 13225.f, 13456.f, 13689.f, 13924.f, 14161.f, + 14400.f, 14641.f, 14884.f, 15129.f, 15376.f, 15625.f, 15876.f, 16129.f, + 16384.f, 16641.f, 16900.f, 17161.f, 17424.f, 17689.f, 17956.f, 18225.f, + 18496.f, 18769.f, 19044.f, 19321.f, 19600.f, 19881.f, 20164.f, 20449.f, + 20736.f, 21025.f, 21316.f, 21609.f, 21904.f, 22201.f, 22500.f, 22801.f, + 23104.f, 23409.f, 23716.f, 24025.f, 24336.f, 24649.f, 24964.f, 25281.f, + 25600.f, 25921.f, 26244.f, 26569.f, 26896.f, 27225.f, 27556.f, 27889.f, + 28224.f, 28561.f, 28900.f, 29241.f, 29584.f, 29929.f, 30276.f, 30625.f, + 30976.f, 31329.f, 31684.f, 32041.f, 32400.f, 32761.f, 33124.f, 33489.f, + 33856.f, 34225.f, 34596.f, 34969.f, 35344.f, 35721.f, 36100.f, 36481.f, + 36864.f, 37249.f, 37636.f, 38025.f, 38416.f, 38809.f, 39204.f, 39601.f, + 40000.f, 40401.f, 40804.f, 41209.f, 41616.f, 42025.f, 42436.f, 42849.f, + 43264.f, 43681.f, 44100.f, 44521.f, 44944.f, 45369.f, 45796.f, 46225.f, + 46656.f, 47089.f, 47524.f, 47961.f, 48400.f, 48841.f, 49284.f, 49729.f, + 50176.f, 50625.f, 51076.f, 51529.f, 51984.f, 52441.f, 52900.f, 53361.f, + 53824.f, 54289.f, 54756.f, 55225.f, 55696.f, 56169.f, 56644.f, 57121.f, + 57600.f, 58081.f, 58564.f, 59049.f, 59536.f, 60025.f, 60516.f, 61009.f, + 61504.f, 62001.f, 62500.f, 63001.f, 63504.f, 64009.f, 64516.f, 65025.f +}; + +const uchar icvSaturate8u_cv[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255 +}; + +/* End of file. */ diff --git a/imgproc/src/templmatch.cpp b/imgproc/src/templmatch.cpp new file mode 100644 index 0000000..28f04a2 --- /dev/null +++ b/imgproc/src/templmatch.cpp @@ -0,0 +1,380 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +namespace cv +{ + +void crossCorr( const Mat& img, const Mat& _templ, Mat& corr, + Size corrsize, int ctype, + Point anchor, double delta, int borderType ) +{ + const double blockScale = 4.5; + const int minBlockSize = 256; + std::vector buf; + + Mat templ = _templ; + int depth = img.depth(), cn = img.channels(); + int tdepth = templ.depth(), tcn = templ.channels(); + int cdepth = CV_MAT_DEPTH(ctype), ccn = CV_MAT_CN(ctype); + + CV_Assert( img.dims <= 2 && templ.dims <= 2 && corr.dims <= 2 ); + + if( depth != tdepth && tdepth != std::max(CV_32F, depth) ) + { + _templ.convertTo(templ, std::max(CV_32F, depth)); + tdepth = templ.depth(); + } + + CV_Assert( depth == tdepth || tdepth == CV_32F); + CV_Assert( corrsize.height <= img.rows + templ.rows - 1 && + corrsize.width <= img.cols + templ.cols - 1 ); + + CV_Assert( ccn == 1 || delta == 0 ); + + corr.create(corrsize, ctype); + + int maxDepth = depth > CV_8S ? CV_64F : std::max(std::max(CV_32F, tdepth), cdepth); + Size blocksize, dftsize; + + blocksize.width = cvRound(templ.cols*blockScale); + blocksize.width = std::max( blocksize.width, minBlockSize - templ.cols + 1 ); + blocksize.width = std::min( blocksize.width, corr.cols ); + blocksize.height = cvRound(templ.rows*blockScale); + blocksize.height = std::max( blocksize.height, minBlockSize - templ.rows + 1 ); + blocksize.height = std::min( blocksize.height, corr.rows ); + + dftsize.width = std::max(getOptimalDFTSize(blocksize.width + templ.cols - 1), 2); + dftsize.height = getOptimalDFTSize(blocksize.height + templ.rows - 1); + if( dftsize.width <= 0 || dftsize.height <= 0 ) + CV_Error( CV_StsOutOfRange, "the input arrays are too big" ); + + // recompute block size + blocksize.width = dftsize.width - templ.cols + 1; + blocksize.width = MIN( blocksize.width, corr.cols ); + blocksize.height = dftsize.height - templ.rows + 1; + blocksize.height = MIN( blocksize.height, corr.rows ); + + Mat dftTempl( dftsize.height*tcn, dftsize.width, maxDepth ); + Mat dftImg( dftsize, maxDepth ); + + int i, k, bufSize = 0; + if( tcn > 1 && tdepth != maxDepth ) + bufSize = templ.cols*templ.rows*CV_ELEM_SIZE(tdepth); + + if( cn > 1 && depth != maxDepth ) + bufSize = std::max( bufSize, (blocksize.width + templ.cols - 1)* + (blocksize.height + templ.rows - 1)*CV_ELEM_SIZE(depth)); + + if( (ccn > 1 || cn > 1) && cdepth != maxDepth ) + bufSize = std::max( bufSize, blocksize.width*blocksize.height*CV_ELEM_SIZE(cdepth)); + + buf.resize(bufSize); + + // compute DFT of each template plane + for( k = 0; k < tcn; k++ ) + { + int yofs = k*dftsize.height; + Mat src = templ; + Mat dst(dftTempl, Rect(0, yofs, dftsize.width, dftsize.height)); + Mat dst1(dftTempl, Rect(0, yofs, templ.cols, templ.rows)); + + if( tcn > 1 ) + { + src = tdepth == maxDepth ? dst1 : Mat(templ.size(), tdepth, &buf[0]); + int pairs[] = {k, 0}; + mixChannels(&templ, 1, &src, 1, pairs, 1); + } + + if( dst1.data != src.data ) + src.convertTo(dst1, dst1.depth()); + + if( dst.cols > templ.cols ) + { + Mat part(dst, Range(0, templ.rows), Range(templ.cols, dst.cols)); + part = Scalar::all(0); + } + dft(dst, dst, 0, templ.rows); + } + + int tileCountX = (corr.cols + blocksize.width - 1)/blocksize.width; + int tileCountY = (corr.rows + blocksize.height - 1)/blocksize.height; + int tileCount = tileCountX * tileCountY; + + Size wholeSize = img.size(); + Point roiofs(0,0); + Mat img0 = img; + + if( !(borderType & BORDER_ISOLATED) ) + { + img.locateROI(wholeSize, roiofs); + img0.adjustROI(roiofs.y, wholeSize.height-img.rows-roiofs.y, + roiofs.x, wholeSize.width-img.cols-roiofs.x); + } + borderType |= BORDER_ISOLATED; + + // calculate correlation by blocks + for( i = 0; i < tileCount; i++ ) + { + int x = (i%tileCountX)*blocksize.width; + int y = (i/tileCountX)*blocksize.height; + + Size bsz(std::min(blocksize.width, corr.cols - x), + std::min(blocksize.height, corr.rows - y)); + Size dsz(bsz.width + templ.cols - 1, bsz.height + templ.rows - 1); + int x0 = x - anchor.x + roiofs.x, y0 = y - anchor.y + roiofs.y; + int x1 = std::max(0, x0), y1 = std::max(0, y0); + int x2 = std::min(img0.cols, x0 + dsz.width); + int y2 = std::min(img0.rows, y0 + dsz.height); + Mat src0(img0, Range(y1, y2), Range(x1, x2)); + Mat dst(dftImg, Rect(0, 0, dsz.width, dsz.height)); + Mat dst1(dftImg, Rect(x1-x0, y1-y0, x2-x1, y2-y1)); + Mat cdst(corr, Rect(x, y, bsz.width, bsz.height)); + + for( k = 0; k < cn; k++ ) + { + Mat src = src0; + dftImg = Scalar::all(0); + + if( cn > 1 ) + { + src = depth == maxDepth ? dst1 : Mat(y2-y1, x2-x1, depth, &buf[0]); + int pairs[] = {k, 0}; + mixChannels(&src0, 1, &src, 1, pairs, 1); + } + + if( dst1.data != src.data ) + src.convertTo(dst1, dst1.depth()); + + if( x2 - x1 < dsz.width || y2 - y1 < dsz.height ) + copyMakeBorder(dst1, dst, y1-y0, dst.rows-dst1.rows-(y1-y0), + x1-x0, dst.cols-dst1.cols-(x1-x0), borderType); + + dft( dftImg, dftImg, 0, dsz.height ); + Mat dftTempl1(dftTempl, Rect(0, tcn > 1 ? k*dftsize.height : 0, + dftsize.width, dftsize.height)); + mulSpectrums(dftImg, dftTempl1, dftImg, 0, true); + dft( dftImg, dftImg, DFT_INVERSE + DFT_SCALE, bsz.height ); + + src = dftImg(Rect(0, 0, bsz.width, bsz.height)); + + if( ccn > 1 ) + { + if( cdepth != maxDepth ) + { + Mat plane(bsz, cdepth, &buf[0]); + src.convertTo(plane, cdepth, 1, delta); + src = plane; + } + int pairs[] = {0, k}; + mixChannels(&src, 1, &cdst, 1, pairs, 1); + } + else + { + if( k == 0 ) + src.convertTo(cdst, cdepth, 1, delta); + else + { + if( maxDepth != cdepth ) + { + Mat plane(bsz, cdepth, &buf[0]); + src.convertTo(plane, cdepth); + src = plane; + } + add(src, cdst, cdst); + } + } + } + } +} + +} + +/*****************************************************************************************/ + +void cv::matchTemplate( InputArray _img, InputArray _templ, OutputArray _result, int method ) +{ + CV_Assert( CV_TM_SQDIFF <= method && method <= CV_TM_CCOEFF_NORMED ); + + int numType = method == CV_TM_CCORR || method == CV_TM_CCORR_NORMED ? 0 : + method == CV_TM_CCOEFF || method == CV_TM_CCOEFF_NORMED ? 1 : 2; + bool isNormed = method == CV_TM_CCORR_NORMED || + method == CV_TM_SQDIFF_NORMED || + method == CV_TM_CCOEFF_NORMED; + + Mat img = _img.getMat(), templ = _templ.getMat(); + if( img.rows < templ.rows || img.cols < templ.cols ) + std::swap(img, templ); + + CV_Assert( (img.depth() == CV_8U || img.depth() == CV_32F) && + img.type() == templ.type() ); + + Size corrSize(img.cols - templ.cols + 1, img.rows - templ.rows + 1); + _result.create(corrSize, CV_32F); + Mat result = _result.getMat(); + + int cn = img.channels(); + crossCorr( img, templ, result, result.size(), result.type(), Point(0,0), 0, 0); + + if( method == CV_TM_CCORR ) + return; + + double invArea = 1./((double)templ.rows * templ.cols); + + Mat sum, sqsum; + Scalar templMean, templSdv; + double *q0 = 0, *q1 = 0, *q2 = 0, *q3 = 0; + double templNorm = 0, templSum2 = 0; + + if( method == CV_TM_CCOEFF ) + { + integral(img, sum, CV_64F); + templMean = mean(templ); + } + else + { + integral(img, sum, sqsum, CV_64F); + meanStdDev( templ, templMean, templSdv ); + + templNorm = CV_SQR(templSdv[0]) + CV_SQR(templSdv[1]) + + CV_SQR(templSdv[2]) + CV_SQR(templSdv[3]); + + if( templNorm < DBL_EPSILON && method == CV_TM_CCOEFF_NORMED ) + { + result = Scalar::all(1); + return; + } + + templSum2 = templNorm + + CV_SQR(templMean[0]) + CV_SQR(templMean[1]) + + CV_SQR(templMean[2]) + CV_SQR(templMean[3]); + + if( numType != 1 ) + { + templMean = Scalar::all(0); + templNorm = templSum2; + } + + templSum2 /= invArea; + templNorm = sqrt(templNorm); + templNorm /= sqrt(invArea); // care of accuracy here + + q0 = (double*)sqsum.data; + q1 = q0 + templ.cols*cn; + q2 = (double*)(sqsum.data + templ.rows*sqsum.step); + q3 = q2 + templ.cols*cn; + } + + double* p0 = (double*)sum.data; + double* p1 = p0 + templ.cols*cn; + double* p2 = (double*)(sum.data + templ.rows*sum.step); + double* p3 = p2 + templ.cols*cn; + + int sumstep = sum.data ? (int)(sum.step / sizeof(double)) : 0; + int sqstep = sqsum.data ? (int)(sqsum.step / sizeof(double)) : 0; + + int i, j, k; + + for( i = 0; i < result.rows; i++ ) + { + float* rrow = (float*)(result.data + i*result.step); + int idx = i * sumstep; + int idx2 = i * sqstep; + + for( j = 0; j < result.cols; j++, idx += cn, idx2 += cn ) + { + double num = rrow[j], t; + double wndMean2 = 0, wndSum2 = 0; + + if( numType == 1 ) + { + for( k = 0; k < cn; k++ ) + { + t = p0[idx+k] - p1[idx+k] - p2[idx+k] + p3[idx+k]; + wndMean2 += CV_SQR(t); + num -= t*templMean[k]; + } + + wndMean2 *= invArea; + } + + if( isNormed || numType == 2 ) + { + for( k = 0; k < cn; k++ ) + { + t = q0[idx2+k] - q1[idx2+k] - q2[idx2+k] + q3[idx2+k]; + wndSum2 += t; + } + + if( numType == 2 ) + num = wndSum2 - 2*num + templSum2; + } + + if( isNormed ) + { + t = sqrt(MAX(wndSum2 - wndMean2,0))*templNorm; + if( fabs(num) < t ) + num /= t; + else if( fabs(num) < t*1.125 ) + num = num > 0 ? 1 : -1; + else + num = method != CV_TM_SQDIFF_NORMED ? 0 : 1; + } + + rrow[j] = (float)num; + } + } +} + + +CV_IMPL void +cvMatchTemplate( const CvArr* _img, const CvArr* _templ, CvArr* _result, int method ) +{ + cv::Mat img = cv::cvarrToMat(_img), templ = cv::cvarrToMat(_templ), + result = cv::cvarrToMat(_result); + CV_Assert( result.size() == cv::Size(std::abs(img.cols - templ.cols) + 1, + std::abs(img.rows - templ.rows) + 1) && + result.type() == CV_32F ); + matchTemplate(img, templ, result, method); +} + +/* End of file. */ diff --git a/imgproc/src/thresh.cpp b/imgproc/src/thresh.cpp new file mode 100644 index 0000000..5730698 --- /dev/null +++ b/imgproc/src/thresh.cpp @@ -0,0 +1,1258 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +namespace cv +{ + +static void +thresh_8u( const Mat& _src, Mat& _dst, uchar thresh, uchar maxval, int type ) +{ + int i, j, j_scalar = 0; + uchar tab[256]; + Size roi = _src.size(); + roi.width *= _src.channels(); + + if( _src.isContinuous() && _dst.isContinuous() ) + { + roi.width *= roi.height; + roi.height = 1; + } + +#ifdef HAVE_TEGRA_OPTIMIZATION + if (tegra::thresh_8u(_src, _dst, roi.width, roi.height, thresh, maxval, type)) + return; +#endif + + switch( type ) + { + case THRESH_BINARY: + for( i = 0; i <= thresh; i++ ) + tab[i] = 0; + for( ; i < 256; i++ ) + tab[i] = maxval; + break; + case THRESH_BINARY_INV: + for( i = 0; i <= thresh; i++ ) + tab[i] = maxval; + for( ; i < 256; i++ ) + tab[i] = 0; + break; + case THRESH_TRUNC: + for( i = 0; i <= thresh; i++ ) + tab[i] = (uchar)i; + for( ; i < 256; i++ ) + tab[i] = thresh; + break; + case THRESH_TOZERO: + for( i = 0; i <= thresh; i++ ) + tab[i] = 0; + for( ; i < 256; i++ ) + tab[i] = (uchar)i; + break; + case THRESH_TOZERO_INV: + for( i = 0; i <= thresh; i++ ) + tab[i] = (uchar)i; + for( ; i < 256; i++ ) + tab[i] = 0; + break; + default: + CV_Error( CV_StsBadArg, "Unknown threshold type" ); + } + +#if CV_NEON + #pragma mark ANUVIS team debugging NEON version + + if (cv::useOptimized()) { + + #ifdef ANUVIS_TEST + CV_Error( CV_StsBadArg, "thresh_8u using Neon was called!" ); + #endif + + //set the 16 signed 8-bit integer values to '\x80' (128) + int8x16_t _x80 = vdupq_n_s8('\x80'); + int8x16_t thresh_u = vdupq_n_s8(thresh); + int8x16_t thresh_s = vdupq_n_s8(thresh ^ 0x80); + int8x16_t maxval_ = vdupq_n_s8(maxval); + + //set the 8 signed 8-bit integer value constants + //we need these shorter equivilents for the last chunk of 32 to avoid overflow + int8x8_t h_x80 = vdup_n_s8('\x80'); + int8x8_t hthresh_u = vdup_n_s8(thresh); + int8x8_t hthresh_s = vdup_n_s8(thresh ^ 0x80); + int8x8_t hmaxval_ = vdup_n_s8(maxval); + + //set the 16 signed 8-bit integer values to '\x80' (128) + uint8x16_t uthresh_u = vdupq_n_u8(thresh); + + //set the 8 signed 8-bit integer value constants + //we need these shorter equivilents for the last chunk of 32 to avoid overflow + + uint8x8_t uhthresh_u = vdup_n_u8(thresh); + + + j_scalar = roi.width & -8; + + //process it row + for( i = 0; i < roi.height; i++ ) + { + const uchar* src = (const uchar*)(_src.data + _src.step*i); + uchar* dst = (uchar*)(_dst.data + _dst.step*i); + + switch( type ) + { + case THRESH_BINARY://~2x + #ifdef ANUVIS_TEST + CV_Error( CV_StsBadArg, "THRESH_BINARY in thresh_8u using Neon was called!" ); + #endif + + //whilst treating 32 signed 8 bit ints at once (except for the last 32) + + for (j = 0; j < roi.width - 32; j += 32) { + int8x16_t v0, v1; + + //load 128-bit value + v0 = vld1q_s8((const int8_t *)(src + j)); + v1 = vld1q_s8((const int8_t *) (src + j + 16)); + + //compares the 16 signed 8-bit integers between a > b + //computes the bitwise XOR of the 128-bit value in a and b + v0 = (int8x16_t)vcgtq_s8(veorq_s8(v0, _x80), thresh_s); + v1 = (int8x16_t)vcgtq_s8(veorq_s8(v1, _x80), thresh_s); + + //computes the bitwise AND of the 128-bit value in a and b + v0 = vandq_s8(v0, maxval_); + v1 = vandq_s8(v1, maxval_); + + //store it + vst1q_s8((int8_t *)(dst + j), v0); + vst1q_s8((int8_t *)(dst + j + 16), v1); + } + + //treat the last 32 + for ( ; j <= roi.width - 8; j += 8) { + int8x8_t v0 = vld1_s8((const int8_t *)(src + j)); + v0 = (int8x8_t)vcgt_s8(veor_s8(v0, h_x80), hthresh_s); + v0 = vand_s8(v0, hmaxval_); + vst1_s8((int8_t *)(dst + j), v0); + } + + break; + + case THRESH_BINARY_INV://~2x + + //whilst treating 32 signed 8 bit ints at once (except for the last 32) + + for (j = 0; j < roi.width - 32; j += 32) { + int8x16_t v0, v1; + + //load 128-bit value + v0 = vld1q_s8((const int8_t *)(src + j)); + v1 = vld1q_s8((const int8_t *) (src + j + 16)); + + //compares the 16 signed 8-bit integers between a > b + //computes the bitwise XOR of the 128-bit value in a and b + v0 = (int8x16_t)vcgtq_s8(veorq_s8(v0, _x80), thresh_s); + v1 = (int8x16_t)vcgtq_s8(veorq_s8(v1, _x80), thresh_s); + + //computes the bitwise AND of the 128-bit value in a and b + //note a is negated using the bitwise not + v0 = vandq_s8(vmvnq_s8(v0), maxval_); + v1 = vandq_s8(vmvnq_s8(v1), maxval_); + + //store it + vst1q_s8((int8_t *)(dst + j), v0); + vst1q_s8((int8_t *)(dst + j + 16), v1); + } + + //treat the last 32 + for ( ; j <= roi.width - 8; j += 8) { + int8x8_t v0 = vld1_s8((const int8_t *)(src + j)); + v0 = (int8x8_t)vcgt_s8(veor_s8(v0, h_x80), hthresh_s); + v0 = vand_s8(vmvn_s8(v0), hmaxval_); + vst1_s8((int8_t *)(dst + j), v0); + } + + break; + + case THRESH_TRUNC: + + //begin + for (j = 0; j < roi.width - 32; j += 32) { + uint8x16_t v0, v1; + + //load 128-bit value + v0 = vld1q_u8((const uint8_t *)(src + j)); + v1 = vld1q_u8((const uint8_t *) (src + j + 16)); + + //Subtracts the 16 unsigned 8-bit integers of b from a and saturates + v0 = vqsubq_u8(v0, vqsubq_u8(v0, uthresh_u)); + v1 = vqsubq_u8(v1, vqsubq_u8(v1, uthresh_u)); + + //store it + vst1q_u8((uint8_t *)(dst + j), v0); + vst1q_u8((uint8_t *)(dst + j + 16), v1); + } + + //treat the last 32 + for ( ; j <= roi.width - 8; j += 8) { + uint8x8_t v0 = vld1_u8((const uint8_t *)(src + j)); + v0 = vqsub_u8(v0, vqsub_u8(v0, uhthresh_u)); + vst1_u8((uint8_t *)(dst + j), v0); + } + break; + + case THRESH_TOZERO: + + for (j = 0; j < roi.width - 32; j += 32) { + int8x16_t v0, v1; + + //load 128-bit value + v0 = vld1q_s8((const int8_t *)(src + j)); + v1 = vld1q_s8((const int8_t *) (src + j + 16)); + + //computes the bitwise AND of the 128-bit value in a and b + //compares the 16 signed 8-bit integers between a > b + //computes the bitwise XOR of the 128-bit value in a and b + v0 = vandq_s8(v0,(int8x16_t)vcgtq_s8(veorq_s8(v0, _x80), thresh_s)); + v1 = vandq_s8(v1, (int8x16_t)vcgtq_s8(veorq_s8(v1, _x80), thresh_s)); + + //store it + vst1q_s8((int8_t *)(dst + j), v0); + vst1q_s8((int8_t *)(dst + j + 16), v1); + } + + //treat the last 32 + for ( ; j <= roi.width - 8; j += 8) { + int8x8_t v0 = vld1_s8((const int8_t *)(src + j)); + v0 = vand_s8(v0, (int8x8_t)vcgt_s8(veor_s8(v0, h_x80), hthresh_s)); + vst1_s8((int8_t *)(dst + j), v0); + } + + break; + + case THRESH_TOZERO_INV: + + for (j = 0; j < roi.width - 32; j += 32) { + int8x16_t v0, v1; + + //load 128-bit value + v0 = vld1q_s8((const int8_t *)(src + j)); + v1 = vld1q_s8((const int8_t *) (src + j + 16)); + + //bitwise NOT on a + //computes the bitwise AND of the 128-bit value in a and b + //compares the 16 signed 8-bit integers between a > b + //computes the bitwise XOR of the 128-bit value in a and b + v0 = vandq_s8(vmvnq_s8((int8x16_t)vcgtq_s8(veorq_s8(v0, _x80), thresh_s)),v0); + v1 = vandq_s8(vmvnq_s8((int8x16_t)vcgtq_s8(veorq_s8(v1, _x80), thresh_s)),v1); + + //store it + vst1q_s8((int8_t *)(dst + j), v0); + vst1q_s8((int8_t *)(dst + j + 16), v1); + } + + //treat the last 32 + for ( ; j <= roi.width - 8; j += 8) { + int8x8_t v0 = vld1_s8((const int8_t *)(src + j)); + v0 = vand_s8(vmvn_s8((int8x8_t)vcgt_s8(veor_s8(v0, h_x80), hthresh_s)),v0); + vst1_s8((int8_t *)(dst + j), v0); + } + + break; + } + } + } +#endif + +#if CV_SSE2 + if( checkHardwareSupport(CV_CPU_SSE2) ) + { + __m128i _x80 = _mm_set1_epi8('\x80'); + __m128i thresh_u = _mm_set1_epi8(thresh); + __m128i thresh_s = _mm_set1_epi8(thresh ^ 0x80); + __m128i maxval_ = _mm_set1_epi8(maxval); + j_scalar = roi.width & -8; + + for( i = 0; i < roi.height; i++ ) + { + const uchar* src = (const uchar*)(_src.data + _src.step*i); + uchar* dst = (uchar*)(_dst.data + _dst.step*i); + + switch( type ) + { + case THRESH_BINARY: + for( j = 0; j <= roi.width - 32; j += 32 ) + { + __m128i v0, v1; + v0 = _mm_loadu_si128( (const __m128i*)(src + j) ); + v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) ); + v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s ); + v1 = _mm_cmpgt_epi8( _mm_xor_si128(v1, _x80), thresh_s ); + v0 = _mm_and_si128( v0, maxval_ ); + v1 = _mm_and_si128( v1, maxval_ ); + _mm_storeu_si128( (__m128i*)(dst + j), v0 ); + _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 ); + } + + for( ; j <= roi.width - 8; j += 8 ) + { + __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) ); + v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s ); + v0 = _mm_and_si128( v0, maxval_ ); + _mm_storel_epi64( (__m128i*)(dst + j), v0 ); + } + break; + + case THRESH_BINARY_INV: + for( j = 0; j <= roi.width - 32; j += 32 ) + { + __m128i v0, v1; + v0 = _mm_loadu_si128( (const __m128i*)(src + j) ); + v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) ); + v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s ); + v1 = _mm_cmpgt_epi8( _mm_xor_si128(v1, _x80), thresh_s ); + v0 = _mm_andnot_si128( v0, maxval_ ); + v1 = _mm_andnot_si128( v1, maxval_ ); + _mm_storeu_si128( (__m128i*)(dst + j), v0 ); + _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 ); + } + + for( ; j <= roi.width - 8; j += 8 ) + { + __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) ); + v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s ); + v0 = _mm_andnot_si128( v0, maxval_ ); + _mm_storel_epi64( (__m128i*)(dst + j), v0 ); + } + break; + + case THRESH_TRUNC: + for( j = 0; j <= roi.width - 32; j += 32 ) + { + __m128i v0, v1; + v0 = _mm_loadu_si128( (const __m128i*)(src + j) ); + v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) ); + v0 = _mm_subs_epu8( v0, _mm_subs_epu8( v0, thresh_u )); + v1 = _mm_subs_epu8( v1, _mm_subs_epu8( v1, thresh_u )); + _mm_storeu_si128( (__m128i*)(dst + j), v0 ); + _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 ); + } + + for( ; j <= roi.width - 8; j += 8 ) + { + __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) ); + v0 = _mm_subs_epu8( v0, _mm_subs_epu8( v0, thresh_u )); + _mm_storel_epi64( (__m128i*)(dst + j), v0 ); + } + break; + + case THRESH_TOZERO: + for( j = 0; j <= roi.width - 32; j += 32 ) + { + __m128i v0, v1; + v0 = _mm_loadu_si128( (const __m128i*)(src + j) ); + v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) ); + v0 = _mm_and_si128( v0, _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s )); + v1 = _mm_and_si128( v1, _mm_cmpgt_epi8(_mm_xor_si128(v1, _x80), thresh_s )); + _mm_storeu_si128( (__m128i*)(dst + j), v0 ); + _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 ); + } + + for( ; j <= roi.width - 8; j += 8 ) + { + __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) ); + v0 = _mm_and_si128( v0, _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s )); + _mm_storel_epi64( (__m128i*)(dst + j), v0 ); + } + break; + + case THRESH_TOZERO_INV: + for( j = 0; j <= roi.width - 32; j += 32 ) + { + __m128i v0, v1; + v0 = _mm_loadu_si128( (const __m128i*)(src + j) ); + v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) ); + v0 = _mm_andnot_si128( _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ), v0 ); + v1 = _mm_andnot_si128( _mm_cmpgt_epi8(_mm_xor_si128(v1, _x80), thresh_s ), v1 ); + _mm_storeu_si128( (__m128i*)(dst + j), v0 ); + _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 ); + } + + for( ; j <= roi.width - 8; j += 8 ) + { + __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) ); + v0 = _mm_andnot_si128( _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ), v0 ); + _mm_storel_epi64( (__m128i*)(dst + j), v0 ); + } + break; + } + } + } +#endif + + if( j_scalar < roi.width ) + { + for( i = 0; i < roi.height; i++ ) + { + const uchar* src = (const uchar*)(_src.data + _src.step*i); + uchar* dst = (uchar*)(_dst.data + _dst.step*i); + j = j_scalar; +#if CV_ENABLE_UNROLLED + for( ; j <= roi.width - 4; j += 4 ) + { + uchar t0 = tab[src[j]]; + uchar t1 = tab[src[j+1]]; + + dst[j] = t0; + dst[j+1] = t1; + + t0 = tab[src[j+2]]; + t1 = tab[src[j+3]]; + + dst[j+2] = t0; + dst[j+3] = t1; + } +#endif + for( ; j < roi.width; j++ ) + dst[j] = tab[src[j]]; + } + } +} + + +static void +thresh_16s( const Mat& _src, Mat& _dst, short thresh, short maxval, int type ) +{ + int i, j; + Size roi = _src.size(); + roi.width *= _src.channels(); + const short* src = (const short*)_src.data; + short* dst = (short*)_dst.data; + size_t src_step = _src.step/sizeof(src[0]); + size_t dst_step = _dst.step/sizeof(dst[0]); + +#if CV_SSE2 + volatile bool useSIMD = checkHardwareSupport(CV_CPU_SSE); +#endif + + if( _src.isContinuous() && _dst.isContinuous() ) + { + roi.width *= roi.height; + roi.height = 1; + } + +#ifdef HAVE_TEGRA_OPTIMIZATION + if (tegra::thresh_16s(_src, _dst, roi.width, roi.height, thresh, maxval, type)) + return; +#endif + + switch( type ) + { + case THRESH_BINARY: + for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step ) + { + j = 0; + + #if CV_NEON //~2.2x + + int16x8_t thresh8 = vdupq_n_s16(thresh); + int16x8_t maxval8 = vdupq_n_s16(maxval); + + //load each 128-bit chunk of signed 16-bit ints + for( ; j <= roi.width - 16; j += 16 ) + { + int16x8_t v0, v1; + + v0 = vld1q_s16((const int16_t *)(src + j)); + v1 = vld1q_s16((const int16_t *)(src + j + 8)); + + v0 = (int16x8_t)vcgtq_s16(v0, thresh8); + v1 = (int16x8_t)vcgtq_s16(v1, thresh8); + + //computes the bitwise AND of the 128-bit value in a and b + v0 = vandq_s16(v0, maxval8); + v1 = vandq_s16(v1, maxval8); + + //store it + vst1q_s16((int16_t *)(dst + j), v0); + vst1q_s16((int16_t *)(dst + j + 8), v1); + + } + + #endif + + #if CV_SSE2 + if( useSIMD ) + { + __m128i thresh8 = _mm_set1_epi16(thresh), maxval8 = _mm_set1_epi16(maxval); + for( ; j <= roi.width - 16; j += 16 ) + { + __m128i v0, v1; + v0 = _mm_loadu_si128( (const __m128i*)(src + j) ); + v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) ); + v0 = _mm_cmpgt_epi16( v0, thresh8 ); + v1 = _mm_cmpgt_epi16( v1, thresh8 ); + v0 = _mm_and_si128( v0, maxval8 ); + v1 = _mm_and_si128( v1, maxval8 ); + _mm_storeu_si128((__m128i*)(dst + j), v0 ); + _mm_storeu_si128((__m128i*)(dst + j + 8), v1 ); + } + } + #endif + + for( ; j < roi.width; j++ ) + dst[j] = src[j] > thresh ? maxval : 0; + } + break; + + case THRESH_BINARY_INV: + for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step ) + { + j = 0; + + #if CV_NEON + + int16x8_t thresh8 = vdupq_n_s16(thresh); + int16x8_t maxval8 = vdupq_n_s16(maxval); + + //load each 128-bit chunk of signed 16-bit ints + for( ; j <= roi.width - 16; j += 16 ) + { + int16x8_t v0, v1; + + v0 = vld1q_s16((const int16_t *)(src + j)); + v1 = vld1q_s16((const int16_t *)(src + j + 8)); + + v0 = (int16x8_t)vcgtq_s16(v0, thresh8); + v1 = (int16x8_t)vcgtq_s16(v1, thresh8); + + //computes the bitwise AND NOT of the 128-bit value in a and b + v0 = vandq_s16(vmvnq_s16(v0), maxval8); + v1 = vandq_s16(vmvnq_s16(v1), maxval8); + + //store it + vst1q_s16((int16_t *)(dst + j), v0); + vst1q_s16((int16_t *)(dst + j + 8), v1); + + } + + #endif + + #if CV_SSE2 + if( useSIMD ) + { + __m128i thresh8 = _mm_set1_epi16(thresh), maxval8 = _mm_set1_epi16(maxval); + for( ; j <= roi.width - 16; j += 16 ) + { + __m128i v0, v1; + v0 = _mm_loadu_si128( (const __m128i*)(src + j) ); + v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) ); + v0 = _mm_cmpgt_epi16( v0, thresh8 ); + v1 = _mm_cmpgt_epi16( v1, thresh8 ); + v0 = _mm_andnot_si128( v0, maxval8 ); + v1 = _mm_andnot_si128( v1, maxval8 ); + _mm_storeu_si128((__m128i*)(dst + j), v0 ); + _mm_storeu_si128((__m128i*)(dst + j + 8), v1 ); + } + } + #endif + + for( ; j < roi.width; j++ ) + dst[j] = src[j] <= thresh ? maxval : 0; + } + break; + + case THRESH_TRUNC: + for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step ) + { + j = 0; + + #if CV_NEON + + int16x8_t thresh8 = vdupq_n_s16(thresh); + + //load each 128-bit chunk of signed 16-bit ints + for( ; j <= roi.width - 16; j += 16 ) + { + int16x8_t v0, v1; + + v0 = vld1q_s16((const int16_t *)(src + j)); + v1 = vld1q_s16((const int16_t *)(src + j + 8)); + + //pairwise minimum + v0 = (int16x8_t)vminq_s16(v0, thresh8); + v1 = (int16x8_t)vminq_s16(v1, thresh8); + + //store it + vst1q_s16((int16_t *)(dst + j), v0); + vst1q_s16((int16_t *)(dst + j + 8), v1); + + } + + #endif + + #if CV_SSE2 + if( useSIMD ) + { + __m128i thresh8 = _mm_set1_epi16(thresh); + for( ; j <= roi.width - 16; j += 16 ) + { + __m128i v0, v1; + v0 = _mm_loadu_si128( (const __m128i*)(src + j) ); + v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) ); + v0 = _mm_min_epi16( v0, thresh8 ); + v1 = _mm_min_epi16( v1, thresh8 ); + _mm_storeu_si128((__m128i*)(dst + j), v0 ); + _mm_storeu_si128((__m128i*)(dst + j + 8), v1 ); + } + } + #endif + + for( ; j < roi.width; j++ ) + dst[j] = std::min(src[j], thresh); + } + break; + + case THRESH_TOZERO: + for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step ) + { + j = 0; + + + #if CV_NEON + + int16x8_t thresh8 = vdupq_n_s16(thresh); + + //load each 128-bit chunk of signed 16-bit ints + for( ; j <= roi.width - 16; j += 16 ) + { + int16x8_t v0, v1; + + v0 = vld1q_s16((const int16_t *)(src + j)); + v1 = vld1q_s16((const int16_t *)(src + j + 8)); + + v0 = vandq_s16(v0, (int16x8_t)vcgtq_s16(v0, thresh8)); + v1 = vandq_s16(v1, (int16x8_t)vcgtq_s16(v1, thresh8)); + + //store it + vst1q_s16((int16_t *)(dst + j), v0); + vst1q_s16((int16_t *)(dst + j + 8), v1); + + } + + + #endif + + #if CV_SSE2 + if( useSIMD ) + { + __m128i thresh8 = _mm_set1_epi16(thresh); + for( ; j <= roi.width - 16; j += 16 ) + { + __m128i v0, v1; + v0 = _mm_loadu_si128( (const __m128i*)(src + j) ); + v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) ); + v0 = _mm_and_si128(v0, _mm_cmpgt_epi16(v0, thresh8)); + v1 = _mm_and_si128(v1, _mm_cmpgt_epi16(v1, thresh8)); + _mm_storeu_si128((__m128i*)(dst + j), v0 ); + _mm_storeu_si128((__m128i*)(dst + j + 8), v1 ); + } + } + #endif + + for( ; j < roi.width; j++ ) + { + short v = src[j]; + dst[j] = v > thresh ? v : 0; + } + } + break; + + case THRESH_TOZERO_INV: + for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step ) + { + j = 0; + + #if CV_NEON + + int16x8_t thresh8 = vdupq_n_s16(thresh); + + //load each 128-bit chunk of signed 16-bit ints + for( ; j <= roi.width - 16; j += 16 ) + { + int16x8_t v0, v1; + + v0 = vld1q_s16((const int16_t *)(src + j)); + v1 = vld1q_s16((const int16_t *)(src + j + 8)); + + v0 = vandq_s16(vmvnq_s16((int16x8_t)vcgtq_s16(v0, thresh8)), v0); + v1 = vandq_s16(vmvnq_s16((int16x8_t)vcgtq_s16(v1, thresh8)), v1); + + //store it + vst1q_s16((int16_t *)(dst + j), v0); + vst1q_s16((int16_t *)(dst + j + 8), v1); + + } + + #endif + + #if CV_SSE2 + if( useSIMD ) + { + __m128i thresh8 = _mm_set1_epi16(thresh); + for( ; j <= roi.width - 16; j += 16 ) + { + __m128i v0, v1; + v0 = _mm_loadu_si128( (const __m128i*)(src + j) ); + v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) ); + v0 = _mm_andnot_si128(_mm_cmpgt_epi16(v0, thresh8), v0); + v1 = _mm_andnot_si128(_mm_cmpgt_epi16(v1, thresh8), v1); + _mm_storeu_si128((__m128i*)(dst + j), v0 ); + _mm_storeu_si128((__m128i*)(dst + j + 8), v1 ); + } + } + #endif + for( ; j < roi.width; j++ ) + { + short v = src[j]; + dst[j] = v <= thresh ? v : 0; + } + } + break; + default: + return CV_Error( CV_StsBadArg, "" ); + } +} + + +static void +thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type ) +{ + int i, j; + Size roi = _src.size(); + roi.width *= _src.channels(); + const float* src = (const float*)_src.data; + float* dst = (float*)_dst.data; + size_t src_step = _src.step/sizeof(src[0]); + size_t dst_step = _dst.step/sizeof(dst[0]); + +#if CV_SSE2 + volatile bool useSIMD = checkHardwareSupport(CV_CPU_SSE); +#endif + + if( _src.isContinuous() && _dst.isContinuous() ) + { + roi.width *= roi.height; + roi.height = 1; + } + +#ifdef HAVE_TEGRA_OPTIMIZATION + if (tegra::thresh_32f(_src, _dst, roi.width, roi.height, thresh, maxval, type)) + return; +#endif + + switch( type ) + { + case THRESH_BINARY: + for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step ) + { + j = 0; + +#pragma mark ANUVIS team debugging +#if CV_NEON + /* + //treat 256 bits (8 floats) at a time + float32x4_t thresh4 = vdupq_n_f32(thresh); + float32x4_t maxval4 = vdupq_n_f32(maxval); + + for( ; j <= roi.width - 8; j += 8 ) + { + float32x4_t v0, v1; + + v0 = vld1q_f32((const float32_t *)(src + j)); + v1 = vld1q_f32((const float32_t *)(src + j + 4)); + + v0 = (float32x4_t)vcgtq_f32(v0, thresh4); + v1 = (float32x4_t)vcgtq_f32(v1, thresh4); + + v0 = (float32x4_t)vandq_s32((int32x4_t)v0, (int32x4_t)thresh4); + v0 = (float32x4_t)vandq_s32((int32x4_t)v1, (int32x4_t)thresh4); + + vst1q_f32((float32_t*)dst + j, v0); + vst1q_f32((float32_t*)dst + j + 4, v1); + } + + */ +#endif + +#if CV_SSE2 + if( useSIMD ) + { + __m128 thresh4 = _mm_set1_ps(thresh), maxval4 = _mm_set1_ps(maxval); + for( ; j <= roi.width - 8; j += 8 ) + { + __m128 v0, v1; + v0 = _mm_loadu_ps( src + j ); + v1 = _mm_loadu_ps( src + j + 4 ); + v0 = _mm_cmpgt_ps( v0, thresh4 ); + v1 = _mm_cmpgt_ps( v1, thresh4 ); + v0 = _mm_and_ps( v0, maxval4 ); + v1 = _mm_and_ps( v1, maxval4 ); + _mm_storeu_ps( dst + j, v0 ); + _mm_storeu_ps( dst + j + 4, v1 ); + } + } +#endif + + for( ; j < roi.width; j++ ) + dst[j] = src[j] > thresh ? maxval : 0; + } + break; + + case THRESH_BINARY_INV: + for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step ) + { + j = 0; +#if CV_SSE2 + if( useSIMD ) + { + __m128 thresh4 = _mm_set1_ps(thresh), maxval4 = _mm_set1_ps(maxval); + for( ; j <= roi.width - 8; j += 8 ) + { + __m128 v0, v1; + v0 = _mm_loadu_ps( src + j ); + v1 = _mm_loadu_ps( src + j + 4 ); + v0 = _mm_cmple_ps( v0, thresh4 ); + v1 = _mm_cmple_ps( v1, thresh4 ); + v0 = _mm_and_ps( v0, maxval4 ); + v1 = _mm_and_ps( v1, maxval4 ); + _mm_storeu_ps( dst + j, v0 ); + _mm_storeu_ps( dst + j + 4, v1 ); + } + } +#endif + + for( ; j < roi.width; j++ ) + dst[j] = src[j] <= thresh ? maxval : 0; + } + break; + + case THRESH_TRUNC: + for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step ) + { + j = 0; +#if CV_SSE2 + if( useSIMD ) + { + __m128 thresh4 = _mm_set1_ps(thresh); + for( ; j <= roi.width - 8; j += 8 ) + { + __m128 v0, v1; + v0 = _mm_loadu_ps( src + j ); + v1 = _mm_loadu_ps( src + j + 4 ); + v0 = _mm_min_ps( v0, thresh4 ); + v1 = _mm_min_ps( v1, thresh4 ); + _mm_storeu_ps( dst + j, v0 ); + _mm_storeu_ps( dst + j + 4, v1 ); + } + } +#endif + + for( ; j < roi.width; j++ ) + dst[j] = std::min(src[j], thresh); + } + break; + + case THRESH_TOZERO: + for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step ) + { + j = 0; +#if CV_SSE2 + if( useSIMD ) + { + __m128 thresh4 = _mm_set1_ps(thresh); + for( ; j <= roi.width - 8; j += 8 ) + { + __m128 v0, v1; + v0 = _mm_loadu_ps( src + j ); + v1 = _mm_loadu_ps( src + j + 4 ); + v0 = _mm_and_ps(v0, _mm_cmpgt_ps(v0, thresh4)); + v1 = _mm_and_ps(v1, _mm_cmpgt_ps(v1, thresh4)); + _mm_storeu_ps( dst + j, v0 ); + _mm_storeu_ps( dst + j + 4, v1 ); + } + } +#endif + + for( ; j < roi.width; j++ ) + { + float v = src[j]; + dst[j] = v > thresh ? v : 0; + } + } + break; + + case THRESH_TOZERO_INV: + for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step ) + { + j = 0; +#if CV_SSE2 + if( useSIMD ) + { + __m128 thresh4 = _mm_set1_ps(thresh); + for( ; j <= roi.width - 8; j += 8 ) + { + __m128 v0, v1; + v0 = _mm_loadu_ps( src + j ); + v1 = _mm_loadu_ps( src + j + 4 ); + v0 = _mm_and_ps(v0, _mm_cmple_ps(v0, thresh4)); + v1 = _mm_and_ps(v1, _mm_cmple_ps(v1, thresh4)); + _mm_storeu_ps( dst + j, v0 ); + _mm_storeu_ps( dst + j + 4, v1 ); + } + } +#endif + for( ; j < roi.width; j++ ) + { + float v = src[j]; + dst[j] = v <= thresh ? v : 0; + } + } + break; + default: + return CV_Error( CV_StsBadArg, "" ); + } +} + + +static double +getThreshVal_Otsu_8u( const Mat& _src ) +{ + Size size = _src.size(); + if( _src.isContinuous() ) + { + size.width *= size.height; + size.height = 1; + } + const int N = 256; + int i, j, h[N] = {0}; + for( i = 0; i < size.height; i++ ) + { + const uchar* src = _src.data + _src.step*i; + j = 0; + #if CV_ENABLE_UNROLLED + for( ; j <= size.width - 4; j += 4 ) + { + int v0 = src[j], v1 = src[j+1]; + h[v0]++; h[v1]++; + v0 = src[j+2]; v1 = src[j+3]; + h[v0]++; h[v1]++; + } + #endif + for( ; j < size.width; j++ ) + h[src[j]]++; + } + + double mu = 0, scale = 1./(size.width*size.height); + for( i = 0; i < N; i++ ) + mu += i*(double)h[i]; + + mu *= scale; + double mu1 = 0, q1 = 0; + double max_sigma = 0, max_val = 0; + + for( i = 0; i < N; i++ ) + { + double p_i, q2, mu2, sigma; + + p_i = h[i]*scale; + mu1 *= q1; + q1 += p_i; + q2 = 1. - q1; + + if( std::min(q1,q2) < FLT_EPSILON || std::max(q1,q2) > 1. - FLT_EPSILON ) + continue; + + mu1 = (mu1 + i*p_i)/q1; + mu2 = (mu - q1*mu1)/q2; + sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2); + if( sigma > max_sigma ) + { + max_sigma = sigma; + max_val = i; + } + } + + return max_val; +} + +class ThresholdRunner +{ +public: + ThresholdRunner(Mat _src, Mat _dst, int _nStripes, double _thresh, double _maxval, int _thresholdType) + { + src = _src; + dst = _dst; + + nStripes = _nStripes; + + thresh = _thresh; + maxval = _maxval; + thresholdType = _thresholdType; + } + + void operator () ( const BlockedRange& range ) const + { + int row0 = std::min(cvRound(range.begin() * src.rows / nStripes), src.rows); + int row1 = std::min(cvRound(range.end() * src.rows / nStripes), src.rows); + + /*if(0) + printf("Size = (%d, %d), range[%d,%d), row0 = %d, row1 = %d\n", + src.rows, src.cols, range.begin(), range.end(), row0, row1);*/ + + Mat srcStripe = src.rowRange(row0, row1); + Mat dstStripe = dst.rowRange(row0, row1); + + if (srcStripe.depth() == CV_8U) + { + thresh_8u( srcStripe, dstStripe, (uchar)thresh, (uchar)maxval, thresholdType ); + } + else if( srcStripe.depth() == CV_16S ) + { + thresh_16s( srcStripe, dstStripe, (short)thresh, (short)maxval, thresholdType ); + } + else if( srcStripe.depth() == CV_32F ) + { + thresh_32f( srcStripe, dstStripe, (float)thresh, (float)maxval, thresholdType ); + } + } + +private: + Mat src; + Mat dst; + int nStripes; + + double thresh; + double maxval; + int thresholdType; +}; + +} + +double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double maxval, int type ) +{ + Mat src = _src.getMat(); + bool use_otsu = (type & THRESH_OTSU) != 0; + type &= THRESH_MASK; + + if( use_otsu ) + { + CV_Assert( src.type() == CV_8UC1 ); + thresh = getThreshVal_Otsu_8u(src); + } + + _dst.create( src.size(), src.type() ); + Mat dst = _dst.getMat(); + + int nStripes = 1; +#if defined HAVE_TBB && defined ANDROID + nStripes = 4; +#endif + + if( src.depth() == CV_8U ) + { + int ithresh = cvFloor(thresh); + thresh = ithresh; + int imaxval = cvRound(maxval); + if( type == THRESH_TRUNC ) + imaxval = ithresh; + imaxval = saturate_cast(imaxval); + + if( ithresh < 0 || ithresh >= 255 ) + { + if( type == THRESH_BINARY || type == THRESH_BINARY_INV || + ((type == THRESH_TRUNC || type == THRESH_TOZERO_INV) && ithresh < 0) || + (type == THRESH_TOZERO && ithresh >= 255) ) + { + int v = type == THRESH_BINARY ? (ithresh >= 255 ? 0 : imaxval) : + type == THRESH_BINARY_INV ? (ithresh >= 255 ? imaxval : 0) : + /*type == THRESH_TRUNC ? imaxval :*/ 0; + dst.setTo(v); + } + else + src.copyTo(dst); + } + else + { + parallel_for(BlockedRange(0, nStripes), + ThresholdRunner(src, dst, nStripes, (uchar)ithresh, (uchar)imaxval, type)); + } + } + else if( src.depth() == CV_16S ) + { + int ithresh = cvFloor(thresh); + thresh = ithresh; + int imaxval = cvRound(maxval); + if( type == THRESH_TRUNC ) + imaxval = ithresh; + imaxval = saturate_cast(imaxval); + + if( ithresh < SHRT_MIN || ithresh >= SHRT_MAX ) + { + if( type == THRESH_BINARY || type == THRESH_BINARY_INV || + ((type == THRESH_TRUNC || type == THRESH_TOZERO_INV) && ithresh < SHRT_MIN) || + (type == THRESH_TOZERO && ithresh >= SHRT_MAX) ) + { + int v = type == THRESH_BINARY ? (ithresh >= SHRT_MAX ? 0 : imaxval) : + type == THRESH_BINARY_INV ? (ithresh >= SHRT_MAX ? imaxval : 0) : + /*type == THRESH_TRUNC ? imaxval :*/ 0; + dst.setTo(v); + } + else + src.copyTo(dst); + } + else + { + parallel_for(BlockedRange(0, nStripes), + ThresholdRunner(src, dst, nStripes, (short)ithresh, (short)imaxval, type)); + } + } + else if( src.depth() == CV_32F ) + { + parallel_for(BlockedRange(0, nStripes), + ThresholdRunner(src, dst, nStripes, (float)thresh, (float)maxval, type)); + } + else + CV_Error( CV_StsUnsupportedFormat, "" ); + + return thresh; +} + + +void cv::adaptiveThreshold( InputArray _src, OutputArray _dst, double maxValue, + int method, int type, int blockSize, double delta ) +{ + Mat src = _src.getMat(); + CV_Assert( src.type() == CV_8UC1 ); + CV_Assert( blockSize % 2 == 1 && blockSize > 1 ); + Size size = src.size(); + + _dst.create( size, src.type() ); + Mat dst = _dst.getMat(); + + if( maxValue < 0 ) + { + dst = Scalar(0); + return; + } + + Mat mean; + + if( src.data != dst.data ) + mean = dst; + + if( method == ADAPTIVE_THRESH_MEAN_C ) + boxFilter( src, mean, src.type(), Size(blockSize, blockSize), + Point(-1,-1), true, BORDER_REPLICATE ); + else if( method == ADAPTIVE_THRESH_GAUSSIAN_C ) + GaussianBlur( src, mean, Size(blockSize, blockSize), 0, 0, BORDER_REPLICATE ); + else + CV_Error( CV_StsBadFlag, "Unknown/unsupported adaptive threshold method" ); + + int i, j; + uchar imaxval = saturate_cast(maxValue); + int idelta = type == THRESH_BINARY ? cvCeil(delta) : cvFloor(delta); + uchar tab[768]; + + if( type == CV_THRESH_BINARY ) + for( i = 0; i < 768; i++ ) + tab[i] = (uchar)(i - 255 > -idelta ? imaxval : 0); + else if( type == CV_THRESH_BINARY_INV ) + for( i = 0; i < 768; i++ ) + tab[i] = (uchar)(i - 255 <= -idelta ? imaxval : 0); + else + CV_Error( CV_StsBadFlag, "Unknown/unsupported threshold type" ); + + if( src.isContinuous() && mean.isContinuous() && dst.isContinuous() ) + { + size.width *= size.height; + size.height = 1; + } + + for( i = 0; i < size.height; i++ ) + { + const uchar* sdata = src.data + src.step*i; + const uchar* mdata = mean.data + mean.step*i; + uchar* ddata = dst.data + dst.step*i; + + for( j = 0; j < size.width; j++ ) + ddata[j] = tab[sdata[j] - mdata[j] + 255]; + } +} + +CV_IMPL double +cvThreshold( const void* srcarr, void* dstarr, double thresh, double maxval, int type ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), dst0 = dst; + + CV_Assert( src.size == dst.size && src.channels() == dst.channels() && + (src.depth() == dst.depth() || dst.depth() == CV_8U)); + + thresh = cv::threshold( src, dst, thresh, maxval, type ); + if( dst0.data != dst.data ) + dst.convertTo( dst0, dst0.depth() ); + return thresh; +} + + +CV_IMPL void +cvAdaptiveThreshold( const void *srcIm, void *dstIm, double maxValue, + int method, int type, int blockSize, double delta ) +{ + cv::Mat src = cv::cvarrToMat(srcIm), dst = cv::cvarrToMat(dstIm); + CV_Assert( src.size == dst.size && src.type() == dst.type() ); + cv::adaptiveThreshold( src, dst, maxValue, method, type, blockSize, delta ); +} + +/* End of file. */ diff --git a/imgproc/src/undistort.cpp b/imgproc/src/undistort.cpp new file mode 100644 index 0000000..fc13b50 --- /dev/null +++ b/imgproc/src/undistort.cpp @@ -0,0 +1,572 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +cv::Mat cv::getDefaultNewCameraMatrix( InputArray _cameraMatrix, Size imgsize, + bool centerPrincipalPoint ) +{ + Mat cameraMatrix = _cameraMatrix.getMat(); + if( !centerPrincipalPoint && cameraMatrix.type() == CV_64F ) + return cameraMatrix; + + Mat newCameraMatrix; + cameraMatrix.convertTo(newCameraMatrix, CV_64F); + if( centerPrincipalPoint ) + { + ((double*)newCameraMatrix.data)[2] = (imgsize.width-1)*0.5; + ((double*)newCameraMatrix.data)[5] = (imgsize.height-1)*0.5; + } + return newCameraMatrix; +} + +void cv::initUndistortRectifyMap( InputArray _cameraMatrix, InputArray _distCoeffs, + InputArray _matR, InputArray _newCameraMatrix, + Size size, int m1type, OutputArray _map1, OutputArray _map2 ) +{ + Mat cameraMatrix = _cameraMatrix.getMat(), distCoeffs = _distCoeffs.getMat(); + Mat matR = _matR.getMat(), newCameraMatrix = _newCameraMatrix.getMat(); + + if( m1type <= 0 ) + m1type = CV_16SC2; + CV_Assert( m1type == CV_16SC2 || m1type == CV_32FC1 || m1type == CV_32FC2 ); + _map1.create( size, m1type ); + Mat map1 = _map1.getMat(), map2; + if( m1type != CV_32FC2 ) + { + _map2.create( size, m1type == CV_16SC2 ? CV_16UC1 : CV_32FC1 ); + map2 = _map2.getMat(); + } + else + _map2.release(); + + Mat_ R = Mat_::eye(3, 3); + Mat_ A = Mat_(cameraMatrix), Ar; + + if( newCameraMatrix.data ) + Ar = Mat_(newCameraMatrix); + else + Ar = getDefaultNewCameraMatrix( A, size, true ); + + if( matR.data ) + R = Mat_(matR); + + if( distCoeffs.data ) + distCoeffs = Mat_(distCoeffs); + else + { + distCoeffs.create(8, 1, CV_64F); + distCoeffs = 0.; + } + + CV_Assert( A.size() == Size(3,3) && A.size() == R.size() ); + CV_Assert( Ar.size() == Size(3,3) || Ar.size() == Size(4, 3)); + Mat_ iR = (Ar.colRange(0,3)*R).inv(DECOMP_LU); + const double* ir = &iR(0,0); + + double u0 = A(0, 2), v0 = A(1, 2); + double fx = A(0, 0), fy = A(1, 1); + + CV_Assert( distCoeffs.size() == Size(1, 4) || distCoeffs.size() == Size(4, 1) || + distCoeffs.size() == Size(1, 5) || distCoeffs.size() == Size(5, 1) || + distCoeffs.size() == Size(1, 8) || distCoeffs.size() == Size(8, 1)); + + if( distCoeffs.rows != 1 && !distCoeffs.isContinuous() ) + distCoeffs = distCoeffs.t(); + + double k1 = ((double*)distCoeffs.data)[0]; + double k2 = ((double*)distCoeffs.data)[1]; + double p1 = ((double*)distCoeffs.data)[2]; + double p2 = ((double*)distCoeffs.data)[3]; + double k3 = distCoeffs.cols + distCoeffs.rows - 1 >= 5 ? ((double*)distCoeffs.data)[4] : 0.; + double k4 = distCoeffs.cols + distCoeffs.rows - 1 >= 8 ? ((double*)distCoeffs.data)[5] : 0.; + double k5 = distCoeffs.cols + distCoeffs.rows - 1 >= 8 ? ((double*)distCoeffs.data)[6] : 0.; + double k6 = distCoeffs.cols + distCoeffs.rows - 1 >= 8 ? ((double*)distCoeffs.data)[7] : 0.; + + for( int i = 0; i < size.height; i++ ) + { + float* m1f = (float*)(map1.data + map1.step*i); + float* m2f = (float*)(map2.data + map2.step*i); + short* m1 = (short*)m1f; + ushort* m2 = (ushort*)m2f; + double _x = i*ir[1] + ir[2], _y = i*ir[4] + ir[5], _w = i*ir[7] + ir[8]; + + for( int j = 0; j < size.width; j++, _x += ir[0], _y += ir[3], _w += ir[6] ) + { + double w = 1./_w, x = _x*w, y = _y*w; + double x2 = x*x, y2 = y*y; + double r2 = x2 + y2, _2xy = 2*x*y; + double kr = (1 + ((k3*r2 + k2)*r2 + k1)*r2)/(1 + ((k6*r2 + k5)*r2 + k4)*r2); + double u = fx*(x*kr + p1*_2xy + p2*(r2 + 2*x2)) + u0; + double v = fy*(y*kr + p1*(r2 + 2*y2) + p2*_2xy) + v0; + if( m1type == CV_16SC2 ) + { + int iu = saturate_cast(u*INTER_TAB_SIZE); + int iv = saturate_cast(v*INTER_TAB_SIZE); + m1[j*2] = (short)(iu >> INTER_BITS); + m1[j*2+1] = (short)(iv >> INTER_BITS); + m2[j] = (ushort)((iv & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (iu & (INTER_TAB_SIZE-1))); + } + else if( m1type == CV_32FC1 ) + { + m1f[j] = (float)u; + m2f[j] = (float)v; + } + else + { + m1f[j*2] = (float)u; + m1f[j*2+1] = (float)v; + } + } + } +} + + +void cv::undistort( InputArray _src, OutputArray _dst, InputArray _cameraMatrix, + InputArray _distCoeffs, InputArray _newCameraMatrix ) +{ + Mat src = _src.getMat(), cameraMatrix = _cameraMatrix.getMat(); + Mat distCoeffs = _distCoeffs.getMat(), newCameraMatrix = _newCameraMatrix.getMat(); + + _dst.create( src.size(), src.type() ); + Mat dst = _dst.getMat(); + + CV_Assert( dst.data != src.data ); + + int stripe_size0 = std::min(std::max(1, (1 << 12) / std::max(src.cols, 1)), src.rows); + Mat map1(stripe_size0, src.cols, CV_16SC2), map2(stripe_size0, src.cols, CV_16UC1); + + Mat_ A, Ar, I = Mat_::eye(3,3); + + cameraMatrix.convertTo(A, CV_64F); + if( distCoeffs.data ) + distCoeffs = Mat_(distCoeffs); + else + { + distCoeffs.create(5, 1, CV_64F); + distCoeffs = 0.; + } + + if( newCameraMatrix.data ) + newCameraMatrix.convertTo(Ar, CV_64F); + else + A.copyTo(Ar); + + double v0 = Ar(1, 2); + for( int y = 0; y < src.rows; y += stripe_size0 ) + { + int stripe_size = std::min( stripe_size0, src.rows - y ); + Ar(1, 2) = v0 - y; + Mat map1_part = map1.rowRange(0, stripe_size), + map2_part = map2.rowRange(0, stripe_size), + dst_part = dst.rowRange(y, y + stripe_size); + + initUndistortRectifyMap( A, distCoeffs, I, Ar, Size(src.cols, stripe_size), + map1_part.type(), map1_part, map2_part ); + remap( src, dst_part, map1_part, map2_part, INTER_LINEAR, BORDER_CONSTANT ); + } +} + + +CV_IMPL void +cvUndistort2( const CvArr* srcarr, CvArr* dstarr, const CvMat* Aarr, const CvMat* dist_coeffs, const CvMat* newAarr ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), dst0 = dst; + cv::Mat A = cv::cvarrToMat(Aarr), distCoeffs = cv::cvarrToMat(dist_coeffs), newA; + if( newAarr ) + newA = cv::cvarrToMat(newAarr); + + CV_Assert( src.size() == dst.size() && src.type() == dst.type() ); + cv::undistort( src, dst, A, distCoeffs, newA ); +} + + +CV_IMPL void cvInitUndistortMap( const CvMat* Aarr, const CvMat* dist_coeffs, + CvArr* mapxarr, CvArr* mapyarr ) +{ + cv::Mat A = cv::cvarrToMat(Aarr), distCoeffs = cv::cvarrToMat(dist_coeffs); + cv::Mat mapx = cv::cvarrToMat(mapxarr), mapy, mapx0 = mapx, mapy0; + + if( mapyarr ) + mapy0 = mapy = cv::cvarrToMat(mapyarr); + + cv::initUndistortRectifyMap( A, distCoeffs, cv::Mat(), A, + mapx.size(), mapx.type(), mapx, mapy ); + CV_Assert( mapx0.data == mapx.data && mapy0.data == mapy.data ); +} + +void +cvInitUndistortRectifyMap( const CvMat* Aarr, const CvMat* dist_coeffs, + const CvMat *Rarr, const CvMat* ArArr, CvArr* mapxarr, CvArr* mapyarr ) +{ + cv::Mat A = cv::cvarrToMat(Aarr), distCoeffs, R, Ar; + cv::Mat mapx = cv::cvarrToMat(mapxarr), mapy, mapx0 = mapx, mapy0; + + if( mapyarr ) + mapy0 = mapy = cv::cvarrToMat(mapyarr); + + if( dist_coeffs ) + distCoeffs = cv::cvarrToMat(dist_coeffs); + if( Rarr ) + R = cv::cvarrToMat(Rarr); + if( ArArr ) + Ar = cv::cvarrToMat(ArArr); + + cv::initUndistortRectifyMap( A, distCoeffs, R, Ar, mapx.size(), mapx.type(), mapx, mapy ); + CV_Assert( mapx0.data == mapx.data && mapy0.data == mapy.data ); +} + + +void cvUndistortPoints( const CvMat* _src, CvMat* _dst, const CvMat* _cameraMatrix, + const CvMat* _distCoeffs, + const CvMat* matR, const CvMat* matP ) +{ + double A[3][3], RR[3][3], k[8]={0,0,0,0,0,0,0,0}, fx, fy, ifx, ify, cx, cy; + CvMat matA=cvMat(3, 3, CV_64F, A), _Dk; + CvMat _RR=cvMat(3, 3, CV_64F, RR); + const CvPoint2D32f* srcf; + const CvPoint2D64f* srcd; + CvPoint2D32f* dstf; + CvPoint2D64f* dstd; + int stype, dtype; + int sstep, dstep; + int i, j, n, iters = 1; + + CV_Assert( CV_IS_MAT(_src) && CV_IS_MAT(_dst) && + (_src->rows == 1 || _src->cols == 1) && + (_dst->rows == 1 || _dst->cols == 1) && + _src->cols + _src->rows - 1 == _dst->rows + _dst->cols - 1 && + (CV_MAT_TYPE(_src->type) == CV_32FC2 || CV_MAT_TYPE(_src->type) == CV_64FC2) && + (CV_MAT_TYPE(_dst->type) == CV_32FC2 || CV_MAT_TYPE(_dst->type) == CV_64FC2)); + + CV_Assert( CV_IS_MAT(_cameraMatrix) && + _cameraMatrix->rows == 3 && _cameraMatrix->cols == 3 ); + + cvConvert( _cameraMatrix, &matA ); + + if( _distCoeffs ) + { + CV_Assert( CV_IS_MAT(_distCoeffs) && + (_distCoeffs->rows == 1 || _distCoeffs->cols == 1) && + (_distCoeffs->rows*_distCoeffs->cols == 4 || + _distCoeffs->rows*_distCoeffs->cols == 5 || + _distCoeffs->rows*_distCoeffs->cols == 8)); + + _Dk = cvMat( _distCoeffs->rows, _distCoeffs->cols, + CV_MAKETYPE(CV_64F,CV_MAT_CN(_distCoeffs->type)), k); + + cvConvert( _distCoeffs, &_Dk ); + iters = 5; + } + + if( matR ) + { + CV_Assert( CV_IS_MAT(matR) && matR->rows == 3 && matR->cols == 3 ); + cvConvert( matR, &_RR ); + } + else + cvSetIdentity(&_RR); + + if( matP ) + { + double PP[3][3]; + CvMat _P3x3, _PP=cvMat(3, 3, CV_64F, PP); + CV_Assert( CV_IS_MAT(matP) && matP->rows == 3 && (matP->cols == 3 || matP->cols == 4)); + cvConvert( cvGetCols(matP, &_P3x3, 0, 3), &_PP ); + cvMatMul( &_PP, &_RR, &_RR ); + } + + srcf = (const CvPoint2D32f*)_src->data.ptr; + srcd = (const CvPoint2D64f*)_src->data.ptr; + dstf = (CvPoint2D32f*)_dst->data.ptr; + dstd = (CvPoint2D64f*)_dst->data.ptr; + stype = CV_MAT_TYPE(_src->type); + dtype = CV_MAT_TYPE(_dst->type); + sstep = _src->rows == 1 ? 1 : _src->step/CV_ELEM_SIZE(stype); + dstep = _dst->rows == 1 ? 1 : _dst->step/CV_ELEM_SIZE(dtype); + + n = _src->rows + _src->cols - 1; + + fx = A[0][0]; + fy = A[1][1]; + ifx = 1./fx; + ify = 1./fy; + cx = A[0][2]; + cy = A[1][2]; + + for( i = 0; i < n; i++ ) + { + double x, y, x0, y0; + if( stype == CV_32FC2 ) + { + x = srcf[i*sstep].x; + y = srcf[i*sstep].y; + } + else + { + x = srcd[i*sstep].x; + y = srcd[i*sstep].y; + } + + x0 = x = (x - cx)*ifx; + y0 = y = (y - cy)*ify; + + // compensate distortion iteratively + for( j = 0; j < iters; j++ ) + { + double r2 = x*x + y*y; + double icdist = (1 + ((k[7]*r2 + k[6])*r2 + k[5])*r2)/(1 + ((k[4]*r2 + k[1])*r2 + k[0])*r2); + double deltaX = 2*k[2]*x*y + k[3]*(r2 + 2*x*x); + double deltaY = k[2]*(r2 + 2*y*y) + 2*k[3]*x*y; + x = (x0 - deltaX)*icdist; + y = (y0 - deltaY)*icdist; + } + + double xx = RR[0][0]*x + RR[0][1]*y + RR[0][2]; + double yy = RR[1][0]*x + RR[1][1]*y + RR[1][2]; + double ww = 1./(RR[2][0]*x + RR[2][1]*y + RR[2][2]); + x = xx*ww; + y = yy*ww; + + if( dtype == CV_32FC2 ) + { + dstf[i*dstep].x = (float)x; + dstf[i*dstep].y = (float)y; + } + else + { + dstd[i*dstep].x = x; + dstd[i*dstep].y = y; + } + } +} + + +void cv::undistortPoints( InputArray _src, OutputArray _dst, + InputArray _cameraMatrix, + InputArray _distCoeffs, + InputArray _Rmat, + InputArray _Pmat ) +{ + Mat src = _src.getMat(), cameraMatrix = _cameraMatrix.getMat(); + Mat distCoeffs = _distCoeffs.getMat(), R = _Rmat.getMat(), P = _Pmat.getMat(); + + CV_Assert( src.isContinuous() && (src.depth() == CV_32F || src.depth() == CV_64F) && + ((src.rows == 1 && src.channels() == 2) || src.cols*src.channels() == 2)); + + _dst.create(src.size(), src.type(), -1, true); + Mat dst = _dst.getMat(); + + CvMat _csrc = src, _cdst = dst, _ccameraMatrix = cameraMatrix; + CvMat matR, matP, _cdistCoeffs, *pR=0, *pP=0, *pD=0; + if( R.data ) + pR = &(matR = R); + if( P.data ) + pP = &(matP = P); + if( distCoeffs.data ) + pD = &(_cdistCoeffs = distCoeffs); + cvUndistortPoints(&_csrc, &_cdst, &_ccameraMatrix, pD, pR, pP); +} + +namespace cv +{ + +static Point2f mapPointSpherical(const Point2f& p, float alpha, Vec4d* J, int projType) +{ + double x = p.x, y = p.y; + double beta = 1 + 2*alpha; + double v = x*x + y*y + 1, iv = 1/v; + double u = sqrt(beta*v + alpha*alpha); + + double k = (u - alpha)*iv; + double kv = (v*beta/u - (u - alpha)*2)*iv*iv; + double kx = kv*x, ky = kv*y; + + if( projType == PROJ_SPHERICAL_ORTHO ) + { + if(J) + *J = Vec4d(kx*x + k, kx*y, ky*x, ky*y + k); + return Point2f((float)(x*k), (float)(y*k)); + } + if( projType == PROJ_SPHERICAL_EQRECT ) + { + // equirectangular + double iR = 1/(alpha + 1); + double x1 = std::max(std::min(x*k*iR, 1.), -1.); + double y1 = std::max(std::min(y*k*iR, 1.), -1.); + + if(J) + { + double fx1 = iR/sqrt(1 - x1*x1); + double fy1 = iR/sqrt(1 - y1*y1); + *J = Vec4d(fx1*(kx*x + k), fx1*ky*x, fy1*kx*y, fy1*(ky*y + k)); + } + return Point2f((float)asin(x1), (float)asin(y1)); + } + CV_Error(CV_StsBadArg, "Unknown projection type"); + return Point2f(); +} + + +static Point2f invMapPointSpherical(Point2f _p, float alpha, int projType) +{ + static int avgiter = 0, avgn = 0; + + double eps = 1e-12; + Vec2d p(_p.x, _p.y), q(_p.x, _p.y), err; + Vec4d J; + int i, maxiter = 5; + + for( i = 0; i < maxiter; i++ ) + { + Point2f p1 = mapPointSpherical(Point2f((float)q[0], (float)q[1]), alpha, &J, projType); + err = Vec2d(p1.x, p1.y) - p; + if( err[0]*err[0] + err[1]*err[1] < eps ) + break; + + Vec4d JtJ(J[0]*J[0] + J[2]*J[2], J[0]*J[1] + J[2]*J[3], + J[0]*J[1] + J[2]*J[3], J[1]*J[1] + J[3]*J[3]); + double d = JtJ[0]*JtJ[3] - JtJ[1]*JtJ[2]; + d = d ? 1./d : 0; + Vec4d iJtJ(JtJ[3]*d, -JtJ[1]*d, -JtJ[2]*d, JtJ[0]*d); + Vec2d JtErr(J[0]*err[0] + J[2]*err[1], J[1]*err[0] + J[3]*err[1]); + + q -= Vec2d(iJtJ[0]*JtErr[0] + iJtJ[1]*JtErr[1], iJtJ[2]*JtErr[0] + iJtJ[3]*JtErr[1]); + //Matx22d J(kx*x + k, kx*y, ky*x, ky*y + k); + //q -= Vec2d((J.t()*J).inv()*(J.t()*err)); + } + + if( i < maxiter ) + { + avgiter += i; + avgn++; + if( avgn == 1500 ) + printf("avg iters = %g\n", (double)avgiter/avgn); + } + + return i < maxiter ? Point2f((float)q[0], (float)q[1]) : Point2f(-FLT_MAX, -FLT_MAX); +} + +} + +float cv::initWideAngleProjMap( InputArray _cameraMatrix0, InputArray _distCoeffs0, + Size imageSize, int destImageWidth, int m1type, + OutputArray _map1, OutputArray _map2, int projType, double _alpha ) +{ + Mat cameraMatrix0 = _cameraMatrix0.getMat(), distCoeffs0 = _distCoeffs0.getMat(); + double k[8] = {0,0,0,0,0,0,0,0}, M[9]={0,0,0,0,0,0,0,0,0}; + Mat distCoeffs(distCoeffs0.rows, distCoeffs0.cols, CV_MAKETYPE(CV_64F,distCoeffs0.channels()), k); + Mat cameraMatrix(3,3,CV_64F,M); + Point2f scenter((float)cameraMatrix.at(0,2), (float)cameraMatrix.at(1,2)); + Point2f dcenter((destImageWidth-1)*0.5f, 0.f); + float xmin = FLT_MAX, xmax = -FLT_MAX, ymin = FLT_MAX, ymax = -FLT_MAX; + int N = 9; + std::vector uvec(1), vvec(1); + Mat I = Mat::eye(3,3,CV_64F); + float alpha = (float)_alpha; + + int ndcoeffs = distCoeffs0.cols*distCoeffs0.rows*distCoeffs0.channels(); + CV_Assert((distCoeffs0.cols == 1 || distCoeffs0.rows == 1) && + (ndcoeffs == 4 || ndcoeffs == 5 || ndcoeffs == 8)); + CV_Assert(cameraMatrix0.size() == Size(3,3)); + distCoeffs0.convertTo(distCoeffs,CV_64F); + cameraMatrix0.convertTo(cameraMatrix,CV_64F); + + alpha = std::min(alpha, 0.999f); + + for( int i = 0; i < N; i++ ) + for( int j = 0; j < N; j++ ) + { + Point2f p((float)j*imageSize.width/(N-1), (float)i*imageSize.height/(N-1)); + uvec[0] = p; + undistortPoints(uvec, vvec, cameraMatrix, distCoeffs, I, I); + Point2f q = mapPointSpherical(vvec[0], alpha, 0, projType); + if( xmin > q.x ) xmin = q.x; + if( xmax < q.x ) xmax = q.x; + if( ymin > q.y ) ymin = q.y; + if( ymax < q.y ) ymax = q.y; + } + + float scale = (float)std::min(dcenter.x/fabs(xmax), dcenter.x/fabs(xmin)); + Size dsize(destImageWidth, cvCeil(std::max(scale*fabs(ymin)*2, scale*fabs(ymax)*2))); + dcenter.y = (dsize.height - 1)*0.5f; + + Mat mapxy(dsize, CV_32FC2); + double k1 = k[0], k2 = k[1], k3 = k[2], p1 = k[3], p2 = k[4], k4 = k[5], k5 = k[6], k6 = k[7]; + double fx = cameraMatrix.at(0,0), fy = cameraMatrix.at(1,1), cx = scenter.x, cy = scenter.y; + + for( int y = 0; y < dsize.height; y++ ) + { + Point2f* mxy = mapxy.ptr(y); + for( int x = 0; x < dsize.width; x++ ) + { + Point2f p = (Point2f((float)x, (float)y) - dcenter)*(1.f/scale); + Point2f q = invMapPointSpherical(p, alpha, projType); + if( q.x <= -FLT_MAX && q.y <= -FLT_MAX ) + { + mxy[x] = Point2f(-1.f, -1.f); + continue; + } + double x2 = q.x*q.x, y2 = q.y*q.y; + double r2 = x2 + y2, _2xy = 2*q.x*q.y; + double kr = 1 + ((k3*r2 + k2)*r2 + k1)*r2/(1 + ((k6*r2 + k5)*r2 + k4)*r2); + double u = fx*(q.x*kr + p1*_2xy + p2*(r2 + 2*x2)) + cx; + double v = fy*(q.y*kr + p1*(r2 + 2*y2) + p2*_2xy) + cy; + + mxy[x] = Point2f((float)u, (float)v); + } + } + + if(m1type == CV_32FC2) + { + _map1.create(mapxy.size(), mapxy.type()); + Mat map1 = _map1.getMat(); + mapxy.copyTo(map1); + _map2.release(); + } + else + convertMaps(mapxy, Mat(), _map1, _map2, m1type, false); + + return scale; +} + +/* End of file */ diff --git a/imgproc/src/utils.cpp b/imgproc/src/utils.cpp new file mode 100644 index 0000000..e7a9438 --- /dev/null +++ b/imgproc/src/utils.cpp @@ -0,0 +1,276 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "precomp.hpp" + +CV_IMPL CvSeq* cvPointSeqFromMat( int seq_kind, const CvArr* arr, + CvContour* contour_header, CvSeqBlock* block ) +{ + CV_Assert( arr != 0 && contour_header != 0 && block != 0 ); + + int eltype; + CvMat* mat = (CvMat*)arr; + + if( !CV_IS_MAT( mat )) + CV_Error( CV_StsBadArg, "Input array is not a valid matrix" ); + + eltype = CV_MAT_TYPE( mat->type ); + if( eltype != CV_32SC2 && eltype != CV_32FC2 ) + CV_Error( CV_StsUnsupportedFormat, + "The matrix can not be converted to point sequence because of " + "inappropriate element type" ); + + if( (mat->width != 1 && mat->height != 1) || !CV_IS_MAT_CONT(mat->type)) + CV_Error( CV_StsBadArg, + "The matrix converted to point sequence must be " + "1-dimensional and continuous" ); + + cvMakeSeqHeaderForArray( + (seq_kind & (CV_SEQ_KIND_MASK|CV_SEQ_FLAG_CLOSED)) | eltype, + sizeof(CvContour), CV_ELEM_SIZE(eltype), mat->data.ptr, + mat->width*mat->height, (CvSeq*)contour_header, block ); + + return (CvSeq*)contour_header; +} + +namespace cv +{ + +static void copyMakeBorder_8u( const uchar* src, size_t srcstep, Size srcroi, + uchar* dst, size_t dststep, Size dstroi, + int top, int left, int cn, int borderType ) +{ + const int isz = (int)sizeof(int); + int i, j, k, elemSize = 1; + bool intMode = false; + + if( (cn | srcstep | dststep | (size_t)src | (size_t)dst) % isz == 0 ) + { + cn /= isz; + elemSize = isz; + intMode = true; + } + + AutoBuffer _tab((dstroi.width - srcroi.width)*cn); + int* tab = _tab; + int right = dstroi.width - srcroi.width - left; + int bottom = dstroi.height - srcroi.height - top; + + for( i = 0; i < left; i++ ) + { + j = borderInterpolate(i - left, srcroi.width, borderType)*cn; + for( k = 0; k < cn; k++ ) + tab[i*cn + k] = j + k; + } + + for( i = 0; i < right; i++ ) + { + j = borderInterpolate(srcroi.width + i, srcroi.width, borderType)*cn; + for( k = 0; k < cn; k++ ) + tab[(i+left)*cn + k] = j + k; + } + + srcroi.width *= cn; + dstroi.width *= cn; + left *= cn; + right *= cn; + + uchar* dstInner = dst + dststep*top + left*elemSize; + + for( i = 0; i < srcroi.height; i++, dstInner += dststep, src += srcstep ) + { + if( dstInner != src ) + memcpy(dstInner, src, srcroi.width*elemSize); + + if( intMode ) + { + const int* isrc = (int*)src; + int* idstInner = (int*)dstInner; + for( j = 0; j < left; j++ ) + idstInner[j - left] = isrc[tab[j]]; + for( j = 0; j < right; j++ ) + idstInner[j + srcroi.width] = isrc[tab[j + left]]; + } + else + { + for( j = 0; j < left; j++ ) + dstInner[j - left] = src[tab[j]]; + for( j = 0; j < right; j++ ) + dstInner[j + srcroi.width] = src[tab[j + left]]; + } + } + + dstroi.width *= elemSize; + dst += dststep*top; + + for( i = 0; i < top; i++ ) + { + j = borderInterpolate(i - top, srcroi.height, borderType); + memcpy(dst + (i - top)*dststep, dst + j*dststep, dstroi.width); + } + + for( i = 0; i < bottom; i++ ) + { + j = borderInterpolate(i + srcroi.height, srcroi.height, borderType); + memcpy(dst + (i + srcroi.height)*dststep, dst + j*dststep, dstroi.width); + } +} + + +static void copyMakeConstBorder_8u( const uchar* src, size_t srcstep, Size srcroi, + uchar* dst, size_t dststep, Size dstroi, + int top, int left, int cn, const uchar* value ) +{ + int i, j; + AutoBuffer _constBuf(dstroi.width*cn); + uchar* constBuf = _constBuf; + int right = dstroi.width - srcroi.width - left; + int bottom = dstroi.height - srcroi.height - top; + + for( i = 0; i < dstroi.width; i++ ) + { + for( j = 0; j < cn; j++ ) + constBuf[i*cn + j] = value[j]; + } + + srcroi.width *= cn; + dstroi.width *= cn; + left *= cn; + right *= cn; + + uchar* dstInner = dst + dststep*top + left; + + for( i = 0; i < srcroi.height; i++, dstInner += dststep, src += srcstep ) + { + if( dstInner != src ) + memcpy( dstInner, src, srcroi.width ); + memcpy( dstInner - left, constBuf, left ); + memcpy( dstInner + srcroi.width, constBuf, right ); + } + + dst += dststep*top; + + for( i = 0; i < top; i++ ) + memcpy(dst + (i - top)*dststep, constBuf, dstroi.width); + + for( i = 0; i < bottom; i++ ) + memcpy(dst + (i + srcroi.height)*dststep, constBuf, dstroi.width); +} + +} + +void cv::copyMakeBorder( InputArray _src, OutputArray _dst, int top, int bottom, + int left, int right, int borderType, const Scalar& value ) +{ + Mat src = _src.getMat(); + CV_Assert( top >= 0 && bottom >= 0 && left >= 0 && right >= 0 ); + + if( src.isSubmatrix() && (borderType & BORDER_ISOLATED) == 0 ) + { + Size wholeSize; + Point ofs; + src.locateROI(wholeSize, ofs); + int dtop = std::min(ofs.y, top); + int dbottom = std::min(wholeSize.height - src.rows - ofs.y, bottom); + int dleft = std::min(ofs.x, left); + int dright = std::min(wholeSize.width - src.cols - ofs.x, right); + src.adjustROI(dtop, dbottom, dleft, dright); + top -= dtop; + left -= dleft; + bottom -= dbottom; + right -= dright; + } + + _dst.create( src.rows + top + bottom, src.cols + left + right, src.type() ); + Mat dst = _dst.getMat(); + + if(top == 0 && left == 0 && bottom == 0 && right == 0) + { + if(src.data != dst.data || src.step != dst.step) + src.copyTo(dst); + return; + } + + borderType &= ~BORDER_ISOLATED; + + if( borderType != BORDER_CONSTANT ) + copyMakeBorder_8u( src.data, src.step, src.size(), + dst.data, dst.step, dst.size(), + top, left, (int)src.elemSize(), borderType ); + else + { + int cn = src.channels(), cn1 = cn; + AutoBuffer buf(cn); + if( cn > 4 ) + { + CV_Assert( value[0] == value[1] && value[0] == value[2] && value[0] == value[3] ); + cn1 = 1; + } + scalarToRawData(value, buf, CV_MAKETYPE(src.depth(), cn1), cn); + copyMakeConstBorder_8u( src.data, src.step, src.size(), + dst.data, dst.step, dst.size(), + top, left, (int)src.elemSize(), (uchar*)(double*)buf ); + } +} + + +double cv::PSNR(InputArray _src1, InputArray _src2) +{ + Mat src1 = _src1.getMat(), src2 = _src2.getMat(); + CV_Assert( src1.depth() == CV_8U ); + double diff = std::sqrt(norm(src1, src2, NORM_L2SQR)/(src1.total()*src1.channels())); + return 20*log10(255./(diff+DBL_EPSILON)); +} + + +CV_IMPL void +cvCopyMakeBorder( const CvArr* srcarr, CvArr* dstarr, CvPoint offset, + int borderType, CvScalar value ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + int left = offset.x, right = dst.cols - src.cols - left; + int top = offset.y, bottom = dst.rows - src.rows - top; + + CV_Assert( dst.type() == src.type() ); + cv::copyMakeBorder( src, dst, top, bottom, left, right, borderType, value ); +} + +/* End of file. */ diff --git a/imgproc/test/test_approxpoly.cpp b/imgproc/test/test_approxpoly.cpp new file mode 100644 index 0000000..be1751a --- /dev/null +++ b/imgproc/test/test_approxpoly.cpp @@ -0,0 +1,359 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" +#include + +using namespace cv; +using namespace std; + +// +// TODO!!!: +// check_slice (and/or check) seem(s) to be broken, or this is a bug in function +// (or its inability to handle possible self-intersections in the generated contours). +// +// At least, if // return TotalErrors; +// is uncommented in check_slice, the test fails easily. +// So, now (and it looks like since 0.9.6) +// we only check that the set of vertices of the approximated polygon is +// a subset of vertices of the original contour. +// + +class CV_ApproxPolyTest : public cvtest::BaseTest +{ +public: + CV_ApproxPolyTest(); + ~CV_ApproxPolyTest(); + void clear(); + //int write_default_params(CvFileStorage* fs); + +protected: + //int read_params( CvFileStorage* fs ); + + int check_slice( CvPoint StartPt, CvPoint EndPt, + CvSeqReader* SrcReader, float Eps, + int* j, int Count ); + int check( CvSeq* SrcSeq, CvSeq* DstSeq, float Eps ); + + bool get_contour( int /*type*/, CvSeq** Seq, int* d, + CvMemStorage* storage ); + + void run(int); +}; + + +CV_ApproxPolyTest::CV_ApproxPolyTest() +{ +} + + +CV_ApproxPolyTest::~CV_ApproxPolyTest() +{ + clear(); +} + + +void CV_ApproxPolyTest::clear() +{ + cvtest::BaseTest::clear(); +} + + +/*int CV_ApproxPolyTest::write_default_params( CvFileStorage* fs ) +{ + cvtest::BaseTest::write_default_params( fs ); + if( ts->get_testing_mode() != cvtest::TS::TIMING_MODE ) + { + write_param( fs, "test_case_count", test_case_count ); + } + return 0; +} + + +int CV_ApproxPolyTest::read_params( CvFileStorage* fs ) +{ + int code = cvtest::BaseTest::read_params( fs ); + if( code < 0 ) + return code; + + test_case_count = cvReadInt( find_param( fs, "test_case_count" ), test_case_count ); + min_log_size = cvtest::clipInt( min_log_size, 1, 10 ); + return 0; +}*/ + + +bool CV_ApproxPolyTest::get_contour( int /*type*/, CvSeq** Seq, int* d, + CvMemStorage* storage ) +{ + RNG& rng = ts->get_rng(); + int max_x = INT_MIN, max_y = INT_MIN, min_x = INT_MAX, min_y = INT_MAX; + int i; + CvSeq* seq; + int total = cvtest::randInt(rng) % 1000 + 1; + CvPoint center; + int radius, angle; + double deg_to_rad = CV_PI/180.; + CvPoint pt; + + center.x = cvtest::randInt( rng ) % 1000; + center.y = cvtest::randInt( rng ) % 1000; + radius = cvtest::randInt( rng ) % 1000; + angle = cvtest::randInt( rng ) % 360; + + seq = cvCreateSeq( CV_SEQ_POLYGON, sizeof(CvContour), sizeof(CvPoint), storage ); + + for( i = 0; i < total; i++ ) + { + int d_radius = cvtest::randInt( rng ) % 10 - 5; + int d_angle = 360/total;//cvtest::randInt( rng ) % 10 - 5; + pt.x = cvRound( center.x + radius*cos(angle*deg_to_rad)); + pt.y = cvRound( center.x - radius*sin(angle*deg_to_rad)); + radius += d_radius; + angle += d_angle; + cvSeqPush( seq, &pt ); + + max_x = MAX( max_x, pt.x ); + max_y = MAX( max_y, pt.y ); + + min_x = MIN( min_x, pt.x ); + min_y = MIN( min_y, pt.y ); + } + + *d = (max_x - min_x)*(max_x - min_x) + (max_y - min_y)*(max_y - min_y); + *Seq = seq; + return true; +} + + +int CV_ApproxPolyTest::check_slice( CvPoint StartPt, CvPoint EndPt, + CvSeqReader* SrcReader, float Eps, + int* _j, int Count ) +{ + /////////// + CvPoint Pt; + /////////// + bool flag; + double dy,dx; + double A,B,C; + double Sq; + double sin_a = 0; + double cos_a = 0; + double d = 0; + double dist; + /////////// + int j, TotalErrors = 0; + + //////////////////////////////// + if( SrcReader == NULL ) + { + assert( false ); + return 0; + } + + ///////// init line //////////// + flag = true; + + dx = (double)StartPt.x - (double)EndPt.x; + dy = (double)StartPt.y - (double)EndPt.y; + + if( ( dx == 0 ) && ( dy == 0 ) ) flag = false; + else + { + A = -dy; + B = dx; + C = dy * (double)StartPt.x - dx * (double)StartPt.y; + Sq = sqrt( A*A + B*B ); + + sin_a = B/Sq; + cos_a = A/Sq; + d = C/Sq; + } + + /////// find start point and check distance //////// + for( j = *_j; j < Count; j++ ) + { + CV_READ_SEQ_ELEM( Pt, *SrcReader ); + if( StartPt.x == Pt.x && StartPt.y == Pt.y ) break; + else + { + if( flag ) dist = sin_a * Pt.y + cos_a * Pt.x - d; + else dist = sqrt( (double)(EndPt.y - Pt.y)*(EndPt.y - Pt.y) + (EndPt.x - Pt.x)*(EndPt.x - Pt.x) ); + if( dist > Eps ) TotalErrors++; + } + } + + *_j = j; + + //return TotalErrors; + return 0; +} + + +int CV_ApproxPolyTest::check( CvSeq* SrcSeq, CvSeq* DstSeq, float Eps ) +{ + ////////// + CvSeqReader DstReader; + CvSeqReader SrcReader; + CvPoint StartPt, EndPt; + /////////// + int TotalErrors = 0; + /////////// + int Count; + int i,j; + + assert( SrcSeq && DstSeq ); + + ////////// init //////////////////// + Count = SrcSeq->total; + + cvStartReadSeq( DstSeq, &DstReader, 0 ); + cvStartReadSeq( SrcSeq, &SrcReader, 0 ); + + CV_READ_SEQ_ELEM( StartPt, DstReader ); + for( i = 0 ; i < Count ; ) + { + CV_READ_SEQ_ELEM( EndPt, SrcReader ); + i++; + if( StartPt.x == EndPt.x && StartPt.y == EndPt.y ) break; + } + + ///////// start //////////////// + for( i = 1, j = 0 ; i <= DstSeq->total ; ) + { + ///////// read slice //////////// + EndPt.x = StartPt.x; + EndPt.y = StartPt.y; + CV_READ_SEQ_ELEM( StartPt, DstReader ); + i++; + + TotalErrors += check_slice( StartPt, EndPt, &SrcReader, Eps, &j, Count ); + + if( j > Count ) + { + TotalErrors++; + return TotalErrors; + } //if( !flag ) + + } // for( int i = 0 ; i < DstSeq->total ; i++ ) + + return TotalErrors; +} + + +//extern CvTestContourGenerator cvTsTestContours[]; + +void CV_ApproxPolyTest::run( int /*start_from*/ ) +{ + int code = cvtest::TS::OK; + CvMemStorage* storage = 0; + ////////////// Variables //////////////// + int IntervalsCount = 10; + /////////// + //CvTestContourGenerator Cont; + CvSeq* SrcSeq = NULL; + CvSeq* DstSeq; + int iDiam; + float dDiam, Eps, EpsStep; + + for( int i = 0; i < 30; i++ ) + { + CvMemStoragePos pos; + + ts->update_context( this, i, false ); + + ///////////////////// init contour ///////// + dDiam = 0; + while( sqrt(dDiam) / IntervalsCount == 0 ) + { + if( storage != 0 ) + cvReleaseMemStorage(&storage); + + storage = cvCreateMemStorage( 0 ); + if( get_contour( 0, &SrcSeq, &iDiam, storage ) ) + dDiam = (float)iDiam; + } + dDiam = (float)sqrt( dDiam ); + + storage = SrcSeq->storage; + + ////////////////// test ///////////// + EpsStep = dDiam / IntervalsCount ; + for( Eps = EpsStep ; Eps < dDiam ; Eps += EpsStep ) + { + cvSaveMemStoragePos( storage, &pos ); + + ////////// call function //////////// + DstSeq = cvApproxPoly( SrcSeq, SrcSeq->header_size, storage, + CV_POLY_APPROX_DP, Eps ); + + if( DstSeq == NULL ) + { + ts->printf( cvtest::TS::LOG, + "cvApproxPoly returned NULL for contour #%d, espilon = %g\n", i, Eps ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + goto _exit_; + } // if( DstSeq == NULL ) + + code = check( SrcSeq, DstSeq, Eps ); + if( code != 0 ) + { + ts->printf( cvtest::TS::LOG, + "Incorrect result for the contour #%d approximated with epsilon=%g\n", i, Eps ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + goto _exit_; + } + + cvRestoreMemStoragePos( storage, &pos ); + } // for( Eps = EpsStep ; Eps <= Diam ; Eps += EpsStep ) + + ///////////// free memory /////////////////// + cvReleaseMemStorage(&storage); + } // for( int i = 0; NULL != ( Cont = Contours[i] ) ; i++ ) + +_exit_: + cvReleaseMemStorage(&storage); + + if( code < 0 ) + ts->set_failed_test_info( code ); +} + +TEST(Imgproc_ApproxPoly, accuracy) { CV_ApproxPolyTest test; test.safe_run(); } + diff --git a/imgproc/test/test_bilateral_filter.cpp b/imgproc/test/test_bilateral_filter.cpp new file mode 100644 index 0000000..7379b14 --- /dev/null +++ b/imgproc/test/test_bilateral_filter.cpp @@ -0,0 +1,290 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; + +namespace cvtest +{ + class CV_BilateralFilterTest : + public cvtest::BaseTest + { + public: + enum + { + MAX_WIDTH = 1920, MIN_WIDTH = 1, + MAX_HEIGHT = 1080, MIN_HEIGHT = 1 + }; + + CV_BilateralFilterTest(); + ~CV_BilateralFilterTest(); + + protected: + virtual void run_func(); + virtual int prepare_test_case(int test_case_index); + virtual int validate_test_results(int test_case_index); + + private: + void reference_bilateral_filter(const Mat& src, Mat& dst, int d, double sigma_color, + double sigma_space, int borderType = BORDER_DEFAULT); + + int getRandInt(RNG& rng, int min_value, int max_value) const; + + double _sigma_color; + double _sigma_space; + + Mat _src; + Mat _parallel_dst; + int _d; + }; + + CV_BilateralFilterTest::CV_BilateralFilterTest() : + cvtest::BaseTest(), _src(), _parallel_dst(), _d() + { + test_case_count = 1000; + } + + CV_BilateralFilterTest::~CV_BilateralFilterTest() + { + } + + int CV_BilateralFilterTest::getRandInt(RNG& rng, int min_value, int max_value) const + { + double rand_value = rng.uniform(log((double)min_value), log((double)max_value + 1)); + return cvRound(exp((double)rand_value)); + } + + void CV_BilateralFilterTest::reference_bilateral_filter(const Mat &src, Mat &dst, int d, + double sigma_color, double sigma_space, int borderType) + { + int cn = src.channels(); + int i, j, k, maxk, radius; + double minValSrc = -1, maxValSrc = 1; + const int kExpNumBinsPerChannel = 1 << 12; + int kExpNumBins = 0; + float lastExpVal = 1.f; + float len, scale_index; + Size size = src.size(); + + dst.create(size, src.type()); + + CV_Assert( (src.type() == CV_32FC1 || src.type() == CV_32FC3) && + src.type() == dst.type() && src.size() == dst.size() && + src.data != dst.data ); + + if( sigma_color <= 0 ) + sigma_color = 1; + if( sigma_space <= 0 ) + sigma_space = 1; + + double gauss_color_coeff = -0.5/(sigma_color*sigma_color); + double gauss_space_coeff = -0.5/(sigma_space*sigma_space); + + if( d <= 0 ) + radius = cvRound(sigma_space*1.5); + else + radius = d/2; + radius = MAX(radius, 1); + d = radius*2 + 1; + // compute the min/max range for the input image (even if multichannel) + + minMaxLoc( src.reshape(1), &minValSrc, &maxValSrc ); + if(std::abs(minValSrc - maxValSrc) < FLT_EPSILON) + { + src.copyTo(dst); + return; + } + + // temporary copy of the image with borders for easy processing + Mat temp; + copyMakeBorder( src, temp, radius, radius, radius, radius, borderType ); + patchNaNs(temp); + + // allocate lookup tables + vector _space_weight(d*d); + vector _space_ofs(d*d); + float* space_weight = &_space_weight[0]; + int* space_ofs = &_space_ofs[0]; + + // assign a length which is slightly more than needed + len = (float)(maxValSrc - minValSrc) * cn; + kExpNumBins = kExpNumBinsPerChannel * cn; + vector _expLUT(kExpNumBins+2); + float* expLUT = &_expLUT[0]; + + scale_index = kExpNumBins/len; + + // initialize the exp LUT + for( i = 0; i < kExpNumBins+2; i++ ) + { + if( lastExpVal > 0.f ) + { + double val = i / scale_index; + expLUT[i] = (float)std::exp(val * val * gauss_color_coeff); + lastExpVal = expLUT[i]; + } + else + expLUT[i] = 0.f; + } + + // initialize space-related bilateral filter coefficients + for( i = -radius, maxk = 0; i <= radius; i++ ) + for( j = -radius; j <= radius; j++ ) + { + double r = std::sqrt((double)i*i + (double)j*j); + if( r > radius ) + continue; + space_weight[maxk] = (float)std::exp(r*r*gauss_space_coeff); + space_ofs[maxk++] = (int)(i*(temp.step/sizeof(float)) + j*cn); + } + + for( i = 0; i < size.height; i++ ) + { + const float* sptr = (const float*)(temp.data + (i+radius)*temp.step) + radius*cn; + float* dptr = (float*)(dst.data + i*dst.step); + + if( cn == 1 ) + { + for( j = 0; j < size.width; j++ ) + { + float sum = 0, wsum = 0; + float val0 = sptr[j]; + for( k = 0; k < maxk; k++ ) + { + float val = sptr[j + space_ofs[k]]; + float alpha = (float)(std::abs(val - val0)*scale_index); + int idx = cvFloor(alpha); + alpha -= idx; + float w = space_weight[k]*(expLUT[idx] + alpha*(expLUT[idx+1] - expLUT[idx])); + sum += val*w; + wsum += w; + } + dptr[j] = (float)(sum/wsum); + } + } + else + { + assert( cn == 3 ); + for( j = 0; j < size.width*3; j += 3 ) + { + float sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0; + float b0 = sptr[j], g0 = sptr[j+1], r0 = sptr[j+2]; + for( k = 0; k < maxk; k++ ) + { + const float* sptr_k = sptr + j + space_ofs[k]; + float b = sptr_k[0], g = sptr_k[1], r = sptr_k[2]; + float alpha = (float)((std::abs(b - b0) + + std::abs(g - g0) + std::abs(r - r0))*scale_index); + int idx = cvFloor(alpha); + alpha -= idx; + float w = space_weight[k]*(expLUT[idx] + alpha*(expLUT[idx+1] - expLUT[idx])); + sum_b += b*w; sum_g += g*w; sum_r += r*w; + wsum += w; + } + wsum = 1.f/wsum; + b0 = sum_b*wsum; + g0 = sum_g*wsum; + r0 = sum_r*wsum; + dptr[j] = b0; dptr[j+1] = g0; dptr[j+2] = r0; + } + } + } + } + + int CV_BilateralFilterTest::prepare_test_case(int /* test_case_index */) + { + const static int types[] = { CV_32FC1, CV_32FC3, CV_8UC1, CV_8UC3 }; + RNG& rng = ts->get_rng(); + Size size(getRandInt(rng, MIN_WIDTH, MAX_WIDTH), getRandInt(rng, MIN_HEIGHT, MAX_HEIGHT)); + int type = types[rng(sizeof(types) / sizeof(types[0]))]; + + _d = rng.uniform(0., 1.) > 0.5 ? 5 : 3; + + _src.create(size, type); + + rng.fill(_src, RNG::UNIFORM, 0, 256); + + _sigma_color = _sigma_space = 1.; + + return 1; + } + + int CV_BilateralFilterTest::validate_test_results(int test_case_index) + { + static const double eps = 1; + + Mat reference_dst, reference_src; + if (_src.depth() == CV_32F) + reference_bilateral_filter(_src, reference_dst, _d, _sigma_color, _sigma_space); + else + { + int type = _src.type(); + _src.convertTo(reference_src, CV_32F); + reference_bilateral_filter(reference_src, reference_dst, _d, _sigma_color, _sigma_space); + reference_dst.convertTo(reference_dst, type); + } + + double e = norm(reference_dst, _parallel_dst); + if (e > eps) + { + ts->printf(cvtest::TS::CONSOLE, "actual error: %g, expected: %g", e, eps); + ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); + } + else + ts->set_failed_test_info(cvtest::TS::OK); + + return BaseTest::validate_test_results(test_case_index); + } + + void CV_BilateralFilterTest::run_func() + { + bilateralFilter(_src, _parallel_dst, _d, _sigma_color, _sigma_space); + } + + TEST(Imgproc_BilateralFilter, accuracy) + { + CV_BilateralFilterTest test; + test.safe_run(); + } + +} // end of namespace cvtest diff --git a/imgproc/test/test_boundingrect.cpp b/imgproc/test/test_boundingrect.cpp new file mode 100644 index 0000000..ffd52ba --- /dev/null +++ b/imgproc/test/test_boundingrect.cpp @@ -0,0 +1,144 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" +#include + +#define IMGPROC_BOUNDINGRECT_ERROR_DIFF 1 + +#define MESSAGE_ERROR_DIFF "Bounding rectangle found by boundingRect function is incorrect." + +using namespace cv; +using namespace std; + +class CV_BoundingRectTest: public cvtest::ArrayTest +{ +public: + CV_BoundingRectTest(); + ~CV_BoundingRectTest(); + +protected: + void run (int); + +private: + template void generate_src_points(vector >& src, int n); + template cv::Rect get_bounding_rect(const vector > src); + template bool checking_function_work(vector >& src, int type); +}; + +CV_BoundingRectTest::CV_BoundingRectTest() {} +CV_BoundingRectTest::~CV_BoundingRectTest() {} + +template void CV_BoundingRectTest::generate_src_points(vector >& src, int n) +{ + src.clear(); + for (int i = 0; i < n; ++i) + src.push_back(Point_(cv::randu(), cv::randu())); +} + +template cv::Rect CV_BoundingRectTest::get_bounding_rect(const vector > src) +{ + int n = (int)src.size(); + T min_w = std::numeric_limits::max(), max_w = std::numeric_limits::min(); + T min_h = min_w, max_h = max_w; + + for (int i = 0; i < n; ++i) + { + min_w = std::min(src.at(i).x, min_w); + max_w = std::max(src.at(i).x, max_w); + min_h = std::min(src.at(i).y, min_h); + max_h = std::max(src.at(i).y, max_h); + } + + return Rect((int)min_w, (int)min_h, (int)max_w-(int)min_w + 1, (int)max_h-(int)min_h + 1); +} + +template bool CV_BoundingRectTest::checking_function_work(vector >& src, int type) +{ + const int MAX_COUNT_OF_POINTS = 1000; + const int N = 10000; + + for (int k = 0; k < N; ++k) + { + + RNG& rng = ts->get_rng(); + + int n = rng.next()%MAX_COUNT_OF_POINTS + 1; + + generate_src_points (src, n); + + cv::Rect right = get_bounding_rect (src); + + cv::Rect rect[2] = { boundingRect(src), boundingRect(Mat(src)) }; + + for (int i = 0; i < 2; ++i) if (rect[i] != right) + { + cout << endl; cout << "Checking for the work of boundingRect function..." << endl; + cout << "Type of src points: "; + switch (type) + { + case 0: {cout << "INT"; break;} + case 1: {cout << "FLOAT"; break;} + default: break; + } + cout << endl; + cout << "Src points are stored as "; if (i == 0) cout << "VECTOR" << endl; else cout << "MAT" << endl; + cout << "Number of points: " << n << endl; + cout << "Right rect (x, y, w, h): [" << right.x << ", " << right.y << ", " << right.width << ", " << right.height << "]" << endl; + cout << "Result rect (x, y, w, h): [" << rect[i].x << ", " << rect[i].y << ", " << rect[i].width << ", " << rect[i].height << "]" << endl; + cout << endl; + CV_Error(IMGPROC_BOUNDINGRECT_ERROR_DIFF, MESSAGE_ERROR_DIFF); + return false; + } + + } + + return true; +} + +void CV_BoundingRectTest::run(int) +{ + vector src_veci; if (!checking_function_work(src_veci, 0)) return; + vector src_vecf; checking_function_work(src_vecf, 1); +} + +TEST (Imgproc_BoundingRect, accuracy) { CV_BoundingRectTest test; test.safe_run(); } diff --git a/imgproc/test/test_canny.cpp b/imgproc/test/test_canny.cpp new file mode 100644 index 0000000..568cc7c --- /dev/null +++ b/imgproc/test/test_canny.cpp @@ -0,0 +1,287 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +class CV_CannyTest : public cvtest::ArrayTest +{ +public: + CV_CannyTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + int prepare_test_case( int test_case_idx ); + void run_func(); + void prepare_to_validation( int ); + int validate_test_results( int /*test_case_idx*/ ); + + int aperture_size; + bool use_true_gradient; + double threshold1, threshold2; + bool test_cpp; +}; + + +CV_CannyTest::CV_CannyTest() +{ + test_array[INPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + element_wise_relative_error = true; + aperture_size = 0; + use_true_gradient = false; + threshold1 = threshold2 = 0; + + test_cpp = false; +} + + +void CV_CannyTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, + vector >& types ) +{ + RNG& rng = ts->get_rng(); + double thresh_range; + + cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_8U; + + aperture_size = cvtest::randInt(rng) % 2 ? 5 : 3; + thresh_range = aperture_size == 3 ? 300 : 1000; + + threshold1 = cvtest::randReal(rng)*thresh_range; + threshold2 = cvtest::randReal(rng)*thresh_range*0.3; + + if( cvtest::randInt(rng) % 2 ) + CV_SWAP( threshold1, threshold2, thresh_range ); + + use_true_gradient = cvtest::randInt(rng) % 2 != 0; + test_cpp = (cvtest::randInt(rng) & 256) == 0; +} + + +int CV_CannyTest::prepare_test_case( int test_case_idx ) +{ + int code = cvtest::ArrayTest::prepare_test_case( test_case_idx ); + if( code > 0 ) + { + Mat& src = test_mat[INPUT][0]; + GaussianBlur(src, src, Size(11, 11), 5, 5); + } + + return code; +} + + +double CV_CannyTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + return 0; +} + + +void CV_CannyTest::run_func() +{ + if(!test_cpp) + cvCanny( test_array[INPUT][0], test_array[OUTPUT][0], threshold1, threshold2, + aperture_size + (use_true_gradient ? CV_CANNY_L2_GRADIENT : 0)); + else + { + cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]); + cv::Canny(cv::cvarrToMat(test_array[INPUT][0]), _out, threshold1, threshold2, + aperture_size + (use_true_gradient ? CV_CANNY_L2_GRADIENT : 0)); + } +} + + +static void +cannyFollow( int x, int y, float lowThreshold, const Mat& mag, Mat& dst ) +{ + static const int ofs[][2] = {{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}}; + int i; + + dst.at(y, x) = (uchar)255; + + for( i = 0; i < 8; i++ ) + { + int x1 = x + ofs[i][0]; + int y1 = y + ofs[i][1]; + if( (unsigned)x1 < (unsigned)mag.cols && + (unsigned)y1 < (unsigned)mag.rows && + mag.at(y1, x1) > lowThreshold && + !dst.at(y1, x1) ) + cannyFollow( x1, y1, lowThreshold, mag, dst ); + } +} + + +static void +test_Canny( const Mat& src, Mat& dst, + double threshold1, double threshold2, + int aperture_size, bool use_true_gradient ) +{ + int m = aperture_size; + Point anchor(m/2, m/2); + const double tan_pi_8 = tan(CV_PI/8.); + const double tan_3pi_8 = tan(CV_PI*3/8); + float lowThreshold = (float)MIN(threshold1, threshold2); + float highThreshold = (float)MAX(threshold1, threshold2); + + int x, y, width = src.cols, height = src.rows; + + Mat dxkernel = cvtest::calcSobelKernel2D( 1, 0, m, 0 ); + Mat dykernel = cvtest::calcSobelKernel2D( 0, 1, m, 0 ); + Mat dx, dy, mag(height, width, CV_32F); + cvtest::filter2D(src, dx, CV_16S, dxkernel, anchor, 0, BORDER_REPLICATE); + cvtest::filter2D(src, dy, CV_16S, dykernel, anchor, 0, BORDER_REPLICATE); + + // calc gradient magnitude + for( y = 0; y < height; y++ ) + { + for( x = 0; x < width; x++ ) + { + int dxval = dx.at(y, x), dyval = dy.at(y, x); + mag.at(y, x) = use_true_gradient ? + (float)sqrt((double)(dxval*dxval + dyval*dyval)) : + (float)(fabs((double)dxval) + fabs((double)dyval)); + } + } + + // calc gradient direction, do nonmaxima suppression + for( y = 0; y < height; y++ ) + { + for( x = 0; x < width; x++ ) + { + + float a = mag.at(y, x), b = 0, c = 0; + int y1 = 0, y2 = 0, x1 = 0, x2 = 0; + + if( a <= lowThreshold ) + continue; + + int dxval = dx.at(y, x); + int dyval = dy.at(y, x); + + double tg = dxval ? (double)dyval/dxval : DBL_MAX*CV_SIGN(dyval); + + if( fabs(tg) < tan_pi_8 ) + { + y1 = y2 = y; x1 = x + 1; x2 = x - 1; + } + else if( tan_pi_8 <= tg && tg <= tan_3pi_8 ) + { + y1 = y + 1; y2 = y - 1; x1 = x + 1; x2 = x - 1; + } + else if( -tan_3pi_8 <= tg && tg <= -tan_pi_8 ) + { + y1 = y - 1; y2 = y + 1; x1 = x + 1; x2 = x - 1; + } + else + { + assert( fabs(tg) > tan_3pi_8 ); + x1 = x2 = x; y1 = y + 1; y2 = y - 1; + } + + if( (unsigned)y1 < (unsigned)height && (unsigned)x1 < (unsigned)width ) + b = (float)fabs(mag.at(y1, x1)); + + if( (unsigned)y2 < (unsigned)height && (unsigned)x2 < (unsigned)width ) + c = (float)fabs(mag.at(y2, x2)); + + if( (a > b || (a == b && ((x1 == x+1 && y1 == y) || (x1 == x && y1 == y+1)))) && a > c ) + ; + else + mag.at(y, x) = -a; + } + } + + dst = Scalar::all(0); + + // hysteresis threshold + for( y = 0; y < height; y++ ) + { + for( x = 0; x < width; x++ ) + if( mag.at(y, x) > highThreshold && !dst.at(y, x) ) + cannyFollow( x, y, lowThreshold, mag, dst ); + } +} + + +void CV_CannyTest::prepare_to_validation( int ) +{ + Mat src = test_mat[INPUT][0], dst = test_mat[REF_OUTPUT][0]; + test_Canny( src, dst, threshold1, threshold2, aperture_size, use_true_gradient ); +} + + +int CV_CannyTest::validate_test_results( int test_case_idx ) +{ + int code = cvtest::TS::OK, nz0; + prepare_to_validation(test_case_idx); + + double err = cvtest::norm(test_mat[OUTPUT][0], test_mat[REF_OUTPUT][0], CV_L1); + if( err == 0 ) + return code; + + if( err != cvRound(err) || cvRound(err)%255 != 0 ) + { + ts->printf( cvtest::TS::LOG, "Some of the pixels, produced by Canny, are not 0's or 255's; the difference is %g\n", err ); + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); + return code; + } + + nz0 = cvRound(cvtest::norm(test_mat[REF_OUTPUT][0], CV_L1)/255); + err = (err/255/MAX(nz0,100))*100; + if( err > 1 ) + { + ts->printf( cvtest::TS::LOG, "Too high percentage of non-matching edge pixels = %g%%\n", err); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + } + + return code; +} + +TEST(Imgproc_Canny, accuracy) { CV_CannyTest test; test.safe_run(); } + +/* End of file. */ diff --git a/imgproc/test/test_color.cpp b/imgproc/test/test_color.cpp new file mode 100644 index 0000000..1422f4c --- /dev/null +++ b/imgproc/test/test_color.cpp @@ -0,0 +1,1713 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +/////////////////////////// base test class for color transformations ///////////////////////// + +class CV_ColorCvtBaseTest : public cvtest::ArrayTest +{ +public: + CV_ColorCvtBaseTest( bool custom_inv_transform, bool allow_32f, bool allow_16u ); + +protected: + int prepare_test_case( int test_case_idx ); + void prepare_to_validation( int /*test_case_idx*/ ); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ); + + // input --- fwd_transform -> ref_output[0] + virtual void convert_forward( const Mat& src, Mat& dst ); + // ref_output[0] --- inv_transform ---> ref_output[1] (or input -- copy --> ref_output[1]) + virtual void convert_backward( const Mat& src, const Mat& dst, Mat& dst2 ); + + // called from default implementation of convert_forward + virtual void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); + + // called from default implementation of convert_backward + virtual void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); + + const char* fwd_code_str; + const char* inv_code_str; + + void run_func(); + bool allow_16u, allow_32f; + int blue_idx; + bool inplace; + bool custom_inv_transform; + int fwd_code, inv_code; + bool test_cpp; + int hue_range; +}; + + +CV_ColorCvtBaseTest::CV_ColorCvtBaseTest( bool _custom_inv_transform, bool _allow_32f, bool _allow_16u ) +{ + test_array[INPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + allow_16u = _allow_16u; + allow_32f = _allow_32f; + custom_inv_transform = _custom_inv_transform; + fwd_code = inv_code = -1; + element_wise_relative_error = false; + + fwd_code_str = inv_code_str = 0; + + test_cpp = false; + hue_range = 0; +} + + +void CV_ColorCvtBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ) +{ + cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high ); + if( i == INPUT ) + { + int depth = CV_MAT_DEPTH(type); + low = Scalar::all(0.); + high = Scalar::all( depth == CV_8U ? 256 : depth == CV_16U ? 65536 : 1. ); + } +} + + +void CV_ColorCvtBaseTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + int depth, cn; + cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + if( allow_16u && allow_32f ) + { + depth = cvtest::randInt(rng) % 3; + depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : CV_32F; + } + else if( allow_16u || allow_32f ) + { + depth = cvtest::randInt(rng) % 2; + depth = depth == 0 ? CV_8U : allow_16u ? CV_16U : CV_32F; + } + else + depth = CV_8U; + + cn = (cvtest::randInt(rng) & 1) + 3; + blue_idx = cvtest::randInt(rng) & 1 ? 2 : 0; + + types[INPUT][0] = CV_MAKETYPE(depth, cn); + types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, 3); + if( test_array[OUTPUT].size() > 1 ) + types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_MAKETYPE(depth, cn); + + inplace = cn == 3 && cvtest::randInt(rng) % 2 != 0; + test_cpp = (cvtest::randInt(rng) & 256) == 0; +} + + +int CV_ColorCvtBaseTest::prepare_test_case( int test_case_idx ) +{ + int code = cvtest::ArrayTest::prepare_test_case( test_case_idx ); + if( code > 0 && inplace ) + cvtest::copy( test_mat[INPUT][0], test_mat[OUTPUT][0] ); + return code; +} + +void CV_ColorCvtBaseTest::run_func() +{ + CvArr* out0 = test_array[OUTPUT][0]; + cv::Mat _out0 = cv::cvarrToMat(out0), _out1 = cv::cvarrToMat(test_array[OUTPUT][1]); + + if(!test_cpp) + cvCvtColor( inplace ? out0 : test_array[INPUT][0], out0, fwd_code ); + else + cv::cvtColor( cv::cvarrToMat(inplace ? out0 : test_array[INPUT][0]), _out0, fwd_code, _out0.channels()); + + if( inplace ) + { + cvCopy( out0, test_array[OUTPUT][1] ); + out0 = test_array[OUTPUT][1]; + } + if(!test_cpp) + cvCvtColor( out0, test_array[OUTPUT][1], inv_code ); + else + cv::cvtColor(cv::cvarrToMat(out0), _out1, inv_code, _out1.channels()); +} + + +void CV_ColorCvtBaseTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + convert_forward( test_mat[INPUT][0], test_mat[REF_OUTPUT][0] ); + convert_backward( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], + test_mat[REF_OUTPUT][1] ); + int depth = test_mat[REF_OUTPUT][0].depth(); + if( depth == CV_8U && hue_range ) + { + for( int y = 0; y < test_mat[REF_OUTPUT][0].rows; y++ ) + { + uchar* h0 = test_mat[REF_OUTPUT][0].ptr(y); + uchar* h = test_mat[OUTPUT][0].ptr(y); + + for( int x = 0; x < test_mat[REF_OUTPUT][0].cols; x++, h0 += 3, h += 3 ) + { + if( abs(*h - *h0) >= hue_range-1 && (*h <= 1 || *h0 <= 1) ) + *h = *h0 = 0; + } + } + } +} + + +void CV_ColorCvtBaseTest::convert_forward( const Mat& src, Mat& dst ) +{ + const float c8u = 0.0039215686274509803f; // 1./255 + const float c16u = 1.5259021896696422e-005f; // 1./65535 + int depth = src.depth(); + int cn = src.channels(), dst_cn = dst.channels(); + int cols = src.cols, dst_cols_n = dst.cols*dst_cn; + vector _src_buf(src.cols*3); + vector _dst_buf(dst.cols*3); + float* src_buf = &_src_buf[0]; + float* dst_buf = &_dst_buf[0]; + int i, j; + + assert( (cn == 3 || cn == 4) && (dst_cn == 3 || dst_cn == 1) ); + + for( i = 0; i < src.rows; i++ ) + { + switch( depth ) + { + case CV_8U: + { + const uchar* src_row = src.ptr(i); + uchar* dst_row = dst.ptr(i); + + for( j = 0; j < cols; j++ ) + { + src_buf[j*3] = src_row[j*cn + blue_idx]*c8u; + src_buf[j*3+1] = src_row[j*cn + 1]*c8u; + src_buf[j*3+2] = src_row[j*cn + (blue_idx^2)]*c8u; + } + + convert_row_bgr2abc_32f_c3( src_buf, dst_buf, cols ); + + for( j = 0; j < dst_cols_n; j++ ) + { + int t = cvRound( dst_buf[j] ); + dst_row[j] = saturate_cast(t); + } + } + break; + case CV_16U: + { + const ushort* src_row = src.ptr(i); + ushort* dst_row = dst.ptr(i); + + for( j = 0; j < cols; j++ ) + { + src_buf[j*3] = src_row[j*cn + blue_idx]*c16u; + src_buf[j*3+1] = src_row[j*cn + 1]*c16u; + src_buf[j*3+2] = src_row[j*cn + (blue_idx^2)]*c16u; + } + + convert_row_bgr2abc_32f_c3( src_buf, dst_buf, cols ); + + for( j = 0; j < dst_cols_n; j++ ) + { + int t = cvRound( dst_buf[j] ); + dst_row[j] = saturate_cast(t); + } + } + break; + case CV_32F: + { + const float* src_row = src.ptr(i); + float* dst_row = dst.ptr(i); + + for( j = 0; j < cols; j++ ) + { + src_buf[j*3] = src_row[j*cn + blue_idx]; + src_buf[j*3+1] = src_row[j*cn + 1]; + src_buf[j*3+2] = src_row[j*cn + (blue_idx^2)]; + } + + convert_row_bgr2abc_32f_c3( src_buf, dst_row, cols ); + } + break; + default: + assert(0); + } + } +} + + +void CV_ColorCvtBaseTest::convert_row_bgr2abc_32f_c3( const float* /*src_row*/, + float* /*dst_row*/, int /*n*/ ) +{ +} + + +void CV_ColorCvtBaseTest::convert_row_abc2bgr_32f_c3( const float* /*src_row*/, + float* /*dst_row*/, int /*n*/ ) +{ +} + + +void CV_ColorCvtBaseTest::convert_backward( const Mat& src, const Mat& dst, Mat& dst2 ) +{ + if( custom_inv_transform ) + { + int depth = src.depth(); + int src_cn = dst.channels(), cn = dst2.channels(); + int cols_n = src.cols*src_cn, dst_cols = dst.cols; + vector _src_buf(src.cols*3); + vector _dst_buf(dst.cols*3); + float* src_buf = &_src_buf[0]; + float* dst_buf = &_dst_buf[0]; + int i, j; + + assert( cn == 3 || cn == 4 ); + + for( i = 0; i < src.rows; i++ ) + { + switch( depth ) + { + case CV_8U: + { + const uchar* src_row = dst.ptr(i); + uchar* dst_row = dst2.ptr(i); + + for( j = 0; j < cols_n; j++ ) + src_buf[j] = src_row[j]; + + convert_row_abc2bgr_32f_c3( src_buf, dst_buf, dst_cols ); + + for( j = 0; j < dst_cols; j++ ) + { + int b = cvRound( dst_buf[j*3]*255. ); + int g = cvRound( dst_buf[j*3+1]*255. ); + int r = cvRound( dst_buf[j*3+2]*255. ); + dst_row[j*cn + blue_idx] = saturate_cast(b); + dst_row[j*cn + 1] = saturate_cast(g); + dst_row[j*cn + (blue_idx^2)] = saturate_cast(r); + if( cn == 4 ) + dst_row[j*cn + 3] = 255; + } + } + break; + case CV_16U: + { + const ushort* src_row = dst.ptr(i); + ushort* dst_row = dst2.ptr(i); + + for( j = 0; j < cols_n; j++ ) + src_buf[j] = src_row[j]; + + convert_row_abc2bgr_32f_c3( src_buf, dst_buf, dst_cols ); + + for( j = 0; j < dst_cols; j++ ) + { + int b = cvRound( dst_buf[j*3]*65535. ); + int g = cvRound( dst_buf[j*3+1]*65535. ); + int r = cvRound( dst_buf[j*3+2]*65535. ); + dst_row[j*cn + blue_idx] = saturate_cast(b); + dst_row[j*cn + 1] = saturate_cast(g); + dst_row[j*cn + (blue_idx^2)] = saturate_cast(r); + if( cn == 4 ) + dst_row[j*cn + 3] = 65535; + } + } + break; + case CV_32F: + { + const float* src_row = dst.ptr(i); + float* dst_row = dst2.ptr(i); + + convert_row_abc2bgr_32f_c3( src_row, dst_buf, dst_cols ); + + for( j = 0; j < dst_cols; j++ ) + { + float b = dst_buf[j*3]; + float g = dst_buf[j*3+1]; + float r = dst_buf[j*3+2]; + dst_row[j*cn + blue_idx] = b; + dst_row[j*cn + 1] = g; + dst_row[j*cn + (blue_idx^2)] = r; + if( cn == 4 ) + dst_row[j*cn + 3] = 1.f; + } + } + break; + default: + assert(0); + } + } + } + else + { + int i, j, k; + int elem_size = (int)src.elemSize(), elem_size1 = (int)src.elemSize1(); + int width_n = src.cols*elem_size; + + for( i = 0; i < src.rows; i++ ) + { + memcpy( dst2.ptr(i), src.ptr(i), width_n ); + if( src.channels() == 4 ) + { + // clear the alpha channel + uchar* ptr = dst2.ptr(i) + elem_size1*3; + for( j = 0; j < width_n; j += elem_size ) + { + for( k = 0; k < elem_size1; k++ ) + ptr[j + k] = 0; + } + } + } + } +} + + +#undef INIT_FWD_INV_CODES +#define INIT_FWD_INV_CODES( fwd, inv ) \ + fwd_code = CV_##fwd; inv_code = CV_##inv; \ + fwd_code_str = #fwd; inv_code_str = #inv + +//// rgb <=> gray +class CV_ColorGrayTest : public CV_ColorCvtBaseTest +{ +public: + CV_ColorGrayTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); + void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); + double get_success_error_level( int test_case_idx, int i, int j ); +}; + + +CV_ColorGrayTest::CV_ColorGrayTest() : CV_ColorCvtBaseTest( true, true, true ) +{ + INIT_FWD_INV_CODES( BGR2GRAY, GRAY2BGR ); +} + + +void CV_ColorGrayTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int cn = CV_MAT_CN(types[INPUT][0]); + types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][0] & CV_MAT_DEPTH_MASK; + inplace = false; + + if( cn == 3 ) + { + if( blue_idx == 0 ) + fwd_code = CV_BGR2GRAY, inv_code = CV_GRAY2BGR; + else + fwd_code = CV_RGB2GRAY, inv_code = CV_GRAY2RGB; + } + else + { + if( blue_idx == 0 ) + fwd_code = CV_BGRA2GRAY, inv_code = CV_GRAY2BGRA; + else + fwd_code = CV_RGBA2GRAY, inv_code = CV_GRAY2RGBA; + } +} + + +double CV_ColorGrayTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) +{ + int depth = test_mat[i][j].depth(); + return depth == CV_8U ? 2 : depth == CV_16U ? 16 : 1e-5; +} + + +void CV_ColorGrayTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int depth = test_mat[INPUT][0].depth(); + double scale = depth == CV_8U ? 255 : depth == CV_16U ? 65535 : 1; + double cr = 0.299*scale; + double cg = 0.587*scale; + double cb = 0.114*scale; + int j; + + for( j = 0; j < n; j++ ) + dst_row[j] = (float)(src_row[j*3]*cb + src_row[j*3+1]*cg + src_row[j*3+2]*cr); +} + + +void CV_ColorGrayTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int j, depth = test_mat[INPUT][0].depth(); + float scale = depth == CV_8U ? (1.f/255) : depth == CV_16U ? 1.f/65535 : 1.f; + for( j = 0; j < n; j++ ) + dst_row[j*3] = dst_row[j*3+1] = dst_row[j*3+2] = src_row[j]*scale; +} + + +//// rgb <=> ycrcb +class CV_ColorYCrCbTest : public CV_ColorCvtBaseTest +{ +public: + CV_ColorYCrCbTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); + void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); +}; + + +CV_ColorYCrCbTest::CV_ColorYCrCbTest() : CV_ColorCvtBaseTest( true, true, true ) +{ + INIT_FWD_INV_CODES( BGR2YCrCb, YCrCb2BGR ); +} + + +void CV_ColorYCrCbTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + if( blue_idx == 0 ) + fwd_code = CV_BGR2YCrCb, inv_code = CV_YCrCb2BGR; + else + fwd_code = CV_RGB2YCrCb, inv_code = CV_YCrCb2RGB; +} + + +double CV_ColorYCrCbTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) +{ + int depth = test_mat[i][j].depth(); + return depth == CV_8U ? 2 : depth == CV_16U ? 32 : 1e-3; +} + + +void CV_ColorYCrCbTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int depth = test_mat[INPUT][0].depth(); + double scale = depth == CV_8U ? 255 : depth == CV_16U ? 65535 : 1; + double bias = depth == CV_8U ? 128 : depth == CV_16U ? 32768 : 0.5; + + double M[] = { 0.299, 0.587, 0.114, + 0.49981, -0.41853, -0.08128, + -0.16864, -0.33107, 0.49970 }; + int j; + for( j = 0; j < 9; j++ ) + M[j] *= scale; + + for( j = 0; j < n*3; j += 3 ) + { + double r = src_row[j+2]; + double g = src_row[j+1]; + double b = src_row[j]; + double y = M[0]*r + M[1]*g + M[2]*b; + double cr = M[3]*r + M[4]*g + M[5]*b + bias; + double cb = M[6]*r + M[7]*g + M[8]*b + bias; + dst_row[j] = (float)y; + dst_row[j+1] = (float)cr; + dst_row[j+2] = (float)cb; + } +} + + +void CV_ColorYCrCbTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int depth = test_mat[INPUT][0].depth(); + double bias = depth == CV_8U ? 128 : depth == CV_16U ? 32768 : 0.5; + double scale = depth == CV_8U ? 1./255 : depth == CV_16U ? 1./65535 : 1; + double M[] = { 1, 1.40252, 0, + 1, -0.71440, -0.34434, + 1, 0, 1.77305 }; + int j; + for( j = 0; j < 9; j++ ) + M[j] *= scale; + + for( j = 0; j < n*3; j += 3 ) + { + double y = src_row[j]; + double cr = src_row[j+1] - bias; + double cb = src_row[j+2] - bias; + double r = M[0]*y + M[1]*cr + M[2]*cb; + double g = M[3]*y + M[4]*cr + M[5]*cb; + double b = M[6]*y + M[7]*cr + M[8]*cb; + dst_row[j] = (float)b; + dst_row[j+1] = (float)g; + dst_row[j+2] = (float)r; + } +} + + +//// rgb <=> hsv +class CV_ColorHSVTest : public CV_ColorCvtBaseTest +{ +public: + CV_ColorHSVTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); + void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); +}; + + +CV_ColorHSVTest::CV_ColorHSVTest() : CV_ColorCvtBaseTest( true, true, false ) +{ + INIT_FWD_INV_CODES( BGR2HSV, HSV2BGR ); + hue_range = 180; +} + + +void CV_ColorHSVTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + RNG& rng = ts->get_rng(); + + bool full_hrange = (rng.next() & 256) != 0; + if( full_hrange ) + { + if( blue_idx == 0 ) + fwd_code = CV_BGR2HSV_FULL, inv_code = CV_HSV2BGR_FULL; + else + fwd_code = CV_RGB2HSV_FULL, inv_code = CV_HSV2RGB_FULL; + hue_range = 256; + } + else + { + if( blue_idx == 0 ) + fwd_code = CV_BGR2HSV, inv_code = CV_HSV2BGR; + else + fwd_code = CV_RGB2HSV, inv_code = CV_HSV2RGB; + hue_range = 180; + } +} + + +double CV_ColorHSVTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) +{ + int depth = test_mat[i][j].depth(); + return depth == CV_8U ? (j == 0 ? 4 : 16) : depth == CV_16U ? 32 : 1e-3; +} + + +void CV_ColorHSVTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int depth = test_mat[INPUT][0].depth(); + float h_scale = depth == CV_8U ? hue_range*30.f/180 : 60.f; + float scale = depth == CV_8U ? 255.f : depth == CV_16U ? 65535.f : 1.f; + int j; + + for( j = 0; j < n*3; j += 3 ) + { + float r = src_row[j+2]; + float g = src_row[j+1]; + float b = src_row[j]; + float vmin = MIN(r,g); + float v = MAX(r,g); + float s, h, diff; + vmin = MIN(vmin,b); + v = MAX(v,b); + diff = v - vmin; + if( diff == 0 ) + s = h = 0; + else + { + s = diff/(v + FLT_EPSILON); + diff = 1.f/diff; + + h = r == v ? (g - b)*diff : + g == v ? 2 + (b - r)*diff : 4 + (r - g)*diff; + + if( h < 0 ) + h += 6; + } + + dst_row[j] = h*h_scale; + dst_row[j+1] = s*scale; + dst_row[j+2] = v*scale; + } +} + +// taken from http://www.cs.rit.edu/~ncs/color/t_convert.html +void CV_ColorHSVTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int depth = test_mat[INPUT][0].depth(); + float h_scale = depth == CV_8U ? 180/(hue_range*30.f) : 1.f/60; + float scale = depth == CV_8U ? 1.f/255 : depth == CV_16U ? 1.f/65535 : 1; + int j; + + for( j = 0; j < n*3; j += 3 ) + { + float h = src_row[j]*h_scale; + float s = src_row[j+1]*scale; + float v = src_row[j+2]*scale; + float r = v, g = v, b = v; + + if( h < 0 ) + h += 6; + else if( h >= 6 ) + h -= 6; + + if( s != 0 ) + { + int i = cvFloor(h); + float f = h - i; + float p = v*(1 - s); + float q = v*(1 - s*f); + float t = v*(1 - s*(1 - f)); + + if( i == 0 ) + r = v, g = t, b = p; + else if( i == 1 ) + r = q, g = v, b = p; + else if( i == 2 ) + r = p, g = v, b = t; + else if( i == 3 ) + r = p, g = q, b = v; + else if( i == 4 ) + r = t, g = p, b = v; + else + r = v, g = p, b = q; + } + + dst_row[j] = b; + dst_row[j+1] = g; + dst_row[j+2] = r; + } +} + + +//// rgb <=> hls +class CV_ColorHLSTest : public CV_ColorCvtBaseTest +{ +public: + CV_ColorHLSTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); + void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); +}; + + +CV_ColorHLSTest::CV_ColorHLSTest() : CV_ColorCvtBaseTest( true, true, false ) +{ + INIT_FWD_INV_CODES( BGR2HLS, HLS2BGR ); + hue_range = 180; +} + + +void CV_ColorHLSTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + if( blue_idx == 0 ) + fwd_code = CV_BGR2HLS, inv_code = CV_HLS2BGR; + else + fwd_code = CV_RGB2HLS, inv_code = CV_HLS2RGB; +} + + +double CV_ColorHLSTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) +{ + int depth = test_mat[i][j].depth(); + return depth == CV_8U ? (j == 0 ? 4 : 16) : depth == CV_16U ? 32 : 1e-4; +} + + +void CV_ColorHLSTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int depth = test_mat[INPUT][0].depth(); + float h_scale = depth == CV_8U ? 30.f : 60.f; + float scale = depth == CV_8U ? 255.f : depth == CV_16U ? 65535.f : 1.f; + int j; + + for( j = 0; j < n*3; j += 3 ) + { + float r = src_row[j+2]; + float g = src_row[j+1]; + float b = src_row[j]; + float vmin = MIN(r,g); + float v = MAX(r,g); + float s, h, l, diff; + vmin = MIN(vmin,b); + v = MAX(v,b); + diff = v - vmin; + + if( diff == 0 ) + s = h = 0, l = v; + else + { + l = (v + vmin)*0.5f; + s = l <= 0.5f ? diff / (v + vmin) : diff / (2 - v - vmin); + diff = 1.f/diff; + + h = r == v ? (g - b)*diff : + g == v ? 2 + (b - r)*diff : 4 + (r - g)*diff; + + if( h < 0 ) + h += 6; + } + + dst_row[j] = h*h_scale; + dst_row[j+1] = l*scale; + dst_row[j+2] = s*scale; + } +} + + +void CV_ColorHLSTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int depth = test_mat[INPUT][0].depth(); + float h_scale = depth == CV_8U ? 1.f/30 : 1.f/60; + float scale = depth == CV_8U ? 1.f/255 : depth == CV_16U ? 1.f/65535 : 1; + int j; + + for( j = 0; j < n*3; j += 3 ) + { + float h = src_row[j]*h_scale; + float l = src_row[j+1]*scale; + float s = src_row[j+2]*scale; + float r = l, g = l, b = l; + + if( h < 0 ) + h += 6; + else if( h >= 6 ) + h -= 6; + + if( s != 0 ) + { + float m2 = l <= 0.5f ? l*(1.f + s) : l + s - l*s; + float m1 = 2*l - m2; + float h1 = h + 2; + + if( h1 >= 6 ) + h1 -= 6; + if( h1 < 1 ) + r = m1 + (m2 - m1)*h1; + else if( h1 < 3 ) + r = m2; + else if( h1 < 4 ) + r = m1 + (m2 - m1)*(4 - h1); + else + r = m1; + + h1 = h; + + if( h1 < 1 ) + g = m1 + (m2 - m1)*h1; + else if( h1 < 3 ) + g = m2; + else if( h1 < 4 ) + g = m1 + (m2 - m1)*(4 - h1); + else + g = m1; + + h1 = h - 2; + if( h1 < 0 ) + h1 += 6; + + if( h1 < 1 ) + b = m1 + (m2 - m1)*h1; + else if( h1 < 3 ) + b = m2; + else if( h1 < 4 ) + b = m1 + (m2 - m1)*(4 - h1); + else + b = m1; + } + + dst_row[j] = b; + dst_row[j+1] = g; + dst_row[j+2] = r; + } +} + + +static const double RGB2XYZ[] = +{ + 0.412453, 0.357580, 0.180423, + 0.212671, 0.715160, 0.072169, + 0.019334, 0.119193, 0.950227 +}; + + +static const double XYZ2RGB[] = +{ + 3.240479, -1.53715, -0.498535, + -0.969256, 1.875991, 0.041556, + 0.055648, -0.204043, 1.057311 +}; + +static const float Xn = 0.950456f; +static const float Zn = 1.088754f; + + +//// rgb <=> xyz +class CV_ColorXYZTest : public CV_ColorCvtBaseTest +{ +public: + CV_ColorXYZTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); + void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); +}; + + +CV_ColorXYZTest::CV_ColorXYZTest() : CV_ColorCvtBaseTest( true, true, true ) +{ + INIT_FWD_INV_CODES( BGR2XYZ, XYZ2BGR ); +} + + +void CV_ColorXYZTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + if( blue_idx == 0 ) + fwd_code = CV_BGR2XYZ, inv_code = CV_XYZ2BGR; + else + fwd_code = CV_RGB2XYZ, inv_code = CV_XYZ2RGB; +} + + +double CV_ColorXYZTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) +{ + int depth = test_mat[i][j].depth(); + return depth == CV_8U ? (j == 0 ? 2 : 8) : depth == CV_16U ? (j == 0 ? 64 : 128) : 1e-1; +} + + +void CV_ColorXYZTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int depth = test_mat[INPUT][0].depth(); + double scale = depth == CV_8U ? 255 : depth == CV_16U ? 65535 : 1; + + double M[9]; + int j; + for( j = 0; j < 9; j++ ) + M[j] = RGB2XYZ[j]*scale; + + for( j = 0; j < n*3; j += 3 ) + { + double r = src_row[j+2]; + double g = src_row[j+1]; + double b = src_row[j]; + double x = M[0]*r + M[1]*g + M[2]*b; + double y = M[3]*r + M[4]*g + M[5]*b; + double z = M[6]*r + M[7]*g + M[8]*b; + dst_row[j] = (float)x; + dst_row[j+1] = (float)y; + dst_row[j+2] = (float)z; + } +} + + +void CV_ColorXYZTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int depth = test_mat[INPUT][0].depth(); + double scale = depth == CV_8U ? 1./255 : depth == CV_16U ? 1./65535 : 1; + + double M[9]; + int j; + for( j = 0; j < 9; j++ ) + M[j] = XYZ2RGB[j]*scale; + + for( j = 0; j < n*3; j += 3 ) + { + double x = src_row[j]; + double y = src_row[j+1]; + double z = src_row[j+2]; + double r = M[0]*x + M[1]*y + M[2]*z; + double g = M[3]*x + M[4]*y + M[5]*z; + double b = M[6]*x + M[7]*y + M[8]*z; + dst_row[j] = (float)b; + dst_row[j+1] = (float)g; + dst_row[j+2] = (float)r; + } +} + + +//// rgb <=> L*a*b* +class CV_ColorLabTest : public CV_ColorCvtBaseTest +{ +public: + CV_ColorLabTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); + void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); +}; + + +CV_ColorLabTest::CV_ColorLabTest() : CV_ColorCvtBaseTest( true, true, false ) +{ + INIT_FWD_INV_CODES( BGR2Lab, Lab2BGR ); +} + + +void CV_ColorLabTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + if( blue_idx == 0 ) + fwd_code = CV_LBGR2Lab, inv_code = CV_Lab2LBGR; + else + fwd_code = CV_LRGB2Lab, inv_code = CV_Lab2LRGB; +} + + +double CV_ColorLabTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) +{ + int depth = test_mat[i][j].depth(); + return depth == CV_8U ? 16 : depth == CV_16U ? 32 : 1e-3; +} + + +static const double _1_3 = 0.333333333333; + +void CV_ColorLabTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int depth = test_mat[INPUT][0].depth(); + float Lscale = depth == CV_8U ? 255.f/100.f : depth == CV_16U ? 65535.f/100.f : 1.f; + float ab_bias = depth == CV_8U ? 128.f : depth == CV_16U ? 32768.f : 0.f; + int j; + float M[9]; + + for( j = 0; j < 9; j++ ) + M[j] = (float)RGB2XYZ[j]; + + for( j = 0; j < n*3; j += 3 ) + { + float r = src_row[j+2]; + float g = src_row[j+1]; + float b = src_row[j]; + + float X = (r*M[0] + g*M[1] + b*M[2])*(1.f/Xn); + float Y = r*M[3] + g*M[4] + b*M[5]; + float Z = (r*M[6] + g*M[7] + b*M[8])*(1.f/Zn); + float fX, fY, fZ; + + float L, a; + + if( Y > 0.008856 ) + { + fY = (float)pow((double)Y,_1_3); + L = 116.f*fY - 16.f; + } + else + { + fY = 7.787f*Y + 16.f/116.f; + L = 903.3f*Y; + } + + if( X > 0.008856 ) + fX = (float)pow((double)X,_1_3); + else + fX = 7.787f*X + 16.f/116.f; + + if( Z > 0.008856 ) + fZ = (float)pow((double)Z,_1_3); + else + fZ = 7.787f*Z + 16.f/116.f; + + a = 500.f*(fX - fY); + b = 200.f*(fY - fZ); + + dst_row[j] = L*Lscale; + dst_row[j+1] = a + ab_bias; + dst_row[j+2] = b + ab_bias; + } +} + + +void CV_ColorLabTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int depth = test_mat[INPUT][0].depth(); + float Lscale = depth == CV_8U ? 100.f/255.f : depth == CV_16U ? 100.f/65535.f : 1.f; + float ab_bias = depth == CV_8U ? 128.f : depth == CV_16U ? 32768.f : 0.f; + int j; + float M[9]; + + for( j = 0; j < 9; j++ ) + M[j] = (float)XYZ2RGB[j]; + + for( j = 0; j < n*3; j += 3 ) + { + float L = src_row[j]*Lscale; + float a = src_row[j+1] - ab_bias; + float b = src_row[j+2] - ab_bias; + + float P = (L + 16.f)*(1.f/116.f); + float X = (P + a*0.002f); + float Z = (P - b*0.005f); + float Y = P*P*P; + X = Xn*X*X*X; + Z = Zn*Z*Z*Z; + + float r = M[0]*X + M[1]*Y + M[2]*Z; + float g = M[3]*X + M[4]*Y + M[5]*Z; + b = M[6]*X + M[7]*Y + M[8]*Z; + + dst_row[j] = b; + dst_row[j+1] = g; + dst_row[j+2] = r; + } +} + + +//// rgb <=> L*u*v* +class CV_ColorLuvTest : public CV_ColorCvtBaseTest +{ +public: + CV_ColorLuvTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); + void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); +}; + + +CV_ColorLuvTest::CV_ColorLuvTest() : CV_ColorCvtBaseTest( true, true, false ) +{ + INIT_FWD_INV_CODES( BGR2Luv, Luv2BGR ); +} + + +void CV_ColorLuvTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + if( blue_idx == 0 ) + fwd_code = CV_LBGR2Luv, inv_code = CV_Luv2LBGR; + else + fwd_code = CV_LRGB2Luv, inv_code = CV_Luv2LRGB; +} + + +double CV_ColorLuvTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) +{ + int depth = test_mat[i][j].depth(); + return depth == CV_8U ? 48 : depth == CV_16U ? 32 : 5e-2; +} + + +void CV_ColorLuvTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int depth = test_mat[INPUT][0].depth(); + float Lscale = depth == CV_8U ? 255.f/100.f : depth == CV_16U ? 65535.f/100.f : 1.f; + int j; + + float M[9]; + float un = 4.f*Xn/(Xn + 15.f*1.f + 3*Zn); + float vn = 9.f*1.f/(Xn + 15.f*1.f + 3*Zn); + float u_scale = 1.f, u_bias = 0.f; + float v_scale = 1.f, v_bias = 0.f; + + for( j = 0; j < 9; j++ ) + M[j] = (float)RGB2XYZ[j]; + + if( depth == CV_8U ) + { + u_scale = 0.720338983f; + u_bias = 96.5254237f; + v_scale = 0.99609375f; + v_bias = 139.453125f; + } + + for( j = 0; j < n*3; j += 3 ) + { + float r = src_row[j+2]; + float g = src_row[j+1]; + float b = src_row[j]; + + float X = r*M[0] + g*M[1] + b*M[2]; + float Y = r*M[3] + g*M[4] + b*M[5]; + float Z = r*M[6] + g*M[7] + b*M[8]; + float d = X + 15*Y + 3*Z, L, u, v; + + if( d == 0 ) + L = u = v = 0; + else + { + if( Y > 0.008856f ) + L = (float)(116.*pow((double)Y,_1_3) - 16.); + else + L = 903.3f * Y; + + d = 1.f/d; + u = 13*L*(4*X*d - un); + v = 13*L*(9*Y*d - vn); + } + dst_row[j] = L*Lscale; + dst_row[j+1] = u*u_scale + u_bias; + dst_row[j+2] = v*v_scale + v_bias; + } +} + + +void CV_ColorLuvTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) +{ + int depth = test_mat[INPUT][0].depth(); + float Lscale = depth == CV_8U ? 100.f/255.f : depth == CV_16U ? 100.f/65535.f : 1.f; + int j; + float M[9]; + float un = 4.f*Xn/(Xn + 15.f*1.f + 3*Zn); + float vn = 9.f*1.f/(Xn + 15.f*1.f + 3*Zn); + float u_scale = 1.f, u_bias = 0.f; + float v_scale = 1.f, v_bias = 0.f; + + for( j = 0; j < 9; j++ ) + M[j] = (float)XYZ2RGB[j]; + + if( depth == CV_8U ) + { + u_scale = 1.f/0.720338983f; + u_bias = 96.5254237f; + v_scale = 1.f/0.99609375f; + v_bias = 139.453125f; + } + + for( j = 0; j < n*3; j += 3 ) + { + float L = src_row[j]*Lscale; + float u = (src_row[j+1] - u_bias)*u_scale; + float v = (src_row[j+2] - v_bias)*v_scale; + float X, Y, Z; + + if( L >= 8 ) + { + Y = (L + 16.f)*(1.f/116.f); + Y = Y*Y*Y; + } + else + { + Y = L * (1.f/903.3f); + if( L == 0 ) + L = 0.001f; + } + + u = u/(13*L) + un; + v = v/(13*L) + vn; + + X = -9*Y*u/((u - 4)*v - u*v); + Z = (9*Y - 15*v*Y - v*X)/(3*v); + + float r = M[0]*X + M[1]*Y + M[2]*Z; + float g = M[3]*X + M[4]*Y + M[5]*Z; + float b = M[6]*X + M[7]*Y + M[8]*Z; + + dst_row[j] = b; + dst_row[j+1] = g; + dst_row[j+2] = r; + } +} + + +//// rgb <=> another rgb +class CV_ColorRGBTest : public CV_ColorCvtBaseTest +{ +public: + CV_ColorRGBTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void convert_forward( const Mat& src, Mat& dst ); + void convert_backward( const Mat& src, const Mat& dst, Mat& dst2 ); + int dst_bits; +}; + + +CV_ColorRGBTest::CV_ColorRGBTest() : CV_ColorCvtBaseTest( true, true, true ) +{ + dst_bits = 0; +} + + +void CV_ColorRGBTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int cn = CV_MAT_CN(types[INPUT][0]); + + dst_bits = 24; + + if( cvtest::randInt(rng) % 3 == 0 ) + { + types[INPUT][0] = types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_MAKETYPE(CV_8U,cn); + types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(CV_8U,2); + if( cvtest::randInt(rng) & 1 ) + { + if( blue_idx == 0 ) + fwd_code = CV_BGR2BGR565, inv_code = CV_BGR5652BGR; + else + fwd_code = CV_RGB2BGR565, inv_code = CV_BGR5652RGB; + dst_bits = 16; + } + else + { + if( blue_idx == 0 ) + fwd_code = CV_BGR2BGR555, inv_code = CV_BGR5552BGR; + else + fwd_code = CV_RGB2BGR555, inv_code = CV_BGR5552RGB; + dst_bits = 15; + } + } + else + { + if( cn == 3 ) + { + fwd_code = CV_RGB2BGR, inv_code = CV_BGR2RGB; + blue_idx = 2; + } + else if( blue_idx == 0 ) + fwd_code = CV_BGRA2BGR, inv_code = CV_BGR2BGRA; + else + fwd_code = CV_RGBA2BGR, inv_code = CV_BGR2RGBA; + } + + if( CV_MAT_CN(types[INPUT][0]) != CV_MAT_CN(types[OUTPUT][0]) ) + inplace = false; +} + + +double CV_ColorRGBTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + return 0; +} + + +void CV_ColorRGBTest::convert_forward( const Mat& src, Mat& dst ) +{ + int depth = src.depth(), cn = src.channels(); +/*#if defined _DEBUG || defined DEBUG + int dst_cn = CV_MAT_CN(dst->type); +#endif*/ + int i, j, cols = src.cols; + int g_rshift = dst_bits == 16 ? 2 : 3; + int r_lshift = dst_bits == 16 ? 11 : 10; + + //assert( (cn == 3 || cn == 4) && (dst_cn == 3 || (dst_cn == 2 && depth == CV_8U)) ); + + for( i = 0; i < src.rows; i++ ) + { + switch( depth ) + { + case CV_8U: + { + const uchar* src_row = src.ptr(i); + uchar* dst_row = dst.ptr(i); + + if( dst_bits == 24 ) + { + for( j = 0; j < cols; j++ ) + { + uchar b = src_row[j*cn + blue_idx]; + uchar g = src_row[j*cn + 1]; + uchar r = src_row[j*cn + (blue_idx^2)]; + dst_row[j*3] = b; + dst_row[j*3+1] = g; + dst_row[j*3+2] = r; + } + } + else + { + for( j = 0; j < cols; j++ ) + { + int b = src_row[j*cn + blue_idx] >> 3; + int g = src_row[j*cn + 1] >> g_rshift; + int r = src_row[j*cn + (blue_idx^2)] >> 3; + ((ushort*)dst_row)[j] = (ushort)(b | (g << 5) | (r << r_lshift)); + if( cn == 4 && src_row[j*4+3] ) + ((ushort*)dst_row)[j] |= 1 << (r_lshift+5); + } + } + } + break; + case CV_16U: + { + const ushort* src_row = src.ptr(i); + ushort* dst_row = dst.ptr(i); + + for( j = 0; j < cols; j++ ) + { + ushort b = src_row[j*cn + blue_idx]; + ushort g = src_row[j*cn + 1]; + ushort r = src_row[j*cn + (blue_idx^2)]; + dst_row[j*3] = b; + dst_row[j*3+1] = g; + dst_row[j*3+2] = r; + } + } + break; + case CV_32F: + { + const float* src_row = src.ptr(i); + float* dst_row = dst.ptr(i); + + for( j = 0; j < cols; j++ ) + { + float b = src_row[j*cn + blue_idx]; + float g = src_row[j*cn + 1]; + float r = src_row[j*cn + (blue_idx^2)]; + dst_row[j*3] = b; + dst_row[j*3+1] = g; + dst_row[j*3+2] = r; + } + } + break; + default: + assert(0); + } + } +} + + +void CV_ColorRGBTest::convert_backward( const Mat& /*src*/, const Mat& src, Mat& dst ) +{ + int depth = src.depth(), cn = dst.channels(); +/*#if defined _DEBUG || defined DEBUG + int src_cn = CV_MAT_CN(src->type); +#endif*/ + int i, j, cols = src.cols; + int g_lshift = dst_bits == 16 ? 2 : 3; + int r_rshift = dst_bits == 16 ? 11 : 10; + + //assert( (cn == 3 || cn == 4) && (src_cn == 3 || (src_cn == 2 && depth == CV_8U)) ); + + for( i = 0; i < src.rows; i++ ) + { + switch( depth ) + { + case CV_8U: + { + const uchar* src_row = src.ptr(i); + uchar* dst_row = dst.ptr(i); + + if( dst_bits == 24 ) + { + for( j = 0; j < cols; j++ ) + { + uchar b = src_row[j*3]; + uchar g = src_row[j*3 + 1]; + uchar r = src_row[j*3 + 2]; + + dst_row[j*cn + blue_idx] = b; + dst_row[j*cn + 1] = g; + dst_row[j*cn + (blue_idx^2)] = r; + + if( cn == 4 ) + dst_row[j*cn + 3] = 255; + } + } + else + { + for( j = 0; j < cols; j++ ) + { + ushort val = ((ushort*)src_row)[j]; + uchar b = (uchar)(val << 3); + uchar g = (uchar)((val >> 5) << g_lshift); + uchar r = (uchar)((val >> r_rshift) << 3); + + dst_row[j*cn + blue_idx] = b; + dst_row[j*cn + 1] = g; + dst_row[j*cn + (blue_idx^2)] = r; + + if( cn == 4 ) + { + uchar alpha = r_rshift == 11 || (val & 0x8000) != 0 ? 255 : 0; + dst_row[j*cn + 3] = alpha; + } + } + } + } + break; + case CV_16U: + { + const ushort* src_row = src.ptr(i); + ushort* dst_row = dst.ptr(i); + + for( j = 0; j < cols; j++ ) + { + ushort b = src_row[j*3]; + ushort g = src_row[j*3 + 1]; + ushort r = src_row[j*3 + 2]; + + dst_row[j*cn + blue_idx] = b; + dst_row[j*cn + 1] = g; + dst_row[j*cn + (blue_idx^2)] = r; + + if( cn == 4 ) + dst_row[j*cn + 3] = 65535; + } + } + break; + case CV_32F: + { + const float* src_row = src.ptr(i); + float* dst_row = dst.ptr(i); + + for( j = 0; j < cols; j++ ) + { + float b = src_row[j*3]; + float g = src_row[j*3 + 1]; + float r = src_row[j*3 + 2]; + + dst_row[j*cn + blue_idx] = b; + dst_row[j*cn + 1] = g; + dst_row[j*cn + (blue_idx^2)] = r; + + if( cn == 4 ) + dst_row[j*cn + 3] = 1.f; + } + } + break; + default: + assert(0); + } + } +} + + +//// rgb <=> bayer + +class CV_ColorBayerTest : public CV_ColorCvtBaseTest +{ +public: + CV_ColorBayerTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void run_func(); + void prepare_to_validation( int test_case_idx ); +}; + + +CV_ColorBayerTest::CV_ColorBayerTest() : CV_ColorCvtBaseTest( false, false, true ) +{ + test_array[OUTPUT].pop_back(); + test_array[REF_OUTPUT].pop_back(); + + fwd_code_str = "BayerBG2BGR"; + inv_code_str = ""; + fwd_code = CV_BayerBG2BGR; + inv_code = -1; +} + + +void CV_ColorBayerTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + types[INPUT][0] = CV_MAT_DEPTH(types[INPUT][0]); + types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(CV_MAT_DEPTH(types[INPUT][0]), 3); + inplace = false; + + fwd_code = cvtest::randInt(rng)%4 + CV_BayerBG2BGR; +} + + +double CV_ColorBayerTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + return 1; +} + + +void CV_ColorBayerTest::run_func() +{ + if(!test_cpp) + cvCvtColor( test_array[INPUT][0], test_array[OUTPUT][0], fwd_code ); + else + { + cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]); + cv::cvtColor(cv::cvarrToMat(test_array[INPUT][0]), _out, fwd_code, _out.channels()); + } +} + + +template +static void bayer2BGR_(const Mat& src, Mat& dst, int code) +{ + int i, j, cols = src.cols - 2; + int bi = 0; + int step = (int)(src.step/sizeof(T)); + + if( code == CV_BayerRG2BGR || code == CV_BayerGR2BGR ) + bi ^= 2; + + for( i = 1; i < src.rows - 1; i++ ) + { + const T* ptr = src.ptr(i) + 1; + T* dst_row = dst.ptr(i) + 3; + int save_code = code; + if( cols <= 0 ) + { + dst_row[-3] = dst_row[-2] = dst_row[-1] = 0; + dst_row[cols*3] = dst_row[cols*3+1] = dst_row[cols*3+2] = 0; + continue; + } + + for( j = 0; j < cols; j++ ) + { + int b, g, r; + if( !(code & 1) ) + { + b = ptr[j]; + g = (ptr[j-1] + ptr[j+1] + ptr[j-step] + ptr[j+step])>>2; + r = (ptr[j-step-1] + ptr[j-step+1] + ptr[j+step-1] + ptr[j+step+1]) >> 2; + } + else + { + b = (ptr[j-1] + ptr[j+1]) >> 1; + g = ptr[j]; + r = (ptr[j-step] + ptr[j+step]) >> 1; + } + code ^= 1; + dst_row[j*3 + bi] = (T)b; + dst_row[j*3 + 1] = (T)g; + dst_row[j*3 + (bi^2)] = (T)r; + } + + dst_row[-3] = dst_row[0]; + dst_row[-2] = dst_row[1]; + dst_row[-1] = dst_row[2]; + dst_row[cols*3] = dst_row[cols*3-3]; + dst_row[cols*3+1] = dst_row[cols*3-2]; + dst_row[cols*3+2] = dst_row[cols*3-1]; + + code = save_code ^ 1; + bi ^= 2; + } + + if( src.rows <= 2 ) + { + memset( dst.ptr(), 0, (cols+2)*3*sizeof(T) ); + memset( dst.ptr(dst.rows-1), 0, (cols+2)*3*sizeof(T) ); + } + else + { + T* top_row = dst.ptr(); + T* bottom_row = dst.ptr(dst.rows-1); + int dstep = (int)(dst.step/sizeof(T)); + + for( j = 0; j < (cols+2)*3; j++ ) + { + top_row[j] = top_row[j + dstep]; + bottom_row[j] = bottom_row[j - dstep]; + } + } +} + + +void CV_ColorBayerTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + const Mat& src = test_mat[INPUT][0]; + Mat& dst = test_mat[REF_OUTPUT][0]; + int depth = src.depth(); + if( depth == CV_8U ) + bayer2BGR_(src, dst, fwd_code); + else if( depth == CV_16U ) + bayer2BGR_(src, dst, fwd_code); + else + CV_Error(CV_StsUnsupportedFormat, ""); +} + + +///////////////////////////////////////////////////////////////////////////////////////////////// + +TEST(Imgproc_ColorGray, accuracy) { CV_ColorGrayTest test; test.safe_run(); } +TEST(Imgproc_ColorYCrCb, accuracy) { CV_ColorYCrCbTest test; test.safe_run(); } +TEST(Imgproc_ColorHSV, accuracy) { CV_ColorHSVTest test; test.safe_run(); } +TEST(Imgproc_ColorHLS, accuracy) { CV_ColorHLSTest test; test.safe_run(); } +TEST(Imgproc_ColorXYZ, accuracy) { CV_ColorXYZTest test; test.safe_run(); } +TEST(Imgproc_ColorLab, accuracy) { CV_ColorLabTest test; test.safe_run(); } +TEST(Imgproc_ColorLuv, accuracy) { CV_ColorLuvTest test; test.safe_run(); } +TEST(Imgproc_ColorRGB, accuracy) { CV_ColorRGBTest test; test.safe_run(); } +TEST(Imgproc_ColorBayer, accuracy) { CV_ColorBayerTest test; test.safe_run(); } + + +TEST(Imgproc_ColorBayer, regression) +{ + cvtest::TS& ts = *cvtest::TS::ptr(); + + Mat given = imread(string(ts.get_data_path()) + "/cvtcolor/bayer_input.png", CV_LOAD_IMAGE_GRAYSCALE); + Mat gold = imread(string(ts.get_data_path()) + "/cvtcolor/bayer_gold.png", CV_LOAD_IMAGE_UNCHANGED); + Mat result; + + cvtColor(given, result, CV_BayerBG2GRAY); + + EXPECT_EQ(gold.type(), result.type()); + EXPECT_EQ(gold.cols, result.cols); + EXPECT_EQ(gold.rows, result.rows); + + Mat diff; + absdiff(gold, result, diff); + + EXPECT_EQ(0, countNonZero(diff.reshape(1) > 1)); +} + +TEST(Imgproc_ColorBayerVNG, regression) +{ + cvtest::TS& ts = *cvtest::TS::ptr(); + + Mat given = imread(string(ts.get_data_path()) + "/cvtcolor/bayer_input.png", CV_LOAD_IMAGE_GRAYSCALE); + Mat gold = imread(string(ts.get_data_path()) + "/cvtcolor/bayerVNG_gold.png", CV_LOAD_IMAGE_UNCHANGED); + Mat result; + + cvtColor(given, result, CV_BayerBG2BGR_VNG, 3); + + EXPECT_EQ(gold.type(), result.type()); + EXPECT_EQ(gold.cols, result.cols); + EXPECT_EQ(gold.rows, result.rows); + + Mat diff; + absdiff(gold, result, diff); + + EXPECT_EQ(0, countNonZero(diff.reshape(1) > 1)); +} diff --git a/imgproc/test/test_contours.cpp b/imgproc/test/test_contours.cpp new file mode 100644 index 0000000..a8c9a72 --- /dev/null +++ b/imgproc/test/test_contours.cpp @@ -0,0 +1,393 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +class CV_FindContourTest : public cvtest::BaseTest +{ +public: + enum { NUM_IMG = 4 }; + + CV_FindContourTest(); + ~CV_FindContourTest(); + void clear(); + +protected: + int read_params( CvFileStorage* fs ); + int prepare_test_case( int test_case_idx ); + int validate_test_results( int test_case_idx ); + void run_func(); + + int min_blob_size, max_blob_size; + int blob_count, max_log_blob_count; + int retr_mode, approx_method; + + int min_log_img_size, max_log_img_size; + CvSize img_size; + int count, count2; + + IplImage* img[NUM_IMG]; + CvMemStorage* storage; + CvSeq *contours, *contours2, *chain; +}; + + +CV_FindContourTest::CV_FindContourTest() +{ + int i; + + test_case_count = 300; + min_blob_size = 1; + max_blob_size = 50; + max_log_blob_count = 10; + + min_log_img_size = 3; + max_log_img_size = 10; + + for( i = 0; i < NUM_IMG; i++ ) + img[i] = 0; + + storage = 0; +} + + +CV_FindContourTest::~CV_FindContourTest() +{ + clear(); +} + + +void CV_FindContourTest::clear() +{ + int i; + + cvtest::BaseTest::clear(); + + for( i = 0; i < NUM_IMG; i++ ) + cvReleaseImage( &img[i] ); + + cvReleaseMemStorage( &storage ); +} + + +int CV_FindContourTest::read_params( CvFileStorage* fs ) +{ + int t; + int code = cvtest::BaseTest::read_params( fs ); + + if( code < 0 ) + return code; + + min_blob_size = cvReadInt( find_param( fs, "min_blob_size" ), min_blob_size ); + max_blob_size = cvReadInt( find_param( fs, "max_blob_size" ), max_blob_size ); + max_log_blob_count = cvReadInt( find_param( fs, "max_log_blob_count" ), max_log_blob_count ); + min_log_img_size = cvReadInt( find_param( fs, "min_log_img_size" ), min_log_img_size ); + max_log_img_size = cvReadInt( find_param( fs, "max_log_img_size" ), max_log_img_size ); + + min_blob_size = cvtest::clipInt( min_blob_size, 1, 100 ); + max_blob_size = cvtest::clipInt( max_blob_size, 1, 100 ); + + if( min_blob_size > max_blob_size ) + CV_SWAP( min_blob_size, max_blob_size, t ); + + max_log_blob_count = cvtest::clipInt( max_log_blob_count, 1, 10 ); + + min_log_img_size = cvtest::clipInt( min_log_img_size, 1, 10 ); + max_log_img_size = cvtest::clipInt( max_log_img_size, 1, 10 ); + + if( min_log_img_size > max_log_img_size ) + CV_SWAP( min_log_img_size, max_log_img_size, t ); + + return 0; +} + + +static void +cvTsGenerateBlobImage( IplImage* img, int min_blob_size, int max_blob_size, + int blob_count, int min_brightness, int max_brightness, + RNG& rng ) +{ + int i; + CvSize size; + + assert( img->depth == IPL_DEPTH_8U && img->nChannels == 1 ); + + cvZero( img ); + + // keep the border clear + cvSetImageROI( img, cvRect(1,1,img->width-2,img->height-2) ); + size = cvGetSize( img ); + + for( i = 0; i < blob_count; i++ ) + { + CvPoint center; + CvSize axes; + int angle = cvtest::randInt(rng) % 180; + int brightness = cvtest::randInt(rng) % + (max_brightness - min_brightness) + min_brightness; + center.x = cvtest::randInt(rng) % size.width; + center.y = cvtest::randInt(rng) % size.height; + + axes.width = (cvtest::randInt(rng) % + (max_blob_size - min_blob_size) + min_blob_size + 1)/2; + axes.height = (cvtest::randInt(rng) % + (max_blob_size - min_blob_size) + min_blob_size + 1)/2; + + cvEllipse( img, center, axes, angle, 0, 360, cvScalar(brightness), CV_FILLED ); + } + + cvResetImageROI( img ); +} + + +static void +cvTsMarkContours( IplImage* img, int val ) +{ + int i, j; + int step = img->widthStep; + + assert( img->depth == IPL_DEPTH_8U && img->nChannels == 1 && (val&1) != 0); + + for( i = 1; i < img->height - 1; i++ ) + for( j = 1; j < img->width - 1; j++ ) + { + uchar* t = (uchar*)(img->imageData + img->widthStep*i + j); + if( *t == 1 && (t[-step] == 0 || t[-1] == 0 || t[1] == 0 || t[step] == 0)) + *t = (uchar)val; + } + + cvThreshold( img, img, val - 2, val, CV_THRESH_BINARY ); +} + + +int CV_FindContourTest::prepare_test_case( int test_case_idx ) +{ + RNG& rng = ts->get_rng(); + const int min_brightness = 0, max_brightness = 2; + int i, code = cvtest::BaseTest::prepare_test_case( test_case_idx ); + + if( code < 0 ) + return code; + + clear(); + + blob_count = cvRound(exp(cvtest::randReal(rng)*max_log_blob_count*CV_LOG2)); + + img_size.width = cvRound(exp((cvtest::randReal(rng)* + (max_log_img_size - min_log_img_size) + min_log_img_size)*CV_LOG2)); + img_size.height = cvRound(exp((cvtest::randReal(rng)* + (max_log_img_size - min_log_img_size) + min_log_img_size)*CV_LOG2)); + + approx_method = cvtest::randInt( rng ) % 4 + 1; + retr_mode = cvtest::randInt( rng ) % 4; + + storage = cvCreateMemStorage( 1 << 10 ); + + for( i = 0; i < NUM_IMG; i++ ) + img[i] = cvCreateImage( img_size, 8, 1 ); + + cvTsGenerateBlobImage( img[0], min_blob_size, max_blob_size, + blob_count, min_brightness, max_brightness, rng ); + + cvCopy( img[0], img[1] ); + cvCopy( img[0], img[2] ); + + cvTsMarkContours( img[1], 255 ); + + return 1; +} + + +void CV_FindContourTest::run_func() +{ + contours = contours2 = chain = 0; + count = cvFindContours( img[2], storage, &contours, sizeof(CvContour), retr_mode, approx_method ); + + cvZero( img[3] ); + + if( contours && retr_mode != CV_RETR_EXTERNAL && approx_method < CV_CHAIN_APPROX_TC89_L1 ) + cvDrawContours( img[3], contours, cvScalar(255), cvScalar(255), INT_MAX, -1 ); + + cvCopy( img[0], img[2] ); + + count2 = cvFindContours( img[2], storage, &chain, sizeof(CvChain), retr_mode, CV_CHAIN_CODE ); + + if( chain ) + contours2 = cvApproxChains( chain, storage, approx_method, 0, 0, 1 ); + + cvZero( img[2] ); + + if( contours && retr_mode != CV_RETR_EXTERNAL && approx_method < CV_CHAIN_APPROX_TC89_L1 ) + cvDrawContours( img[2], contours2, cvScalar(255), cvScalar(255), INT_MAX ); +} + + +// the whole testing is done here, run_func() is not utilized in this test +int CV_FindContourTest::validate_test_results( int /*test_case_idx*/ ) +{ + int code = cvtest::TS::OK; + + cvCmpS( img[0], 0, img[0], CV_CMP_GT ); + + if( count != count2 ) + { + ts->printf( cvtest::TS::LOG, "The number of contours retrieved with different " + "approximation methods is not the same\n" + "(%d contour(s) for method %d vs %d contour(s) for method %d)\n", + count, approx_method, count2, CV_CHAIN_CODE ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + } + + if( retr_mode != CV_RETR_EXTERNAL && approx_method < CV_CHAIN_APPROX_TC89_L1 ) + { + Mat _img[4]; + for( int i = 0; i < 4; i++ ) + _img[i] = cvarrToMat(img[i]); + + code = cvtest::cmpEps2(ts, _img[0], _img[3], 0, true, "Comparing original image with the map of filled contours" ); + + if( code < 0 ) + goto _exit_; + + code = cvtest::cmpEps2( ts, _img[1], _img[2], 0, true, + "Comparing contour outline vs manually produced edge map" ); + + if( code < 0 ) + goto _exit_; + } + + if( contours ) + { + CvTreeNodeIterator iterator1; + CvTreeNodeIterator iterator2; + int count3; + + for(int i = 0; i < 2; i++ ) + { + CvTreeNodeIterator iterator; + cvInitTreeNodeIterator( &iterator, i == 0 ? contours : contours2, INT_MAX ); + + for( count3 = 0; cvNextTreeNode( &iterator ) != 0; count3++ ) + ; + + if( count3 != count ) + { + ts->printf( cvtest::TS::LOG, + "The returned number of retrieved contours (using the approx_method = %d) does not match\n" + "to the actual number of contours in the tree/list (returned %d, actual %d)\n", + i == 0 ? approx_method : 0, count, count3 ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + goto _exit_; + } + } + + cvInitTreeNodeIterator( &iterator1, contours, INT_MAX ); + cvInitTreeNodeIterator( &iterator2, contours2, INT_MAX ); + + for( count3 = 0; count3 < count; count3++ ) + { + CvSeq* seq1 = (CvSeq*)cvNextTreeNode( &iterator1 ); + CvSeq* seq2 = (CvSeq*)cvNextTreeNode( &iterator2 ); + CvSeqReader reader1; + CvSeqReader reader2; + + if( !seq1 || !seq2 ) + { + ts->printf( cvtest::TS::LOG, + "There are NULL pointers in the original contour tree or the " + "tree produced by cvApproxChains\n" ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + goto _exit_; + } + + cvStartReadSeq( seq1, &reader1 ); + cvStartReadSeq( seq2, &reader2 ); + + if( seq1->total != seq2->total ) + { + ts->printf( cvtest::TS::LOG, + "The original contour #%d has %d points, while the corresponding contour has %d point\n", + count3, seq1->total, seq2->total ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + goto _exit_; + } + + for(int i = 0; i < seq1->total; i++ ) + { + CvPoint pt1; + CvPoint pt2; + + CV_READ_SEQ_ELEM( pt1, reader1 ); + CV_READ_SEQ_ELEM( pt2, reader2 ); + + if( pt1.x != pt2.x || pt1.y != pt2.y ) + { + ts->printf( cvtest::TS::LOG, + "The point #%d in the contour #%d is different from the corresponding point " + "in the approximated chain ((%d,%d) vs (%d,%d)", count3, i, pt1.x, pt1.y, pt2.x, pt2.y ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + goto _exit_; + } + } + } + } + +_exit_: + if( code < 0 ) + { +#if 0 + cvNamedWindow( "test", 0 ); + cvShowImage( "test", img[0] ); + cvWaitKey(); +#endif + ts->set_failed_test_info( code ); + } + + return code; +} + + +TEST(Imgproc_FindContours, accuracy) { CV_FindContourTest test; test.safe_run(); } + +/* End of file. */ diff --git a/imgproc/test/test_convhull.cpp b/imgproc/test/test_convhull.cpp new file mode 100644 index 0000000..19f536a --- /dev/null +++ b/imgproc/test/test_convhull.cpp @@ -0,0 +1,1703 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +/*static int +cvTsPointConvexPolygon( CvPoint2D32f pt, CvPoint2D32f* v, int n ) +{ + CvPoint2D32f v0 = v[n-1]; + int i, sign = 0; + + for( i = 0; i < n; i++ ) + { + CvPoint2D32f v1 = v[i]; + float dx = pt.x - v0.x, dy = pt.y - v0.y; + float dx1 = v1.x - v0.x, dy1 = v1.y - v0.y; + double t = (double)dx*dy1 - (double)dx1*dy; + if( fabs(t) > DBL_EPSILON ) + { + if( t*sign < 0 ) + break; + if( sign == 0 ) + sign = t < 0 ? -1 : 1; + } + else if( fabs(dx) + fabs(dy) < DBL_EPSILON ) + return i+1; + v0 = v1; + } + + return i < n ? -1 : 0; +}*/ + +CV_INLINE double +cvTsDist( CvPoint2D32f a, CvPoint2D32f b ) +{ + double dx = a.x - b.x; + double dy = a.y - b.y; + return sqrt(dx*dx + dy*dy); +} + +CV_INLINE double +cvTsPtLineDist( CvPoint2D32f pt, CvPoint2D32f a, CvPoint2D32f b ) +{ + double d0 = cvTsDist( pt, a ), d1; + double dd = cvTsDist( a, b ); + if( dd < FLT_EPSILON ) + return d0; + d1 = cvTsDist( pt, b ); + dd = fabs((double)(pt.x - a.x)*(b.y - a.y) - (double)(pt.y - a.y)*(b.x - a.x))/dd; + d0 = MIN( d0, d1 ); + return MIN( d0, dd ); +} + +static double +cvTsPointPolygonTest( CvPoint2D32f pt, const CvPoint2D32f* vv, int n, int* _idx=0, int* _on_edge=0 ) +{ + int i; + CvPoint2D32f v = vv[n-1], v0; + double min_dist_num = FLT_MAX, min_dist_denom = 1; + int min_dist_idx = -1, min_on_edge = 0; + int counter = 0; + double result; + + for( i = 0; i < n; i++ ) + { + double dx, dy, dx1, dy1, dx2, dy2, dist_num, dist_denom = 1; + int on_edge = 0, idx = i; + + v0 = v; v = vv[i]; + dx = v.x - v0.x; dy = v.y - v0.y; + dx1 = pt.x - v0.x; dy1 = pt.y - v0.y; + dx2 = pt.x - v.x; dy2 = pt.y - v.y; + + if( dx2*dx + dy2*dy >= 0 ) + dist_num = dx2*dx2 + dy2*dy2; + else if( dx1*dx + dy1*dy <= 0 ) + { + dist_num = dx1*dx1 + dy1*dy1; + idx = i - 1; + if( idx < 0 ) idx = n-1; + } + else + { + dist_num = (dy1*dx - dx1*dy); + dist_num *= dist_num; + dist_denom = dx*dx + dy*dy; + on_edge = 1; + } + + if( dist_num*min_dist_denom < min_dist_num*dist_denom ) + { + min_dist_num = dist_num; + min_dist_denom = dist_denom; + min_dist_idx = idx; + min_on_edge = on_edge; + if( min_dist_num == 0 ) + break; + } + + if( (v0.y <= pt.y && v.y <= pt.y) || + (v0.y > pt.y && v.y > pt.y) || + (v0.x < pt.x && v.x < pt.x) ) + continue; + + dist_num = dy1*dx - dx1*dy; + if( dy < 0 ) + dist_num = -dist_num; + counter += dist_num > 0; + } + + result = sqrt(min_dist_num/min_dist_denom); + if( counter % 2 == 0 ) + result = -result; + + if( _idx ) + *_idx = min_dist_idx; + if( _on_edge ) + *_on_edge = min_on_edge; + + return result; +} + + +/****************************************************************************************\ +* Base class for shape descriptor tests * +\****************************************************************************************/ + +class CV_BaseShapeDescrTest : public cvtest::BaseTest +{ +public: + CV_BaseShapeDescrTest(); + virtual ~CV_BaseShapeDescrTest(); + void clear(); + +protected: + int read_params( CvFileStorage* fs ); + void run_func(void); + int prepare_test_case( int test_case_idx ); + int validate_test_results( int test_case_idx ); + virtual void generate_point_set( void* points ); + virtual void extract_points(); + + int min_log_size; + int max_log_size; + int dims; + bool enable_flt_points; + + CvMemStorage* storage; + CvSeq* points1; + CvMat* points2; + void* points; + void* result; + double low_high_range; + CvScalar low, high; + + bool test_cpp; +}; + + +CV_BaseShapeDescrTest::CV_BaseShapeDescrTest() +{ + points1 = 0; + points2 = 0; + points = 0; + storage = 0; + test_case_count = 500; + min_log_size = 0; + max_log_size = 10; + low = high = cvScalarAll(0); + low_high_range = 50; + dims = 2; + enable_flt_points = true; + + test_cpp = false; +} + + +CV_BaseShapeDescrTest::~CV_BaseShapeDescrTest() +{ + clear(); +} + + +void CV_BaseShapeDescrTest::clear() +{ + cvtest::BaseTest::clear(); + cvReleaseMemStorage( &storage ); + cvReleaseMat( &points2 ); + points1 = 0; + points = 0; +} + + +int CV_BaseShapeDescrTest::read_params( CvFileStorage* fs ) +{ + int code = cvtest::BaseTest::read_params( fs ); + if( code < 0 ) + return code; + + test_case_count = cvReadInt( find_param( fs, "struct_count" ), test_case_count ); + min_log_size = cvReadInt( find_param( fs, "min_log_size" ), min_log_size ); + max_log_size = cvReadInt( find_param( fs, "max_log_size" ), max_log_size ); + + min_log_size = cvtest::clipInt( min_log_size, 0, 8 ); + max_log_size = cvtest::clipInt( max_log_size, 0, 10 ); + if( min_log_size > max_log_size ) + { + int t; + CV_SWAP( min_log_size, max_log_size, t ); + } + + return 0; +} + + +void CV_BaseShapeDescrTest::generate_point_set( void* pointsSet ) +{ + RNG& rng = ts->get_rng(); + int i, k, n, total, point_type; + CvSeqReader reader; + uchar* data = 0; + double a[4], b[4]; + + for( k = 0; k < 4; k++ ) + { + a[k] = high.val[k] - low.val[k]; + b[k] = low.val[k]; + } + memset( &reader, 0, sizeof(reader) ); + + if( CV_IS_SEQ(pointsSet) ) + { + CvSeq* ptseq = (CvSeq*)pointsSet; + total = ptseq->total; + point_type = CV_SEQ_ELTYPE(ptseq); + cvStartReadSeq( ptseq, &reader ); + } + else + { + CvMat* ptm = (CvMat*)pointsSet; + assert( CV_IS_MAT(ptm) && CV_IS_MAT_CONT(ptm->type) ); + total = ptm->rows + ptm->cols - 1; + point_type = CV_MAT_TYPE(ptm->type); + data = ptm->data.ptr; + } + + n = CV_MAT_CN(point_type); + point_type = CV_MAT_DEPTH(point_type); + + assert( (point_type == CV_32S || point_type == CV_32F) && n <= 4 ); + + for( i = 0; i < total; i++ ) + { + int* pi; + float* pf; + if( reader.ptr ) + { + pi = (int*)reader.ptr; + pf = (float*)reader.ptr; + CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader ); + } + else + { + pi = (int*)data + i*n; + pf = (float*)data + i*n; + } + if( point_type == CV_32S ) + for( k = 0; k < n; k++ ) + pi[k] = cvRound(cvtest::randReal(rng)*a[k] + b[k]); + else + for( k = 0; k < n; k++ ) + pf[k] = (float)(cvtest::randReal(rng)*a[k] + b[k]); + } +} + + +int CV_BaseShapeDescrTest::prepare_test_case( int test_case_idx ) +{ + int size; + int use_storage = 0; + int point_type; + int i; + RNG& rng = ts->get_rng(); + + cvtest::BaseTest::prepare_test_case( test_case_idx ); + + clear(); + size = cvRound( exp((cvtest::randReal(rng) * (max_log_size - min_log_size) + min_log_size)*CV_LOG2) ); + use_storage = cvtest::randInt(rng) % 2; + point_type = CV_MAKETYPE(cvtest::randInt(rng) % + (enable_flt_points ? 2 : 1) ? CV_32F : CV_32S, dims); + + if( use_storage ) + { + storage = cvCreateMemStorage( (cvtest::randInt(rng)%10 + 1)*1024 ); + points1 = cvCreateSeq( point_type, sizeof(CvSeq), CV_ELEM_SIZE(point_type), storage ); + cvSeqPushMulti( points1, 0, size ); + points = points1; + } + else + { + int rows = 1, cols = size; + if( cvtest::randInt(rng) % 2 ) + rows = size, cols = 1; + + points2 = cvCreateMat( rows, cols, point_type ); + points = points2; + } + + for( i = 0; i < 4; i++ ) + { + low.val[i] = (cvtest::randReal(rng)-0.5)*low_high_range*2; + high.val[i] = (cvtest::randReal(rng)-0.5)*low_high_range*2; + if( low.val[i] > high.val[i] ) + { + double t; + CV_SWAP( low.val[i], high.val[i], t ); + } + if( high.val[i] < low.val[i] + 1 ) + high.val[i] += 1; + } + + generate_point_set( points ); + + test_cpp = (cvtest::randInt(rng) & 16) == 0; + return 1; +} + + +void CV_BaseShapeDescrTest::extract_points() +{ + if( points1 ) + { + points2 = cvCreateMat( 1, points1->total, CV_SEQ_ELTYPE(points1) ); + cvCvtSeqToArray( points1, points2->data.ptr ); + } + + if( CV_MAT_DEPTH(points2->type) != CV_32F && enable_flt_points ) + { + CvMat tmp = cvMat( points2->rows, points2->cols, + (points2->type & ~CV_MAT_DEPTH_MASK) | CV_32F, points2->data.ptr ); + cvConvert( points2, &tmp ); + } +} + + +void CV_BaseShapeDescrTest::run_func(void) +{ +} + + +int CV_BaseShapeDescrTest::validate_test_results( int /*test_case_idx*/ ) +{ + extract_points(); + return 0; +} + + +/****************************************************************************************\ +* Convex Hull Test * +\****************************************************************************************/ + +class CV_ConvHullTest : public CV_BaseShapeDescrTest +{ +public: + CV_ConvHullTest(); + virtual ~CV_ConvHullTest(); + void clear(); + +protected: + void run_func(void); + int prepare_test_case( int test_case_idx ); + int validate_test_results( int test_case_idx ); + + CvSeq* hull1; + CvMat* hull2; + void* hull_storage; + int orientation; + int return_points; +}; + + +CV_ConvHullTest::CV_ConvHullTest() +{ + hull1 = 0; + hull2 = 0; + hull_storage = 0; + orientation = return_points = 0; +} + + +CV_ConvHullTest::~CV_ConvHullTest() +{ + clear(); +} + + +void CV_ConvHullTest::clear() +{ + CV_BaseShapeDescrTest::clear(); + cvReleaseMat( &hull2 ); + hull1 = 0; + hull_storage = 0; +} + + +int CV_ConvHullTest::prepare_test_case( int test_case_idx ) +{ + int code = CV_BaseShapeDescrTest::prepare_test_case( test_case_idx ); + int use_storage_for_hull = 0; + RNG& rng = ts->get_rng(); + + if( code <= 0 ) + return code; + + orientation = cvtest::randInt(rng) % 2 ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE; + return_points = cvtest::randInt(rng) % 2; + + use_storage_for_hull = (cvtest::randInt(rng) % 2) && !test_cpp; + if( use_storage_for_hull ) + { + if( !storage ) + storage = cvCreateMemStorage( (cvtest::randInt(rng)%10 + 1)*1024 ); + hull_storage = storage; + } + else + { + int rows, cols; + int sz = points1 ? points1->total : points2->cols + points2->rows - 1; + int point_type = points1 ? CV_SEQ_ELTYPE(points1) : CV_MAT_TYPE(points2->type); + + if( cvtest::randInt(rng) % 2 ) + rows = sz, cols = 1; + else + rows = 1, cols = sz; + + hull2 = cvCreateMat( rows, cols, return_points ? point_type : CV_32SC1 ); + hull_storage = hull2; + } + + return code; +} + + +void CV_ConvHullTest::run_func() +{ + if(!test_cpp) + hull1 = cvConvexHull2( points, hull_storage, orientation, return_points ); + else + { + cv::Mat _points = cv::cvarrToMat(points); + bool clockwise = orientation == CV_CLOCKWISE; + size_t n = 0; + if( !return_points ) + { + std::vector _hull; + cv::convexHull(_points, _hull, clockwise); + n = _hull.size(); + memcpy(hull2->data.ptr, &_hull[0], n*sizeof(_hull[0])); + } + else if(_points.type() == CV_32SC2) + { + std::vector _hull; + cv::convexHull(_points, _hull, clockwise); + n = _hull.size(); + memcpy(hull2->data.ptr, &_hull[0], n*sizeof(_hull[0])); + } + else if(_points.type() == CV_32FC2) + { + std::vector _hull; + cv::convexHull(_points, _hull, clockwise); + n = _hull.size(); + memcpy(hull2->data.ptr, &_hull[0], n*sizeof(_hull[0])); + } + if(hull2->rows > hull2->cols) + hull2->rows = (int)n; + else + hull2->cols = (int)n; + } +} + + +int CV_ConvHullTest::validate_test_results( int test_case_idx ) +{ + int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx ); + CvMat* hull = 0; + CvMat* mask = 0; + int i, point_count, hull_count; + CvPoint2D32f *p, *h; + CvSeq header, hheader, *ptseq, *hseq; + CvSeqBlock block, hblock; + + if( points1 ) + ptseq = points1; + else + ptseq = cvMakeSeqHeaderForArray( CV_MAT_TYPE(points2->type), + sizeof(CvSeq), CV_ELEM_SIZE(points2->type), points2->data.ptr, + points2->rows + points2->cols - 1, &header, &block ); + point_count = ptseq->total; + p = (CvPoint2D32f*)(points2->data.ptr); + + if( hull1 ) + hseq = hull1; + else + hseq = cvMakeSeqHeaderForArray( CV_MAT_TYPE(hull2->type), + sizeof(CvSeq), CV_ELEM_SIZE(hull2->type), hull2->data.ptr, + hull2->rows + hull2->cols - 1, &hheader, &hblock ); + hull_count = hseq->total; + hull = cvCreateMat( 1, hull_count, CV_32FC2 ); + mask = cvCreateMat( 1, hull_count, CV_8UC1 ); + cvZero( mask ); + h = (CvPoint2D32f*)(hull->data.ptr); + + // extract convex hull points + if( return_points ) + { + cvCvtSeqToArray( hseq, hull->data.ptr ); + if( CV_SEQ_ELTYPE(hseq) != CV_32FC2 ) + { + CvMat tmp = cvMat( hull->rows, hull->cols, CV_32SC2, hull->data.ptr ); + cvConvert( &tmp, hull ); + } + } + else + { + CvSeqReader reader; + cvStartReadSeq( hseq, &reader ); + + for( i = 0; i < hull_count; i++ ) + { + schar* ptr = reader.ptr; + int idx; + CV_NEXT_SEQ_ELEM( hseq->elem_size, reader ); + + if( hull1 ) + idx = cvSeqElemIdx( ptseq, *(uchar**)ptr ); + else + idx = *(int*)ptr; + + if( idx < 0 || idx >= point_count ) + { + ts->printf( cvtest::TS::LOG, "Invalid convex hull point #%d\n", i ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + goto _exit_; + } + h[i] = p[idx]; + } + } + + // check that the convex hull is a convex polygon + if( hull_count >= 3 ) + { + CvPoint2D32f pt0 = h[hull_count-1]; + for( i = 0; i < hull_count; i++ ) + { + int j = i+1; + CvPoint2D32f pt1 = h[i], pt2 = h[j < hull_count ? j : 0]; + float dx0 = pt1.x - pt0.x, dy0 = pt1.y - pt0.y; + float dx1 = pt2.x - pt1.x, dy1 = pt2.y - pt1.y; + double t = (double)dx0*dy1 - (double)dx1*dy0; + if( (t < 0) ^ (orientation != CV_COUNTER_CLOCKWISE) ) + { + ts->printf( cvtest::TS::LOG, "The convex hull is not convex or has a wrong orientation (vtx %d)\n", i ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + goto _exit_; + } + pt0 = pt1; + } + } + + // check that all the points are inside the hull or on the hull edge + // and at least hull_point points are at the hull vertices + for( i = 0; i < point_count; i++ ) + { + int idx = 0, on_edge = 0; + double pptresult = cvTsPointPolygonTest( p[i], h, hull_count, &idx, &on_edge ); + + if( pptresult < 0 ) + { + ts->printf( cvtest::TS::LOG, "The point #%d is outside of the convex hull\n", i ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + goto _exit_; + } + + if( pptresult < FLT_EPSILON && !on_edge ) + mask->data.ptr[idx] = (uchar)1; + } + + if( cvNorm( mask, 0, CV_L1 ) != hull_count ) + { + ts->printf( cvtest::TS::LOG, "Not every convex hull vertex coincides with some input point\n" ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + goto _exit_; + } + +_exit_: + + cvReleaseMat( &hull ); + cvReleaseMat( &mask ); + if( code < 0 ) + ts->set_failed_test_info( code ); + return code; +} + + +/****************************************************************************************\ +* MinAreaRect Test * +\****************************************************************************************/ + +class CV_MinAreaRectTest : public CV_BaseShapeDescrTest +{ +public: + CV_MinAreaRectTest(); + +protected: + void run_func(void); + int validate_test_results( int test_case_idx ); + + CvBox2D box; + CvPoint2D32f box_pt[4]; +}; + + +CV_MinAreaRectTest::CV_MinAreaRectTest() +{ +} + + +void CV_MinAreaRectTest::run_func() +{ + if(!test_cpp) + { + box = cvMinAreaRect2( points, storage ); + cvBoxPoints( box, box_pt ); + } + else + { + cv::RotatedRect r = cv::minAreaRect(cv::cvarrToMat(points)); + box = (CvBox2D)r; + r.points((cv::Point2f*)box_pt); + } +} + + +int CV_MinAreaRectTest::validate_test_results( int test_case_idx ) +{ + double eps = 1e-1; + int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx ); + int i, j, point_count = points2->rows + points2->cols - 1; + CvPoint2D32f *p = (CvPoint2D32f*)(points2->data.ptr); + int mask[] = {0,0,0,0}; + + // check that the bounding box is a rotated rectangle: + // 1. diagonals should be equal + // 2. they must intersect in their middle points + { + double d0 = cvTsDist( box_pt[0], box_pt[2] ); + double d1 = cvTsDist( box_pt[1], box_pt[3] ); + + double x0 = (box_pt[0].x + box_pt[2].x)*0.5; + double y0 = (box_pt[0].y + box_pt[2].y)*0.5; + double x1 = (box_pt[1].x + box_pt[3].x)*0.5; + double y1 = (box_pt[1].y + box_pt[3].y)*0.5; + + if( fabs(d0 - d1) + fabs(x0 - x1) + fabs(y0 - y1) > eps*MAX(d0,d1) ) + { + ts->printf( cvtest::TS::LOG, "The bounding box is not a rectangle\n" ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + goto _exit_; + } + } + +#if 0 + { + int n = 4; + double a = 8, c = 8, b = 100, d = 150; + CvPoint bp[4], *bpp = bp; + cvNamedWindow( "test", 1 ); + IplImage* img = cvCreateImage( cvSize(500,500), 8, 3 ); + cvZero(img); + for( i = 0; i < point_count; i++ ) + cvCircle(img,cvPoint(cvRound(p[i].x*a+b),cvRound(p[i].y*c+d)), 3, CV_RGB(0,255,0), -1 ); + for( i = 0; i < n; i++ ) + bp[i] = cvPoint(cvRound(box_pt[i].x*a+b),cvRound(box_pt[i].y*c+d)); + cvPolyLine( img, &bpp, &n, 1, 1, CV_RGB(255,255,0), 1, CV_AA, 0 ); + cvShowImage( "test", img ); + cvWaitKey(); + cvReleaseImage(&img); + } +#endif + + // check that the box includes all the points + // and there is at least one point at (or very close to) every box side + for( i = 0; i < point_count; i++ ) + { + int idx = 0, on_edge = 0; + double pptresult = cvTsPointPolygonTest( p[i], box_pt, 4, &idx, &on_edge ); + if( pptresult < -eps ) + { + ts->printf( cvtest::TS::LOG, "The point #%d is outside of the box\n", i ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + goto _exit_; + } + + if( pptresult < eps ) + { + for( j = 0; j < 4; j++ ) + { + double d = cvTsPtLineDist( p[i], box_pt[(j-1)&3], box_pt[j] ); + if( d < eps ) + mask[j] = (uchar)1; + } + } + } + + if( mask[0] + mask[1] + mask[2] + mask[3] != 4 ) + { + ts->printf( cvtest::TS::LOG, "Not every box side has a point nearby\n" ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + goto _exit_; + } + +_exit_: + + if( code < 0 ) + ts->set_failed_test_info( code ); + return code; +} + + +/****************************************************************************************\ +* MinEnclosingCircle Test * +\****************************************************************************************/ + +class CV_MinCircleTest : public CV_BaseShapeDescrTest +{ +public: + CV_MinCircleTest(); + +protected: + void run_func(void); + int validate_test_results( int test_case_idx ); + + CvPoint2D32f center; + float radius; +}; + + +CV_MinCircleTest::CV_MinCircleTest() +{ +} + + +void CV_MinCircleTest::run_func() +{ + if(!test_cpp) + cvMinEnclosingCircle( points, ¢er, &radius ); + else + { + cv::Point2f tmpcenter; + cv::minEnclosingCircle(cv::cvarrToMat(points), tmpcenter, radius); + center = tmpcenter; + } +} + + +int CV_MinCircleTest::validate_test_results( int test_case_idx ) +{ + double eps = 1.03; + int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx ); + int i, j = 0, point_count = points2->rows + points2->cols - 1; + CvPoint2D32f *p = (CvPoint2D32f*)(points2->data.ptr); + CvPoint2D32f v[3]; + +#if 0 + { + double a = 2, b = 200, d = 400; + cvNamedWindow( "test", 1 ); + IplImage* img = cvCreateImage( cvSize(500,500), 8, 3 ); + cvZero(img); + for( i = 0; i < point_count; i++ ) + cvCircle(img,cvPoint(cvRound(p[i].x*a+b),cvRound(p[i].y*a+d)), 3, CV_RGB(0,255,0), -1 ); + cvCircle( img, cvPoint(cvRound(center.x*a+b),cvRound(center.y*a+d)), + cvRound(radius*a), CV_RGB(255,255,0), 1 ); + cvShowImage( "test", img ); + cvWaitKey(); + cvReleaseImage(&img); + } +#endif + + // check that the circle contains all the points inside and + // remember at most 3 points that are close to the boundary + for( i = 0; i < point_count; i++ ) + { + double d = cvTsDist( p[i], center ); + if( d > radius ) + { + ts->printf( cvtest::TS::LOG, "The point #%d is outside of the circle\n", i ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + goto _exit_; + } + + if( radius - d < eps*radius && j < 3 ) + v[j++] = p[i]; + } + + if( point_count >= 2 && (j < 2 || (j == 2 && cvTsDist(v[0],v[1]) < (radius-1)*2/eps)) ) + { + ts->printf( cvtest::TS::LOG, + "There should be at at least 3 points near the circle boundary or 2 points on the diameter\n" ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + goto _exit_; + } + +_exit_: + + if( code < 0 ) + ts->set_failed_test_info( code ); + return code; +} + + +/****************************************************************************************\ +* Perimeter Test * +\****************************************************************************************/ + +class CV_PerimeterTest : public CV_BaseShapeDescrTest +{ +public: + CV_PerimeterTest(); + +protected: + int prepare_test_case( int test_case_idx ); + void run_func(void); + int validate_test_results( int test_case_idx ); + CvSlice slice; + int is_closed; + double result; +}; + + +CV_PerimeterTest::CV_PerimeterTest() +{ +} + + +int CV_PerimeterTest::prepare_test_case( int test_case_idx ) +{ + int code = CV_BaseShapeDescrTest::prepare_test_case( test_case_idx ); + RNG& rng = ts->get_rng(); + int total; + + if( code < 0 ) + return code; + + is_closed = cvtest::randInt(rng) % 2; + + if( points1 ) + { + points1->flags |= CV_SEQ_KIND_CURVE; + if( is_closed ) + points1->flags |= CV_SEQ_FLAG_CLOSED; + total = points1->total; + } + else + total = points2->cols + points2->rows - 1; + + if( (cvtest::randInt(rng) % 3) && !test_cpp ) + { + slice.start_index = cvtest::randInt(rng) % total; + slice.end_index = cvtest::randInt(rng) % total; + } + else + slice = CV_WHOLE_SEQ; + + return 1; +} + + +void CV_PerimeterTest::run_func() +{ + if(!test_cpp) + result = cvArcLength( points, slice, points1 ? -1 : is_closed ); + else + result = cv::arcLength(cv::cvarrToMat(points), + !points1 ? is_closed != 0 : (points1->flags & CV_SEQ_FLAG_CLOSED) != 0); +} + + +int CV_PerimeterTest::validate_test_results( int test_case_idx ) +{ + int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx ); + int i, len = slice.end_index - slice.start_index, total = points2->cols + points2->rows - 1; + double result0 = 0; + CvPoint2D32f prev_pt, pt, *ptr; + + if( len < 0 ) + len += total; + + len = MIN( len, total ); + //len -= !is_closed && len == total; + + ptr = (CvPoint2D32f*)points2->data.fl; + prev_pt = ptr[(is_closed ? slice.start_index+len-1 : slice.start_index) % total]; + + for( i = 0; i < len + (len < total && (!is_closed || len==1)); i++ ) + { + pt = ptr[(i + slice.start_index) % total]; + double dx = pt.x - prev_pt.x, dy = pt.y - prev_pt.y; + result0 += sqrt(dx*dx + dy*dy); + prev_pt = pt; + } + + if( cvIsNaN(result) || cvIsInf(result) ) + { + ts->printf( cvtest::TS::LOG, "cvArcLength() returned invalid value (%g)\n", result ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + } + else if( fabs(result - result0) > FLT_EPSILON*100*result0 ) + { + ts->printf( cvtest::TS::LOG, "The function returned %g, while the correct result is %g\n", result, result0 ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + } + + if( code < 0 ) + ts->set_failed_test_info( code ); + return code; +} + + +/****************************************************************************************\ +* FitEllipse Test * +\****************************************************************************************/ + +class CV_FitEllipseTest : public CV_BaseShapeDescrTest +{ +public: + CV_FitEllipseTest(); + +protected: + int prepare_test_case( int test_case_idx ); + void generate_point_set( void* points ); + void run_func(void); + int validate_test_results( int test_case_idx ); + CvBox2D box0, box; + double min_ellipse_size, max_noise; +}; + + +CV_FitEllipseTest::CV_FitEllipseTest() +{ + min_log_size = 5; // for robust ellipse fitting a dozen of points is needed at least + max_log_size = 10; + min_ellipse_size = 10; + max_noise = 0.05; +} + + +void CV_FitEllipseTest::generate_point_set( void* pointsSet ) +{ + RNG& rng = ts->get_rng(); + int i, total, point_type; + CvSeqReader reader; + uchar* data = 0; + double a, b; + + box0.center.x = (float)((low.val[0] + high.val[0])*0.5); + box0.center.y = (float)((low.val[1] + high.val[1])*0.5); + box0.size.width = (float)(MAX(high.val[0] - low.val[0], min_ellipse_size)*2); + box0.size.height = (float)(MAX(high.val[1] - low.val[1], min_ellipse_size)*2); + box0.angle = (float)(cvtest::randReal(rng)*180); + a = cos(box0.angle*CV_PI/180.); + b = sin(box0.angle*CV_PI/180.); + + if( box0.size.width > box0.size.height ) + { + float t; + CV_SWAP( box0.size.width, box0.size.height, t ); + } + memset( &reader, 0, sizeof(reader) ); + + if( CV_IS_SEQ(pointsSet) ) + { + CvSeq* ptseq = (CvSeq*)pointsSet; + total = ptseq->total; + point_type = CV_SEQ_ELTYPE(ptseq); + cvStartReadSeq( ptseq, &reader ); + } + else + { + CvMat* ptm = (CvMat*)pointsSet; + assert( CV_IS_MAT(ptm) && CV_IS_MAT_CONT(ptm->type) ); + total = ptm->rows + ptm->cols - 1; + point_type = CV_MAT_TYPE(ptm->type); + data = ptm->data.ptr; + } + + assert( point_type == CV_32SC2 || point_type == CV_32FC2 ); + + for( i = 0; i < total; i++ ) + { + CvPoint* pp; + CvPoint2D32f p; + double angle = cvtest::randReal(rng)*CV_PI*2; + double x = box0.size.height*0.5*(cos(angle) + (cvtest::randReal(rng)-0.5)*2*max_noise); + double y = box0.size.width*0.5*(sin(angle) + (cvtest::randReal(rng)-0.5)*2*max_noise); + p.x = (float)(box0.center.x + a*x + b*y); + p.y = (float)(box0.center.y - b*x + a*y); + + if( reader.ptr ) + { + pp = (CvPoint*)reader.ptr; + CV_NEXT_SEQ_ELEM( sizeof(*pp), reader ); + } + else + pp = ((CvPoint*)data) + i; + if( point_type == CV_32SC2 ) + { + pp->x = cvRound(p.x); + pp->y = cvRound(p.y); + } + else + *(CvPoint2D32f*)pp = p; + } +} + + +int CV_FitEllipseTest::prepare_test_case( int test_case_idx ) +{ + min_log_size = MAX(min_log_size,4); + max_log_size = MAX(min_log_size,max_log_size); + return CV_BaseShapeDescrTest::prepare_test_case( test_case_idx ); +} + + +void CV_FitEllipseTest::run_func() +{ + if(!test_cpp) + box = cvFitEllipse2( points ); + else + box = (CvBox2D)cv::fitEllipse(cv::cvarrToMat(points)); +} + + +int CV_FitEllipseTest::validate_test_results( int test_case_idx ) +{ + int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx ); + double diff_angle; + + if( cvIsNaN(box.center.x) || cvIsInf(box.center.x) || + cvIsNaN(box.center.y) || cvIsInf(box.center.y) || + cvIsNaN(box.size.width) || cvIsInf(box.size.width) || + cvIsNaN(box.size.height) || cvIsInf(box.size.height) || + cvIsNaN(box.angle) || cvIsInf(box.angle) ) + { + ts->printf( cvtest::TS::LOG, "Some of the computed ellipse parameters are invalid (x=%g,y=%g,w=%g,h=%g,angle=%g)\n", + box.center.x, box.center.y, box.size.width, box.size.height, box.angle ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + goto _exit_; + } + + box.angle = (float)(90-box.angle); + if( box.angle < 0 ) + box.angle += 360; + if( box.angle > 360 ) + box.angle -= 360; + + if( fabs(box.center.x - box0.center.x) > 3 || + fabs(box.center.y - box0.center.y) > 3 || + fabs(box.size.width - box0.size.width) > 0.1*fabs(box0.size.width) || + fabs(box.size.height - box0.size.height) > 0.1*fabs(box0.size.height) ) + { + ts->printf( cvtest::TS::LOG, "The computed ellipse center and/or size are incorrect:\n\t" + "(x=%.1f,y=%.1f,w=%.1f,h=%.1f), while it should be (x=%.1f,y=%.1f,w=%.1f,h=%.1f)\n", + box.center.x, box.center.y, box.size.width, box.size.height, + box0.center.x, box0.center.y, box0.size.width, box0.size.height ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + goto _exit_; + } + + diff_angle = fabs(box0.angle - box.angle); + diff_angle = MIN( diff_angle, fabs(diff_angle - 360)); + diff_angle = MIN( diff_angle, fabs(diff_angle - 180)); + + if( box0.size.height >= 1.3*box0.size.width && diff_angle > 30 ) + { + ts->printf( cvtest::TS::LOG, "Incorrect ellipse angle (=%1.f, should be %1.f)\n", + box.angle, box0.angle ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + goto _exit_; + } + +_exit_: + +#if 0 + if( code < 0 ) + { + cvNamedWindow( "test", 0 ); + IplImage* img = cvCreateImage( cvSize(cvRound(low_high_range*4), + cvRound(low_high_range*4)), 8, 3 ); + cvZero( img ); + + box.center.x += (float)low_high_range*2; + box.center.y += (float)low_high_range*2; + cvEllipseBox( img, box, CV_RGB(255,0,0), 3, 8 ); + + for( int i = 0; i < points2->rows + points2->cols - 1; i++ ) + { + CvPoint pt; + pt.x = cvRound(points2->data.fl[i*2] + low_high_range*2); + pt.y = cvRound(points2->data.fl[i*2+1] + low_high_range*2); + cvCircle( img, pt, 1, CV_RGB(255,255,255), -1, 8 ); + } + + cvShowImage( "test", img ); + cvReleaseImage( &img ); + cvWaitKey(0); + } +#endif + + if( code < 0 ) + { + ts->set_failed_test_info( code ); + } + return code; +} + + +class CV_FitEllipseSmallTest : public cvtest::BaseTest +{ +public: + CV_FitEllipseSmallTest() {} + ~CV_FitEllipseSmallTest() {} +protected: + void run(int) + { + Size sz(50, 50); + vector > c; + c.push_back(vector()); + int scale = 1; + Point ofs = Point(0,0);//sz.width/2, sz.height/2) - Point(4,4)*scale; + c[0].push_back(Point(2, 0)*scale+ofs); + c[0].push_back(Point(0, 2)*scale+ofs); + c[0].push_back(Point(0, 6)*scale+ofs); + c[0].push_back(Point(2, 8)*scale+ofs); + c[0].push_back(Point(6, 8)*scale+ofs); + c[0].push_back(Point(8, 6)*scale+ofs); + c[0].push_back(Point(8, 2)*scale+ofs); + c[0].push_back(Point(6, 0)*scale+ofs); + + RotatedRect e = fitEllipse(c[0]); + CV_Assert( fabs(e.center.x - 4) <= 1. && + fabs(e.center.y - 4) <= 1. && + fabs(e.size.width - 9) <= 1. && + fabs(e.size.height - 9) <= 1. ); + } +}; + +/****************************************************************************************\ +* FitLine Test * +\****************************************************************************************/ + +class CV_FitLineTest : public CV_BaseShapeDescrTest +{ +public: + CV_FitLineTest(); + +protected: + int prepare_test_case( int test_case_idx ); + void generate_point_set( void* points ); + void run_func(void); + int validate_test_results( int test_case_idx ); + double max_noise; + float line[6], line0[6]; + int dist_type; + double reps, aeps; +}; + + +CV_FitLineTest::CV_FitLineTest() +{ + min_log_size = 5; // for robust ellipse fitting a dozen of points is needed at least + max_log_size = 10; + max_noise = 0.05; +} + + +void CV_FitLineTest::generate_point_set( void* pointsSet ) +{ + RNG& rng = ts->get_rng(); + int i, k, n, total, point_type; + CvSeqReader reader; + uchar* data = 0; + double s = 0; + + n = dims; + for( k = 0; k < n; k++ ) + { + line0[k+n] = (float)((low.val[k] + high.val[k])*0.5); + line0[k] = (float)(high.val[k] - low.val[k]); + if( cvtest::randInt(rng) % 2 ) + line0[k] = -line0[k]; + s += (double)line0[k]*line0[k]; + } + + s = 1./sqrt(s); + for( k = 0; k < n; k++ ) + line0[k] = (float)(line0[k]*s); + + memset( &reader, 0, sizeof(reader) ); + + if( CV_IS_SEQ(pointsSet) ) + { + CvSeq* ptseq = (CvSeq*)pointsSet; + total = ptseq->total; + point_type = CV_MAT_DEPTH(CV_SEQ_ELTYPE(ptseq)); + cvStartReadSeq( ptseq, &reader ); + } + else + { + CvMat* ptm = (CvMat*)pointsSet; + assert( CV_IS_MAT(ptm) && CV_IS_MAT_CONT(ptm->type) ); + total = ptm->rows + ptm->cols - 1; + point_type = CV_MAT_DEPTH(CV_MAT_TYPE(ptm->type)); + data = ptm->data.ptr; + } + + for( i = 0; i < total; i++ ) + { + int* pi; + float* pf; + float p[4], t; + if( reader.ptr ) + { + pi = (int*)reader.ptr; + pf = (float*)reader.ptr; + CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader ); + } + else + { + pi = (int*)data + i*n; + pf = (float*)data + i*n; + } + + t = (float)((cvtest::randReal(rng)-0.5)*low_high_range*2); + + for( k = 0; k < n; k++ ) + p[k] = (float)((cvtest::randReal(rng)-0.5)*max_noise*2 + t*line0[k] + line0[k+n]); + + if( point_type == CV_32S ) + for( k = 0; k < n; k++ ) + pi[k] = cvRound(p[k]); + else + for( k = 0; k < n; k++ ) + pf[k] = p[k]; + } +} + + +int CV_FitLineTest::prepare_test_case( int test_case_idx ) +{ + RNG& rng = ts->get_rng(); + dims = cvtest::randInt(rng) % 2 + 2; + min_log_size = MAX(min_log_size,5); + max_log_size = MAX(min_log_size,max_log_size); + int code = CV_BaseShapeDescrTest::prepare_test_case( test_case_idx ); + dist_type = cvtest::randInt(rng) % 6 + 1; + dist_type += dist_type == CV_DIST_C; + reps = 0.1; aeps = 0.01; + return code; +} + + +void CV_FitLineTest::run_func() +{ + if(!test_cpp) + cvFitLine( points, dist_type, 0, reps, aeps, line ); + else if(dims == 2) + cv::fitLine(cv::cvarrToMat(points), (cv::Vec4f&)line[0], dist_type, 0, reps, aeps); + else + cv::fitLine(cv::cvarrToMat(points), (cv::Vec6f&)line[0], dist_type, 0, reps, aeps); +} + + +int CV_FitLineTest::validate_test_results( int test_case_idx ) +{ + int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx ); + int k, max_k = 0; + double vec_diff = 0, t; + + for( k = 0; k < dims*2; k++ ) + { + if( cvIsNaN(line[k]) || cvIsInf(line[k]) ) + { + ts->printf( cvtest::TS::LOG, "Some of the computed line parameters are invalid (line[%d]=%g)\n", + k, line[k] ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + goto _exit_; + } + } + + if( fabs(line0[1]) > fabs(line0[0]) ) + max_k = 1; + if( fabs(line0[dims-1]) > fabs(line0[max_k]) ) + max_k = dims-1; + if( line0[max_k] < 0 ) + for( k = 0; k < dims; k++ ) + line0[k] = -line0[k]; + if( line[max_k] < 0 ) + for( k = 0; k < dims; k++ ) + line[k] = -line[k]; + + for( k = 0; k < dims; k++ ) + { + double dt = line[k] - line0[k]; + vec_diff += dt*dt; + } + + if( sqrt(vec_diff) > 0.05 ) + { + if( dims == 2 ) + ts->printf( cvtest::TS::LOG, + "The computed line vector (%.2f,%.2f) is different from the actual (%.2f,%.2f)\n", + line[0], line[1], line0[0], line0[1] ); + else + ts->printf( cvtest::TS::LOG, + "The computed line vector (%.2f,%.2f,%.2f) is different from the actual (%.2f,%.2f,%.2f)\n", + line[0], line[1], line[2], line0[0], line0[1], line0[2] ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + goto _exit_; + } + + t = (line[max_k+dims] - line0[max_k+dims])/line0[max_k]; + for( k = 0; k < dims; k++ ) + { + double p = line0[k+dims] + t*line0[k] - line[k+dims]; + vec_diff += p*p; + } + + if( sqrt(vec_diff) > 1*MAX(fabs(t),1) ) + { + if( dims == 2 ) + ts->printf( cvtest::TS::LOG, + "The computed line point (%.2f,%.2f) is too far from the actual line\n", + line[2]+line0[2], line[3]+line0[3] ); + else + ts->printf( cvtest::TS::LOG, + "The computed line point (%.2f,%.2f,%.2f) is too far from the actual line\n", + line[3]+line0[3], line[4]+line0[4], line[5]+line0[5] ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + goto _exit_; + } + +_exit_: + + if( code < 0 ) + { + ts->set_failed_test_info( code ); + } + return code; +} + + +/****************************************************************************************\ +* ContourMoments Test * +\****************************************************************************************/ + + +static void +cvTsGenerateTousledBlob( CvPoint2D32f center, CvSize2D32f axes, + double max_r_scale, double angle, CvArr* points, RNG& rng ) +{ + int i, total, point_type; + uchar* data = 0; + CvSeqReader reader; + memset( &reader, 0, sizeof(reader) ); + + if( CV_IS_SEQ(points) ) + { + CvSeq* ptseq = (CvSeq*)points; + total = ptseq->total; + point_type = CV_SEQ_ELTYPE(ptseq); + cvStartReadSeq( ptseq, &reader ); + } + else + { + CvMat* ptm = (CvMat*)points; + assert( CV_IS_MAT(ptm) && CV_IS_MAT_CONT(ptm->type) ); + total = ptm->rows + ptm->cols - 1; + point_type = CV_MAT_TYPE(ptm->type); + data = ptm->data.ptr; + } + + assert( point_type == CV_32SC2 || point_type == CV_32FC2 ); + + for( i = 0; i < total; i++ ) + { + CvPoint* pp; + CvPoint2D32f p; + + double phi0 = 2*CV_PI*i/total; + double phi = CV_PI*angle/180.; + double t = cvtest::randReal(rng)*max_r_scale + (1 - max_r_scale); + double ta = axes.height*t; + double tb = axes.width*t; + double c0 = cos(phi0)*ta, s0 = sin(phi0)*tb; + double c = cos(phi), s = sin(phi); + p.x = (float)(c0*c - s0*s + center.x); + p.y = (float)(c0*s + s0*c + center.y); + + if( reader.ptr ) + { + pp = (CvPoint*)reader.ptr; + CV_NEXT_SEQ_ELEM( sizeof(*pp), reader ); + } + else + pp = ((CvPoint*)data) + i; + + if( point_type == CV_32SC2 ) + { + pp->x = cvRound(p.x); + pp->y = cvRound(p.y); + } + else + *(CvPoint2D32f*)pp = p; + } +} + + +class CV_ContourMomentsTest : public CV_BaseShapeDescrTest +{ +public: + CV_ContourMomentsTest(); + +protected: + int prepare_test_case( int test_case_idx ); + void generate_point_set( void* points ); + void run_func(void); + int validate_test_results( int test_case_idx ); + CvMoments moments0, moments; + double area0, area; + CvSize2D32f axes; + CvPoint2D32f center; + int max_max_r_scale; + double max_r_scale, angle; + CvSize img_size; +}; + + +CV_ContourMomentsTest::CV_ContourMomentsTest() +{ + min_log_size = 3; + max_log_size = 8; + max_max_r_scale = 15; + low_high_range = 200; + enable_flt_points = false; +} + + +void CV_ContourMomentsTest::generate_point_set( void* pointsSet ) +{ + RNG& rng = ts->get_rng(); + float max_sz; + + axes.width = (float)((cvtest::randReal(rng)*0.9 + 0.1)*low_high_range); + axes.height = (float)((cvtest::randReal(rng)*0.9 + 0.1)*low_high_range); + max_sz = MAX(axes.width, axes.height); + + img_size.width = img_size.height = cvRound(low_high_range*2.2); + + center.x = (float)(img_size.width*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.width - max_sz*2)*0.8); + center.y = (float)(img_size.height*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.height - max_sz*2)*0.8); + + assert( 0 < center.x - max_sz && center.x + max_sz < img_size.width && + 0 < center.y - max_sz && center.y + max_sz < img_size.height ); + + max_r_scale = cvtest::randReal(rng)*max_max_r_scale*0.01; + angle = cvtest::randReal(rng)*360; + + cvTsGenerateTousledBlob( center, axes, max_r_scale, angle, pointsSet, rng ); + + if( points1 ) + points1->flags = CV_SEQ_MAGIC_VAL + CV_SEQ_POLYGON; +} + + +int CV_ContourMomentsTest::prepare_test_case( int test_case_idx ) +{ + min_log_size = MAX(min_log_size,3); + max_log_size = MIN(max_log_size,8); + max_log_size = MAX(min_log_size,max_log_size); + int code = CV_BaseShapeDescrTest::prepare_test_case( test_case_idx ); + return code; +} + + +void CV_ContourMomentsTest::run_func() +{ + if(!test_cpp) + { + cvMoments( points, &moments ); + area = cvContourArea( points ); + } + else + { + moments = (CvMoments)cv::moments(cv::cvarrToMat(points)); + area = cv::contourArea(cv::cvarrToMat(points)); + } +} + + +int CV_ContourMomentsTest::validate_test_results( int test_case_idx ) +{ + int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx ); + int i, n = (int)(sizeof(moments)/sizeof(moments.inv_sqrt_m00)); + CvMat* img = cvCreateMat( img_size.height, img_size.width, CV_8UC1 ); + CvPoint* pt = (CvPoint*)points2->data.i; + int count = points2->cols + points2->rows - 1; + double max_v0 = 0; + + cvZero(img); + cvFillPoly( img, &pt, &count, 1, cvScalarAll(1)); + cvMoments( img, &moments0 ); + + for( i = 0; i < n; i++ ) + { + double t = fabs((&moments0.m00)[i]); + max_v0 = MAX(max_v0, t); + } + + for( i = 0; i <= n; i++ ) + { + double v = i < n ? (&moments.m00)[i] : area; + double v0 = i < n ? (&moments0.m00)[i] : moments0.m00; + + if( cvIsNaN(v) || cvIsInf(v) ) + { + ts->printf( cvtest::TS::LOG, + "The contour %s is invalid (=%g)\n", i < n ? "moment" : "area", v ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + break; + } + + if( fabs(v - v0) > 0.1*max_v0 ) + { + ts->printf( cvtest::TS::LOG, + "The computed contour %s is %g, while it should be %g\n", + i < n ? "moment" : "area", v, v0 ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + break; + } + } + + if( code < 0 ) + { +#if 0 + cvCmpS( img, 0, img, CV_CMP_GT ); + cvNamedWindow( "test", 1 ); + cvShowImage( "test", img ); + cvWaitKey(); +#endif + ts->set_failed_test_info( code ); + } + + cvReleaseMat( &img ); + return code; +} + + +////////////////////////////////////// Perimeter/Area/Slice test /////////////////////////////////// + +class CV_PerimeterAreaSliceTest : public cvtest::BaseTest +{ +public: + CV_PerimeterAreaSliceTest(); + ~CV_PerimeterAreaSliceTest(); +protected: + void run(int); +}; + +CV_PerimeterAreaSliceTest::CV_PerimeterAreaSliceTest() +{ +} +CV_PerimeterAreaSliceTest::~CV_PerimeterAreaSliceTest() {} + +void CV_PerimeterAreaSliceTest::run( int ) +{ + Ptr storage = cvCreateMemStorage(); + RNG& rng = theRNG(); + const double min_r = 90, max_r = 120; + + for( int i = 0; i < 100; i++ ) + { + ts->update_context( this, i, true ); + int n = rng.uniform(3, 30); + cvClearMemStorage(storage); + CvSeq* contour = cvCreateSeq(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(CvPoint), storage); + double dphi = CV_PI*2/n; + CvPoint center; + center.x = rng.uniform(cvCeil(max_r), cvFloor(640-max_r)); + center.y = rng.uniform(cvCeil(max_r), cvFloor(480-max_r)); + + for( int j = 0; j < n; j++ ) + { + CvPoint pt; + double r = rng.uniform(min_r, max_r); + double phi = j*dphi; + pt.x = cvRound(center.x + r*cos(phi)); + pt.y = cvRound(center.y - r*sin(phi)); + cvSeqPush(contour, &pt); + } + + CvSlice slice; + for(;;) + { + slice.start_index = rng.uniform(-n/2, 3*n/2); + slice.end_index = rng.uniform(-n/2, 3*n/2); + int len = cvSliceLength(slice, contour); + if( len > 2 ) + break; + } + CvSeq *cslice = cvSeqSlice(contour, slice); + /*printf( "%d. (%d, %d) of %d, length = %d, length1 = %d\n", + i, slice.start_index, slice.end_index, + contour->total, cvSliceLength(slice, contour), cslice->total ); + + double area0 = cvContourArea(cslice); + double area1 = cvContourArea(contour, slice); + if( area0 != area1 ) + { + ts->printf(cvtest::TS::LOG, + "The contour area slice is computed differently (%g vs %g)\n", area0, area1 ); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + }*/ + + double len0 = cvArcLength(cslice, CV_WHOLE_SEQ, 1); + double len1 = cvArcLength(contour, slice, 1); + if( len0 != len1 ) + { + ts->printf(cvtest::TS::LOG, + "The contour arc length is computed differently (%g vs %g)\n", len0, len1 ); + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + } + ts->set_failed_test_info(cvtest::TS::OK); +} + + +TEST(Imgproc_ConvexHull, accuracy) { CV_ConvHullTest test; test.safe_run(); } +TEST(Imgproc_MinAreaRect, accuracy) { CV_MinAreaRectTest test; test.safe_run(); } +TEST(Imgproc_MinCircle, accuracy) { CV_MinCircleTest test; test.safe_run(); } +TEST(Imgproc_ContourPerimeter, accuracy) { CV_PerimeterTest test; test.safe_run(); } +TEST(Imgproc_FitEllipse, accuracy) { CV_FitEllipseTest test; test.safe_run(); } +TEST(Imgproc_FitLine, accuracy) { CV_FitLineTest test; test.safe_run(); } +TEST(Imgproc_ContourMoments, accuracy) { CV_ContourMomentsTest test; test.safe_run(); } +TEST(Imgproc_ContourPerimeterSlice, accuracy) { CV_PerimeterAreaSliceTest test; test.safe_run(); } +TEST(Imgproc_FitEllipse, small) { CV_FitEllipseSmallTest test; test.safe_run(); } + +/* End of file. */ + diff --git a/imgproc/test/test_cvtyuv.cpp b/imgproc/test/test_cvtyuv.cpp new file mode 100644 index 0000000..b790949 --- /dev/null +++ b/imgproc/test/test_cvtyuv.cpp @@ -0,0 +1,484 @@ +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +#undef RGB +#undef YUV + +typedef Vec3b YUV; +typedef Vec3b RGB; + +int countOfDifferencies(const Mat& gold, const Mat& result, int maxAllowedDifference = 1) +{ + Mat diff; + absdiff(gold, result, diff); + return countNonZero(diff.reshape(1) > maxAllowedDifference); +} + +class YUVreader +{ +public: + virtual ~YUVreader() {} + virtual YUV read(const Mat& yuv, int row, int col) = 0; + virtual int channels() = 0; + virtual Size size(Size imgSize) = 0; + + virtual bool requiresEvenHeight() { return true; } + virtual bool requiresEvenWidth() { return true; } + + static YUVreader* getReader(int code); +}; + +class RGBwriter +{ +public: + virtual ~RGBwriter() {} + + virtual void write(Mat& rgb, int row, int col, const RGB& val) = 0; + virtual int channels() = 0; + + static RGBwriter* getWriter(int code); +}; + +class GRAYwriter +{ +public: + virtual ~GRAYwriter() {} + + virtual void write(Mat& gray, int row, int col, const uchar& val) + { + gray.at(row, col) = val; + } + + virtual int channels() { return 1; } + + static GRAYwriter* getWriter(int code); +}; + +class RGB888Writer : public RGBwriter +{ + void write(Mat& rgb, int row, int col, const RGB& val) + { + rgb.at(row, col) = val; + } + + int channels() { return 3; } +}; + +class BGR888Writer : public RGBwriter +{ + void write(Mat& rgb, int row, int col, const RGB& val) + { + Vec3b tmp(val[2], val[1], val[0]); + rgb.at(row, col) = tmp; + } + + int channels() { return 3; } +}; + +class RGBA8888Writer : public RGBwriter +{ + void write(Mat& rgb, int row, int col, const RGB& val) + { + Vec4b tmp(val[0], val[1], val[2], 255); + rgb.at(row, col) = tmp; + } + + int channels() { return 4; } +}; + +class BGRA8888Writer : public RGBwriter +{ + void write(Mat& rgb, int row, int col, const RGB& val) + { + Vec4b tmp(val[2], val[1], val[0], 255); + rgb.at(row, col) = tmp; + } + + int channels() { return 4; } +}; + +class YUV420Reader: public YUVreader +{ + int channels() { return 1; } + Size size(Size imgSize) { return Size(imgSize.width, imgSize.height * 3 / 2); } +}; + +class YUV422Reader: public YUVreader +{ + int channels() { return 2; } + Size size(Size imgSize) { return imgSize; } + bool requiresEvenHeight() { return false; } +}; + +class NV21Reader: public YUV420Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + uchar y = yuv.ptr(row)[col]; + uchar u = yuv.ptr(yuv.rows * 2 / 3 + row/2)[(col/2)*2 + 1]; + uchar v = yuv.ptr(yuv.rows * 2 / 3 + row/2)[(col/2)*2]; + + return YUV(y, u, v); + } +}; + + +struct NV12Reader: public YUV420Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + uchar y = yuv.ptr(row)[col]; + uchar u = yuv.ptr(yuv.rows * 2 / 3 + row/2)[(col/2)*2]; + uchar v = yuv.ptr(yuv.rows * 2 / 3 + row/2)[(col/2)*2 + 1]; + + return YUV(y, u, v); + } +}; + +class YV12Reader: public YUV420Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + int h = yuv.rows * 2 / 3; + uchar y = yuv.ptr(row)[col]; + uchar u = yuv.ptr(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)]; + uchar v = yuv.ptr(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)]; + + return YUV(y, u, v); + } +}; + +class IYUVReader: public YUV420Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + int h = yuv.rows * 2 / 3; + uchar y = yuv.ptr(row)[col]; + uchar u = yuv.ptr(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)]; + uchar v = yuv.ptr(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)]; + + return YUV(y, u, v); + } +}; + +class UYVYReader: public YUV422Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + uchar y = yuv.ptr(row)[col][1]; + uchar u = yuv.ptr(row)[(col/2)*2][0]; + uchar v = yuv.ptr(row)[(col/2)*2 + 1][0]; + + return YUV(y, u, v); + } +}; + +class YUY2Reader: public YUV422Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + uchar y = yuv.ptr(row)[col][0]; + uchar u = yuv.ptr(row)[(col/2)*2][1]; + uchar v = yuv.ptr(row)[(col/2)*2 + 1][1]; + + return YUV(y, u, v); + } +}; + +class YVYUReader: public YUV422Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + uchar y = yuv.ptr(row)[col][0]; + uchar u = yuv.ptr(row)[(col/2)*2 + 1][1]; + uchar v = yuv.ptr(row)[(col/2)*2][1]; + + return YUV(y, u, v); + } +}; + +class YUV888Reader : public YUVreader +{ + YUV read(const Mat& yuv, int row, int col) + { + return yuv.at(row, col); + } + + int channels() { return 3; } + Size size(Size imgSize) { return imgSize; } + bool requiresEvenHeight() { return false; } + bool requiresEvenWidth() { return false; } +}; + +class YUV2RGB_Converter +{ +public: + RGB convert(YUV yuv) + { + int y = std::max(0, yuv[0] - 16); + int u = yuv[1] - 128; + int v = yuv[2] - 128; + uchar r = saturate_cast(1.164f * y + 1.596f * v); + uchar g = saturate_cast(1.164f * y - 0.813f * v - 0.391f * u); + uchar b = saturate_cast(1.164f * y + 2.018f * u); + + return RGB(r, g, b); + } +}; + +class YUV2GRAY_Converter +{ +public: + uchar convert(YUV yuv) + { + return yuv[0]; + } +}; + +YUVreader* YUVreader::getReader(int code) +{ + switch(code) + { + case CV_YUV2RGB_NV12: + case CV_YUV2BGR_NV12: + case CV_YUV2RGBA_NV12: + case CV_YUV2BGRA_NV12: + return new NV12Reader(); + case CV_YUV2RGB_NV21: + case CV_YUV2BGR_NV21: + case CV_YUV2RGBA_NV21: + case CV_YUV2BGRA_NV21: + return new NV21Reader(); + case CV_YUV2RGB_YV12: + case CV_YUV2BGR_YV12: + case CV_YUV2RGBA_YV12: + case CV_YUV2BGRA_YV12: + return new YV12Reader(); + case CV_YUV2RGB_IYUV: + case CV_YUV2BGR_IYUV: + case CV_YUV2RGBA_IYUV: + case CV_YUV2BGRA_IYUV: + return new IYUVReader(); + case CV_YUV2RGB_UYVY: + case CV_YUV2BGR_UYVY: + case CV_YUV2RGBA_UYVY: + case CV_YUV2BGRA_UYVY: + return new UYVYReader(); + //case CV_YUV2RGB_VYUY = 109, + //case CV_YUV2BGR_VYUY = 110, + //case CV_YUV2RGBA_VYUY = 113, + //case CV_YUV2BGRA_VYUY = 114, + // return ?? + case CV_YUV2RGB_YUY2: + case CV_YUV2BGR_YUY2: + case CV_YUV2RGBA_YUY2: + case CV_YUV2BGRA_YUY2: + return new YUY2Reader(); + case CV_YUV2RGB_YVYU: + case CV_YUV2BGR_YVYU: + case CV_YUV2RGBA_YVYU: + case CV_YUV2BGRA_YVYU: + return new YVYUReader(); + case CV_YUV2GRAY_420: + return new NV21Reader(); + case CV_YUV2GRAY_UYVY: + return new UYVYReader(); + case CV_YUV2GRAY_YUY2: + return new YUY2Reader(); + case CV_YUV2BGR: + case CV_YUV2RGB: + return new YUV888Reader(); + default: + return 0; + } +} + +RGBwriter* RGBwriter::getWriter(int code) +{ + switch(code) + { + case CV_YUV2RGB_NV12: + case CV_YUV2RGB_NV21: + case CV_YUV2RGB_YV12: + case CV_YUV2RGB_IYUV: + case CV_YUV2RGB_UYVY: + //case CV_YUV2RGB_VYUY: + case CV_YUV2RGB_YUY2: + case CV_YUV2RGB_YVYU: + case CV_YUV2RGB: + return new RGB888Writer(); + case CV_YUV2BGR_NV12: + case CV_YUV2BGR_NV21: + case CV_YUV2BGR_YV12: + case CV_YUV2BGR_IYUV: + case CV_YUV2BGR_UYVY: + //case CV_YUV2BGR_VYUY: + case CV_YUV2BGR_YUY2: + case CV_YUV2BGR_YVYU: + case CV_YUV2BGR: + return new BGR888Writer(); + case CV_YUV2RGBA_NV12: + case CV_YUV2RGBA_NV21: + case CV_YUV2RGBA_YV12: + case CV_YUV2RGBA_IYUV: + case CV_YUV2RGBA_UYVY: + //case CV_YUV2RGBA_VYUY: + case CV_YUV2RGBA_YUY2: + case CV_YUV2RGBA_YVYU: + return new RGBA8888Writer(); + case CV_YUV2BGRA_NV12: + case CV_YUV2BGRA_NV21: + case CV_YUV2BGRA_YV12: + case CV_YUV2BGRA_IYUV: + case CV_YUV2BGRA_UYVY: + //case CV_YUV2BGRA_VYUY: + case CV_YUV2BGRA_YUY2: + case CV_YUV2BGRA_YVYU: + return new BGRA8888Writer(); + default: + return 0; + }; +} + +GRAYwriter* GRAYwriter::getWriter(int code) +{ + switch(code) + { + case CV_YUV2GRAY_420: + case CV_YUV2GRAY_UYVY: + case CV_YUV2GRAY_YUY2: + return new GRAYwriter(); + default: + return 0; + } +} + +template +void referenceYUV2RGB(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, RGBwriter* rgbWriter) +{ + convertor cvt; + + for(int row = 0; row < rgb.rows; ++row) + for(int col = 0; col < rgb.cols; ++col) + rgbWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col))); +} + +template +void referenceYUV2GRAY(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, GRAYwriter* grayWriter) +{ + convertor cvt; + + for(int row = 0; row < rgb.rows; ++row) + for(int col = 0; col < rgb.cols; ++col) + grayWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col))); +} + +CV_ENUM(YUVCVTS, CV_YUV2RGB_NV12, CV_YUV2BGR_NV12, CV_YUV2RGB_NV21, CV_YUV2BGR_NV21, + CV_YUV2RGBA_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGBA_NV21, CV_YUV2BGRA_NV21, + CV_YUV2RGB_YV12, CV_YUV2BGR_YV12, CV_YUV2RGB_IYUV, CV_YUV2BGR_IYUV, + CV_YUV2RGBA_YV12, CV_YUV2BGRA_YV12, CV_YUV2RGBA_IYUV, CV_YUV2BGRA_IYUV, + CV_YUV2RGB_UYVY, CV_YUV2BGR_UYVY, CV_YUV2RGBA_UYVY, CV_YUV2BGRA_UYVY, + CV_YUV2RGB_YUY2, CV_YUV2BGR_YUY2, CV_YUV2RGB_YVYU, CV_YUV2BGR_YVYU, + CV_YUV2RGBA_YUY2, CV_YUV2BGRA_YUY2, CV_YUV2RGBA_YVYU, CV_YUV2BGRA_YVYU, + CV_YUV2GRAY_420, CV_YUV2GRAY_UYVY, CV_YUV2GRAY_YUY2, + CV_YUV2BGR, CV_YUV2RGB); + +typedef ::testing::TestWithParam Imgproc_ColorYUV; + +TEST_P(Imgproc_ColorYUV, accuracy) +{ + int code = GetParam(); + RNG& random = theRNG(); + + YUVreader* yuvReader = YUVreader::getReader(code); + RGBwriter* rgbWriter = RGBwriter::getWriter(code); + GRAYwriter* grayWriter = GRAYwriter::getWriter(code); + + int dcn = (rgbWriter == 0) ? grayWriter->channels() : rgbWriter->channels(); + + for(int iter = 0; iter < 30; ++iter) + { + Size sz(random.uniform(1, 641), random.uniform(1, 481)); + + if(yuvReader->requiresEvenWidth()) sz.width += sz.width % 2; + if(yuvReader->requiresEvenHeight()) sz.height += sz.height % 2; + + Size ysz = yuvReader->size(sz); + Mat src = Mat(ysz.height, ysz.width * yuvReader->channels(), CV_8UC1).reshape(yuvReader->channels()); + + Mat dst = Mat(sz.height, sz.width * dcn, CV_8UC1).reshape(dcn); + Mat gold(sz, CV_8UC(dcn)); + + random.fill(src, RNG::UNIFORM, 0, 256); + + if(rgbWriter) + referenceYUV2RGB(src, gold, yuvReader, rgbWriter); + else + referenceYUV2GRAY(src, gold, yuvReader, grayWriter); + + cv::cvtColor(src, dst, code, -1); + + EXPECT_EQ(0, countOfDifferencies(gold, dst)); + } +} + +TEST_P(Imgproc_ColorYUV, roi_accuracy) +{ + int code = GetParam(); + RNG& random = theRNG(); + + YUVreader* yuvReader = YUVreader::getReader(code); + RGBwriter* rgbWriter = RGBwriter::getWriter(code); + GRAYwriter* grayWriter = GRAYwriter::getWriter(code); + + int dcn = (rgbWriter == 0) ? grayWriter->channels() : rgbWriter->channels(); + + for(int iter = 0; iter < 30; ++iter) + { + Size sz(random.uniform(1, 641), random.uniform(1, 481)); + + if(yuvReader->requiresEvenWidth()) sz.width += sz.width % 2; + if(yuvReader->requiresEvenHeight()) sz.height += sz.height % 2; + + int roi_offset_top = random.uniform(0, 6); + int roi_offset_bottom = random.uniform(0, 6); + int roi_offset_left = random.uniform(0, 6); + int roi_offset_right = random.uniform(0, 6); + + Size ysz = yuvReader->size(sz); + + Mat src_full(ysz.height + roi_offset_top + roi_offset_bottom, ysz.width + roi_offset_left + roi_offset_right, CV_8UC(yuvReader->channels())); + Mat dst_full(sz.height + roi_offset_left + roi_offset_right, sz.width + roi_offset_top + roi_offset_bottom, CV_8UC(dcn), Scalar::all(0)); + Mat gold_full(dst_full.size(), CV_8UC(dcn), Scalar::all(0)); + + random.fill(src_full, RNG::UNIFORM, 0, 256); + + Mat src = src_full(Range(roi_offset_top, roi_offset_top + ysz.height), Range(roi_offset_left, roi_offset_left + ysz.width)); + Mat dst = dst_full(Range(roi_offset_left, roi_offset_left + sz.height), Range(roi_offset_top, roi_offset_top + sz.width)); + Mat gold = gold_full(Range(roi_offset_left, roi_offset_left + sz.height), Range(roi_offset_top, roi_offset_top + sz.width)); + + if(rgbWriter) + referenceYUV2RGB(src, gold, yuvReader, rgbWriter); + else + referenceYUV2GRAY(src, gold, yuvReader, grayWriter); + + cv::cvtColor(src, dst, code, -1); + + EXPECT_EQ(0, countOfDifferencies(gold_full, dst_full)); + } +} + +INSTANTIATE_TEST_CASE_P(cvt420, Imgproc_ColorYUV, + ::testing::Values((int)CV_YUV2RGB_NV12, (int)CV_YUV2BGR_NV12, (int)CV_YUV2RGB_NV21, (int)CV_YUV2BGR_NV21, + (int)CV_YUV2RGBA_NV12, (int)CV_YUV2BGRA_NV12, (int)CV_YUV2RGBA_NV21, (int)CV_YUV2BGRA_NV21, + (int)CV_YUV2RGB_YV12, (int)CV_YUV2BGR_YV12, (int)CV_YUV2RGB_IYUV, (int)CV_YUV2BGR_IYUV, + (int)CV_YUV2RGBA_YV12, (int)CV_YUV2BGRA_YV12, (int)CV_YUV2RGBA_IYUV, (int)CV_YUV2BGRA_IYUV, + (int)CV_YUV2GRAY_420)); + +INSTANTIATE_TEST_CASE_P(cvt422, Imgproc_ColorYUV, + ::testing::Values((int)CV_YUV2RGB_UYVY, (int)CV_YUV2BGR_UYVY, (int)CV_YUV2RGBA_UYVY, (int)CV_YUV2BGRA_UYVY, + (int)CV_YUV2RGB_YUY2, (int)CV_YUV2BGR_YUY2, (int)CV_YUV2RGB_YVYU, (int)CV_YUV2BGR_YVYU, + (int)CV_YUV2RGBA_YUY2, (int)CV_YUV2BGRA_YUY2, (int)CV_YUV2RGBA_YVYU, (int)CV_YUV2BGRA_YVYU, + (int)CV_YUV2GRAY_UYVY, (int)CV_YUV2GRAY_YUY2)); diff --git a/imgproc/test/test_distancetransform.cpp b/imgproc/test/test_distancetransform.cpp new file mode 100644 index 0000000..bdf205b --- /dev/null +++ b/imgproc/test/test_distancetransform.cpp @@ -0,0 +1,297 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +class CV_DisTransTest : public cvtest::ArrayTest +{ +public: + CV_DisTransTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void run_func(); + void prepare_to_validation( int ); + + void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ); + int prepare_test_case( int test_case_idx ); + + int mask_size; + int dist_type; + int fill_labels; + float mask[3]; +}; + + +CV_DisTransTest::CV_DisTransTest() +{ + test_array[INPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + optional_mask = false; + element_wise_relative_error = true; +} + + +void CV_DisTransTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + types[INPUT][0] = CV_8UC1; + types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_32FC1; + types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_32SC1; + + if( cvtest::randInt(rng) & 1 ) + { + mask_size = 3; + dist_type = cvtest::randInt(rng) % 4; + dist_type = dist_type == 0 ? CV_DIST_C : dist_type == 1 ? CV_DIST_L1 : + dist_type == 2 ? CV_DIST_L2 : CV_DIST_USER; + } + else + { + mask_size = 5; + dist_type = cvtest::randInt(rng) % 10; + dist_type = dist_type == 0 ? CV_DIST_C : dist_type == 1 ? CV_DIST_L1 : + dist_type < 6 ? CV_DIST_L2 : CV_DIST_USER; + } + + // for now, check only the "labeled" distance transform mode + fill_labels = 0; + + if( !fill_labels ) + sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = cvSize(0,0); + + if( dist_type == CV_DIST_USER ) + { + mask[0] = (float)(1.1 - cvtest::randReal(rng)*0.2); + mask[1] = (float)(1.9 - cvtest::randReal(rng)*0.8); + mask[2] = (float)(3. - cvtest::randReal(rng)); + } +} + + +double CV_DisTransTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + Size sz = test_mat[INPUT][0].size(); + return dist_type == CV_DIST_C || dist_type == CV_DIST_L1 ? 0 : 0.01*MAX(sz.width, sz.height); +} + + +void CV_DisTransTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ) +{ + cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high ); + if( i == INPUT && CV_MAT_DEPTH(type) == CV_8U ) + { + low = Scalar::all(0); + high = Scalar::all(10); + } +} + +int CV_DisTransTest::prepare_test_case( int test_case_idx ) +{ + int code = cvtest::ArrayTest::prepare_test_case( test_case_idx ); + if( code > 0 ) + { + // the function's response to an "all-nonzeros" image is not determined, + // so put at least one zero point + Mat& mat = test_mat[INPUT][0]; + RNG& rng = ts->get_rng(); + int i = cvtest::randInt(rng) % mat.rows; + int j = cvtest::randInt(rng) % mat.cols; + mat.at(i,j) = 0; + } + + return code; +} + + +void CV_DisTransTest::run_func() +{ + cvDistTransform( test_array[INPUT][0], test_array[OUTPUT][0], dist_type, mask_size, + dist_type == CV_DIST_USER ? mask : 0, test_array[OUTPUT][1] ); +} + + +static void +cvTsDistTransform( const CvMat* _src, CvMat* _dst, int dist_type, + int mask_size, float* _mask, CvMat* /*_labels*/ ) +{ + int i, j, k; + int width = _src->cols, height = _src->rows; + const float init_val = 1e6; + float mask[3]; + CvMat* temp; + int ofs[16]; + float delta[16]; + int tstep, count; + + assert( mask_size == 3 || mask_size == 5 ); + + if( dist_type == CV_DIST_USER ) + memcpy( mask, _mask, sizeof(mask) ); + else if( dist_type == CV_DIST_C ) + { + mask_size = 3; + mask[0] = mask[1] = 1.f; + } + else if( dist_type == CV_DIST_L1 ) + { + mask_size = 3; + mask[0] = 1.f; + mask[1] = 2.f; + } + else if( mask_size == 3 ) + { + mask[0] = 0.955f; + mask[1] = 1.3693f; + } + else + { + mask[0] = 1.0f; + mask[1] = 1.4f; + mask[2] = 2.1969f; + } + + temp = cvCreateMat( height + mask_size-1, width + mask_size-1, CV_32F ); + tstep = temp->step / sizeof(float); + + if( mask_size == 3 ) + { + count = 4; + ofs[0] = -1; delta[0] = mask[0]; + ofs[1] = -tstep-1; delta[1] = mask[1]; + ofs[2] = -tstep; delta[2] = mask[0]; + ofs[3] = -tstep+1; delta[3] = mask[1]; + } + else + { + count = 8; + ofs[0] = -1; delta[0] = mask[0]; + ofs[1] = -tstep-2; delta[1] = mask[2]; + ofs[2] = -tstep-1; delta[2] = mask[1]; + ofs[3] = -tstep; delta[3] = mask[0]; + ofs[4] = -tstep+1; delta[4] = mask[1]; + ofs[5] = -tstep+2; delta[5] = mask[2]; + ofs[6] = -tstep*2-1; delta[6] = mask[2]; + ofs[7] = -tstep*2+1; delta[7] = mask[2]; + } + + for( i = 0; i < mask_size/2; i++ ) + { + float* t0 = (float*)(temp->data.ptr + i*temp->step); + float* t1 = (float*)(temp->data.ptr + (temp->rows - i - 1)*temp->step); + + for( j = 0; j < width + mask_size - 1; j++ ) + t0[j] = t1[j] = init_val; + } + + for( i = 0; i < height; i++ ) + { + uchar* s = _src->data.ptr + i*_src->step; + float* tmp = (float*)(temp->data.ptr + temp->step*(i + (mask_size/2))) + (mask_size/2); + + for( j = 0; j < mask_size/2; j++ ) + tmp[-j-1] = tmp[j + width] = init_val; + + for( j = 0; j < width; j++ ) + { + if( s[j] == 0 ) + tmp[j] = 0; + else + { + float min_dist = init_val; + for( k = 0; k < count; k++ ) + { + float t = tmp[j+ofs[k]] + delta[k]; + if( min_dist > t ) + min_dist = t; + } + tmp[j] = min_dist; + } + } + } + + for( i = height - 1; i >= 0; i-- ) + { + float* d = (float*)(_dst->data.ptr + i*_dst->step); + float* tmp = (float*)(temp->data.ptr + temp->step*(i + (mask_size/2))) + (mask_size/2); + + for( j = width - 1; j >= 0; j-- ) + { + float min_dist = tmp[j]; + if( min_dist > mask[0] ) + { + for( k = 0; k < count; k++ ) + { + float t = tmp[j-ofs[k]] + delta[k]; + if( min_dist > t ) + min_dist = t; + } + tmp[j] = min_dist; + } + d[j] = min_dist; + } + } + + cvReleaseMat( &temp ); +} + + +void CV_DisTransTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + CvMat _input = test_mat[INPUT][0], _output = test_mat[REF_OUTPUT][0]; + + cvTsDistTransform( &_input, &_output, dist_type, mask_size, mask, 0 ); +} + + +TEST(Imgproc_DistanceTransform, accuracy) { CV_DisTransTest test; test.safe_run(); } + + diff --git a/imgproc/test/test_emd.cpp b/imgproc/test/test_emd.cpp new file mode 100644 index 0000000..1880bb3 --- /dev/null +++ b/imgproc/test/test_emd.cpp @@ -0,0 +1,95 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +/*////////////////////// emd_test /////////////////////////*/ + +class CV_EMDTest : public cvtest::BaseTest +{ +public: + CV_EMDTest(); +protected: + void run(int); +}; + + +CV_EMDTest::CV_EMDTest() +{ +} + +void CV_EMDTest::run( int ) +{ + int code = cvtest::TS::OK; + const double success_error_level = 1e-6; + #define M 10000 + double emd0 = 2460./210; + static float cost[] = + { + 16, 16, 13, 22, 17, + 14, 14, 13, 19, 15, + 19, 19, 20, 23, M, + M , 0, M, 0, 0 + }; + static float w1[] = { 50, 60, 50, 50 }, + w2[] = { 30, 20, 70, 30, 60 }; + Mat _w1(4, 1, CV_32F, w1); + Mat _w2(5, 1, CV_32F, w2); + Mat _cost(_w1.rows, _w2.rows, CV_32F, cost); + + float emd = EMD( _w1, _w2, -1, _cost ); + if( fabs( emd - emd0 ) > success_error_level*emd0 ) + { + ts->printf( cvtest::TS::LOG, + "The computed distance is %.2f, while it should be %.2f\n", emd, emd0 ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + } + + if( code < 0 ) + ts->set_failed_test_info( code ); +} + +TEST(Imgproc_EMD, regression) { CV_EMDTest test; test.safe_run(); } + +/* End of file. */ diff --git a/imgproc/test/test_filter.cpp b/imgproc/test/test_filter.cpp new file mode 100644 index 0000000..0260bdf --- /dev/null +++ b/imgproc/test/test_filter.cpp @@ -0,0 +1,1881 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +class CV_FilterBaseTest : public cvtest::ArrayTest +{ +public: + CV_FilterBaseTest( bool _fp_kernel ); + +protected: + int prepare_test_case( int test_case_idx ); + int read_params( CvFileStorage* fs ); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ); + CvSize aperture_size; + CvPoint anchor; + int max_aperture_size; + bool fp_kernel; + bool inplace; + int border; +}; + + +CV_FilterBaseTest::CV_FilterBaseTest( bool _fp_kernel ) : fp_kernel(_fp_kernel) +{ + test_array[INPUT].push_back(NULL); + test_array[INPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + max_aperture_size = 13; + inplace = false; + aperture_size = cvSize(0,0); + anchor = cvPoint(0,0); + element_wise_relative_error = false; +} + + +int CV_FilterBaseTest::read_params( CvFileStorage* fs ) +{ + int code = cvtest::ArrayTest::read_params( fs ); + if( code < 0 ) + return code; + + max_aperture_size = cvReadInt( find_param( fs, "max_aperture_size" ), max_aperture_size ); + max_aperture_size = cvtest::clipInt( max_aperture_size, 1, 100 ); + + return code; +} + + +void CV_FilterBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ) +{ + cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high ); + if( i == INPUT ) + { + if( j == 1 ) + { + if( fp_kernel ) + { + RNG& rng = ts->get_rng(); + double val = exp( cvtest::randReal(rng)*10 - 4 ); + low = Scalar::all(-val); + high = Scalar::all(val); + } + else + { + low = Scalar::all(0); + high = Scalar::all(2); + } + } + else if( CV_MAT_DEPTH(type) == CV_32F ) + { + low = Scalar::all(-10.); + high = Scalar::all(10.); + } + } +} + + +void CV_FilterBaseTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, + vector >& types ) +{ + RNG& rng = ts->get_rng(); + int depth = cvtest::randInt(rng) % CV_32F; + int cn = cvtest::randInt(rng) % 3 + 1; + cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + depth += depth == CV_8S; + cn += cn == 2; + + types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn); + + aperture_size.width = cvtest::randInt(rng) % max_aperture_size + 1; + aperture_size.height = cvtest::randInt(rng) % max_aperture_size + 1; + anchor.x = cvtest::randInt(rng) % aperture_size.width; + anchor.y = cvtest::randInt(rng) % aperture_size.height; + + types[INPUT][1] = fp_kernel ? CV_32FC1 : CV_8UC1; + sizes[INPUT][1] = aperture_size; + + inplace = cvtest::randInt(rng) % 2 != 0; + border = BORDER_REPLICATE; +} + + +int CV_FilterBaseTest::prepare_test_case( int test_case_idx ) +{ + int code = cvtest::ArrayTest::prepare_test_case( test_case_idx ); + if( code > 0 ) + { + if( inplace && test_mat[INPUT][0].type() == test_mat[OUTPUT][0].type()) + cvtest::copy( test_mat[INPUT][0], test_mat[OUTPUT][0] ); + else + inplace = false; + } + return code; +} + + +///////////////////////// + +class CV_MorphologyBaseTest : public CV_FilterBaseTest +{ +public: + CV_MorphologyBaseTest(); + +protected: + void prepare_to_validation( int test_case_idx ); + int prepare_test_case( int test_case_idx ); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + int optype, optype_min, optype_max; + int shape; + IplConvKernel* element; +}; + + +CV_MorphologyBaseTest::CV_MorphologyBaseTest() : CV_FilterBaseTest( false ) +{ + shape = -1; + element = 0; + optype = optype_min = optype_max = -1; +} + + +void CV_MorphologyBaseTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int depth = cvtest::randInt(rng) % 4; + depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : depth == 2 ? CV_16S : CV_32F; + int cn = CV_MAT_CN(types[INPUT][0]); + + types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn); + shape = cvtest::randInt(rng) % 4; + if( shape >= 3 ) + shape = CV_SHAPE_CUSTOM; + else + sizes[INPUT][1] = cvSize(0,0); + optype = cvtest::randInt(rng) % (optype_max - optype_min + 1) + optype_min; +} + + +double CV_MorphologyBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + return test_mat[INPUT][0].depth() < CV_32F || + (optype == CV_MOP_ERODE || optype == CV_MOP_DILATE || + optype == CV_MOP_OPEN || optype == CV_MOP_CLOSE) ? 0 : 1e-5; +} + + +int CV_MorphologyBaseTest::prepare_test_case( int test_case_idx ) +{ + int code = CV_FilterBaseTest::prepare_test_case( test_case_idx ); + vector eldata; + + if( code <= 0 ) + return code; + + if( shape == CV_SHAPE_CUSTOM ) + { + eldata.resize(aperture_size.width*aperture_size.height); + uchar* src = test_mat[INPUT][1].data; + int srcstep = (int)test_mat[INPUT][1].step; + int i, j, nonzero = 0; + + for( i = 0; i < aperture_size.height; i++ ) + { + for( j = 0; j < aperture_size.width; j++ ) + { + eldata[i*aperture_size.width + j] = src[i*srcstep + j]; + nonzero += src[i*srcstep + j] != 0; + } + } + + if( nonzero == 0 ) + eldata[anchor.y*aperture_size.width + anchor.x] = 1; + } + + cvReleaseStructuringElement( &element ); + element = cvCreateStructuringElementEx( aperture_size.width, aperture_size.height, + anchor.x, anchor.y, shape, eldata.empty() ? 0 : &eldata[0] ); + return code; +} + + +void CV_MorphologyBaseTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat& src = test_mat[INPUT][0], &dst = test_mat[REF_OUTPUT][0]; + Mat _ielement(element->nRows, element->nCols, CV_32S, element->values); + Mat _element; + _ielement.convertTo(_element, CV_8U); + Point _anchor(element->anchorX, element->anchorY); + int _border = BORDER_REPLICATE; + + if( optype == CV_MOP_ERODE ) + { + cvtest::erode( src, dst, _element, _anchor, _border ); + } + else if( optype == CV_MOP_DILATE ) + { + cvtest::dilate( src, dst, _element, _anchor, _border ); + } + else + { + Mat temp; + if( optype == CV_MOP_OPEN ) + { + cvtest::erode( src, temp, _element, _anchor, _border ); + cvtest::dilate( temp, dst, _element, _anchor, _border ); + } + else if( optype == CV_MOP_CLOSE ) + { + cvtest::dilate( src, temp, _element, _anchor, _border ); + cvtest::erode( temp, dst, _element, _anchor, _border ); + } + else if( optype == CV_MOP_GRADIENT ) + { + cvtest::erode( src, temp, _element, _anchor, _border ); + cvtest::dilate( src, dst, _element, _anchor, _border ); + cvtest::add( dst, 1, temp, -1, Scalar::all(0), dst, dst.type() ); + } + else if( optype == CV_MOP_TOPHAT ) + { + cvtest::erode( src, temp, _element, _anchor, _border ); + cvtest::dilate( temp, dst, _element, _anchor, _border ); + cvtest::add( src, 1, dst, -1, Scalar::all(0), dst, dst.type() ); + } + else if( optype == CV_MOP_BLACKHAT ) + { + cvtest::dilate( src, temp, _element, _anchor, _border ); + cvtest::erode( temp, dst, _element, _anchor, _border ); + cvtest::add( dst, 1, src, -1, Scalar::all(0), dst, dst.type() ); + } + else + CV_Error( CV_StsBadArg, "Unknown operation" ); + } + + cvReleaseStructuringElement( &element ); +} + + +/////////////// erode /////////////// + +class CV_ErodeTest : public CV_MorphologyBaseTest +{ +public: + CV_ErodeTest(); +protected: + void run_func(); +}; + + +CV_ErodeTest::CV_ErodeTest() +{ + optype_min = optype_max = CV_MOP_ERODE; +} + + +void CV_ErodeTest::run_func() +{ + cvErode( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0], + test_array[OUTPUT][0], element, 1 ); +} + + +/////////////// dilate /////////////// + +class CV_DilateTest : public CV_MorphologyBaseTest +{ +public: + CV_DilateTest(); +protected: + void run_func(); +}; + + +CV_DilateTest::CV_DilateTest() +{ + optype_min = optype_max = CV_MOP_DILATE; +} + + +void CV_DilateTest::run_func() +{ + cvDilate( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0], + test_array[OUTPUT][0], element, 1 ); +} + +/////////////// morphEx /////////////// + +class CV_MorphExTest : public CV_MorphologyBaseTest +{ +public: + CV_MorphExTest(); +protected: + void run_func(); +}; + + +CV_MorphExTest::CV_MorphExTest() +{ + optype_min = CV_MOP_ERODE; + optype_max = CV_MOP_BLACKHAT; +} + + +void CV_MorphExTest::run_func() +{ + cvMorphologyEx( test_array[inplace ? OUTPUT : INPUT][0], + test_array[OUTPUT][0], 0, element, optype, 1 ); +} + +/////////////// generic filter /////////////// + +class CV_FilterTest : public CV_FilterBaseTest +{ +public: + CV_FilterTest(); + +protected: + void prepare_to_validation( int test_case_idx ); + void run_func(); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); +}; + + +CV_FilterTest::CV_FilterTest() : CV_FilterBaseTest( true ) +{ +} + + +void CV_FilterTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + RNG& rng = ts->get_rng(); + int depth = cvtest::randInt(rng)%3; + int cn = CV_MAT_CN(types[INPUT][0]); + depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : CV_32F; + types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn); +} + + +double CV_FilterTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth <= CV_8S ? 2 : depth <= CV_32S ? 32 : + depth == CV_32F ? 1e-4 : 1e-10; +} + + +void CV_FilterTest::run_func() +{ + CvMat kernel = test_mat[INPUT][1]; + cvFilter2D( test_array[inplace ? OUTPUT : INPUT][0], + test_array[OUTPUT][0], &kernel, anchor ); +} + + +void CV_FilterTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].type(), + test_mat[INPUT][1], anchor, 0, BORDER_REPLICATE ); +} + + +//////////////////////// + +class CV_DerivBaseTest : public CV_FilterBaseTest +{ +public: + CV_DerivBaseTest(); +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + int _aperture_size; +}; + + +CV_DerivBaseTest::CV_DerivBaseTest() : CV_FilterBaseTest( true ) +{ + max_aperture_size = 7; +} + + +void CV_DerivBaseTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int depth = cvtest::randInt(rng) % 2; + depth = depth == 0 ? CV_8U : CV_32F; + types[INPUT][0] = CV_MAKETYPE(depth,1); + types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth==CV_8U?CV_16S:CV_32F,1); + _aperture_size = (cvtest::randInt(rng)%5)*2 - 1; + sizes[INPUT][1] = aperture_size = cvSize(_aperture_size, _aperture_size); +} + + +double CV_DerivBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth <= CV_8S ? 2 : 5e-4; +} + + +/////////////// sobel /////////////// + +class CV_SobelTest : public CV_DerivBaseTest +{ +public: + CV_SobelTest(); + +protected: + void prepare_to_validation( int test_case_idx ); + void run_func(); + void get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ); + int dx, dy, origin; +}; + + +CV_SobelTest::CV_SobelTest() {} + + +void CV_SobelTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, + vector >& types ) +{ + RNG& rng = ts->get_rng(); + CV_DerivBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int max_d = _aperture_size > 0 ? 2 : 1; + origin = cvtest::randInt(rng) % 2; + dx = cvtest::randInt(rng) % (max_d + 1); + dy = cvtest::randInt(rng) % (max_d + 1 - dx); + if( dx == 0 && dy == 0 ) + dx = 1; + if( cvtest::randInt(rng) % 2 ) + { + int t; + CV_SWAP( dx, dy, t ); + } + + if( _aperture_size < 0 ) + aperture_size = cvSize(3, 3); + else if( _aperture_size == 1 ) + { + if( dx == 0 ) + aperture_size = cvSize(1, 3); + else if( dy == 0 ) + aperture_size = cvSize(3, 1); + else + { + _aperture_size = 3; + aperture_size = cvSize(3, 3); + } + } + else + aperture_size = cvSize(_aperture_size, _aperture_size); + + sizes[INPUT][1] = aperture_size; + anchor.x = aperture_size.width / 2; + anchor.y = aperture_size.height / 2; +} + + +void CV_SobelTest::run_func() +{ + cvSobel( test_array[inplace ? OUTPUT : INPUT][0], + test_array[OUTPUT][0], dx, dy, _aperture_size ); + /*cv::Sobel( test_mat[inplace ? OUTPUT : INPUT][0], + test_mat[OUTPUT][0], test_mat[OUTPUT][0].depth(), + dx, dy, _aperture_size, 1, 0, border );*/ +} + + +void CV_SobelTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat kernel = cvtest::calcSobelKernel2D( dx, dy, _aperture_size, 0 ); + cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].depth(), + kernel, anchor, 0, BORDER_REPLICATE); +} + + +/////////////// laplace /////////////// + +class CV_LaplaceTest : public CV_DerivBaseTest +{ +public: + CV_LaplaceTest(); + +protected: + int prepare_test_case( int test_case_idx ); + void prepare_to_validation( int test_case_idx ); + void run_func(); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); +}; + + +CV_LaplaceTest::CV_LaplaceTest() +{ +} + + +void CV_LaplaceTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + CV_DerivBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + if( _aperture_size <= 1 ) + { + if( _aperture_size < 0 ) + _aperture_size = 1; + aperture_size = cvSize(3, 3); + } + else + aperture_size = cvSize(_aperture_size, _aperture_size); + + sizes[INPUT][1] = aperture_size; + anchor.x = aperture_size.width / 2; + anchor.y = aperture_size.height / 2; +} + + +void CV_LaplaceTest::run_func() +{ + cvLaplace( test_array[inplace ? OUTPUT : INPUT][0], + test_array[OUTPUT][0], _aperture_size ); +} + + +int CV_LaplaceTest::prepare_test_case( int test_case_idx ) +{ + int code = CV_DerivBaseTest::prepare_test_case( test_case_idx ); + return _aperture_size < 0 ? 0 : code; +} + + +void CV_LaplaceTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat kernel = cvtest::calcLaplaceKernel2D( _aperture_size ); + cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].depth(), + kernel, anchor, 0, BORDER_REPLICATE ); +} + + +//////////////////////////////////////////////////////////// + +class CV_SmoothBaseTest : public CV_FilterBaseTest +{ +public: + CV_SmoothBaseTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + const char* smooth_type; +}; + + +CV_SmoothBaseTest::CV_SmoothBaseTest() : CV_FilterBaseTest( true ) +{ + smooth_type = ""; +} + + +void CV_SmoothBaseTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int depth = cvtest::randInt(rng) % 2; + int cn = CV_MAT_CN(types[INPUT][0]); + depth = depth == 0 ? CV_8U : CV_32F; + types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth,cn); + anchor.x = cvtest::randInt(rng)%(max_aperture_size/2+1); + anchor.y = cvtest::randInt(rng)%(max_aperture_size/2+1); + aperture_size.width = anchor.x*2 + 1; + aperture_size.height = anchor.y*2 + 1; + sizes[INPUT][1] = aperture_size; +} + + +double CV_SmoothBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth <= CV_8S ? 1 : 1e-5; +} + + +/////////////// blur /////////////// + +class CV_BlurTest : public CV_SmoothBaseTest +{ +public: + CV_BlurTest(); + +protected: + int prepare_test_case( int test_case_idx ); + void prepare_to_validation( int test_case_idx ); + void run_func(); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + bool normalize; +}; + + +CV_BlurTest::CV_BlurTest() +{ +} + + +void CV_BlurTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + CV_SmoothBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + normalize = cvtest::randInt(rng) % 2 != 0; + if( !normalize ) + { + int depth = CV_MAT_DEPTH(types[INPUT][0]); + types[INPUT][0] = CV_MAKETYPE(depth, 1); + types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth==CV_8U?CV_16S:CV_32F,1); + } +} + + +void CV_BlurTest::run_func() +{ + cvSmooth( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0], + test_array[OUTPUT][0], normalize ? CV_BLUR : CV_BLUR_NO_SCALE, + aperture_size.width, aperture_size.height ); +} + + +int CV_BlurTest::prepare_test_case( int test_case_idx ) +{ + int code = CV_SmoothBaseTest::prepare_test_case( test_case_idx ); + return code > 0 && !normalize && test_mat[INPUT][0].channels() > 1 ? 0 : code; +} + + +void CV_BlurTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat kernel(aperture_size, CV_64F); + kernel.setTo(Scalar::all(normalize ? 1./(aperture_size.width*aperture_size.height) : 1.)); + cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].depth(), + kernel, anchor, 0, BORDER_REPLICATE ); +} + + +/////////////// gaussian /////////////// + +class CV_GaussianBlurTest : public CV_SmoothBaseTest +{ +public: + CV_GaussianBlurTest(); + +protected: + void prepare_to_validation( int test_case_idx ); + void run_func(); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ); + double sigma; + int param1, param2; +}; + + +CV_GaussianBlurTest::CV_GaussianBlurTest() : CV_SmoothBaseTest() +{ + sigma = 0.; + smooth_type = "Gaussian"; +} + + +double CV_GaussianBlurTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth <= CV_8S ? 8 : 1e-5; +} + + +void CV_GaussianBlurTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + int kernel_case = cvtest::randInt(rng) % 2; + CV_SmoothBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + anchor = cvPoint(aperture_size.width/2,aperture_size.height/2); + + sigma = exp(cvtest::randReal(rng)*5-2); + param1 = aperture_size.width; + param2 = aperture_size.height; + + if( kernel_case == 0 ) + sigma = 0.; +} + +void CV_GaussianBlurTest::run_func() +{ + cvSmooth( test_array[inplace ? OUTPUT : INPUT][0], + test_array[OUTPUT][0], CV_GAUSSIAN, + param1, param2, sigma, sigma ); +} + + +// !!! Copied from cvSmooth, if the code is changed in cvSmooth, +// make sure to update this one too. +#define SMALL_GAUSSIAN_SIZE 7 +static void +calcGaussianKernel( int n, double sigma, vector& kernel ) +{ + static const float small_gaussian_tab[][SMALL_GAUSSIAN_SIZE] = + { + {1.f}, + {0.25f, 0.5f, 0.25f}, + {0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f}, + {0.03125, 0.109375, 0.21875, 0.28125, 0.21875, 0.109375, 0.03125} + }; + + kernel.resize(n); + if( n <= SMALL_GAUSSIAN_SIZE && sigma <= 0 ) + { + assert( n%2 == 1 ); + memcpy( &kernel[0], small_gaussian_tab[n>>1], n*sizeof(kernel[0])); + } + else + { + double sigmaX = sigma > 0 ? sigma : (n/2 - 1)*0.3 + 0.8; + double scale2X = -0.5/(sigmaX*sigmaX); + double sum = 1.; + int i; + sum = kernel[n/2] = 1.f; + + for( i = 1; i <= n/2; i++ ) + { + kernel[n/2+i] = kernel[n/2-i] = (float)exp(scale2X*i*i); + sum += kernel[n/2+i]*2; + } + + sum = 1./sum; + for( i = 0; i <= n/2; i++ ) + kernel[n/2+i] = kernel[n/2-i] = (float)(kernel[n/2+i]*sum); + } +} + + +static Mat calcGaussianKernel2D( Size ksize, double sigma ) +{ + vector kx, ky; + Mat kernel(ksize, CV_32F); + + calcGaussianKernel( kernel.cols, sigma, kx ); + calcGaussianKernel( kernel.rows, sigma, ky ); + + for( int i = 0; i < kernel.rows; i++ ) + for( int j = 0; j < kernel.cols; j++ ) + kernel.at(i, j) = kx[j]*ky[i]; + return kernel; +} + + +void CV_GaussianBlurTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat kernel = calcGaussianKernel2D( aperture_size, sigma ); + cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].depth(), + kernel, anchor, 0, border & ~BORDER_ISOLATED ); +} + + +/////////////// median /////////////// + +class CV_MedianBlurTest : public CV_SmoothBaseTest +{ +public: + CV_MedianBlurTest(); + +protected: + void prepare_to_validation( int test_case_idx ); + double get_success_error_level( int test_case_idx, int i, int j ); + void run_func(); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); +}; + + +CV_MedianBlurTest::CV_MedianBlurTest() +{ + smooth_type = "Median"; +} + + +void CV_MedianBlurTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + CV_SmoothBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int depth = CV_8U; + int cn = CV_MAT_CN(types[INPUT][0]); + types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth,cn); + types[INPUT][1] = CV_MAKETYPE(depth,1); + + aperture_size.height = aperture_size.width; + anchor.x = anchor.y = aperture_size.width / 2; + sizes[INPUT][1] = cvSize(aperture_size.width,aperture_size.height); + + sizes[OUTPUT][0] = sizes[INPUT][0]; + sizes[REF_OUTPUT][0] = sizes[INPUT][0]; + + inplace = false; + border = BORDER_REPLICATE | BORDER_ISOLATED; +} + + +double CV_MedianBlurTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + return 0; +} + + +void CV_MedianBlurTest::run_func() +{ + cvSmooth( test_array[INPUT][0], test_array[OUTPUT][0], + CV_MEDIAN, aperture_size.width ); +} + + +struct median_pair +{ + int col; + int val; + median_pair() {}; + median_pair( int _col, int _val ) : col(_col), val(_val) {}; +}; + + +static void test_medianFilter( const Mat& src, Mat& dst, int m ) +{ + int i, j, k, l, m2 = m*m, n; + vector col_buf(m+1); + vector _buf0(m*m+1), _buf1(m*m+1); + median_pair *buf0 = &_buf0[0], *buf1 = &_buf1[0]; + int step = (int)(src.step/src.elemSize()); + + assert( src.rows == dst.rows + m - 1 && src.cols == dst.cols + m - 1 && + src.type() == dst.type() && src.type() == CV_8UC1 ); + + for( i = 0; i < dst.rows; i++ ) + { + uchar* dst1 = dst.ptr(i); + for( k = 0; k < m; k++ ) + { + const uchar* src1 = src.ptr(i+k); + for( j = 0; j < m-1; j++ ) + *buf0++ = median_pair(j, src1[j]); + } + + n = m2 - m; + buf0 -= n; + for( k = n-1; k > 0; k-- ) + { + int f = 0; + for( j = 0; j < k; j++ ) + { + if( buf0[j].val > buf0[j+1].val ) + { + median_pair t; + CV_SWAP( buf0[j], buf0[j+1], t ); + f = 1; + } + } + if( !f ) + break; + } + + for( j = 0; j < dst.cols; j++ ) + { + int ins_col = j + m - 1; + int del_col = j - 1; + const uchar* src1 = src.ptr(i) + ins_col; + for( k = 0; k < m; k++, src1 += step ) + { + col_buf[k] = src1[0]; + for( l = k-1; l >= 0; l-- ) + { + int t; + if( col_buf[l] < col_buf[l+1] ) + break; + CV_SWAP( col_buf[l], col_buf[l+1], t ); + } + } + + col_buf[m] = INT_MAX; + + for( k = 0, l = 0; k < n; ) + { + if( buf0[k].col == del_col ) + k++; + else if( buf0[k].val < col_buf[l] ) + *buf1++ = buf0[k++]; + else + { + assert( col_buf[l] < INT_MAX ); + *buf1++ = median_pair(ins_col,col_buf[l++]); + } + } + + for( ; l < m; l++ ) + *buf1++ = median_pair(ins_col,col_buf[l]); + + if( del_col < 0 ) + n += m; + buf1 -= n; + assert( n == m2 ); + dst1[j] = (uchar)buf1[n/2].val; + median_pair* tbuf; + CV_SWAP( buf0, buf1, tbuf ); + } + } +} + + +void CV_MedianBlurTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + // CV_SmoothBaseTest::prepare_to_validation( test_case_idx ); + const Mat& src0 = test_mat[INPUT][0]; + Mat& dst0 = test_mat[REF_OUTPUT][0]; + int i, cn = src0.channels(); + int m = aperture_size.width; + Mat src(src0.rows + m - 1, src0.cols + m - 1, src0.depth()); + Mat dst; + if( cn == 1 ) + dst = dst0; + else + dst.create(src0.size(), src0.depth()); + + for( i = 0; i < cn; i++ ) + { + Mat ptr = src0; + if( cn > 1 ) + { + cvtest::extract( src0, dst, i ); + ptr = dst; + } + cvtest::copyMakeBorder( ptr, src, m/2, m/2, m/2, m/2, border & ~BORDER_ISOLATED ); + test_medianFilter( src, dst, m ); + if( cn > 1 ) + cvtest::insert( dst, dst0, i ); + } +} + + +/////////////// pyramid tests /////////////// + +class CV_PyramidBaseTest : public CV_FilterBaseTest +{ +public: + CV_PyramidBaseTest( bool downsample ); + +protected: + double get_success_error_level( int test_case_idx, int i, int j ); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + bool downsample; + Mat kernel; +}; + + +CV_PyramidBaseTest::CV_PyramidBaseTest( bool _downsample ) : CV_FilterBaseTest(true) +{ + static float kdata[] = { 1.f, 4.f, 6.f, 4.f, 1.f }; + downsample = _downsample; + Mat kernel1d(1, 5, CV_32F, kdata); + kernel = (kernel1d.t()*kernel1d)*((downsample ? 1 : 4)/256.); +} + + +double CV_PyramidBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth < CV_32F ? 1 : 1e-5; +} + + +void CV_PyramidBaseTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, + vector >& types ) +{ + const int channels[] = {1, 3, 4}; + const int depthes[] = {CV_8U, CV_16S, CV_16U, CV_32F}; + + RNG& rng = ts->get_rng(); + CvSize sz; + CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + int depth = depthes[cvtest::randInt(rng) % (sizeof(depthes)/sizeof(depthes[0]))]; + int cn = channels[cvtest::randInt(rng) % (sizeof(channels)/sizeof(channels[0]))]; + + aperture_size = cvSize(5,5); + anchor = cvPoint(aperture_size.width/2, aperture_size.height/2); + + types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn); + + sz.width = MAX( sizes[INPUT][0].width/2, 1 ); + sz.height = MAX( sizes[INPUT][0].height/2, 1 ); + + if( downsample ) + { + sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz; + sz.width *= 2; + sz.height *= 2; + sizes[INPUT][0] = sz; + } + else + { + sizes[INPUT][0] = sz; + sz.width *= 2; + sz.height *= 2; + sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz; + } + + sizes[INPUT][1] = aperture_size; + inplace = false; +} + + +/////// pyrdown //////// + +class CV_PyramidDownTest : public CV_PyramidBaseTest +{ +public: + CV_PyramidDownTest(); + +protected: + void run_func(); + void prepare_to_validation( int ); +}; + + +CV_PyramidDownTest::CV_PyramidDownTest() : CV_PyramidBaseTest( true ) +{ +} + + +void CV_PyramidDownTest::run_func() +{ + cvPyrDown( test_array[INPUT][0], test_array[OUTPUT][0], CV_GAUSSIAN_5x5 ); +} + + +void CV_PyramidDownTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat& src = test_mat[INPUT][0], &dst = test_mat[REF_OUTPUT][0]; + Mat temp; + cvtest::filter2D(src, temp, src.depth(), + kernel, Point(kernel.cols/2, kernel.rows/2), + 0, BORDER_REFLECT_101); + + size_t elem_size = temp.elemSize(); + size_t ncols = dst.cols*elem_size; + + for( int i = 0; i < dst.rows; i++ ) + { + const uchar* src_row = temp.ptr(i*2); + uchar* dst_row = dst.ptr(i); + + for( size_t j = 0; j < ncols; j += elem_size ) + { + for( size_t k = 0; k < elem_size; k++ ) + dst_row[j+k] = src_row[j*2+k]; + } + } +} + + +/////// pyrup //////// + +class CV_PyramidUpTest : public CV_PyramidBaseTest +{ +public: + CV_PyramidUpTest(); + +protected: + void run_func(); + void prepare_to_validation( int ); +}; + + +CV_PyramidUpTest::CV_PyramidUpTest() : CV_PyramidBaseTest( false ) +{ +} + + +void CV_PyramidUpTest::run_func() +{ + cvPyrUp( test_array[INPUT][0], test_array[OUTPUT][0], CV_GAUSSIAN_5x5 ); +} + + +void CV_PyramidUpTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat& src = test_mat[INPUT][0], &dst = test_mat[REF_OUTPUT][0]; + Mat temp(dst.size(), dst.type()); + + size_t elem_size = src.elemSize(); + size_t ncols = src.cols*elem_size; + + for( int i = 0; i < src.rows; i++ ) + { + const uchar* src_row = src.ptr(i); + uchar* dst_row = temp.ptr(i*2); + + if( i*2 + 1 < temp.rows ) + memset( temp.ptr(i*2+1), 0, temp.cols*elem_size ); + for( size_t j = 0; j < ncols; j += elem_size ) + { + for( size_t k = 0; k < elem_size; k++ ) + { + dst_row[j*2+k] = src_row[j+k]; + dst_row[j*2+k+elem_size] = 0; + } + } + } + + cvtest::filter2D(temp, dst, dst.depth(), + kernel, Point(kernel.cols/2, kernel.rows/2), + 0, BORDER_REFLECT_101); +} + + +//////////////////////// feature selection ////////////////////////// + +class CV_FeatureSelBaseTest : public cvtest::ArrayTest +{ +public: + CV_FeatureSelBaseTest( int width_factor ); + +protected: + int read_params( CvFileStorage* fs ); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ); + double get_success_error_level( int test_case_idx, int i, int j ); + int aperture_size, block_size; + int max_aperture_size; + int max_block_size; + int width_factor; +}; + + +CV_FeatureSelBaseTest::CV_FeatureSelBaseTest( int _width_factor ) +{ + max_aperture_size = 7; + max_block_size = 21; + // 1 input, 1 output, temp arrays are allocated in the reference functions + test_array[INPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + element_wise_relative_error = false; + width_factor = _width_factor; +} + + +int CV_FeatureSelBaseTest::read_params( CvFileStorage* fs ) +{ + int code = cvtest::BaseTest::read_params( fs ); + if( code < 0 ) + return code; + + max_aperture_size = cvReadInt( find_param( fs, "max_aperture_size" ), max_aperture_size ); + max_aperture_size = cvtest::clipInt( max_aperture_size, 1, 9 ); + max_block_size = cvReadInt( find_param( fs, "max_block_size" ), max_block_size ); + max_block_size = cvtest::clipInt( max_aperture_size, 1, 100 ); + + return code; +} + + +double CV_FeatureSelBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth <= CV_8S ? 3e-2 : depth == CV_32F ? 1e-3 : 1e-10; +} + + +void CV_FeatureSelBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ) +{ + cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high ); + if( i == INPUT && CV_MAT_DEPTH(type) == CV_32F ) + { + low = Scalar::all(-10.); + high = Scalar::all(10.); + } +} + + +void CV_FeatureSelBaseTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int depth = cvtest::randInt(rng) % 2, asz; + + depth = depth == 0 ? CV_8U : CV_32F; + types[INPUT][0] = depth; + types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_32FC1; + + aperture_size = (cvtest::randInt(rng) % (max_aperture_size+2) - 1) | 1; + if( aperture_size == 1 ) + aperture_size = 3; + if( depth == CV_8U ) + aperture_size = MIN( aperture_size, 5 ); + block_size = (cvtest::randInt(rng) % max_block_size + 1) | 1; + if( block_size <= 3 ) + block_size = 3; + asz = aperture_size > 0 ? aperture_size : 3; + + sizes[INPUT][0].width = MAX( sizes[INPUT][0].width, asz + block_size ); + sizes[INPUT][0].height = MAX( sizes[INPUT][0].height, asz + block_size ); + sizes[OUTPUT][0].height = sizes[REF_OUTPUT][0].height = sizes[INPUT][0].height; + sizes[OUTPUT][0].width = sizes[REF_OUTPUT][0].width = sizes[INPUT][0].width*width_factor; +} + + +static void +test_cornerEigenValsVecs( const Mat& src, Mat& eigenv, Mat& ocv_eigenv, + int block_size, int _aperture_size, int mode ) +{ + int i, j; + int aperture_size = _aperture_size < 0 ? 3 : _aperture_size; + Point anchor( aperture_size/2, aperture_size/2 ); + + CV_Assert( src.type() == CV_8UC1 || src.type() == CV_32FC1 ); + CV_Assert( eigenv.type() == CV_32FC1 ); + CV_Assert( src.rows == eigenv.rows && + ((mode > 0 && src.cols == eigenv.cols) || + (mode == 0 && src.cols*6 == eigenv.cols)) ); + + int type = src.type(); + int ftype = CV_32FC1; + double kernel_scale = type != ftype ? 1./255 : 1; + + Mat dx2, dy2, dxdy(src.size(), CV_32F), kernel; + + kernel = cvtest::calcSobelKernel2D( 1, 0, _aperture_size ); + cvtest::filter2D( src, dx2, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE ); + kernel = cvtest::calcSobelKernel2D( 0, 1, _aperture_size ); + cvtest::filter2D( src, dy2, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE ); + + double denom = (1 << (aperture_size-1))*block_size; + denom = denom * denom; + if( _aperture_size < 0 ) + denom *= 4; + denom = 1./denom; + + for( i = 0; i < src.rows; i++ ) + { + float* dxdyp = dxdy.ptr(i); + float* dx2p = dx2.ptr(i); + float* dy2p = dy2.ptr(i); + + for( j = 0; j < src.cols; j++ ) + { + double xval = dx2p[j], yval = dy2p[j]; + dxdyp[j] = (float)(xval*yval*denom); + dx2p[j] = (float)(xval*xval*denom); + dy2p[j] = (float)(yval*yval*denom); + } + } + + kernel = Mat::ones(block_size, block_size, CV_32F); + anchor = Point(block_size/2, block_size/2); + + cvtest::filter2D( dx2, dx2, ftype, kernel, anchor, 0, BORDER_REPLICATE ); + cvtest::filter2D( dy2, dy2, ftype, kernel, anchor, 0, BORDER_REPLICATE ); + cvtest::filter2D( dxdy, dxdy, ftype, kernel, anchor, 0, BORDER_REPLICATE ); + + if( mode == 0 ) + { + for( i = 0; i < src.rows; i++ ) + { + float* eigenvp = eigenv.ptr(i); + float* ocv_eigenvp = ocv_eigenv.ptr(i); + const float* dxdyp = dxdy.ptr(i); + const float* dx2p = dx2.ptr(i); + const float* dy2p = dy2.ptr(i); + + for( j = 0; j < src.cols; j++ ) + { + double a = dx2p[j], b = dxdyp[j], c = dy2p[j]; + double d = sqrt((a-c)*(a-c) + 4*b*b); + double l1 = 0.5*(a + c + d); + double l2 = 0.5*(a + c - d); + double x1, y1, x2, y2, s; + + if( fabs(a - l1) + fabs(b) >= 1e-3 ) + x1 = b, y1 = l1 - a; + else + x1 = l1 - c, y1 = b; + s = 1./(sqrt(x1*x1+y1*y1)+DBL_EPSILON); + x1 *= s; y1 *= s; + + if( fabs(a - l2) + fabs(b) >= 1e-3 ) + x2 = b, y2 = l2 - a; + else + x2 = l2 - c, y2 = b; + s = 1./(sqrt(x2*x2+y2*y2)+DBL_EPSILON); + x2 *= s; y2 *= s; + + /* the orientation of eigen vectors might be inversed relative to OpenCV function, + which is normal */ + if( (fabs(x1) >= fabs(y1) && ocv_eigenvp[j*6+2]*x1 < 0) || + (fabs(x1) < fabs(y1) && ocv_eigenvp[j*6+3]*y1 < 0) ) + x1 = -x1, y1 = -y1; + + if( (fabs(x2) >= fabs(y2) && ocv_eigenvp[j*6+4]*x2 < 0) || + (fabs(x2) < fabs(y2) && ocv_eigenvp[j*6+5]*y2 < 0) ) + x2 = -x2, y2 = -y2; + + eigenvp[j*6] = (float)l1; + eigenvp[j*6+1] = (float)l2; + eigenvp[j*6+2] = (float)x1; + eigenvp[j*6+3] = (float)y1; + eigenvp[j*6+4] = (float)x2; + eigenvp[j*6+5] = (float)y2; + } + } + } + else if( mode == 1 ) + { + for( i = 0; i < src.rows; i++ ) + { + float* eigenvp = eigenv.ptr(i); + const float* dxdyp = dxdy.ptr(i); + const float* dx2p = dx2.ptr(i); + const float* dy2p = dy2.ptr(i); + + for( j = 0; j < src.cols; j++ ) + { + double a = dx2p[j], b = dxdyp[j], c = dy2p[j]; + double d = sqrt((a-c)*(a-c) + 4*b*b); + eigenvp[j] = (float)(0.5*(a + c - d)); + } + } + } +} + + +// min eigenval +class CV_MinEigenValTest : public CV_FeatureSelBaseTest +{ +public: + CV_MinEigenValTest(); + +protected: + void run_func(); + void prepare_to_validation( int ); +}; + + +CV_MinEigenValTest::CV_MinEigenValTest() : CV_FeatureSelBaseTest( 1 ) +{ +} + + +void CV_MinEigenValTest::run_func() +{ + cvCornerMinEigenVal( test_array[INPUT][0], test_array[OUTPUT][0], + block_size, aperture_size ); +} + + +void CV_MinEigenValTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + test_cornerEigenValsVecs( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], + test_mat[OUTPUT][0], block_size, aperture_size, 1 ); +} + + +// eigenval's & vec's +class CV_EigenValVecTest : public CV_FeatureSelBaseTest +{ +public: + CV_EigenValVecTest(); + +protected: + void run_func(); + void prepare_to_validation( int ); +}; + + +CV_EigenValVecTest::CV_EigenValVecTest() : CV_FeatureSelBaseTest( 6 ) +{ +} + + +void CV_EigenValVecTest::run_func() +{ + cvCornerEigenValsAndVecs( test_array[INPUT][0], test_array[OUTPUT][0], + block_size, aperture_size ); +} + + +void CV_EigenValVecTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + test_cornerEigenValsVecs( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], + test_mat[OUTPUT][0], block_size, aperture_size, 0 ); +} + + +// precornerdetect +class CV_PreCornerDetectTest : public CV_FeatureSelBaseTest +{ +public: + CV_PreCornerDetectTest(); + +protected: + void run_func(); + void prepare_to_validation( int ); + int prepare_test_case( int ); +}; + + +CV_PreCornerDetectTest::CV_PreCornerDetectTest() : CV_FeatureSelBaseTest( 1 ) +{ +} + + +void CV_PreCornerDetectTest::run_func() +{ + cvPreCornerDetect( test_array[INPUT][0], test_array[OUTPUT][0], aperture_size ); +} + + +int CV_PreCornerDetectTest::prepare_test_case( int test_case_idx ) +{ + int code = CV_FeatureSelBaseTest::prepare_test_case( test_case_idx ); + if( aperture_size < 0 ) + aperture_size = 3; + return code; +} + + +void CV_PreCornerDetectTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + /*cvTsCornerEigenValsVecs( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], + block_size, aperture_size, 0 );*/ + const Mat& src = test_mat[INPUT][0]; + Mat& dst = test_mat[REF_OUTPUT][0]; + + int type = src.type(), ftype = CV_32FC1; + Point anchor(aperture_size/2, aperture_size/2); + + double kernel_scale = type != ftype ? 1./255 : 1.; + + Mat dx, dy, d2x, d2y, dxy, kernel; + + kernel = cvtest::calcSobelKernel2D(1, 0, aperture_size); + cvtest::filter2D(src, dx, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE); + kernel = cvtest::calcSobelKernel2D(2, 0, aperture_size); + cvtest::filter2D(src, d2x, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE); + kernel = cvtest::calcSobelKernel2D(0, 1, aperture_size); + cvtest::filter2D(src, dy, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE); + kernel = cvtest::calcSobelKernel2D(0, 2, aperture_size); + cvtest::filter2D(src, d2y, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE); + kernel = cvtest::calcSobelKernel2D(1, 1, aperture_size); + cvtest::filter2D(src, dxy, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE); + + double denom = 1 << (aperture_size-1); + denom = denom * denom * denom; + denom = 1./denom; + + for( int i = 0; i < src.rows; i++ ) + { + const float* _dx = dx.ptr(i); + const float* _dy = dy.ptr(i); + const float* _d2x = d2x.ptr(i); + const float* _d2y = d2y.ptr(i); + const float* _dxy = dxy.ptr(i); + float* corner = dst.ptr(i); + + for( int j = 0; j < src.cols; j++ ) + { + double x = _dx[j]; + double y = _dy[j]; + + corner[j] = (float)(denom*(x*x*_d2y[j] + y*y*_d2x[j] - 2*x*y*_dxy[j])); + } + } +} + + +///////// integral ///////// + +class CV_IntegralTest : public cvtest::ArrayTest +{ +public: + CV_IntegralTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ); + double get_success_error_level( int test_case_idx, int i, int j ); + void run_func(); + void prepare_to_validation( int ); + + int prepare_test_case( int test_case_idx ); +}; + + +CV_IntegralTest::CV_IntegralTest() +{ + test_array[INPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + element_wise_relative_error = true; +} + + +void CV_IntegralTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ) +{ + cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high ); + int depth = CV_MAT_DEPTH(type); + if( depth == CV_32F ) + { + low = Scalar::all(-10.); + high = Scalar::all(10.); + } +} + + +void CV_IntegralTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + int depth = cvtest::randInt(rng) % 2, sum_depth; + int cn = cvtest::randInt(rng) % 3 + 1; + cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + Size sum_size; + + depth = depth == 0 ? CV_8U : CV_32F; + cn += cn == 2; + int b = (cvtest::randInt(rng) & 1) != 0; + sum_depth = depth == CV_8U && b ? CV_32S : b ? CV_32F : CV_64F; + + types[INPUT][0] = CV_MAKETYPE(depth,cn); + types[OUTPUT][0] = types[REF_OUTPUT][0] = + types[OUTPUT][2] = types[REF_OUTPUT][2] = CV_MAKETYPE(sum_depth, cn); + types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_MAKETYPE(CV_64F, cn); + + sum_size.width = sizes[INPUT][0].width + 1; + sum_size.height = sizes[INPUT][0].height + 1; + + sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sum_size; + sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = + sizes[OUTPUT][2] = sizes[REF_OUTPUT][2] = Size(0,0); + + if( cvtest::randInt(rng) % 3 > 0 ) + { + sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = sum_size; + if( cvtest::randInt(rng) % 2 > 0 ) + sizes[REF_OUTPUT][2] = sizes[OUTPUT][2] = sum_size; + } +} + + +double CV_IntegralTest::get_success_error_level( int, int i, int j ) +{ + int depth = test_mat[i][j].depth(); + return depth == CV_32S ? 0 : depth == CV_64F ? FLT_EPSILON : 5e-3; +} + + +int CV_IntegralTest::prepare_test_case( int test_case_idx ) +{ + int code = cvtest::ArrayTest::prepare_test_case( test_case_idx ); + return code > 0 && ((test_array[OUTPUT][2] && test_mat[OUTPUT][2].channels() > 1) || + test_mat[OUTPUT][0].depth() < test_mat[INPUT][0].depth()) ? 0 : code; +} + + +void CV_IntegralTest::run_func() +{ + cvIntegral( test_array[INPUT][0], test_array[OUTPUT][0], + test_array[OUTPUT][1], test_array[OUTPUT][2] ); +} + + +static void test_integral( const Mat& img, Mat* sum, Mat* sqsum, Mat* tilted ) +{ + CV_Assert( img.depth() == CV_32F ); + + sum->create(img.rows+1, img.cols+1, CV_64F); + if( sqsum ) + sqsum->create(img.rows+1, img.cols+1, CV_64F); + if( tilted ) + tilted->create(img.rows+1, img.cols+1, CV_64F); + + const float* data = img.ptr(); + double* sdata = sum->ptr(); + double* sqdata = sqsum ? sqsum->ptr() : 0; + double* tdata = tilted ? tilted->ptr() : 0; + int step = (int)(img.step/sizeof(data[0])); + int sstep = (int)(sum->step/sizeof(sdata[0])); + int sqstep = sqsum ? (int)(sqsum->step/sizeof(sqdata[0])) : 0; + int tstep = tilted ? (int)(tilted->step/sizeof(tdata[0])) : 0; + Size size = img.size(); + + memset( sdata, 0, (size.width+1)*sizeof(sdata[0]) ); + if( sqsum ) + memset( sqdata, 0, (size.width+1)*sizeof(sqdata[0]) ); + if( tilted ) + memset( tdata, 0, (size.width+1)*sizeof(tdata[0]) ); + + for( ; size.height--; data += step ) + { + double s = 0, sq = 0; + int x; + sdata += sstep; + sqdata += sqstep; + tdata += tstep; + + for( x = 0; x <= size.width; x++ ) + { + double t = x > 0 ? data[x-1] : 0, ts = t; + s += t; + sq += t*t; + + sdata[x] = s + sdata[x - sstep]; + if( sqdata ) + sqdata[x] = sq + sqdata[x - sqstep]; + + if( !tdata ) + continue; + + if( x == 0 ) + ts += tdata[-tstep+1]; + else + { + ts += tdata[x-tstep-1]; + if( data > img.ptr() ) + { + ts += data[x-step-1]; + if( x < size.width ) + ts += tdata[x-tstep+1] - tdata[x-tstep*2]; + } + } + + tdata[x] = ts; + } + } +} + + +void CV_IntegralTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat& src = test_mat[INPUT][0]; + int cn = src.channels(); + + Mat* sum0 = &test_mat[REF_OUTPUT][0]; + Mat* sqsum0 = test_array[REF_OUTPUT][1] ? &test_mat[REF_OUTPUT][1] : 0; + Mat* tsum0 = test_array[REF_OUTPUT][2] ? &test_mat[REF_OUTPUT][2] : 0; + + Mat plane, srcf, psum, psqsum, ptsum, psum2, psqsum2, ptsum2; + if( cn == 1 ) + { + plane = src; + psum2 = *sum0; + psqsum2 = sqsum0 ? *sqsum0 : Mat(); + ptsum2 = tsum0 ? *tsum0 : Mat(); + } + + for( int i = 0; i < cn; i++ ) + { + if( cn > 1 ) + cvtest::extract(src, plane, i); + plane.convertTo(srcf, CV_32F); + + test_integral( srcf, &psum, sqsum0 ? &psqsum : 0, tsum0 ? &ptsum : 0 ); + psum.convertTo(psum2, sum0->depth()); + if( sqsum0 ) + psqsum.convertTo(psqsum2, sqsum0->depth()); + if( tsum0 ) + ptsum.convertTo(ptsum2, tsum0->depth()); + + if( cn > 1 ) + { + cvtest::insert(psum2, *sum0, i); + if( sqsum0 ) + cvtest::insert(psqsum2, *sqsum0, i); + if( tsum0 ) + cvtest::insert(ptsum2, *tsum0, i); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////////// + +TEST(Imgproc_Erode, accuracy) { CV_ErodeTest test; test.safe_run(); } +TEST(Imgproc_Dilate, accuracy) { CV_DilateTest test; test.safe_run(); } +TEST(Imgproc_MorphologyEx, accuracy) { CV_MorphExTest test; test.safe_run(); } +TEST(Imgproc_Filter2D, accuracy) { CV_FilterTest test; test.safe_run(); } +TEST(Imgproc_Sobel, accuracy) { CV_SobelTest test; test.safe_run(); } +TEST(Imgproc_Laplace, accuracy) { CV_LaplaceTest test; test.safe_run(); } +TEST(Imgproc_Blur, accuracy) { CV_BlurTest test; test.safe_run(); } +TEST(Imgproc_GaussianBlur, accuracy) { CV_GaussianBlurTest test; test.safe_run(); } +TEST(Imgproc_MedianBlur, accuracy) { CV_MedianBlurTest test; test.safe_run(); } +TEST(Imgproc_PyramidDown, accuracy) { CV_PyramidDownTest test; test.safe_run(); } +TEST(Imgproc_PyramidUp, accuracy) { CV_PyramidUpTest test; test.safe_run(); } +TEST(Imgproc_MinEigenVal, accuracy) { CV_MinEigenValTest test; test.safe_run(); } +TEST(Imgproc_EigenValsVecs, accuracy) { CV_EigenValVecTest test; test.safe_run(); } +TEST(Imgproc_PreCornerDetect, accuracy) { CV_PreCornerDetectTest test; test.safe_run(); } +TEST(Imgproc_Integral, accuracy) { CV_IntegralTest test; test.safe_run(); } + +////////////////////////////////////////////////////////////////////////////////// + +class CV_FilterSupportedFormatsTest : public cvtest::BaseTest +{ +public: + CV_FilterSupportedFormatsTest() {} + ~CV_FilterSupportedFormatsTest() {} +protected: + void run(int) + { + const int depths[][2] = + { + {CV_8U, CV_8U}, + {CV_8U, CV_16U}, + {CV_8U, CV_16S}, + {CV_8U, CV_32F}, + {CV_8U, CV_64F}, + {CV_16U, CV_16U}, + {CV_16U, CV_32F}, + {CV_16U, CV_64F}, + {CV_16S, CV_16S}, + {CV_16S, CV_32F}, + {CV_16S, CV_64F}, + {CV_32F, CV_32F}, + {CV_64F, CV_64F}, + {-1, -1} + }; + + int i = 0; + volatile int fidx = -1; + try + { + // use some "odd" size to do yet another smoke + // testing of the non-SIMD loop tails + Size sz(163, 117); + Mat small_kernel(5, 5, CV_32F), big_kernel(21, 21, CV_32F); + Mat kernelX(11, 1, CV_32F), kernelY(7, 1, CV_32F); + Mat symkernelX(11, 1, CV_32F), symkernelY(7, 1, CV_32F); + randu(small_kernel, -10, 10); + randu(big_kernel, -1, 1); + randu(kernelX, -1, 1); + randu(kernelY, -1, 1); + flip(kernelX, symkernelX, 0); + symkernelX += kernelX; + flip(kernelY, symkernelY, 0); + symkernelY += kernelY; + + Mat elem_ellipse = getStructuringElement(MORPH_ELLIPSE, Size(7, 7)); + Mat elem_rect = getStructuringElement(MORPH_RECT, Size(7, 7)); + + for( i = 0; depths[i][0] >= 0; i++ ) + { + int sdepth = depths[i][0]; + int ddepth = depths[i][1]; + Mat src(sz, CV_MAKETYPE(sdepth, 5)), dst; + randu(src, 0, 100); + // non-separable filtering with a small kernel + fidx = 0; + filter2D(src, dst, ddepth, small_kernel); + fidx++; + filter2D(src, dst, ddepth, big_kernel); + fidx++; + sepFilter2D(src, dst, ddepth, kernelX, kernelY); + fidx++; + sepFilter2D(src, dst, ddepth, symkernelX, symkernelY); + fidx++; + Sobel(src, dst, ddepth, 2, 0, 5); + fidx++; + Scharr(src, dst, ddepth, 0, 1); + if( sdepth != ddepth ) + continue; + fidx++; + GaussianBlur(src, dst, Size(5, 5), 1.2, 1.2); + fidx++; + blur(src, dst, Size(11, 11)); + fidx++; + morphologyEx(src, dst, MORPH_GRADIENT, elem_ellipse); + fidx++; + morphologyEx(src, dst, MORPH_GRADIENT, elem_rect); + } + } + catch(...) + { + ts->printf(cvtest::TS::LOG, "Combination of depths %d => %d in %s is not supported (yet it should be)", + depths[i][0], depths[i][1], + fidx == 0 ? "filter2D (small kernel)" : + fidx == 1 ? "filter2D (large kernel)" : + fidx == 2 ? "sepFilter2D" : + fidx == 3 ? "sepFilter2D (symmetrical/asymmetrical kernel)" : + fidx == 4 ? "Sobel" : + fidx == 5 ? "Scharr" : + fidx == 6 ? "GaussianBlur" : + fidx == 7 ? "blur" : + fidx == 8 || fidx == 9 ? "morphologyEx" : + "unknown???"); + + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + } + } +}; + +TEST(Imgproc_Filtering, supportedFormats) { CV_FilterSupportedFormatsTest test; test.safe_run(); } + diff --git a/imgproc/test/test_floodfill.cpp b/imgproc/test/test_floodfill.cpp new file mode 100644 index 0000000..e46e9e1 --- /dev/null +++ b/imgproc/test/test_floodfill.cpp @@ -0,0 +1,522 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +class CV_FloodFillTest : public cvtest::ArrayTest +{ +public: + CV_FloodFillTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void run_func(); + void prepare_to_validation( int ); + + void fill_array( int test_case_idx, int i, int j, Mat& arr ); + + /*int write_default_params(CvFileStorage* fs); + void get_timing_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types + CvSize** whole_sizes, bool *are_images ); + void print_timing_params( int test_case_idx, char* ptr, int params_left );*/ + CvPoint seed_pt; + CvScalar new_val; + CvScalar l_diff, u_diff; + int connectivity; + bool use_mask, mask_only; + int range_type; + int new_mask_val; + bool test_cpp; +}; + + +CV_FloodFillTest::CV_FloodFillTest() +{ + test_array[INPUT_OUTPUT].push_back(NULL); + test_array[INPUT_OUTPUT].push_back(NULL); + test_array[REF_INPUT_OUTPUT].push_back(NULL); + test_array[REF_INPUT_OUTPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + optional_mask = false; + element_wise_relative_error = true; + + test_cpp = false; +} + + +void CV_FloodFillTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, + vector >& types ) +{ + RNG& rng = ts->get_rng(); + int depth, cn; + int i; + double buff[8]; + cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + + depth = cvtest::randInt(rng) % 3; + depth = depth == 0 ? CV_8U : depth == 1 ? CV_32S : CV_32F; + cn = cvtest::randInt(rng) & 1 ? 3 : 1; + + use_mask = (cvtest::randInt(rng) & 1) != 0; + connectivity = (cvtest::randInt(rng) & 1) ? 4 : 8; + mask_only = use_mask && (cvtest::randInt(rng) & 1) != 0; + new_mask_val = cvtest::randInt(rng) & 255; + range_type = cvtest::randInt(rng) % 3; + + types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(depth, cn); + types[INPUT_OUTPUT][1] = types[REF_INPUT_OUTPUT][1] = CV_8UC1; + types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1; + sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(9,1); + + if( !use_mask ) + sizes[INPUT_OUTPUT][1] = sizes[REF_INPUT_OUTPUT][1] = cvSize(0,0); + else + { + CvSize sz = sizes[INPUT_OUTPUT][0]; + sizes[INPUT_OUTPUT][1] = sizes[REF_INPUT_OUTPUT][1] = cvSize(sz.width+2,sz.height+2); + } + + seed_pt.x = cvtest::randInt(rng) % sizes[INPUT_OUTPUT][0].width; + seed_pt.y = cvtest::randInt(rng) % sizes[INPUT_OUTPUT][0].height; + + if( range_type == 0 ) + l_diff = u_diff = Scalar::all(0.); + else + { + Mat m( 1, 8, CV_16S, buff ); + rng.fill( m, RNG::NORMAL, Scalar::all(0), Scalar::all(32) ); + for( i = 0; i < 4; i++ ) + { + l_diff.val[i] = fabs(m.at(i)/16.); + u_diff.val[i] = fabs(m.at(i+4)/16.); + } + } + + new_val = Scalar::all(0.); + for( i = 0; i < cn; i++ ) + new_val.val[i] = cvtest::randReal(rng)*255; + + test_cpp = (cvtest::randInt(rng) & 256) == 0; +} + + +double CV_FloodFillTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) +{ + return i == OUTPUT ? FLT_EPSILON : j == 0 ? FLT_EPSILON : 0; +} + + +void CV_FloodFillTest::fill_array( int test_case_idx, int i, int j, Mat& arr ) +{ + RNG& rng = ts->get_rng(); + + if( i != INPUT && i != INPUT_OUTPUT ) + { + cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr ); + return; + } + + if( j == 0 ) + { + Mat tmp = arr; + Scalar m = Scalar::all(128); + Scalar s = Scalar::all(10); + + if( arr.depth() == CV_32FC1 ) + tmp.create(arr.size(), CV_MAKETYPE(CV_8U, arr.channels())); + + if( range_type == 0 ) + s = Scalar::all(2); + + rng.fill(tmp, RNG::NORMAL, m, s ); + if( arr.data != tmp.data ) + cvtest::convert(tmp, arr, arr.type()); + } + else + { + Scalar l = Scalar::all(-2); + Scalar u = Scalar::all(2); + cvtest::randUni(rng, arr, l, u ); + rectangle( arr, Point(0,0), Point(arr.cols-1,arr.rows-1), Scalar::all(1), 1, 8, 0 ); + } +} + + +void CV_FloodFillTest::run_func() +{ + int flags = connectivity + (mask_only ? CV_FLOODFILL_MASK_ONLY : 0) + + (range_type == 1 ? CV_FLOODFILL_FIXED_RANGE : 0) + (new_mask_val << 8); + double* odata = test_mat[OUTPUT][0].ptr(); + + if(!test_cpp) + { + CvConnectedComp comp; + cvFloodFill( test_array[INPUT_OUTPUT][0], seed_pt, new_val, l_diff, u_diff, &comp, + flags, test_array[INPUT_OUTPUT][1] ); + odata[0] = comp.area; + odata[1] = comp.rect.x; + odata[2] = comp.rect.y; + odata[3] = comp.rect.width; + odata[4] = comp.rect.height; + odata[5] = comp.value.val[0]; + odata[6] = comp.value.val[1]; + odata[7] = comp.value.val[2]; + odata[8] = comp.value.val[3]; + } + else + { + cv::Mat img = cv::cvarrToMat(test_array[INPUT_OUTPUT][0]), + mask = test_array[INPUT_OUTPUT][1] ? cv::cvarrToMat(test_array[INPUT_OUTPUT][1]) : cv::Mat(); + cv::Rect rect; + int area; + if( !mask.data ) + area = cv::floodFill( img, seed_pt, new_val, &rect, l_diff, u_diff, flags ); + else + area = cv::floodFill( img, mask, seed_pt, new_val, &rect, l_diff, u_diff, flags ); + odata[0] = area; + odata[1] = rect.x; + odata[2] = rect.y; + odata[3] = rect.width; + odata[4] = rect.height; + odata[5] = odata[6] = odata[7] = odata[8] = 0; + } +} + + +typedef struct ff_offset_pair_t +{ + int mofs, iofs; +} +ff_offset_pair_t; + +static void +cvTsFloodFill( CvMat* _img, CvPoint seed_pt, CvScalar new_val, + CvScalar l_diff, CvScalar u_diff, CvMat* _mask, + double* comp, int connectivity, int range_type, + int new_mask_val, bool mask_only ) +{ + CvMemStorage* st = cvCreateMemStorage(); + ff_offset_pair_t p0, p; + CvSeq* seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(p0), st ); + CvMat* tmp = _img; + CvMat* mask; + CvRect r = cvRect( 0, 0, -1, -1 ); + int area = 0; + int i, j; + ushort* m; + float* img; + int mstep, step; + int cn = CV_MAT_CN(_img->type); + int mdelta[8], idelta[8], ncount; + int cols = _img->cols, rows = _img->rows; + int u0 = 0, u1 = 0, u2 = 0; + double s0 = 0, s1 = 0, s2 = 0; + + if( CV_MAT_DEPTH(_img->type) == CV_8U || CV_MAT_DEPTH(_img->type) == CV_32S ) + { + tmp = cvCreateMat( rows, cols, CV_MAKETYPE(CV_32F,CV_MAT_CN(_img->type)) ); + cvTsConvert(_img, tmp); + } + + mask = cvCreateMat( rows + 2, cols + 2, CV_16UC1 ); + + if( _mask ) + cvTsConvert( _mask, mask ); + else + { + cvTsZero( mask ); + cvRectangle( mask, cvPoint(0,0), cvPoint(mask->cols-1,mask->rows-1), Scalar::all(1.), 1, 8, 0 ); + } + + new_mask_val = (new_mask_val != 0 ? new_mask_val : 1) << 8; + + m = (ushort*)(mask->data.ptr + mask->step) + 1; + mstep = mask->step / sizeof(m[0]); + img = tmp->data.fl; + step = tmp->step / sizeof(img[0]); + + p0.mofs = seed_pt.y*mstep + seed_pt.x; + p0.iofs = seed_pt.y*step + seed_pt.x*cn; + + if( m[p0.mofs] ) + goto _exit_; + + cvSeqPush( seq, &p0 ); + m[p0.mofs] = (ushort)new_mask_val; + + if( connectivity == 4 ) + { + ncount = 4; + mdelta[0] = -mstep; idelta[0] = -step; + mdelta[1] = -1; idelta[1] = -cn; + mdelta[2] = 1; idelta[2] = cn; + mdelta[3] = mstep; idelta[3] = step; + } + else + { + ncount = 8; + mdelta[0] = -mstep-1; mdelta[1] = -mstep; mdelta[2] = -mstep+1; + idelta[0] = -step-cn; idelta[1] = -step; idelta[2] = -step+cn; + + mdelta[3] = -1; mdelta[4] = 1; + idelta[3] = -cn; idelta[4] = cn; + + mdelta[5] = mstep-1; mdelta[6] = mstep; mdelta[7] = mstep+1; + idelta[5] = step-cn; idelta[6] = step; idelta[7] = step+cn; + } + + if( cn == 1 ) + { + float a0 = (float)-l_diff.val[0]; + float b0 = (float)u_diff.val[0]; + + s0 = img[p0.iofs]; + + if( range_type < 2 ) + { + a0 += (float)s0; b0 += (float)s0; + } + + while( seq->total ) + { + cvSeqPop( seq, &p0 ); + float a = a0, b = b0; + float* ptr = img + p0.iofs; + ushort* mptr = m + p0.mofs; + + if( range_type == 2 ) + a += ptr[0], b += ptr[0]; + + for( i = 0; i < ncount; i++ ) + { + int md = mdelta[i], id = idelta[i]; + float v; + if( !mptr[md] && a <= (v = ptr[id]) && v <= b ) + { + mptr[md] = (ushort)new_mask_val; + p.mofs = p0.mofs + md; + p.iofs = p0.iofs + id; + cvSeqPush( seq, &p ); + } + } + } + } + else + { + float a0 = (float)-l_diff.val[0]; + float a1 = (float)-l_diff.val[1]; + float a2 = (float)-l_diff.val[2]; + float b0 = (float)u_diff.val[0]; + float b1 = (float)u_diff.val[1]; + float b2 = (float)u_diff.val[2]; + + s0 = img[p0.iofs]; + s1 = img[p0.iofs + 1]; + s2 = img[p0.iofs + 2]; + + if( range_type < 2 ) + { + a0 += (float)s0; b0 += (float)s0; + a1 += (float)s1; b1 += (float)s1; + a2 += (float)s2; b2 += (float)s2; + } + + while( seq->total ) + { + cvSeqPop( seq, &p0 ); + float _a0 = a0, _a1 = a1, _a2 = a2; + float _b0 = b0, _b1 = b1, _b2 = b2; + float* ptr = img + p0.iofs; + ushort* mptr = m + p0.mofs; + + if( range_type == 2 ) + { + _a0 += ptr[0]; _b0 += ptr[0]; + _a1 += ptr[1]; _b1 += ptr[1]; + _a2 += ptr[2]; _b2 += ptr[2]; + } + + for( i = 0; i < ncount; i++ ) + { + int md = mdelta[i], id = idelta[i]; + float v; + if( !mptr[md] && + _a0 <= (v = ptr[id]) && v <= _b0 && + _a1 <= (v = ptr[id+1]) && v <= _b1 && + _a2 <= (v = ptr[id+2]) && v <= _b2 ) + { + mptr[md] = (ushort)new_mask_val; + p.mofs = p0.mofs + md; + p.iofs = p0.iofs + id; + cvSeqPush( seq, &p ); + } + } + } + } + + r.x = r.width = seed_pt.x; + r.y = r.height = seed_pt.y; + + if( !mask_only ) + { + s0 = new_val.val[0]; + s1 = new_val.val[1]; + s2 = new_val.val[2]; + + if( tmp != _img ) + { + u0 = saturate_cast(s0); + u1 = saturate_cast(s1); + u2 = saturate_cast(s2); + + s0 = u0; + s1 = u1; + s2 = u2; + } + } + else + s0 = s1 = s2 = 0; + + new_mask_val >>= 8; + + for( i = 0; i < rows; i++ ) + { + float* ptr = img + i*step; + ushort* mptr = m + i*mstep; + uchar* dmptr = _mask ? _mask->data.ptr + (i+1)*_mask->step + 1 : 0; + double area0 = area; + + for( j = 0; j < cols; j++ ) + { + if( mptr[j] > 255 ) + { + if( dmptr ) + dmptr[j] = (uchar)new_mask_val; + if( !mask_only ) + { + if( cn == 1 ) + ptr[j] = (float)s0; + else + { + ptr[j*3] = (float)s0; + ptr[j*3+1] = (float)s1; + ptr[j*3+2] = (float)s2; + } + } + else + { + if( cn == 1 ) + s0 += ptr[j]; + else + { + s0 += ptr[j*3]; + s1 += ptr[j*3+1]; + s2 += ptr[j*3+2]; + } + } + + area++; + if( r.x > j ) + r.x = j; + if( r.width < j ) + r.width = j; + } + } + + if( area != area0 ) + { + if( r.y > i ) + r.y = i; + if( r.height < i ) + r.height = i; + } + } + +_exit_: + cvReleaseMat( &mask ); + if( tmp != _img ) + { + if( !mask_only ) + cvTsConvert(tmp, _img); + cvReleaseMat( &tmp ); + } + + comp[0] = area; + comp[1] = r.x; + comp[2] = r.y; + comp[3] = r.width - r.x + 1; + comp[4] = r.height - r.y + 1; + if( mask_only ) + { + double t = area ? 1./area : 0; + s0 *= t; + s1 *= t; + s2 *= t; + } + comp[5] = s0; + comp[6] = s1; + comp[7] = s2; + comp[8] = 0; +} + + +void CV_FloodFillTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + double* comp = test_mat[REF_OUTPUT][0].ptr(); + CvMat _input = test_mat[REF_INPUT_OUTPUT][0]; + CvMat _mask = test_mat[REF_INPUT_OUTPUT][1]; + cvTsFloodFill( &_input, seed_pt, new_val, l_diff, u_diff, + _mask.data.ptr ? &_mask : 0, + comp, connectivity, range_type, + new_mask_val, mask_only ); + if(test_cpp) + comp[5] = comp[6] = comp[7] = comp[8] = 0; +} + +TEST(Imgproc_FloodFill, accuracy) { CV_FloodFillTest test; test.safe_run(); } + +/* End of file. */ diff --git a/imgproc/test/test_grabcut.cpp b/imgproc/test/test_grabcut.cpp new file mode 100644 index 0000000..caf2f58 --- /dev/null +++ b/imgproc/test/test_grabcut.cpp @@ -0,0 +1,172 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +#include +#include + +using namespace std; +using namespace cv; + +class CV_GrabcutTest : public cvtest::BaseTest +{ +public: + CV_GrabcutTest(); + ~CV_GrabcutTest(); +protected: + bool verify(const Mat& mask, const Mat& exp); + void run(int); +}; + +CV_GrabcutTest::CV_GrabcutTest() {} +CV_GrabcutTest::~CV_GrabcutTest() {} + +bool CV_GrabcutTest::verify(const Mat& mask, const Mat& exp) +{ + const float maxDiffRatio = 0.005f; + int expArea = countNonZero( exp ); + int nonIntersectArea = countNonZero( mask != exp ); + + float curRatio = (float)nonIntersectArea / (float)expArea; + ts->printf( cvtest::TS::LOG, "nonIntersectArea/expArea = %f\n", curRatio ); + return curRatio < maxDiffRatio; +} + +void CV_GrabcutTest::run( int /* start_from */) +{ + cvtest::DefaultRngAuto defRng; + + Mat img = imread(string(ts->get_data_path()) + "shared/airplane.jpg"); + Mat mask_prob = imread(string(ts->get_data_path()) + "grabcut/mask_prob.png", 0); + Mat exp_mask1 = imread(string(ts->get_data_path()) + "grabcut/exp_mask1.png", 0); + Mat exp_mask2 = imread(string(ts->get_data_path()) + "grabcut/exp_mask2.png", 0); + + if (img.empty() || (!mask_prob.empty() && img.size() != mask_prob.size()) || + (!exp_mask1.empty() && img.size() != exp_mask1.size()) || + (!exp_mask2.empty() && img.size() != exp_mask2.size()) ) + { + ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA); + return; + } + + Rect rect(Point(24, 126), Point(483, 294)); + Mat exp_bgdModel, exp_fgdModel; + + Mat mask; + mask = Scalar(0); + Mat bgdModel, fgdModel; + grabCut( img, mask, rect, bgdModel, fgdModel, 0, GC_INIT_WITH_RECT ); + grabCut( img, mask, rect, bgdModel, fgdModel, 2, GC_EVAL ); + + // Multiply images by 255 for more visuality of test data. + if( mask_prob.empty() ) + { + mask.copyTo( mask_prob ); + imwrite(string(ts->get_data_path()) + "grabcut/mask_prob.png", mask_prob); + } + if( exp_mask1.empty() ) + { + exp_mask1 = (mask & 1) * 255; + imwrite(string(ts->get_data_path()) + "grabcut/exp_mask1.png", exp_mask1); + } + + if (!verify((mask & 1) * 255, exp_mask1)) + { + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + return; + } + + mask = mask_prob; + bgdModel.release(); + fgdModel.release(); + rect = Rect(); + grabCut( img, mask, rect, bgdModel, fgdModel, 0, GC_INIT_WITH_MASK ); + grabCut( img, mask, rect, bgdModel, fgdModel, 1, GC_EVAL ); + + if( exp_mask2.empty() ) + { + exp_mask2 = (mask & 1) * 255; + imwrite(string(ts->get_data_path()) + "grabcut/exp_mask2.png", exp_mask2); + } + + if (!verify((mask & 1) * 255, exp_mask2)) + { + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + return; + } + ts->set_failed_test_info(cvtest::TS::OK); +} + +TEST(Imgproc_GrabCut, regression) { CV_GrabcutTest test; test.safe_run(); } + +TEST(Imgproc_GrabCut, repeatability) +{ + cvtest::TS& ts = *cvtest::TS::ptr(); + + Mat image_1 = imread(string(ts.get_data_path()) + "grabcut/image1652.ppm", CV_LOAD_IMAGE_COLOR); + Mat mask_1 = imread(string(ts.get_data_path()) + "grabcut/mask1652.ppm", CV_LOAD_IMAGE_GRAYSCALE); + Rect roi_1(0, 0, 150, 150); + + Mat image_2 = image_1.clone(); + Mat mask_2 = mask_1.clone(); + Rect roi_2 = roi_1; + + Mat image_3 = image_1.clone(); + Mat mask_3 = mask_1.clone(); + Rect roi_3 = roi_1; + + Mat bgdModel_1, fgdModel_1; + Mat bgdModel_2, fgdModel_2; + Mat bgdModel_3, fgdModel_3; + + theRNG().state = 12378213; + grabCut(image_1, mask_1, roi_1, bgdModel_1, fgdModel_1, 1, GC_INIT_WITH_MASK); + theRNG().state = 12378213; + grabCut(image_2, mask_2, roi_2, bgdModel_2, fgdModel_2, 1, GC_INIT_WITH_MASK); + theRNG().state = 12378213; + grabCut(image_3, mask_3, roi_3, bgdModel_3, fgdModel_3, 1, GC_INIT_WITH_MASK); + + EXPECT_EQ(0, countNonZero(mask_1 != mask_2)); + EXPECT_EQ(0, countNonZero(mask_1 != mask_3)); + EXPECT_EQ(0, countNonZero(mask_2 != mask_3)); +} diff --git a/imgproc/test/test_histograms.cpp b/imgproc/test/test_histograms.cpp new file mode 100644 index 0000000..3ac1e94 --- /dev/null +++ b/imgproc/test/test_histograms.cpp @@ -0,0 +1,1837 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +class CV_BaseHistTest : public cvtest::BaseTest +{ +public: + enum { MAX_HIST = 12 }; + + CV_BaseHistTest(); + ~CV_BaseHistTest(); + void clear(); + +protected: + int read_params( CvFileStorage* fs ); + void run_func(void); + int prepare_test_case( int test_case_idx ); + int validate_test_results( int test_case_idx ); + virtual void init_hist( int test_case_idx, int i ); + + virtual void get_hist_params( int test_case_idx ); + virtual float** get_hist_ranges( int test_case_idx ); + + int max_log_size; + int max_cdims; + int cdims; + int dims[CV_MAX_DIM]; + int total_size; + int hist_type; + int hist_count; + int uniform; + int gen_random_hist; + double gen_hist_max_val, gen_hist_sparse_nz_ratio; + + int init_ranges; + int img_type; + int img_max_log_size; + double low, high, range_delta; + CvSize img_size; + + vector hist; + vector _ranges; + vector ranges; + bool test_cpp; +}; + + +CV_BaseHistTest::CV_BaseHistTest() +{ + test_case_count = 100; + max_log_size = 20; + img_max_log_size = 8; + max_cdims = 6; + hist_count = 1; + init_ranges = 0; + gen_random_hist = 0; + gen_hist_max_val = 100; + + test_cpp = false; +} + + +CV_BaseHistTest::~CV_BaseHistTest() +{ + clear(); +} + + +void CV_BaseHistTest::clear() +{ + cvtest::BaseTest::clear(); + for( size_t i = 0; i < hist.size(); i++ ) + cvReleaseHist( &hist[i] ); +} + + +int CV_BaseHistTest::read_params( CvFileStorage* fs ) +{ + int code = cvtest::BaseTest::read_params( fs ); + if( code < 0 ) + return code; + + test_case_count = cvReadInt( find_param( fs, "struct_count" ), test_case_count ); + max_log_size = cvReadInt( find_param( fs, "max_log_size" ), max_log_size ); + max_log_size = cvtest::clipInt( max_log_size, 1, 20 ); + img_max_log_size = cvReadInt( find_param( fs, "max_log_array_size" ), img_max_log_size ); + img_max_log_size = cvtest::clipInt( img_max_log_size, 1, 9 ); + + max_cdims = cvReadInt( find_param( fs, "max_cdims" ), max_cdims ); + max_cdims = cvtest::clipInt( max_cdims, 1, 6 ); + + return 0; +} + + +void CV_BaseHistTest::get_hist_params( int /*test_case_idx*/ ) +{ + RNG& rng = ts->get_rng(); + int i, max_dim_size, max_ni_dim_size = 31; + double hist_size; + + cdims = cvtest::randInt(rng) % max_cdims + 1; + hist_size = exp(cvtest::randReal(rng)*max_log_size*CV_LOG2); + max_dim_size = cvRound(pow(hist_size,1./cdims)); + total_size = 1; + uniform = cvtest::randInt(rng) % 2; + hist_type = cvtest::randInt(rng) % 2 ? CV_HIST_SPARSE : CV_HIST_ARRAY; + + for( i = 0; i < cdims; i++ ) + { + dims[i] = cvtest::randInt(rng) % (max_dim_size + 2) + 2; + if( !uniform ) + dims[i] = MIN(dims[i], max_ni_dim_size); + total_size *= dims[i]; + } + + img_type = cvtest::randInt(rng) % 2 ? CV_32F : CV_8U; + img_size.width = cvRound( exp(cvtest::randReal(rng) * img_max_log_size * CV_LOG2) ); + img_size.height = cvRound( exp(cvtest::randReal(rng) * img_max_log_size * CV_LOG2) ); + + if( img_type < CV_32F ) + { + low = cvtest::getMinVal(img_type); + high = cvtest::getMaxVal(img_type); + } + else + { + high = 1000; + low = -high; + } + + range_delta = (cvtest::randInt(rng) % 2)*(high-low)*0.05; +} + + +float** CV_BaseHistTest::get_hist_ranges( int /*test_case_idx*/ ) +{ + double _low = low + range_delta, _high = high - range_delta; + + if( !init_ranges ) + return 0; + + ranges.resize(cdims); + + if( uniform ) + { + _ranges.resize(cdims*2); + for( int i = 0; i < cdims; i++ ) + { + _ranges[i*2] = (float)_low; + _ranges[i*2+1] = (float)_high; + ranges[i] = &_ranges[i*2]; + } + } + else + { + int i, dims_sum = 0, ofs = 0; + for( i = 0; i < cdims; i++ ) + dims_sum += dims[i] + 1; + _ranges.resize(dims_sum); + + for( i = 0; i < cdims; i++ ) + { + int j, n = dims[i]; + // generate logarithmic scale + double delta, q, val; + for( j = 0; j < 10; j++ ) + { + q = 1. + (j+1)*0.1; + if( (pow(q,(double)n)-1)/(q-1.) >= _high-_low ) + break; + } + + if( j == 0 ) + { + delta = (_high-_low)/n; + q = 1.; + } + else + { + q = 1 + j*0.1; + delta = cvFloor((_high-_low)*(q-1)/(pow(q,(double)n) - 1)); + delta = MAX(delta, 1.); + } + val = _low; + + for( j = 0; j <= n; j++ ) + { + _ranges[j+ofs] = (float)MIN(val,_high); + val += delta; + delta *= q; + } + ranges[i] = &_ranges[ofs]; + ofs += n + 1; + } + } + + return &ranges[0]; +} + + +void CV_BaseHistTest::init_hist( int /*test_case_idx*/, int hist_i ) +{ + if( gen_random_hist ) + { + RNG& rng = ts->get_rng(); + + if( hist_type == CV_HIST_ARRAY ) + { + Mat h = cvarrToMat(hist[hist_i]->bins); + cvtest::randUni(rng, h, Scalar::all(0), Scalar::all(gen_hist_max_val) ); + } + else + { + CvArr* arr = hist[hist_i]->bins; + int i, j, totalSize = 1, nz_count; + int idx[CV_MAX_DIM]; + for( i = 0; i < cdims; i++ ) + totalSize *= dims[i]; + + nz_count = cvtest::randInt(rng) % MAX( totalSize/4, 100 ); + nz_count = MIN( nz_count, totalSize ); + + // a zero number of non-zero elements should be allowed + for( i = 0; i < nz_count; i++ ) + { + for( j = 0; j < cdims; j++ ) + idx[j] = cvtest::randInt(rng) % dims[j]; + cvSetRealND(arr, idx, cvtest::randReal(rng)*gen_hist_max_val); + } + } + } +} + + +int CV_BaseHistTest::prepare_test_case( int test_case_idx ) +{ + int i; + float** r; + + clear(); + + cvtest::BaseTest::prepare_test_case( test_case_idx ); + get_hist_params( test_case_idx ); + r = get_hist_ranges( test_case_idx ); + hist.resize(hist_count); + + for( i = 0; i < hist_count; i++ ) + { + hist[i] = cvCreateHist( cdims, dims, hist_type, r, uniform ); + init_hist( test_case_idx, i ); + } + test_cpp = (cvtest::randInt(ts->get_rng()) % 2) != 0; + + return 1; +} + + +void CV_BaseHistTest::run_func(void) +{ +} + + +int CV_BaseHistTest::validate_test_results( int /*test_case_idx*/ ) +{ + return 0; +} + + +////////////// testing operation for reading/writing individual histogram bins ////////////// + +class CV_QueryHistTest : public CV_BaseHistTest +{ +public: + CV_QueryHistTest(); + ~CV_QueryHistTest(); + void clear(); + +protected: + void run_func(void); + int prepare_test_case( int test_case_idx ); + int validate_test_results( int test_case_idx ); + void init_hist( int test_case_idx, int i ); + + CvMat* indices; + CvMat* values; + CvMat* values0; +}; + + + +CV_QueryHistTest::CV_QueryHistTest() +{ + hist_count = 1; + indices = 0; + values = 0; + values0 = 0; +} + + +CV_QueryHistTest::~CV_QueryHistTest() +{ + clear(); +} + + +void CV_QueryHistTest::clear() +{ + cvReleaseMat( &indices ); + cvReleaseMat( &values ); + cvReleaseMat( &values0 ); + CV_BaseHistTest::clear(); +} + + +void CV_QueryHistTest::init_hist( int /*test_case_idx*/, int i ) +{ + if( hist_type == CV_HIST_ARRAY ) + cvZero( hist[i]->bins ); +} + + +int CV_QueryHistTest::prepare_test_case( int test_case_idx ) +{ + int code = CV_BaseHistTest::prepare_test_case( test_case_idx ); + + if( code > 0 ) + { + int i, j, iters; + float default_value = 0.f; + RNG& rng = ts->get_rng(); + CvMat* bit_mask = 0; + int* idx; + + iters = (cvtest::randInt(rng) % MAX(total_size/10,100)) + 1; + iters = MIN( iters, total_size*9/10 + 1 ); + + indices = cvCreateMat( 1, iters*cdims, CV_32S ); + values = cvCreateMat( 1, iters, CV_32F ); + values0 = cvCreateMat( 1, iters, CV_32F ); + idx = indices->data.i; + + //printf( "total_size = %d, cdims = %d, iters = %d\n", total_size, cdims, iters ); + + bit_mask = cvCreateMat( 1, (total_size + 7)/8, CV_8U ); + cvZero( bit_mask ); + + #define GET_BIT(n) (bit_mask->data.ptr[(n)/8] & (1 << ((n)&7))) + #define SET_BIT(n) bit_mask->data.ptr[(n)/8] |= (1 << ((n)&7)) + + // set random histogram bins' values to the linear indices of the bins + for( i = 0; i < iters; i++ ) + { + int lin_idx = 0; + for( j = 0; j < cdims; j++ ) + { + int t = cvtest::randInt(rng) % dims[j]; + idx[i*cdims + j] = t; + lin_idx = lin_idx*dims[j] + t; + } + + if( cvtest::randInt(rng) % 8 || GET_BIT(lin_idx) ) + { + values0->data.fl[i] = (float)(lin_idx+1); + SET_BIT(lin_idx); + } + else + // some histogram bins will not be initialized intentionally, + // they should be equal to the default value + values0->data.fl[i] = default_value; + } + + // do the second pass to make values0 consistent with bit_mask + for( i = 0; i < iters; i++ ) + { + int lin_idx = 0; + for( j = 0; j < cdims; j++ ) + lin_idx = lin_idx*dims[j] + idx[i*cdims + j]; + + if( GET_BIT(lin_idx) ) + values0->data.fl[i] = (float)(lin_idx+1); + } + + cvReleaseMat( &bit_mask ); + } + + return code; +} + + +void CV_QueryHistTest::run_func(void) +{ + int i, iters = values->cols; + CvArr* h = hist[0]->bins; + const int* idx = indices->data.i; + float* val = values->data.fl; + float default_value = 0.f; + + // stage 1: write bins + if( cdims == 1 ) + for( i = 0; i < iters; i++ ) + { + float v0 = values0->data.fl[i]; + if( fabs(v0 - default_value) < FLT_EPSILON ) + continue; + if( !(i % 2) ) + { + if( !(i % 4) ) + cvSetReal1D( h, idx[i], v0 ); + else + *(float*)cvPtr1D( h, idx[i] ) = v0; + } + else + cvSetRealND( h, idx+i, v0 ); + } + else if( cdims == 2 ) + for( i = 0; i < iters; i++ ) + { + float v0 = values0->data.fl[i]; + if( fabs(v0 - default_value) < FLT_EPSILON ) + continue; + if( !(i % 2) ) + { + if( !(i % 4) ) + cvSetReal2D( h, idx[i*2], idx[i*2+1], v0 ); + else + *(float*)cvPtr2D( h, idx[i*2], idx[i*2+1] ) = v0; + } + else + cvSetRealND( h, idx+i*2, v0 ); + } + else if( cdims == 3 ) + for( i = 0; i < iters; i++ ) + { + float v0 = values0->data.fl[i]; + if( fabs(v0 - default_value) < FLT_EPSILON ) + continue; + if( !(i % 2) ) + { + if( !(i % 4) ) + cvSetReal3D( h, idx[i*3], idx[i*3+1], idx[i*3+2], v0 ); + else + *(float*)cvPtr3D( h, idx[i*3], idx[i*3+1], idx[i*3+2] ) = v0; + } + else + cvSetRealND( h, idx+i*3, v0 ); + } + else + for( i = 0; i < iters; i++ ) + { + float v0 = values0->data.fl[i]; + if( fabs(v0 - default_value) < FLT_EPSILON ) + continue; + if( !(i % 2) ) + cvSetRealND( h, idx+i*cdims, v0 ); + else + *(float*)cvPtrND( h, idx+i*cdims ) = v0; + } + + // stage 2: read bins + if( cdims == 1 ) + for( i = 0; i < iters; i++ ) + { + if( !(i % 2) ) + val[i] = *(float*)cvPtr1D( h, idx[i] ); + else + val[i] = (float)cvGetReal1D( h, idx[i] ); + } + else if( cdims == 2 ) + for( i = 0; i < iters; i++ ) + { + if( !(i % 2) ) + val[i] = *(float*)cvPtr2D( h, idx[i*2], idx[i*2+1] ); + else + val[i] = (float)cvGetReal2D( h, idx[i*2], idx[i*2+1] ); + } + else if( cdims == 3 ) + for( i = 0; i < iters; i++ ) + { + if( !(i % 2) ) + val[i] = *(float*)cvPtr3D( h, idx[i*3], idx[i*3+1], idx[i*3+2] ); + else + val[i] = (float)cvGetReal3D( h, idx[i*3], idx[i*3+1], idx[i*3+2] ); + } + else + for( i = 0; i < iters; i++ ) + { + if( !(i % 2) ) + val[i] = *(float*)cvPtrND( h, idx+i*cdims ); + else + val[i] = (float)cvGetRealND( h, idx+i*cdims ); + } +} + + +int CV_QueryHistTest::validate_test_results( int /*test_case_idx*/ ) +{ + int code = cvtest::TS::OK; + int i, j, iters = values->cols; + + for( i = 0; i < iters; i++ ) + { + float v = values->data.fl[i], v0 = values0->data.fl[i]; + + if( cvIsNaN(v) || cvIsInf(v) ) + { + ts->printf( cvtest::TS::LOG, "The bin #%d has invalid value\n", i ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + } + else if( fabs(v - v0) > FLT_EPSILON ) + { + ts->printf( cvtest::TS::LOG, "The bin #%d = %g, while it should be %g\n", i, v, v0 ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + } + + if( code < 0 ) + { + ts->printf( cvtest::TS::LOG, "The bin index = (" ); + for( j = 0; j < cdims; j++ ) + ts->printf( cvtest::TS::LOG, "%d%s", indices->data.i[i*cdims + j], + j < cdims-1 ? ", " : ")\n" ); + break; + } + } + + if( code < 0 ) + ts->set_failed_test_info( code ); + return code; +} + + +////////////// cvGetMinMaxHistValue ////////////// + +class CV_MinMaxHistTest : public CV_BaseHistTest +{ +public: + CV_MinMaxHistTest(); + +protected: + void run_func(void); + void init_hist(int, int); + int validate_test_results( int test_case_idx ); + int min_idx[CV_MAX_DIM], max_idx[CV_MAX_DIM]; + float min_val, max_val; + int min_idx0[CV_MAX_DIM], max_idx0[CV_MAX_DIM]; + float min_val0, max_val0; +}; + + + +CV_MinMaxHistTest::CV_MinMaxHistTest() +{ + hist_count = 1; + gen_random_hist = 1; +} + + +void CV_MinMaxHistTest::init_hist(int test_case_idx, int hist_i) +{ + int i, eq = 1; + RNG& rng = ts->get_rng(); + CV_BaseHistTest::init_hist( test_case_idx, hist_i ); + + for(;;) + { + for( i = 0; i < cdims; i++ ) + { + min_idx0[i] = cvtest::randInt(rng) % dims[i]; + max_idx0[i] = cvtest::randInt(rng) % dims[i]; + eq &= min_idx0[i] == max_idx0[i]; + } + if( !eq || total_size == 1 ) + break; + } + + min_val0 = (float)(-cvtest::randReal(rng)*10 - FLT_EPSILON); + max_val0 = (float)(cvtest::randReal(rng)*10 + FLT_EPSILON + gen_hist_max_val); + + if( total_size == 1 ) + min_val0 = max_val0; + + cvSetRealND( hist[0]->bins, min_idx0, min_val0 ); + cvSetRealND( hist[0]->bins, max_idx0, max_val0 ); +} + + +void CV_MinMaxHistTest::run_func(void) +{ + if( hist_type != CV_HIST_ARRAY && test_cpp ) + { + cv::SparseMat h((CvSparseMat*)hist[0]->bins); + double _min_val = 0, _max_val = 0; + cv::minMaxLoc(h, &_min_val, &_max_val, min_idx, max_idx ); + min_val = (float)_min_val; + max_val = (float)_max_val; + } + else + cvGetMinMaxHistValue( hist[0], &min_val, &max_val, min_idx, max_idx ); +} + + +int CV_MinMaxHistTest::validate_test_results( int /*test_case_idx*/ ) +{ + int code = cvtest::TS::OK; + + if( cvIsNaN(min_val) || cvIsInf(min_val) || + cvIsNaN(max_val) || cvIsInf(max_val) ) + { + ts->printf( cvtest::TS::LOG, + "The extrema histogram bin values are invalid (min = %g, max = %g)\n", min_val, max_val ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + } + else if( fabs(min_val - min_val0) > FLT_EPSILON || + fabs(max_val - max_val0) > FLT_EPSILON ) + { + ts->printf( cvtest::TS::LOG, + "The extrema histogram bin values are incorrect: (min = %g, should be = %g), (max = %g, should be = %g)\n", + min_val, min_val0, max_val, max_val0 ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + } + else + { + int i; + for( i = 0; i < cdims; i++ ) + { + if( min_idx[i] != min_idx0[i] || max_idx[i] != max_idx0[i] ) + { + ts->printf( cvtest::TS::LOG, + "The %d-th coordinates of extrema histogram bin values are incorrect: " + "(min = %d, should be = %d), (max = %d, should be = %d)\n", + i, min_idx[i], min_idx0[i], max_idx[i], max_idx0[i] ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + } + } + } + + if( code < 0 ) + ts->set_failed_test_info( code ); + return code; +} + + +////////////// cvNormalizeHist ////////////// + +class CV_NormHistTest : public CV_BaseHistTest +{ +public: + CV_NormHistTest(); + +protected: + int prepare_test_case( int test_case_idx ); + void run_func(void); + int validate_test_results( int test_case_idx ); + double factor; +}; + + + +CV_NormHistTest::CV_NormHistTest() +{ + hist_count = 1; + gen_random_hist = 1; + factor = 0; +} + + +int CV_NormHistTest::prepare_test_case( int test_case_idx ) +{ + int code = CV_BaseHistTest::prepare_test_case( test_case_idx ); + + if( code > 0 ) + { + RNG& rng = ts->get_rng(); + factor = cvtest::randReal(rng)*10 + 0.1; + if( hist_type == CV_HIST_SPARSE && + ((CvSparseMat*)hist[0]->bins)->heap->active_count == 0 ) + factor = 0; + } + + return code; +} + + +void CV_NormHistTest::run_func(void) +{ + if( hist_type != CV_HIST_ARRAY && test_cpp ) + { + cv::SparseMat h((CvSparseMat*)hist[0]->bins); + cv::normalize(h, h, factor, CV_L1); + cvReleaseSparseMat((CvSparseMat**)&hist[0]->bins); + hist[0]->bins = (CvSparseMat*)h; + } + else + cvNormalizeHist( hist[0], factor ); +} + + +int CV_NormHistTest::validate_test_results( int /*test_case_idx*/ ) +{ + int code = cvtest::TS::OK; + double sum = 0; + + if( hist_type == CV_HIST_ARRAY ) + { + int i; + const float* ptr = (float*)cvPtr1D( hist[0]->bins, 0 ); + + for( i = 0; i < total_size; i++ ) + sum += ptr[i]; + } + else + { + CvSparseMat* sparse = (CvSparseMat*)hist[0]->bins; + CvSparseMatIterator iterator; + CvSparseNode *node; + + for( node = cvInitSparseMatIterator( sparse, &iterator ); + node != 0; node = cvGetNextSparseNode( &iterator )) + { + sum += *(float*)CV_NODE_VAL(sparse,node); + } + } + + if( cvIsNaN(sum) || cvIsInf(sum) ) + { + ts->printf( cvtest::TS::LOG, + "The normalized histogram has invalid sum =%g\n", sum ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + } + else if( fabs(sum - factor) > FLT_EPSILON*10*fabs(factor) ) + { + ts->printf( cvtest::TS::LOG, + "The normalized histogram has incorrect sum =%g, while it should be =%g\n", sum, factor ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + } + + if( code < 0 ) + ts->set_failed_test_info( code ); + return code; +} + + +////////////// cvThreshHist ////////////// + +class CV_ThreshHistTest : public CV_BaseHistTest +{ +public: + CV_ThreshHistTest(); + ~CV_ThreshHistTest(); + void clear(); + +protected: + int prepare_test_case( int test_case_idx ); + void run_func(void); + int validate_test_results( int test_case_idx ); + CvMat* indices; + CvMat* values; + int orig_nz_count; + + double threshold; +}; + + + +CV_ThreshHistTest::CV_ThreshHistTest() +{ + hist_count = 1; + gen_random_hist = 1; + threshold = 0; + indices = values = 0; +} + + +CV_ThreshHistTest::~CV_ThreshHistTest() +{ + clear(); +} + + +void CV_ThreshHistTest::clear() +{ + cvReleaseMat( &indices ); + cvReleaseMat( &values ); + CV_BaseHistTest::clear(); +} + + +int CV_ThreshHistTest::prepare_test_case( int test_case_idx ) +{ + int code = CV_BaseHistTest::prepare_test_case( test_case_idx ); + + if( code > 0 ) + { + RNG& rng = ts->get_rng(); + threshold = cvtest::randReal(rng)*gen_hist_max_val; + + if( hist_type == CV_HIST_ARRAY ) + { + orig_nz_count = total_size; + + values = cvCreateMat( 1, total_size, CV_32F ); + memcpy( values->data.fl, cvPtr1D( hist[0]->bins, 0 ), total_size*sizeof(float) ); + } + else + { + CvSparseMat* sparse = (CvSparseMat*)hist[0]->bins; + CvSparseMatIterator iterator; + CvSparseNode* node; + int i, k; + + orig_nz_count = sparse->heap->active_count; + + values = cvCreateMat( 1, orig_nz_count+1, CV_32F ); + indices = cvCreateMat( 1, (orig_nz_count+1)*cdims, CV_32S ); + + for( node = cvInitSparseMatIterator( sparse, &iterator ), i = 0; + node != 0; node = cvGetNextSparseNode( &iterator ), i++ ) + { + const int* idx = CV_NODE_IDX(sparse,node); + + OPENCV_ASSERT( i < orig_nz_count, "CV_ThreshHistTest::prepare_test_case", "Buffer overflow" ); + + values->data.fl[i] = *(float*)CV_NODE_VAL(sparse,node); + for( k = 0; k < cdims; k++ ) + indices->data.i[i*cdims + k] = idx[k]; + } + + OPENCV_ASSERT( i == orig_nz_count, "Unmatched buffer size", + "CV_ThreshHistTest::prepare_test_case" ); + } + } + + return code; +} + + +void CV_ThreshHistTest::run_func(void) +{ + cvThreshHist( hist[0], threshold ); +} + + +int CV_ThreshHistTest::validate_test_results( int /*test_case_idx*/ ) +{ + int code = cvtest::TS::OK; + int i; + float* ptr0 = values->data.fl; + float* ptr = 0; + CvSparseMat* sparse = 0; + + if( hist_type == CV_HIST_ARRAY ) + ptr = (float*)cvPtr1D( hist[0]->bins, 0 ); + else + sparse = (CvSparseMat*)hist[0]->bins; + + if( code > 0 ) + { + for( i = 0; i < orig_nz_count; i++ ) + { + float v0 = ptr0[i], v; + + if( hist_type == CV_HIST_ARRAY ) + v = ptr[i]; + else + { + v = (float)cvGetRealND( sparse, indices->data.i + i*cdims ); + cvClearND( sparse, indices->data.i + i*cdims ); + } + + if( v0 <= threshold ) v0 = 0.f; + if( cvIsNaN(v) || cvIsInf(v) ) + { + ts->printf( cvtest::TS::LOG, "The %d-th bin is invalid (=%g)\n", i, v ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + break; + } + else if( fabs(v0 - v) > FLT_EPSILON*10*fabs(v0) ) + { + ts->printf( cvtest::TS::LOG, "The %d-th bin is incorrect (=%g, should be =%g)\n", i, v, v0 ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + break; + } + } + } + + if( code > 0 && hist_type == CV_HIST_SPARSE ) + { + if( sparse->heap->active_count > 0 ) + { + ts->printf( cvtest::TS::LOG, + "There some extra histogram bins in the sparse histogram after the thresholding\n" ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + } + } + + if( code < 0 ) + ts->set_failed_test_info( code ); + return code; +} + + +////////////// cvCompareHist ////////////// + +class CV_CompareHistTest : public CV_BaseHistTest +{ +public: + enum { MAX_METHOD = 4 }; + + CV_CompareHistTest(); +protected: + int prepare_test_case( int test_case_idx ); + void run_func(void); + int validate_test_results( int test_case_idx ); + double result[MAX_METHOD+1]; +}; + + + +CV_CompareHistTest::CV_CompareHistTest() +{ + hist_count = 2; + gen_random_hist = 1; +} + + +int CV_CompareHistTest::prepare_test_case( int test_case_idx ) +{ + int code = CV_BaseHistTest::prepare_test_case( test_case_idx ); + + return code; +} + + +void CV_CompareHistTest::run_func(void) +{ + int k; + if( hist_type != CV_HIST_ARRAY && test_cpp ) + { + cv::SparseMat h0((CvSparseMat*)hist[0]->bins); + cv::SparseMat h1((CvSparseMat*)hist[1]->bins); + for( k = 0; k < MAX_METHOD; k++ ) + result[k] = cv::compareHist(h0, h1, k); + } + else + for( k = 0; k < MAX_METHOD; k++ ) + result[k] = cvCompareHist( hist[0], hist[1], k ); +} + + +int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ ) +{ + int code = cvtest::TS::OK; + int i; + double result0[MAX_METHOD+1]; + double s0 = 0, s1 = 0, sq0 = 0, sq1 = 0, t; + + for( i = 0; i < MAX_METHOD; i++ ) + result0[i] = 0; + + if( hist_type == CV_HIST_ARRAY ) + { + float* ptr0 = (float*)cvPtr1D( hist[0]->bins, 0 ); + float* ptr1 = (float*)cvPtr1D( hist[1]->bins, 0 ); + + for( i = 0; i < total_size; i++ ) + { + double v0 = ptr0[i], v1 = ptr1[i]; + result0[CV_COMP_CORREL] += v0*v1; + result0[CV_COMP_INTERSECT] += MIN(v0,v1); + if( fabs(v0) > DBL_EPSILON ) + result0[CV_COMP_CHISQR] += (v0 - v1)*(v0 - v1)/v0; + s0 += v0; + s1 += v1; + sq0 += v0*v0; + sq1 += v1*v1; + result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1); + } + } + else + { + CvSparseMat* sparse0 = (CvSparseMat*)hist[0]->bins; + CvSparseMat* sparse1 = (CvSparseMat*)hist[1]->bins; + CvSparseMatIterator iterator; + CvSparseNode* node; + + for( node = cvInitSparseMatIterator( sparse0, &iterator ); + node != 0; node = cvGetNextSparseNode( &iterator ) ) + { + const int* idx = CV_NODE_IDX(sparse0, node); + double v0 = *(float*)CV_NODE_VAL(sparse0, node); + double v1 = (float)cvGetRealND(sparse1, idx); + + result0[CV_COMP_CORREL] += v0*v1; + result0[CV_COMP_INTERSECT] += MIN(v0,v1); + if( fabs(v0) > DBL_EPSILON ) + result0[CV_COMP_CHISQR] += (v0 - v1)*(v0 - v1)/v0; + s0 += v0; + sq0 += v0*v0; + result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1); + } + + for( node = cvInitSparseMatIterator( sparse1, &iterator ); + node != 0; node = cvGetNextSparseNode( &iterator ) ) + { + double v1 = *(float*)CV_NODE_VAL(sparse1, node); + s1 += v1; + sq1 += v1*v1; + } + } + + t = (sq0 - s0*s0/total_size)*(sq1 - s1*s1/total_size); + result0[CV_COMP_CORREL] = fabs(t) > DBL_EPSILON ? + (result0[CV_COMP_CORREL] - s0*s1/total_size)/sqrt(t) : 1; + + s1 *= s0; + s0 = result0[CV_COMP_BHATTACHARYYA]; + s0 = 1. - s0*(s1 > FLT_EPSILON ? 1./sqrt(s1) : 1.); + result0[CV_COMP_BHATTACHARYYA] = sqrt(MAX(s0,0.)); + + for( i = 0; i < MAX_METHOD; i++ ) + { + double v = result[i], v0 = result0[i]; + const char* method_name = + i == CV_COMP_CHISQR ? "Chi-Square" : + i == CV_COMP_CORREL ? "Correlation" : + i == CV_COMP_INTERSECT ? "Intersection" : + i == CV_COMP_BHATTACHARYYA ? "Bhattacharyya" : "Unknown"; + + if( cvIsNaN(v) || cvIsInf(v) ) + { + ts->printf( cvtest::TS::LOG, "The comparison result using the method #%d (%s) is invalid (=%g)\n", + i, method_name, v ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + break; + } + else if( fabs(v0 - v) > FLT_EPSILON*10*MAX(fabs(v0),0.1) ) + { + ts->printf( cvtest::TS::LOG, "The comparison result using the method #%d (%s)\n\tis inaccurate (=%g, should be =%g)\n", + i, method_name, v, v0 ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + break; + } + } + + if( code < 0 ) + ts->set_failed_test_info( code ); + return code; +} + + +////////////// cvCalcHist ////////////// + +class CV_CalcHistTest : public CV_BaseHistTest +{ +public: + CV_CalcHistTest(); + ~CV_CalcHistTest(); + void clear(); + +protected: + int prepare_test_case( int test_case_idx ); + void run_func(void); + int validate_test_results( int test_case_idx ); + IplImage* images[CV_MAX_DIM+1]; + int channels[CV_MAX_DIM+1]; +}; + + + +CV_CalcHistTest::CV_CalcHistTest() +{ + int i; + + hist_count = 2; + gen_random_hist = 0; + init_ranges = 1; + + for( i = 0; i <= CV_MAX_DIM; i++ ) + { + images[i] = 0; + channels[i] = 0; + } +} + + +CV_CalcHistTest::~CV_CalcHistTest() +{ + clear(); +} + + +void CV_CalcHistTest::clear() +{ + int i; + + for( i = 0; i <= CV_MAX_DIM; i++ ) + cvReleaseImage( &images[i] ); + + CV_BaseHistTest::clear(); +} + + +int CV_CalcHistTest::prepare_test_case( int test_case_idx ) +{ + int code = CV_BaseHistTest::prepare_test_case( test_case_idx ); + + if( code > 0 ) + { + RNG& rng = ts->get_rng(); + int i; + + for( i = 0; i <= CV_MAX_DIM; i++ ) + { + if( i < cdims ) + { + int nch = 1; //cvtest::randInt(rng) % 3 + 1; + images[i] = cvCreateImage( img_size, + img_type == CV_8U ? IPL_DEPTH_8U : IPL_DEPTH_32F, nch ); + channels[i] = cvtest::randInt(rng) % nch; + Mat images_i = cvarrToMat(images[i]); + + cvtest::randUni( rng, images_i, Scalar::all(low), Scalar::all(high) ); + } + else if( i == CV_MAX_DIM && cvtest::randInt(rng) % 2 ) + { + // create mask + images[i] = cvCreateImage( img_size, IPL_DEPTH_8U, 1 ); + Mat images_i = cvarrToMat(images[i]); + + // make ~25% pixels in the mask non-zero + cvtest::randUni( rng, images_i, Scalar::all(-2), Scalar::all(2) ); + } + } + } + + return code; +} + + +void CV_CalcHistTest::run_func(void) +{ + cvCalcHist( images, hist[0], 0, images[CV_MAX_DIM] ); +} + + +static void +cvTsCalcHist( IplImage** _images, CvHistogram* hist, IplImage* _mask, int* channels ) +{ + int x, y, k, cdims; + union + { + float* fl; + uchar* ptr; + } + plane[CV_MAX_DIM]; + int nch[CV_MAX_DIM]; + int dims[CV_MAX_DIM]; + int uniform = CV_IS_UNIFORM_HIST(hist); + CvSize img_size = cvGetSize(_images[0]); + CvMat images[CV_MAX_DIM], mask = cvMat(1,1,CV_8U); + int img_depth = _images[0]->depth; + + cdims = cvGetDims( hist->bins, dims ); + + cvZero( hist->bins ); + + for( k = 0; k < cdims; k++ ) + { + cvGetMat( _images[k], &images[k] ); + nch[k] = _images[k]->nChannels; + } + + if( _mask ) + cvGetMat( _mask, &mask ); + + for( y = 0; y < img_size.height; y++ ) + { + const uchar* mptr = _mask ? &CV_MAT_ELEM(mask, uchar, y, 0 ) : 0; + + if( img_depth == IPL_DEPTH_8U ) + for( k = 0; k < cdims; k++ ) + plane[k].ptr = &CV_MAT_ELEM(images[k], uchar, y, 0 ) + channels[k]; + else + for( k = 0; k < cdims; k++ ) + plane[k].fl = &CV_MAT_ELEM(images[k], float, y, 0 ) + channels[k]; + + for( x = 0; x < img_size.width; x++ ) + { + float val[CV_MAX_DIM]; + int idx[CV_MAX_DIM]; + + if( mptr && !mptr[x] ) + continue; + if( img_depth == IPL_DEPTH_8U ) + for( k = 0; k < cdims; k++ ) + val[k] = plane[k].ptr[x*nch[k]]; + else + for( k = 0; k < cdims; k++ ) + val[k] = plane[k].fl[x*nch[k]]; + + idx[cdims-1] = -1; + + if( uniform ) + { + for( k = 0; k < cdims; k++ ) + { + double v = val[k], lo = hist->thresh[k][0], hi = hist->thresh[k][1]; + idx[k] = cvFloor((v - lo)*dims[k]/(hi - lo)); + if( idx[k] < 0 || idx[k] >= dims[k] ) + break; + } + } + else + { + for( k = 0; k < cdims; k++ ) + { + float v = val[k]; + float* t = hist->thresh2[k]; + int j, n = dims[k]; + + for( j = 0; j <= n; j++ ) + if( v < t[j] ) + break; + if( j <= 0 || j > n ) + break; + idx[k] = j-1; + } + } + + if( k < cdims ) + continue; + + (*(float*)cvPtrND( hist->bins, idx ))++; + } + } +} + + +int CV_CalcHistTest::validate_test_results( int /*test_case_idx*/ ) +{ + int code = cvtest::TS::OK; + double diff; + cvTsCalcHist( images, hist[1], images[CV_MAX_DIM], channels ); + diff = cvCompareHist( hist[0], hist[1], CV_COMP_CHISQR ); + if( diff > DBL_EPSILON ) + { + ts->printf( cvtest::TS::LOG, "The histogram does not match to the reference one\n" ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + + } + + if( code < 0 ) + ts->set_failed_test_info( code ); + return code; +} + + +CV_CalcHistTest hist_calc_test; + + + +////////////// cvCalcBackProject ////////////// + +class CV_CalcBackProjectTest : public CV_BaseHistTest +{ +public: + CV_CalcBackProjectTest(); + ~CV_CalcBackProjectTest(); + void clear(); + +protected: + int prepare_test_case( int test_case_idx ); + void run_func(void); + int validate_test_results( int test_case_idx ); + IplImage* images[CV_MAX_DIM+3]; + int channels[CV_MAX_DIM+3]; +}; + + + +CV_CalcBackProjectTest::CV_CalcBackProjectTest() +{ + int i; + + hist_count = 1; + gen_random_hist = 0; + init_ranges = 1; + + for( i = 0; i < CV_MAX_DIM+3; i++ ) + { + images[i] = 0; + channels[i] = 0; + } +} + + +CV_CalcBackProjectTest::~CV_CalcBackProjectTest() +{ + clear(); +} + + +void CV_CalcBackProjectTest::clear() +{ + int i; + + for( i = 0; i < CV_MAX_DIM+3; i++ ) + cvReleaseImage( &images[i] ); + + CV_BaseHistTest::clear(); +} + + +int CV_CalcBackProjectTest::prepare_test_case( int test_case_idx ) +{ + int code = CV_BaseHistTest::prepare_test_case( test_case_idx ); + + if( code > 0 ) + { + RNG& rng = ts->get_rng(); + int i, j, n, img_len = img_size.width*img_size.height; + + for( i = 0; i < CV_MAX_DIM + 3; i++ ) + { + if( i < cdims ) + { + int nch = 1; //cvtest::randInt(rng) % 3 + 1; + images[i] = cvCreateImage( img_size, + img_type == CV_8U ? IPL_DEPTH_8U : IPL_DEPTH_32F, nch ); + channels[i] = cvtest::randInt(rng) % nch; + + Mat images_i = cvarrToMat(images[i]); + cvtest::randUni( rng, images_i, Scalar::all(low), Scalar::all(high) ); + } + else if( i == CV_MAX_DIM && cvtest::randInt(rng) % 2 ) + { + // create mask + images[i] = cvCreateImage( img_size, IPL_DEPTH_8U, 1 ); + Mat images_i = cvarrToMat(images[i]); + // make ~25% pixels in the mask non-zero + cvtest::randUni( rng, images_i, Scalar::all(-2), Scalar::all(2) ); + } + else if( i > CV_MAX_DIM ) + { + images[i] = cvCreateImage( img_size, images[0]->depth, 1 ); + } + } + + cvTsCalcHist( images, hist[0], images[CV_MAX_DIM], channels ); + + // now modify the images a bit to add some zeros go to the backprojection + n = cvtest::randInt(rng) % (img_len/20+1); + for( i = 0; i < cdims; i++ ) + { + char* data = images[i]->imageData; + for( j = 0; j < n; j++ ) + { + int idx = cvtest::randInt(rng) % img_len; + double val = cvtest::randReal(rng)*(high - low) + low; + + if( img_type == CV_8U ) + ((uchar*)data)[idx] = (uchar)cvRound(val); + else + ((float*)data)[idx] = (float)val; + } + } + } + + return code; +} + + +void CV_CalcBackProjectTest::run_func(void) +{ + cvCalcBackProject( images, images[CV_MAX_DIM+1], hist[0] ); +} + + +static void +cvTsCalcBackProject( IplImage** images, IplImage* dst, CvHistogram* hist, int* channels ) +{ + int x, y, k, cdims; + union + { + float* fl; + uchar* ptr; + } + plane[CV_MAX_DIM]; + int nch[CV_MAX_DIM]; + int dims[CV_MAX_DIM]; + int uniform = CV_IS_UNIFORM_HIST(hist); + CvSize img_size = cvGetSize(images[0]); + int img_depth = images[0]->depth; + + cdims = cvGetDims( hist->bins, dims ); + + for( k = 0; k < cdims; k++ ) + nch[k] = images[k]->nChannels; + + for( y = 0; y < img_size.height; y++ ) + { + if( img_depth == IPL_DEPTH_8U ) + for( k = 0; k < cdims; k++ ) + plane[k].ptr = &CV_IMAGE_ELEM(images[k], uchar, y, 0 ) + channels[k]; + else + for( k = 0; k < cdims; k++ ) + plane[k].fl = &CV_IMAGE_ELEM(images[k], float, y, 0 ) + channels[k]; + + for( x = 0; x < img_size.width; x++ ) + { + float val[CV_MAX_DIM]; + float bin_val = 0; + int idx[CV_MAX_DIM]; + + if( img_depth == IPL_DEPTH_8U ) + for( k = 0; k < cdims; k++ ) + val[k] = plane[k].ptr[x*nch[k]]; + else + for( k = 0; k < cdims; k++ ) + val[k] = plane[k].fl[x*nch[k]]; + idx[cdims-1] = -1; + + if( uniform ) + { + for( k = 0; k < cdims; k++ ) + { + double v = val[k], lo = hist->thresh[k][0], hi = hist->thresh[k][1]; + idx[k] = cvFloor((v - lo)*dims[k]/(hi - lo)); + if( idx[k] < 0 || idx[k] >= dims[k] ) + break; + } + } + else + { + for( k = 0; k < cdims; k++ ) + { + float v = val[k]; + float* t = hist->thresh2[k]; + int j, n = dims[k]; + + for( j = 0; j <= n; j++ ) + if( v < t[j] ) + break; + if( j <= 0 || j > n ) + break; + idx[k] = j-1; + } + } + + if( k == cdims ) + bin_val = (float)cvGetRealND( hist->bins, idx ); + + if( img_depth == IPL_DEPTH_8U ) + { + int t = cvRound(bin_val); + CV_IMAGE_ELEM( dst, uchar, y, x ) = saturate_cast(t); + } + else + CV_IMAGE_ELEM( dst, float, y, x ) = bin_val; + } + } +} + + +int CV_CalcBackProjectTest::validate_test_results( int /*test_case_idx*/ ) +{ + int code = cvtest::TS::OK; + + cvTsCalcBackProject( images, images[CV_MAX_DIM+2], hist[0], channels ); + Mat a = cvarrToMat(images[CV_MAX_DIM+1]), b = cvarrToMat(images[CV_MAX_DIM+2]); + double threshold = a.depth() == CV_8U ? 2 : FLT_EPSILON; + code = cvtest::cmpEps2( ts, a, b, threshold, true, "Back project image" ); + + if( code < 0 ) + ts->set_failed_test_info( code ); + + return code; +} + + +////////////// cvCalcBackProjectPatch ////////////// + +class CV_CalcBackProjectPatchTest : public CV_BaseHistTest +{ +public: + CV_CalcBackProjectPatchTest(); + ~CV_CalcBackProjectPatchTest(); + void clear(); + +protected: + int prepare_test_case( int test_case_idx ); + void run_func(void); + int validate_test_results( int test_case_idx ); + IplImage* images[CV_MAX_DIM+2]; + int channels[CV_MAX_DIM+2]; + + CvSize patch_size; + double factor; + int method; +}; + + + +CV_CalcBackProjectPatchTest::CV_CalcBackProjectPatchTest() +{ + int i; + + hist_count = 1; + gen_random_hist = 0; + init_ranges = 1; + img_max_log_size = 6; + + for( i = 0; i < CV_MAX_DIM+2; i++ ) + { + images[i] = 0; + channels[i] = 0; + } +} + + +CV_CalcBackProjectPatchTest::~CV_CalcBackProjectPatchTest() +{ + clear(); +} + + +void CV_CalcBackProjectPatchTest::clear() +{ + int i; + + for( i = 0; i < CV_MAX_DIM+2; i++ ) + cvReleaseImage( &images[i] ); + + CV_BaseHistTest::clear(); +} + + +int CV_CalcBackProjectPatchTest::prepare_test_case( int test_case_idx ) +{ + int code = CV_BaseHistTest::prepare_test_case( test_case_idx ); + + if( code > 0 ) + { + RNG& rng = ts->get_rng(); + int i, j, n, img_len = img_size.width*img_size.height; + + patch_size.width = cvtest::randInt(rng) % img_size.width + 1; + patch_size.height = cvtest::randInt(rng) % img_size.height + 1; + patch_size.width = MIN( patch_size.width, 30 ); + patch_size.height = MIN( patch_size.height, 30 ); + + factor = 1.; + method = cvtest::randInt(rng) % CV_CompareHistTest::MAX_METHOD; + + for( i = 0; i < CV_MAX_DIM + 2; i++ ) + { + if( i < cdims ) + { + int nch = 1; //cvtest::randInt(rng) % 3 + 1; + images[i] = cvCreateImage( img_size, + img_type == CV_8U ? IPL_DEPTH_8U : IPL_DEPTH_32F, nch ); + channels[i] = cvtest::randInt(rng) % nch; + + Mat images_i = cvarrToMat(images[i]); + cvtest::randUni( rng, images_i, Scalar::all(low), Scalar::all(high) ); + } + else if( i >= CV_MAX_DIM ) + { + images[i] = cvCreateImage( + cvSize(img_size.width - patch_size.width + 1, + img_size.height - patch_size.height + 1), + IPL_DEPTH_32F, 1 ); + } + } + + cvTsCalcHist( images, hist[0], 0, channels ); + cvNormalizeHist( hist[0], factor ); + + // now modify the images a bit + n = cvtest::randInt(rng) % (img_len/10+1); + for( i = 0; i < cdims; i++ ) + { + char* data = images[i]->imageData; + for( j = 0; j < n; j++ ) + { + int idx = cvtest::randInt(rng) % img_len; + double val = cvtest::randReal(rng)*(high - low) + low; + + if( img_type == CV_8U ) + ((uchar*)data)[idx] = (uchar)cvRound(val); + else + ((float*)data)[idx] = (float)val; + } + } + } + + return code; +} + + +void CV_CalcBackProjectPatchTest::run_func(void) +{ + cvCalcBackProjectPatch( images, images[CV_MAX_DIM], patch_size, hist[0], method, factor ); +} + + +static void +cvTsCalcBackProjectPatch( IplImage** images, IplImage* dst, CvSize patch_size, + CvHistogram* hist, int method, + double factor, int* channels ) +{ + CvHistogram* model = 0; + + IplImage imgstub[CV_MAX_DIM], *img[CV_MAX_DIM]; + IplROI roi; + int i, dims; + int x, y; + CvSize size = cvGetSize(dst); + + dims = cvGetDims( hist->bins ); + cvCopyHist( hist, &model ); + cvNormalizeHist( hist, factor ); + cvZero( dst ); + + for( i = 0; i < dims; i++ ) + { + CvMat stub, *mat; + mat = cvGetMat( images[i], &stub, 0, 0 ); + img[i] = cvGetImage( mat, &imgstub[i] ); + img[i]->roi = &roi; + } + + roi.coi = 0; + + for( y = 0; y < size.height; y++ ) + { + for( x = 0; x < size.width; x++ ) + { + double result; + + roi.xOffset = x; + roi.yOffset = y; + roi.width = patch_size.width; + roi.height = patch_size.height; + + cvTsCalcHist( img, model, 0, channels ); + cvNormalizeHist( model, factor ); + result = cvCompareHist( model, hist, method ); + CV_IMAGE_ELEM( dst, float, y, x ) = (float)result; + } + } + + cvReleaseHist( &model ); +} + + +int CV_CalcBackProjectPatchTest::validate_test_results( int /*test_case_idx*/ ) +{ + int code = cvtest::TS::OK; + double err_level = 5e-3; + + cvTsCalcBackProjectPatch( images, images[CV_MAX_DIM+1], + patch_size, hist[0], method, factor, channels ); + + Mat a = cvarrToMat(images[CV_MAX_DIM]), b = cvarrToMat(images[CV_MAX_DIM+1]); + code = cvtest::cmpEps2( ts, a, b, err_level, true, "BackProjectPatch result" ); + + if( code < 0 ) + ts->set_failed_test_info( code ); + + return code; +} + + +////////////// cvCalcBayesianProb ////////////// + +class CV_BayesianProbTest : public CV_BaseHistTest +{ +public: + enum { MAX_METHOD = 4 }; + + CV_BayesianProbTest(); +protected: + int prepare_test_case( int test_case_idx ); + void run_func(void); + int validate_test_results( int test_case_idx ); + void init_hist( int test_case_idx, int i ); + void get_hist_params( int test_case_idx ); +}; + + + +CV_BayesianProbTest::CV_BayesianProbTest() +{ + hist_count = CV_MAX_DIM; + gen_random_hist = 1; +} + + +void CV_BayesianProbTest::get_hist_params( int test_case_idx ) +{ + CV_BaseHistTest::get_hist_params( test_case_idx ); + hist_type = CV_HIST_ARRAY; +} + + +void CV_BayesianProbTest::init_hist( int test_case_idx, int hist_i ) +{ + if( hist_i < hist_count/2 ) + CV_BaseHistTest::init_hist( test_case_idx, hist_i ); +} + + +int CV_BayesianProbTest::prepare_test_case( int test_case_idx ) +{ + RNG& rng = ts->get_rng(); + + hist_count = (cvtest::randInt(rng) % (MAX_HIST/2-1) + 2)*2; + hist_count = MIN( hist_count, MAX_HIST ); + int code = CV_BaseHistTest::prepare_test_case( test_case_idx ); + + return code; +} + + +void CV_BayesianProbTest::run_func(void) +{ + cvCalcBayesianProb( &hist[0], hist_count/2, &hist[hist_count/2] ); +} + + +int CV_BayesianProbTest::validate_test_results( int /*test_case_idx*/ ) +{ + int code = cvtest::TS::OK; + int i, j, n = hist_count/2; + double s[CV_MAX_DIM]; + const double err_level = 1e-5; + + for( i = 0; i < total_size; i++ ) + { + double sum = 0; + for( j = 0; j < n; j++ ) + { + double v = hist[j]->mat.data.fl[i]; + sum += v; + s[j] = v; + } + sum = sum > DBL_EPSILON ? 1./sum : 0; + + for( j = 0; j < n; j++ ) + { + double v0 = s[j]*sum; + double v = hist[j+n]->mat.data.fl[i]; + + if( cvIsNaN(v) || cvIsInf(v) ) + { + ts->printf( cvtest::TS::LOG, + "The element #%d in the destination histogram #%d is invalid (=%g)\n", + i, j, v ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + break; + } + else if( fabs(v0 - v) > err_level*fabs(v0) ) + { + ts->printf( cvtest::TS::LOG, + "The element #%d in the destination histogram #%d is inaccurate (=%g, should be =%g)\n", + i, j, v, v0 ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + break; + } + } + if( j < n ) + break; + } + + if( code < 0 ) + ts->set_failed_test_info( code ); + return code; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////// + +TEST(Imgproc_Hist_Calc, accuracy) { CV_CalcHistTest test; test.safe_run(); } +TEST(Imgproc_Hist_Query, accuracy) { CV_QueryHistTest test; test.safe_run(); } + +TEST(Imgproc_Hist_Compare, accuracy) { CV_CompareHistTest test; test.safe_run(); } +TEST(Imgproc_Hist_Threshold, accuracy) { CV_ThreshHistTest test; test.safe_run(); } +TEST(Imgproc_Hist_Normalize, accuracy) { CV_NormHistTest test; test.safe_run(); } +TEST(Imgproc_Hist_MinMaxVal, accuracy) { CV_MinMaxHistTest test; test.safe_run(); } + +TEST(Imgproc_Hist_CalcBackProject, accuracy) { CV_CalcBackProjectTest test; test.safe_run(); } +TEST(Imgproc_Hist_CalcBackProjectPatch, accuracy) { CV_CalcBackProjectPatchTest test; test.safe_run(); } +TEST(Imgproc_Hist_BayesianProb, accuracy) { CV_BayesianProbTest test; test.safe_run(); } + +/* End Of File */ diff --git a/imgproc/test/test_imgwarp.cpp b/imgproc/test/test_imgwarp.cpp new file mode 100644 index 0000000..c43ecd4 --- /dev/null +++ b/imgproc/test/test_imgwarp.cpp @@ -0,0 +1,1519 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +class CV_ImgWarpBaseTest : public cvtest::ArrayTest +{ +public: + CV_ImgWarpBaseTest( bool warp_matrix ); + +protected: + int read_params( CvFileStorage* fs ); + int prepare_test_case( int test_case_idx ); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ); + void fill_array( int test_case_idx, int i, int j, Mat& arr ); + + int interpolation; + int max_interpolation; + double spatial_scale_zoom, spatial_scale_decimate; +}; + + +CV_ImgWarpBaseTest::CV_ImgWarpBaseTest( bool warp_matrix ) +{ + test_array[INPUT].push_back(NULL); + if( warp_matrix ) + test_array[INPUT].push_back(NULL); + test_array[INPUT_OUTPUT].push_back(NULL); + test_array[REF_INPUT_OUTPUT].push_back(NULL); + max_interpolation = 5; + interpolation = 0; + element_wise_relative_error = false; + spatial_scale_zoom = 0.01; + spatial_scale_decimate = 0.005; +} + + +int CV_ImgWarpBaseTest::read_params( CvFileStorage* fs ) +{ + int code = cvtest::ArrayTest::read_params( fs ); + return code; +} + + +void CV_ImgWarpBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ) +{ + cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high ); + if( CV_MAT_DEPTH(type) == CV_32F ) + { + low = Scalar::all(-10.); + high = Scalar::all(10); + } +} + + +void CV_ImgWarpBaseTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + int depth = cvtest::randInt(rng) % 3; + int cn = cvtest::randInt(rng) % 3 + 1; + cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : CV_32F; + cn += cn == 2; + + types[INPUT][0] = types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(depth, cn); + if( test_array[INPUT].size() > 1 ) + types[INPUT][1] = cvtest::randInt(rng) & 1 ? CV_32FC1 : CV_64FC1; + + interpolation = cvtest::randInt(rng) % max_interpolation; +} + + +void CV_ImgWarpBaseTest::fill_array( int test_case_idx, int i, int j, Mat& arr ) +{ + if( i != INPUT || j != 0 ) + cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr ); +} + +int CV_ImgWarpBaseTest::prepare_test_case( int test_case_idx ) +{ + int code = cvtest::ArrayTest::prepare_test_case( test_case_idx ); + Mat& img = test_mat[INPUT][0]; + int i, j, cols = img.cols; + int type = img.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); + double scale = depth == CV_16U ? 1000. : 255.*0.5; + double space_scale = spatial_scale_decimate; + vector buffer(img.cols*cn); + + if( code <= 0 ) + return code; + + if( test_mat[INPUT_OUTPUT][0].cols >= img.cols && + test_mat[INPUT_OUTPUT][0].rows >= img.rows ) + space_scale = spatial_scale_zoom; + + for( i = 0; i < img.rows; i++ ) + { + uchar* ptr = img.ptr(i); + switch( cn ) + { + case 1: + for( j = 0; j < cols; j++ ) + buffer[j] = (float)((sin((i+1)*space_scale)*sin((j+1)*space_scale)+1.)*scale); + break; + case 2: + for( j = 0; j < cols; j++ ) + { + buffer[j*2] = (float)((sin((i+1)*space_scale)+1.)*scale); + buffer[j*2+1] = (float)((sin((i+j)*space_scale)+1.)*scale); + } + break; + case 3: + for( j = 0; j < cols; j++ ) + { + buffer[j*3] = (float)((sin((i+1)*space_scale)+1.)*scale); + buffer[j*3+1] = (float)((sin(j*space_scale)+1.)*scale); + buffer[j*3+2] = (float)((sin((i+j)*space_scale)+1.)*scale); + } + break; + case 4: + for( j = 0; j < cols; j++ ) + { + buffer[j*4] = (float)((sin((i+1)*space_scale)+1.)*scale); + buffer[j*4+1] = (float)((sin(j*space_scale)+1.)*scale); + buffer[j*4+2] = (float)((sin((i+j)*space_scale)+1.)*scale); + buffer[j*4+3] = (float)((sin((i-j)*space_scale)+1.)*scale); + } + break; + default: + assert(0); + } + + /*switch( depth ) + { + case CV_8U: + for( j = 0; j < cols*cn; j++ ) + ptr[j] = (uchar)cvRound(buffer[j]); + break; + case CV_16U: + for( j = 0; j < cols*cn; j++ ) + ((ushort*)ptr)[j] = (ushort)cvRound(buffer[j]); + break; + case CV_32F: + for( j = 0; j < cols*cn; j++ ) + ((float*)ptr)[j] = (float)buffer[j]; + break; + default: + assert(0); + }*/ + cv::Mat src(1, cols*cn, CV_32F, &buffer[0]); + cv::Mat dst(1, cols*cn, depth, ptr); + src.convertTo(dst, dst.type()); + } + + return code; +} + + +///////////////////////// + +class CV_ResizeTest : public CV_ImgWarpBaseTest +{ +public: + CV_ResizeTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void run_func(); + void prepare_to_validation( int /*test_case_idx*/ ); + double get_success_error_level( int test_case_idx, int i, int j ); +}; + + +CV_ResizeTest::CV_ResizeTest() : CV_ImgWarpBaseTest( false ) +{ +} + + +void CV_ResizeTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + CvSize sz; + + sz.width = (cvtest::randInt(rng) % sizes[INPUT][0].width) + 1; + sz.height = (cvtest::randInt(rng) % sizes[INPUT][0].height) + 1; + + if( cvtest::randInt(rng) & 1 ) + { + int xfactor = cvtest::randInt(rng) % 10 + 1; + int yfactor = cvtest::randInt(rng) % 10 + 1; + + if( cvtest::randInt(rng) & 1 ) + yfactor = xfactor; + + sz.width = sizes[INPUT][0].width / xfactor; + sz.width = MAX(sz.width,1); + sz.height = sizes[INPUT][0].height / yfactor; + sz.height = MAX(sz.height,1); + sizes[INPUT][0].width = sz.width * xfactor; + sizes[INPUT][0].height = sz.height * yfactor; + } + + if( cvtest::randInt(rng) & 1 ) + sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = sz; + else + { + sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = sizes[INPUT][0]; + sizes[INPUT][0] = sz; + } + if( interpolation == 4 && + (MIN(sizes[INPUT][0].width,sizes[INPUT_OUTPUT][0].width) < 4 || + MIN(sizes[INPUT][0].height,sizes[INPUT_OUTPUT][0].height) < 4)) + interpolation = 2; +} + + +void CV_ResizeTest::run_func() +{ + cvResize( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], interpolation ); +} + + +double CV_ResizeTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 1e-1; +} + + +void CV_ResizeTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + CvMat _src = test_mat[INPUT][0], _dst = test_mat[REF_INPUT_OUTPUT][0]; + CvMat *src = &_src, *dst = &_dst; + int i, j, k; + CvMat* x_idx = cvCreateMat( 1, dst->cols, CV_32SC1 ); + CvMat* y_idx = cvCreateMat( 1, dst->rows, CV_32SC1 ); + int* x_tab = x_idx->data.i; + int elem_size = CV_ELEM_SIZE(src->type); + int drows = dst->rows, dcols = dst->cols; + + if( interpolation == CV_INTER_NN ) + { + for( j = 0; j < dcols; j++ ) + { + int t = (j*src->cols*2 + MIN(src->cols,dcols) - 1)/(dcols*2); + t -= t >= src->cols; + x_idx->data.i[j] = t*elem_size; + } + + for( j = 0; j < drows; j++ ) + { + int t = (j*src->rows*2 + MIN(src->rows,drows) - 1)/(drows*2); + t -= t >= src->rows; + y_idx->data.i[j] = t; + } + } + else + { + double scale_x = (double)src->cols/dcols; + double scale_y = (double)src->rows/drows; + + for( j = 0; j < dcols; j++ ) + { + double f = ((j+0.5)*scale_x - 0.5); + i = cvRound(f); + x_idx->data.i[j] = (i < 0 ? 0 : i >= src->cols ? src->cols - 1 : i)*elem_size; + } + + for( j = 0; j < drows; j++ ) + { + double f = ((j+0.5)*scale_y - 0.5); + i = cvRound(f); + y_idx->data.i[j] = i < 0 ? 0 : i >= src->rows ? src->rows - 1 : i; + } + } + + for( i = 0; i < drows; i++ ) + { + uchar* dptr = dst->data.ptr + dst->step*i; + const uchar* sptr0 = src->data.ptr + src->step*y_idx->data.i[i]; + + for( j = 0; j < dcols; j++, dptr += elem_size ) + { + const uchar* sptr = sptr0 + x_tab[j]; + for( k = 0; k < elem_size; k++ ) + dptr[k] = sptr[k]; + } + } + + cvReleaseMat( &x_idx ); + cvReleaseMat( &y_idx ); +} + + +///////////////////////// + +static void test_remap( const Mat& src, Mat& dst, const Mat& mapx, const Mat& mapy, + Mat* mask=0, int interpolation=CV_INTER_LINEAR ) +{ + int x, y, k; + int drows = dst.rows, dcols = dst.cols; + int srows = src.rows, scols = src.cols; + uchar* sptr0 = src.data; + int depth = src.depth(), cn = src.channels(); + int elem_size = (int)src.elemSize(); + int step = (int)(src.step / CV_ELEM_SIZE(depth)); + int delta; + + if( interpolation != CV_INTER_CUBIC ) + { + delta = 0; + scols -= 1; srows -= 1; + } + else + { + delta = 1; + scols = MAX(scols - 3, 0); + srows = MAX(srows - 3, 0); + } + + int scols1 = MAX(scols - 2, 0); + int srows1 = MAX(srows - 2, 0); + + if( mask ) + *mask = Scalar::all(0); + + for( y = 0; y < drows; y++ ) + { + uchar* dptr = dst.ptr(y); + const float* mx = mapx.ptr(y); + const float* my = mapy.ptr(y); + uchar* m = mask ? mask->ptr(y) : 0; + + for( x = 0; x < dcols; x++, dptr += elem_size ) + { + float xs = mx[x]; + float ys = my[x]; + int ixs = cvFloor(xs); + int iys = cvFloor(ys); + + if( (unsigned)(ixs - delta - 1) >= (unsigned)scols1 || + (unsigned)(iys - delta - 1) >= (unsigned)srows1 ) + { + if( m ) + m[x] = 1; + if( (unsigned)(ixs - delta) >= (unsigned)scols || + (unsigned)(iys - delta) >= (unsigned)srows ) + continue; + } + + xs -= ixs; + ys -= iys; + + switch( depth ) + { + case CV_8U: + { + const uchar* sptr = sptr0 + iys*step + ixs*cn; + for( k = 0; k < cn; k++ ) + { + float v00 = sptr[k]; + float v01 = sptr[cn + k]; + float v10 = sptr[step + k]; + float v11 = sptr[step + cn + k]; + + v00 = v00 + xs*(v01 - v00); + v10 = v10 + xs*(v11 - v10); + v00 = v00 + ys*(v10 - v00); + dptr[k] = (uchar)cvRound(v00); + } + } + break; + case CV_16U: + { + const ushort* sptr = (const ushort*)sptr0 + iys*step + ixs*cn; + for( k = 0; k < cn; k++ ) + { + float v00 = sptr[k]; + float v01 = sptr[cn + k]; + float v10 = sptr[step + k]; + float v11 = sptr[step + cn + k]; + + v00 = v00 + xs*(v01 - v00); + v10 = v10 + xs*(v11 - v10); + v00 = v00 + ys*(v10 - v00); + ((ushort*)dptr)[k] = (ushort)cvRound(v00); + } + } + break; + case CV_32F: + { + const float* sptr = (const float*)sptr0 + iys*step + ixs*cn; + for( k = 0; k < cn; k++ ) + { + float v00 = sptr[k]; + float v01 = sptr[cn + k]; + float v10 = sptr[step + k]; + float v11 = sptr[step + cn + k]; + + v00 = v00 + xs*(v01 - v00); + v10 = v10 + xs*(v11 - v10); + v00 = v00 + ys*(v10 - v00); + ((float*)dptr)[k] = (float)v00; + } + } + break; + default: + assert(0); + } + } + } +} + +///////////////////////// + +class CV_WarpAffineTest : public CV_ImgWarpBaseTest +{ +public: + CV_WarpAffineTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void run_func(); + int prepare_test_case( int test_case_idx ); + void prepare_to_validation( int /*test_case_idx*/ ); + double get_success_error_level( int test_case_idx, int i, int j ); +}; + + +CV_WarpAffineTest::CV_WarpAffineTest() : CV_ImgWarpBaseTest( true ) +{ + //spatial_scale_zoom = spatial_scale_decimate; + spatial_scale_decimate = spatial_scale_zoom; +} + + +void CV_WarpAffineTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + CvSize sz = sizes[INPUT][0]; + // run for the second time to get output of a different size + CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + sizes[INPUT][0] = sz; + sizes[INPUT][1] = cvSize( 3, 2 ); +} + + +void CV_WarpAffineTest::run_func() +{ + CvMat mtx = test_mat[INPUT][1]; + cvWarpAffine( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &mtx, interpolation ); +} + + +double CV_WarpAffineTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2; +} + + +int CV_WarpAffineTest::prepare_test_case( int test_case_idx ) +{ + RNG& rng = ts->get_rng(); + int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx ); + const Mat& src = test_mat[INPUT][0]; + const Mat& dst = test_mat[INPUT_OUTPUT][0]; + Mat& mat = test_mat[INPUT][1]; + CvPoint2D32f center; + double scale, angle; + + if( code <= 0 ) + return code; + + double buffer[6]; + Mat tmp( 2, 3, mat.type(), buffer ); + + center.x = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.cols); + center.y = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.rows); + angle = cvtest::randReal(rng)*360; + scale = ((double)dst.rows/src.rows + (double)dst.cols/src.cols)*0.5; + getRotationMatrix2D(center, angle, scale).convertTo(mat, mat.depth()); + rng.fill( tmp, CV_RAND_NORMAL, Scalar::all(1.), Scalar::all(0.01) ); + cv::max(tmp, 0.9, tmp); + cv::min(tmp, 1.1, tmp); + cv::multiply(tmp, mat, mat, 1.); + + return code; +} + + +void CV_WarpAffineTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + const Mat& src = test_mat[INPUT][0]; + Mat& dst = test_mat[REF_INPUT_OUTPUT][0]; + Mat& dst0 = test_mat[INPUT_OUTPUT][0]; + Mat mapx(dst.size(), CV_32F), mapy(dst.size(), CV_32F); + double m[6]; + Mat srcAb, dstAb( 2, 3, CV_64FC1, m ); + + //cvInvert( &tM, &M, CV_LU ); + // [R|t] -> [R^-1 | -(R^-1)*t] + test_mat[INPUT][1].convertTo( srcAb, CV_64F ); + Mat A = srcAb.colRange(0, 2); + Mat b = srcAb.col(2); + Mat invA = dstAb.colRange(0, 2); + Mat invAb = dstAb.col(2); + cv::invert(A, invA, CV_SVD); + cv::gemm(invA, b, -1, Mat(), 0, invAb); + + for( int y = 0; y < dst.rows; y++ ) + for( int x = 0; x < dst.cols; x++ ) + { + mapx.at(y, x) = (float)(x*m[0] + y*m[1] + m[2]); + mapy.at(y, x) = (float)(x*m[3] + y*m[4] + m[5]); + } + + Mat mask( dst.size(), CV_8U ); + test_remap( src, dst, mapx, mapy, &mask ); + dst.setTo(Scalar::all(0), mask); + dst0.setTo(Scalar::all(0), mask); +} + + +///////////////////////// + +class CV_WarpPerspectiveTest : public CV_ImgWarpBaseTest +{ +public: + CV_WarpPerspectiveTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void run_func(); + int prepare_test_case( int test_case_idx ); + void prepare_to_validation( int /*test_case_idx*/ ); + double get_success_error_level( int test_case_idx, int i, int j ); +}; + + +CV_WarpPerspectiveTest::CV_WarpPerspectiveTest() : CV_ImgWarpBaseTest( true ) +{ + //spatial_scale_zoom = spatial_scale_decimate; + spatial_scale_decimate = spatial_scale_zoom; +} + + +void CV_WarpPerspectiveTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + CvSize sz = sizes[INPUT][0]; + // run for the second time to get output of a different size + CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + sizes[INPUT][0] = sz; + sizes[INPUT][1] = cvSize( 3, 3 ); +} + + +void CV_WarpPerspectiveTest::run_func() +{ + CvMat mtx = test_mat[INPUT][1]; + cvWarpPerspective( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &mtx, interpolation ); +} + + +double CV_WarpPerspectiveTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2; +} + + +int CV_WarpPerspectiveTest::prepare_test_case( int test_case_idx ) +{ + RNG& rng = ts->get_rng(); + int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx ); + const CvMat& src = test_mat[INPUT][0]; + const CvMat& dst = test_mat[INPUT_OUTPUT][0]; + Mat& mat = test_mat[INPUT][1]; + Point2f s[4], d[4]; + int i; + + if( code <= 0 ) + return code; + + s[0] = Point2f(0,0); + d[0] = Point2f(0,0); + s[1] = Point2f(src.cols-1.f,0); + d[1] = Point2f(dst.cols-1.f,0); + s[2] = Point2f(src.cols-1.f,src.rows-1.f); + d[2] = Point2f(dst.cols-1.f,dst.rows-1.f); + s[3] = Point2f(0,src.rows-1.f); + d[3] = Point2f(0,dst.rows-1.f); + + float bufer[16]; + Mat tmp( 1, 16, CV_32FC1, bufer ); + + rng.fill( tmp, CV_RAND_NORMAL, Scalar::all(0.), Scalar::all(0.1) ); + + for( i = 0; i < 4; i++ ) + { + s[i].x += bufer[i*4]*src.cols/2; + s[i].y += bufer[i*4+1]*src.rows/2; + d[i].x += bufer[i*4+2]*dst.cols/2; + d[i].y += bufer[i*4+3]*dst.rows/2; + } + + cv::getPerspectiveTransform( s, d ).convertTo( mat, mat.depth() ); + return code; +} + + +void CV_WarpPerspectiveTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat& src = test_mat[INPUT][0]; + Mat& dst = test_mat[REF_INPUT_OUTPUT][0]; + Mat& dst0 = test_mat[INPUT_OUTPUT][0]; + Mat mapx(dst.size(), CV_32F), mapy(dst.size(), CV_32F); + double m[9]; + Mat srcM, dstM(3, 3, CV_64F, m); + + //cvInvert( &tM, &M, CV_LU ); + // [R|t] -> [R^-1 | -(R^-1)*t] + test_mat[INPUT][1].convertTo( srcM, CV_64F ); + cv::invert(srcM, dstM, CV_SVD); + + for( int y = 0; y < dst.rows; y++ ) + { + for( int x = 0; x < dst.cols; x++ ) + { + double xs = x*m[0] + y*m[1] + m[2]; + double ys = x*m[3] + y*m[4] + m[5]; + double ds = x*m[6] + y*m[7] + m[8]; + + ds = ds ? 1./ds : 0; + xs *= ds; + ys *= ds; + + mapx.at(y, x) = (float)xs; + mapy.at(y, x) = (float)ys; + } + } + + Mat mask( dst.size(), CV_8U ); + test_remap( src, dst, mapx, mapy, &mask ); + dst.setTo(Scalar::all(0), mask); + dst0.setTo(Scalar::all(0), mask); +} + + +///////////////////////// + +class CV_RemapTest : public CV_ImgWarpBaseTest +{ +public: + CV_RemapTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void run_func(); + int prepare_test_case( int test_case_idx ); + void prepare_to_validation( int /*test_case_idx*/ ); + double get_success_error_level( int test_case_idx, int i, int j ); + void fill_array( int test_case_idx, int i, int j, Mat& arr ); +}; + + +CV_RemapTest::CV_RemapTest() : CV_ImgWarpBaseTest( false ) +{ + //spatial_scale_zoom = spatial_scale_decimate; + test_array[INPUT].push_back(NULL); + test_array[INPUT].push_back(NULL); + + spatial_scale_decimate = spatial_scale_zoom; +} + + +void CV_RemapTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + types[INPUT][1] = types[INPUT][2] = CV_32FC1; + interpolation = CV_INTER_LINEAR; +} + + +void CV_RemapTest::fill_array( int test_case_idx, int i, int j, Mat& arr ) +{ + if( i != INPUT ) + CV_ImgWarpBaseTest::fill_array( test_case_idx, i, j, arr ); +} + + +void CV_RemapTest::run_func() +{ + cvRemap( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], + test_array[INPUT][1], test_array[INPUT][2], interpolation ); +} + + +double CV_RemapTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2; +} + + +int CV_RemapTest::prepare_test_case( int test_case_idx ) +{ + RNG& rng = ts->get_rng(); + int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx ); + const Mat& src = test_mat[INPUT][0]; + double a[9] = {0,0,0,0,0,0,0,0,1}, k[4]; + Mat _a( 3, 3, CV_64F, a ); + Mat _k( 4, 1, CV_64F, k ); + double sz = MAX(src.rows, src.cols); + + if( code <= 0 ) + return code; + + double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7; + a[2] = (src.cols - 1)*0.5 + cvtest::randReal(rng)*10 - 5; + a[5] = (src.rows - 1)*0.5 + cvtest::randReal(rng)*10 - 5; + a[0] = sz/(0.9 - cvtest::randReal(rng)*0.6); + a[4] = aspect_ratio*a[0]; + k[0] = cvtest::randReal(rng)*0.06 - 0.03; + k[1] = cvtest::randReal(rng)*0.06 - 0.03; + if( k[0]*k[1] > 0 ) + k[1] = -k[1]; + k[2] = cvtest::randReal(rng)*0.004 - 0.002; + k[3] = cvtest::randReal(rng)*0.004 - 0.002; + + cvtest::initUndistortMap( _a, _k, test_mat[INPUT][1].size(), test_mat[INPUT][1], test_mat[INPUT][2] ); + return code; +} + + +void CV_RemapTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat& dst = test_mat[REF_INPUT_OUTPUT][0]; + Mat& dst0 = test_mat[INPUT_OUTPUT][0]; + Mat mask( dst.size(), CV_8U ); + test_remap(test_mat[INPUT][0], dst, test_mat[INPUT][1], + test_mat[INPUT][2], &mask, interpolation ); + dst.setTo(Scalar::all(0), mask); + dst0.setTo(Scalar::all(0), mask); +} + + +////////////////////////////// undistort ///////////////////////////////// + +class CV_UndistortTest : public CV_ImgWarpBaseTest +{ +public: + CV_UndistortTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void run_func(); + int prepare_test_case( int test_case_idx ); + void prepare_to_validation( int /*test_case_idx*/ ); + double get_success_error_level( int test_case_idx, int i, int j ); + void fill_array( int test_case_idx, int i, int j, Mat& arr ); + +private: + bool useCPlus; + cv::Mat input0; + cv::Mat input1; + cv::Mat input2; + cv::Mat input_new_cam; + cv::Mat input_output; + + bool zero_new_cam; + bool zero_distortion; +}; + + +CV_UndistortTest::CV_UndistortTest() : CV_ImgWarpBaseTest( false ) +{ + //spatial_scale_zoom = spatial_scale_decimate; + test_array[INPUT].push_back(NULL); + test_array[INPUT].push_back(NULL); + test_array[INPUT].push_back(NULL); + + spatial_scale_decimate = spatial_scale_zoom; +} + + +void CV_UndistortTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int type = types[INPUT][0]; + type = CV_MAKETYPE( CV_8U, CV_MAT_CN(type) ); + types[INPUT][0] = types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = type; + types[INPUT][1] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F; + types[INPUT][2] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F; + sizes[INPUT][1] = cvSize(3,3); + sizes[INPUT][2] = cvtest::randInt(rng)%2 ? cvSize(4,1) : cvSize(1,4); + types[INPUT][3] = types[INPUT][1]; + sizes[INPUT][3] = sizes[INPUT][1]; + interpolation = CV_INTER_LINEAR; +} + + +void CV_UndistortTest::fill_array( int test_case_idx, int i, int j, Mat& arr ) +{ + if( i != INPUT ) + CV_ImgWarpBaseTest::fill_array( test_case_idx, i, j, arr ); +} + + +void CV_UndistortTest::run_func() +{ + if (!useCPlus) + { + CvMat a = test_mat[INPUT][1], k = test_mat[INPUT][2]; + cvUndistort2( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &a, &k); + } + else + { + if (zero_distortion) + { + cv::undistort(input0,input_output,input1,cv::Mat()); + } + else + { + cv::undistort(input0,input_output,input1,input2); + } + } +} + + +double CV_UndistortTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2; +} + + +int CV_UndistortTest::prepare_test_case( int test_case_idx ) +{ + RNG& rng = ts->get_rng(); + int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx ); + + const Mat& src = test_mat[INPUT][0]; + double k[4], a[9] = {0,0,0,0,0,0,0,0,1}; + double new_cam[9] = {0,0,0,0,0,0,0,0,1}; + double sz = MAX(src.rows, src.cols); + + Mat& _new_cam0 = test_mat[INPUT][3]; + Mat _new_cam(test_mat[INPUT][3].rows,test_mat[INPUT][3].cols,CV_64F,new_cam); + Mat& _a0 = test_mat[INPUT][1]; + Mat _a(3,3,CV_64F,a); + Mat& _k0 = test_mat[INPUT][2]; + Mat _k(_k0.rows,_k0.cols, CV_MAKETYPE(CV_64F,_k0.channels()),k); + + if( code <= 0 ) + return code; + + double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7; + a[2] = (src.cols - 1)*0.5 + cvtest::randReal(rng)*10 - 5; + a[5] = (src.rows - 1)*0.5 + cvtest::randReal(rng)*10 - 5; + a[0] = sz/(0.9 - cvtest::randReal(rng)*0.6); + a[4] = aspect_ratio*a[0]; + k[0] = cvtest::randReal(rng)*0.06 - 0.03; + k[1] = cvtest::randReal(rng)*0.06 - 0.03; + if( k[0]*k[1] > 0 ) + k[1] = -k[1]; + if( cvtest::randInt(rng)%4 != 0 ) + { + k[2] = cvtest::randReal(rng)*0.004 - 0.002; + k[3] = cvtest::randReal(rng)*0.004 - 0.002; + } + else + k[2] = k[3] = 0; + + new_cam[0] = a[0] + (cvtest::randReal(rng) - (double)0.5)*0.2*a[0]; //10% + new_cam[4] = a[4] + (cvtest::randReal(rng) - (double)0.5)*0.2*a[4]; //10% + new_cam[2] = a[2] + (cvtest::randReal(rng) - (double)0.5)*0.3*test_mat[INPUT][0].rows; //15% + new_cam[5] = a[5] + (cvtest::randReal(rng) - (double)0.5)*0.3*test_mat[INPUT][0].cols; //15% + + _a.convertTo(_a0, _a0.depth()); + + zero_distortion = (cvtest::randInt(rng)%2) == 0 ? false : true; + _k.convertTo(_k0, _k0.depth()); + + zero_new_cam = (cvtest::randInt(rng)%2) == 0 ? false : true; + _new_cam.convertTo(_new_cam0, _new_cam0.depth()); + + //Testing C++ code + useCPlus = ((cvtest::randInt(rng) % 2)!=0); + if (useCPlus) + { + input0 = test_mat[INPUT][0]; + input1 = test_mat[INPUT][1]; + input2 = test_mat[INPUT][2]; + input_new_cam = test_mat[INPUT][3]; + } + + return code; +} + + +void CV_UndistortTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + if (useCPlus) + { + Mat& output = test_mat[INPUT_OUTPUT][0]; + input_output.convertTo(output, output.type()); + } + Mat& src = test_mat[INPUT][0]; + Mat& dst = test_mat[REF_INPUT_OUTPUT][0]; + Mat& dst0 = test_mat[INPUT_OUTPUT][0]; + Mat mapx, mapy; + cvtest::initUndistortMap( test_mat[INPUT][1], test_mat[INPUT][2], dst.size(), mapx, mapy ); + Mat mask( dst.size(), CV_8U ); + test_remap( src, dst, mapx, mapy, &mask, interpolation ); + dst.setTo(Scalar::all(0), mask); + dst0.setTo(Scalar::all(0), mask); +} + + +class CV_UndistortMapTest : public cvtest::ArrayTest +{ +public: + CV_UndistortMapTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void run_func(); + int prepare_test_case( int test_case_idx ); + void prepare_to_validation( int /*test_case_idx*/ ); + double get_success_error_level( int test_case_idx, int i, int j ); + void fill_array( int test_case_idx, int i, int j, Mat& arr ); + +private: + bool dualChannel; +}; + + +CV_UndistortMapTest::CV_UndistortMapTest() +{ + test_array[INPUT].push_back(NULL); + test_array[INPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + + element_wise_relative_error = false; +} + + +void CV_UndistortMapTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int depth = cvtest::randInt(rng)%2 ? CV_64F : CV_32F; + + CvSize sz = sizes[OUTPUT][0]; + types[INPUT][0] = types[INPUT][1] = depth; + dualChannel = cvtest::randInt(rng)%2 == 0; + types[OUTPUT][0] = types[OUTPUT][1] = + types[REF_OUTPUT][0] = types[REF_OUTPUT][1] = dualChannel ? CV_32FC2 : CV_32F; + sizes[INPUT][0] = cvSize(3,3); + sizes[INPUT][1] = cvtest::randInt(rng)%2 ? cvSize(4,1) : cvSize(1,4); + + sz.width = MAX(sz.width,16); + sz.height = MAX(sz.height,16); + sizes[OUTPUT][0] = sizes[OUTPUT][1] = + sizes[REF_OUTPUT][0] = sizes[REF_OUTPUT][1] = sz; +} + + +void CV_UndistortMapTest::fill_array( int test_case_idx, int i, int j, Mat& arr ) +{ + if( i != INPUT ) + cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr ); +} + + +void CV_UndistortMapTest::run_func() +{ + CvMat a = test_mat[INPUT][0], k = test_mat[INPUT][1]; + + if (!dualChannel ) + cvInitUndistortMap( &a, &k, test_array[OUTPUT][0], test_array[OUTPUT][1] ); + else + cvInitUndistortMap( &a, &k, test_array[OUTPUT][0], 0 ); +} + + +double CV_UndistortMapTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + return 1e-3; +} + + +int CV_UndistortMapTest::prepare_test_case( int test_case_idx ) +{ + RNG& rng = ts->get_rng(); + int code = cvtest::ArrayTest::prepare_test_case( test_case_idx ); + const Mat& mapx = test_mat[OUTPUT][0]; + double k[4], a[9] = {0,0,0,0,0,0,0,0,1}; + double sz = MAX(mapx.rows, mapx.cols); + Mat& _a0 = test_mat[INPUT][0], &_k0 = test_mat[INPUT][1]; + Mat _a(3,3,CV_64F,a); + Mat _k(_k0.rows,_k0.cols, CV_MAKETYPE(CV_64F,_k0.channels()),k); + + if( code <= 0 ) + return code; + + double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7; + a[2] = (mapx.cols - 1)*0.5 + cvtest::randReal(rng)*10 - 5; + a[5] = (mapx.rows - 1)*0.5 + cvtest::randReal(rng)*10 - 5; + a[0] = sz/(0.9 - cvtest::randReal(rng)*0.6); + a[4] = aspect_ratio*a[0]; + k[0] = cvtest::randReal(rng)*0.06 - 0.03; + k[1] = cvtest::randReal(rng)*0.06 - 0.03; + if( k[0]*k[1] > 0 ) + k[1] = -k[1]; + k[2] = cvtest::randReal(rng)*0.004 - 0.002; + k[3] = cvtest::randReal(rng)*0.004 - 0.002; + + _a.convertTo(_a0, _a0.depth()); + _k.convertTo(_k0, _k0.depth()); + + if (dualChannel) + { + test_mat[REF_OUTPUT][1] = Scalar::all(0); + test_mat[OUTPUT][1] = Scalar::all(0); + } + + return code; +} + + +void CV_UndistortMapTest::prepare_to_validation( int ) +{ + Mat mapx, mapy; + cvtest::initUndistortMap( test_mat[INPUT][0], test_mat[INPUT][1], test_mat[REF_OUTPUT][0].size(), mapx, mapy ); + if( !dualChannel ) + { + mapx.copyTo(test_mat[REF_OUTPUT][0]); + mapy.copyTo(test_mat[REF_OUTPUT][1]); + } + else + { + Mat p[2] = {mapx, mapy}; + cv::merge(p, 2, test_mat[REF_OUTPUT][0]); + } +} + +////////////////////////////// GetRectSubPix ///////////////////////////////// + +static void +test_getQuadrangeSubPix( const Mat& src, Mat& dst, double* a ) +{ + int sstep = (int)(src.step / sizeof(float)); + int scols = src.cols, srows = src.rows; + + CV_Assert( src.depth() == CV_32F && src.type() == dst.type() ); + + int cn = dst.channels(); + + for( int y = 0; y < dst.rows; y++ ) + for( int x = 0; x < dst.cols; x++ ) + { + float* d = dst.ptr(y) + x*cn; + float sx = (float)(a[0]*x + a[1]*y + a[2]); + float sy = (float)(a[3]*x + a[4]*y + a[5]); + int ix = cvFloor(sx), iy = cvFloor(sy); + int dx = cn, dy = sstep; + const float* s; + sx -= ix; sy -= iy; + + if( (unsigned)ix >= (unsigned)(scols-1) ) + ix = ix < 0 ? 0 : scols - 1, sx = 0, dx = 0; + if( (unsigned)iy >= (unsigned)(srows-1) ) + iy = iy < 0 ? 0 : srows - 1, sy = 0, dy = 0; + + s = src.ptr(iy) + ix*cn; + for( int k = 0; k < cn; k++, s++ ) + { + float t0 = s[0] + sx*(s[dx] - s[0]); + float t1 = s[dy] + sx*(s[dy + dx] - s[dy]); + d[k] = t0 + sy*(t1 - t0); + } + } +} + + +class CV_GetRectSubPixTest : public CV_ImgWarpBaseTest +{ +public: + CV_GetRectSubPixTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void run_func(); + int prepare_test_case( int test_case_idx ); + void prepare_to_validation( int /*test_case_idx*/ ); + double get_success_error_level( int test_case_idx, int i, int j ); + void fill_array( int test_case_idx, int i, int j, Mat& arr ); + + CvPoint2D32f center; + bool test_cpp; +}; + + +CV_GetRectSubPixTest::CV_GetRectSubPixTest() : CV_ImgWarpBaseTest( false ) +{ + //spatial_scale_zoom = spatial_scale_decimate; + spatial_scale_decimate = spatial_scale_zoom; + test_cpp = false; +} + + +void CV_GetRectSubPixTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int src_depth = cvtest::randInt(rng) % 2, dst_depth; + int cn = cvtest::randInt(rng) % 2 ? 3 : 1; + CvSize src_size, dst_size; + + dst_depth = src_depth = src_depth == 0 ? CV_8U : CV_32F; + if( src_depth < CV_32F && cvtest::randInt(rng) % 2 ) + dst_depth = CV_32F; + + types[INPUT][0] = CV_MAKETYPE(src_depth,cn); + types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(dst_depth,cn); + + src_size = sizes[INPUT][0]; + dst_size.width = cvRound(sqrt(cvtest::randReal(rng)*src_size.width) + 1); + dst_size.height = cvRound(sqrt(cvtest::randReal(rng)*src_size.height) + 1); + dst_size.width = MIN(dst_size.width,src_size.width); + dst_size.height = MIN(dst_size.width,src_size.height); + sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = dst_size; + + center.x = (float)(cvtest::randReal(rng)*src_size.width); + center.y = (float)(cvtest::randReal(rng)*src_size.height); + interpolation = CV_INTER_LINEAR; + + test_cpp = (cvtest::randInt(rng) & 256) == 0; +} + + +void CV_GetRectSubPixTest::fill_array( int test_case_idx, int i, int j, Mat& arr ) +{ + if( i != INPUT ) + CV_ImgWarpBaseTest::fill_array( test_case_idx, i, j, arr ); +} + + +void CV_GetRectSubPixTest::run_func() +{ + if(!test_cpp) + cvGetRectSubPix( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], center ); + else + { + cv::Mat _out = cv::cvarrToMat(test_array[INPUT_OUTPUT][0]); + cv::getRectSubPix( cv::cvarrToMat(test_array[INPUT][0]), _out.size(), center, _out, _out.type()); + } +} + + +double CV_GetRectSubPixTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int in_depth = test_mat[INPUT][0].depth(); + int out_depth = test_mat[INPUT_OUTPUT][0].depth(); + + return in_depth >= CV_32F ? 1e-3 : out_depth >= CV_32F ? 1e-2 : 1; +} + + +int CV_GetRectSubPixTest::prepare_test_case( int test_case_idx ) +{ + return CV_ImgWarpBaseTest::prepare_test_case( test_case_idx ); +} + + +void CV_GetRectSubPixTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat& src0 = test_mat[INPUT][0]; + Mat& dst0 = test_mat[REF_INPUT_OUTPUT][0]; + Mat src = src0, dst = dst0; + int ftype = CV_MAKETYPE(CV_32F,src0.channels()); + double a[] = { 1, 0, center.x - dst.cols*0.5 + 0.5, + 0, 1, center.y - dst.rows*0.5 + 0.5 }; + if( src.depth() != CV_32F ) + src0.convertTo(src, CV_32F); + + if( dst.depth() != CV_32F ) + dst.create(dst0.size(), ftype); + + test_getQuadrangeSubPix( src, dst, a ); + + if( dst.data != dst0.data ) + dst.convertTo(dst0, dst0.depth()); +} + + +class CV_GetQuadSubPixTest : public CV_ImgWarpBaseTest +{ +public: + CV_GetQuadSubPixTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void run_func(); + int prepare_test_case( int test_case_idx ); + void prepare_to_validation( int /*test_case_idx*/ ); + double get_success_error_level( int test_case_idx, int i, int j ); +}; + + +CV_GetQuadSubPixTest::CV_GetQuadSubPixTest() : CV_ImgWarpBaseTest( true ) +{ + //spatial_scale_zoom = spatial_scale_decimate; + spatial_scale_decimate = spatial_scale_zoom; +} + + +void CV_GetQuadSubPixTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) +{ + int min_size = 4; + CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + CvSize sz = sizes[INPUT][0], dsz; + RNG& rng = ts->get_rng(); + int msz, src_depth = cvtest::randInt(rng) % 2, dst_depth; + int cn = cvtest::randInt(rng) % 2 ? 3 : 1; + + dst_depth = src_depth = src_depth == 0 ? CV_8U : CV_32F; + if( src_depth < CV_32F && cvtest::randInt(rng) % 2 ) + dst_depth = CV_32F; + + types[INPUT][0] = CV_MAKETYPE(src_depth,cn); + types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(dst_depth,cn); + + sz.width = MAX(sz.width,min_size); + sz.height = MAX(sz.height,min_size); + sizes[INPUT][0] = sz; + msz = MIN( sz.width, sz.height ); + + dsz.width = cvRound(sqrt(cvtest::randReal(rng)*msz) + 1); + dsz.height = cvRound(sqrt(cvtest::randReal(rng)*msz) + 1); + dsz.width = MIN(dsz.width,msz); + dsz.height = MIN(dsz.width,msz); + dsz.width = MAX(dsz.width,min_size); + dsz.height = MAX(dsz.height,min_size); + sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = dsz; + sizes[INPUT][1] = cvSize( 3, 2 ); +} + + +void CV_GetQuadSubPixTest::run_func() +{ + CvMat mtx = test_mat[INPUT][1]; + cvGetQuadrangleSubPix( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &mtx ); +} + + +double CV_GetQuadSubPixTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int in_depth = test_mat[INPUT][0].depth(); + //int out_depth = test_mat[INPUT_OUTPUT][0].depth(); + + return in_depth >= CV_32F ? 1e-2 : 4; +} + + +int CV_GetQuadSubPixTest::prepare_test_case( int test_case_idx ) +{ + RNG& rng = ts->get_rng(); + int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx ); + const Mat& src = test_mat[INPUT][0]; + Mat& mat = test_mat[INPUT][1]; + CvPoint2D32f center; + double scale, angle; + + if( code <= 0 ) + return code; + + double a[6]; + Mat A( 2, 3, CV_64FC1, a ); + + center.x = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.cols); + center.y = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.rows); + angle = cvtest::randReal(rng)*360; + scale = cvtest::randReal(rng)*0.2 + 0.9; + + // y = Ax + b -> x = A^-1(y - b) = A^-1*y - A^-1*b + scale = 1./scale; + angle = angle*(CV_PI/180.); + a[0] = a[4] = cos(angle)*scale; + a[1] = sin(angle)*scale; + a[3] = -a[1]; + a[2] = center.x - a[0]*center.x - a[1]*center.y; + a[5] = center.y - a[3]*center.x - a[4]*center.y; + A.convertTo( mat, mat.depth() ); + + return code; +} + + +void CV_GetQuadSubPixTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat& src0 = test_mat[INPUT][0]; + Mat& dst0 = test_mat[REF_INPUT_OUTPUT][0]; + Mat src = src0, dst = dst0; + int ftype = CV_MAKETYPE(CV_32F,src0.channels()); + double a[6], dx = (dst0.cols - 1)*0.5, dy = (dst0.rows - 1)*0.5; + Mat A( 2, 3, CV_64F, a ); + + if( src.depth() != CV_32F ) + src0.convertTo(src, CV_32F); + + if( dst.depth() != CV_32F ) + dst.create(dst0.size(), ftype); + + test_mat[INPUT][1].convertTo( A, CV_64F ); + a[2] -= a[0]*dx + a[1]*dy; + a[5] -= a[3]*dx + a[4]*dy; + test_getQuadrangeSubPix( src, dst, a ); + + if( dst.data != dst0.data ) + dst.convertTo(dst0, dst0.depth()); +} + +TEST(Imgproc_cvWarpAffine, regression) +{ + IplImage* src = cvCreateImage(cvSize(100, 100), IPL_DEPTH_8U, 1); + IplImage* dst = cvCreateImage(cvSize(100, 100), IPL_DEPTH_8U, 1); + + float m[6]; + CvMat M = cvMat( 2, 3, CV_32F, m ); + int w = src->width; + int h = src->height; + cv2DRotationMatrix(cvPoint2D32f(w*0.5f, h*0.5f), 45.0, 1.0, &M); + cvWarpAffine(src, dst, &M); +} + +TEST(Imgproc_fitLine_vector_3d, regression) +{ + std::vector points_vector; + + Point3f p21(4,4,4); + Point3f p22(8,8,8); + + points_vector.push_back(p21); + points_vector.push_back(p22); + + std::vector line; + + cv::fitLine(points_vector, line, CV_DIST_L2, 0 ,0 ,0); + + ASSERT_EQ(line.size(), (size_t)6); + +} + +TEST(Imgproc_fitLine_vector_2d, regression) +{ + std::vector points_vector; + + Point2f p21(4,4); + Point2f p22(8,8); + Point2f p23(16,16); + + points_vector.push_back(p21); + points_vector.push_back(p22); + points_vector.push_back(p23); + + std::vector line; + + cv::fitLine(points_vector, line, CV_DIST_L2, 0 ,0 ,0); + + ASSERT_EQ(line.size(), (size_t)4); +} + +TEST(Imgproc_fitLine_Mat_2dC2, regression) +{ + cv::Mat mat1(3, 1, CV_32SC2); + std::vector line1; + + cv::fitLine(mat1, line1, CV_DIST_L2, 0 ,0 ,0); + + ASSERT_EQ(line1.size(), (size_t)4); +} + +TEST(Imgproc_fitLine_Mat_2dC1, regression) +{ + cv::Matx mat2; + std::vector line2; + + cv::fitLine(mat2, line2, CV_DIST_L2, 0 ,0 ,0); + + ASSERT_EQ(line2.size(), (size_t)4); +} + +TEST(Imgproc_fitLine_Mat_3dC3, regression) +{ + cv::Mat mat1(2, 1, CV_32SC3); + std::vector line1; + + cv::fitLine(mat1, line1, CV_DIST_L2, 0 ,0 ,0); + + ASSERT_EQ(line1.size(), (size_t)6); +} + +TEST(Imgproc_fitLine_Mat_3dC1, regression) +{ + cv::Mat mat2(2, 3, CV_32SC1); + std::vector line2; + + cv::fitLine(mat2, line2, CV_DIST_L2, 0 ,0 ,0); + + ASSERT_EQ(line2.size(), (size_t)6); +} + +TEST(Imgproc_resize_area, regression) +{ + static ushort input_data[16 * 16] = { + 90, 94, 80, 3, 231, 2, 186, 245, 188, 165, 10, 19, 201, 169, 8, 228, + 86, 5, 203, 120, 136, 185, 24, 94, 81, 150, 163, 137, 88, 105, 132, 132, + 236, 48, 250, 218, 19, 52, 54, 221, 159, 112, 45, 11, 152, 153, 112, 134, + 78, 133, 136, 83, 65, 76, 82, 250, 9, 235, 148, 26, 236, 179, 200, 50, + 99, 51, 103, 142, 201, 65, 176, 33, 49, 226, 177, 109, 46, 21, 67, 130, + 54, 125, 107, 154, 145, 51, 199, 189, 161, 142, 231, 240, 139, 162, 240, 22, + 231, 86, 79, 106, 92, 47, 146, 156, 36, 207, 71, 33, 2, 244, 221, 71, + 44, 127, 71, 177, 75, 126, 68, 119, 200, 129, 191, 251, 6, 236, 247, 6, + 133, 175, 56, 239, 147, 221, 243, 154, 242, 82, 106, 99, 77, 158, 60, 229, + 2, 42, 24, 174, 27, 198, 14, 204, 246, 251, 141, 31, 114, 163, 29, 147, + 121, 53, 74, 31, 147, 189, 42, 98, 202, 17, 228, 123, 209, 40, 77, 49, + 112, 203, 30, 12, 205, 25, 19, 106, 145, 185, 163, 201, 237, 223, 247, 38, + 33, 105, 243, 117, 92, 179, 204, 248, 160, 90, 73, 126, 2, 41, 213, 204, + 6, 124, 195, 201, 230, 187, 210, 167, 48, 79, 123, 159, 145, 218, 105, 209, + 240, 152, 136, 235, 235, 164, 157, 9, 152, 38, 27, 209, 120, 77, 238, 196, + 240, 233, 10, 241, 90, 67, 12, 79, 0, 43, 58, 27, 83, 199, 190, 182}; + + static ushort expected_data[5 * 5] = { + 120, 100, 151, 101, 130, + 106, 115, 141, 130, 127, + 91, 136, 170, 114, 140, + 104, 122, 131, 147, 133, + 161, 163, 70, 107, 182 + }; + + cv::Mat src(16, 16, CV_16UC1, input_data); + cv::Mat actual; + cv::Mat expected(5,5,CV_16UC1, expected_data); + + cv::resize(src, actual, cv::Size(), 0.3, 0.3, INTER_AREA); + + ASSERT_EQ(actual.type(), expected.type()); + ASSERT_EQ(actual.size(), expected.size()); + Mat diff; + absdiff(actual, expected, diff); + Mat one_channel_diff = diff.reshape(1); + ASSERT_EQ(norm(one_channel_diff, cv::NORM_INF),0); +} + + +////////////////////////////////////////////////////////////////////////// + +TEST(Imgproc_Resize, accuracy) { CV_ResizeTest test; test.safe_run(); } +TEST(Imgproc_WarpAffine, accuracy) { CV_WarpAffineTest test; test.safe_run(); } +TEST(Imgproc_WarpPerspective, accuracy) { CV_WarpPerspectiveTest test; test.safe_run(); } +TEST(Imgproc_Remap, accuracy) { CV_RemapTest test; test.safe_run(); } +TEST(Imgproc_Undistort, accuracy) { CV_UndistortTest test; test.safe_run(); } +TEST(Imgproc_InitUndistortMap, accuracy) { CV_UndistortMapTest test; test.safe_run(); } +TEST(Imgproc_GetRectSubPix, accuracy) { CV_GetRectSubPixTest test; test.safe_run(); } +TEST(Imgproc_GetQuadSubPix, accuracy) { CV_GetQuadSubPixTest test; test.safe_run(); } + +/* End of file. */ diff --git a/imgproc/test/test_main.cpp b/imgproc/test/test_main.cpp new file mode 100644 index 0000000..6b24993 --- /dev/null +++ b/imgproc/test/test_main.cpp @@ -0,0 +1,3 @@ +#include "test_precomp.hpp" + +CV_TEST_MAIN("cv") diff --git a/imgproc/test/test_moments.cpp b/imgproc/test/test_moments.cpp new file mode 100644 index 0000000..0152777 --- /dev/null +++ b/imgproc/test/test_moments.cpp @@ -0,0 +1,423 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +// image moments +class CV_MomentsTest : public cvtest::ArrayTest +{ +public: + CV_MomentsTest(); + +protected: + + enum { MOMENT_COUNT = 25 }; + int prepare_test_case( int test_case_idx ); + void prepare_to_validation( int /*test_case_idx*/ ); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ); + double get_success_error_level( int test_case_idx, int i, int j ); + void run_func(); + int coi; + bool is_binary; +}; + + +CV_MomentsTest::CV_MomentsTest() +{ + test_array[INPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + coi = -1; + is_binary = false; + //element_wise_relative_error = false; +} + + +void CV_MomentsTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ) +{ + cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high ); + int depth = CV_MAT_DEPTH(type); + + if( depth == CV_16U ) + { + low = Scalar::all(0); + high = Scalar::all(1000); + } + else if( depth == CV_16S ) + { + low = Scalar::all(-1000); + high = Scalar::all(1000); + } + else if( depth == CV_32F ) + { + low = Scalar::all(-1); + high = Scalar::all(1); + } +} + + +void CV_MomentsTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + int cn = cvtest::randInt(rng) % 4 + 1; + int depth = cvtest::randInt(rng) % 4; + depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : depth == 2 ? CV_16S : CV_32F; + if( cn == 2 ) + cn = 1; + + types[INPUT][0] = CV_MAKETYPE(depth, cn); + types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1; + sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(MOMENT_COUNT,1); + + is_binary = cvtest::randInt(rng) % 2 != 0; + coi = 0; + cvmat_allowed = true; + if( cn > 1 ) + { + coi = cvtest::randInt(rng) % cn; + cvmat_allowed = false; + } +} + + +double CV_MomentsTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + int depth = test_mat[INPUT][0].depth(); + return depth != CV_32F ? FLT_EPSILON*10 : FLT_EPSILON*100; +} + +int CV_MomentsTest::prepare_test_case( int test_case_idx ) +{ + int code = cvtest::ArrayTest::prepare_test_case( test_case_idx ); + if( code > 0 ) + { + int cn = test_mat[INPUT][0].channels(); + if( cn > 1 ) + cvSetImageCOI( (IplImage*)test_array[INPUT][0], coi + 1 ); + } + + return code; +} + + +void CV_MomentsTest::run_func() +{ + CvMoments* m = (CvMoments*)test_mat[OUTPUT][0].ptr(); + double* others = (double*)(m + 1); + cvMoments( test_array[INPUT][0], m, is_binary ); + others[0] = cvGetNormalizedCentralMoment( m, 2, 0 ); + others[1] = cvGetNormalizedCentralMoment( m, 1, 1 ); + others[2] = cvGetNormalizedCentralMoment( m, 0, 2 ); + others[3] = cvGetNormalizedCentralMoment( m, 3, 0 ); + others[4] = cvGetNormalizedCentralMoment( m, 2, 1 ); + others[5] = cvGetNormalizedCentralMoment( m, 1, 2 ); + others[6] = cvGetNormalizedCentralMoment( m, 0, 3 ); +} + + +void CV_MomentsTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + Mat& src = test_mat[INPUT][0]; + CvMoments m; + double* mdata = test_mat[REF_OUTPUT][0].ptr(); + int depth = src.depth(); + int cn = src.channels(); + int i, y, x, cols = src.cols; + double xc = 0., yc = 0.; + + memset( &m, 0, sizeof(m)); + + for( y = 0; y < src.rows; y++ ) + { + double s0 = 0, s1 = 0, s2 = 0, s3 = 0; + uchar* ptr = src.ptr(y); + for( x = 0; x < cols; x++ ) + { + double val; + if( depth == CV_8U ) + val = ptr[x*cn + coi]; + else if( depth == CV_16U ) + val = ((ushort*)ptr)[x*cn + coi]; + else if( depth == CV_16S ) + val = ((short*)ptr)[x*cn + coi]; + else + val = ((float*)ptr)[x*cn + coi]; + + if( is_binary ) + val = val != 0; + + s0 += val; + s1 += val*x; + s2 += val*x*x; + s3 += ((val*x)*x)*x; + } + + m.m00 += s0; + m.m01 += s0*y; + m.m02 += (s0*y)*y; + m.m03 += ((s0*y)*y)*y; + + m.m10 += s1; + m.m11 += s1*y; + m.m12 += (s1*y)*y; + + m.m20 += s2; + m.m21 += s2*y; + + m.m30 += s3; + } + + if( m.m00 != 0 ) + { + xc = m.m10/m.m00, yc = m.m01/m.m00; + m.inv_sqrt_m00 = 1./sqrt(fabs(m.m00)); + } + + for( y = 0; y < src.rows; y++ ) + { + double s0 = 0, s1 = 0, s2 = 0, s3 = 0, y1 = y - yc; + uchar* ptr = src.ptr(y); + for( x = 0; x < cols; x++ ) + { + double val, x1 = x - xc; + if( depth == CV_8U ) + val = ptr[x*cn + coi]; + else if( depth == CV_16U ) + val = ((ushort*)ptr)[x*cn + coi]; + else if( depth == CV_16S ) + val = ((short*)ptr)[x*cn + coi]; + else + val = ((float*)ptr)[x*cn + coi]; + + if( is_binary ) + val = val != 0; + + s0 += val; + s1 += val*x1; + s2 += val*x1*x1; + s3 += ((val*x1)*x1)*x1; + } + + m.mu02 += s0*y1*y1; + m.mu03 += ((s0*y1)*y1)*y1; + + m.mu11 += s1*y1; + m.mu12 += (s1*y1)*y1; + + m.mu20 += s2; + m.mu21 += s2*y1; + + m.mu30 += s3; + } + + memcpy( mdata, &m, sizeof(m)); + mdata += sizeof(m)/sizeof(m.m00); + + /* calc normalized moments */ + { + double inv_m00 = m.inv_sqrt_m00*m.inv_sqrt_m00; + double s2 = inv_m00*inv_m00; /* 1./(m00 ^ (2/2 + 1)) */ + double s3 = s2*m.inv_sqrt_m00; /* 1./(m00 ^ (3/2 + 1)) */ + + mdata[0] = m.mu20 * s2; + mdata[1] = m.mu11 * s2; + mdata[2] = m.mu02 * s2; + + mdata[3] = m.mu30 * s3; + mdata[4] = m.mu21 * s3; + mdata[5] = m.mu12 * s3; + mdata[6] = m.mu03 * s3; + } + + double* a = test_mat[REF_OUTPUT][0].ptr(); + double* b = test_mat[OUTPUT][0].ptr(); + for( i = 0; i < MOMENT_COUNT; i++ ) + { + if( fabs(a[i]) < 1e-3 ) + a[i] = 0; + if( fabs(b[i]) < 1e-3 ) + b[i] = 0; + } +} + + +// Hu invariants +class CV_HuMomentsTest : public cvtest::ArrayTest +{ +public: + CV_HuMomentsTest(); + +protected: + + enum { MOMENT_COUNT = 18, HU_MOMENT_COUNT = 7 }; + + int prepare_test_case( int test_case_idx ); + void prepare_to_validation( int /*test_case_idx*/ ); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ); + double get_success_error_level( int test_case_idx, int i, int j ); + void run_func(); +}; + + +CV_HuMomentsTest::CV_HuMomentsTest() +{ + test_array[INPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); +} + + +void CV_HuMomentsTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ) +{ + cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high ); + low = Scalar::all(-10000); + high = Scalar::all(10000); +} + + +void CV_HuMomentsTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1; + sizes[INPUT][0] = cvSize(MOMENT_COUNT,1); + sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(HU_MOMENT_COUNT,1); +} + + +double CV_HuMomentsTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + return FLT_EPSILON; +} + + + +int CV_HuMomentsTest::prepare_test_case( int test_case_idx ) +{ + int code = cvtest::ArrayTest::prepare_test_case( test_case_idx ); + if( code > 0 ) + { + // ... + } + + return code; +} + + +void CV_HuMomentsTest::run_func() +{ + cvGetHuMoments( (CvMoments*)test_mat[INPUT][0].data, + (CvHuMoments*)test_mat[OUTPUT][0].data ); +} + + +void CV_HuMomentsTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + CvMoments* m = (CvMoments*)test_mat[INPUT][0].data; + CvHuMoments* hu = (CvHuMoments*)test_mat[REF_OUTPUT][0].data; + + double inv_m00 = m->inv_sqrt_m00*m->inv_sqrt_m00; + double s2 = inv_m00*inv_m00; /* 1./(m00 ^ (2/2 + 1)) */ + double s3 = s2*m->inv_sqrt_m00; /* 1./(m00 ^ (3/2 + 1)) */ + + double nu20 = m->mu20 * s2; + double nu11 = m->mu11 * s2; + double nu02 = m->mu02 * s2; + + double nu30 = m->mu30 * s3; + double nu21 = m->mu21 * s3; + double nu12 = m->mu12 * s3; + double nu03 = m->mu03 * s3; + + #undef sqr + #define sqr(a) ((a)*(a)) + + hu->hu1 = nu20 + nu02; + hu->hu2 = sqr(nu20 - nu02) + 4*sqr(nu11); + hu->hu3 = sqr(nu30 - 3*nu12) + sqr(3*nu21 - nu03); + hu->hu4 = sqr(nu30 + nu12) + sqr(nu21 + nu03); + hu->hu5 = (nu30 - 3*nu12)*(nu30 + nu12)*(sqr(nu30 + nu12) - 3*sqr(nu21 + nu03)) + + (3*nu21 - nu03)*(nu21 + nu03)*(3*sqr(nu30 + nu12) - sqr(nu21 + nu03)); + hu->hu6 = (nu20 - nu02)*(sqr(nu30 + nu12) - sqr(nu21 + nu03)) + + 4*nu11*(nu30 + nu12)*(nu21 + nu03); + hu->hu7 = (3*nu21 - nu03)*(nu30 + nu12)*(sqr(nu30 + nu12) - 3*sqr(nu21 + nu03)) + + (3*nu12 - nu30)*(nu21 + nu03)*(3*sqr(nu30 + nu12) - sqr(nu21 + nu03)); +} + + +TEST(Imgproc_Moments, accuracy) { CV_MomentsTest test; test.safe_run(); } +TEST(Imgproc_HuMoments, accuracy) { CV_HuMomentsTest test; test.safe_run(); } + +class CV_SmallContourMomentTest : public cvtest::BaseTest +{ +public: + CV_SmallContourMomentTest() {} + ~CV_SmallContourMomentTest() {} +protected: + void run(int) + { + try + { + vector points; + points.push_back(Point(50, 56)); + points.push_back(Point(53, 53)); + points.push_back(Point(46, 54)); + points.push_back(Point(49, 51)); + + Moments m = moments(points, false); + double area = contourArea(points); + + CV_Assert( m.m00 == 0 && m.m01 == 0 && m.m10 == 0 && area == 0 ); + } + catch(...) + { + ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); + } + } +}; + +TEST(Imgproc_ContourMoment, small) { CV_SmallContourMomentTest test; test.safe_run(); } diff --git a/imgproc/test/test_pc.cpp b/imgproc/test/test_pc.cpp new file mode 100644 index 0000000..f1c86d5 --- /dev/null +++ b/imgproc/test/test_pc.cpp @@ -0,0 +1,89 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +namespace cvtest +{ + +/// phase correlation +class CV_PhaseCorrelatorTest : public cvtest::ArrayTest +{ +public: + CV_PhaseCorrelatorTest(); +protected: + void run( int ); +}; + +CV_PhaseCorrelatorTest::CV_PhaseCorrelatorTest() {} + +void CV_PhaseCorrelatorTest::run( int ) +{ + ts->set_failed_test_info(cvtest::TS::OK); + + Mat r1 = Mat::ones(Size(129, 128), CV_64F); + Mat r2 = Mat::ones(Size(129, 128), CV_64F); + + double expectedShiftX = -10.0; + double expectedShiftY = -20.0; + + // draw 10x10 rectangles @ (100, 100) and (90, 80) should see ~(-10, -20) shift here... + cv::rectangle(r1, Point(100, 100), Point(110, 110), Scalar(0, 0, 0), CV_FILLED); + cv::rectangle(r2, Point(90, 80), Point(100, 90), Scalar(0, 0, 0), CV_FILLED); + + Mat hann; + createHanningWindow(hann, r1.size(), CV_64F); + Point2d phaseShift = phaseCorrelate(r1, r2, hann); + + // test accuracy should be less than 1 pixel... + if((expectedShiftX - phaseShift.x) >= 1 || (expectedShiftY - phaseShift.y) >= 1) + { + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + } +} + +TEST(Imgproc_PhaseCorrelatorTest, accuracy) { CV_PhaseCorrelatorTest test; test.safe_run(); } + +} diff --git a/imgproc/test/test_precomp.cpp b/imgproc/test/test_precomp.cpp new file mode 100644 index 0000000..5956e13 --- /dev/null +++ b/imgproc/test/test_precomp.cpp @@ -0,0 +1 @@ +#include "test_precomp.hpp" diff --git a/imgproc/test/test_precomp.hpp b/imgproc/test/test_precomp.hpp new file mode 100644 index 0000000..f83a864 --- /dev/null +++ b/imgproc/test/test_precomp.hpp @@ -0,0 +1,16 @@ +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wmissing-declarations" +# pragma GCC diagnostic ignored "-Wmissing-prototypes" //OSX +#endif + +#ifndef __OPENCV_TEST_PRECOMP_HPP__ +#define __OPENCV_TEST_PRECOMP_HPP__ + +#include "opencv2/ts/ts.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/imgproc/imgproc_c.h" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/highgui/highgui_c.h" +#include + +#endif diff --git a/imgproc/test/test_templmatch.cpp b/imgproc/test/test_templmatch.cpp new file mode 100644 index 0000000..1b38e56 --- /dev/null +++ b/imgproc/test/test_templmatch.cpp @@ -0,0 +1,336 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +class CV_TemplMatchTest : public cvtest::ArrayTest +{ +public: + CV_TemplMatchTest(); + +protected: + int read_params( CvFileStorage* fs ); + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ); + double get_success_error_level( int test_case_idx, int i, int j ); + void run_func(); + void prepare_to_validation( int ); + + int max_template_size; + int method; + bool test_cpp; +}; + + +CV_TemplMatchTest::CV_TemplMatchTest() +{ + test_array[INPUT].push_back(NULL); + test_array[INPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + element_wise_relative_error = false; + max_template_size = 100; + method = 0; + test_cpp = false; +} + + +int CV_TemplMatchTest::read_params( CvFileStorage* fs ) +{ + int code = cvtest::ArrayTest::read_params( fs ); + if( code < 0 ) + return code; + + max_template_size = cvReadInt( find_param( fs, "max_template_size" ), max_template_size ); + max_template_size = cvtest::clipInt( max_template_size, 1, 100 ); + + return code; +} + + +void CV_TemplMatchTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ) +{ + cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high ); + int depth = CV_MAT_DEPTH(type); + if( depth == CV_32F ) + { + low = Scalar::all(-10.); + high = Scalar::all(10.); + } +} + + +void CV_TemplMatchTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + int depth = cvtest::randInt(rng) % 2, cn = cvtest::randInt(rng) & 1 ? 3 : 1; + cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + depth = depth == 0 ? CV_8U : CV_32F; + + types[INPUT][0] = types[INPUT][1] = CV_MAKETYPE(depth,cn); + types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_32FC1; + + sizes[INPUT][1].width = cvtest::randInt(rng)%MIN(sizes[INPUT][1].width,max_template_size) + 1; + sizes[INPUT][1].height = cvtest::randInt(rng)%MIN(sizes[INPUT][1].height,max_template_size) + 1; + sizes[OUTPUT][0].width = sizes[INPUT][0].width - sizes[INPUT][1].width + 1; + sizes[OUTPUT][0].height = sizes[INPUT][0].height - sizes[INPUT][1].height + 1; + sizes[REF_OUTPUT][0] = sizes[OUTPUT][0]; + + method = cvtest::randInt(rng)%6; + test_cpp = (cvtest::randInt(rng) & 256) == 0; +} + + +double CV_TemplMatchTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + if( test_mat[INPUT][1].depth() == CV_8U || + (method >= CV_TM_CCOEFF && test_mat[INPUT][1].cols*test_mat[INPUT][1].rows <= 2) ) + return 1e-2; + else + return 1e-3; +} + + +void CV_TemplMatchTest::run_func() +{ + if(!test_cpp) + cvMatchTemplate( test_array[INPUT][0], test_array[INPUT][1], test_array[OUTPUT][0], method ); + else + { + cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]); + cv::matchTemplate(cv::cvarrToMat(test_array[INPUT][0]), cv::cvarrToMat(test_array[INPUT][1]), _out, method); + } +} + + +static void cvTsMatchTemplate( const CvMat* img, const CvMat* templ, CvMat* result, int method ) +{ + int i, j, k, l; + int depth = CV_MAT_DEPTH(img->type), cn = CV_MAT_CN(img->type); + int width_n = templ->cols*cn, height = templ->rows; + int a_step = img->step / CV_ELEM_SIZE(img->type & CV_MAT_DEPTH_MASK); + int b_step = templ->step / CV_ELEM_SIZE(templ->type & CV_MAT_DEPTH_MASK); + CvScalar b_mean, b_sdv; + double b_denom = 1., b_sum2 = 0; + int area = templ->rows*templ->cols; + + cvAvgSdv(templ, &b_mean, &b_sdv); + + for( i = 0; i < cn; i++ ) + b_sum2 += (b_sdv.val[i]*b_sdv.val[i] + b_mean.val[i]*b_mean.val[i])*area; + + if( b_sdv.val[0]*b_sdv.val[0] + b_sdv.val[1]*b_sdv.val[1] + + b_sdv.val[2]*b_sdv.val[2] + b_sdv.val[3]*b_sdv.val[3] < DBL_EPSILON && + method == CV_TM_CCOEFF_NORMED ) + { + cvSet( result, cvScalarAll(1.) ); + return; + } + + if( method & 1 ) + { + b_denom = 0; + if( method != CV_TM_CCOEFF_NORMED ) + { + b_denom = b_sum2; + } + else + { + for( i = 0; i < cn; i++ ) + b_denom += b_sdv.val[i]*b_sdv.val[i]*area; + } + b_denom = sqrt(b_denom); + if( b_denom == 0 ) + b_denom = 1.; + } + + assert( CV_TM_SQDIFF <= method && method <= CV_TM_CCOEFF_NORMED ); + + for( i = 0; i < result->rows; i++ ) + { + for( j = 0; j < result->cols; j++ ) + { + CvScalar a_sum = {{ 0, 0, 0, 0 }}, a_sum2 = {{ 0, 0, 0, 0 }}; + CvScalar ccorr = {{ 0, 0, 0, 0 }}; + double value = 0.; + + if( depth == CV_8U ) + { + const uchar* a = img->data.ptr + i*img->step + j*cn; + const uchar* b = templ->data.ptr; + + if( cn == 1 || method < CV_TM_CCOEFF ) + { + for( k = 0; k < height; k++, a += a_step, b += b_step ) + for( l = 0; l < width_n; l++ ) + { + ccorr.val[0] += a[l]*b[l]; + a_sum.val[0] += a[l]; + a_sum2.val[0] += a[l]*a[l]; + } + } + else + { + for( k = 0; k < height; k++, a += a_step, b += b_step ) + for( l = 0; l < width_n; l += 3 ) + { + ccorr.val[0] += a[l]*b[l]; + ccorr.val[1] += a[l+1]*b[l+1]; + ccorr.val[2] += a[l+2]*b[l+2]; + a_sum.val[0] += a[l]; + a_sum.val[1] += a[l+1]; + a_sum.val[2] += a[l+2]; + a_sum2.val[0] += a[l]*a[l]; + a_sum2.val[1] += a[l+1]*a[l+1]; + a_sum2.val[2] += a[l+2]*a[l+2]; + } + } + } + else + { + const float* a = (const float*)(img->data.ptr + i*img->step) + j*cn; + const float* b = (const float*)templ->data.ptr; + + if( cn == 1 || method < CV_TM_CCOEFF ) + { + for( k = 0; k < height; k++, a += a_step, b += b_step ) + for( l = 0; l < width_n; l++ ) + { + ccorr.val[0] += a[l]*b[l]; + a_sum.val[0] += a[l]; + a_sum2.val[0] += a[l]*a[l]; + } + } + else + { + for( k = 0; k < height; k++, a += a_step, b += b_step ) + for( l = 0; l < width_n; l += 3 ) + { + ccorr.val[0] += a[l]*b[l]; + ccorr.val[1] += a[l+1]*b[l+1]; + ccorr.val[2] += a[l+2]*b[l+2]; + a_sum.val[0] += a[l]; + a_sum.val[1] += a[l+1]; + a_sum.val[2] += a[l+2]; + a_sum2.val[0] += a[l]*a[l]; + a_sum2.val[1] += a[l+1]*a[l+1]; + a_sum2.val[2] += a[l+2]*a[l+2]; + } + } + } + + switch( method ) + { + case CV_TM_CCORR: + case CV_TM_CCORR_NORMED: + value = ccorr.val[0]; + break; + case CV_TM_SQDIFF: + case CV_TM_SQDIFF_NORMED: + value = (a_sum2.val[0] + b_sum2 - 2*ccorr.val[0]); + break; + default: + value = (ccorr.val[0] - a_sum.val[0]*b_mean.val[0]+ + ccorr.val[1] - a_sum.val[1]*b_mean.val[1]+ + ccorr.val[2] - a_sum.val[2]*b_mean.val[2]); + } + + if( method & 1 ) + { + double denom; + + // calc denominator + if( method != CV_TM_CCOEFF_NORMED ) + { + denom = a_sum2.val[0] + a_sum2.val[1] + a_sum2.val[2]; + } + else + { + denom = a_sum2.val[0] - (a_sum.val[0]*a_sum.val[0])/area; + denom += a_sum2.val[1] - (a_sum.val[1]*a_sum.val[1])/area; + denom += a_sum2.val[2] - (a_sum.val[2]*a_sum.val[2])/area; + } + denom = sqrt(MAX(denom,0))*b_denom; + if( fabs(value) < denom ) + value /= denom; + else if( fabs(value) < denom*1.125 ) + value = value > 0 ? 1 : -1; + else + value = method != CV_TM_SQDIFF_NORMED ? 0 : 1; + } + + ((float*)(result->data.ptr + result->step*i))[j] = (float)value; + } + } +} + + +void CV_TemplMatchTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + CvMat _input = test_mat[INPUT][0], _templ = test_mat[INPUT][1]; + CvMat _output = test_mat[REF_OUTPUT][0]; + cvTsMatchTemplate( &_input, &_templ, &_output, method ); + + //if( ts->get_current_test_info()->test_case_idx == 0 ) + /*{ + CvFileStorage* fs = cvOpenFileStorage( "_match_template.yml", 0, CV_STORAGE_WRITE ); + cvWrite( fs, "image", &test_mat[INPUT][0] ); + cvWrite( fs, "template", &test_mat[INPUT][1] ); + cvWrite( fs, "ref", &test_mat[REF_OUTPUT][0] ); + cvWrite( fs, "opencv", &test_mat[OUTPUT][0] ); + cvWriteInt( fs, "method", method ); + cvReleaseFileStorage( &fs ); + }*/ + + if( method >= CV_TM_CCOEFF ) + { + // avoid numerical stability problems in singular cases (when the results are near to 0) + const double delta = 10.; + test_mat[REF_OUTPUT][0] += Scalar::all(delta); + test_mat[OUTPUT][0] += Scalar::all(delta); + } +} + +TEST(Imgproc_MatchTemplate, accuracy) { CV_TemplMatchTest test; test.safe_run(); } diff --git a/imgproc/test/test_thresh.cpp b/imgproc/test/test_thresh.cpp new file mode 100644 index 0000000..80f06b8 --- /dev/null +++ b/imgproc/test/test_thresh.cpp @@ -0,0 +1,321 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +class CV_ThreshTest : public cvtest::ArrayTest +{ +public: + CV_ThreshTest(); + +protected: + void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); + double get_success_error_level( int test_case_idx, int i, int j ); + void run_func(); + void prepare_to_validation( int ); + + int thresh_type; + float thresh_val; + float max_val; +}; + + +CV_ThreshTest::CV_ThreshTest() +{ + test_array[INPUT].push_back(NULL); + test_array[OUTPUT].push_back(NULL); + test_array[REF_OUTPUT].push_back(NULL); + optional_mask = false; + element_wise_relative_error = true; +} + + +void CV_ThreshTest::get_test_array_types_and_sizes( int test_case_idx, + vector >& sizes, vector >& types ) +{ + RNG& rng = ts->get_rng(); + int depth = cvtest::randInt(rng) % 3, cn = cvtest::randInt(rng) % 4 + 1; + cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); + depth = depth == 0 ? CV_8U : depth == 1 ? CV_16S : CV_32F; + + types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth,cn); + thresh_type = cvtest::randInt(rng) % 5; + + if( depth == CV_8U ) + { + thresh_val = (float)(cvtest::randReal(rng)*350. - 50.); + max_val = (float)(cvtest::randReal(rng)*350. - 50.); + if( cvtest::randInt(rng)%4 == 0 ) + max_val = 255.f; + } + else if( depth == CV_16S ) + { + float min_val = SHRT_MIN-100.f; + max_val = SHRT_MAX+100.f; + thresh_val = (float)(cvtest::randReal(rng)*(max_val - min_val) + min_val); + max_val = (float)(cvtest::randReal(rng)*(max_val - min_val) + min_val); + if( cvtest::randInt(rng)%4 == 0 ) + max_val = (float)SHRT_MAX; + } + else + { + thresh_val = (float)(cvtest::randReal(rng)*1000. - 500.); + max_val = (float)(cvtest::randReal(rng)*1000. - 500.); + } +} + + +double CV_ThreshTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) +{ + return FLT_EPSILON*10; +} + + +void CV_ThreshTest::run_func() +{ + cvThreshold( test_array[INPUT][0], test_array[OUTPUT][0], + thresh_val, max_val, thresh_type ); +} + + +static void test_threshold( const Mat& _src, Mat& _dst, + float thresh, float maxval, int thresh_type ) +{ + int i, j; + int depth = _src.depth(), cn = _src.channels(); + int width_n = _src.cols*cn, height = _src.rows; + int ithresh = cvFloor(thresh); + int imaxval, ithresh2; + + if( depth == CV_8U ) + { + ithresh2 = saturate_cast(ithresh); + imaxval = saturate_cast(maxval); + } + else if( depth == CV_16S ) + { + ithresh2 = saturate_cast(ithresh); + imaxval = saturate_cast(maxval); + } + else + { + ithresh2 = cvRound(ithresh); + imaxval = cvRound(maxval); + } + + assert( depth == CV_8U || depth == CV_16S || depth == CV_32F ); + + switch( thresh_type ) + { + case CV_THRESH_BINARY: + for( i = 0; i < height; i++ ) + { + if( depth == CV_8U ) + { + const uchar* src = _src.ptr(i); + uchar* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + dst[j] = (uchar)(src[j] > ithresh ? imaxval : 0); + } + else if( depth == CV_16S ) + { + const short* src = _src.ptr(i); + short* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + dst[j] = (short)(src[j] > ithresh ? imaxval : 0); + } + else + { + const float* src = _src.ptr(i); + float* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + dst[j] = src[j] > thresh ? maxval : 0.f; + } + } + break; + case CV_THRESH_BINARY_INV: + for( i = 0; i < height; i++ ) + { + if( depth == CV_8U ) + { + const uchar* src = _src.ptr(i); + uchar* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + dst[j] = (uchar)(src[j] > ithresh ? 0 : imaxval); + } + else if( depth == CV_16S ) + { + const short* src = _src.ptr(i); + short* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + dst[j] = (short)(src[j] > ithresh ? 0 : imaxval); + } + else + { + const float* src = _src.ptr(i); + float* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + dst[j] = src[j] > thresh ? 0.f : maxval; + } + } + break; + case CV_THRESH_TRUNC: + for( i = 0; i < height; i++ ) + { + if( depth == CV_8U ) + { + const uchar* src = _src.ptr(i); + uchar* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + { + int s = src[j]; + dst[j] = (uchar)(s > ithresh ? ithresh2 : s); + } + } + else if( depth == CV_16S ) + { + const short* src = _src.ptr(i); + short* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + { + int s = src[j]; + dst[j] = (short)(s > ithresh ? ithresh2 : s); + } + } + else + { + const float* src = _src.ptr(i); + float* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + { + float s = src[j]; + dst[j] = s > thresh ? thresh : s; + } + } + } + break; + case CV_THRESH_TOZERO: + for( i = 0; i < height; i++ ) + { + if( depth == CV_8U ) + { + const uchar* src = _src.ptr(i); + uchar* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + { + int s = src[j]; + dst[j] = (uchar)(s > ithresh ? s : 0); + } + } + else if( depth == CV_16S ) + { + const short* src = _src.ptr(i); + short* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + { + int s = src[j]; + dst[j] = (short)(s > ithresh ? s : 0); + } + } + else + { + const float* src = _src.ptr(i); + float* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + { + float s = src[j]; + dst[j] = s > thresh ? s : 0.f; + } + } + } + break; + case CV_THRESH_TOZERO_INV: + for( i = 0; i < height; i++ ) + { + if( depth == CV_8U ) + { + const uchar* src = _src.ptr(i); + uchar* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + { + int s = src[j]; + dst[j] = (uchar)(s > ithresh ? 0 : s); + } + } + else if( depth == CV_16S ) + { + const short* src = _src.ptr(i); + short* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + { + int s = src[j]; + dst[j] = (short)(s > ithresh ? 0 : s); + } + } + else + { + const float* src = _src.ptr(i); + float* dst = _dst.ptr(i); + for( j = 0; j < width_n; j++ ) + { + float s = src[j]; + dst[j] = s > thresh ? 0.f : s; + } + } + } + break; + default: + assert(0); + } +} + + +void CV_ThreshTest::prepare_to_validation( int /*test_case_idx*/ ) +{ + test_threshold( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], + thresh_val, max_val, thresh_type ); +} + +TEST(Imgproc_Threshold, accuracy) { CV_ThreshTest test; test.safe_run(); } + diff --git a/imgproc/test/test_watershed.cpp b/imgproc/test/test_watershed.cpp new file mode 100644 index 0000000..e515c82 --- /dev/null +++ b/imgproc/test/test_watershed.cpp @@ -0,0 +1,133 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "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 Intel Corporation or contributors 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. +// +//M*/ + +#include "test_precomp.hpp" +#include + +using namespace cv; +using namespace std; + +class CV_WatershedTest : public cvtest::BaseTest +{ +public: + CV_WatershedTest(); + ~CV_WatershedTest(); +protected: + void run(int); +}; + +CV_WatershedTest::CV_WatershedTest() {} +CV_WatershedTest::~CV_WatershedTest() {} + +void CV_WatershedTest::run( int /* start_from */) +{ + string exp_path = string(ts->get_data_path()) + "watershed/wshed_exp.png"; + Mat exp = imread(exp_path, 0); + Mat orig = imread(string(ts->get_data_path()) + "inpaint/orig.jpg"); + FileStorage fs(string(ts->get_data_path()) + "watershed/comp.xml", FileStorage::READ); + + if (orig.empty() || !fs.isOpened()) + { + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); + return; + } + + CvSeq* cnts = (CvSeq*)fs["contours"].readObj(); + + Mat markers(orig.size(), CV_32SC1); + markers = Scalar(0); + IplImage iplmrks = markers; + + vector colors(1); + for(int i = 0; cnts != 0; cnts = cnts->h_next, ++i ) + { + cvDrawContours( &iplmrks, cnts, Scalar::all(i + 1), Scalar::all(i + 1), -1, CV_FILLED); + Point* p = (Point*)cvGetSeqElem(cnts, 0); + + //expected image was added with 1 in order to save to png + //so now we substract 1 to get real color + if(exp.data) + colors.push_back(exp.ptr(p->y)[p->x] - 1); + } + fs.release(); + const int compNum = (int)(colors.size() - 1); + + watershed(orig, markers); + + for(int j = 0; j < markers.rows; ++j) + { + int* line = markers.ptr(j); + for(int i = 0; i < markers.cols; ++i) + { + int& pixel = line[i]; + + if (pixel == -1) // border + continue; + + if (pixel <= 0 || pixel > compNum) + continue; // bad result, doing nothing and going to get error latter; + + // repaint in saved color to compare with expected; + if(exp.data) + pixel = colors[pixel]; + } + } + + Mat markers8U; + markers.convertTo(markers8U, CV_8U, 1, 1); + + if( exp.empty() || orig.size() != exp.size() ) + { + imwrite(exp_path, markers8U); + exp = markers8U; + } + + if (0 != norm(markers8U, exp, NORM_INF)) + { + ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH ); + return; + } + ts->set_failed_test_info(cvtest::TS::OK); +} + +TEST(Imgproc_Watershed, regression) { CV_WatershedTest test; test.safe_run(); } +