moved part of video to contrib/{outflow, bgsegm}; moved matlab to contrib

This commit is contained in:
Vadim Pisarevsky 2014-08-10 23:24:16 +04:00
parent 4de4ff5682
commit d0137b6d2d
62 changed files with 54 additions and 159912 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2172,18 +2172,21 @@ void cv::medianBlur( InputArray _src0, OutputArray _dst, int ksize )
} \
while ((void)0, 0)
Ipp32s bufSize;
IppiSize dstRoiSize = ippiSize(dst.cols, dst.rows), maskSize = ippiSize(ksize, ksize);
if( ksize <= 5 )
{
Ipp32s bufSize;
IppiSize dstRoiSize = ippiSize(dst.cols, dst.rows), maskSize = ippiSize(ksize, ksize);
int type = src0.type();
if (type == CV_8UC1)
IPP_FILTER_MEDIAN_BORDER(Ipp8u, ipp8u, 8u_C1R);
else if (type == CV_16UC1)
IPP_FILTER_MEDIAN_BORDER(Ipp16u, ipp16u, 16u_C1R);
else if (type == CV_16SC1)
IPP_FILTER_MEDIAN_BORDER(Ipp16s, ipp16s, 16s_C1R);
else if (type == CV_32FC1)
IPP_FILTER_MEDIAN_BORDER(Ipp32f, ipp32f, 32f_C1R);
int type = src0.type();
if (type == CV_8UC1)
IPP_FILTER_MEDIAN_BORDER(Ipp8u, ipp8u, 8u_C1R);
else if (type == CV_16UC1)
IPP_FILTER_MEDIAN_BORDER(Ipp16u, ipp16u, 16u_C1R);
else if (type == CV_16SC1)
IPP_FILTER_MEDIAN_BORDER(Ipp16s, ipp16s, 16s_C1R);
else if (type == CV_32FC1)
IPP_FILTER_MEDIAN_BORDER(Ipp32f, ipp32f, 32f_C1R);
}
#undef IPP_FILTER_MEDIAN_BORDER
#endif

View File

@ -1,312 +0,0 @@
# ----------------------------------------------------------------------------
# CMake file for Matlab/Octave support
#
# Matlab code generation and compilation is broken down into two distinct
# stages: configure time and build time. The idea is that we want to give
# the user reasonable guarantees that once they type 'make', wrapper
# generation is unlikely to fail. Therefore we run a series of tests at
# configure time to check the working status of the core components.
#
# Configure Time
# During configure time, the script attempts to ascertain whether the
# generator and mex compiler are working for a given architecture.
# Currently this involves:
# 1) Generating a simple CV_EXPORTS_W symbol and checking whether a file
# of the symbol name is generated
# 2) Compiling a simple mex gateway to check that Bridge.hpp and mex.h
# can be found, and that a file with the mexext is produced
#
# Build Time
# If the configure time tests pass, then we assume Matlab wrapper generation
# will not fail during build time. We simply glob all of the symbols in
# the OpenCV module headers, generate intermediate .cpp files, then compile
# them with mex.
# ----------------------------------------------------------------------------
# PREPEND
# Given a list of strings IN and a TOKEN, prepend the token to each string
# and append to OUT. This is used for passing command line "-I", "-L" and "-l"
# arguments to mex. e.g.
# prepend("-I" OUT /path/to/include/dir) --> -I/path/to/include/dir
macro(PREPEND TOKEN OUT IN)
foreach(VAR ${IN} ${ARGN})
list(APPEND ${OUT} "${TOKEN}${VAR}")
endforeach()
endmacro()
# WARN_MIXED_PRECISION
# Formats a warning message if the compiler and Matlab bitness is different
macro(WARN_MIXED_PRECISION COMPILER_BITNESS MATLAB_BITNESS)
set(MSG "Your compiler is ${COMPILER_BITNESS}-bit")
set(MSG "${MSG} but your version of Matlab is ${MATLAB_BITNESS}-bit.")
set(MSG "${MSG} To build Matlab bindings, please switch to a ${MATLAB_BITNESS}-bit compiler.")
message(WARNING ${MSG})
endmacro()
# ----------------------------------------------------------------------------
# Architecture checks
# ----------------------------------------------------------------------------
# make sure we're on a supported architecture with Matlab and python installed
if (IOS OR ANDROID OR NOT MATLAB_FOUND)
ocv_module_disable(matlab)
return()
elseif (NOT PYTHON_DEFAULT_AVAILABLE)
message(WARNING "A required dependency of the matlab module (PythonLibs) was not found. Disabling Matlab bindings...")
ocv_module_disable(matlab)
return()
endif()
# If the user built OpenCV as X-bit, but they have a Y-bit version of Matlab,
# attempting to link to OpenCV during binding generation will fail, since
# mixed precision pointers are not allowed. Disable the bindings.
math(EXPR ARCH "${CMAKE_SIZEOF_VOID_P} * 8")
if (${ARCH} EQUAL 32 AND ${MATLAB_ARCH} MATCHES "64")
warn_mixed_precision("32" "64")
ocv_module_disable(matlab)
return()
elseif (${ARCH} EQUAL 64 AND NOT ${MATLAB_ARCH} MATCHES "64")
warn_mixed_precision("64" "32")
ocv_module_disable(matlab)
return()
endif()
# If it's MSVC, warn the user that bindings will only be built in Release mode.
# Debug mode seems to cause issues...
if (MSVC)
message(STATUS "Warning: Matlab bindings will only be built in Release configurations")
endif()
# ----------------------------------------------------------------------------
# Configure time components
# ----------------------------------------------------------------------------
set(the_description "The Matlab/Octave bindings")
ocv_add_module(matlab BINDINGS
OPTIONAL opencv_core
opencv_imgproc opencv_ml
opencv_imgcodecs opencv_videoio opencv_highgui
opencv_objdetect opencv_flann opencv_features2d
opencv_photo opencv_video opencv_videostab
opencv_calib opencv_calib3d
opencv_stitching opencv_superres
opencv_nonfree
)
# get the commit information
execute_process(COMMAND git log -1 --pretty=%H OUTPUT_VARIABLE GIT_COMMIT ERROR_QUIET)
string(REGEX REPLACE "(\r?\n)+$" "" GIT_COMMIT "${GIT_COMMIT}")
# set the path to the C++ header and doc parser, and template engine
set(JINJA2_PATH ${CMAKE_SOURCE_DIR}/3rdparty)
set(HDR_PARSER_PATH ${CMAKE_SOURCE_DIR}/modules/python/src2)
set(RST_PARSER_PATH ${CMAKE_SOURCE_DIR}/modules/java/generator)
# set mex compiler options
prepend("-I" MEX_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include)
if (MSVC)
prepend("-L" MEX_LIB_DIR ${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR})
else()
prepend("-L" MEX_LIB_DIR ${LIBRARY_OUTPUT_PATH})
endif()
set(MEX_OPTS "-largeArrayDims")
if (BUILD_TESTS)
add_subdirectory(test)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
# intersection of available modules and optional dependencies
# 1. populate the command-line include directories (-I/path/to/module/header, ...)
# 2. populate the command-line link libraries (-lopencv_core, ...) for Debug and Release
set(MATLAB_DEPS ${OPENCV_MODULE_${the_module}_REQ_DEPS} ${OPENCV_MODULE_${the_module}_OPT_DEPS})
foreach(opencv_module ${MATLAB_DEPS})
if (HAVE_${opencv_module})
string(REPLACE "opencv_" "" module ${opencv_module})
list(APPEND opencv_modules ${module})
list(APPEND ${the_module}_ACTUAL_DEPS ${opencv_module})
prepend("-I" MEX_INCLUDE_DIRS "${OPENCV_MODULE_${opencv_module}_LOCATION}/include")
prepend("-l" MEX_LIBS ${opencv_module}${OPENCV_DLLVERSION})
prepend("-l" MEX_DEBUG_LIBS ${opencv_module}${OPENCV_DLLVERSION}${OPENCV_DEBUG_POSTFIX})
endif()
endforeach()
# add extra headers by hand
list(APPEND opencv_extra_hdrs "core=${OPENCV_MODULE_opencv_core_LOCATION}/include/opencv2/core/base.hpp")
list(APPEND opencv_extra_hdrs "video=${OPENCV_MODULE_opencv_video_LOCATION}/include/opencv2/video/tracking.hpp")
# pass the OPENCV_CXX_EXTRA_FLAGS through to the mex compiler
# remove the visibility modifiers, so the mex gateway is visible
# TODO: get mex working without warnings
string(REGEX REPLACE "[^\ ]*visibility[^\ ]*" "" MEX_CXXFLAGS "${OPENCV_EXTRA_FLAGS} ${OPENCV_EXTRA_CXX_FLAGS}")
# Configure checks
# Check to see whether the generator and the mex compiler are working.
# The checks currently test:
# - whether the python generator can be found
# - whether the python generator correctly outputs a file for a definition
# - whether the mex compiler can find the required headers
# - whether the mex compiler can compile a trivial definition
if (NOT MEX_WORKS)
# attempt to generate a gateway for a function
message(STATUS "Trying to generate Matlab code")
execute_process(
COMMAND ${PYTHON_DEFAULT_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/generator/gen_matlab.py
--jinja2 ${JINJA2_PATH}
--hdrparser ${HDR_PARSER_PATH}
--rstparser ${RST_PARSER_PATH}
--extra "test=${CMAKE_CURRENT_SOURCE_DIR}/test/test_generator.hpp"
--outdir ${CMAKE_BINARY_DIR}/junk
ERROR_VARIABLE GEN_ERROR
OUTPUT_QUIET
)
if (GEN_ERROR)
message(${GEN_ERROR})
message(STATUS "Error generating Matlab code. Disabling Matlab bindings...")
ocv_module_disable(matlab)
return()
else()
message(STATUS "Trying to generate Matlab code - OK")
endif()
# attempt to compile a gateway using mex
message(STATUS "Trying to compile mex file")
execute_process(
COMMAND ${MATLAB_MEX_SCRIPT} ${MEX_OPTS} "CXXFLAGS=\$CXXFLAGS ${MEX_CXX_FLAGS}"
${MEX_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/test/test_compiler.cpp
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/junk
ERROR_VARIABLE MEX_ERROR
OUTPUT_QUIET
)
if (MEX_ERROR)
message(${MEX_ERROR})
message(STATUS "Error compiling mex file. Disabling Matlab bindings...")
ocv_module_disable(matlab)
return()
else()
message(STATUS "Trying to compile mex file - OK")
endif()
endif()
# if we make it here, mex works!
set(MEX_WORKS True CACHE BOOL ADVANCED)
# ----------------------------------------------------------------------------
# Build time components
# ----------------------------------------------------------------------------
# proxies
# these proxies are used to trigger the add_custom_commands
# (which do the real work) only when they're outdated
set(GENERATE_PROXY ${CMAKE_CURRENT_BINARY_DIR}/generate.proxy)
set(COMPILE_PROXY ${CMAKE_CURRENT_BINARY_DIR}/compile.proxy)
# TODO: Remove following line before merging with master
file(REMOVE ${GENERATE_PROXY} ${COMPILE_PROXY})
# generate
# call the python executable to generate the Matlab gateways
add_custom_command(
OUTPUT ${GENERATE_PROXY}
COMMAND ${PYTHON_DEFAULT_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/generator/gen_matlab.py
--jinja2 ${JINJA2_PATH}
--hdrparser ${HDR_PARSER_PATH}
--rstparser ${RST_PARSER_PATH}
--moduleroot ${CMAKE_SOURCE_DIR}/modules
--modules ${opencv_modules}
--extra ${opencv_extra_hdrs}
--outdir ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${PYTHON_DEFAULT_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/generator/build_info.py
--jinja2 ${JINJA2_PATH}
--os ${CMAKE_SYSTEM}
--arch ${ARCH} ${CMAKE_SYSTEM_PROCESSOR}
--compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}
--mex_arch ${MATLAB_ARCH}
--mex_script ${MATLAB_MEX_SCRIPT}
--cxx_flags ${MEX_CXXFLAGS}
--opencv_version ${OPENCV_VERSION}
--commit ${GIT_COMMIT}
--modules ${opencv_modules}
--configuration $<CONFIGURATION>
--outdir ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${PYTHON_DEFAULT_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/generator/cvmex.py
--jinja2 ${JINJA2_PATH}
--opts="${MEX_OPTS}"
--include_dirs="${MEX_INCLUDE_DIRS}"
--lib_dir="${MEX_LIB_DIR}"
--libs="${MEX_LIBS}"
--flags ${MEX_CXXFLAGS}
--outdir ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/test/help.m ${CMAKE_CURRENT_BINARY_DIR}/+cv
COMMAND ${CMAKE_COMMAND} -E touch ${GENERATE_PROXY}
COMMENT "Generating Matlab source files"
)
# compile
# call the mex compiler to compile the gateways
# because we don't know the source files at configure-time, this
# has to be executed in a separate script in cmake's script processing mode
add_custom_command(
OUTPUT ${COMPILE_PROXY}
COMMAND ${CMAKE_COMMAND} -DMATLAB_MEX_SCRIPT=${MATLAB_MEX_SCRIPT}
-DMATLAB_MEXEXT=${MATLAB_MEXEXT}
-DMEX_OPTS=${MEX_OPTS}
-DMEX_CXXFLAGS=${MEX_CXX_FLAGS}
-DMEX_INCLUDE_DIRS="${MEX_INCLUDE_DIRS}"
-DMEX_LIB_DIR="${MEX_LIB_DIR}"
-DCONFIGURATION="$<CONFIGURATION>"
-DMEX_LIBS="${MEX_LIBS}"
-DMEX_DEBUG_LIBS="${MEX_DEBUG_LIBS}"
-P ${CMAKE_CURRENT_SOURCE_DIR}/compile.cmake
COMMAND ${CMAKE_COMMAND} -E touch ${COMPILE_PROXY}
COMMENT "Compiling Matlab source files. This could take a while..."
)
# targets
# opencv_matlab_sources --> opencv_matlab
add_custom_target(${the_module}_sources ALL DEPENDS ${GENERATE_PROXY})
add_custom_target(${the_module} ALL DEPENDS ${COMPILE_PROXY})
add_dependencies(${the_module} ${the_module}_sources ${${the_module}_ACTUAL_DEPS})
if (ENABLE_SOLUTION_FOLDERS)
set_target_properties(${the_module} PROPERTIES FOLDER "modules")
endif()
# ----------------------------------------------------------------------------
# Install time components
# ----------------------------------------------------------------------------
# NOTE: Trailing slashes on the DIRECTORY paths are important!
# TODO: What needs to be done with rpath????
# install the +cv directory verbatim
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION ${OPENCV_INCLUDE_INSTALL_PATH})
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/+cv/ DESTINATION matlab/+cv)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cv.m DESTINATION matlab)
# update the custom mex compiler to point to the install locations
string(REPLACE ";" "\\ " MEX_OPTS "${MEX_OPTS}")
string(REPLACE ";" "\\ " MEX_LIBS "${MEX_LIBS}")
string(REPLACE " " "\\ " MEX_CXXFLAGS ${MEX_CXXFLAGS})
string(REPLACE ";" "\\ " MEX_INCLUDE_DIRS "${MEX_INCLUDE_DIRS}")
install(CODE
"execute_process(
COMMAND ${PYTHON_DEFAULT_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/generator/cvmex.py
--jinja2 ${JINJA2_PATH}
--opts=${MEX_OPTS}
--include_dirs=-I${CMAKE_INSTALL_PREFIX}/${OPENCV_INCLUDE_INSTALL_PATH}
--lib_dir=-L${CMAKE_INSTALL_PREFIX}/${OPENCV_LIB_INSTALL_PATH}
--libs=${MEX_LIBS}
--flags=${MEX_CXXFLAGS}
--outdir ${CMAKE_INSTALL_PREFIX}/matlab
)"
)

View File

@ -1,42 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
//
// 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) 2013, OpenCV Foundation, 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.
//
////////////////////////////////////////////////////////////////////////////////

View File

@ -1,394 +0,0 @@
OpenCV Matlab Code Generator
============================
This module contains a code generator to automatically produce Matlab mex wrappers for other modules within the OpenCV library. Once compiled and added to the Matlab path, this gives users the ability to call OpenCV methods natively from within Matlab.
Build
-----
The Matlab code generator is fully integrated into the OpenCV build system. If cmake finds a Matlab installation available on the host system while configuring OpenCV, it will attempt to generate Matlab wrappers for all OpenCV modules. If cmake is having trouble finding your Matlab installation, you can explicitly point it to the root by defining the `MATLAB_ROOT_DIR` variable. For example, on a Mac you could type:
cmake -DMATLAB_ROOT_DIR=/Applications/MATLAB_R2013a.app ..
Install
-------
In order to use the bindings, you will need to add them to the Matlab path. The path to add is:
1. `${CMAKE_BUILD_DIR}/modules/matlab` if you are working from the build tree, or
2. `${CMAKE_INSTALL_PREFIX}/matlab` if you have installed OpenCV
In Matlab, simply run:
addpath('/path/to/opencv/matlab/');
Run
---
Once you've added the bindings directory to the Matlab path, you can start using them straight away! OpenCV calls need to be prefixed with a 'cv' qualifier, to disambiguate them from Matlab methods of the same name. For example, to compute the dft of a matrix, you might do the following:
```matlab
% load an image (Matlab)
I = imread('cameraman.tif');
% compute the DFT (OpenCV)
If = cv.dft(I, cv.DFT_COMPLEX_OUTPUT);
```
As you can see, both OpenCV methods and constants can be used with 'cv' qualification. You can also call:
help cv.dft
to get help on the purpose and call signature of a particular method, or
help cv
to get general help regarding the OpenCV bindings. If you ever run into issues with the bindings
cv.buildInformation();
will produce a printout of diagnostic information pertaining to your particular build of OS, OpenCV and Matlab. It is useful to submit this information alongside a bug report to the OpenCV team.
Writing your own mex files
--------------------------
The Matlab bindings come with a set of utilities to help you quickly write your own mex files using OpenCV definitions. By doing so, you have all the speed and freedom of C++, with the power of OpenCV's math expressions and optimizations.
The first thing you need to learn how to do is write a mex-file with Matlab constructs. Following is a brief example:
```cpp
// include useful constructs
// this automatically includes opencv core.hpp and mex.h)
#include <opencv2/matlab/bridge.hpp>
using namespace cv;
using namespace matlab;
using namespace bridge;
// define the mex gateway
void mexFunction(int nlhs, mxArray* plhs[],
int nrhs, const mxArray* prhs[]) {
// claim the inputs into scoped management
MxArrayVector raw(prhs, prhs+nrhs);
// add an argument parser to automatically handle basic options
ArgumentParser parser("my function");
parser.addVariant(1, 1, "opt");
MxArrayVector reordered = parser.parse(raw);
// if we get here, we know the inputs are valid and reordered. Unpack...
BridgeVector inputs(reordered.begin(), reordered.end());
Mat required = inputs[0].toMat();
string optional = inputs[1].empty() ? "Default string" : inputs[1].toString();
try {
// Do stuff...
} catch(Exception& e) {
error(e.what());
} catch(...) {
error("Uncaught exception occurred");
}
// allocate an output
Bridge out = required;
plhs[0] = out.toMxArray().releaseOwnership();
}
```
There are a couple of important things going on in this example. Firstly, you need to include `<opencv2/matlab/bridge.hpp>` to enable the bridging capabilities. Once you've done this, you get some nice utilities for free. `MxArray` is a class that wraps Matlab's `mxArray*` class in an OOP-style interface. `ArgumentParser` is a class that handles default, optional and named arguments for you, along with multiple possible calling syntaxes. Finally, `Bridge` is a class that allows bidirectional conversions between OpenCV/std and Matlab types.
Once you have written your file, it can be compiled with the provided mex utility:
cv.mex('my_function.cpp');
This utility automatically links in all of the necessary OpenCV libraries to make your function work.
NOTE: OpenCV uses exceptions throughout the codebase. It is a **very** good idea to wrap your code in exception handlers to avoid crashing Matlab in the event of an exception being thrown.
------------------------------------------------------------------
Developer
=========
The following sections contain information for developers seeking to use, understand or extend the Matlab bindings. The bindings are generated in python using a powerful templating engine called Jinja2. Because Matlab mex gateways have a common structure, they are well suited to templatization. There are separate templates for formatting C++ classes, Matlab classes, C++ functions, constants (enums) and documentation.
The task of the generator is two-fold:
1. To parse the OpenCV headers and build a semantic tree that can be fed to the template engine
2. To define type conversions between C++/OpenCV and Matlab types
Once a source file has been generated for each OpenCV definition, and type conversions have been established, the mex compiler is invoked to produce the mex gateway (shared object) and link in the OpenCV libraries.
File layout
-----------
opencv/modules/matlab (this module)
* `CMakeLists.txt` (main cmake configuration file)
* `README.md` (this file)
* `compile.cmake` (the cmake script for compiling generated source code)
* `generator` (the folder containing generator code)
* `filters.py` (template filters)
* `gen_matlab.py` (the binding generator control script)
* `parse_tree.py` (python class to refactor the hdr_parser.py output)
* `templates` (the raw templates for populating classes, constants, functions and docs)
* `include` (C++ headers for the bindings)
* `mxarray.hpp` (C++ OOP-style interface for Matlab mxArray* class)
* `bridge.hpp` (type conversions)
* `map.hpp` (hash map interface for instance storage and method lookup)
* `test` (generator, compiler and binding test scripts)
Call Tree
---------
The cmake call tree can be broken into 3 main components:
1. configure time
2. build time
3. install time
**Find Matlab (configure)**
The first thing to do is discover a Matlab installation on the host system. This is handled by the `OpenCVFindMatlab.cmake` in `opencv/cmake`. On Windows machines it searches the registry and path, while on *NIX machines it searches a set of canonical install paths. Once Matlab has been found, a number of variables are defined, such as the path to the mex compiler, the mex libraries, the mex include paths, the architectural extension, etc.
**Test the generator (configure)**
Attempt to produce a source file for a simple definition. This tests whether python and pythonlibs are correctly invoked on the host.
**Test the mex compiler (configure)**
Attempt to compile a simple definition using the mex compiler. A mex file is actually just a shared object with a special exported symbol `_mexFunction` which serves as the entry-point to the function. As such, the mex compiler is just a set of scripts configuring the system compiler. In most cases this is the same as the OpenCV compiler, but *could* be different. The test checks whether the mex and generator includes can be found, the system libraries can be linked and the passed compiler flags are compatible.
If any of the configure time tests fail, the bindings will be disabled, but the main OpenCV configure will continue without error. The configuration summary will contain the block:
Matlab
mex: /Applications/MATLAB_R2013a.app/bin/mex
compiler/generator: Not working (bindings will not be generated)
**Generate the sources (build)**
Given a set of modules (the intersection of the OpenCV modules being built and the matlab module optional dependencies), the `CppHeaderParser()` from `opencv/modules/python/src2/hdr_parser.py` will parse the module headers and produce a set of definitions.
The `ParseTree()` from `opencv/modules/matlab/generator/parse_tree.py` takes this set of definitions and refactors them into a semantic tree better suited to templatization. For example, a trivial definition from the header parser may look something like:
```python
[fill, void, ['/S'], [cv::Mat&, mat, '', ['/I', '/O']]]
```
The equivalent refactored output will look like:
```python
Function
name = 'fill'
rtype = 'void'
static = True
req =
Argument
name = 'mat'
type = 'cv::Mat'
ref = '&'
I = True
O = True
default = ''
```
The added semantics (Namespace, Class, Function, Argument, name, etc) make it easier for the templating engine to parse, slice and populate definitions.
Once the definitions have been parsed, `gen_matlab.py` passes each definition to the template engine with the appropriate template (class, function, enum, doc) and the filled template gets written to the `${CMAKE_CURRENT_BUILD_DIR}/src` directory.
The generator relies upon a proxy object called `generate.proxy` to determine when the sources are out of date and need to be re-generated.
**Compile the sources (build)**
Once the sources have been generated, they are compiled by the mex compiler. The `compile.cmake` script in `opencv/modules/matlab/` takes responsibility for iterating over each source file in `${CMAKE_CURRENT_BUILD_DIR}/src` and compiling it with the passed includes and OpenCV libraries.
The flags used to compile the main OpenCV libraries are also forwarded to the mex compiler. So if, for example, you compiled OpenCV with SSE support, the mex bindings will also use SSE. Likewise, if you compile OpenCV in debug mode, the bindings will link to the debug version of the libraries.
Importantly, the mex compiler includes the `mxarray.hpp`, `bridge.hpp` and `map.hpp` files from the `opencv/modules/matlab/include` directory. `mxarray.hpp` defines a `MxArray` class which wraps Matlab's `mxArray*` type in a more friendly OOP-syle interface. `bridge.hpp` defines a `Bridge` class which is able to perform type conversions between Matlab types and std/OpenCV types. It can be extended with new definitions using the plugin interface described in that file.
The compiler relies upon a proxy object called `compile.proxy` to determine when the generated sources are out of date and need to be re-compiled.
**Install the files (install)**
At install time, the mex files are put into place at `${CMAKE_INSTALL_PREFIX}/matlab` and their linkages updated.
Jinja2
------
Jinja2 is a powerful templating engine, similar to python's builtin `string.Template` class but implementing the model-view-controller paradigm. For example, a trivial view could be populated as follows:
**view.py**
```html+django
<title>{{ title }}</title>
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username | sanitize }}</a></li>
{% endfor %}
</ul>
```
**model.py**
```python
class User(object):
__init__(self):
self.username = ''
self.url = ''
def sanitize(text):
"""Filter for escaping html tags to prevent code injection"""
```
**controller.py**
```python
def populate(users):
# initialize jinja
jtemplate = jinja2.Environment(loader=FileSystemLoader())
# add the filters to the engine
jtemplate['sanitize'] = sanitize
# get the view
template = jtemplate.get_template('view')
# populate the template with a list of User objects
populated = template.render(title='all users', users=users)
# write to file
with open('users.html', 'wb') as f:
f.write(populated)
```
Thus the style and layout of the view is kept separate from the content (model). This modularity improves readability and maintainability of both the view and content and (for my own sanity) has helped significantly in debugging errors.
File Reference
--------------
**gen_matlab.py**
gen_matlab has the following call signature:
gen_matlab.py --jinja2 path/to/jinja2/engine
--hdrparser path/to/hdr_parser/dir
--rstparser path/to/rst_parser/dir
--moduleroot path/to/opencv/modules
--modules [core imgproc highgui ...]
--extra namespace=/additional/header/to/parse
--outdir /path/to/place/generated/src
**build_info.py**
build_info has the following call signature:
build_info.py --jinja2 path/to/jinja2/engine
--os operating_system_string
--arch [bitness processor]
--compiler [id version]
--mex_arch arch_string
--mex_script /path/to/mex/script
--cxx_flags [-list -of -flags -to -passthrough]
--opencv_version version_string
--commit commit_hash_if_using_git
--modules core imgproc highgui etc
--configuration Debug/Release
--outdir path/to/place/build/info
**cvmex.py**
cvmex.py, the custom compiler generator, has the following call signature:
cvmex.py --jinja2 path/to/jinja2/engine
--opts [-list -of -opts]
--include_dirs [-list -of -opencv_include_directories]
--lib_dir opencv_lib_directory
--libs [-lopencv_core -lopencv_imgproc ...]
--flags [-Wall -opencv_build_flags ...]
--outdir /path/to/generated/output
**parse_tree.py**
To build a parse tree, first parse a set of headers, then invoke the parse tree to refactor the output:
```python
# parse a set of definitions into a dictionary of namespaces
parser = CppHeaderParser()
ns['core'] = parser.parse('path/to/opencv/core.hpp')
# refactor into a semantic tree
parse_tree = ParseTree()
parse_tree.build(ns)
# iterate over the tree
for namespace in parse_tree.namespaces:
for clss in namespace.classes:
# do stuff
for method in namespace.methods:
# do stuff
```
**mxarray.hpp**
mxarray.hpp defines a class called `MxArray` which provides an OOP-style interface for Matlab's homogeneous `mxArray*` type. To create an `MxArray`, you can either inherit an existing array
```cpp
MxArray mat(prhs[0]);
```
or create a new array
```cpp
MxArray mat(5, 5, Matlab::Traits<double>::ScalarType);
MxArray mat = MxArray::Matrix<double>(5, 5);
```
The default constructor allocates a `0 x 0` array. Once you have encapculated an `mxArray*` you can access its properties through member functions:
```cpp
mat.rows();
mat.cols();
mat.size();
mat.channels();
mat.isComplex();
mat.isNumeric();
mat.isLogical();
mat.isClass();
mat.className();
mat.real();
mat.imag();
```
The MxArray object uses scoped memory management. If you wish to pass an MxArray back to Matlab (as a lhs pointer), you need to explicitly release ownership of the array so that it is not destroyed when it leaves scope:
```cpp
plhs[0] = mat.releaseOwnership();
```
mxarray.hpp also includes a number of helper utilities that make working in mex-world a little easier. One such utility is the `ArgumentParser`. `ArgumentParser` automatically handles required and optional arguments to a method, and even enables named arguments as used in many core Matlab functions. For example, if you had a function with the following signature:
```cpp
void f(Mat first, Mat second, Mat mask=Mat(), int dtype=-1);
```
then you can create an `ArgumentParser` as follows:
```cpp
ArgumentParser parser("f");
parser.addVariant(2, 2, "mask", "dtype");
MxArrayVector inputs = parser.parse(prhs, prhs+nrhs);
```
and that will make available the following calling syntaxes:
```matlab
f(first, second);
f(first, second, mask);
f(first, second, mask, dtype);
f(first, second, 'dtype', dtype, 'mask', mask); % optional ordering does not matter
f(first, second, 'dtype', dtype); % only second optional argument provided
f(first, second, mask, 'dtype', dtype); % mixture of ordered and named
```
Further, the output of the `parser.parse()` method will always contain the total number of required and optional arguments that the method can take, with unspecified arguments given by empty matrices. Thus, to check if an optional argument has been given, you can do:
```cpp
int dtype = inputs[3].empty() ? -1 : inputs[3].scalar<double>();
```
**bridge.hpp**
The bridge interface defines a `Bridge` class which provides type conversion between std/OpenCV and Matlab types. A type conversion must provide the following:
```cpp
Bridge& operator=(const MyObject&);
MyObject toMyObject();
operator MyObject();
```
The binding generator will then automatically call the conversion operators (either explicitly or implicitly) if your `MyObject` class is encountered as an input or return from a parsed definition.

View File

@ -1,49 +0,0 @@
# LISTIFY
# Given a string of space-delimited tokens, reparse as a string of
# semi-colon delimited tokens, which in CMake land is exactly equivalent
# to a list
macro(listify OUT_LIST IN_STRING)
string(REPLACE " " ";" ${OUT_LIST} ${IN_STRING})
endmacro()
# listify multiple-argument inputs
listify(MEX_INCLUDE_DIRS_LIST ${MEX_INCLUDE_DIRS})
if (${CONFIGURATION} MATCHES "Debug")
listify(MEX_LIBS_LIST ${MEX_DEBUG_LIBS})
else()
listify(MEX_LIBS_LIST ${MEX_LIBS})
endif()
# if it's MSVC building a Debug configuration, don't build bindings
if ("${CONFIGURATION}" MATCHES "Debug")
message(STATUS "Matlab bindings are only available in Release configurations. Skipping...")
return()
endif()
# -----------------------------------------------------------------------------
# Compile
# -----------------------------------------------------------------------------
# for each generated source file:
# 1. check if the file has already been compiled
# 2. attempt compile if required
# 3. if the compile fails, throw an error and cancel compilation
file(GLOB SOURCE_FILES "${CMAKE_CURRENT_BINARY_DIR}/src/*.cpp")
foreach(SOURCE_FILE ${SOURCE_FILES})
# strip out the filename
get_filename_component(FILENAME ${SOURCE_FILE} NAME_WE)
# compile the source file using mex
if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/+cv/${FILENAME}.${MATLAB_MEXEXT})
execute_process(
COMMAND ${MATLAB_MEX_SCRIPT} ${MEX_OPTS} "CXXFLAGS=\$CXXFLAGS ${MEX_CXXFLAGS}" ${MEX_INCLUDE_DIRS_LIST}
${MEX_LIB_DIR} ${MEX_LIBS_LIST} ${SOURCE_FILE}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/+cv
OUTPUT_QUIET
ERROR_VARIABLE FAILED
)
endif()
# TODO: If a mex file fails to compile, should we error out?
# TODO: Warnings are currently treated as errors...
if (FAILED)
message(FATAL_ERROR "Failed to compile ${FILENAME}: ${FAILED}")
endif()
endforeach()

View File

@ -1,75 +0,0 @@
#!/usr/bin/env python
def substitute(build, output_dir):
# setup the template engine
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jtemplate = Environment(loader=FileSystemLoader(template_dir), trim_blocks=True, lstrip_blocks=True)
# add the filters
jtemplate.filters['csv'] = csv
jtemplate.filters['stripExtraSpaces'] = stripExtraSpaces
# load the template
template = jtemplate.get_template('template_build_info.m')
# create the build directory
output_dir = output_dir+'/+cv'
if not os.path.isdir(output_dir):
os.mkdir(output_dir)
# populate template
populated = template.render(build=build, time=time)
with open(os.path.join(output_dir, 'buildInformation.m'), 'wb') as f:
f.write(populated.encode('utf-8'))
if __name__ == "__main__":
"""
Usage: python build_info.py --jinja2 /path/to/jinja2/engine
--os os_version_string
--arch [bitness processor]
--compiler [id version]
--mex_arch arch_string
--mex_script /path/to/mex/script
--cxx_flags [-list -of -flags -to -passthrough]
--opencv_version version_string
--commit commit_hash_if_using_git
--modules [core imgproc highgui etc]
--configuration Debug/Release
--outdir /path/to/write/build/info
build_info.py generates a Matlab function that can be invoked with a call to
>> cv.buildInformation();
This function prints a summary of the user's OS, OpenCV and Matlab build
given the information passed to this module. build_info.py invokes Jinja2
on the template_build_info.m template.
"""
# parse the input options
import sys, re, os, time
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('--jinja2')
parser.add_argument('--os')
parser.add_argument('--arch', nargs=2)
parser.add_argument('--compiler', nargs='+')
parser.add_argument('--mex_arch')
parser.add_argument('--mex_script')
parser.add_argument('--mex_opts', default=['-largeArrayDims'], nargs='*')
parser.add_argument('--cxx_flags', default=[], nargs='*')
parser.add_argument('--opencv_version', default='', nargs='?')
parser.add_argument('--commit', default='Not in working git tree', nargs='?')
parser.add_argument('--modules', nargs='+')
parser.add_argument('--configuration')
parser.add_argument('--outdir')
build = parser.parse_args()
# add jinja to the path
sys.path.append(build.jinja2)
from filters import *
from jinja2 import Environment, FileSystemLoader
# populate the build info template
substitute(build, build.outdir)

View File

@ -1,63 +0,0 @@
#!/usr/bin/env python
def substitute(cv, output_dir):
# setup the template engine
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jtemplate = Environment(loader=FileSystemLoader(template_dir), trim_blocks=True, lstrip_blocks=True)
# add the filters
jtemplate.filters['cellarray'] = cellarray
jtemplate.filters['split'] = split
jtemplate.filters['csv'] = csv
# load the template
template = jtemplate.get_template('template_cvmex_base.m')
# create the build directory
output_dir = output_dir+'/+cv'
if not os.path.isdir(output_dir):
os.mkdir(output_dir)
# populate template
populated = template.render(cv=cv, time=time)
with open(os.path.join(output_dir, 'mex.m'), 'wb') as f:
f.write(populated.encode('utf-8'))
if __name__ == "__main__":
"""
Usage: python cvmex.py --jinja2 /path/to/jinja2/engine
--opts [-list -of -opts]
--include_dirs [-list -of -opencv_include_directories]
--lib_dir opencv_lib_directory
--libs [-lopencv_core -lopencv_imgproc ...]
--flags [-Wall -opencv_build_flags ...]
--outdir /path/to/generated/output
cvmex.py generates a custom mex compiler that automatically links OpenCV
libraries to built sources where appropriate. The calling syntax is the
same as the builtin mex compiler, with added cv qualification:
>> cv.mex(..., ...);
"""
# parse the input options
import sys, re, os, time
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('--jinja2')
parser.add_argument('--opts')
parser.add_argument('--include_dirs')
parser.add_argument('--lib_dir')
parser.add_argument('--libs')
parser.add_argument('--flags')
parser.add_argument('--outdir')
cv = parser.parse_args()
# add jinja to the path
sys.path.append(cv.jinja2)
from filters import *
from jinja2 import Environment, FileSystemLoader
# populate the mex base template
substitute(cv, cv.outdir)

View File

@ -1,179 +0,0 @@
from textwrap import TextWrapper
import re, os
# precompile a URL matching regular expression
urlexpr = re.compile(r"((https?):((//)|(\\\\))+[\w\d:#@%/;$()~_?\+-=\\\.&]*)", re.MULTILINE|re.UNICODE)
def inputs(args):
'''Keeps only the input arguments in a list of elements.
In OpenCV input arguments are all arguments with names
not beginning with 'dst'
'''
try:
return [arg for arg in args['only'] if arg.I and not arg.O]
except:
return [arg for arg in args if arg.I]
def ninputs(fun):
'''Counts the number of input arguments in the input list'''
return len(inputs(fun.req)) + len(inputs(fun.opt))
def outputs(args):
'''Determines whether any of the given arguments is an output
reference, and returns a list of only those elements.
In OpenCV, output references are preceeded by 'dst'
'''
try:
return [arg for arg in args['only'] if arg.O and not arg.I]
except:
return [arg for arg in args if arg.O]
def only(args):
'''Returns exclusively the arguments which are only inputs
or only outputs'''
d = {};
d['only'] = args
return d
def void(arg):
'''Is the input 'void' '''
return arg == 'void'
def flip(arg):
'''flip the sign of the input'''
return not arg
def noutputs(fun):
'''Counts the number of output arguments in the input list'''
return int(not void(fun.rtp)) + len(outputs(fun.req)) + len(outputs(fun.opt))
def convertibleToInt(string):
'''Can the input string be evaluated to an integer?'''
salt = '1+'
try:
exec(salt+string)
return True
except:
return False
def binaryToDecimal(string):
'''Attempt to convert the input string to floating point representation'''
try:
return str(eval(string))
except:
return string
def formatMatlabConstant(string, table):
'''
Given a string representing a Constant, and a table of all Constants,
attempt to resolve the Constant into a valid Matlab expression
For example, the input
DEPENDENT_VALUE = 1 << FIXED_VALUE
needs to be converted to
DEPENDENT_VALUE = bitshift(1, cv.FIXED_VALUE);
'''
# split the string into expressions
words = re.split('(\W+)', string)
# add a 'cv' prefix if an expression is also a key in the lookup table
words = ''.join([('cv.'+word if word in table else word) for word in words])
# attempt to convert arithmetic expressions and binary/hex to decimal
words = binaryToDecimal(words)
# convert any remaining bitshifts to Matlab 'bitshift' methods
shift = re.sub('[\(\) ]', '', words).split('<<')
words = 'bitshift('+shift[0]+', '+shift[1]+')' if len(shift) == 2 else words
return words
def matlabURL(string):
"""This filter is used to construct a Matlab specific URL that calls the
system browser instead of the (insanely bad) builtin Matlab browser"""
return re.sub(urlexpr, '<a href="matlab: web(\'\\1\', \'-browser\')">\\1</a>', string)
def capitalizeFirst(text):
'''Capitalize only the first character of the text string'''
return text[0].upper() + text[1:]
def toUpperCamelCase(text):
'''variable_name --> VariableName'''
return ''.join([capitalizeFirst(word) for word in text.split('_')])
def toLowerCamelCase(text):
'''variable_name --> variableName'''
upper_camel = toUpperCamelCase(test)
return upper_camel[0].lower() + upper_camel[1:]
def toUnderCase(text):
'''VariableName --> variable_name'''
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', text)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
def stripTags(text):
'''
strip or convert html tags from a text string
<code>content</code> --> content
<anything> --> ''
&lt --> <
&gt --> >
&le --> <=
&ge --> >=
'''
upper = lambda pattern: pattern.group(1).upper()
text = re.sub('<code>(.*?)</code>', upper, text)
text = re.sub('<([^=\s].*?)>', '', text)
text = re.sub('&lt', '<', text)
text = re.sub('&gt', '>', text)
text = re.sub('&le', '<=', text)
text = re.sub('&ge', '>=', text)
return text
def qualify(text, name):
'''Adds uppercase 'CV.' qualification to any occurrences of name in text'''
return re.sub(name.upper(), 'CV.'+name.upper(), text)
def slugify(text):
'''A_Function_name --> a-function-name'''
return text.lower().replace('_', '-')
def filename(fullpath):
'''Returns only the filename without an extension from a file path
eg. /path/to/file.txt --> file
'''
return os.path.splitext(os.path.basename(fullpath))[0]
def split(text, delimiter=' '):
'''Split a text string into a list using the specified delimiter'''
return text.split(delimiter)
def csv(items, sep=', '):
'''format a list with a separator (comma if not specified)'''
return sep.join(item for item in items)
def cellarray(items, escape='\''):
'''format a list of items as a matlab cell array'''
return '{' + ', '.join(escape+item+escape for item in items) + '}'
def stripExtraSpaces(text):
'''Removes superfluous whitespace from a string, including the removal
of all leading and trailing whitespace'''
return ' '.join(text.split())
def comment(text, wrap=80, escape='% ', escape_first='', escape_last=''):
'''comment filter
Takes a string in text, and wraps it to wrap characters in length with
preceding comment escape sequence on each line. escape_first and
escape_last can be used for languages which define block comments.
Examples:
C++ inline comment comment(80, '// ')
C block comment: comment(80, ' * ', '/*', ' */')
Matlab comment: comment(80, '% ')
Matlab block comment: comment(80, '', '%{', '%}')
Python docstrings: comment(80, '', '\'\'\'', '\'\'\'')
'''
tw = TextWrapper(width=wrap-len(escape))
if escape_first:
escape_first = escape_first+'\n'
if escape_last:
escape_last = '\n'+escape_last
escapn = '\n'+escape
lines = text.split('\n')
wlines = (tw.wrap(line) for line in lines)
return escape_first+escape+escapn.join(escapn.join(line) for line in wlines)+escape_last

View File

@ -1,198 +0,0 @@
#!/usr/bin/env python
import sys, re, os, time
from string import Template
from parse_tree import ParseTree, todict, constants
from filters import *
class MatlabWrapperGenerator(object):
"""
MatlabWrapperGenerator is a class for generating Matlab mex sources from
a set of C++ headers. MatlabWrapperGenerator objects can be default
constructed. Given an instance, the gen() method performs the translation.
"""
def gen(self, module_root, modules, extras, output_dir):
"""
Generate a set of Matlab mex source files by parsing exported symbols
in a set of C++ headers. The headers can be input in one (or both) of
two methods:
1. specify module_root and modules
Given a path to the OpenCV module root and a list of module names,
the headers to parse are implicitly constructed.
2. specifiy header locations explicitly in extras
Each element in the list of extras must be of the form:
'namespace=/full/path/to/extra/header.hpp' where 'namespace' is
the namespace in which the definitions should be added.
The output_dir specifies the directory to write the generated sources
to.
"""
# dynamically import the parsers
from jinja2 import Environment, FileSystemLoader
import hdr_parser
import rst_parser
# parse each of the files and store in a dictionary
# as a separate "namespace"
parser = hdr_parser.CppHeaderParser()
rst = rst_parser.RstParser(parser)
rst_parser.verbose = False
rst_parser.show_warnings = False
rst_parser.show_errors = False
rst_parser.show_critical_errors = False
ns = dict((key, []) for key in modules)
doc = dict((key, []) for key in modules)
path_template = Template('${module}/include/opencv2/${module}.hpp')
for module in modules:
# construct a header path from the module root and a path template
header = os.path.join(module_root, path_template.substitute(module=module))
# parse the definitions
ns[module] = parser.parse(header)
# parse the documentation
rst.parse(module, os.path.join(module_root, module))
doc[module] = rst.definitions
rst.definitions = {}
for extra in extras:
module = extra.split("=")[0]
header = extra.split("=")[1]
ns[module] = ns[module] + parser.parse(header) if module in ns else parser.parse(header)
# cleanify the parser output
parse_tree = ParseTree()
parse_tree.build(ns)
# setup the template engine
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jtemplate = Environment(loader=FileSystemLoader(template_dir), trim_blocks=True, lstrip_blocks=True)
# add the custom filters
jtemplate.filters['formatMatlabConstant'] = formatMatlabConstant
jtemplate.filters['convertibleToInt'] = convertibleToInt
jtemplate.filters['toUpperCamelCase'] = toUpperCamelCase
jtemplate.filters['toLowerCamelCase'] = toLowerCamelCase
jtemplate.filters['toUnderCase'] = toUnderCase
jtemplate.filters['matlabURL'] = matlabURL
jtemplate.filters['stripTags'] = stripTags
jtemplate.filters['filename'] = filename
jtemplate.filters['comment'] = comment
jtemplate.filters['inputs'] = inputs
jtemplate.filters['ninputs'] = ninputs
jtemplate.filters['outputs'] = outputs
jtemplate.filters['noutputs'] = noutputs
jtemplate.filters['qualify'] = qualify
jtemplate.filters['slugify'] = slugify
jtemplate.filters['only'] = only
jtemplate.filters['void'] = void
jtemplate.filters['not'] = flip
# load the templates
tfunction = jtemplate.get_template('template_function_base.cpp')
tclassm = jtemplate.get_template('template_class_base.m')
tclassc = jtemplate.get_template('template_class_base.cpp')
tdoc = jtemplate.get_template('template_doc_base.m')
tconst = jtemplate.get_template('template_map_base.m')
# create the build directory
output_source_dir = output_dir+'/src'
output_private_dir = output_source_dir+'/private'
output_class_dir = output_dir+'/+cv'
output_map_dir = output_dir+'/map'
if not os.path.isdir(output_source_dir):
os.makedirs(output_source_dir)
if not os.path.isdir(output_private_dir):
os.makedirs(output_private_dir)
if not os.path.isdir(output_class_dir):
os.makedirs(output_class_dir)
if not os.path.isdir(output_map_dir):
os.makedirs(output_map_dir)
# populate templates
for namespace in parse_tree.namespaces:
# functions
for method in namespace.methods:
populated = tfunction.render(fun=method, time=time, includes=namespace.name)
with open(output_source_dir+'/'+method.name+'.cpp', 'wb') as f:
f.write(populated.encode('utf-8'))
if namespace.name in doc and method.name in doc[namespace.name]:
populated = tdoc.render(fun=method, doc=doc[namespace.name][method.name], time=time)
with open(output_class_dir+'/'+method.name+'.m', 'wb') as f:
f.write(populated.encode('utf-8'))
# classes
for clss in namespace.classes:
# cpp converter
populated = tclassc.render(clss=clss, time=time)
with open(output_private_dir+'/'+clss.name+'Bridge.cpp', 'wb') as f:
f.write(populated.encode('utf-8'))
# matlab classdef
populated = tclassm.render(clss=clss, time=time)
with open(output_class_dir+'/'+clss.name+'.m', 'wb') as f:
f.write(populated.encode('utf-8'))
# create a global constants lookup table
const = dict(constants(todict(parse_tree.namespaces)))
populated = tconst.render(constants=const, time=time)
with open(output_dir+'/cv.m', 'wb') as f:
f.write(populated.encode('utf-8'))
if __name__ == "__main__":
"""
Usage: python gen_matlab.py --jinja2 /path/to/jinja2/engine
--hdrparser /path/to/hdr_parser/dir
--rstparser /path/to/rst_parser/dir
--moduleroot /path/to/opencv/modules
--modules [core imgproc objdetect etc]
--extra namespace=/path/to/extra/header.hpp
--outdir /path/to/output/generated/srcs
gen_matlab.py is the main control script for generating matlab source
files from given set of headers. Internally, gen_matlab:
1. constructs the headers to parse from the module root and list of modules
2. parses the headers using CppHeaderParser
3. refactors the definitions using ParseTree
4. parses .rst docs using RstParser
5. populates the templates for classes, function, enums and docs from the
definitions
gen_matlab.py requires the following inputs:
--jinja2 the path to the Jinja2 templating engine
e.g. ${CMAKE_SOURCE_DIR}/3rdparty
--hdrparser the path to the header parser directory
(opencv/modules/python/src2)
--rstparser the path to the rst parser directory
(opencv/modules/java/generator)
--moduleroot (optional) path to the opencv directory containing the modules
--modules (optional - required if --moduleroot specified) the modules
to produce bindings for. The path to the include directories
as well as the namespaces are constructed from the modules
and the moduleroot
--extra extra headers explicitly defined to parse. This must be in
the format "namepsace=/path/to/extra/header.hpp". For example,
the core module requires the extra header:
"core=/opencv/modules/core/include/opencv2/core/core/base.hpp"
--outdir the output directory to put the generated matlab sources. In
the OpenCV build this is "${CMAKE_CURRENT_BUILD_DIR}/src"
"""
# parse the input options
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('--jinja2')
parser.add_argument('--hdrparser')
parser.add_argument('--rstparser')
parser.add_argument('--moduleroot', default='', required=False)
parser.add_argument('--modules', nargs='*', default=[], required=False)
parser.add_argument('--extra', nargs='*', default=[], required=False)
parser.add_argument('--outdir')
args = parser.parse_args()
# add the hdr_parser and rst_parser modules to the path
sys.path.append(args.jinja2)
sys.path.append(args.hdrparser)
sys.path.append(args.rstparser)
# create the generator
mwg = MatlabWrapperGenerator()
mwg.gen(args.moduleroot, args.modules, args.extra, args.outdir)

View File

@ -1,359 +0,0 @@
import collections
from textwrap import fill
from filters import *
try:
# Python 2.7+
basestring
except NameError:
# Python 3.3+
basestring = str
class ParseTree(object):
"""
The ParseTree class produces a semantic tree of C++ definitions given
the output of the CppHeaderParser (from opencv/modules/python/src2/hdr_parser.py)
The full hierarchy is as follows:
Namespaces
|
|- name
|- Classes
|
|- name
|- Methods
|- Constants
|- Methods
|
|- name
|- static (T/F)
|- return type
|- required Arguments
|
|- name
|- const (T/F)
|- reference ('&'/'*')
|- type
|- input
|- output (pass return by reference)
|- default value
|- optional Arguments
|- Constants
|
|- name
|- const (T/F)
|- reference ('&'/'*')
|- type
|- value
The semantic tree contains substantial information for easily introspecting
information about objects. How many methods does the 'core' namespace have?
Does the 'randn' method have any return by reference (output) arguments?
How many required and optional arguments does the 'add' method have? Is the
variable passed by reference or raw pointer?
Individual definitions from the parse tree (Classes, Functions, Constants)
are passed to the Jinja2 template engine where they are manipulated to
produce Matlab mex sources.
A common call tree for constructing and using a ParseTree object is:
# parse a set of definitions into a dictionary of namespaces
parser = CppHeaderParser()
ns['core'] = parser.parse('path/to/opencv/core.hpp')
# refactor into a semantic tree
parse_tree = ParseTree()
parse_tree.build(ns)
# iterate over the tree
for namespace in parse_tree.namespaces:
for clss in namespace.classes:
# do stuff
for method in namespace.methods:
# do stuff
Calling 'print' on a ParseTree object will reconstruct the definitions
to produce an output resembling the original C++ code.
"""
def __init__(self, namespaces=None):
self.namespaces = namespaces if namespaces else []
def __str__(self):
return '\n\n\n'.join(ns.__str__() for ns in self.namespaces)
def build(self, namespaces):
babel = Translator()
for name, definitions in namespaces.items():
class_tree = {}
methods = []
constants = []
for defn in definitions:
obj = babel.translate(defn)
if obj is None:
continue
if type(obj) is Class or obj.clss:
self.insertIntoClassTree(obj, class_tree)
elif type(obj) is Method:
methods.append(obj)
elif type(obj) is Constant:
constants.append(obj)
else:
raise TypeError('Unexpected object type: '+str(type(obj)))
self.namespaces.append(Namespace(name, constants, list(class_tree.values()), methods))
def insertIntoClassTree(self, obj, class_tree):
cname = obj.name if type(obj) is Class else obj.clss
if not cname:
return
if not cname in class_tree:
# add a new class to the tree
class_tree[cname] = Class(cname)
# insert the definition into the class
val = class_tree[cname]
if type(obj) is Method:
val.methods.append(obj)
elif type(obj) is Constant:
val.constants.append(obj)
else:
raise TypeError('Unexpected object type: '+str(type(obj)))
class Translator(object):
"""
The Translator class does the heavy lifting of translating the nested
list representation of the hdr_parser into individual definitions that
are inserted into the ParseTree.
Translator consists of a top-level method: translate()
along with a number of helper methods: translateClass(), translateMethod(),
translateArgument(), translateConstant(), translateName(), and
translateClassName()
"""
def translate(self, defn):
# --- class ---
# classes have 'class' prefixed on their name
if 'class' in defn[0].split(' ') or 'struct' in defn[0].split(' '):
return self.translateClass(defn)
# --- operators! ---
#TODO: implement operators: http://www.mathworks.com.au/help/matlab/matlab_oop/implementing-operators-for-your-class.html
if 'operator' in defn[0]:
return
# --- constant ---
elif convertibleToInt(defn[1]):
return self.translateConstant(defn)
# --- function ---
# functions either need to have input arguments, or not uppercase names
elif defn[3] or not self.translateName(defn[0]).split('_')[0].isupper():
return self.translateMethod(defn)
# --- constant ---
else:
return self.translateConstant(defn)
def translateClass(self, defn):
return Class()
def translateMethod(self, defn, class_tree=None):
name = self.translateName(defn[0])
clss = self.translateClassName(defn[0])
rtp = defn[1]
static = True if 'S' in ''.join(defn[2]) else False
args = defn[3]
req = []
opt = []
for arg in args:
if arg:
a = self.translateArgument(arg)
opt.append(a) if a.default else req.append(a)
return Method(name, clss, static, '', rtp, False, req, opt)
def translateConstant(self, defn):
const = True if 'const' in defn[0] else False
name = self.translateName(defn[0])
clss = self.translateClassName(defn[0])
tp = 'int'
val = defn[1]
return Constant(name, clss, tp, const, '', val)
def translateArgument(self, defn):
ref = '*' if '*' in defn[0] else ''
ref = '&' if '&' in defn[0] else ref
const = ' const ' in ' '+defn[0]+' '
tp = " ".join([word for word in defn[0].replace(ref, '').split() if not ' const ' in ' '+word+' '])
name = defn[1]
default = defn[2] if defn[2] else ''
modifiers = ''.join(defn[3])
I = True if not modifiers or 'I' in modifiers else False
O = True if 'O' in modifiers else False
return Argument(name, tp, const, I, O, ref, default)
def translateName(self, name):
return name.split(' ')[-1].split('.')[-1]
def translateClassName(self, name):
name = name.split(' ')[-1]
parts = name.split('.')
return parts[-2] if len(parts) > 1 and not parts[-2] == 'cv' else ''
class Namespace(object):
"""
Namespace
|
|- name
|- Constants
|- Methods
|- Constants
"""
def __init__(self, name='', constants=None, classes=None, methods=None):
self.name = name
self.constants = constants if constants else []
self.classes = classes if classes else []
self.methods = methods if methods else []
def __str__(self):
return 'namespace '+self.name+' {\n\n'+\
('\n'.join(c.__str__() for c in self.constants)+'\n\n' if self.constants else '')+\
('\n'.join(f.__str__() for f in self.methods)+'\n\n' if self.methods else '')+\
('\n\n'.join(o.__str__() for o in self.classes) if self.classes else '')+'\n};'
class Class(object):
"""
Class
|
|- name
|- Methods
|- Constants
"""
def __init__(self, name='', namespace='', constants=None, methods=None):
self.name = name
self.namespace = namespace
self.constants = constants if constants else []
self.methods = methods if methods else []
def __str__(self):
return 'class '+self.name+' {\n\t'+\
('\n\t'.join(c.__str__() for c in self.constants)+'\n\n\t' if self.constants else '')+\
('\n\t'.join(f.__str__() for f in self.methods) if self.methods else '')+'\n};'
class Method(object):
"""
Method
int VideoWriter::read( cv::Mat& frame, const cv::Mat& mask=cv::Mat() );
--- ----- ---- -------- ----------------
rtp class name required optional
name the method name
clss the class the method belongs to ('' if free)
static static?
namespace the namespace the method belongs to ('' if free)
rtp the return type
const const?
req list of required arguments
opt list of optional arguments
"""
def __init__(self, name='', clss='', static=False, namespace='', rtp='', const=False, req=None, opt=None):
self.name = name
self.clss = clss
self.constructor = True if name == clss else False
self.static = static
self.const = const
self.namespace = namespace
self.rtp = rtp
self.req = req if req else []
self.opt = opt if opt else []
def __str__(self):
return (self.rtp+' ' if self.rtp else '')+self.name+'('+\
', '.join(arg.__str__() for arg in self.req+self.opt)+\
')'+(' const' if self.const else '')+';'
class Argument(object):
"""
Argument
const cv::Mat& mask=cv::Mat()
----- ---- --- ---- -------
const tp ref name default
name the argument name
tp the argument type
const const?
I is the argument treated as an input?
O is the argument treated as an output (return by reference)
ref is the argument passed by reference? ('*'/'&')
default the default value of the argument ('' if required)
"""
def __init__(self, name='', tp='', const=False, I=True, O=False, ref='', default=''):
self.name = name
self.tp = tp
self.ref = ref
self.I = I
self.O = O
self.const = const
self.default = default
def __str__(self):
return ('const ' if self.const else '')+self.tp+self.ref+\
' '+self.name+('='+self.default if self.default else '')
class Constant(object):
"""
Constant
DFT_COMPLEX_OUTPUT = 12;
---- -------
name default
name the name of the constant
clss the class that the constant belongs to ('' if free)
tp the type of the constant ('' if int)
const const?
ref is the constant a reference? ('*'/'&')
default default value, required for constants
"""
def __init__(self, name='', clss='', tp='', const=False, ref='', default=''):
self.name = name
self.clss = clss
self.tp = tp
self.ref = ref
self.const = const
self.default = default
def __str__(self):
return ('const ' if self.const else '')+self.tp+self.ref+\
' '+self.name+('='+self.default if self.default else '')+';'
def constants(tree):
"""
recursive generator to strip all Constant objects from the ParseTree
and place them into a flat dictionary of { name, value (default) }
"""
if isinstance(tree, dict) and 'constants' in tree and isinstance(tree['constants'], list):
for node in tree['constants']:
yield (node['name'], node['default'])
if isinstance(tree, dict):
for key, val in tree.items():
for gen in constants(val):
yield gen
if isinstance(tree, list):
for val in tree:
for gen in constants(val):
yield gen
def todict(obj):
"""
Recursively convert a Python object graph to sequences (lists)
and mappings (dicts) of primitives (bool, int, float, string, ...)
"""
if isinstance(obj, basestring):
return obj
elif isinstance(obj, dict):
return dict((key, todict(val)) for key, val in obj.items())
elif isinstance(obj, collections.Iterable):
return [todict(val) for val in obj]
elif hasattr(obj, '__dict__'):
return todict(vars(obj))
elif hasattr(obj, '__slots__'):
return todict(dict((name, getattr(obj, name)) for name in getattr(obj, '__slots__')))
return obj

View File

@ -1,149 +0,0 @@
/*
* compose
* compose a function call
* This macro takes as input a Method object and composes
* a function call by inspecting the types and argument names
*/
{% macro compose(fun) %}
{# ----------- Return type ------------- #}
{%- if not fun.rtp|void and not fun.constructor -%} retval = {% endif -%}
{%- if fun.constructor -%}{{fun.clss}} obj = {% endif -%}
{%- if fun.clss and not fun.constructor -%}inst.{%- else -%} cv:: {%- endif -%}
{{fun.name}}(
{#- ----------- Required ------------- -#}
{%- for arg in fun.req -%}
{%- if arg.ref == '*' -%}&{%- endif -%}
{{arg.name}}
{%- if not loop.last %}, {% endif %}
{% endfor %}
{#- ----------- Optional ------------- -#}
{% if fun.req and fun.opt %}, {% endif %}
{%- for opt in fun.opt -%}
{%- if opt.ref == '*' -%}&{%- endif -%}
{{opt.name}}
{%- if not loop.last -%}, {% endif %}
{%- endfor -%}
);
{%- endmacro %}
/*
* composeMatlab
* compose a Matlab function call
* This macro takes as input a Method object and composes
* a Matlab function call by inspecting the types and argument names
*/
{% macro composeMatlab(fun) %}
{# ----------- Return type ------------- #}
{%- if fun|noutputs > 1 -%}[{% endif -%}
{%- if not fun.rtp|void -%}LVALUE{% endif -%}
{%- if not fun.rtp|void and fun|noutputs > 1 -%},{% endif -%}
{# ------------- Outputs ------------- -#}
{%- for arg in fun.req|outputs + fun.opt|outputs -%}
{{arg.name}}
{%- if arg.I -%}_out{%- endif -%}
{%- if not loop.last %}, {% endif %}
{% endfor %}
{%- if fun|noutputs > 1 -%}]{% endif -%}
{%- if fun|noutputs %} = {% endif -%}
cv.{{fun.name}}(
{#- ------------ Inputs -------------- -#}
{%- for arg in fun.req|inputs + fun.opt|inputs -%}
{{arg.name}}
{%- if arg.O -%}_in{%- endif -%}
{%- if not loop.last %}, {% endif -%}
{% endfor -%}
);
{%- endmacro %}
/*
* composeVariant
* compose a variant call for the ArgumentParser
*/
{% macro composeVariant(fun) %}
addVariant("{{ fun.name }}", {{ fun.req|inputs|length }}, {{ fun.opt|inputs|length }}
{%- if fun.opt|inputs|length %}, {% endif -%}
{%- for arg in fun.opt|inputs -%}
"{{arg.name}}"
{%- if not loop.last %}, {% endif -%}
{% endfor -%}
)
{%- endmacro %}
/*
* composeWithExceptionHandler
* compose a function call wrapped in exception traps
* This macro takes an input a Method object and composes a function
* call through the compose() macro, then wraps the return in traps
* for cv::Exceptions, std::exceptions, and all generic exceptions
* and returns a useful error message to the Matlab interpreter
*/
{%- macro composeWithExceptionHandler(fun) -%}
// call the opencv function
// [out =] namespace.fun(src1, ..., srcn, dst1, ..., dstn, opt1, ..., optn);
try {
{{ compose(fun) }}
} catch(cv::Exception& e) {
error(std::string("cv::exception caught: ").append(e.what()).c_str());
} catch(std::exception& e) {
error(std::string("std::exception caught: ").append(e.what()).c_str());
} catch(...) {
error("Uncaught exception occurred in {{fun.name}}");
}
{%- endmacro %}
/*
* handleInputs
* unpack input arguments from the Bridge
* Given an input Bridge object, this unpacks the object from the Bridge and
* casts them into the correct type
*/
{%- macro handleInputs(fun) %}
{% if fun|ninputs or (fun|noutputs and not fun.constructor) %}
// unpack the arguments
{# ----------- Inputs ------------- #}
{% for arg in fun.req|inputs %}
{{arg.tp}} {{arg.name}} = inputs[{{ loop.index0 }}].to{{arg.tp|toUpperCamelCase}}();
{% endfor %}
{% for opt in fun.opt|inputs %}
{{opt.tp}} {{opt.name}} = inputs[{{loop.index0 + fun.req|inputs|length}}].empty() ? ({{opt.tp}}) {% if opt.ref == '*' -%} {{opt.tp}}() {%- else -%} {{opt.default}} {%- endif %} : inputs[{{loop.index0 + fun.req|inputs|length}}].to{{opt.tp|toUpperCamelCase}}();
{% endfor %}
{# ----------- Outputs ------------ #}
{% for arg in fun.req|only|outputs %}
{{arg.tp}} {{arg.name}};
{% endfor %}
{% for opt in fun.opt|only|outputs %}
{{opt.tp}} {{opt.name}};
{% endfor %}
{% if not fun.rtp|void and not fun.constructor %}
{{fun.rtp}} retval;
{% endif %}
{% endif %}
{%- endmacro %}
/*
* handleOutputs
* pack outputs into the bridge
* Given a set of outputs, this methods assigns them into the bridge for
* return to the calling method
*/
{%- macro handleOutputs(fun) %}
{% if fun|noutputs %}
// assign the outputs into the bridge
{% if not fun.rtp|void and not fun.constructor %}
outputs[0] = retval;
{% endif %}
{% for arg in fun.req|outputs %}
outputs[{{loop.index0 + fun.rtp|void|not}}] = {{arg.name}};
{% endfor %}
{% for opt in fun.opt|outputs %}
outputs[{{loop.index0 + fun.rtp|void|not + fun.req|outputs|length}}] = {{opt.name}};
{% endfor %}
{% endif %}
{%- endmacro %}

View File

@ -1,41 +0,0 @@
function buildInformation()
%CV.BUILDINFORMATION display OpenCV Toolbox build information
%
% Call CV.BUILDINFORMATION() to get a printout of diagonstic information
% pertaining to your particular build of the OpenCV Toolbox. If you ever
% run into issues with the Toolbox, it is useful to submit this
% information alongside a bug report to the OpenCV team.
%
% Copyright {{ time.strftime("%Y", time.localtime()) }} The OpenCV Foundation
%
info = {
' ------------------------------------------------------------------------'
' <strong>OpenCV Toolbox</strong>'
' Build and diagnostic information'
' ------------------------------------------------------------------------'
''
' <strong>Platform</strong>'
' OS: {{ build.os }}'
' Architecture: {{ build.arch[0] }}-bit {{ build.arch[1] }}'
' Compiler: {{ build.compiler | csv(' ') }}'
''
' <strong>Matlab</strong>'
[' Version: ' version()]
[' Mex extension: ' mexext()]
' Architecture: {{ build.mex_arch }}'
' Mex path: {{ build.mex_script }}'
' Mex flags: {{ build.mex_opts | csv(' ') }}'
' CXX flags: {{ build.cxx_flags | csv(' ') | stripExtraSpaces | wordwrap(60, True, '\'\n\' ') }}'
''
' <strong>OpenCV</strong>'
' Version: {{ build.opencv_version }}'
' Commit: {{ build.commit }}'
' Configuration: {{ build.configuration }}'
' Modules: {{ build.modules | csv | wordwrap(60, True, '\'\n\' ') }}'
''
};
info = cellfun(@(x) [x '\n'], info, 'UniformOutput', false);
info = horzcat(info{:});
fprintf(info);
end

View File

@ -1,98 +0,0 @@
{% import 'functional.cpp' as functional %}
/*
* file: {{clss.name}}Bridge.cpp
* author: A trusty code generator
* date: {{time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())}}
*
* This file was autogenerated, do not modify.
* See LICENSE for full modification and redistribution details.
* Copyright {{time.strftime("%Y", time.localtime())}} The OpenCV Foundation
*/
#include <mex.h>
#include <vector>
#include <string>
#include <opencv2/matlab/map.hpp>
#include <opencv2/matlab/bridge.hpp>
#include <opencv2/core.hpp>
using namespace cv;
using namespace matlab;
using namespace bridge;
namespace {
typedef std::vector<Bridge> (*)({{clss.name}}&, const std::vector<Bridge>&) MethodSignature;
{% for function in clss.methods %}
{% if function.constructor %}
// wrapper for {{function.name}}() constructor
{{ function.clss }} {{function.name}}(const std::vector<Bridge>& inputs) {
{{ functional.handleInputs(function) }}
{{ functional.compose(function) }}
return obj;
}
{% else %}
// wrapper for {{function.name}}() method
std::vector<Bridge> {{function.name}}({{clss.name}}& inst, const std::vector<Bridge>& inputs) {
std::vector<Bridge> outputs{% if function|noutputs %}({{function|noutputs}}){% endif %};
{{ functional.handleInputs(function) }}
{{ functional.composeWithExceptionHandler(function) }}
{{ functional.handleOutputs(function) }}
return outputs;
}
{% endif %}
{% endfor %}
Map<std::string, MethodSignature> createMethodMap() {
Map<std::string, MethodSignature> m;
{% for function in clss.methods %}
m["{{function.name}}"] = &{{function.name}};
{% endfor %}
return m;
}
static const Map<std::string, MethodSignature> methods = createMethodMap();
// map of created {{clss.name}} instances. Don't trust the user to keep them safe...
static Map<void *, {{clss.name}}> instances;
/*
* {{ clss.name }}
* Gateway routine
* nlhs - number of return arguments
* plhs - pointers to return arguments
* nrhs - number of input arguments
* prhs - pointers to input arguments
*/
void mexFunction(int nlhs, mxArray* plhs[],
int nrhs, const mxArray* prhs[]) {
// parse the inputs
Bridge method_name(prhs[0]);
Bridge handle(prhs[1]);
std::vector<Bridge> brhs(prhs+2, prhs+nrhs);
// retrieve the instance of interest
try {
{{clss.name}}& inst = instances.at(handle.address());
} catch (const std::out_of_range& e) {
mexErrMsgTxt("Invalid object instance provided");
}
// invoke the correct method on the data
try {
std::vector<Bridge> blhs = (*methods.at(method_name))(inst, brhs);
} catch (const std::out_of_range& e) {
mexErrMsgTxt("Unknown method specified");
}
{% block postfun %}
{% endblock %}
{% block cleanup %}
{% endblock %}
}
} // end namespace

View File

@ -1,31 +0,0 @@
% {{clss.name | upper}}
% Matlab handle class for OpenCV object classes
%
% This file was autogenerated, do not modify.
% See LICENSE for full modification and redistribution details.
% Copyright {{time.strftime("%Y", time.localtime())}} The OpenCV Foundation
classdef {{clss.name}} < handle
properties (SetAccess = private, Hidden = true)
ptr_ = 0; % handle to the underlying c++ clss instance
end
methods
% constructor
function this = {{clss.name}}(varargin)
this.ptr_ = {{clss.name}}Bridge('new', varargin{:});
end
% destructor
function delete(this)
{{clss.name}}Bridge(this.ptr_, 'delete');
end
{% for function in clss.functions %}
% {{function.__str__()}}
function varargout = {{function.name}}(this, varargin)
[varargout{1:nargout}] = {{clss.name}}Bridge('{{function.name}}', this.ptr_, varargin{:});
end
{% endfor %}
end
end

View File

@ -1,46 +0,0 @@
function mex(varargin)
%CV.MEX compile MEX-function with OpenCV linkages
%
% Usage:
% CV.MEX [options ...] file [file file ...]
%
% Description:
% CV.MEX compiles one or more C/C++ source files into a shared-library
% called a mex-file. This function is equivalent to the builtin MEX
% routine, with the notable exception that it automatically resolves
% OpenCV includes, and links in the OpenCV libraries where appropriate.
% It also forwards the flags used to build OpenCV, so architecture-
% specific optimizations can be used.
%
% CV.MEX is designed to be used in situations where the source(s) you
% are compiling contain OpenCV definitions. In such cases, it streamlines
% the finding and including of appropriate OpenCV libraries.
%
% See also: mex
%
% Copyright {{ time.strftime("%Y", time.localtime()) }} The OpenCV Foundation
%
% forward the OpenCV build flags (C++ only)
EXTRA_FLAGS = ['"CXXFLAGS="\$CXXFLAGS '...
'{{ cv.flags | trim | wordwrap(60, false, '\'...\n \'') }}""'];
% add the OpenCV include dirs
INCLUDE_DIRS = {{ cv.include_dirs | split | cellarray | wordwrap(60, false, '...\n ') }};
% add the lib dir (singular in both build tree and install tree)
LIB_DIR = '{{ cv.lib_dir }}';
% add the OpenCV libs. Only the used libs will actually be linked
LIBS = {{ cv.libs | split | cellarray | wordwrap(60, false, '...\n ') }};
% add the mex opts (usually at least -largeArrayDims)
OPTS = {{ cv.opts | split | cellarray | wordwrap(60, false, '...\n ') }};
% merge all of the default options (EXTRA_FLAGS, LIBS, etc) and the options
% and files passed by the user (varargin) into a single cell array
merged = [ {EXTRA_FLAGS}, INCLUDE_DIRS, {LIB_DIR}, LIBS, OPTS, varargin ];
% expand the merged argument list into the builtin mex utility
mex(merged{:});
end

View File

@ -1,62 +0,0 @@
{% import 'functional.cpp' as functional %}
{{ ('CV.' + fun.name | upper + ' ' + doc.brief | stripTags) | comment(75, '%') | matlabURL }}
%
% {{ functional.composeMatlab(fun) | upper }}
{% if doc.long %}
{{ doc.long | stripTags | qualify(fun.name) | comment(75, '% ') | matlabURL }}
{% endif %}
%
{# ----------------------- Returns --------------------- #}
{% if fun.rtp|void|not or fun.req|outputs|length or fun.opt|outputs|length %}
% Returns:
{% if fun.rtp|void|not %}
% LVALUE
{% endif %}
{% for arg in fun.req|outputs + fun.opt|outputs %}
{% set uname = arg.name | upper + ('_OUT' if arg.I else '') %}
{% if arg.name in doc.params %}
{{ (uname + ' ' + doc.params[arg.name]) | stripTags | comment(75, '% ') }}
{% else %}
{{ uname }}
{% endif %}
{% endfor %}
%
{% endif %}
{# ----------------- Required Inputs ------------------- #}
{% if fun.req|inputs|length %}
% Required Inputs:
{% for arg in fun.req|inputs %}
{% set uname = arg.name | upper + ('_IN' if arg.O else '') %}
{% if arg.name in doc.params %}
{{ (uname + ' ' + doc.params[arg.name]) | stripTags | comment(75, '% ') }}
{% else %}
{% endif %}
{% endfor %}
%
{% endif %}
{# ------------------ Optional Inputs ------------------- #}
{% if fun.opt|inputs|length %}
% Optional Inputs:
{% for arg in fun.opt|inputs %}
{% set uname = arg.name | upper + ('_IN' if arg.O else '') + ' (default: ' + arg.default + ')' %}
{% if arg.name in doc.params %}
{{ (uname + ' ' + doc.params[arg.name]) | stripTags | comment(75, '% ') }}
{% else %}
{{ uname }}
{% endif %}
{% endfor %}
%
{% endif %}
{# ---------------------- See also --------------------- #}
{% if 'seealso' in doc %}
% See also: {% for item in doc['seealso'] %}
cv.{{ item }}{% if not loop.last %}, {% endif %}
{% endfor %}
%
{% endif %}
{# ----------------------- Online ---------------------- #}
{% set url = 'http://docs.opencv.org/modules/' + doc.module + '/doc/' + (doc.file|filename) + '.html#' + (fun.name|slugify) %}
% Online docs: {{ url | matlabURL }}
% Copyright {{ time.strftime("%Y", time.localtime()) }} The OpenCV Foundation
%

View File

@ -1,60 +0,0 @@
{% import 'functional.cpp' as functional %}
/*
* file: {{fun.name}}.cpp
* author: A trusty code generator
* date: {{time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())}}
*
* This file was autogenerated, do not modify.
* See LICENSE for full modification and redistribution details.
* Copyright {{time.strftime("%Y", time.localtime())}} The OpenCV Foundation
*/
#include <string>
#include <vector>
#include <cassert>
#include <exception>
#include <opencv2/matlab/bridge.hpp>
#include <opencv2/{{includes}}.hpp>
using namespace cv;
using namespace matlab;
using namespace bridge;
/*
* {{ fun.name }}
* {{ fun }}
* Gateway routine
* nlhs - number of return arguments
* plhs - pointers to return arguments
* nrhs - number of input arguments
* prhs - pointers to input arguments
*/
void mexFunction(int nlhs, mxArray*{% if fun|noutputs %} plhs[]{% else %}*{% endif %},
int nrhs, const mxArray*{% if fun|ninputs %} prhs[]{% else %}*{% endif %}) {
{% if fun|ninputs %}
// parse the inputs
ArgumentParser parser("{{fun.name}}");
parser.{{ functional.composeVariant(fun) }};
MxArrayVector sorted = parser.parse(MxArrayVector(prhs, prhs+nrhs));
{% endif %}
{% if fun|ninputs or fun|noutputs %}
// setup
{% if fun|ninputs %}
BridgeVector inputs(sorted.begin(), sorted.end());
{% endif -%}
{%- if fun|noutputs %}
BridgeVector outputs({{fun|noutputs}});
{% endif %}
{% endif %}
{{ functional.handleInputs(fun) }}
{{ functional.composeWithExceptionHandler(fun) }}
{{ functional.handleOutputs(fun) }}
{% if fun|noutputs %}
// push the outputs back to matlab
for (size_t n = 0; n < static_cast<size_t>(std::max(nlhs,1)); ++n) {
plhs[n] = outputs[n].toMxArray().releaseOwnership();
}
{% endif %}
}

View File

@ -1,71 +0,0 @@
% ------------------------------------------------------------------------
% <strong>OpenCV Toolbox</strong>
% Matlab bindings for the OpenCV library
% ------------------------------------------------------------------------
%
% The OpenCV Toolbox allows you to make calls to native OpenCV methods
% and classes directly from within Matlab.
%
% <strong>PATHS</strong>
% To call OpenCV methods from anywhere in your workspace, add the
% directory containing this file to the path:
%
% addpath(fileparts(which('cv')));
%
% The OpenCV Toolbox contains two important locations:
% cv.m - This file, containing OpenCV enums
% +cv/ - The directory containing the OpenCV methods and classes
%
% <strong>CALLING SYNTAX</strong>
% To call an OpenCV method, class or enum, it must be prefixed with the
% 'cv' qualifier. For example:
%
% % perform a Fourier transform
% Xf = cv.dft(X, cv.DFT_COMPLEX_OUTPUT);
%
% % create a VideoCapture object, and open a file
% camera = cv.VideoCapture();
% camera.open('/path/to/file');
%
% You can specify optional arguments by name, similar to how python
% and many builtin Matlab functions work. For example, the cv.dft
% method used above has an optional 'nonzeroRows' argument. If
% you want to specify that, but keep the default 'flags' behaviour,
% simply call the method as:
%
% Xf = cv.dft(X, 'nonzeroRows', 7);
%
% <strong>HELP</strong>
% Each method has its own help file containing information about the
% arguments, return values, and what operation the method performs.
% You can access this help information by typing:
%
% help cv.methodName
%
% The full list of methods can be found by inspecting the +cv/
% directory. Note that the methods available to you will depend
% on which modules you configured OpenCV to build.
%
% <strong>DIAGNOSTICS</strong>
% If you are having problems with the OpenCV Toolbox and need to send a
% bug report to the OpenCV team, you can get a printout of diagnostic
% information to submit along with your report by typing:
%
% <a href="matlab: cv.buildInformation()">cv.buildInformation();</a>
%
% <strong>OTHER RESOURCES</strong>
% OpenCV documentation online: <a href="matlab: web('http://docs.opencv.org', '-browser')">http://docs.opencv.org</a>
% OpenCV issue tracker: <a href="matlab: web('http://code.opencv.org', '-browser')">http://code.opencv.org</a>
% OpenCV Q&A: <a href="matlab: web('http://answers.opencv.org', '-browser')">http://answers.opencv.org</a>
%
% See also: cv.help, <a href="matlab: cv.buildInformation()">cv.buildInformation</a>
%
% Copyright {{ time.strftime("%Y", time.localtime()) }} The OpenCV Foundation
%
classdef cv
properties (Constant = true)
{% for key, val in constants.items() %}
{{key}} = {{val|formatMatlabConstant(constants)}};
{% endfor %}
end
end

View File

@ -1,616 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
//
// 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) 2013, OpenCV Foundation, 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.
//
////////////////////////////////////////////////////////////////////////////////
#ifndef OPENCV_BRIDGE_HPP_
#define OPENCV_BRIDGE_HPP_
#include "mxarray.hpp"
#include <vector>
#include <string>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/photo.hpp>
#include <opencv2/video.hpp>
namespace cv {
namespace bridge {
/*
* Custom typedefs
* Parsed names from the hdr_parser
*/
typedef std::vector<cv::Mat> vector_Mat;
typedef std::vector<cv::Point> vector_Point;
typedef std::vector<int> vector_int;
typedef std::vector<float> vector_float;
typedef std::vector<cv::String> vector_String;
typedef std::vector<unsigned char> vector_uchar;
typedef std::vector<std::vector<char> > vector_vector_char;
typedef std::vector<std::vector<cv::DMatch> > vector_vector_DMatch;
typedef std::vector<cv::Rect> vector_Rect;
typedef std::vector<cv::KeyPoint> vector_KeyPoint;
typedef cv::Ptr<cv::StereoBM> Ptr_StereoBM;
typedef cv::Ptr<cv::StereoSGBM> Ptr_StereoSGBM;
typedef cv::Ptr<cv::FeatureDetector> Ptr_FeatureDetector;
typedef cv::Ptr<CLAHE> Ptr_CLAHE;
typedef cv::Ptr<LineSegmentDetector> Ptr_LineSegmentDetector;
typedef cv::Ptr<AlignMTB> Ptr_AlignMTB;
typedef cv::Ptr<CalibrateDebevec> Ptr_CalibrateDebevec;
typedef cv::Ptr<CalibrateRobertson> Ptr_CalibrateRobertson;
typedef cv::Ptr<DenseOpticalFlow> Ptr_DenseOpticalFlow;
typedef cv::Ptr<MergeDebevec> Ptr_MergeDebevec;
typedef cv::Ptr<MergeMertens> Ptr_MergeMertens;
typedef cv::Ptr<MergeRobertson> Ptr_MergeRobertson;
typedef cv::Ptr<Tonemap> Ptr_Tonemap;
typedef cv::Ptr<TonemapDrago> Ptr_TonemapDrago;
typedef cv::Ptr<TonemapDurand> Ptr_TonemapDurand;
typedef cv::Ptr<TonemapMantiuk> Ptr_TonemapMantiuk;
typedef cv::Ptr<TonemapReinhard> Ptr_TonemapReinhard;
// ----------------------------------------------------------------------------
// PREDECLARATIONS
// ----------------------------------------------------------------------------
class Bridge;
typedef std::vector<Bridge> BridgeVector;
template <typename InputScalar, typename OutputScalar>
void deepCopyAndTranspose(const cv::Mat& src, matlab::MxArray& dst);
template <typename InputScalar, typename OutputScalar>
void deepCopyAndTranspose(const matlab::MxArray& src, cv::Mat& dst);
// ----------------------------------------------------------------------------
// BRIDGE
// ----------------------------------------------------------------------------
/*!
* @class Bridge
* @brief Type conversion class for converting OpenCV and native C++ types
*
* Bridge provides an interface for converting between OpenCV/C++ types
* to Matlab's mxArray format.
*
* Each type conversion requires three operators:
* // conversion from ObjectType --> Bridge
* Bridge& operator=(const ObjectType&);
* // implicit conversion from Bridge --> ObjectType
* operator ObjectType();
* // explicit conversion from Bridge --> ObjectType
* ObjectType toObjectType();
*
* The bridging class provides common conversions between OpenCV types,
* std and stl types to Matlab's mxArray format. By inheriting Bridge,
* you can add your own custom type conversions.
*
* Because Matlab uses a homogeneous storage type, all operations are provided
* relative to Matlab's type. That is, Bridge always stores an matlab::MxArray object
* and converts to and from other object types on demand.
*
* NOTE: for the explicit conversion function, the object name must be
* in UpperCamelCase, for example:
* int --> toInt
* my_object --> MyObject
* my_Object --> MyObject
* myObject --> MyObject
* this is because the binding generator standardises the calling syntax.
*
* Bridge attempts to make as few assumptions as possible, however in
* some cases where 1-to-1 mappings don't exist, some assumptions are necessary.
* In particular:
* - conversion from of a 2-channel Mat to an mxArray will result in a complex
* output
* - conversion from multi-channel interleaved Mats will result in
* multichannel planar mxArrays
*
*/
class Bridge {
private:
matlab::MxArray ptr_;
public:
// bridges are default constructible
Bridge() {}
virtual ~Bridge() {}
// --------------------------------------------------------------------------
// Bridge Properties
// --------------------------------------------------------------------------
bool empty() const { return ptr_.empty(); }
/*! @brief unpack an object from Matlab into C++
*
* this function checks whether the given bridge is derived from an
* object in Matlab. If so, it converts it to a (platform dependent)
* pointer to the underlying C++ object.
*
* NOTE! This function assumes that the C++ pointer is stored in inst_
*/
template <typename Object>
Object* getObjectByName(const std::string& name) {
// check that the object is actually of correct type before unpacking
// TODO: Traverse class hierarchy?
if (!ptr_.isClass(name)) {
matlab::error(std::string("Expected class ").append(std::string(name))
.append(" but was given ").append(ptr_.className()));
}
// get the instance field
matlab::MxArray inst = ptr_.field("inst_");
Object* obj = NULL;
// make sure the pointer is the correct size for the system
if (sizeof(void *) == 8 && inst.ID() == mxUINT64_CLASS) {
// 64-bit pointers
// TODO: Do we REALLY REALLY need to reinterpret_cast?
obj = reinterpret_cast<Object *>(inst.scalar<uint64_t>());
} else if (sizeof(void *) == 4 && inst.ID() == mxUINT32_CLASS) {
// 32-bit pointers
obj = reinterpret_cast<Object *>(inst.scalar<uint32_t>());
} else {
matlab::error("Incorrect pointer type stored for architecture");
}
// finally check if the object is NULL
matlab::conditionalError(obj, std::string("Object ").append(std::string(name)).append(std::string(" is NULL")));
return obj;
}
// --------------------------------------------------------------------------
// MATLAB TYPES
// --------------------------------------------------------------------------
Bridge& operator=(const mxArray* obj) { ptr_ = obj; return *this; }
Bridge& operator=(const matlab::MxArray& obj) { ptr_ = obj; return *this; }
Bridge(const matlab::MxArray& obj) : ptr_(obj) {}
Bridge(const mxArray* obj) : ptr_(obj) {}
matlab::MxArray toMxArray() { return ptr_; }
// --------------------------------------------------------------------------
// MATRIX CONVERSIONS
// --------------------------------------------------------------------------
Bridge& operator=(const cv::Mat& mat);
cv::Mat toMat() const;
operator cv::Mat() const { return toMat(); }
template <typename Scalar>
static matlab::MxArray FromMat(const cv::Mat& mat) {
matlab::MxArray arr(mat.rows, mat.cols, mat.channels(), matlab::Traits<Scalar>::ScalarType);
switch (mat.depth()) {
case CV_8U: deepCopyAndTranspose<uint8_t, Scalar>(mat, arr); break;
case CV_8S: deepCopyAndTranspose<int8_t, Scalar>(mat, arr); break;
case CV_16U: deepCopyAndTranspose<uint16_t, Scalar>(mat, arr); break;
case CV_16S: deepCopyAndTranspose<int16_t, Scalar>(mat, arr); break;
case CV_32S: deepCopyAndTranspose<int32_t, Scalar>(mat, arr); break;
case CV_32F: deepCopyAndTranspose<float, Scalar>(mat, arr); break;
case CV_64F: deepCopyAndTranspose<double, Scalar>(mat, arr); break;
default: matlab::error("Attempted to convert from unknown class");
}
return arr;
}
template <typename Scalar>
cv::Mat toMat() const {
cv::Mat mat(ptr_.rows(), ptr_.cols(), CV_MAKETYPE(cv::DataType<Scalar>::type, ptr_.channels()));
switch (ptr_.ID()) {
case mxINT8_CLASS: deepCopyAndTranspose<int8_t, Scalar>(ptr_, mat); break;
case mxUINT8_CLASS: deepCopyAndTranspose<uint8_t, Scalar>(ptr_, mat); break;
case mxINT16_CLASS: deepCopyAndTranspose<int16_t, Scalar>(ptr_, mat); break;
case mxUINT16_CLASS: deepCopyAndTranspose<uint16_t, Scalar>(ptr_, mat); break;
case mxINT32_CLASS: deepCopyAndTranspose<int32_t, Scalar>(ptr_, mat); break;
case mxUINT32_CLASS: deepCopyAndTranspose<uint32_t, Scalar>(ptr_, mat); break;
case mxINT64_CLASS: deepCopyAndTranspose<int64_t, Scalar>(ptr_, mat); break;
case mxUINT64_CLASS: deepCopyAndTranspose<uint64_t, Scalar>(ptr_, mat); break;
case mxSINGLE_CLASS: deepCopyAndTranspose<float, Scalar>(ptr_, mat); break;
case mxDOUBLE_CLASS: deepCopyAndTranspose<double, Scalar>(ptr_, mat); break;
case mxCHAR_CLASS: deepCopyAndTranspose<char, Scalar>(ptr_, mat); break;
case mxLOGICAL_CLASS: deepCopyAndTranspose<int8_t, Scalar>(ptr_, mat); break;
default: matlab::error("Attempted to convert from unknown class");
}
return mat;
}
// --------------------------------------------------------------------------
// INTEGRAL TYPES
// --------------------------------------------------------------------------
// --------------------------- string --------------------------------------
Bridge& operator=(const std::string& ) { return *this; }
std::string toString() {
return ptr_.toString();
}
operator std::string() { return toString(); }
// --------------------------- bool --------------------------------------
Bridge& operator=(const bool& ) { return *this; }
bool toBool() { return 0; }
operator bool() { return toBool(); }
// --------------------------- double --------------------------------------
Bridge& operator=(const double& ) { return *this; }
double toDouble() { return ptr_.scalar<double>(); }
operator double() { return toDouble(); }
// --------------------------- float ---------------------------------------
Bridge& operator=(const float& ) { return *this; }
float toFloat() { return ptr_.scalar<float>(); }
operator float() { return toFloat(); }
// --------------------------- int --------------------------------------
Bridge& operator=(const int& ) { return *this; }
int toInt() { return ptr_.scalar<int>(); }
operator int() { return toInt(); }
// --------------------------------------------------------------------------
// CORE OPENCV TYPES
// --------------------------------------------------------------------------
// -------------------------- Point --------------------------------------
Bridge& operator=(const cv::Point& ) { return *this; }
cv::Point toPoint() const { return cv::Point(); }
operator cv::Point() const { return toPoint(); }
// -------------------------- Point2f ------------------------------------
Bridge& operator=(const cv::Point2f& ) { return *this; }
cv::Point2f toPoint2f() const { return cv::Point2f(); }
operator cv::Point2f() const { return toPoint2f(); }
// -------------------------- Point2d ------------------------------------
Bridge& operator=(const cv::Point2d& ) { return *this; }
cv::Point2d toPoint2d() const { return cv::Point2d(); }
operator cv::Point2d() const { return toPoint2d(); }
// -------------------------- Size ---------------------------------------
Bridge& operator=(const cv::Size& ) { return *this; }
cv::Size toSize() const { return cv::Size(); }
operator cv::Size() const { return toSize(); }
// -------------------------- Moments --------------------------------------
Bridge& operator=(const cv::Moments& ) { return *this; }
cv::Moments toMoments() const { return cv::Moments(); }
operator cv::Moments() const { return toMoments(); }
// -------------------------- Scalar --------------------------------------
Bridge& operator=(const cv::Scalar& ) { return *this; }
cv::Scalar toScalar() { return cv::Scalar(); }
operator cv::Scalar() { return toScalar(); }
// -------------------------- Rect -----------------------------------------
Bridge& operator=(const cv::Rect& ) { return *this; }
cv::Rect toRect() { return cv::Rect(); }
operator cv::Rect() { return toRect(); }
// ---------------------- RotatedRect ---------------------------------------
Bridge& operator=(const cv::RotatedRect& ) { return *this; }
cv::RotatedRect toRotatedRect() { return cv::RotatedRect(); }
operator cv::RotatedRect() { return toRotatedRect(); }
// ---------------------- TermCriteria --------------------------------------
Bridge& operator=(const cv::TermCriteria& ) { return *this; }
cv::TermCriteria toTermCriteria() { return cv::TermCriteria(); }
operator cv::TermCriteria() { return toTermCriteria(); }
// ---------------------- RNG --------------------------------------
Bridge& operator=(const cv::RNG& ) { return *this; }
/*! @brief explicit conversion to cv::RNG()
*
* Converts a bridge object to a cv::RNG(). We explicitly assert that
* the object is an RNG in matlab space before attempting to deference
* its pointer
*/
cv::RNG toRNG() {
return (*getObjectByName<cv::RNG>("RNG"));
}
operator cv::RNG() { return toRNG(); }
// --------------------------------------------------------------------------
// OPENCV VECTOR TYPES
// --------------------------------------------------------------------------
// -------------------- vector_Mat ------------------------------------------
Bridge& operator=(const vector_Mat& ) { return *this; }
vector_Mat toVectorMat() { return vector_Mat(); }
operator vector_Mat() { return toVectorMat(); }
// --------------------------- vector_int ----------------------------------
Bridge& operator=(const vector_int& ) { return *this; }
vector_int toVectorInt() { return vector_int(); }
operator vector_int() { return toVectorInt(); }
// --------------------------- vector_float --------------------------------
Bridge& operator=(const vector_float& ) { return *this; }
vector_float toVectorFloat() { return vector_float(); }
operator vector_float() { return toVectorFloat(); }
// --------------------------- vector_Rect ---------------------------------
Bridge& operator=(const vector_Rect& ) { return *this; }
vector_Rect toVectorRect() { return vector_Rect(); }
operator vector_Rect() { return toVectorRect(); }
// --------------------------- vector_KeyPoint -----------------------------
Bridge& operator=(const vector_KeyPoint& ) { return *this; }
vector_KeyPoint toVectorKeyPoint() { return vector_KeyPoint(); }
operator vector_KeyPoint() { return toVectorKeyPoint(); }
// --------------------------- vector_String -------------------------------
Bridge& operator=(const vector_String& ) { return *this; }
vector_String toVectorString() { return vector_String(); }
operator vector_String() { return toVectorString(); }
// ------------------------ vector_Point ------------------------------------
Bridge& operator=(const vector_Point& ) { return *this; }
vector_Point toVectorPoint() { return vector_Point(); }
operator vector_Point() { return toVectorPoint(); }
// ------------------------ vector_uchar ------------------------------------
Bridge& operator=(const vector_uchar& ) { return *this; }
vector_uchar toVectorUchar() { return vector_uchar(); }
operator vector_uchar() { return toVectorUchar(); }
// ------------------------ vector_vector_char ------------------------------
Bridge& operator=(const vector_vector_char& ) { return *this; }
vector_vector_char toVectorVectorChar() { return vector_vector_char(); }
operator vector_vector_char() { return toVectorVectorChar(); }
// ------------------------ vector_vector_DMatch ---------------------------
Bridge& operator=(const vector_vector_DMatch& ) { return *this; }
vector_vector_DMatch toVectorVectorDMatch() { return vector_vector_DMatch(); }
operator vector_vector_DMatch() { return toVectorVectorDMatch(); }
// --------------------------------------------------------------------------
// OPENCV COMPOUND TYPES
// --------------------------------------------------------------------------
// --------------------------- Ptr_StereoBM -----------------------------
Bridge& operator=(const Ptr_StereoBM& ) { return *this; }
Ptr_StereoBM toPtrStereoBM() { return Ptr_StereoBM(); }
operator Ptr_StereoBM() { return toPtrStereoBM(); }
// --------------------------- Ptr_StereoSGBM ---------------------------
Bridge& operator=(const Ptr_StereoSGBM& ) { return *this; }
Ptr_StereoSGBM toPtrStereoSGBM() { return Ptr_StereoSGBM(); }
operator Ptr_StereoSGBM() { return toPtrStereoSGBM(); }
// --------------------------- Ptr_FeatureDetector ----------------------
Bridge& operator=(const Ptr_FeatureDetector& ) { return *this; }
Ptr_FeatureDetector toPtrFeatureDetector() { return Ptr_FeatureDetector(); }
operator Ptr_FeatureDetector() { return toPtrFeatureDetector(); }
// --------------------------- Ptr_CLAHE --------------------------------
Bridge& operator=(const Ptr_CLAHE& ) { return *this; }
Ptr_CLAHE toPtrCLAHE() { return Ptr_CLAHE(); }
operator Ptr_CLAHE() { return toPtrCLAHE(); }
// --------------------------- Ptr_LineSegmentDetector ------------------
Bridge& operator=(const Ptr_LineSegmentDetector& ) { return *this; }
Ptr_LineSegmentDetector toPtrLineSegmentDetector() { return Ptr_LineSegmentDetector(); }
operator Ptr_LineSegmentDetector() { return toPtrLineSegmentDetector(); }
// --------------------------- Ptr_AlignMTB -----------------------------
Bridge& operator=(const Ptr_AlignMTB& ) { return *this; }
Ptr_AlignMTB toPtrAlignMTB() { return Ptr_AlignMTB(); }
operator Ptr_AlignMTB() { return toPtrAlignMTB(); }
// --------------------------- Ptr_CalibrateDebevec -------------------
Bridge& operator=(const Ptr_CalibrateDebevec& ) { return *this; }
Ptr_CalibrateDebevec toPtrCalibrateDebevec() { return Ptr_CalibrateDebevec(); }
operator Ptr_CalibrateDebevec() { return toPtrCalibrateDebevec(); }
// --------------------------- Ptr_CalibrateRobertson -------------------
Bridge& operator=(const Ptr_CalibrateRobertson& ) { return *this; }
Ptr_CalibrateRobertson toPtrCalibrateRobertson() { return Ptr_CalibrateRobertson(); }
operator Ptr_CalibrateRobertson() { return toPtrCalibrateRobertson(); }
// --------------------------- Ptr_DenseOpticalFlow -------------------
Bridge& operator=(const Ptr_DenseOpticalFlow& ) { return *this; }
Ptr_DenseOpticalFlow toPtrDenseOpticalFlow() { return Ptr_DenseOpticalFlow(); }
operator Ptr_DenseOpticalFlow() { return toPtrDenseOpticalFlow(); }
// --------------------------- Ptr_MergeDebevec -----------------------
Bridge& operator=(const Ptr_MergeDebevec& ) { return *this; }
Ptr_MergeDebevec toPtrMergeDebevec() { return Ptr_MergeDebevec(); }
operator Ptr_MergeDebevec() { return toPtrMergeDebevec(); }
// --------------------------- Ptr_MergeMertens -----------------------
Bridge& operator=(const Ptr_MergeMertens& ) { return *this; }
Ptr_MergeMertens toPtrMergeMertens() { return Ptr_MergeMertens(); }
operator Ptr_MergeMertens() { return toPtrMergeMertens(); }
// --------------------------- Ptr_MergeRobertson -----------------------
Bridge& operator=(const Ptr_MergeRobertson& ) { return *this; }
Ptr_MergeRobertson toPtrMergeRobertson() { return Ptr_MergeRobertson(); }
operator Ptr_MergeRobertson() { return toPtrMergeRobertson(); }
// --------------------------- Ptr_Tonemap ------------------------------
Bridge& operator=(const Ptr_Tonemap& ) { return *this; }
Ptr_Tonemap toPtrTonemap() { return Ptr_Tonemap(); }
operator Ptr_Tonemap() { return toPtrTonemap(); }
// --------------------------- Ptr_TonemapDrago -------------------------
Bridge& operator=(const Ptr_TonemapDrago& ) { return *this; }
Ptr_TonemapDrago toPtrTonemapDrago() { return Ptr_TonemapDrago(); }
operator Ptr_TonemapDrago() { return toPtrTonemapDrago(); }
// --------------------------- Ptr_TonemapDurand ------------------------
Bridge& operator=(const Ptr_TonemapDurand& ) { return *this; }
Ptr_TonemapDurand toPtrTonemapDurand() { return Ptr_TonemapDurand(); }
operator Ptr_TonemapDurand() { return toPtrTonemapDurand(); }
// --------------------------- Ptr_TonemapMantiuk -----------------------
Bridge& operator=(const Ptr_TonemapMantiuk& ) { return *this; }
Ptr_TonemapMantiuk toPtrTonemapMantiuk() { return Ptr_TonemapMantiuk(); }
operator Ptr_TonemapMantiuk() { return toPtrTonemapMantiuk(); }
// --------------------------- Ptr_TonemapReinhard ----------------------
Bridge& operator=(const Ptr_TonemapReinhard& ) { return *this; }
Ptr_TonemapReinhard toPtrTonemapReinhard() { return Ptr_TonemapReinhard(); }
operator Ptr_TonemapReinhard() { return toPtrTonemapReinhard(); }
}; // class Bridge
// --------------------------------------------------------------------------
// SPECIALIZATIONS
// --------------------------------------------------------------------------
/*!
* @brief template specialization for inheriting types
*
* This template specialization attempts to preserve the best mapping
* between OpenCV and Matlab types. Matlab uses double types almost universally, so
* all floating float types are converted to doubles.
* Unfortunately OpenCV does not have a native logical type, so
* that gets mapped to an unsigned 8-bit value
*/
template <>
matlab::MxArray Bridge::FromMat<matlab::InheritType>(const cv::Mat& mat) {
switch (mat.depth()) {
case CV_8U: return FromMat<uint8_t>(mat);
case CV_8S: return FromMat<int8_t>(mat);
case CV_16U: return FromMat<uint16_t>(mat);
case CV_16S: return FromMat<int16_t>(mat);
case CV_32S: return FromMat<int32_t>(mat);
case CV_32F: return FromMat<double>(mat); //NOTE: Matlab uses double as native type!
case CV_64F: return FromMat<double>(mat);
default: matlab::error("Attempted to convert from unknown class");
}
return matlab::MxArray();
}
/*!
* @brief template specialization for inheriting types
*
* This template specialization attempts to preserve the best mapping
* between Matlab and OpenCV types. OpenCV has poor support for double precision
* types, so all floating point types are cast to float. Logicals get cast
* to unsignd 8-bit value.
*/
template <>
cv::Mat Bridge::toMat<matlab::InheritType>() const {
switch (ptr_.ID()) {
case mxINT8_CLASS: return toMat<int8_t>();
case mxUINT8_CLASS: return toMat<uint8_t>();
case mxINT16_CLASS: return toMat<int16_t>();
case mxUINT16_CLASS: return toMat<uint16_t>();
case mxINT32_CLASS: return toMat<int32_t>();
case mxUINT32_CLASS: return toMat<int32_t>();
case mxINT64_CLASS: return toMat<int64_t>();
case mxUINT64_CLASS: return toMat<int64_t>();
case mxSINGLE_CLASS: return toMat<float>();
case mxDOUBLE_CLASS: return toMat<float>(); //NOTE: OpenCV uses float as native type!
case mxCHAR_CLASS: return toMat<int8_t>();
case mxLOGICAL_CLASS: return toMat<int8_t>();
default: matlab::error("Attempted to convert from unknown class");
}
return cv::Mat();
}
Bridge& Bridge::operator=(const cv::Mat& mat) { ptr_ = FromMat<matlab::InheritType>(mat); return *this; }
cv::Mat Bridge::toMat() const { return toMat<matlab::InheritType>(); }
// ----------------------------------------------------------------------------
// MATRIX TRANSPOSE
// ----------------------------------------------------------------------------
template <typename InputScalar, typename OutputScalar>
void deepCopyAndTranspose(const cv::Mat& in, matlab::MxArray& out) {
matlab::conditionalError(static_cast<size_t>(in.rows) == out.rows(), "Matrices must have the same number of rows");
matlab::conditionalError(static_cast<size_t>(in.cols) == out.cols(), "Matrices must have the same number of cols");
matlab::conditionalError(static_cast<size_t>(in.channels()) == out.channels(), "Matrices must have the same number of channels");
std::vector<cv::Mat> channels;
cv::split(in, channels);
for (size_t c = 0; c < out.channels(); ++c) {
cv::transpose(channels[c], channels[c]);
cv::Mat outmat(out.cols(), out.rows(), cv::DataType<OutputScalar>::type,
static_cast<void *>(out.real<OutputScalar>() + out.cols()*out.rows()*c));
channels[c].convertTo(outmat, cv::DataType<OutputScalar>::type);
}
//const InputScalar* inp = in.ptr<InputScalar>(0);
//OutputScalar* outp = out.real<OutputScalar>();
//gemt('R', out.rows(), out.cols(), inp, in.step1(), outp, out.rows());
}
template <typename InputScalar, typename OutputScalar>
void deepCopyAndTranspose(const matlab::MxArray& in, cv::Mat& out) {
matlab::conditionalError(in.rows() == static_cast<size_t>(out.rows), "Matrices must have the same number of rows");
matlab::conditionalError(in.cols() == static_cast<size_t>(out.cols), "Matrices must have the same number of cols");
matlab::conditionalError(in.channels() == static_cast<size_t>(out.channels()), "Matrices must have the same number of channels");
std::vector<cv::Mat> channels;
for (size_t c = 0; c < in.channels(); ++c) {
cv::Mat outmat;
cv::Mat inmat(in.cols(), in.rows(), cv::DataType<InputScalar>::type,
static_cast<void *>(const_cast<InputScalar *>(in.real<InputScalar>() + in.cols()*in.rows()*c)));
inmat.convertTo(outmat, cv::DataType<OutputScalar>::type);
cv::transpose(outmat, outmat);
channels.push_back(outmat);
}
cv::merge(channels, out);
//const InputScalar* inp = in.real<InputScalar>();
//OutputScalar* outp = out.ptr<OutputScalar>(0);
//gemt('C', in.rows(), in.cols(), inp, in.rows(), outp, out.step1());
}
} // namespace bridge
} // namespace cv
#endif

View File

@ -1,91 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
//
// 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) 2013, OpenCV Foundation, 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.
//
////////////////////////////////////////////////////////////////////////////////
#ifndef OPENCV_MAP_HPP_
#define OPENCV_MAP_HPP_
namespace matlab {
#if __cplusplus >= 201103L
// If we have C++11 support, we just want to use unordered_map
#include <unordered_map>
template <typename KeyType, typename ValueType>
using Map = std::unordered_map<KeyType, ValueType>;
#else
// If we don't have C++11 support, we wrap another map implementation
// in the same public API as unordered_map
#include <map>
#include <stdexcept>
template <typename KeyType, typename ValueType>
class Map {
private:
std::map<KeyType, ValueType> map_;
public:
// map[key] = val;
ValueType& operator[] (const KeyType& k) {
return map_[k];
}
// map.at(key) = val (throws)
ValueType& at(const KeyType& k) {
typename std::map<KeyType, ValueType>::iterator it;
it = map_.find(k);
if (it == map_.end()) throw std::out_of_range("Key not found");
return *it;
}
// val = map.at(key) (throws, const)
const ValueType& at(const KeyType& k) const {
typename std::map<KeyType, ValueType>::const_iterator it;
it = map_.find(k);
if (it == map_.end()) throw std::out_of_range("Key not found");
return *it;
}
};
} // namespace matlab
#endif
#endif

View File

@ -1,684 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
//
// 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) 2013, OpenCV Foundation, 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.
//
////////////////////////////////////////////////////////////////////////////////
#ifndef OPENCV_MXARRAY_HPP_
#define OPENCV_MXARRAY_HPP_
#include <mex.h>
#include <stdint.h>
#include <cstdarg>
#include <algorithm>
#include <string>
#include <vector>
#include <sstream>
#if __cplusplus > 201103
#include <unordered_set>
typedef std::unordered_set<std::string> StringSet;
#else
#include <set>
typedef std::set<std::string> StringSet;
#endif
/*
* All recent versions of Matlab ship with the MKL library which contains
* a blas extension called mkl_?omatcopy(). This defines an out-of-place
* copy and transpose operation.
*
* The mkl library is in ${MATLAB_ROOT}/bin/${MATLAB_MEXEXT}/libmkl...
* Matlab does not ship headers for the mkl functions, so we define them
* here.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
namespace matlab {
// ----------------------------------------------------------------------------
// PREDECLARATIONS
// ----------------------------------------------------------------------------
class MxArray;
typedef std::vector<MxArray> MxArrayVector;
/*!
* @brief raise error if condition fails
*
* This is a conditional wrapper for mexErrMsgTxt. If the conditional
* expression fails, an error is raised and the mex function returns
* to Matlab, otherwise this function does nothing
*/
static void conditionalError(bool expr, const std::string& str) {
if (!expr) mexErrMsgTxt(std::string("condition failed: ").append(str).c_str());
}
/*!
* @brief raise an error
*
* This function is a wrapper around mexErrMsgTxt
*/
static void error(const std::string& str) {
mexErrMsgTxt(str.c_str());
}
// ----------------------------------------------------------------------------
// MATLAB TRAITS
// ----------------------------------------------------------------------------
class DefaultTraits {};
class InheritType {};
template<typename _Tp = DefaultTraits> class Traits {
public:
static const mxClassID ScalarType = mxUNKNOWN_CLASS;
static const mxComplexity Complex = mxCOMPLEX;
static const mxComplexity Real = mxREAL;
static std::string ToString() { return "Unknown/Unsupported"; }
};
// bool
template<> class Traits<bool> {
public:
static const mxClassID ScalarType = mxLOGICAL_CLASS;
static std::string ToString() { return "boolean"; }
};
// uint8_t
template<> class Traits<uint8_t> {
public:
static const mxClassID ScalarType = mxUINT8_CLASS;
static std::string ToString() { return "uint8_t"; }
};
// int8_t
template<> class Traits<int8_t> {
public:
static const mxClassID ScalarType = mxINT8_CLASS;
static std::string ToString() { return "int8_t"; }
};
// uint16_t
template<> class Traits<uint16_t> {
public:
static const mxClassID ScalarType = mxUINT16_CLASS;
static std::string ToString() { return "uint16_t"; }
};
// int16_t
template<> class Traits<int16_t> {
public:
static const mxClassID ScalarType = mxINT16_CLASS;
static std::string ToString() { return "int16_t"; }
};
// uint32_t
template<> class Traits<uint32_t> {
public:
static const mxClassID ScalarType = mxUINT32_CLASS;
static std::string ToString() { return "uint32_t"; }
};
// int32_t
template<> class Traits<int32_t> {
public:
static const mxClassID ScalarType = mxINT32_CLASS;
static std::string ToString() { return "int32_t"; }
};
// uint64_t
template<> class Traits<uint64_t> {
public:
static const mxClassID ScalarType = mxUINT64_CLASS;
static std::string ToString() { return "uint64_t"; }
};
// int64_t
template<> class Traits<int64_t> {
public:
static const mxClassID ScalarType = mxINT64_CLASS;
static std::string ToString() { return "int64_t"; }
};
// float
template<> class Traits<float> {
public:
static const mxClassID ScalarType = mxSINGLE_CLASS;
static std::string ToString() { return "float"; }
};
// double
template<> class Traits<double> {
public:
static const mxClassID ScalarType = mxDOUBLE_CLASS;
static std::string ToString() { return "double"; }
};
// char
template<> class Traits<char> {
public:
static const mxClassID ScalarType = mxCHAR_CLASS;
static std::string ToString() { return "char"; }
};
// inherited type
template<> class Traits<matlab::InheritType> {
public:
static std::string ToString() { return "Inherited type"; }
};
// ----------------------------------------------------------------------------
// MXARRAY
// ----------------------------------------------------------------------------
/*!
* @class MxArray
* @brief A thin wrapper around Matlab's mxArray types
*
* MxArray provides a thin object oriented wrapper around Matlab's
* native mxArray type which exposes most of the functionality of the
* Matlab interface, but in a more C++ manner. MxArray objects are scoped,
* so you can freely create and destroy them without worrying about memory
* management. If you wish to pass the underlying mxArray* representation
* back to Matlab as an lvalue, see the releaseOwnership() method
*
* MxArrays can be directly converted into OpenCV mat objects and std::string
* objects, since there is a natural mapping between these types. More
* complex types are mapped through the Bridge which does custom conversions
* such as MxArray --> cv::Keypoints, etc
*/
class MxArray {
private:
mxArray* ptr_;
bool owns_;
/*!
* @brief swap all members of this and other
*
* the swap method is used by the assignment and move constructors
* to swap the members of two MxArrays, leaving both in destructible states
*/
friend void swap(MxArray& first, MxArray& second) {
using std::swap;
swap(first.ptr_, second.ptr_);
swap(first.owns_, second.owns_);
}
void dealloc() {
if (owns_ && ptr_) { mxDestroyArray(ptr_); ptr_ = NULL; owns_ = false; }
}
public:
// --------------------------------------------------------------------------
// CONSTRUCTORS
// --------------------------------------------------------------------------
/*!
* @brief default constructor
*
* Construct a valid 0x0 matrix (so all other methods do not need validity checks)
*/
MxArray() : ptr_(mxCreateDoubleMatrix(0, 0, matlab::Traits<>::Real)), owns_(true) {}
/*!
* @brief destructor
*
* The destructor deallocates any data allocated by mxCreate* methods only
* if the object is owned
*/
virtual ~MxArray() {
dealloc();
}
/*!
* @brief inheriting constructor
*
* Inherit an mxArray from Matlab. Don't claim ownership of the array,
* just encapsulate it
*/
MxArray(const mxArray* ptr) : ptr_(const_cast<mxArray *>(ptr)), owns_(false) {}
MxArray& operator=(const mxArray* ptr) {
dealloc();
ptr_ = const_cast<mxArray *>(ptr);
owns_ = false;
return *this;
}
/*!
* @brief explicit typed constructor
*
* This constructor explicitly creates an MxArray of the given size and type.
*/
MxArray(size_t m, size_t n, size_t k, mxClassID id, mxComplexity com = matlab::Traits<>::Real)
: ptr_(NULL), owns_(true) {
mwSize dims[] = { static_cast<mwSize>(m), static_cast<mwSize>(n), static_cast<mwSize>(k) };
ptr_ = mxCreateNumericArray(3, dims, id, com);
}
/*!
* @brief explicit tensor constructor
*
* Explicitly construct a tensor of given size and type. Since constructors cannot
* be explicitly templated, this is a static factory method
*/
template <typename Scalar>
static MxArray Tensor(size_t m, size_t n, size_t k=1) {
return MxArray(m, n, k, matlab::Traits<Scalar>::ScalarType);
}
/*!
* @brief explicit matrix constructor
*
* Explicitly construct a matrix of given size and type. Since constructors cannot
* be explicitly templated, this is a static factory method
*/
template <typename Scalar>
static MxArray Matrix(size_t m, size_t n) {
return MxArray(m, n, 1, matlab::Traits<Scalar>::ScalarType);
}
/*!
* @brief explicit vector constructor
*
* Explicitly construct a vector of given size and type. Since constructors cannot
* be explicitly templated, this is a static factory method
*/
template <typename Scalar>
static MxArray Vector(size_t m) {
return MxArray(m, 1, 1, matlab::Traits<Scalar>::ScalarType);
}
/*!
* @brief explicit scalar constructor
*
* Explicitly construct a scalar of given type. Since constructors cannot
* be explicitly templated, this is a static factory method
*/
template <typename ScalarType>
static MxArray Scalar(ScalarType value = 0) {
MxArray s(1, 1, 1, matlab::Traits<ScalarType>::ScalarType);
s.real<ScalarType>()[0] = value;
return s;
}
/*!
* @brief copy constructor
*
* All copies are deep copies. If you have a C++11 compatible compiler, prefer
* move construction to copy construction
*/
MxArray(const MxArray& other) : ptr_(mxDuplicateArray(other.ptr_)), owns_(true) {}
/*!
* @brief copy-and-swap assignment
*
* This assignment operator uses the copy and swap idiom to provide a strong
* exception guarantee when swapping two objects.
*
* Note in particular that the other MxArray is passed by value, thus invoking
* the copy constructor which performs a deep copy of the input. The members of
* this and other are then swapped
*/
MxArray& operator=(MxArray other) {
swap(*this, other);
return *this;
}
#if __cplusplus >= 201103L
/*
* @brief C++11 move constructor
*
* When C++11 support is available, move construction is used to move returns
* out of functions, etc. This is much fast than copy construction, since the
* move constructed object replaced itself with a default constructed MxArray,
* which is of size 0 x 0.
*/
MxArray(MxArray&& other) : MxArray() {
swap(*this, other);
}
#endif
/*
* @brief release ownership to allow return into Matlab workspace
*
* MxArray is not directly convertible back to mxArray types through assignment
* because the MxArray may have been allocated on the free store, making it impossible
* to know whether the returned pointer will be released by someone else or not.
*
* Since Matlab requires mxArrays be passed back into the workspace, the only way
* to achieve that is through this function, which explicitly releases ownership
* of the object, assuming the Matlab interpreter receving the object will delete
* it at a later time
*
* e.g.
* {
* MxArray A = MxArray::Matrix<double>(5, 5); // allocates memory
* MxArray B = MxArray::Matrix<double>(5, 5); // ditto
* plhs[0] = A; // not allowed!!
* plhs[0] = A.releaseOwnership(); // makes explicit that ownership is being released
* } // end of scope. B is released, A isn't
*
*/
mxArray* releaseOwnership() {
owns_ = false;
return ptr_;
}
MxArray field(const std::string& name) { return MxArray(mxGetField(ptr_, 0, name.c_str())); }
template <typename Scalar>
Scalar* real() { return static_cast<Scalar *>(mxGetData(ptr_)); }
template <typename Scalar>
Scalar* imag() { return static_cast<Scalar *>(mxGetImagData(ptr_)); }
template <typename Scalar>
const Scalar* real() const { return static_cast<const Scalar *>(mxGetData(ptr_)); }
template <typename Scalar>
const Scalar* imag() const { return static_cast<const Scalar *>(mxGetData(ptr_)); }
template <typename Scalar>
Scalar scalar() const { return static_cast<Scalar *>(mxGetData(ptr_))[0]; }
std::string toString() const {
conditionalError(isString(), "Attempted to convert non-string type to string");
std::string str(size(), '\0');
mxGetString(ptr_, const_cast<char *>(str.data()), str.size()+1);
return str;
}
size_t size() const { return mxGetNumberOfElements(ptr_); }
bool empty() const { return size() == 0; }
size_t rows() const { return mxGetDimensions(ptr_)[0]; }
size_t cols() const { return mxGetDimensions(ptr_)[1]; }
size_t channels() const { return (mxGetNumberOfDimensions(ptr_) > 2) ? mxGetDimensions(ptr_)[2] : 1; }
bool isComplex() const { return mxIsComplex(ptr_); }
bool isNumeric() const { return mxIsNumeric(ptr_); }
bool isLogical() const { return mxIsLogical(ptr_); }
bool isString() const { return mxIsChar(ptr_); }
bool isCell() const { return mxIsCell(ptr_); }
bool isStructure() const { return mxIsStruct(ptr_); }
bool isClass(const std::string& name) const { return mxIsClass(ptr_, name.c_str()); }
std::string className() const { return std::string(mxGetClassName(ptr_)); }
mxClassID ID() const { return mxGetClassID(ptr_); }
};
// ----------------------------------------------------------------------------
// ARGUMENT PARSER
// ----------------------------------------------------------------------------
/*! @class ArgumentParser
* @brief parses inputs to a method and resolves the argument names.
*
* The ArgumentParser resolves the inputs to a method. It checks that all
* required arguments are specified and also allows named optional arguments.
* For example, the C++ function:
* void randn(Mat& mat, Mat& mean=Mat(), Mat& std=Mat());
* could be called in Matlab using any of the following signatures:
* \code
* out = randn(in);
* out = randn(in, 0, 1);
* out = randn(in, 'mean', 0, 'std', 1);
* \endcode
*
* ArgumentParser also enables function overloading by allowing users
* to add variants to a method. For example, there may be two C++ sum() methods:
* \code
* double sum(Mat& mat); % sum elements of a matrix
* Mat sum(Mat& A, Mat& B); % add two matrices
* \endcode
*
* by adding two variants to ArgumentParser, the correct underlying sum
* method can be called. If the function call is ambiguous, the
* ArgumentParser will fail with an error message.
*
* The previous example could be parsed as:
* \code
* // set up the Argument parser
* ArgumentParser arguments;
* arguments.addVariant("elementwise", 1);
* arguments.addVariant("matrix", 2);
*
* // parse the arguments
* std::vector<MxArray> inputs;
* inputs = arguments.parse(std::vector<MxArray>(prhs, prhs+nrhs));
*
* // if we get here, one unique variant is valid
* if (arguments.variantIs("elementwise")) {
* // call elementwise sum()
* }
* \endcode
*/
class ArgumentParser {
private:
struct Variant;
typedef std::string String;
typedef std::vector<std::string> StringVector;
typedef std::vector<size_t> IndexVector;
typedef std::vector<Variant> VariantVector;
/* @class Variant
* @brief Describes a variant of arguments to a method
*
* When addVariant() is called on an instance to ArgumentParser, this class
* holds the the information that decribes that variant. The parse() method
* of ArgumentParser then attempts to match a Variant, given a set of
* inputs for a method invocation.
*/
class Variant {
private:
String name_;
size_t Nreq_;
size_t Nopt_;
StringVector keys_;
IndexVector order_;
bool valid_;
size_t nparsed_;
size_t nkeys_;
size_t working_opt_;
bool expecting_val_;
bool using_named_;
size_t find(const String& key) const {
return std::find(keys_.begin(), keys_.end(), key) - keys_.begin();
}
public:
/*! @brief default constructor */
Variant() : Nreq_(0), Nopt_(0), valid_(false) {}
/*! @brief construct a new variant spec */
Variant(const String& name, size_t Nreq, size_t Nopt, const StringVector& keys)
: name_(name), Nreq_(Nreq), Nopt_(Nopt), keys_(keys),
order_(Nreq+Nopt, Nreq+2*Nopt), valid_(true), nparsed_(0), nkeys_(0),
working_opt_(0), expecting_val_(false), using_named_(false) {}
/*! @brief the name of the variant */
String name() const { return name_; }
/*! @brief return the total number of arguments the variant can take */
size_t size() const { return Nreq_ + Nopt_; }
/*! @brief has the variant been fulfilled? */
bool fulfilled() const { return (valid_ && nparsed_ >= Nreq_ && !expecting_val_); }
/*! @brief is the variant in a valid state (though not necessarily fulfilled) */
bool valid() const { return valid_; }
/*! @brief check if the named argument exists in the variant */
bool exist(const String& key) const { return find(key) != keys_.size(); }
/*! @brief retrieve the order mapping raw inputs to their position in the variant */
const IndexVector& order() const { return order_; }
size_t order(size_t n) const { return order_[n]; }
/*! @brief attempt to parse the next argument as a value */
bool parseNextAsValue() {
if (!valid_) {}
else if ((using_named_ && !expecting_val_) || (nparsed_-nkeys_ == Nreq_+Nopt_)) { valid_ = false; }
else if (nparsed_ < Nreq_) { order_[nparsed_] = nparsed_; }
else if (!using_named_) { order_[nparsed_] = nparsed_; }
else if (using_named_ && expecting_val_) { order_[Nreq_ + working_opt_] = nparsed_; }
nparsed_++;
expecting_val_ = false;
return valid_;
}
/*! @biref attempt to parse the next argument as a name (key) */
bool parseNextAsKey(const String& key) {
if (!valid_) {}
else if ((nparsed_ < Nreq_) || (nparsed_-nkeys_ == Nreq_+Nopt_)) { valid_ = false; }
else if (using_named_ && expecting_val_) { valid_ = false; }
else if ((working_opt_ = find(key)) == keys_.size()) { valid_ = false; }
else { using_named_ = true; expecting_val_ = true; nkeys_++; nparsed_++; }
return valid_;
}
String toString(const String& method_name="f") const {
int req_begin = 0, req_end = 0, opt_begin = 0, opt_end = 0;
std::ostringstream s;
// f(...)
s << method_name << "(";
// required arguments
req_begin = s.str().size();
for (size_t n = 0; n < Nreq_; ++n) { s << "src" << n+1 << (n != Nreq_-1 ? ", " : ""); }
req_end = s.str().size();
if (Nreq_ && Nopt_) s << ", ";
// optional arguments
opt_begin = s.str().size();
for (size_t n = 0; n < keys_.size(); ++n) { s << "'" << keys_[n] << "', " << keys_[n] << (n != Nopt_-1 ? ", " : ""); }
opt_end = s.str().size();
s << ");";
if (Nreq_ + Nopt_ == 0) return s.str();
// underscores
String under = String(req_begin, ' ') + String(req_end-req_begin, '-')
+ String(std::max(opt_begin-req_end,0), ' ') + String(opt_end-opt_begin, '-');
s << "\n" << under;
// required and optional sets
String req_set(req_end-req_begin, ' ');
String opt_set(opt_end-opt_begin, ' ');
if (!req_set.empty() && req_set.size() < 8) req_set.replace((req_set.size()-3)/2, 3, "req");
if (req_set.size() > 7) req_set.replace((req_set.size()-8)/2, 8, "required");
if (!opt_set.empty() && opt_set.size() < 8) opt_set.replace((opt_set.size()-3)/2, 3, "opt");
if (opt_set.size() > 7) opt_set.replace((opt_set.size()-8)/2, 8, "optional");
String set = String(req_begin, ' ') + req_set + String(std::max(opt_begin-req_end,0), ' ') + opt_set;
s << "\n" << set;
return s.str();
}
};
/*! @brief given an input and output vector of arguments, and a variant spec, sort */
void sortArguments(Variant& v, MxArrayVector& in, MxArrayVector& out) {
// allocate the output array with ALL arguments
out.resize(v.size());
// reorder the inputs based on the variant ordering
for (size_t n = 0; n < v.size(); ++n) {
if (v.order(n) >= in.size()) continue;
swap(in[v.order(n)], out[n]);
}
}
VariantVector variants_;
String valid_;
String method_name_;
public:
ArgumentParser(const String& method_name) : method_name_(method_name) {}
/*! @brief add a function call variant to the parser
*
* Adds a function-call signature to the parser. The function call *must* be
* unique either in its number of arguments, or in the named-syntax.
* Currently this function does not check whether that invariant stands true.
*
* This function is variadic. If should be called as follows:
* addVariant(2, 2, 'opt_1_name', 'opt_2_name');
*/
void addVariant(const String& name, size_t nreq, size_t nopt = 0, ...) {
StringVector keys;
va_list opt;
va_start(opt, nopt);
for (size_t n = 0; n < nopt; ++n) keys.push_back(va_arg(opt, const char*));
addVariant(name, nreq, nopt, keys);
}
void addVariant(const String& name, size_t nreq, size_t nopt, StringVector keys) {
variants_.push_back(Variant(name, nreq, nopt, keys));
}
/*! @brief check if the valid variant is the key name */
bool variantIs(const String& name) {
return name.compare(valid_) == 0;
}
/*! @brief parse a vector of input arguments
*
* This method parses a vector of input arguments, attempting to match them
* to a Variant spec. For each input, the method attempts to cull any
* Variants which don't match the given inputs so far.
*
* Once all inputs have been parsed, if there is one unique spec remaining,
* the output MxArray vector gets populated with the arguments, with named
* arguments removed. Any optional arguments that have not been encountered
* are set to an empty array.
*
* If multiple variants or no variants match the given call, an error
* message is emitted
*/
MxArrayVector parse(const MxArrayVector& inputs) {
// allocate the outputs
String variant_string;
MxArrayVector outputs;
VariantVector candidates = variants_;
// iterate over the inputs, attempting to match a variant
for (MxArrayVector::const_iterator input = inputs.begin(); input != inputs.end(); ++input) {
String name = input->isString() ? input->toString() : String();
for (VariantVector::iterator candidate = candidates.begin(); candidate < candidates.end(); ++candidate) {
candidate->exist(name) ? candidate->parseNextAsKey(name) : candidate->parseNextAsValue();
}
}
// make sure the candidates have been fulfilled
for (VariantVector::iterator candidate = candidates.begin(); candidate < candidates.end(); ++candidate) {
if (!candidate->fulfilled()) candidate = candidates.erase(candidate)--;
}
// if there is not a unique candidate, throw an error
for (VariantVector::iterator variant = variants_.begin(); variant != variants_.end(); ++variant) {
variant_string += "\n" + variant->toString(method_name_);
}
// if there is not a unique candidate, throw an error
if (candidates.size() > 1) {
error(String("Call to method is ambiguous. Valid variants are:")
.append(variant_string).append("\nUse named arguments to disambiguate call"));
}
if (candidates.size() == 0) {
error(String("No matching method signatures for given arguments. Valid variants are:").append(variant_string));
}
// Unique candidate!
valid_ = candidates[0].name();
sortArguments(candidates[0], const_cast<MxArrayVector&>(inputs), outputs);
return outputs;
}
};
} // namespace matlab
#endif

View File

@ -1,141 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
//
// 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) 2013, OpenCV Foundation, 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.
//
////////////////////////////////////////////////////////////////////////////////
#ifndef OPENCV_TRANSPOSE_HPP_
#define OPENCV_TRANSPOSE_HPP_
template <typename InputScalar, typename OutputScalar>
void transposeBlock(const size_t M, const size_t N, const InputScalar* src, size_t lda, OutputScalar* dst, size_t ldb) {
InputScalar cache[16];
// copy the source into the cache contiguously
for (size_t n = 0; n < N; ++n)
for (size_t m = 0; m < M; ++m)
cache[m+n*4] = src[m+n*lda];
// copy the destination out of the cache contiguously
for (size_t m = 0; m < M; ++m)
for (size_t n = 0; n < N; ++n)
dst[n+m*ldb] = cache[m+n*4];
}
template <typename InputScalar, typename OutputScalar>
void transpose4x4(const InputScalar* src, size_t lda, OutputScalar* dst, size_t ldb) {
InputScalar cache[16];
// copy the source into the cache contiguously
cache[0] = src[0]; cache[1] = src[1]; cache[2] = src[2]; cache[3] = src[3]; src+=lda;
cache[4] = src[0]; cache[5] = src[1]; cache[6] = src[2]; cache[7] = src[3]; src+=lda;
cache[8] = src[0]; cache[9] = src[1]; cache[10] = src[2]; cache[11] = src[3]; src+=lda;
cache[12] = src[0]; cache[13] = src[1]; cache[14] = src[2]; cache[15] = src[3]; src+=lda;
// copy the destination out of the contiguously
dst[0] = cache[0]; dst[1] = cache[4]; dst[2] = cache[8]; dst[3] = cache[12]; dst+=ldb;
dst[0] = cache[1]; dst[1] = cache[5]; dst[2] = cache[9]; dst[3] = cache[13]; dst+=ldb;
dst[0] = cache[2]; dst[1] = cache[6]; dst[2] = cache[10]; dst[3] = cache[14]; dst+=ldb;
dst[0] = cache[3]; dst[1] = cache[7]; dst[2] = cache[11]; dst[3] = cache[15]; dst+=ldb;
}
/*
* Vanilla copy, transpose and cast
*/
template <typename InputScalar, typename OutputScalar>
void gemt(const char major, const size_t M, const size_t N, const InputScalar* a, size_t lda, OutputScalar* b, size_t ldb) {
// 1x1 transpose is just copy
if (M == 1 && N == 1) { *b = *a; return; }
// get the interior 4x4 blocks, and the extra skirting
const size_t Fblock = (major == 'R') ? N/4 : M/4;
const size_t Frem = (major == 'R') ? N%4 : M%4;
const size_t Sblock = (major == 'R') ? M/4 : N/4;
const size_t Srem = (major == 'R') ? M%4 : N%4;
// if less than 4x4, invoke the block transpose immediately
if (M < 4 && N < 4) { transposeBlock(Frem, Srem, a, lda, b, ldb); return; }
// transpose 4x4 blocks
const InputScalar* aptr = a;
OutputScalar* bptr = b;
for (size_t second = 0; second < Sblock; ++second) {
aptr = a + second*lda;
bptr = b + second;
for (size_t first = 0; first < Fblock; ++first) {
transposeBlock(4, 4, aptr, lda, bptr, ldb);
//transpose4x4(aptr, lda, bptr, ldb);
aptr+=4;
bptr+=4*ldb;
}
// transpose trailing blocks on primary dimension
transposeBlock(Frem, 4, aptr, lda, bptr, ldb);
}
// transpose trailing blocks on secondary dimension
aptr = a + 4*Sblock*lda;
bptr = b + 4*Sblock;
for (size_t first = 0; first < Fblock; ++first) {
transposeBlock(4, Srem, aptr, lda, bptr, ldb);
aptr+=4;
bptr+=4*ldb;
}
// transpose bottom right-hand corner
transposeBlock(Frem, Srem, aptr, lda, bptr, ldb);
}
#ifdef __SSE2__
/*
* SSE2 supported fast copy, transpose and cast
*/
#include <emmintrin.h>
template <>
void transpose4x4<float, float>(const float* src, size_t lda, float* dst, size_t ldb) {
__m128 row0, row1, row2, row3;
row0 = _mm_loadu_ps(src);
row1 = _mm_loadu_ps(src+lda);
row2 = _mm_loadu_ps(src+2*lda);
row3 = _mm_loadu_ps(src+3*lda);
_MM_TRANSPOSE4_PS(row0, row1, row2, row3);
_mm_storeu_ps(dst, row0);
_mm_storeu_ps(dst+ldb, row1);
_mm_storeu_ps(dst+2*ldb, row2);
_mm_storeu_ps(dst+3*ldb, row3);
}
#endif
#endif

View File

@ -1,23 +0,0 @@
set(TEST_PROXY ${CMAKE_CURRENT_BINARY_DIR}/test.proxy)
file(REMOVE ${TEST_PROXY})
# generate
# call the python executable to generate the Matlab gateways
add_custom_command(
OUTPUT ${TEST_PROXY}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/OpenCVTest.m ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/testsuite.m ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E touch ${TEST_PROXY}
COMMENT "Building Matlab tests"
)
# targets
# opencv_matlab_sources --> opencv_matlab
add_custom_target(opencv_test_matlab ALL DEPENDS ${TEST_PROXY})
add_dependencies(opencv_test_matlab ${the_module})
# run the matlab test suite
add_test(opencv_test_matlab
COMMAND ${MATLAB_BIN} "-nodisplay" "-r" "testsuite.m"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)

View File

@ -1,166 +0,0 @@
% Matlab binding test cases
% Uses Matlab's builtin testing framework
classdef OpenCVTest < matlab.unittest.TestCase
methods(Test)
% -------------------------------------------------------------------------
% EXCEPTIONS
% Check that errors and exceptions are thrown correctly
% -------------------------------------------------------------------------
% check that std exception is thrown
function stdException(testcase)
try
std_exception();
testcase.verifyFail();
catch
% TODO: Catch more specific exception
testcase.verifyTrue(true);
end
end
% check that OpenCV exceptions are correctly caught
function cvException(testcase)
try
cv_exception();
testcase.verifyFail();
catch
% TODO: Catch more specific exception
testcase.verifyTrue(true);
end
end
% check that all exceptions are caught
function allException(testcase)
try
exception();
testcase.verifyFail();
catch
% TODO: Catch more specific exception
testcase.verifyTrue(true);
end
end
% -------------------------------------------------------------------------
% SIZES AND FILLS
% Check that matrices are correctly filled and resized
% -------------------------------------------------------------------------
% check that a matrix is correctly filled with random numbers
function randomFill(testcase)
sz = [7 11];
mat = zeros(sz);
mat = cv.randn(mat, 0, 1);
testcase.verifyEqual(size(mat), sz, 'Matrix should not change size');
testcase.verifyNotEqual(mat, zeros(sz), 'Matrix should be nonzero');
end
function transpose(testcase)
m = randn(19, 81);
mt1 = transpose(m);
mt2 = cv.transpose(m);
testcase.verifyEqual(size(mt1), size(mt2), 'Matrix transposed to incorrect dimensionality');
testcase.verifyLessThan(norm(mt1 - mt2), 1e-8, 'Too much precision lost in tranposition');
end
% multiple return
function multipleReturn(testcase)
A = randn(10);
A = A'*A;
[V1, D1] = eig(A); D1 = diag(D1);
[~, D2, V2] = cv.eigen(A);
testcase.verifyLessThan(norm(V1 - V2), 1e-6, 'Too much precision lost in eigenvectors');
testcase.verifyLessThan(norm(D1 - D2), 1e-6, 'Too much precision lost in eigenvalues');
end
% complex output from SVD
function complexOutputSVD(testcase)
A = randn(10);
[V1, D1] = eig(A);
[~, D2, V2] = cv.eigen(A);
testcase.verifyTrue(~isreal(V2) && size(V2,3) == 1, 'Output should be complex');
testcase.verifyLessThan(norm(V1 - V2), 1e-6, 'Too much precision lost in eigenvectors');
end
% complex output from Fourier Transform
function complexOutputFFT(testcase)
A = randn(10);
F1 = fft2(A);
F2 = cv.dft(A, cv.DFT_COMPLEX_OUTPUT);
testcase.verifyTrue(~isreal(F2) && size(F2,3) == 1, 'Output should be complex');
testcase.verifyLessThan(norm(F1 - F2), 1e-6, 'Too much precision lost in eigenvectors');
end
% -------------------------------------------------------------------------
% TYPE CASTS
% Check that types are correctly cast
% -------------------------------------------------------------------------
% -------------------------------------------------------------------------
% PRECISION
% Check that basic operations are performed with sufficient precision
% -------------------------------------------------------------------------
% check that summing elements is within reasonable precision
function sumElements(testcase)
a = randn(5000);
b = sum(a(:));
c = cv.sum(a);
testcase.verifyLessThan(norm(b - c), 1e-8, 'Matrix reduction with insufficient precision');
end
% check that adding two matrices is within reasonable precision
function addPrecision(testcase)
a = randn(50);
b = randn(50);
c = a+b;
d = cv.add(a, b);
testcase.verifyLessThan(norm(c - d), 1e-8, 'Matrices are added with insufficient precision');
end
% check that performing gemm is within reasonable precision
function gemmPrecision(testcase)
a = randn(10, 50);
b = randn(50, 10);
c = randn(10, 10);
alpha = 2.71828;
gamma = 1.61803;
d = alpha*a*b + gamma*c;
e = cv.gemm(a, b, alpha, c, gamma);
testcase.verifyLessThan(norm(d - e), 1e-8, 'Matrices are multiplied with insufficient precision');
end
% -------------------------------------------------------------------------
% MISCELLANEOUS
% Miscellaneous tests
% -------------------------------------------------------------------------
% check that cv::waitKey waits for at least specified time
function waitKey(testcase)
tic();
cv.waitKey(500);
elapsed = toc();
testcase.verifyGreaterThan(elapsed, 0.5, 'Elapsed time should be at least 0.5 seconds');
end
% check that highgui window can be created and destroyed
function createAndDestroyWindow(testcase)
try
cv.namedWindow('test window');
catch
testcase.verifyFail('could not create window');
end
try
cv.destroyWindow('test window');
catch
testcase.verifyFail('could not destroy window');
end
testcase.verifyTrue(true);
end
end
end

View File

@ -1,33 +0,0 @@
/*
* file: exception.cpp
* author: Hilton Bristow
* date: Wed, 19 Jun 2013 11:15:15
*
* See LICENCE for full modification and redistribution details.
* Copyright 2013 The OpenCV Foundation
*/
#include <exception>
#include <opencv2/core.hpp>
#include "mex.h"
/*
* exception
* Gateway routine
* nlhs - number of return arguments
* plhs - pointers to return arguments
* nrhs - number of input arguments
* prhs - pointers to input arguments
*/
void mexFunction(int nlhs, mxArray* plhs[],
int nrhs, const mxArray* prhs[]) {
// call the opencv function
// [out =] namespace.fun(src1, ..., srcn, dst1, ..., dstn, opt1, ..., optn);
try {
throw cv::Exception(-1, "OpenCV exception thrown", __func__, __FILE__, __LINE__);
} catch(cv::Exception& e) {
mexErrMsgTxt(e.what());
} catch(...) {
mexErrMsgTxt("Incorrect exception caught!");
}
}

View File

@ -1,29 +0,0 @@
/*
* file: exception.cpp
* author: Hilton Bristow
* date: Wed, 19 Jun 2013 11:15:15
*
* See LICENCE for full modification and redistribution details.
* Copyright 2013 The OpenCV Foundation
*/
#include "mex.h"
/*
* exception
* Gateway routine
* nlhs - number of return arguments
* plhs - pointers to return arguments
* nrhs - number of input arguments
* prhs - pointers to input arguments
*/
void mexFunction(int nlhs, mxArray* plhs[],
int nrhs, const mxArray* prhs[]) {
// call the opencv function
// [out =] namespace.fun(src1, ..., srcn, dst1, ..., dstn, opt1, ..., optn);
try {
throw 1;
} catch(...) {
mexErrMsgTxt("Uncaught exception occurred!");
}
}

View File

@ -1,15 +0,0 @@
function help()
%CV.HELP display help information for the OpenCV Toolbox
%
% Calling:
% >> cv.help();
%
% is equivalent to calling:
% >> help cv;
%
% It displays high-level usage information about the OpenCV toolbox
% along with resources to find out more information.
%
% See also: cv.buildInformation
help('cv');
end

View File

@ -1,32 +0,0 @@
/*
* file: exception.cpp
* author: Hilton Bristow
* date: Wed, 19 Jun 2013 11:15:15
*
* See LICENCE for full modification and redistribution details.
* Copyright 2013 The OpenCV Foundation
*/
#include <exception>
#include "mex.h"
/*
* exception
* Gateway routine
* nlhs - number of return arguments
* plhs - pointers to return arguments
* nrhs - number of input arguments
* prhs - pointers to input arguments
*/
void mexFunction(int nlhs, mxArray* plhs[],
int nrhs, const mxArray* prhs[]) {
// call the opencv function
// [out =] namespace.fun(src1, ..., srcn, dst1, ..., dstn, opt1, ..., optn);
try {
throw std::exception();
} catch(std::exception& e) {
mexErrMsgTxt(e.what());
} catch(...) {
mexErrMsgTxt("Incorrect exception caught!");
}
}

View File

@ -1,31 +0,0 @@
/*
* file: rand.cpp
* author: A trusty code generator
* date: Wed, 19 Jun 2013 11:15:15
*
* This file was autogenerated, do not modify.
* See LICENCE for full modification and redistribution details.
* Copyright 2013 The OpenCV Foundation
*/
#include "mex.h"
#include <vector>
/*
* rand
* Gateway routine
* nlhs - number of return arguments
* plhs - pointers to return arguments
* nrhs - number of input arguments
* prhs - pointers to input arguments
*/
void mexFunction(int nlhs, mxArray* plhs[],
int nrhs, const mxArray* prhs[]) {
// call the opencv function
// [out =] namespace.fun(src1, ..., srcn, dst1, ..., dstn, opt1, ..., optn);
try {
rand();
} catch(...) {
mexErrMsgTxt("Uncaught exception occurred in rand");
}
}

View File

@ -1,15 +0,0 @@
/*
* a rather innocuous-looking function which is actually
* part of <cstdlib>, so we can be reasonably sure its
* definition will be found
*/
#ifndef __OPENCV_MATLAB_TEST_GENERATOR_HPP_
#define __OPENCV_MATLAB_TEST_GENERATOR_HPP_
namespace cv {
CV_EXPORTS_W int rand( );
};
#endif

View File

@ -1,11 +0,0 @@
% add the opencv bindings folder
addpath ..
%setup the tests
opencv_tests = OpenCVTest();
%run the tests
result = run(opencv_tests);
% shutdown
exit();

View File

@ -18,6 +18,8 @@ ocv_list_filterout(candidate_deps "^opencv_adas$")
ocv_list_filterout(candidate_deps "^opencv_face$")
ocv_list_filterout(candidate_deps "^opencv_matlab$")
ocv_list_filterout(candidate_deps "^opencv_tracking$")
ocv_list_filterout(candidate_deps "^opencv_optflow$")
ocv_list_filterout(candidate_deps "^opencv_bgsegm$")
ocv_add_module(${MODULE_NAME} BINDINGS OPTIONAL ${candidate_deps})

View File

@ -229,6 +229,7 @@ Ptr<DenseOpticalFlowExt> cv::superres::createOptFlow_Farneback()
///////////////////////////////////////////////////////////////////
// Simple
/*
namespace
{
class Simple : public CpuOpticalFlow
@ -311,7 +312,7 @@ namespace
Ptr<DenseOpticalFlowExt> cv::superres::createOptFlow_Simple()
{
return makePtr<Simple>();
}
}*/
///////////////////////////////////////////////////////////////////
// DualTVL1

View File

@ -214,135 +214,6 @@ Unlike :ocv:func:`findHomography` and :ocv:func:`estimateRigidTransform`, the fu
:ocv:func:`findHomography`
updateMotionHistory
-----------------------
Updates the motion history image by a moving silhouette.
.. ocv:function:: void updateMotionHistory( InputArray silhouette, InputOutputArray mhi, double timestamp, double duration )
.. ocv:pyfunction:: cv2.updateMotionHistory(silhouette, mhi, timestamp, duration) -> mhi
.. ocv:cfunction:: void cvUpdateMotionHistory( const CvArr* silhouette, CvArr* mhi, double timestamp, double duration )
:param silhouette: Silhouette mask that has non-zero pixels where the motion occurs.
:param mhi: Motion history image that is updated by the function (single-channel, 32-bit floating-point).
:param timestamp: Current time in milliseconds or other units.
:param duration: Maximal duration of the motion track in the same units as ``timestamp`` .
The function updates the motion history image as follows:
.. math::
\texttt{mhi} (x,y)= \forkthree{\texttt{timestamp}}{if $\texttt{silhouette}(x,y) \ne 0$}{0}{if $\texttt{silhouette}(x,y) = 0$ and $\texttt{mhi} < (\texttt{timestamp} - \texttt{duration})$}{\texttt{mhi}(x,y)}{otherwise}
That is, MHI pixels where the motion occurs are set to the current ``timestamp`` , while the pixels where the motion happened last time a long time ago are cleared.
The function, together with
:ocv:func:`calcMotionGradient` and
:ocv:func:`calcGlobalOrientation` , implements a motion templates technique described in
[Davis97]_ and [Bradski00]_.
See also the OpenCV sample ``motempl.c`` that demonstrates the use of all the motion template functions.
calcMotionGradient
----------------------
Calculates a gradient orientation of a motion history image.
.. ocv:function:: void calcMotionGradient( InputArray mhi, OutputArray mask, OutputArray orientation, double delta1, double delta2, int apertureSize=3 )
.. ocv:pyfunction:: cv2.calcMotionGradient(mhi, delta1, delta2[, mask[, orientation[, apertureSize]]]) -> mask, orientation
.. ocv:cfunction:: void cvCalcMotionGradient( const CvArr* mhi, CvArr* mask, CvArr* orientation, double delta1, double delta2, int aperture_size=3 )
:param mhi: Motion history single-channel floating-point image.
:param mask: Output mask image that has the type ``CV_8UC1`` and the same size as ``mhi`` . Its non-zero elements mark pixels where the motion gradient data is correct.
:param orientation: Output motion gradient orientation image that has the same type and the same size as ``mhi`` . Each pixel of the image is a motion orientation, from 0 to 360 degrees.
:param delta1: Minimal (or maximal) allowed difference between ``mhi`` values within a pixel neighborhood.
:param delta2: Maximal (or minimal) allowed difference between ``mhi`` values within a pixel neighborhood. That is, the function finds the minimum ( :math:`m(x,y)` ) and maximum ( :math:`M(x,y)` ) ``mhi`` values over :math:`3 \times 3` neighborhood of each pixel and marks the motion orientation at :math:`(x, y)` as valid only if
.. math::
\min ( \texttt{delta1} , \texttt{delta2} ) \le M(x,y)-m(x,y) \le \max ( \texttt{delta1} , \texttt{delta2} ).
:param apertureSize: Aperture size of the :ocv:func:`Sobel` operator.
The function calculates a gradient orientation at each pixel
:math:`(x, y)` as:
.. math::
\texttt{orientation} (x,y)= \arctan{\frac{d\texttt{mhi}/dy}{d\texttt{mhi}/dx}}
In fact,
:ocv:func:`fastAtan2` and
:ocv:func:`phase` are used so that the computed angle is measured in degrees and covers the full range 0..360. Also, the ``mask`` is filled to indicate pixels where the computed angle is valid.
.. note::
* (Python) An example on how to perform a motion template technique can be found at opencv_source_code/samples/python2/motempl.py
calcGlobalOrientation
-------------------------
Calculates a global motion orientation in a selected region.
.. ocv:function:: double calcGlobalOrientation( InputArray orientation, InputArray mask, InputArray mhi, double timestamp, double duration )
.. ocv:pyfunction:: cv2.calcGlobalOrientation(orientation, mask, mhi, timestamp, duration) -> retval
.. ocv:cfunction:: double cvCalcGlobalOrientation( const CvArr* orientation, const CvArr* mask, const CvArr* mhi, double timestamp, double duration )
:param orientation: Motion gradient orientation image calculated by the function :ocv:func:`calcMotionGradient` .
:param mask: Mask image. It may be a conjunction of a valid gradient mask, also calculated by :ocv:func:`calcMotionGradient` , and the mask of a region whose direction needs to be calculated.
:param mhi: Motion history image calculated by :ocv:func:`updateMotionHistory` .
:param timestamp: Timestamp passed to :ocv:func:`updateMotionHistory` .
:param duration: Maximum duration of a motion track in milliseconds, passed to :ocv:func:`updateMotionHistory` .
The function calculates an average
motion direction in the selected region and returns the angle between
0 degrees and 360 degrees. The average direction is computed from
the weighted orientation histogram, where a recent motion has a larger
weight and the motion occurred in the past has a smaller weight, as recorded in ``mhi`` .
segmentMotion
-------------
Splits a motion history image into a few parts corresponding to separate independent motions (for example, left hand, right hand).
.. ocv:function:: void segmentMotion(InputArray mhi, OutputArray segmask, vector<Rect>& boundingRects, double timestamp, double segThresh)
.. ocv:pyfunction:: cv2.segmentMotion(mhi, timestamp, segThresh[, segmask]) -> segmask, boundingRects
.. ocv:cfunction:: CvSeq* cvSegmentMotion( const CvArr* mhi, CvArr* seg_mask, CvMemStorage* storage, double timestamp, double seg_thresh )
:param mhi: Motion history image.
:param segmask: Image where the found mask should be stored, single-channel, 32-bit floating-point.
:param boundingRects: Vector containing ROIs of motion connected components.
:param timestamp: Current time in milliseconds or other units.
:param segThresh: Segmentation threshold that is recommended to be equal to the interval between motion history "steps" or greater.
The function finds all of the motion segments and marks them in ``segmask`` with individual values (1,2,...). It also computes a vector with ROIs of motion connected components. After that the motion direction for every component can be calculated with :ocv:func:`calcGlobalOrientation` using the extracted mask of the particular component.
CamShift
--------
Finds an object center, size, and orientation.
@ -994,52 +865,6 @@ Sets the prior probability that each individual pixel is a background pixel.
.. ocv:function:: void BackgroundSubtractorGMG::setBackgroundPrior(double bgprior)
calcOpticalFlowSF
-----------------
Calculate an optical flow using "SimpleFlow" algorithm.
.. ocv:function:: void calcOpticalFlowSF( InputArray from, InputArray to, OutputArray flow, int layers, int averaging_block_size, int max_flow )
.. ocv:function:: calcOpticalFlowSF( InputArray from, InputArray to, OutputArray flow, int layers, int averaging_block_size, int max_flow, double sigma_dist, double sigma_color, int postprocess_window, double sigma_dist_fix, double sigma_color_fix, double occ_thr, int upscale_averaging_radius, double upscale_sigma_dist, double upscale_sigma_color, double speed_up_thr )
:param prev: First 8-bit 3-channel image.
:param next: Second 8-bit 3-channel image of the same size as ``prev``
:param flow: computed flow image that has the same size as ``prev`` and type ``CV_32FC2``
:param layers: Number of layers
:param averaging_block_size: Size of block through which we sum up when calculate cost function for pixel
:param max_flow: maximal flow that we search at each level
:param sigma_dist: vector smooth spatial sigma parameter
:param sigma_color: vector smooth color sigma parameter
:param postprocess_window: window size for postprocess cross bilateral filter
:param sigma_dist_fix: spatial sigma for postprocess cross bilateralf filter
:param sigma_color_fix: color sigma for postprocess cross bilateral filter
:param occ_thr: threshold for detecting occlusions
:param upscale_averaging_radius: window size for bilateral upscale operation
:param upscale_sigma_dist: spatial sigma for bilateral upscale operation
:param upscale_sigma_color: color sigma for bilateral upscale operation
:param speed_up_thr: threshold to detect point with irregular flow - where flow should be recalculated after upscale
See [Tao2012]_. And site of project - http://graphics.berkeley.edu/papers/Tao-SAN-2012-05/.
.. note::
* An example using the simpleFlow algorithm can be found at opencv_source_code/samples/cpp/simpleflow_demo.cpp
createOptFlow_DualTVL1
----------------------
"Dual TV L1" Optical Flow Algorithm.
@ -1080,8 +905,6 @@ createOptFlow_DualTVL1
Stopping criterion iterations number used in the numerical scheme.
DenseOpticalFlow::calc
--------------------------
Calculates an optical flow.
@ -1108,10 +931,6 @@ Releases all inner buffers.
.. [Bradski98] Bradski, G.R. "Computer Vision Face Tracking for Use in a Perceptual User Interface", Intel, 1998
.. [Bradski00] Davis, J.W. and Bradski, G.R. "Motion Segmentation and Pose Recognition with Motion History Gradients", WACV00, 2000
.. [Davis97] Davis, J.W. and Bobick, A.F. "The Representation and Recognition of Action Using Temporal Templates", CVPR97, 1997
.. [EP08] Evangelidis, G.D. and Psarakis E.Z. "Parametric Image Alignment using Enhanced Correlation Coefficient Maximization", IEEE Transactions on PAMI, vol. 32, no. 10, 2008
.. [Farneback2003] Gunnar Farneback, Two-frame motion estimation based on polynomial expansion, Lecture Notes in Computer Science, 2003, (2749), , 363-370.
@ -1126,8 +945,6 @@ Releases all inner buffers.
.. [Welch95] Greg Welch and Gary Bishop "An Introduction to the Kalman Filter", 1995
.. [Tao2012] Michael Tao, Jiamin Bai, Pushmeet Kohli and Sylvain Paris. SimpleFlow: A Non-iterative, Sublinear Optical Flow Algorithm. Computer Graphics Forum (Eurographics 2012)
.. [Zach2007] C. Zach, T. Pock and H. Bischof. "A Duality Based Approach for Realtime TV-L1 Optical Flow", In Proceedings of Pattern Recognition (DAGM), Heidelberg, Germany, pp. 214-223, 2007
.. [Zivkovic2004] Z. Zivkovic. "Improved adaptive Gausian mixture model for background subtraction", International Conference Pattern Recognition, UK, August, 2004, http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf. The code is very fast and performs also shadow detection. Number of Gausssian components is adapted per pixel.

View File

@ -66,39 +66,6 @@ public:
};
/*!
Gaussian Mixture-based Backbround/Foreground Segmentation Algorithm
The class implements the following algorithm:
"An improved adaptive background mixture model for real-time tracking with shadow detection"
P. KadewTraKuPong and R. Bowden,
Proc. 2nd European Workshp on Advanced Video-Based Surveillance Systems, 2001."
http://personal.ee.surrey.ac.uk/Personal/R.Bowden/publications/avbs01/avbs01.pdf
*/
class CV_EXPORTS_W BackgroundSubtractorMOG : public BackgroundSubtractor
{
public:
CV_WRAP virtual int getHistory() const = 0;
CV_WRAP virtual void setHistory(int nframes) = 0;
CV_WRAP virtual int getNMixtures() const = 0;
CV_WRAP virtual void setNMixtures(int nmix) = 0;
CV_WRAP virtual double getBackgroundRatio() const = 0;
CV_WRAP virtual void setBackgroundRatio(double backgroundRatio) = 0;
CV_WRAP virtual double getNoiseSigma() const = 0;
CV_WRAP virtual void setNoiseSigma(double noiseSigma) = 0;
};
CV_EXPORTS_W Ptr<BackgroundSubtractorMOG>
createBackgroundSubtractorMOG(int history=200, int nmixtures=5,
double backgroundRatio=0.7, double noiseSigma=0);
/*!
The class implements the following algorithm:
"Improved adaptive Gausian mixture model for background subtraction"
@ -189,51 +156,6 @@ CV_EXPORTS_W Ptr<BackgroundSubtractorKNN>
createBackgroundSubtractorKNN(int history=500, double dist2Threshold=400.0,
bool detectShadows=true);
/**
* Background Subtractor module. Takes a series of images and returns a sequence of mask (8UC1)
* images of the same size, where 255 indicates Foreground and 0 represents Background.
* This class implements an algorithm described in "Visual Tracking of Human Visitors under
* Variable-Lighting Conditions for a Responsive Audio Art Installation," A. Godbehere,
* A. Matsukawa, K. Goldberg, American Control Conference, Montreal, June 2012.
*/
class CV_EXPORTS_W BackgroundSubtractorGMG : public BackgroundSubtractor
{
public:
CV_WRAP virtual int getMaxFeatures() const = 0;
CV_WRAP virtual void setMaxFeatures(int maxFeatures) = 0;
CV_WRAP virtual double getDefaultLearningRate() const = 0;
CV_WRAP virtual void setDefaultLearningRate(double lr) = 0;
CV_WRAP virtual int getNumFrames() const = 0;
CV_WRAP virtual void setNumFrames(int nframes) = 0;
CV_WRAP virtual int getQuantizationLevels() const = 0;
CV_WRAP virtual void setQuantizationLevels(int nlevels) = 0;
CV_WRAP virtual double getBackgroundPrior() const = 0;
CV_WRAP virtual void setBackgroundPrior(double bgprior) = 0;
CV_WRAP virtual int getSmoothingRadius() const = 0;
CV_WRAP virtual void setSmoothingRadius(int radius) = 0;
CV_WRAP virtual double getDecisionThreshold() const = 0;
CV_WRAP virtual void setDecisionThreshold(double thresh) = 0;
CV_WRAP virtual bool getUpdateBackgroundModel() const = 0;
CV_WRAP virtual void setUpdateBackgroundModel(bool update) = 0;
CV_WRAP virtual double getMinVal() const = 0;
CV_WRAP virtual void setMinVal(double val) = 0;
CV_WRAP virtual double getMaxVal() const = 0;
CV_WRAP virtual void setMaxVal(double val) = 0;
};
CV_EXPORTS_W Ptr<BackgroundSubtractorGMG> createBackgroundSubtractorGMG(int initializationFrames=120,
double decisionThreshold=0.8);
} // cv
#endif

View File

@ -55,28 +55,6 @@ enum { OPTFLOW_USE_INITIAL_FLOW = 4,
OPTFLOW_FARNEBACK_GAUSSIAN = 256
};
enum { MOTION_TRANSLATION = 0,
MOTION_EUCLIDEAN = 1,
MOTION_AFFINE = 2,
MOTION_HOMOGRAPHY = 3
};
//! updates motion history image using the current silhouette
CV_EXPORTS_W void updateMotionHistory( InputArray silhouette, InputOutputArray mhi,
double timestamp, double duration );
//! computes the motion gradient orientation image from the motion history image
CV_EXPORTS_W void calcMotionGradient( InputArray mhi, OutputArray mask, OutputArray orientation,
double delta1, double delta2, int apertureSize = 3 );
//! computes the global orientation of the selected motion history image part
CV_EXPORTS_W double calcGlobalOrientation( InputArray orientation, InputArray mask, InputArray mhi,
double timestamp, double duration );
CV_EXPORTS_W void segmentMotion( InputArray mhi, OutputArray segmask,
CV_OUT std::vector<Rect>& boundingRects,
double timestamp, double segThresh );
//! updates the object tracking window using CAMSHIFT algorithm
CV_EXPORTS_W RotatedRect CamShift( InputArray probImage, CV_IN_OUT Rect& window,
TermCriteria criteria );
@ -109,6 +87,15 @@ CV_EXPORTS_W void calcOpticalFlowFarneback( InputArray prev, InputArray next, In
// that maps one 2D point set to another or one image to another.
CV_EXPORTS_W Mat estimateRigidTransform( InputArray src, InputArray dst, bool fullAffine );
enum
{
MOTION_TRANSLATION = 0,
MOTION_EUCLIDEAN = 1,
MOTION_AFFINE = 2,
MOTION_HOMOGRAPHY = 3
};
//! estimates the best-fit Translation, Euclidean, Affine or Perspective Transformation
// with respect to Enhanced Correlation Coefficient criterion that maps one image to
// another (area-based alignment)
@ -120,20 +107,6 @@ CV_EXPORTS_W double findTransformECC( InputArray templateImage, InputArray input
InputOutputArray warpMatrix, int motionType = MOTION_AFFINE,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 50, 0.001));
//! computes dense optical flow using Simple Flow algorithm
CV_EXPORTS_W void calcOpticalFlowSF( InputArray from, InputArray to, OutputArray flow,
int layers, int averaging_block_size, int max_flow);
CV_EXPORTS_W void calcOpticalFlowSF( InputArray from, InputArray to, OutputArray flow, int layers,
int averaging_block_size, int max_flow,
double sigma_dist, double sigma_color, int postprocess_window,
double sigma_dist_fix, double sigma_color_fix, double occ_thr,
int upscale_averaging_radius, double upscale_sigma_dist,
double upscale_sigma_color, double speed_up_thr );
/*!
Kalman filter.

View File

@ -8,7 +8,7 @@
#include "../perf_precomp.hpp"
#include "opencv2/ts/ocl_perf.hpp"
#ifdef HAVE_OPENCL
#if 0 //def HAVE_OPENCL
namespace cvtest {
namespace ocl {

View File

@ -1,850 +0,0 @@
/*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, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, 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/imgproc/imgproc_c.h"
#include "opencv2/video/tracking_c.h"
// to be moved to legacy
static int icvMinimalPyramidSize( CvSize imgSize )
{
return cvAlign(imgSize.width,8) * imgSize.height / 3;
}
static void
icvInitPyramidalAlgorithm( const CvMat* imgA, const CvMat* imgB,
CvMat* pyrA, CvMat* pyrB,
int level, CvTermCriteria * criteria,
int max_iters, int flags,
uchar *** imgI, uchar *** imgJ,
int **step, CvSize** size,
double **scale, cv::AutoBuffer<uchar>* buffer )
{
const int ALIGN = 8;
int pyrBytes, bufferBytes = 0, elem_size;
int level1 = level + 1;
int i;
CvSize imgSize, levelSize;
*imgI = *imgJ = 0;
*step = 0;
*scale = 0;
*size = 0;
/* check input arguments */
if( ((flags & CV_LKFLOW_PYR_A_READY) != 0 && !pyrA) ||
((flags & CV_LKFLOW_PYR_B_READY) != 0 && !pyrB) )
CV_Error( CV_StsNullPtr, "Some of the precomputed pyramids are missing" );
if( level < 0 )
CV_Error( CV_StsOutOfRange, "The number of pyramid levels is negative" );
switch( criteria->type )
{
case CV_TERMCRIT_ITER:
criteria->epsilon = 0.f;
break;
case CV_TERMCRIT_EPS:
criteria->max_iter = max_iters;
break;
case CV_TERMCRIT_ITER | CV_TERMCRIT_EPS:
break;
default:
assert( 0 );
CV_Error( CV_StsBadArg, "Invalid termination criteria" );
}
/* compare squared values */
criteria->epsilon *= criteria->epsilon;
/* set pointers and step for every level */
pyrBytes = 0;
imgSize = cvGetSize(imgA);
elem_size = CV_ELEM_SIZE(imgA->type);
levelSize = imgSize;
for( i = 1; i < level1; i++ )
{
levelSize.width = (levelSize.width + 1) >> 1;
levelSize.height = (levelSize.height + 1) >> 1;
int tstep = cvAlign(levelSize.width,ALIGN) * elem_size;
pyrBytes += tstep * levelSize.height;
}
assert( pyrBytes <= imgSize.width * imgSize.height * elem_size * 4 / 3 );
/* buffer_size = <size for patches> + <size for pyramids> */
bufferBytes = (int)((level1 >= 0) * ((pyrA->data.ptr == 0) +
(pyrB->data.ptr == 0)) * pyrBytes +
(sizeof(imgI[0][0]) * 2 + sizeof(step[0][0]) +
sizeof(size[0][0]) + sizeof(scale[0][0])) * level1);
buffer->allocate( bufferBytes );
*imgI = (uchar **) (uchar*)(*buffer);
*imgJ = *imgI + level1;
*step = (int *) (*imgJ + level1);
*scale = (double *) (*step + level1);
*size = (CvSize *)(*scale + level1);
imgI[0][0] = imgA->data.ptr;
imgJ[0][0] = imgB->data.ptr;
step[0][0] = imgA->step;
scale[0][0] = 1;
size[0][0] = imgSize;
if( level > 0 )
{
uchar *bufPtr = (uchar *) (*size + level1);
uchar *ptrA = pyrA->data.ptr;
uchar *ptrB = pyrB->data.ptr;
if( !ptrA )
{
ptrA = bufPtr;
bufPtr += pyrBytes;
}
if( !ptrB )
ptrB = bufPtr;
levelSize = imgSize;
/* build pyramids for both frames */
for( i = 1; i <= level; i++ )
{
int levelBytes;
CvMat prev_level, next_level;
levelSize.width = (levelSize.width + 1) >> 1;
levelSize.height = (levelSize.height + 1) >> 1;
size[0][i] = levelSize;
step[0][i] = cvAlign( levelSize.width, ALIGN ) * elem_size;
scale[0][i] = scale[0][i - 1] * 0.5;
levelBytes = step[0][i] * levelSize.height;
imgI[0][i] = (uchar *) ptrA;
ptrA += levelBytes;
if( !(flags & CV_LKFLOW_PYR_A_READY) )
{
prev_level = cvMat( size[0][i-1].height, size[0][i-1].width, CV_8UC1 );
next_level = cvMat( size[0][i].height, size[0][i].width, CV_8UC1 );
cvSetData( &prev_level, imgI[0][i-1], step[0][i-1] );
cvSetData( &next_level, imgI[0][i], step[0][i] );
cvPyrDown( &prev_level, &next_level );
}
imgJ[0][i] = (uchar *) ptrB;
ptrB += levelBytes;
if( !(flags & CV_LKFLOW_PYR_B_READY) )
{
prev_level = cvMat( size[0][i-1].height, size[0][i-1].width, CV_8UC1 );
next_level = cvMat( size[0][i].height, size[0][i].width, CV_8UC1 );
cvSetData( &prev_level, imgJ[0][i-1], step[0][i-1] );
cvSetData( &next_level, imgJ[0][i], step[0][i] );
cvPyrDown( &prev_level, &next_level );
}
}
}
}
/* compute dI/dx and dI/dy */
static void
icvCalcIxIy_32f( const float* src, int src_step, float* dstX, float* dstY, int dst_step,
CvSize src_size, const float* smooth_k, float* buffer0 )
{
int src_width = src_size.width, dst_width = src_size.width-2;
int x, height = src_size.height - 2;
float* buffer1 = buffer0 + src_width;
src_step /= sizeof(src[0]);
dst_step /= sizeof(dstX[0]);
for( ; height--; src += src_step, dstX += dst_step, dstY += dst_step )
{
const float* src2 = src + src_step;
const float* src3 = src + src_step*2;
for( x = 0; x < src_width; x++ )
{
float t0 = (src3[x] + src[x])*smooth_k[0] + src2[x]*smooth_k[1];
float t1 = src3[x] - src[x];
buffer0[x] = t0; buffer1[x] = t1;
}
for( x = 0; x < dst_width; x++ )
{
float t0 = buffer0[x+2] - buffer0[x];
float t1 = (buffer1[x] + buffer1[x+2])*smooth_k[0] + buffer1[x+1]*smooth_k[1];
dstX[x] = t0; dstY[x] = t1;
}
}
}
#undef CV_8TO32F
#define CV_8TO32F(a) (a)
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;
}
static 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_32F8U(x) ((uchar)cvRound(x))
#define ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( flavor, srctype, dsttype, worktype, cast_macro, cvt ) \
static 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; \
}
ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( 8u32f, uchar, float, double, cv::saturate_cast<float>, CV_8TO32F )
/* Affine tracking algorithm */
CV_IMPL void
cvCalcAffineFlowPyrLK( const void* arrA, const void* arrB,
void* pyrarrA, void* pyrarrB,
const CvPoint2D32f * featuresA,
CvPoint2D32f * featuresB,
float *matrices, int count,
CvSize winSize, int level,
char *status, float *error,
CvTermCriteria criteria, int flags )
{
const int MAX_ITERS = 100;
cv::AutoBuffer<char> _status;
cv::AutoBuffer<uchar> buffer;
cv::AutoBuffer<uchar> pyr_buffer;
CvMat stubA, *imgA = (CvMat*)arrA;
CvMat stubB, *imgB = (CvMat*)arrB;
CvMat pstubA, *pyrA = (CvMat*)pyrarrA;
CvMat pstubB, *pyrB = (CvMat*)pyrarrB;
static const float smoothKernel[] = { 0.09375, 0.3125, 0.09375 }; /* 3/32, 10/32, 3/32 */
int bufferBytes = 0;
uchar **imgI = 0;
uchar **imgJ = 0;
int *step = 0;
double *scale = 0;
CvSize* size = 0;
float *patchI;
float *patchJ;
float *Ix;
float *Iy;
int i, j, k, l;
CvSize patchSize = cvSize( winSize.width * 2 + 1, winSize.height * 2 + 1 );
int patchLen = patchSize.width * patchSize.height;
int patchStep = patchSize.width * sizeof( patchI[0] );
CvSize srcPatchSize = cvSize( patchSize.width + 2, patchSize.height + 2 );
int srcPatchLen = srcPatchSize.width * srcPatchSize.height;
int srcPatchStep = srcPatchSize.width * sizeof( patchI[0] );
CvSize imgSize;
float eps = (float)MIN(winSize.width, winSize.height);
imgA = cvGetMat( imgA, &stubA );
imgB = cvGetMat( imgB, &stubB );
if( CV_MAT_TYPE( imgA->type ) != CV_8UC1 )
CV_Error( CV_StsUnsupportedFormat, "" );
if( !CV_ARE_TYPES_EQ( imgA, imgB ))
CV_Error( CV_StsUnmatchedFormats, "" );
if( !CV_ARE_SIZES_EQ( imgA, imgB ))
CV_Error( CV_StsUnmatchedSizes, "" );
if( imgA->step != imgB->step )
CV_Error( CV_StsUnmatchedSizes, "imgA and imgB must have equal steps" );
if( !matrices )
CV_Error( CV_StsNullPtr, "" );
imgSize = cv::Size(imgA->cols, imgA->rows);
if( pyrA )
{
pyrA = cvGetMat( pyrA, &pstubA );
if( pyrA->step*pyrA->height < icvMinimalPyramidSize( imgSize ) )
CV_Error( CV_StsBadArg, "pyramid A has insufficient size" );
}
else
{
pyrA = &pstubA;
pyrA->data.ptr = 0;
}
if( pyrB )
{
pyrB = cvGetMat( pyrB, &pstubB );
if( pyrB->step*pyrB->height < icvMinimalPyramidSize( imgSize ) )
CV_Error( CV_StsBadArg, "pyramid B has insufficient size" );
}
else
{
pyrB = &pstubB;
pyrB->data.ptr = 0;
}
if( count == 0 )
return;
/* check input arguments */
if( !featuresA || !featuresB || !matrices )
CV_Error( CV_StsNullPtr, "" );
if( winSize.width <= 1 || winSize.height <= 1 )
CV_Error( CV_StsOutOfRange, "the search window is too small" );
if( count < 0 )
CV_Error( CV_StsOutOfRange, "" );
icvInitPyramidalAlgorithm( imgA, imgB,
pyrA, pyrB, level, &criteria, MAX_ITERS, flags,
&imgI, &imgJ, &step, &size, &scale, &pyr_buffer );
/* buffer_size = <size for patches> + <size for pyramids> */
bufferBytes = (srcPatchLen + patchLen*3)*sizeof(patchI[0]) + (36*2 + 6)*sizeof(double);
buffer.allocate(bufferBytes);
if( !status )
{
_status.allocate(count);
status = _status;
}
patchI = (float *)(uchar*)buffer;
patchJ = patchI + srcPatchLen;
Ix = patchJ + patchLen;
Iy = Ix + patchLen;
if( status )
memset( status, 1, count );
if( !(flags & CV_LKFLOW_INITIAL_GUESSES) )
{
memcpy( featuresB, featuresA, count * sizeof( featuresA[0] ));
for( i = 0; i < count * 4; i += 4 )
{
matrices[i] = matrices[i + 3] = 1.f;
matrices[i + 1] = matrices[i + 2] = 0.f;
}
}
for( i = 0; i < count; i++ )
{
featuresB[i].x = (float)(featuresB[i].x * scale[level] * 0.5);
featuresB[i].y = (float)(featuresB[i].y * scale[level] * 0.5);
}
/* do processing from top pyramid level (smallest image)
to the bottom (original image) */
for( l = level; l >= 0; l-- )
{
CvSize levelSize = size[l];
int levelStep = step[l];
/* find flow for each given point at the particular level */
for( i = 0; i < count; i++ )
{
CvPoint2D32f u;
float Av[6];
double G[36];
double meanI = 0, meanJ = 0;
int x, y;
int pt_status = status[i];
CvMat mat;
if( !pt_status )
continue;
Av[0] = matrices[i*4];
Av[1] = matrices[i*4+1];
Av[3] = matrices[i*4+2];
Av[4] = matrices[i*4+3];
Av[2] = featuresB[i].x += featuresB[i].x;
Av[5] = featuresB[i].y += featuresB[i].y;
u.x = (float) (featuresA[i].x * scale[l]);
u.y = (float) (featuresA[i].y * scale[l]);
if( u.x < -eps || u.x >= levelSize.width+eps ||
u.y < -eps || u.y >= levelSize.height+eps ||
icvGetRectSubPix_8u32f_C1R( imgI[l], levelStep,
levelSize, patchI, srcPatchStep, srcPatchSize, u ) < 0 )
{
/* point is outside the image. take the next */
if( l == 0 )
status[i] = 0;
continue;
}
icvCalcIxIy_32f( patchI, srcPatchStep, Ix, Iy,
(srcPatchSize.width-2)*sizeof(patchI[0]), srcPatchSize,
smoothKernel, patchJ );
/* repack patchI (remove borders) */
for( k = 0; k < patchSize.height; k++ )
memcpy( patchI + k * patchSize.width,
patchI + (k + 1) * srcPatchSize.width + 1, patchStep );
memset( G, 0, sizeof( G ));
/* calculate G matrix */
for( y = -winSize.height, k = 0; y <= winSize.height; y++ )
{
for( x = -winSize.width; x <= winSize.width; x++, k++ )
{
double ixix = ((double) Ix[k]) * Ix[k];
double ixiy = ((double) Ix[k]) * Iy[k];
double iyiy = ((double) Iy[k]) * Iy[k];
double xx, xy, yy;
G[0] += ixix;
G[1] += ixiy;
G[2] += x * ixix;
G[3] += y * ixix;
G[4] += x * ixiy;
G[5] += y * ixiy;
// G[6] == G[1]
G[7] += iyiy;
// G[8] == G[4]
// G[9] == G[5]
G[10] += x * iyiy;
G[11] += y * iyiy;
xx = x * x;
xy = x * y;
yy = y * y;
// G[12] == G[2]
// G[13] == G[8] == G[4]
G[14] += xx * ixix;
G[15] += xy * ixix;
G[16] += xx * ixiy;
G[17] += xy * ixiy;
// G[18] == G[3]
// G[19] == G[9]
// G[20] == G[15]
G[21] += yy * ixix;
// G[22] == G[17]
G[23] += yy * ixiy;
// G[24] == G[4]
// G[25] == G[10]
// G[26] == G[16]
// G[27] == G[22]
G[28] += xx * iyiy;
G[29] += xy * iyiy;
// G[30] == G[5]
// G[31] == G[11]
// G[32] == G[17]
// G[33] == G[23]
// G[34] == G[29]
G[35] += yy * iyiy;
meanI += patchI[k];
}
}
meanI /= patchSize.width*patchSize.height;
G[8] = G[4];
G[9] = G[5];
G[22] = G[17];
// fill part of G below its diagonal
for( y = 1; y < 6; y++ )
for( x = 0; x < y; x++ )
G[y * 6 + x] = G[x * 6 + y];
cvInitMatHeader( &mat, 6, 6, CV_64FC1, G );
if( cvInvert( &mat, &mat, CV_SVD ) < 1e-4 )
{
/* bad matrix. take the next point */
if( l == 0 )
status[i] = 0;
continue;
}
for( j = 0; j < criteria.max_iter; j++ )
{
double b[6] = {0,0,0,0,0,0}, eta[6];
double t0, t1, s = 0;
if( Av[2] < -eps || Av[2] >= levelSize.width+eps ||
Av[5] < -eps || Av[5] >= levelSize.height+eps ||
icvGetQuadrangleSubPix_8u32f_C1R( imgJ[l], levelStep,
levelSize, patchJ, patchStep, patchSize, Av ) < 0 )
{
pt_status = 0;
break;
}
for( y = -winSize.height, k = 0, meanJ = 0; y <= winSize.height; y++ )
for( x = -winSize.width; x <= winSize.width; x++, k++ )
meanJ += patchJ[k];
meanJ = meanJ / (patchSize.width * patchSize.height) - meanI;
for( y = -winSize.height, k = 0; y <= winSize.height; y++ )
{
for( x = -winSize.width; x <= winSize.width; x++, k++ )
{
double t = patchI[k] - patchJ[k] + meanJ;
double ixt = Ix[k] * t;
double iyt = Iy[k] * t;
s += t;
b[0] += ixt;
b[1] += iyt;
b[2] += x * ixt;
b[3] += y * ixt;
b[4] += x * iyt;
b[5] += y * iyt;
}
}
for( k = 0; k < 6; k++ )
eta[k] = G[k*6]*b[0] + G[k*6+1]*b[1] + G[k*6+2]*b[2] +
G[k*6+3]*b[3] + G[k*6+4]*b[4] + G[k*6+5]*b[5];
Av[2] = (float)(Av[2] + Av[0] * eta[0] + Av[1] * eta[1]);
Av[5] = (float)(Av[5] + Av[3] * eta[0] + Av[4] * eta[1]);
t0 = Av[0] * (1 + eta[2]) + Av[1] * eta[4];
t1 = Av[0] * eta[3] + Av[1] * (1 + eta[5]);
Av[0] = (float)t0;
Av[1] = (float)t1;
t0 = Av[3] * (1 + eta[2]) + Av[4] * eta[4];
t1 = Av[3] * eta[3] + Av[4] * (1 + eta[5]);
Av[3] = (float)t0;
Av[4] = (float)t1;
if( eta[0] * eta[0] + eta[1] * eta[1] < criteria.epsilon )
break;
}
if( pt_status != 0 || l == 0 )
{
status[i] = (char)pt_status;
featuresB[i].x = Av[2];
featuresB[i].y = Av[5];
matrices[i*4] = Av[0];
matrices[i*4+1] = Av[1];
matrices[i*4+2] = Av[3];
matrices[i*4+3] = Av[4];
}
if( pt_status && l == 0 && error )
{
/* calc error */
double err = 0;
for( y = 0, k = 0; y < patchSize.height; y++ )
{
for( x = 0; x < patchSize.width; x++, k++ )
{
double t = patchI[k] - patchJ[k] + meanJ;
err += t * t;
}
}
error[i] = (float)std::sqrt(err);
}
}
}
}

View File

@ -1,472 +0,0 @@
/*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, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, 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 <float.h>
// to make sure we can use these short names
#undef K
#undef L
#undef T
// This is based on the "An Improved Adaptive Background Mixture Model for
// Real-time Tracking with Shadow Detection" by P. KaewTraKulPong and R. Bowden
// http://personal.ee.surrey.ac.uk/Personal/R.Bowden/publications/avbs01/avbs01.pdf
//
// The windowing method is used, but not the shadow detection. I make some of my
// own modifications which make more sense. There are some errors in some of their
// equations.
//
namespace cv
{
static const int defaultNMixtures = 5;
static const int defaultHistory = 200;
static const double defaultBackgroundRatio = 0.7;
static const double defaultVarThreshold = 2.5*2.5;
static const double defaultNoiseSigma = 30*0.5;
static const double defaultInitialWeight = 0.05;
class BackgroundSubtractorMOGImpl : public BackgroundSubtractorMOG
{
public:
//! the default constructor
BackgroundSubtractorMOGImpl()
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
nmixtures = defaultNMixtures;
history = defaultHistory;
varThreshold = defaultVarThreshold;
backgroundRatio = defaultBackgroundRatio;
noiseSigma = defaultNoiseSigma;
name_ = "BackgroundSubtractor.MOG";
}
// the full constructor that takes the length of the history,
// the number of gaussian mixtures, the background ratio parameter and the noise strength
BackgroundSubtractorMOGImpl(int _history, int _nmixtures, double _backgroundRatio, double _noiseSigma=0)
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
nmixtures = std::min(_nmixtures > 0 ? _nmixtures : defaultNMixtures, 8);
history = _history > 0 ? _history : defaultHistory;
varThreshold = defaultVarThreshold;
backgroundRatio = std::min(_backgroundRatio > 0 ? _backgroundRatio : 0.95, 1.);
noiseSigma = _noiseSigma <= 0 ? defaultNoiseSigma : _noiseSigma;
}
//! the update operator
virtual void apply(InputArray image, OutputArray fgmask, double learningRate=0);
//! re-initiaization method
virtual void initialize(Size _frameSize, int _frameType)
{
frameSize = _frameSize;
frameType = _frameType;
nframes = 0;
int nchannels = CV_MAT_CN(frameType);
CV_Assert( CV_MAT_DEPTH(frameType) == CV_8U );
// for each gaussian mixture of each pixel bg model we store ...
// the mixture sort key (w/sum_of_variances), the mixture weight (w),
// the mean (nchannels values) and
// the diagonal covariance matrix (another nchannels values)
bgmodel.create( 1, frameSize.height*frameSize.width*nmixtures*(2 + 2*nchannels), CV_32F );
bgmodel = Scalar::all(0);
}
virtual AlgorithmInfo* info() const { return 0; }
virtual void getBackgroundImage(OutputArray) const
{
CV_Error( Error::StsNotImplemented, "" );
}
virtual int getHistory() const { return history; }
virtual void setHistory(int _nframes) { history = _nframes; }
virtual int getNMixtures() const { return nmixtures; }
virtual void setNMixtures(int nmix) { nmixtures = nmix; }
virtual double getBackgroundRatio() const { return backgroundRatio; }
virtual void setBackgroundRatio(double _backgroundRatio) { backgroundRatio = _backgroundRatio; }
virtual double getNoiseSigma() const { return noiseSigma; }
virtual void setNoiseSigma(double _noiseSigma) { noiseSigma = _noiseSigma; }
virtual void write(FileStorage& fs) const
{
fs << "name" << name_
<< "history" << history
<< "nmixtures" << nmixtures
<< "backgroundRatio" << backgroundRatio
<< "noiseSigma" << noiseSigma;
}
virtual void read(const FileNode& fn)
{
CV_Assert( (String)fn["name"] == name_ );
history = (int)fn["history"];
nmixtures = (int)fn["nmixtures"];
backgroundRatio = (double)fn["backgroundRatio"];
noiseSigma = (double)fn["noiseSigma"];
}
protected:
Size frameSize;
int frameType;
Mat bgmodel;
int nframes;
int history;
int nmixtures;
double varThreshold;
double backgroundRatio;
double noiseSigma;
String name_;
};
template<typename VT> struct MixData
{
float sortKey;
float weight;
VT mean;
VT var;
};
static void process8uC1( const Mat& image, Mat& fgmask, double learningRate,
Mat& bgmodel, int nmixtures, double backgroundRatio,
double varThreshold, double noiseSigma )
{
int x, y, k, k1, rows = image.rows, cols = image.cols;
float alpha = (float)learningRate, T = (float)backgroundRatio, vT = (float)varThreshold;
int K = nmixtures;
MixData<float>* mptr = (MixData<float>*)bgmodel.data;
const float w0 = (float)defaultInitialWeight;
const float sk0 = (float)(w0/(defaultNoiseSigma*2));
const float var0 = (float)(defaultNoiseSigma*defaultNoiseSigma*4);
const float minVar = (float)(noiseSigma*noiseSigma);
for( y = 0; y < rows; y++ )
{
const uchar* src = image.ptr<uchar>(y);
uchar* dst = fgmask.ptr<uchar>(y);
if( alpha > 0 )
{
for( x = 0; x < cols; x++, mptr += K )
{
float wsum = 0;
float pix = src[x];
int kHit = -1, kForeground = -1;
for( k = 0; k < K; k++ )
{
float w = mptr[k].weight;
wsum += w;
if( w < FLT_EPSILON )
break;
float mu = mptr[k].mean;
float var = mptr[k].var;
float diff = pix - mu;
float d2 = diff*diff;
if( d2 < vT*var )
{
wsum -= w;
float dw = alpha*(1.f - w);
mptr[k].weight = w + dw;
mptr[k].mean = mu + alpha*diff;
var = std::max(var + alpha*(d2 - var), minVar);
mptr[k].var = var;
mptr[k].sortKey = w/std::sqrt(var);
for( k1 = k-1; k1 >= 0; k1-- )
{
if( mptr[k1].sortKey >= mptr[k1+1].sortKey )
break;
std::swap( mptr[k1], mptr[k1+1] );
}
kHit = k1+1;
break;
}
}
if( kHit < 0 ) // no appropriate gaussian mixture found at all, remove the weakest mixture and create a new one
{
kHit = k = std::min(k, K-1);
wsum += w0 - mptr[k].weight;
mptr[k].weight = w0;
mptr[k].mean = pix;
mptr[k].var = var0;
mptr[k].sortKey = sk0;
}
else
for( ; k < K; k++ )
wsum += mptr[k].weight;
float wscale = 1.f/wsum;
wsum = 0;
for( k = 0; k < K; k++ )
{
wsum += mptr[k].weight *= wscale;
mptr[k].sortKey *= wscale;
if( wsum > T && kForeground < 0 )
kForeground = k+1;
}
dst[x] = (uchar)(-(kHit >= kForeground));
}
}
else
{
for( x = 0; x < cols; x++, mptr += K )
{
float pix = src[x];
int kHit = -1, kForeground = -1;
for( k = 0; k < K; k++ )
{
if( mptr[k].weight < FLT_EPSILON )
break;
float mu = mptr[k].mean;
float var = mptr[k].var;
float diff = pix - mu;
float d2 = diff*diff;
if( d2 < vT*var )
{
kHit = k;
break;
}
}
if( kHit >= 0 )
{
float wsum = 0;
for( k = 0; k < K; k++ )
{
wsum += mptr[k].weight;
if( wsum > T )
{
kForeground = k+1;
break;
}
}
}
dst[x] = (uchar)(kHit < 0 || kHit >= kForeground ? 255 : 0);
}
}
}
}
static void process8uC3( const Mat& image, Mat& fgmask, double learningRate,
Mat& bgmodel, int nmixtures, double backgroundRatio,
double varThreshold, double noiseSigma )
{
int x, y, k, k1, rows = image.rows, cols = image.cols;
float alpha = (float)learningRate, T = (float)backgroundRatio, vT = (float)varThreshold;
int K = nmixtures;
const float w0 = (float)defaultInitialWeight;
const float sk0 = (float)(w0/(defaultNoiseSigma*2*std::sqrt(3.)));
const float var0 = (float)(defaultNoiseSigma*defaultNoiseSigma*4);
const float minVar = (float)(noiseSigma*noiseSigma);
MixData<Vec3f>* mptr = (MixData<Vec3f>*)bgmodel.data;
for( y = 0; y < rows; y++ )
{
const uchar* src = image.ptr<uchar>(y);
uchar* dst = fgmask.ptr<uchar>(y);
if( alpha > 0 )
{
for( x = 0; x < cols; x++, mptr += K )
{
float wsum = 0;
Vec3f pix(src[x*3], src[x*3+1], src[x*3+2]);
int kHit = -1, kForeground = -1;
for( k = 0; k < K; k++ )
{
float w = mptr[k].weight;
wsum += w;
if( w < FLT_EPSILON )
break;
Vec3f mu = mptr[k].mean;
Vec3f var = mptr[k].var;
Vec3f diff = pix - mu;
float d2 = diff.dot(diff);
if( d2 < vT*(var[0] + var[1] + var[2]) )
{
wsum -= w;
float dw = alpha*(1.f - w);
mptr[k].weight = w + dw;
mptr[k].mean = mu + alpha*diff;
var = Vec3f(std::max(var[0] + alpha*(diff[0]*diff[0] - var[0]), minVar),
std::max(var[1] + alpha*(diff[1]*diff[1] - var[1]), minVar),
std::max(var[2] + alpha*(diff[2]*diff[2] - var[2]), minVar));
mptr[k].var = var;
mptr[k].sortKey = w/std::sqrt(var[0] + var[1] + var[2]);
for( k1 = k-1; k1 >= 0; k1-- )
{
if( mptr[k1].sortKey >= mptr[k1+1].sortKey )
break;
std::swap( mptr[k1], mptr[k1+1] );
}
kHit = k1+1;
break;
}
}
if( kHit < 0 ) // no appropriate gaussian mixture found at all, remove the weakest mixture and create a new one
{
kHit = k = std::min(k, K-1);
wsum += w0 - mptr[k].weight;
mptr[k].weight = w0;
mptr[k].mean = pix;
mptr[k].var = Vec3f(var0, var0, var0);
mptr[k].sortKey = sk0;
}
else
for( ; k < K; k++ )
wsum += mptr[k].weight;
float wscale = 1.f/wsum;
wsum = 0;
for( k = 0; k < K; k++ )
{
wsum += mptr[k].weight *= wscale;
mptr[k].sortKey *= wscale;
if( wsum > T && kForeground < 0 )
kForeground = k+1;
}
dst[x] = (uchar)(-(kHit >= kForeground));
}
}
else
{
for( x = 0; x < cols; x++, mptr += K )
{
Vec3f pix(src[x*3], src[x*3+1], src[x*3+2]);
int kHit = -1, kForeground = -1;
for( k = 0; k < K; k++ )
{
if( mptr[k].weight < FLT_EPSILON )
break;
Vec3f mu = mptr[k].mean;
Vec3f var = mptr[k].var;
Vec3f diff = pix - mu;
float d2 = diff.dot(diff);
if( d2 < vT*(var[0] + var[1] + var[2]) )
{
kHit = k;
break;
}
}
if( kHit >= 0 )
{
float wsum = 0;
for( k = 0; k < K; k++ )
{
wsum += mptr[k].weight;
if( wsum > T )
{
kForeground = k+1;
break;
}
}
}
dst[x] = (uchar)(kHit < 0 || kHit >= kForeground ? 255 : 0);
}
}
}
}
void BackgroundSubtractorMOGImpl::apply(InputArray _image, OutputArray _fgmask, double learningRate)
{
Mat image = _image.getMat();
bool needToInitialize = nframes == 0 || learningRate >= 1 || image.size() != frameSize || image.type() != frameType;
if( needToInitialize )
initialize(image.size(), image.type());
CV_Assert( image.depth() == CV_8U );
_fgmask.create( image.size(), CV_8U );
Mat fgmask = _fgmask.getMat();
++nframes;
learningRate = learningRate >= 0 && nframes > 1 ? learningRate : 1./std::min( nframes, history );
CV_Assert(learningRate >= 0);
if( image.type() == CV_8UC1 )
process8uC1( image, fgmask, learningRate, bgmodel, nmixtures, backgroundRatio, varThreshold, noiseSigma );
else if( image.type() == CV_8UC3 )
process8uC3( image, fgmask, learningRate, bgmodel, nmixtures, backgroundRatio, varThreshold, noiseSigma );
else
CV_Error( Error::StsUnsupportedFormat, "Only 1- and 3-channel 8-bit images are supported in BackgroundSubtractorMOG" );
}
Ptr<BackgroundSubtractorMOG> createBackgroundSubtractorMOG(int history, int nmixtures,
double backgroundRatio, double noiseSigma)
{
return makePtr<BackgroundSubtractorMOGImpl>(history, nmixtures, backgroundRatio, noiseSigma);
}
}
/* End of file. */

View File

@ -1,522 +0,0 @@
/*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, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, 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*/
/*
* This class implements an algorithm described in "Visual Tracking of Human Visitors under
* Variable-Lighting Conditions for a Responsive Audio Art Installation," A. Godbehere,
* A. Matsukawa, K. Goldberg, American Control Conference, Montreal, June 2012.
*
* Prepared and integrated by Andrew B. Godbehere.
*/
#include "precomp.hpp"
#include <limits>
namespace cv
{
class BackgroundSubtractorGMGImpl : public BackgroundSubtractorGMG
{
public:
BackgroundSubtractorGMGImpl()
{
/*
* Default Parameter Values. Override with algorithm "set" method.
*/
maxFeatures = 64;
learningRate = 0.025;
numInitializationFrames = 120;
quantizationLevels = 16;
backgroundPrior = 0.8;
decisionThreshold = 0.8;
smoothingRadius = 7;
updateBackgroundModel = true;
minVal_ = maxVal_ = 0;
name_ = "BackgroundSubtractor.GMG";
}
~BackgroundSubtractorGMGImpl()
{
}
virtual AlgorithmInfo* info() const { return 0; }
/**
* Validate parameters and set up data structures for appropriate image size.
* Must call before running on data.
* @param frameSize input frame size
* @param min minimum value taken on by pixels in image sequence. Usually 0
* @param max maximum value taken on by pixels in image sequence. e.g. 1.0 or 255
*/
void initialize(Size frameSize, double minVal, double maxVal);
/**
* Performs single-frame background subtraction and builds up a statistical background image
* model.
* @param image Input image
* @param fgmask Output mask image representing foreground and background pixels
*/
virtual void apply(InputArray image, OutputArray fgmask, double learningRate=-1.0);
/**
* Releases all inner buffers.
*/
void release();
virtual int getMaxFeatures() const { return maxFeatures; }
virtual void setMaxFeatures(int _maxFeatures) { maxFeatures = _maxFeatures; }
virtual double getDefaultLearningRate() const { return learningRate; }
virtual void setDefaultLearningRate(double lr) { learningRate = lr; }
virtual int getNumFrames() const { return numInitializationFrames; }
virtual void setNumFrames(int nframes) { numInitializationFrames = nframes; }
virtual int getQuantizationLevels() const { return quantizationLevels; }
virtual void setQuantizationLevels(int nlevels) { quantizationLevels = nlevels; }
virtual double getBackgroundPrior() const { return backgroundPrior; }
virtual void setBackgroundPrior(double bgprior) { backgroundPrior = bgprior; }
virtual int getSmoothingRadius() const { return smoothingRadius; }
virtual void setSmoothingRadius(int radius) { smoothingRadius = radius; }
virtual double getDecisionThreshold() const { return decisionThreshold; }
virtual void setDecisionThreshold(double thresh) { decisionThreshold = thresh; }
virtual bool getUpdateBackgroundModel() const { return updateBackgroundModel; }
virtual void setUpdateBackgroundModel(bool update) { updateBackgroundModel = update; }
virtual double getMinVal() const { return minVal_; }
virtual void setMinVal(double val) { minVal_ = val; }
virtual double getMaxVal() const { return maxVal_; }
virtual void setMaxVal(double val) { maxVal_ = val; }
virtual void getBackgroundImage(OutputArray) const
{
CV_Error( Error::StsNotImplemented, "" );
}
virtual void write(FileStorage& fs) const
{
fs << "name" << name_
<< "maxFeatures" << maxFeatures
<< "defaultLearningRate" << learningRate
<< "numFrames" << numInitializationFrames
<< "quantizationLevels" << quantizationLevels
<< "backgroundPrior" << backgroundPrior
<< "decisionThreshold" << decisionThreshold
<< "smoothingRadius" << smoothingRadius
<< "updateBackgroundModel" << (int)updateBackgroundModel;
// we do not save minVal_ & maxVal_, since they depend on the image type.
}
virtual void read(const FileNode& fn)
{
CV_Assert( (String)fn["name"] == name_ );
maxFeatures = (int)fn["maxFeatures"];
learningRate = (double)fn["defaultLearningRate"];
numInitializationFrames = (int)fn["numFrames"];
quantizationLevels = (int)fn["quantizationLevels"];
backgroundPrior = (double)fn["backgroundPrior"];
smoothingRadius = (int)fn["smoothingRadius"];
decisionThreshold = (double)fn["decisionThreshold"];
updateBackgroundModel = (int)fn["updateBackgroundModel"] != 0;
minVal_ = maxVal_ = 0;
frameSize_ = Size();
}
//! Total number of distinct colors to maintain in histogram.
int maxFeatures;
//! Set between 0.0 and 1.0, determines how quickly features are "forgotten" from histograms.
double learningRate;
//! Number of frames of video to use to initialize histograms.
int numInitializationFrames;
//! Number of discrete levels in each channel to be used in histograms.
int quantizationLevels;
//! Prior probability that any given pixel is a background pixel. A sensitivity parameter.
double backgroundPrior;
//! Value above which pixel is determined to be FG.
double decisionThreshold;
//! Smoothing radius, in pixels, for cleaning up FG image.
int smoothingRadius;
//! Perform background model update
bool updateBackgroundModel;
private:
double maxVal_;
double minVal_;
Size frameSize_;
int frameNum_;
String name_;
Mat_<int> nfeatures_;
Mat_<unsigned int> colors_;
Mat_<float> weights_;
Mat buf_;
};
void BackgroundSubtractorGMGImpl::initialize(Size frameSize, double minVal, double maxVal)
{
CV_Assert(minVal < maxVal);
CV_Assert(maxFeatures > 0);
CV_Assert(learningRate >= 0.0 && learningRate <= 1.0);
CV_Assert(numInitializationFrames >= 1);
CV_Assert(quantizationLevels >= 1 && quantizationLevels <= 255);
CV_Assert(backgroundPrior >= 0.0 && backgroundPrior <= 1.0);
minVal_ = minVal;
maxVal_ = maxVal;
frameSize_ = frameSize;
frameNum_ = 0;
nfeatures_.create(frameSize_);
colors_.create(frameSize_.area(), maxFeatures);
weights_.create(frameSize_.area(), maxFeatures);
nfeatures_.setTo(Scalar::all(0));
}
namespace
{
float findFeature(unsigned int color, const unsigned int* colors, const float* weights, int nfeatures)
{
for (int i = 0; i < nfeatures; ++i)
{
if (color == colors[i])
return weights[i];
}
// not in histogram, so return 0.
return 0.0f;
}
void normalizeHistogram(float* weights, int nfeatures)
{
float total = 0.0f;
for (int i = 0; i < nfeatures; ++i)
total += weights[i];
if (total != 0.0f)
{
for (int i = 0; i < nfeatures; ++i)
weights[i] /= total;
}
}
bool insertFeature(unsigned int color, float weight, unsigned int* colors, float* weights, int& nfeatures, int maxFeatures)
{
int idx = -1;
for (int i = 0; i < nfeatures; ++i)
{
if (color == colors[i])
{
// feature in histogram
weight += weights[i];
idx = i;
break;
}
}
if (idx >= 0)
{
// move feature to beginning of list
::memmove(colors + 1, colors, idx * sizeof(unsigned int));
::memmove(weights + 1, weights, idx * sizeof(float));
colors[0] = color;
weights[0] = weight;
}
else if (nfeatures == maxFeatures)
{
// discard oldest feature
::memmove(colors + 1, colors, (nfeatures - 1) * sizeof(unsigned int));
::memmove(weights + 1, weights, (nfeatures - 1) * sizeof(float));
colors[0] = color;
weights[0] = weight;
}
else
{
colors[nfeatures] = color;
weights[nfeatures] = weight;
++nfeatures;
return true;
}
return false;
}
}
namespace
{
template <typename T> struct Quantization
{
static unsigned int apply(const void* src_, int x, int cn, double minVal, double maxVal, int quantizationLevels)
{
const T* src = static_cast<const T*>(src_);
src += x * cn;
unsigned int res = 0;
for (int i = 0, shift = 0; i < cn; ++i, ++src, shift += 8)
res |= static_cast<int>((*src - minVal) * quantizationLevels / (maxVal - minVal)) << shift;
return res;
}
};
class GMG_LoopBody : public ParallelLoopBody
{
public:
GMG_LoopBody(const Mat& frame, const Mat& fgmask, const Mat_<int>& nfeatures, const Mat_<unsigned int>& colors, const Mat_<float>& weights,
int maxFeatures, double learningRate, int numInitializationFrames, int quantizationLevels, double backgroundPrior, double decisionThreshold,
double maxVal, double minVal, int frameNum, bool updateBackgroundModel) :
frame_(frame), fgmask_(fgmask), nfeatures_(nfeatures), colors_(colors), weights_(weights),
maxFeatures_(maxFeatures), learningRate_(learningRate), numInitializationFrames_(numInitializationFrames), quantizationLevels_(quantizationLevels),
backgroundPrior_(backgroundPrior), decisionThreshold_(decisionThreshold), updateBackgroundModel_(updateBackgroundModel),
maxVal_(maxVal), minVal_(minVal), frameNum_(frameNum)
{
}
void operator() (const Range& range) const;
private:
Mat frame_;
mutable Mat_<uchar> fgmask_;
mutable Mat_<int> nfeatures_;
mutable Mat_<unsigned int> colors_;
mutable Mat_<float> weights_;
int maxFeatures_;
double learningRate_;
int numInitializationFrames_;
int quantizationLevels_;
double backgroundPrior_;
double decisionThreshold_;
bool updateBackgroundModel_;
double maxVal_;
double minVal_;
int frameNum_;
};
void GMG_LoopBody::operator() (const Range& range) const
{
typedef unsigned int (*func_t)(const void* src_, int x, int cn, double minVal, double maxVal, int quantizationLevels);
static const func_t funcs[] =
{
Quantization<uchar>::apply,
Quantization<schar>::apply,
Quantization<ushort>::apply,
Quantization<short>::apply,
Quantization<int>::apply,
Quantization<float>::apply,
Quantization<double>::apply
};
const func_t func = funcs[frame_.depth()];
CV_Assert(func != 0);
const int cn = frame_.channels();
for (int y = range.start, featureIdx = y * frame_.cols; y < range.end; ++y)
{
const uchar* frame_row = frame_.ptr(y);
int* nfeatures_row = nfeatures_[y];
uchar* fgmask_row = fgmask_[y];
for (int x = 0; x < frame_.cols; ++x, ++featureIdx)
{
int nfeatures = nfeatures_row[x];
unsigned int* colors = colors_[featureIdx];
float* weights = weights_[featureIdx];
unsigned int newFeatureColor = func(frame_row, x, cn, minVal_, maxVal_, quantizationLevels_);
bool isForeground = false;
if (frameNum_ >= numInitializationFrames_)
{
// typical operation
const double weight = findFeature(newFeatureColor, colors, weights, nfeatures);
// see Godbehere, Matsukawa, Goldberg (2012) for reasoning behind this implementation of Bayes rule
const double posterior = (weight * backgroundPrior_) / (weight * backgroundPrior_ + (1.0 - weight) * (1.0 - backgroundPrior_));
isForeground = ((1.0 - posterior) > decisionThreshold_);
// update histogram.
if (updateBackgroundModel_)
{
for (int i = 0; i < nfeatures; ++i)
weights[i] *= (float)(1.0f - learningRate_);
bool inserted = insertFeature(newFeatureColor, (float)learningRate_, colors, weights, nfeatures, maxFeatures_);
if (inserted)
{
normalizeHistogram(weights, nfeatures);
nfeatures_row[x] = nfeatures;
}
}
}
else if (updateBackgroundModel_)
{
// training-mode update
insertFeature(newFeatureColor, 1.0f, colors, weights, nfeatures, maxFeatures_);
if (frameNum_ == numInitializationFrames_ - 1)
normalizeHistogram(weights, nfeatures);
}
fgmask_row[x] = (uchar)(-(schar)isForeground);
}
}
}
}
void BackgroundSubtractorGMGImpl::apply(InputArray _frame, OutputArray _fgmask, double newLearningRate)
{
Mat frame = _frame.getMat();
CV_Assert(frame.depth() == CV_8U || frame.depth() == CV_16U || frame.depth() == CV_32F);
CV_Assert(frame.channels() == 1 || frame.channels() == 3 || frame.channels() == 4);
if (newLearningRate != -1.0)
{
CV_Assert(newLearningRate >= 0.0 && newLearningRate <= 1.0);
learningRate = newLearningRate;
}
if (frame.size() != frameSize_)
{
double minval = minVal_;
double maxval = maxVal_;
if( minVal_ == 0 && maxVal_ == 0 )
{
minval = 0;
maxval = frame.depth() == CV_8U ? 255.0 : frame.depth() == CV_16U ? std::numeric_limits<ushort>::max() : 1.0;
}
initialize(frame.size(), minval, maxval);
}
_fgmask.create(frameSize_, CV_8UC1);
Mat fgmask = _fgmask.getMat();
GMG_LoopBody body(frame, fgmask, nfeatures_, colors_, weights_,
maxFeatures, learningRate, numInitializationFrames, quantizationLevels, backgroundPrior, decisionThreshold,
maxVal_, minVal_, frameNum_, updateBackgroundModel);
parallel_for_(Range(0, frame.rows), body, frame.total()/(double)(1<<16));
if (smoothingRadius > 0)
{
medianBlur(fgmask, buf_, smoothingRadius);
swap(fgmask, buf_);
}
// keep track of how many frames we have processed
++frameNum_;
}
void BackgroundSubtractorGMGImpl::release()
{
frameSize_ = Size();
nfeatures_.release();
colors_.release();
weights_.release();
buf_.release();
}
Ptr<BackgroundSubtractorGMG> createBackgroundSubtractorGMG(int initializationFrames, double decisionThreshold)
{
Ptr<BackgroundSubtractorGMG> bgfg = makePtr<BackgroundSubtractorGMGImpl>();
bgfg->setNumFrames(initializationFrames);
bgfg->setDecisionThreshold(decisionThreshold);
return bgfg;
}
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////
CV_INIT_ALGORITHM(BackgroundSubtractorGMG, "BackgroundSubtractor.GMG",
obj.info()->addParam(obj, "maxFeatures", obj.maxFeatures,false,0,0,
"Maximum number of features to store in histogram. Harsh enforcement of sparsity constraint.");
obj.info()->addParam(obj, "learningRate", obj.learningRate,false,0,0,
"Adaptation rate of histogram. Close to 1, slow adaptation. Close to 0, fast adaptation, features forgotten quickly.");
obj.info()->addParam(obj, "initializationFrames", obj.numInitializationFrames,false,0,0,
"Number of frames to use to initialize histograms of pixels.");
obj.info()->addParam(obj, "quantizationLevels", obj.quantizationLevels,false,0,0,
"Number of discrete colors to be used in histograms. Up-front quantization.");
obj.info()->addParam(obj, "backgroundPrior", obj.backgroundPrior,false,0,0,
"Prior probability that each individual pixel is a background pixel.");
obj.info()->addParam(obj, "smoothingRadius", obj.smoothingRadius,false,0,0,
"Radius of smoothing kernel to filter noise from FG mask image.");
obj.info()->addParam(obj, "decisionThreshold", obj.decisionThreshold,false,0,0,
"Threshold for FG decision rule. Pixel is FG if posterior probability exceeds threshold.");
obj.info()->addParam(obj, "updateBackgroundModel", obj.updateBackgroundModel,false,0,0,
"Perform background model update.");
obj.info()->addParam(obj, "minVal", obj.minVal_,false,0,0,
"Minimum of the value range (mostly for regression testing)");
obj.info()->addParam(obj, "maxVal", obj.maxVal_,false,0,0,
"Maximum of the value range (mostly for regression testing)");
);
*/
}

View File

@ -87,76 +87,6 @@ cvCamShift( const void* imgProb, CvRect windowIn,
return rr.size.width*rr.size.height > 0.f ? 1 : -1;
}
///////////////////////// Motion Templates ////////////////////////////
CV_IMPL void
cvUpdateMotionHistory( const void* silhouette, void* mhimg,
double timestamp, double mhi_duration )
{
cv::Mat silh = cv::cvarrToMat(silhouette), mhi = cv::cvarrToMat(mhimg);
cv::updateMotionHistory(silh, mhi, timestamp, mhi_duration);
}
CV_IMPL void
cvCalcMotionGradient( const CvArr* mhimg, CvArr* maskimg,
CvArr* orientation,
double delta1, double delta2,
int aperture_size )
{
cv::Mat mhi = cv::cvarrToMat(mhimg);
const cv::Mat mask = cv::cvarrToMat(maskimg), orient = cv::cvarrToMat(orientation);
cv::calcMotionGradient(mhi, mask, orient, delta1, delta2, aperture_size);
}
CV_IMPL double
cvCalcGlobalOrientation( const void* orientation, const void* maskimg, const void* mhimg,
double curr_mhi_timestamp, double mhi_duration )
{
cv::Mat mhi = cv::cvarrToMat(mhimg);
cv::Mat mask = cv::cvarrToMat(maskimg), orient = cv::cvarrToMat(orientation);
return cv::calcGlobalOrientation(orient, mask, mhi, curr_mhi_timestamp, mhi_duration);
}
CV_IMPL CvSeq*
cvSegmentMotion( const CvArr* mhimg, CvArr* segmaskimg, CvMemStorage* storage,
double timestamp, double segThresh )
{
cv::Mat mhi = cv::cvarrToMat(mhimg);
const cv::Mat segmask = cv::cvarrToMat(segmaskimg);
std::vector<cv::Rect> brs;
cv::segmentMotion(mhi, segmask, brs, timestamp, segThresh);
CvSeq* seq = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvConnectedComp), storage);
CvConnectedComp comp;
memset(&comp, 0, sizeof(comp));
for( size_t i = 0; i < brs.size(); i++ )
{
cv::Rect roi = brs[i];
float compLabel = (float)(i+1);
int x, y, area = 0;
cv::Mat part = segmask(roi);
for( y = 0; y < roi.height; y++ )
{
const float* partptr = part.ptr<float>(y);
for( x = 0; x < roi.width; x++ )
area += partptr[x] == compLabel;
}
comp.value = cv::Scalar(compLabel);
comp.rect = roi;
comp.area = area;
cvSeqPush(seq, &comp);
}
return seq;
}
///////////////////////////////// Kalman ///////////////////////////////
CV_IMPL CvKalman*

View File

@ -1,416 +0,0 @@
/*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 "opencl_kernels_video.hpp"
#ifdef HAVE_OPENCL
namespace cv {
static bool ocl_updateMotionHistory( InputArray _silhouette, InputOutputArray _mhi,
float timestamp, float delbound )
{
ocl::Kernel k("updateMotionHistory", ocl::video::updatemotionhistory_oclsrc);
if (k.empty())
return false;
UMat silh = _silhouette.getUMat(), mhi = _mhi.getUMat();
k.args(ocl::KernelArg::ReadOnlyNoSize(silh), ocl::KernelArg::ReadWrite(mhi),
timestamp, delbound);
size_t globalsize[2] = { silh.cols, silh.rows };
return k.run(2, globalsize, NULL, false);
}
}
#endif
void cv::updateMotionHistory( InputArray _silhouette, InputOutputArray _mhi,
double timestamp, double duration )
{
CV_Assert( _silhouette.type() == CV_8UC1 && _mhi.type() == CV_32FC1 );
CV_Assert( _silhouette.sameSize(_mhi) );
float ts = (float)timestamp;
float delbound = (float)(timestamp - duration);
CV_OCL_RUN(_mhi.isUMat() && _mhi.dims() <= 2,
ocl_updateMotionHistory(_silhouette, _mhi, ts, delbound))
Mat silh = _silhouette.getMat(), mhi = _mhi.getMat();
Size size = silh.size();
#if defined(HAVE_IPP)
int silhstep = (int)silh.step, mhistep = (int)mhi.step;
#endif
if( silh.isContinuous() && mhi.isContinuous() )
{
size.width *= size.height;
size.height = 1;
#if defined(HAVE_IPP)
silhstep = (int)silh.total();
mhistep = (int)mhi.total() * sizeof(Ipp32f);
#endif
}
#if defined(HAVE_IPP)
IppStatus status = ippiUpdateMotionHistory_8u32f_C1IR((const Ipp8u *)silh.data, silhstep, (Ipp32f *)mhi.data, mhistep,
ippiSize(size.width, size.height), (Ipp32f)timestamp, (Ipp32f)duration);
if (status >= 0)
return;
#endif
#if CV_SSE2
volatile bool useSIMD = cv::checkHardwareSupport(CV_CPU_SSE2);
#endif
for(int y = 0; y < size.height; y++ )
{
const uchar* silhData = silh.ptr<uchar>(y);
float* mhiData = mhi.ptr<float>(y);
int x = 0;
#if CV_SSE2
if( useSIMD )
{
__m128 ts4 = _mm_set1_ps(ts), db4 = _mm_set1_ps(delbound);
for( ; x <= size.width - 8; x += 8 )
{
__m128i z = _mm_setzero_si128();
__m128i s = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(silhData + x)), z);
__m128 s0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(s, z)), s1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(s, z));
__m128 v0 = _mm_loadu_ps(mhiData + x), v1 = _mm_loadu_ps(mhiData + x + 4);
__m128 fz = _mm_setzero_ps();
v0 = _mm_and_ps(v0, _mm_cmpge_ps(v0, db4));
v1 = _mm_and_ps(v1, _mm_cmpge_ps(v1, db4));
__m128 m0 = _mm_and_ps(_mm_xor_ps(v0, ts4), _mm_cmpneq_ps(s0, fz));
__m128 m1 = _mm_and_ps(_mm_xor_ps(v1, ts4), _mm_cmpneq_ps(s1, fz));
v0 = _mm_xor_ps(v0, m0);
v1 = _mm_xor_ps(v1, m1);
_mm_storeu_ps(mhiData + x, v0);
_mm_storeu_ps(mhiData + x + 4, v1);
}
}
#endif
for( ; x < size.width; x++ )
{
float val = mhiData[x];
val = silhData[x] ? ts : val < delbound ? 0 : val;
mhiData[x] = val;
}
}
}
void cv::calcMotionGradient( InputArray _mhi, OutputArray _mask,
OutputArray _orientation,
double delta1, double delta2,
int aperture_size )
{
static int runcase = 0; runcase++;
Mat mhi = _mhi.getMat();
Size size = mhi.size();
_mask.create(size, CV_8U);
_orientation.create(size, CV_32F);
Mat mask = _mask.getMat();
Mat orient = _orientation.getMat();
if( aperture_size < 3 || aperture_size > 7 || (aperture_size & 1) == 0 )
CV_Error( Error::StsOutOfRange, "aperture_size must be 3, 5 or 7" );
if( delta1 <= 0 || delta2 <= 0 )
CV_Error( Error::StsOutOfRange, "both delta's must be positive" );
if( mhi.type() != CV_32FC1 )
CV_Error( Error::StsUnsupportedFormat,
"MHI must be single-channel floating-point images" );
if( orient.data == mhi.data )
{
_orientation.release();
_orientation.create(size, CV_32F);
orient = _orientation.getMat();
}
if( delta1 > delta2 )
std::swap(delta1, delta2);
float gradient_epsilon = 1e-4f * aperture_size * aperture_size;
float min_delta = (float)delta1;
float max_delta = (float)delta2;
Mat dX_min, dY_max;
// calc Dx and Dy
Sobel( mhi, dX_min, CV_32F, 1, 0, aperture_size, 1, 0, BORDER_REPLICATE );
Sobel( mhi, dY_max, CV_32F, 0, 1, aperture_size, 1, 0, BORDER_REPLICATE );
int x, y;
if( mhi.isContinuous() && orient.isContinuous() && mask.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
// calc gradient
for( y = 0; y < size.height; y++ )
{
const float* dX_min_row = dX_min.ptr<float>(y);
const float* dY_max_row = dY_max.ptr<float>(y);
float* orient_row = orient.ptr<float>(y);
uchar* mask_row = mask.ptr<uchar>(y);
fastAtan2(dY_max_row, dX_min_row, orient_row, size.width, true);
// make orientation zero where the gradient is very small
for( x = 0; x < size.width; x++ )
{
float dY = dY_max_row[x];
float dX = dX_min_row[x];
if( std::abs(dX) < gradient_epsilon && std::abs(dY) < gradient_epsilon )
{
mask_row[x] = (uchar)0;
orient_row[x] = 0.f;
}
else
mask_row[x] = (uchar)1;
}
}
erode( mhi, dX_min, noArray(), Point(-1,-1), (aperture_size-1)/2, BORDER_REPLICATE );
dilate( mhi, dY_max, noArray(), Point(-1,-1), (aperture_size-1)/2, BORDER_REPLICATE );
// mask off pixels which have little motion difference in their neighborhood
for( y = 0; y < size.height; y++ )
{
const float* dX_min_row = dX_min.ptr<float>(y);
const float* dY_max_row = dY_max.ptr<float>(y);
float* orient_row = orient.ptr<float>(y);
uchar* mask_row = mask.ptr<uchar>(y);
for( x = 0; x < size.width; x++ )
{
float d0 = dY_max_row[x] - dX_min_row[x];
if( mask_row[x] == 0 || d0 < min_delta || max_delta < d0 )
{
mask_row[x] = (uchar)0;
orient_row[x] = 0.f;
}
}
}
}
double cv::calcGlobalOrientation( InputArray _orientation, InputArray _mask,
InputArray _mhi, double /*timestamp*/,
double duration )
{
Mat orient = _orientation.getMat(), mask = _mask.getMat(), mhi = _mhi.getMat();
Size size = mhi.size();
CV_Assert( mask.type() == CV_8U && orient.type() == CV_32F && mhi.type() == CV_32F );
CV_Assert( mask.size() == size && orient.size() == size );
CV_Assert( duration > 0 );
int histSize = 12;
float _ranges[] = { 0.f, 360.f };
const float* ranges = _ranges;
Mat hist;
calcHist(&orient, 1, 0, mask, hist, 1, &histSize, &ranges);
// find the maximum index (the dominant orientation)
Point baseOrientPt;
minMaxLoc(hist, 0, 0, 0, &baseOrientPt);
float fbaseOrient = (baseOrientPt.x + baseOrientPt.y)*360.f/histSize;
// override timestamp with the maximum value in MHI
double timestamp = 0;
minMaxLoc( mhi, 0, &timestamp, 0, 0, mask );
// find the shift relative to the dominant orientation as weighted sum of relative angles
float a = (float)(254. / 255. / duration);
float b = (float)(1. - timestamp * a);
float delbound = (float)(timestamp - duration);
if( mhi.isContinuous() && mask.isContinuous() && orient.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
/*
a = 254/(255*dt)
b = 1 - t*a = 1 - 254*t/(255*dur) =
(255*dt - 254*t)/(255*dt) =
(dt - (t - dt)*254)/(255*dt);
--------------------------------------------------------
ax + b = 254*x/(255*dt) + (dt - (t - dt)*254)/(255*dt) =
(254*x + dt - (t - dt)*254)/(255*dt) =
((x - (t - dt))*254 + dt)/(255*dt) =
(((x - (t - dt))/dt)*254 + 1)/255 = (((x - low_time)/dt)*254 + 1)/255
*/
float shiftOrient = 0, shiftWeight = 0;
for( int y = 0; y < size.height; y++ )
{
const float* mhiptr = mhi.ptr<float>(y);
const float* oriptr = orient.ptr<float>(y);
const uchar* maskptr = mask.ptr<uchar>(y);
for( int x = 0; x < size.width; x++ )
{
if( maskptr[x] != 0 && mhiptr[x] > delbound )
{
/*
orient in 0..360, base_orient in 0..360
-> (rel_angle = orient - base_orient) in -360..360.
rel_angle is translated to -180..180
*/
float weight = mhiptr[x] * a + b;
float relAngle = oriptr[x] - fbaseOrient;
relAngle += (relAngle < -180 ? 360 : 0);
relAngle += (relAngle > 180 ? -360 : 0);
if( fabs(relAngle) < 45 )
{
shiftOrient += weight * relAngle;
shiftWeight += weight;
}
}
}
}
// add the dominant orientation and the relative shift
if( shiftWeight == 0 )
shiftWeight = 0.01f;
fbaseOrient += shiftOrient / shiftWeight;
fbaseOrient -= (fbaseOrient < 360 ? 0 : 360);
fbaseOrient += (fbaseOrient >= 0 ? 0 : 360);
return fbaseOrient;
}
void cv::segmentMotion(InputArray _mhi, OutputArray _segmask,
std::vector<Rect>& boundingRects,
double timestamp, double segThresh)
{
Mat mhi = _mhi.getMat();
_segmask.create(mhi.size(), CV_32F);
Mat segmask = _segmask.getMat();
segmask = Scalar::all(0);
CV_Assert( mhi.type() == CV_32F );
CV_Assert( segThresh >= 0 );
Mat mask = Mat::zeros( mhi.rows + 2, mhi.cols + 2, CV_8UC1 );
int x, y;
// protect zero mhi pixels from floodfill.
for( y = 0; y < mhi.rows; y++ )
{
const float* mhiptr = mhi.ptr<float>(y);
uchar* maskptr = mask.ptr<uchar>(y+1) + 1;
for( x = 0; x < mhi.cols; x++ )
{
if( mhiptr[x] == 0 )
maskptr[x] = 1;
}
}
float ts = (float)timestamp;
float comp_idx = 1.f;
for( y = 0; y < mhi.rows; y++ )
{
float* mhiptr = mhi.ptr<float>(y);
uchar* maskptr = mask.ptr<uchar>(y+1) + 1;
for( x = 0; x < mhi.cols; x++ )
{
if( mhiptr[x] == ts && maskptr[x] == 0 )
{
Rect cc;
floodFill( mhi, mask, Point(x,y), Scalar::all(0),
&cc, Scalar::all(segThresh), Scalar::all(segThresh),
FLOODFILL_MASK_ONLY + 2*256 + 4 );
for( int y1 = 0; y1 < cc.height; y1++ )
{
float* segmaskptr = segmask.ptr<float>(cc.y + y1) + cc.x;
uchar* maskptr1 = mask.ptr<uchar>(cc.y + y1 + 1) + cc.x + 1;
for( int x1 = 0; x1 < cc.width; x1++ )
{
if( maskptr1[x1] > 1 )
{
maskptr1[x1] = 1;
segmaskptr[x1] = comp_idx;
}
}
}
comp_idx += 1.f;
boundingRects.push_back(cc);
}
}
}
}
/* End of file. */

View File

@ -1,27 +0,0 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
// Copyright (C) 2014, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
__kernel void updateMotionHistory(__global const uchar * silh, int silh_step, int silh_offset,
__global uchar * mhiptr, int mhi_step, int mhi_offset, int mhi_rows, int mhi_cols,
float timestamp, float delbound)
{
int x = get_global_id(0);
int y = get_global_id(1);
if (x < mhi_cols && y < mhi_rows)
{
int silh_index = mad24(y, silh_step, silh_offset + x);
int mhi_index = mad24(y, mhi_step, mhi_offset + x * (int)sizeof(float));
silh += silh_index;
__global float * mhi = (__global float *)(mhiptr + mhi_index);
float val = mhi[0];
val = silh[0] ? timestamp : val < delbound ? 0 : val;
mhi[0] = val;
}
}

View File

@ -1,673 +0,0 @@
/*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"
//
// 2D dense optical flow algorithm from the following paper:
// Michael Tao, Jiamin Bai, Pushmeet Kohli, and Sylvain Paris.
// "SimpleFlow: A Non-iterative, Sublinear Optical Flow Algorithm"
// Computer Graphics Forum (Eurographics 2012)
// http://graphics.berkeley.edu/papers/Tao-SAN-2012-05/
//
namespace cv
{
static const uchar MASK_TRUE_VALUE = (uchar)255;
inline static float dist(const Vec3b& p1, const Vec3b& p2) {
return (float)((p1[0] - p2[0]) * (p1[0] - p2[0]) +
(p1[1] - p2[1]) * (p1[1] - p2[1]) +
(p1[2] - p2[2]) * (p1[2] - p2[2]));
}
inline static float dist(const Vec2f& p1, const Vec2f& p2) {
return (p1[0] - p2[0]) * (p1[0] - p2[0]) +
(p1[1] - p2[1]) * (p1[1] - p2[1]);
}
template<class T>
inline static T min(T t1, T t2, T t3) {
return (t1 <= t2 && t1 <= t3) ? t1 : min(t2, t3);
}
static void removeOcclusions(const Mat& flow,
const Mat& flow_inv,
float occ_thr,
Mat& confidence) {
const int rows = flow.rows;
const int cols = flow.cols;
if (!confidence.data) {
confidence = Mat::zeros(rows, cols, CV_32F);
}
for (int r = 0; r < rows; ++r) {
for (int c = 0; c < cols; ++c) {
if (dist(flow.at<Vec2f>(r, c), -flow_inv.at<Vec2f>(r, c)) > occ_thr) {
confidence.at<float>(r, c) = 0;
} else {
confidence.at<float>(r, c) = 1;
}
}
}
}
static void wd(Mat& d, int top_shift, int bottom_shift, int left_shift, int right_shift, float sigma) {
for (int dr = -top_shift, r = 0; dr <= bottom_shift; ++dr, ++r) {
for (int dc = -left_shift, c = 0; dc <= right_shift; ++dc, ++c) {
d.at<float>(r, c) = (float)-(dr*dr + dc*dc);
}
}
d *= 1.0 / (2.0 * sigma * sigma);
exp(d, d);
}
static void wc(const Mat& image, Mat& d, int r0, int c0,
int top_shift, int bottom_shift, int left_shift, int right_shift, float sigma) {
const Vec3b centeral_point = image.at<Vec3b>(r0, c0);
int left_border = c0-left_shift, right_border = c0+right_shift;
for (int dr = r0-top_shift, r = 0; dr <= r0+bottom_shift; ++dr, ++r) {
const Vec3b *row = image.ptr<Vec3b>(dr);
float *d_row = d.ptr<float>(r);
for (int dc = left_border, c = 0; dc <= right_border; ++dc, ++c) {
d_row[c] = -dist(centeral_point, row[dc]);
}
}
d *= 1.0 / (2.0 * sigma * sigma);
exp(d, d);
}
static void crossBilateralFilter(const Mat& image,
const Mat& edge_image,
const Mat confidence,
Mat& dst, int d,
float sigma_color, float sigma_space,
bool flag=false) {
const int rows = image.rows;
const int cols = image.cols;
Mat image_extended, edge_image_extended, confidence_extended;
copyMakeBorder(image, image_extended, d, d, d, d, BORDER_DEFAULT);
copyMakeBorder(edge_image, edge_image_extended, d, d, d, d, BORDER_DEFAULT);
copyMakeBorder(confidence, confidence_extended, d, d, d, d, BORDER_CONSTANT, Scalar(0));
Mat weights_space(2*d+1, 2*d+1, CV_32F);
wd(weights_space, d, d, d, d, sigma_space);
Mat weights(2*d+1, 2*d+1, CV_32F);
Mat weighted_sum(2*d+1, 2*d+1, CV_32F);
std::vector<Mat> image_extended_channels;
split(image_extended, image_extended_channels);
for (int row = 0; row < rows; ++row) {
for (int col = 0; col < cols; ++col) {
wc(edge_image_extended, weights, row+d, col+d, d, d, d, d, sigma_color);
Range window_rows(row,row+2*d+1);
Range window_cols(col,col+2*d+1);
multiply(weights, confidence_extended(window_rows, window_cols), weights);
multiply(weights, weights_space, weights);
float weights_sum = (float)sum(weights)[0];
for (int ch = 0; ch < 2; ++ch) {
multiply(weights, image_extended_channels[ch](window_rows, window_cols), weighted_sum);
float total_sum = (float)sum(weighted_sum)[0];
dst.at<Vec2f>(row, col)[ch] = (flag && fabs(weights_sum) < 1e-9)
? image.at<float>(row, col)
: total_sum / weights_sum;
}
}
}
}
static void calcConfidence(const Mat& prev,
const Mat& next,
const Mat& flow,
Mat& confidence,
int max_flow) {
const int rows = prev.rows;
const int cols = prev.cols;
confidence = Mat::zeros(rows, cols, CV_32F);
for (int r0 = 0; r0 < rows; ++r0) {
for (int c0 = 0; c0 < cols; ++c0) {
Vec2f flow_at_point = flow.at<Vec2f>(r0, c0);
int u0 = cvRound(flow_at_point[0]);
if (r0 + u0 < 0) { u0 = -r0; }
if (r0 + u0 >= rows) { u0 = rows - 1 - r0; }
int v0 = cvRound(flow_at_point[1]);
if (c0 + v0 < 0) { v0 = -c0; }
if (c0 + v0 >= cols) { v0 = cols - 1 - c0; }
const int top_row_shift = -std::min(r0 + u0, max_flow);
const int bottom_row_shift = std::min(rows - 1 - (r0 + u0), max_flow);
const int left_col_shift = -std::min(c0 + v0, max_flow);
const int right_col_shift = std::min(cols - 1 - (c0 + v0), max_flow);
bool first_flow_iteration = true;
float sum_e = 0, min_e = 0;
for (int u = top_row_shift; u <= bottom_row_shift; ++u) {
for (int v = left_col_shift; v <= right_col_shift; ++v) {
float e = dist(prev.at<Vec3b>(r0, c0), next.at<Vec3b>(r0 + u0 + u, c0 + v0 + v));
if (first_flow_iteration) {
sum_e = e;
min_e = e;
first_flow_iteration = false;
} else {
sum_e += e;
min_e = std::min(min_e, e);
}
}
}
int windows_square = (bottom_row_shift - top_row_shift + 1) *
(right_col_shift - left_col_shift + 1);
confidence.at<float>(r0, c0) = (windows_square == 0) ? 0
: sum_e / windows_square - min_e;
CV_Assert(confidence.at<float>(r0, c0) >= 0);
}
}
}
static void calcOpticalFlowSingleScaleSF(const Mat& prev_extended,
const Mat& next_extended,
const Mat& mask,
Mat& flow,
int averaging_radius,
int max_flow,
float sigma_dist,
float sigma_color) {
const int averaging_radius_2 = averaging_radius << 1;
const int rows = prev_extended.rows - averaging_radius_2;
const int cols = prev_extended.cols - averaging_radius_2;
Mat weight_window(averaging_radius_2 + 1, averaging_radius_2 + 1, CV_32F);
Mat space_weight_window(averaging_radius_2 + 1, averaging_radius_2 + 1, CV_32F);
wd(space_weight_window, averaging_radius, averaging_radius, averaging_radius, averaging_radius, sigma_dist);
for (int r0 = 0; r0 < rows; ++r0) {
for (int c0 = 0; c0 < cols; ++c0) {
if (!mask.at<uchar>(r0, c0)) {
continue;
}
// TODO: do smth with this creepy staff
Vec2f flow_at_point = flow.at<Vec2f>(r0, c0);
int u0 = cvRound(flow_at_point[0]);
if (r0 + u0 < 0) { u0 = -r0; }
if (r0 + u0 >= rows) { u0 = rows - 1 - r0; }
int v0 = cvRound(flow_at_point[1]);
if (c0 + v0 < 0) { v0 = -c0; }
if (c0 + v0 >= cols) { v0 = cols - 1 - c0; }
const int top_row_shift = -std::min(r0 + u0, max_flow);
const int bottom_row_shift = std::min(rows - 1 - (r0 + u0), max_flow);
const int left_col_shift = -std::min(c0 + v0, max_flow);
const int right_col_shift = std::min(cols - 1 - (c0 + v0), max_flow);
float min_cost = FLT_MAX, best_u = (float)u0, best_v = (float)v0;
wc(prev_extended, weight_window, r0 + averaging_radius, c0 + averaging_radius,
averaging_radius, averaging_radius, averaging_radius, averaging_radius, sigma_color);
multiply(weight_window, space_weight_window, weight_window);
const int prev_extended_top_window_row = r0;
const int prev_extended_left_window_col = c0;
for (int u = top_row_shift; u <= bottom_row_shift; ++u) {
const int next_extended_top_window_row = r0 + u0 + u;
for (int v = left_col_shift; v <= right_col_shift; ++v) {
const int next_extended_left_window_col = c0 + v0 + v;
float cost = 0;
for (int r = 0; r <= averaging_radius_2; ++r) {
const Vec3b *prev_extended_window_row = prev_extended.ptr<Vec3b>(prev_extended_top_window_row + r);
const Vec3b *next_extended_window_row = next_extended.ptr<Vec3b>(next_extended_top_window_row + r);
const float* weight_window_row = weight_window.ptr<float>(r);
for (int c = 0; c <= averaging_radius_2; ++c) {
cost += weight_window_row[c] *
dist(prev_extended_window_row[prev_extended_left_window_col + c],
next_extended_window_row[next_extended_left_window_col + c]);
}
}
// cost should be divided by sum(weight_window), but because
// we interested only in min(cost) and sum(weight_window) is constant
// for every point - we remove it
if (cost < min_cost) {
min_cost = cost;
best_u = (float)(u + u0);
best_v = (float)(v + v0);
}
}
}
flow.at<Vec2f>(r0, c0) = Vec2f(best_u, best_v);
}
}
}
static Mat upscaleOpticalFlow(int new_rows,
int new_cols,
const Mat& image,
const Mat& confidence,
Mat& flow,
int averaging_radius,
float sigma_dist,
float sigma_color) {
crossBilateralFilter(flow, image, confidence, flow, averaging_radius, sigma_color, sigma_dist, true);
Mat new_flow;
resize(flow, new_flow, Size(new_cols, new_rows), 0, 0, INTER_NEAREST);
new_flow *= 2;
return new_flow;
}
static Mat calcIrregularityMat(const Mat& flow, int radius) {
const int rows = flow.rows;
const int cols = flow.cols;
Mat irregularity = Mat::zeros(rows, cols, CV_32F);
for (int r = 0; r < rows; ++r) {
const int start_row = std::max(0, r - radius);
const int end_row = std::min(rows - 1, r + radius);
for (int c = 0; c < cols; ++c) {
const int start_col = std::max(0, c - radius);
const int end_col = std::min(cols - 1, c + radius);
for (int dr = start_row; dr <= end_row; ++dr) {
for (int dc = start_col; dc <= end_col; ++dc) {
const float diff = dist(flow.at<Vec2f>(r, c), flow.at<Vec2f>(dr, dc));
if (diff > irregularity.at<float>(r, c)) {
irregularity.at<float>(r, c) = diff;
}
}
}
}
}
return irregularity;
}
static void selectPointsToRecalcFlow(const Mat& flow,
int irregularity_metric_radius,
float speed_up_thr,
int curr_rows,
int curr_cols,
const Mat& prev_speed_up,
Mat& speed_up,
Mat& mask) {
const int prev_rows = flow.rows;
const int prev_cols = flow.cols;
Mat is_flow_regular = calcIrregularityMat(flow, irregularity_metric_radius)
< speed_up_thr;
Mat done = Mat::zeros(prev_rows, prev_cols, CV_8U);
speed_up = Mat::zeros(curr_rows, curr_cols, CV_8U);
mask = Mat::zeros(curr_rows, curr_cols, CV_8U);
for (int r = 0; r < is_flow_regular.rows; ++r) {
for (int c = 0; c < is_flow_regular.cols; ++c) {
if (!done.at<uchar>(r, c)) {
if (is_flow_regular.at<uchar>(r, c) &&
2*r + 1 < curr_rows && 2*c + 1< curr_cols) {
bool all_flow_in_region_regular = true;
int speed_up_at_this_point = prev_speed_up.at<uchar>(r, c);
int step = (1 << speed_up_at_this_point) - 1;
int prev_top = r;
int prev_bottom = std::min(r + step, prev_rows - 1);
int prev_left = c;
int prev_right = std::min(c + step, prev_cols - 1);
for (int rr = prev_top; rr <= prev_bottom; ++rr) {
for (int cc = prev_left; cc <= prev_right; ++cc) {
done.at<uchar>(rr, cc) = 1;
if (!is_flow_regular.at<uchar>(rr, cc)) {
all_flow_in_region_regular = false;
}
}
}
int curr_top = std::min(2 * r, curr_rows - 1);
int curr_bottom = std::min(2*(r + step) + 1, curr_rows - 1);
int curr_left = std::min(2 * c, curr_cols - 1);
int curr_right = std::min(2*(c + step) + 1, curr_cols - 1);
if (all_flow_in_region_regular &&
curr_top != curr_bottom &&
curr_left != curr_right) {
mask.at<uchar>(curr_top, curr_left) = MASK_TRUE_VALUE;
mask.at<uchar>(curr_bottom, curr_left) = MASK_TRUE_VALUE;
mask.at<uchar>(curr_top, curr_right) = MASK_TRUE_VALUE;
mask.at<uchar>(curr_bottom, curr_right) = MASK_TRUE_VALUE;
for (int rr = curr_top; rr <= curr_bottom; ++rr) {
for (int cc = curr_left; cc <= curr_right; ++cc) {
speed_up.at<uchar>(rr, cc) = (uchar)(speed_up_at_this_point + 1);
}
}
} else {
for (int rr = curr_top; rr <= curr_bottom; ++rr) {
for (int cc = curr_left; cc <= curr_right; ++cc) {
mask.at<uchar>(rr, cc) = MASK_TRUE_VALUE;
}
}
}
} else {
done.at<uchar>(r, c) = 1;
for (int dr = 0; dr <= 1; ++dr) {
int nr = 2*r + dr;
for (int dc = 0; dc <= 1; ++dc) {
int nc = 2*c + dc;
if (nr < curr_rows && nc < curr_cols) {
mask.at<uchar>(nr, nc) = MASK_TRUE_VALUE;
}
}
}
}
}
}
}
}
static inline float extrapolateValueInRect(int height, int width,
float v11, float v12,
float v21, float v22,
int r, int c) {
if (r == 0 && c == 0) { return v11;}
if (r == 0 && c == width) { return v12;}
if (r == height && c == 0) { return v21;}
if (r == height && c == width) { return v22;}
CV_Assert(height > 0 && width > 0);
float qr = float(r) / height;
float pr = 1.0f - qr;
float qc = float(c) / width;
float pc = 1.0f - qc;
return v11*pr*pc + v12*pr*qc + v21*qr*pc + v22*qc*qr;
}
static void extrapolateFlow(Mat& flow,
const Mat& speed_up) {
const int rows = flow.rows;
const int cols = flow.cols;
Mat done = Mat::zeros(rows, cols, CV_8U);
for (int r = 0; r < rows; ++r) {
for (int c = 0; c < cols; ++c) {
if (!done.at<uchar>(r, c) && speed_up.at<uchar>(r, c) > 1) {
int step = (1 << speed_up.at<uchar>(r, c)) - 1;
int top = r;
int bottom = std::min(r + step, rows - 1);
int left = c;
int right = std::min(c + step, cols - 1);
int height = bottom - top;
int width = right - left;
for (int rr = top; rr <= bottom; ++rr) {
for (int cc = left; cc <= right; ++cc) {
done.at<uchar>(rr, cc) = 1;
Vec2f flow_at_point;
Vec2f top_left = flow.at<Vec2f>(top, left);
Vec2f top_right = flow.at<Vec2f>(top, right);
Vec2f bottom_left = flow.at<Vec2f>(bottom, left);
Vec2f bottom_right = flow.at<Vec2f>(bottom, right);
flow_at_point[0] = extrapolateValueInRect(height, width,
top_left[0], top_right[0],
bottom_left[0], bottom_right[0],
rr-top, cc-left);
flow_at_point[1] = extrapolateValueInRect(height, width,
top_left[1], top_right[1],
bottom_left[1], bottom_right[1],
rr-top, cc-left);
flow.at<Vec2f>(rr, cc) = flow_at_point;
}
}
}
}
}
}
static void buildPyramidWithResizeMethod(const Mat& src,
std::vector<Mat>& pyramid,
int layers,
int interpolation_type) {
pyramid.push_back(src);
for (int i = 1; i <= layers; ++i) {
Mat prev = pyramid[i - 1];
if (prev.rows <= 1 || prev.cols <= 1) {
break;
}
Mat next;
resize(prev, next, Size((prev.cols + 1) / 2, (prev.rows + 1) / 2), 0, 0, interpolation_type);
pyramid.push_back(next);
}
}
CV_EXPORTS_W void calcOpticalFlowSF(InputArray _from,
InputArray _to,
OutputArray _resulted_flow,
int layers,
int averaging_radius,
int max_flow,
double sigma_dist,
double sigma_color,
int postprocess_window,
double sigma_dist_fix,
double sigma_color_fix,
double occ_thr,
int upscale_averaging_radius,
double upscale_sigma_dist,
double upscale_sigma_color,
double speed_up_thr)
{
Mat from = _from.getMat();
Mat to = _to.getMat();
std::vector<Mat> pyr_from_images;
std::vector<Mat> pyr_to_images;
buildPyramidWithResizeMethod(from, pyr_from_images, layers - 1, INTER_CUBIC);
buildPyramidWithResizeMethod(to, pyr_to_images, layers - 1, INTER_CUBIC);
CV_Assert((int)pyr_from_images.size() == layers && (int)pyr_to_images.size() == layers);
Mat curr_from, curr_to, prev_from, prev_to;
Mat curr_from_extended, curr_to_extended;
curr_from = pyr_from_images[layers - 1];
curr_to = pyr_to_images[layers - 1];
copyMakeBorder(curr_from, curr_from_extended,
averaging_radius, averaging_radius, averaging_radius, averaging_radius,
BORDER_DEFAULT);
copyMakeBorder(curr_to, curr_to_extended,
averaging_radius, averaging_radius, averaging_radius, averaging_radius,
BORDER_DEFAULT);
Mat mask = Mat::ones(curr_from.size(), CV_8U);
Mat mask_inv = Mat::ones(curr_from.size(), CV_8U);
Mat flow = Mat::zeros(curr_from.size(), CV_32FC2);
Mat flow_inv = Mat::zeros(curr_to.size(), CV_32FC2);
Mat confidence;
Mat confidence_inv;
calcOpticalFlowSingleScaleSF(curr_from_extended,
curr_to_extended,
mask,
flow,
averaging_radius,
max_flow,
(float)sigma_dist,
(float)sigma_color);
calcOpticalFlowSingleScaleSF(curr_to_extended,
curr_from_extended,
mask_inv,
flow_inv,
averaging_radius,
max_flow,
(float)sigma_dist,
(float)sigma_color);
removeOcclusions(flow,
flow_inv,
(float)occ_thr,
confidence);
removeOcclusions(flow_inv,
flow,
(float)occ_thr,
confidence_inv);
Mat speed_up = Mat::zeros(curr_from.size(), CV_8U);
Mat speed_up_inv = Mat::zeros(curr_from.size(), CV_8U);
for (int curr_layer = layers - 2; curr_layer >= 0; --curr_layer) {
curr_from = pyr_from_images[curr_layer];
curr_to = pyr_to_images[curr_layer];
prev_from = pyr_from_images[curr_layer + 1];
prev_to = pyr_to_images[curr_layer + 1];
copyMakeBorder(curr_from, curr_from_extended,
averaging_radius, averaging_radius, averaging_radius, averaging_radius,
BORDER_DEFAULT);
copyMakeBorder(curr_to, curr_to_extended,
averaging_radius, averaging_radius, averaging_radius, averaging_radius,
BORDER_DEFAULT);
const int curr_rows = curr_from.rows;
const int curr_cols = curr_from.cols;
Mat new_speed_up, new_speed_up_inv;
selectPointsToRecalcFlow(flow,
averaging_radius,
(float)speed_up_thr,
curr_rows,
curr_cols,
speed_up,
new_speed_up,
mask);
selectPointsToRecalcFlow(flow_inv,
averaging_radius,
(float)speed_up_thr,
curr_rows,
curr_cols,
speed_up_inv,
new_speed_up_inv,
mask_inv);
speed_up = new_speed_up;
speed_up_inv = new_speed_up_inv;
flow = upscaleOpticalFlow(curr_rows,
curr_cols,
prev_from,
confidence,
flow,
upscale_averaging_radius,
(float)upscale_sigma_dist,
(float)upscale_sigma_color);
flow_inv = upscaleOpticalFlow(curr_rows,
curr_cols,
prev_to,
confidence_inv,
flow_inv,
upscale_averaging_radius,
(float)upscale_sigma_dist,
(float)upscale_sigma_color);
calcConfidence(curr_from, curr_to, flow, confidence, max_flow);
calcOpticalFlowSingleScaleSF(curr_from_extended,
curr_to_extended,
mask,
flow,
averaging_radius,
max_flow,
(float)sigma_dist,
(float)sigma_color);
calcConfidence(curr_to, curr_from, flow_inv, confidence_inv, max_flow);
calcOpticalFlowSingleScaleSF(curr_to_extended,
curr_from_extended,
mask_inv,
flow_inv,
averaging_radius,
max_flow,
(float)sigma_dist,
(float)sigma_color);
extrapolateFlow(flow, speed_up);
extrapolateFlow(flow_inv, speed_up_inv);
//TODO: should we remove occlusions for the last stage?
removeOcclusions(flow, flow_inv, (float)occ_thr, confidence);
removeOcclusions(flow_inv, flow, (float)occ_thr, confidence_inv);
}
crossBilateralFilter(flow, curr_from, confidence, flow,
postprocess_window, (float)sigma_color_fix, (float)sigma_dist_fix);
GaussianBlur(flow, flow, Size(3, 3), 5);
_resulted_flow.create(flow.size(), CV_32FC2);
Mat resulted_flow = _resulted_flow.getMat();
int from_to[] = {0,1 , 1,0};
mixChannels(&flow, 1, &resulted_flow, 1, from_to, 2);
}
CV_EXPORTS_W void calcOpticalFlowSF(InputArray from,
InputArray to,
OutputArray flow,
int layers,
int averaging_block_size,
int max_flow) {
calcOpticalFlowSF(from, to, flow, layers, averaging_block_size, max_flow,
4.1, 25.5, 18, 55.0, 25.5, 0.35, 18, 55.0, 25.5, 10);
}
}

View File

@ -1,67 +0,0 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
// Copyright (C) 2014, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#include "../test_precomp.hpp"
#include "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
namespace cvtest {
namespace ocl {
PARAM_TEST_CASE(UpdateMotionHistory, bool)
{
double timestamp, duration;
bool use_roi;
TEST_DECLARE_INPUT_PARAMETER(silhouette);
TEST_DECLARE_OUTPUT_PARAMETER(mhi);
virtual void SetUp()
{
use_roi = GET_PARAM(0);
}
virtual void generateTestData()
{
Size roiSize = randomSize(1, MAX_VALUE);
Border silhouetteBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(silhouette, silhouette_roi, roiSize, silhouetteBorder, CV_8UC1, -11, 11);
Border mhiBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(mhi, mhi_roi, roiSize, mhiBorder, CV_32FC1, 0, 1);
timestamp = randomDouble(0, 1);
duration = randomDouble(0, 1);
if (timestamp < duration)
std::swap(timestamp, duration);
UMAT_UPLOAD_INPUT_PARAMETER(silhouette);
UMAT_UPLOAD_OUTPUT_PARAMETER(mhi);
}
};
OCL_TEST_P(UpdateMotionHistory, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData();
OCL_OFF(cv::updateMotionHistory(silhouette_roi, mhi_roi, timestamp, duration));
OCL_ON(cv::updateMotionHistory(usilhouette_roi, umhi_roi, timestamp, duration));
OCL_EXPECT_MATS_NEAR(mhi, 0);
}
}
//////////////////////////////////////// Instantiation /////////////////////////////////////////
OCL_INSTANTIATE_TEST_CASE_P(Video, UpdateMotionHistory, Values(false, true));
} } // namespace cvtest::ocl
#endif // HAVE_OPENCL

View File

@ -1,137 +0,0 @@
/*
* BackgroundSubtractorGBH_test.cpp
*
* Created on: Jun 14, 2012
* Author: andrewgodbehere
*/
#include "test_precomp.hpp"
using namespace cv;
class CV_BackgroundSubtractorTest : public cvtest::BaseTest
{
public:
CV_BackgroundSubtractorTest();
protected:
void run(int);
};
CV_BackgroundSubtractorTest::CV_BackgroundSubtractorTest()
{
}
/**
* This test checks the following:
* (i) BackgroundSubtractorGMG can operate with matrices of various types and sizes
* (ii) Training mode returns empty fgmask
* (iii) End of training mode, and anomalous frame yields every pixel detected as FG
*/
void CV_BackgroundSubtractorTest::run(int)
{
int code = cvtest::TS::OK;
RNG& rng = ts->get_rng();
int type = ((unsigned int)rng)%7; //!< pick a random type, 0 - 6, defined in types_c.h
int channels = 1 + ((unsigned int)rng)%4; //!< random number of channels from 1 to 4.
int channelsAndType = CV_MAKETYPE(type,channels);
int width = 2 + ((unsigned int)rng)%98; //!< Mat will be 2 to 100 in width and height
int height = 2 + ((unsigned int)rng)%98;
Ptr<BackgroundSubtractorGMG> fgbg = createBackgroundSubtractorGMG();
Mat fgmask;
if (!fgbg)
CV_Error(Error::StsError,"Failed to create Algorithm\n");
/**
* Set a few parameters
*/
fgbg->setSmoothingRadius(7);
fgbg->setDecisionThreshold(0.7);
fgbg->setNumFrames(120);
/**
* Generate bounds for the values in the matrix for each type
*/
double maxd = 0, mind = 0;
/**
* Max value for simulated images picked randomly in upper half of type range
* Min value for simulated images picked randomly in lower half of type range
*/
if (type == CV_8U)
{
uchar half = UCHAR_MAX/2;
maxd = (unsigned char)rng.uniform(half+32, UCHAR_MAX);
mind = (unsigned char)rng.uniform(0, half-32);
}
else if (type == CV_8S)
{
maxd = (char)rng.uniform(32, CHAR_MAX);
mind = (char)rng.uniform(CHAR_MIN, -32);
}
else if (type == CV_16U)
{
ushort half = USHRT_MAX/2;
maxd = (unsigned int)rng.uniform(half+32, USHRT_MAX);
mind = (unsigned int)rng.uniform(0, half-32);
}
else if (type == CV_16S)
{
maxd = rng.uniform(32, SHRT_MAX);
mind = rng.uniform(SHRT_MIN, -32);
}
else if (type == CV_32S)
{
maxd = rng.uniform(32, INT_MAX);
mind = rng.uniform(INT_MIN, -32);
}
else if (type == CV_32F)
{
maxd = rng.uniform(32.0f, FLT_MAX);
mind = rng.uniform(-FLT_MAX, -32.0f);
}
else if (type == CV_64F)
{
maxd = rng.uniform(32.0, DBL_MAX);
mind = rng.uniform(-DBL_MAX, -32.0);
}
fgbg->setMinVal(mind);
fgbg->setMaxVal(maxd);
Mat simImage = Mat::zeros(height, width, channelsAndType);
int numLearningFrames = 120;
for (int i = 0; i < numLearningFrames; ++i)
{
/**
* Genrate simulated "image" for any type. Values always confined to upper half of range.
*/
rng.fill(simImage, RNG::UNIFORM, (mind + maxd)*0.5, maxd);
/**
* Feed simulated images into background subtractor
*/
fgbg->apply(simImage,fgmask);
Mat fullbg = Mat::zeros(simImage.rows, simImage.cols, CV_8U);
//! fgmask should be entirely background during training
code = cvtest::cmpEps2( ts, fgmask, fullbg, 0, false, "The training foreground mask" );
if (code < 0)
ts->set_failed_test_info( code );
}
//! generate last image, distinct from training images
rng.fill(simImage, RNG::UNIFORM, mind, maxd);
fgbg->apply(simImage,fgmask);
//! now fgmask should be entirely foreground
Mat fullfg = 255*Mat::ones(simImage.rows, simImage.cols, CV_8U);
code = cvtest::cmpEps2( ts, fgmask, fullfg, 255, false, "The final foreground mask" );
if (code < 0)
{
ts->set_failed_test_info( code );
}
}
TEST(VIDEO_BGSUBGMG, accuracy) { CV_BackgroundSubtractorTest test; test.safe_run(); }

View File

@ -1,500 +0,0 @@
/*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 MHI class ///////////////////////
class CV_MHIBaseTest : public cvtest::ArrayTest
{
public:
CV_MHIBaseTest();
protected:
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
int prepare_test_case( int test_case_idx );
double timestamp, duration, max_log_duration;
int mhi_i, mhi_ref_i;
double silh_ratio;
};
CV_MHIBaseTest::CV_MHIBaseTest()
{
timestamp = duration = 0;
max_log_duration = 9;
mhi_i = mhi_ref_i = -1;
silh_ratio = 0.25;
}
void CV_MHIBaseTest::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(cvRound(-1./silh_ratio)+2.);
high = Scalar::all(2);
}
else if( i == mhi_i || i == mhi_ref_i )
{
low = Scalar::all(-exp(max_log_duration));
high = Scalar::all(0.);
}
}
void CV_MHIBaseTest::get_test_array_types_and_sizes( int test_case_idx,
vector<vector<Size> >& sizes, vector<vector<int> >& 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[mhi_i][0] = types[mhi_ref_i][0] = CV_32FC1;
duration = exp(cvtest::randReal(rng)*max_log_duration);
timestamp = duration + cvtest::randReal(rng)*30.-10.;
}
int CV_MHIBaseTest::prepare_test_case( int test_case_idx )
{
int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
if( code > 0 )
{
Mat& mat = test_mat[mhi_i][0];
mat += Scalar::all(duration);
cv::max(mat, 0, mat);
if( mhi_i != mhi_ref_i )
{
Mat& mat0 = test_mat[mhi_ref_i][0];
cvtest::copy( mat, mat0 );
}
}
return code;
}
///////////////////// update motion history ////////////////////////////
static void test_updateMHI( const Mat& silh, Mat& mhi, double timestamp, double duration )
{
int i, j;
float delbound = (float)(timestamp - duration);
for( i = 0; i < mhi.rows; i++ )
{
const uchar* silh_row = silh.ptr(i);
float* mhi_row = mhi.ptr<float>(i);
for( j = 0; j < mhi.cols; j++ )
{
if( silh_row[j] )
mhi_row[j] = (float)timestamp;
else if( mhi_row[j] < delbound )
mhi_row[j] = 0.f;
}
}
}
class CV_UpdateMHITest : public CV_MHIBaseTest
{
public:
CV_UpdateMHITest();
protected:
double get_success_error_level( int test_case_idx, int i, int j );
void run_func();
void prepare_to_validation( int );
};
CV_UpdateMHITest::CV_UpdateMHITest()
{
test_array[INPUT].push_back(NULL);
test_array[INPUT_OUTPUT].push_back(NULL);
test_array[REF_INPUT_OUTPUT].push_back(NULL);
mhi_i = INPUT_OUTPUT; mhi_ref_i = REF_INPUT_OUTPUT;
}
double CV_UpdateMHITest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
{
return 0;
}
void CV_UpdateMHITest::run_func()
{
cv::updateMotionHistory( test_mat[INPUT][0], test_mat[INPUT_OUTPUT][0], timestamp, duration);
}
void CV_UpdateMHITest::prepare_to_validation( int /*test_case_idx*/ )
{
//CvMat m0 = test_mat[REF_INPUT_OUTPUT][0];
test_updateMHI( test_mat[INPUT][0], test_mat[REF_INPUT_OUTPUT][0], timestamp, duration );
}
///////////////////// calc motion gradient ////////////////////////////
static void test_MHIGradient( const Mat& mhi, Mat& mask, Mat& orientation,
double delta1, double delta2, int aperture_size )
{
Point anchor( aperture_size/2, aperture_size/2 );
double limit = 1e-4*aperture_size*aperture_size;
Mat dx, dy, min_mhi, max_mhi;
Mat kernel = cvtest::calcSobelKernel2D( 1, 0, aperture_size );
cvtest::filter2D( mhi, dx, CV_32F, kernel, anchor, 0, BORDER_REPLICATE );
kernel = cvtest::calcSobelKernel2D( 0, 1, aperture_size );
cvtest::filter2D( mhi, dy, CV_32F, kernel, anchor, 0, BORDER_REPLICATE );
kernel = Mat::ones(aperture_size, aperture_size, CV_8U);
cvtest::erode(mhi, min_mhi, kernel, anchor, 0, BORDER_REPLICATE);
cvtest::dilate(mhi, max_mhi, kernel, anchor, 0, BORDER_REPLICATE);
if( delta1 > delta2 )
{
std::swap( delta1, delta2 );
}
for( int i = 0; i < mhi.rows; i++ )
{
uchar* mask_row = mask.ptr(i);
float* orient_row = orientation.ptr<float>(i);
const float* dx_row = dx.ptr<float>(i);
const float* dy_row = dy.ptr<float>(i);
const float* min_row = min_mhi.ptr<float>(i);
const float* max_row = max_mhi.ptr<float>(i);
for( int j = 0; j < mhi.cols; j++ )
{
double delta = max_row[j] - min_row[j];
double _dx = dx_row[j], _dy = dy_row[j];
if( delta1 <= delta && delta <= delta2 &&
(fabs(_dx) > limit || fabs(_dy) > limit) )
{
mask_row[j] = 1;
double angle = atan2( _dy, _dx ) * (180/CV_PI);
if( angle < 0 )
angle += 360.;
orient_row[j] = (float)angle;
}
else
{
mask_row[j] = 0;
orient_row[j] = 0.f;
}
}
}
}
class CV_MHIGradientTest : public CV_MHIBaseTest
{
public:
CV_MHIGradientTest();
protected:
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
double get_success_error_level( int test_case_idx, int i, int j );
void run_func();
void prepare_to_validation( int );
double delta1, delta2, delta_range_log;
int aperture_size;
};
CV_MHIGradientTest::CV_MHIGradientTest()
{
mhi_i = mhi_ref_i = INPUT;
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);
delta1 = delta2 = 0;
aperture_size = 0;
delta_range_log = 4;
}
void CV_MHIGradientTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
{
RNG& rng = ts->get_rng();
CV_MHIBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_8UC1;
types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_32FC1;
delta1 = exp(cvtest::randReal(rng)*delta_range_log + 1.);
delta2 = exp(cvtest::randReal(rng)*delta_range_log + 1.);
aperture_size = (cvtest::randInt(rng)%3)*2+3;
//duration = exp(cvtest::randReal(rng)*max_log_duration);
//timestamp = duration + cvtest::randReal(rng)*30.-10.;
}
double CV_MHIGradientTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int j )
{
return j == 0 ? 0 : 2e-1;
}
void CV_MHIGradientTest::run_func()
{
cv::calcMotionGradient(test_mat[INPUT][0], test_mat[OUTPUT][0],
test_mat[OUTPUT][1], delta1, delta2, aperture_size );
//cvCalcMotionGradient( test_array[INPUT][0], test_array[OUTPUT][0],
// test_array[OUTPUT][1], delta1, delta2, aperture_size );
}
void CV_MHIGradientTest::prepare_to_validation( int /*test_case_idx*/ )
{
test_MHIGradient( test_mat[INPUT][0], test_mat[REF_OUTPUT][0],
test_mat[REF_OUTPUT][1], delta1, delta2, aperture_size );
test_mat[REF_OUTPUT][0] += Scalar::all(1);
test_mat[OUTPUT][0] += Scalar::all(1);
}
////////////////////// calc global orientation /////////////////////////
static double test_calcGlobalOrientation( const Mat& orient, const Mat& mask,
const Mat& mhi, double timestamp, double duration )
{
const int HIST_SIZE = 12;
int y, x;
int histogram[HIST_SIZE];
int max_bin = 0;
double base_orientation = 0, delta_orientation = 0, weight = 0;
double low_time, global_orientation;
memset( histogram, 0, sizeof( histogram ));
timestamp = 0;
for( y = 0; y < orient.rows; y++ )
{
const float* orient_data = orient.ptr<float>(y);
const uchar* mask_data = mask.ptr(y);
const float* mhi_data = mhi.ptr<float>(y);
for( x = 0; x < orient.cols; x++ )
if( mask_data[x] )
{
int bin = cvFloor( (orient_data[x]*HIST_SIZE)/360 );
histogram[bin < 0 ? 0 : bin >= HIST_SIZE ? HIST_SIZE-1 : bin]++;
if( mhi_data[x] > timestamp )
timestamp = mhi_data[x];
}
}
low_time = timestamp - duration;
for( x = 1; x < HIST_SIZE; x++ )
{
if( histogram[x] > histogram[max_bin] )
max_bin = x;
}
base_orientation = ((double)max_bin*360)/HIST_SIZE;
for( y = 0; y < orient.rows; y++ )
{
const float* orient_data = orient.ptr<float>(y);
const float* mhi_data = mhi.ptr<float>(y);
const uchar* mask_data = mask.ptr(y);
for( x = 0; x < orient.cols; x++ )
{
if( mask_data[x] && mhi_data[x] > low_time )
{
double diff = orient_data[x] - base_orientation;
double delta_weight = (((mhi_data[x] - low_time)/duration)*254 + 1)/255;
if( diff < -180 ) diff += 360;
if( diff > 180 ) diff -= 360;
if( delta_weight > 0 && fabs(diff) < 45 )
{
delta_orientation += diff*delta_weight;
weight += delta_weight;
}
}
}
}
if( weight == 0 )
global_orientation = base_orientation;
else
{
global_orientation = base_orientation + delta_orientation/weight;
if( global_orientation < 0 ) global_orientation += 360;
if( global_orientation > 360 ) global_orientation -= 360;
}
return global_orientation;
}
class CV_MHIGlobalOrientTest : public CV_MHIBaseTest
{
public:
CV_MHIGlobalOrientTest();
protected:
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& 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 validate_test_results( int test_case_idx );
void run_func();
double angle, min_angle, max_angle;
};
CV_MHIGlobalOrientTest::CV_MHIGlobalOrientTest()
{
mhi_i = mhi_ref_i = INPUT;
test_array[INPUT].push_back(NULL);
test_array[INPUT].push_back(NULL);
test_array[INPUT].push_back(NULL);
min_angle = max_angle = 0;
}
void CV_MHIGlobalOrientTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
{
RNG& rng = ts->get_rng();
CV_MHIBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
Size size = sizes[INPUT][0];
size.width = MAX( size.width, 16 );
size.height = MAX( size.height, 16 );
sizes[INPUT][0] = sizes[INPUT][1] = sizes[INPUT][2] = size;
types[INPUT][1] = CV_8UC1; // mask
types[INPUT][2] = CV_32FC1; // orientation
min_angle = cvtest::randReal(rng)*359.9;
max_angle = cvtest::randReal(rng)*359.9;
if( min_angle >= max_angle )
{
std::swap( min_angle, max_angle);
}
max_angle += 0.1;
duration = exp(cvtest::randReal(rng)*max_log_duration);
timestamp = duration + cvtest::randReal(rng)*30.-10.;
}
void CV_MHIGlobalOrientTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
{
CV_MHIBaseTest::get_minmax_bounds( i, j, type, low, high );
if( i == INPUT && j == 2 )
{
low = Scalar::all(min_angle);
high = Scalar::all(max_angle);
}
}
double CV_MHIGlobalOrientTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
{
return 15;
}
void CV_MHIGlobalOrientTest::run_func()
{
//angle = cvCalcGlobalOrientation( test_array[INPUT][2], test_array[INPUT][1],
// test_array[INPUT][0], timestamp, duration );
angle = cv::calcGlobalOrientation(test_mat[INPUT][2], test_mat[INPUT][1],
test_mat[INPUT][0], timestamp, duration );
}
int CV_MHIGlobalOrientTest::validate_test_results( int test_case_idx )
{
//printf("%d. rows=%d, cols=%d, nzmask=%d\n", test_case_idx, test_mat[INPUT][1].rows, test_mat[INPUT][1].cols,
// cvCountNonZero(test_array[INPUT][1]));
double ref_angle = test_calcGlobalOrientation( test_mat[INPUT][2], test_mat[INPUT][1],
test_mat[INPUT][0], timestamp, duration );
double err_level = get_success_error_level( test_case_idx, 0, 0 );
int code = cvtest::TS::OK;
int nz = countNonZero( test_mat[INPUT][1] );
if( nz > 32 && !(min_angle - err_level <= angle &&
max_angle + err_level >= angle) &&
!(min_angle - err_level <= angle+360 &&
max_angle + err_level >= angle+360) )
{
ts->printf( cvtest::TS::LOG, "The angle=%g is outside (%g,%g) range\n",
angle, min_angle - err_level, max_angle + err_level );
code = cvtest::TS::FAIL_BAD_ACCURACY;
}
else if( fabs(angle - ref_angle) > err_level &&
fabs(360 - fabs(angle - ref_angle)) > err_level )
{
ts->printf( cvtest::TS::LOG, "The angle=%g differs too much from reference value=%g\n",
angle, ref_angle );
code = cvtest::TS::FAIL_BAD_ACCURACY;
}
if( code < 0 )
ts->set_failed_test_info( code );
return code;
}
TEST(Video_MHIUpdate, accuracy) { CV_UpdateMHITest test; test.safe_run(); }
TEST(Video_MHIGradient, accuracy) { CV_MHIGradientTest test; test.safe_run(); }
TEST(Video_MHIGlobalOrient, accuracy) { CV_MHIGlobalOrientTest test; test.safe_run(); }

View File

@ -1,190 +0,0 @@
/*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 <string>
using namespace std;
/* ///////////////////// simpleflow_test ///////////////////////// */
class CV_SimpleFlowTest : public cvtest::BaseTest
{
public:
CV_SimpleFlowTest();
protected:
void run(int);
};
CV_SimpleFlowTest::CV_SimpleFlowTest() {}
static bool readOpticalFlowFromFile(FILE* file, cv::Mat& flow) {
char header[5];
if (fread(header, 1, 4, file) < 4 && (string)header != "PIEH") {
return false;
}
int cols, rows;
if (fread(&cols, sizeof(int), 1, file) != 1||
fread(&rows, sizeof(int), 1, file) != 1) {
return false;
}
flow = cv::Mat::zeros(rows, cols, CV_32FC2);
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
cv::Vec2f flow_at_point;
if (fread(&(flow_at_point[0]), sizeof(float), 1, file) != 1 ||
fread(&(flow_at_point[1]), sizeof(float), 1, file) != 1) {
return false;
}
flow.at<cv::Vec2f>(i, j) = flow_at_point;
}
}
return true;
}
static bool isFlowCorrect(float u) {
return !cvIsNaN(u) && (fabs(u) < 1e9);
}
static float calc_rmse(cv::Mat flow1, cv::Mat flow2) {
float sum = 0;
int counter = 0;
const int rows = flow1.rows;
const int cols = flow1.cols;
for (int y = 0; y < rows; ++y) {
for (int x = 0; x < cols; ++x) {
cv::Vec2f flow1_at_point = flow1.at<cv::Vec2f>(y, x);
cv::Vec2f flow2_at_point = flow2.at<cv::Vec2f>(y, x);
float u1 = flow1_at_point[0];
float v1 = flow1_at_point[1];
float u2 = flow2_at_point[0];
float v2 = flow2_at_point[1];
if (isFlowCorrect(u1) && isFlowCorrect(u2) && isFlowCorrect(v1) && isFlowCorrect(v2)) {
sum += (u1-u2)*(u1-u2) + (v1-v2)*(v1-v2);
counter++;
}
}
}
return (float)sqrt(sum / (1e-9 + counter));
}
void CV_SimpleFlowTest::run(int) {
const float MAX_RMSE = 0.6f;
const string frame1_path = ts->get_data_path() + "optflow/RubberWhale1.png";
const string frame2_path = ts->get_data_path() + "optflow/RubberWhale2.png";
const string gt_flow_path = ts->get_data_path() + "optflow/RubberWhale.flo";
cv::Mat frame1 = cv::imread(frame1_path);
cv::Mat frame2 = cv::imread(frame2_path);
if (frame1.empty()) {
ts->printf(cvtest::TS::LOG, "could not read image %s\n", frame2_path.c_str());
ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
return;
}
if (frame2.empty()) {
ts->printf(cvtest::TS::LOG, "could not read image %s\n", frame2_path.c_str());
ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
return;
}
if (frame1.rows != frame2.rows && frame1.cols != frame2.cols) {
ts->printf(cvtest::TS::LOG, "images should be of equal sizes (%s and %s)",
frame1_path.c_str(), frame2_path.c_str());
ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
return;
}
if (frame1.type() != 16 || frame2.type() != 16) {
ts->printf(cvtest::TS::LOG, "images should be of equal type CV_8UC3 (%s and %s)",
frame1_path.c_str(), frame2_path.c_str());
ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
return;
}
cv::Mat flow_gt;
FILE* gt_flow_file = fopen(gt_flow_path.c_str(), "rb");
if (gt_flow_file == NULL) {
ts->printf(cvtest::TS::LOG, "could not read ground-thuth flow from file %s",
gt_flow_path.c_str());
ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
return;
}
if (!readOpticalFlowFromFile(gt_flow_file, flow_gt)) {
ts->printf(cvtest::TS::LOG, "error while reading flow data from file %s",
gt_flow_path.c_str());
ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
return;
}
fclose(gt_flow_file);
cv::Mat flow;
cv::calcOpticalFlowSF(frame1, frame2, flow, 3, 2, 4);
float rmse = calc_rmse(flow_gt, flow);
ts->printf(cvtest::TS::LOG, "Optical flow estimation RMSE for SimpleFlow algorithm : %lf\n",
rmse);
if (rmse > MAX_RMSE) {
ts->printf( cvtest::TS::LOG,
"Too big rmse error : %lf ( >= %lf )\n", rmse, MAX_RMSE);
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
return;
}
}
TEST(Video_OpticalFlowSimpleFlow, accuracy) { CV_SimpleFlowTest test; test.safe_run(); }
/* End of file. */

View File

@ -1,81 +0,0 @@
/*
* FGBGTest.cpp
*
* Created on: May 7, 2012
* Author: Andrew B. Godbehere
*/
#include "opencv2/video.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include <opencv2/core/utility.hpp>
#include <iostream>
using namespace cv;
static void help()
{
std::cout <<
"\nA program demonstrating the use and capabilities of a particular BackgroundSubtraction\n"
"algorithm described in A. Godbehere, A. Matsukawa, K. Goldberg, \n"
"\"Visual Tracking of Human Visitors under Variable-Lighting Conditions for a Responsive\n"
"Audio Art Installation\", American Control Conference, 2012, used in an interactive\n"
"installation at the Contemporary Jewish Museum in San Francisco, CA from March 31 through\n"
"July 31, 2011.\n"
"Call:\n"
"./BackgroundSubtractorGMG_sample\n"
"Using OpenCV version " << CV_VERSION << "\n"<<std::endl;
}
int main(int argc, char** argv)
{
help();
initModule_video();
setUseOptimized(true);
setNumThreads(8);
Ptr<BackgroundSubtractor> fgbg = createBackgroundSubtractorGMG(20, 0.7);
if (!fgbg)
{
std::cerr << "Failed to create BackgroundSubtractor.GMG Algorithm." << std::endl;
return -1;
}
VideoCapture cap;
if (argc > 1)
cap.open(argv[1]);
else
cap.open(0);
if (!cap.isOpened())
{
std::cerr << "Cannot read video. Try moving video file to sample directory." << std::endl;
return -1;
}
Mat frame, fgmask, segm;
namedWindow("FG Segmentation", WINDOW_NORMAL);
for (;;)
{
cap >> frame;
if (frame.empty())
break;
fgbg->apply(frame, fgmask);
frame.convertTo(segm, CV_8U, 0.5);
add(frame, Scalar(100, 100, 0), segm, fgmask);
imshow("FG Segmentation", segm);
int c = waitKey(30);
if (c == 'q' || c == 'Q' || (c & 255) == 27)
break;
}
return 0;
}

View File

@ -21,6 +21,8 @@ static void help()
const char* keys =
{
"{c camera | | use camera or not}"
"{m method |mog2 | method (knn or mog2) }"
"{s smooth | | smooth the mask }"
"{fn file_name|tree.avi | movie file }"
};
@ -31,7 +33,9 @@ int main(int argc, const char** argv)
CommandLineParser parser(argc, argv, keys);
bool useCamera = parser.has("camera");
bool smoothMask = parser.has("smooth");
string file = parser.get<string>("file_name");
string method = parser.get<string>("method");
VideoCapture cap;
bool update_bg_model = true;
@ -53,24 +57,31 @@ int main(int argc, const char** argv)
namedWindow("foreground image", WINDOW_NORMAL);
namedWindow("mean background image", WINDOW_NORMAL);
Ptr<BackgroundSubtractor> bg_model = createBackgroundSubtractorMOG2();
Ptr<BackgroundSubtractor> bg_model = method == "knn" ?
createBackgroundSubtractorKNN().dynamicCast<BackgroundSubtractor>() :
createBackgroundSubtractorMOG2().dynamicCast<BackgroundSubtractor>();
Mat img, fgmask, fgimg;
Mat img0, img, fgmask, fgimg;
for(;;)
{
cap >> img;
cap >> img0;
if( img.empty() )
if( img0.empty() )
break;
//cvtColor(_img, img, COLOR_BGR2GRAY);
resize(img0, img, Size(640, 640*img0.rows/img0.cols), INTER_LINEAR);
if( fgimg.empty() )
fgimg.create(img.size(), img.type());
//update the model
bg_model->apply(img, fgmask, update_bg_model ? -1 : 0);
if( smoothMask )
{
GaussianBlur(fgmask, fgmask, Size(11, 11), 3.5, 3.5);
threshold(fgmask, fgmask, 10, 255, THRESH_BINARY);
}
fgimg = Scalar::all(0);
img.copyTo(fgimg, fgmask);

View File

@ -1,204 +0,0 @@
#include "opencv2/video/tracking_c.h"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/videoio/videoio_c.h"
#include "opencv2/highgui/highgui_c.h"
#include <time.h>
#include <stdio.h>
#include <ctype.h>
static void help(void)
{
printf(
"\nThis program demonstrated the use of motion templates -- basically using the gradients\n"
"of thresholded layers of decaying frame differencing. New movements are stamped on top with floating system\n"
"time code and motions too old are thresholded away. This is the 'motion history file'. The program reads from the camera of your choice or from\n"
"a file. Gradients of motion history are used to detect direction of motoin etc\n"
"Usage :\n"
"./motempl [camera number 0-n or file name, default is camera 0]\n"
);
}
// various tracking parameters (in seconds)
const double MHI_DURATION = 1;
const double MAX_TIME_DELTA = 0.5;
const double MIN_TIME_DELTA = 0.05;
// number of cyclic frame buffer used for motion detection
// (should, probably, depend on FPS)
const int N = 4;
// ring image buffer
IplImage **buf = 0;
int last = 0;
// temporary images
IplImage *mhi = 0; // MHI
IplImage *orient = 0; // orientation
IplImage *mask = 0; // valid orientation mask
IplImage *segmask = 0; // motion segmentation map
CvMemStorage* storage = 0; // temporary storage
// parameters:
// img - input video frame
// dst - resultant motion picture
// args - optional parameters
static void update_mhi( IplImage* img, IplImage* dst, int diff_threshold )
{
double timestamp = (double)clock()/CLOCKS_PER_SEC; // get current time in seconds
CvSize size = cvSize(img->width,img->height); // get current frame size
int i, idx1 = last, idx2;
IplImage* silh;
CvSeq* seq;
CvRect comp_rect;
double count;
double angle;
CvPoint center;
double magnitude;
CvScalar color;
// allocate images at the beginning or
// reallocate them if the frame size is changed
if( !mhi || mhi->width != size.width || mhi->height != size.height ) {
if( buf == 0 ) {
buf = (IplImage**)malloc(N*sizeof(buf[0]));
memset( buf, 0, N*sizeof(buf[0]));
}
for( i = 0; i < N; i++ ) {
cvReleaseImage( &buf[i] );
buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 );
cvZero( buf[i] );
}
cvReleaseImage( &mhi );
cvReleaseImage( &orient );
cvReleaseImage( &segmask );
cvReleaseImage( &mask );
mhi = cvCreateImage( size, IPL_DEPTH_32F, 1 );
cvZero( mhi ); // clear MHI at the beginning
orient = cvCreateImage( size, IPL_DEPTH_32F, 1 );
segmask = cvCreateImage( size, IPL_DEPTH_32F, 1 );
mask = cvCreateImage( size, IPL_DEPTH_8U, 1 );
}
cvCvtColor( img, buf[last], CV_BGR2GRAY ); // convert frame to grayscale
idx2 = (last + 1) % N; // index of (last - (N-1))th frame
last = idx2;
silh = buf[idx2];
cvAbsDiff( buf[idx1], buf[idx2], silh ); // get difference between frames
cvThreshold( silh, silh, diff_threshold, 1, CV_THRESH_BINARY ); // and threshold it
cvUpdateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // update MHI
// convert MHI to blue 8u image
cvCvtScale( mhi, mask, 255./MHI_DURATION,
(MHI_DURATION - timestamp)*255./MHI_DURATION );
cvZero( dst );
cvMerge( mask, 0, 0, 0, dst );
// calculate motion gradient orientation and valid orientation mask
cvCalcMotionGradient( mhi, mask, orient, MAX_TIME_DELTA, MIN_TIME_DELTA, 3 );
if( !storage )
storage = cvCreateMemStorage(0);
else
cvClearMemStorage(storage);
// segment motion: get sequence of motion components
// segmask is marked motion components map. It is not used further
seq = cvSegmentMotion( mhi, segmask, storage, timestamp, MAX_TIME_DELTA );
// iterate through the motion components,
// One more iteration (i == -1) corresponds to the whole image (global motion)
for( i = -1; i < seq->total; i++ ) {
if( i < 0 ) { // case of the whole image
comp_rect = cvRect( 0, 0, size.width, size.height );
color = CV_RGB(255,255,255);
magnitude = 100;
}
else { // i-th motion component
comp_rect = ((CvConnectedComp*)cvGetSeqElem( seq, i ))->rect;
if( comp_rect.width + comp_rect.height < 100 ) // reject very small components
continue;
color = CV_RGB(255,0,0);
magnitude = 30;
}
// select component ROI
cvSetImageROI( silh, comp_rect );
cvSetImageROI( mhi, comp_rect );
cvSetImageROI( orient, comp_rect );
cvSetImageROI( mask, comp_rect );
// calculate orientation
angle = cvCalcGlobalOrientation( orient, mask, mhi, timestamp, MHI_DURATION);
angle = 360.0 - angle; // adjust for images with top-left origin
count = cvNorm( silh, 0, CV_L1, 0 ); // calculate number of points within silhouette ROI
cvResetImageROI( mhi );
cvResetImageROI( orient );
cvResetImageROI( mask );
cvResetImageROI( silh );
// check for the case of little motion
if( count < comp_rect.width*comp_rect.height * 0.05 )
continue;
// draw a clock with arrow indicating the direction
center = cvPoint( (comp_rect.x + comp_rect.width/2),
(comp_rect.y + comp_rect.height/2) );
cvCircle( dst, center, cvRound(magnitude*1.2), color, 3, CV_AA, 0 );
cvLine( dst, center, cvPoint( cvRound( center.x + magnitude*cos(angle*CV_PI/180)),
cvRound( center.y - magnitude*sin(angle*CV_PI/180))), color, 3, CV_AA, 0 );
}
}
int main(int argc, char** argv)
{
IplImage* motion = 0;
CvCapture* capture = 0;
help();
if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );
else if( argc == 2 )
capture = cvCaptureFromFile( argv[1] );
if( capture )
{
cvNamedWindow( "Motion", 1 );
for(;;)
{
IplImage* image = cvQueryFrame( capture );
if( !image )
break;
if( !motion )
{
motion = cvCreateImage( cvSize(image->width,image->height), 8, 3 );
cvZero( motion );
motion->origin = image->origin;
}
update_mhi( image, motion, 30 );
cvShowImage( "Motion", motion );
if( cvWaitKey(10) >= 0 )
break;
}
cvReleaseCapture( &capture );
cvDestroyWindow( "Motion" );
}
return 0;
}
#ifdef _EiC
main(1,"motempl.c");
#endif

View File

@ -88,8 +88,8 @@ int main(int argc, char** argv)
namedWindow("video", 1);
namedWindow("segmented", 1);
Ptr<BackgroundSubtractorMOG> bgsubtractor=createBackgroundSubtractorMOG();
bgsubtractor->setNoiseSigma(10);
Ptr<BackgroundSubtractorMOG2> bgsubtractor=createBackgroundSubtractorMOG2();
bgsubtractor->setVarThreshold(10);
for(;;)
{

View File

@ -1,221 +0,0 @@
#include <opencv2/core/utility.hpp>
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <cstdio>
#include <iostream>
using namespace cv;
using namespace std;
#define APP_NAME "simpleflow_demo : "
static void help()
{
// print a welcome message, and the OpenCV version
printf("This is a demo of SimpleFlow optical flow algorithm,\n"
"Using OpenCV version %s\n\n", CV_VERSION);
printf("Usage: simpleflow_demo frame1 frame2 output_flow"
"\nApplication will write estimated flow "
"\nbetween 'frame1' and 'frame2' in binary format"
"\ninto file 'output_flow'"
"\nThen one can use code from http://vision.middlebury.edu/flow/data/"
"\nto convert flow in binary file to image\n");
}
// binary file format for flow data specified here:
// http://vision.middlebury.edu/flow/data/
static void writeOpticalFlowToFile(const Mat& flow, FILE* file) {
int cols = flow.cols;
int rows = flow.rows;
fprintf(file, "PIEH");
if (fwrite(&cols, sizeof(int), 1, file) != 1 ||
fwrite(&rows, sizeof(int), 1, file) != 1) {
printf(APP_NAME "writeOpticalFlowToFile : problem writing header\n");
exit(1);
}
for (int i= 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
Vec2f flow_at_point = flow.at<Vec2f>(i, j);
if (fwrite(&(flow_at_point[0]), sizeof(float), 1, file) != 1 ||
fwrite(&(flow_at_point[1]), sizeof(float), 1, file) != 1) {
printf(APP_NAME "writeOpticalFlowToFile : problem writing data\n");
exit(1);
}
}
}
}
static void run(int argc, char** argv) {
if (argc < 3) {
printf(APP_NAME "Wrong number of command line arguments for mode `run`: %d (expected %d)\n",
argc, 3);
exit(1);
}
Mat frame1 = imread(argv[0]);
Mat frame2 = imread(argv[1]);
if (frame1.empty()) {
printf(APP_NAME "Image #1 : %s cannot be read\n", argv[0]);
exit(1);
}
if (frame2.empty()) {
printf(APP_NAME "Image #2 : %s cannot be read\n", argv[1]);
exit(1);
}
if (frame1.rows != frame2.rows && frame1.cols != frame2.cols) {
printf(APP_NAME "Images should be of equal sizes\n");
exit(1);
}
if (frame1.type() != 16 || frame2.type() != 16) {
printf(APP_NAME "Images should be of equal type CV_8UC3\n");
exit(1);
}
printf(APP_NAME "Read two images of size [rows = %d, cols = %d]\n",
frame1.rows, frame1.cols);
Mat flow;
float start = (float)getTickCount();
calcOpticalFlowSF(frame1, frame2,
flow,
3, 2, 4, 4.1, 25.5, 18, 55.0, 25.5, 0.35, 18, 55.0, 25.5, 10);
printf(APP_NAME "calcOpticalFlowSF : %lf sec\n", (getTickCount() - start) / getTickFrequency());
FILE* file = fopen(argv[2], "wb");
if (file == NULL) {
printf(APP_NAME "Unable to open file '%s' for writing\n", argv[2]);
exit(1);
}
printf(APP_NAME "Writing to file\n");
writeOpticalFlowToFile(flow, file);
fclose(file);
}
static bool readOpticalFlowFromFile(FILE* file, Mat& flow) {
char header[5];
if (fread(header, 1, 4, file) < 4 && (string)header != "PIEH") {
return false;
}
int cols, rows;
if (fread(&cols, sizeof(int), 1, file) != 1||
fread(&rows, sizeof(int), 1, file) != 1) {
return false;
}
flow = Mat::zeros(rows, cols, CV_32FC2);
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
Vec2f flow_at_point;
if (fread(&(flow_at_point[0]), sizeof(float), 1, file) != 1 ||
fread(&(flow_at_point[1]), sizeof(float), 1, file) != 1) {
return false;
}
flow.at<Vec2f>(i, j) = flow_at_point;
}
}
return true;
}
static bool isFlowCorrect(float u) {
return !cvIsNaN(u) && (fabs(u) < 1e9);
}
static float calc_rmse(Mat flow1, Mat flow2) {
float sum = 0;
int counter = 0;
const int rows = flow1.rows;
const int cols = flow1.cols;
for (int y = 0; y < rows; ++y) {
for (int x = 0; x < cols; ++x) {
Vec2f flow1_at_point = flow1.at<Vec2f>(y, x);
Vec2f flow2_at_point = flow2.at<Vec2f>(y, x);
float u1 = flow1_at_point[0];
float v1 = flow1_at_point[1];
float u2 = flow2_at_point[0];
float v2 = flow2_at_point[1];
if (isFlowCorrect(u1) && isFlowCorrect(u2) && isFlowCorrect(v1) && isFlowCorrect(v2)) {
sum += (u1-u2)*(u1-u2) + (v1-v2)*(v1-v2);
counter++;
}
}
}
return (float)sqrt(sum / (1e-9 + counter));
}
static void eval(int argc, char** argv) {
if (argc < 2) {
printf(APP_NAME "Wrong number of command line arguments for mode `eval` : %d (expected %d)\n",
argc, 2);
exit(1);
}
Mat flow1, flow2;
FILE* flow_file_1 = fopen(argv[0], "rb");
if (flow_file_1 == NULL) {
printf(APP_NAME "Cannot open file with first flow : %s\n", argv[0]);
exit(1);
}
if (!readOpticalFlowFromFile(flow_file_1, flow1)) {
printf(APP_NAME "Cannot read flow data from file %s\n", argv[0]);
exit(1);
}
fclose(flow_file_1);
FILE* flow_file_2 = fopen(argv[1], "rb");
if (flow_file_2 == NULL) {
printf(APP_NAME "Cannot open file with first flow : %s\n", argv[1]);
exit(1);
}
if (!readOpticalFlowFromFile(flow_file_2, flow2)) {
printf(APP_NAME "Cannot read flow data from file %s\n", argv[1]);
exit(1);
}
fclose(flow_file_2);
float rmse = calc_rmse(flow1, flow2);
printf("%lf\n", rmse);
}
int main(int argc, char** argv) {
if (argc < 2) {
printf(APP_NAME "Mode is not specified\n");
help();
exit(1);
}
string mode = (string)argv[1];
int new_argc = argc - 2;
char** new_argv = &argv[2];
if ("run" == mode) {
run(new_argc, new_argv);
} else if ("eval" == mode) {
eval(new_argc, new_argv);
} else if ("help" == mode)
help();
else {
printf(APP_NAME "Unknown mode : %s\n", argv[1]);
help();
}
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -20,9 +20,7 @@ using namespace std;
// Global variables
Mat frame; //current frame
Mat fgMaskMOG; //fg mask generated by MOG method
Mat fgMaskMOG2; //fg mask fg mask generated by MOG2 method
Ptr<BackgroundSubtractor> pMOG; //MOG Background subtractor
Ptr<BackgroundSubtractor> pMOG2; //MOG2 Background subtractor
int keyboard; //input from keyboard
@ -63,11 +61,9 @@ int main(int argc, char* argv[])
//create GUI windows
namedWindow("Frame");
namedWindow("FG Mask MOG");
namedWindow("FG Mask MOG 2");
//create Background Subtractor objects
pMOG = createBackgroundSubtractorMOG(); //MOG approach
pMOG2 = createBackgroundSubtractorMOG2(); //MOG2 approach
if(strcmp(argv[1], "-vid") == 0) {
@ -109,7 +105,6 @@ void processVideo(char* videoFilename) {
exit(EXIT_FAILURE);
}
//update the background model
pMOG->apply(frame, fgMaskMOG);
pMOG2->apply(frame, fgMaskMOG2);
//get the frame number and write it on the current frame
stringstream ss;
@ -121,7 +116,6 @@ void processVideo(char* videoFilename) {
FONT_HERSHEY_SIMPLEX, 0.5 , cv::Scalar(0,0,0));
//show the current frame and the fg masks
imshow("Frame", frame);
imshow("FG Mask MOG", fgMaskMOG);
imshow("FG Mask MOG 2", fgMaskMOG2);
//get the input from the keyboard
keyboard = waitKey( 30 );
@ -146,7 +140,6 @@ void processImages(char* fistFrameFilename) {
//read input data. ESC or 'q' for quitting
while( (char)keyboard != 'q' && (char)keyboard != 27 ){
//update the background model
pMOG->apply(frame, fgMaskMOG);
pMOG2->apply(frame, fgMaskMOG2);
//get the frame number and write it on the current frame
size_t index = fn.find_last_of("/");
@ -166,7 +159,6 @@ void processImages(char* fistFrameFilename) {
FONT_HERSHEY_SIMPLEX, 0.5 , cv::Scalar(0,0,0));
//show the current frame and the fg masks
imshow("Frame", frame);
imshow("FG Mask MOG", fgMaskMOG);
imshow("FG Mask MOG 2", fgMaskMOG2);
//get the input from the keyboard
keyboard = waitKey( 30 );

View File

@ -1,85 +0,0 @@
#!/usr/bin/env python
import numpy as np
import cv2
import video
from common import nothing, clock, draw_str
MHI_DURATION = 0.5
DEFAULT_THRESHOLD = 32
MAX_TIME_DELTA = 0.25
MIN_TIME_DELTA = 0.05
def draw_motion_comp(vis, (x, y, w, h), angle, color):
cv2.rectangle(vis, (x, y), (x+w, y+h), (0, 255, 0))
r = min(w/2, h/2)
cx, cy = x+w/2, y+h/2
angle = angle*np.pi/180
cv2.circle(vis, (cx, cy), r, color, 3)
cv2.line(vis, (cx, cy), (int(cx+np.cos(angle)*r), int(cy+np.sin(angle)*r)), color, 3)
if __name__ == '__main__':
import sys
try:
video_src = sys.argv[1]
except:
video_src = 0
cv2.namedWindow('motempl')
visuals = ['input', 'frame_diff', 'motion_hist', 'grad_orient']
cv2.createTrackbar('visual', 'motempl', 2, len(visuals)-1, nothing)
cv2.createTrackbar('threshold', 'motempl', DEFAULT_THRESHOLD, 255, nothing)
cam = video.create_capture(video_src, fallback='synth:class=chess:bg=../cpp/lena.jpg:noise=0.01')
ret, frame = cam.read()
h, w = frame.shape[:2]
prev_frame = frame.copy()
motion_history = np.zeros((h, w), np.float32)
hsv = np.zeros((h, w, 3), np.uint8)
hsv[:,:,1] = 255
while True:
ret, frame = cam.read()
frame_diff = cv2.absdiff(frame, prev_frame)
gray_diff = cv2.cvtColor(frame_diff, cv2.COLOR_BGR2GRAY)
thrs = cv2.getTrackbarPos('threshold', 'motempl')
ret, motion_mask = cv2.threshold(gray_diff, thrs, 1, cv2.THRESH_BINARY)
timestamp = clock()
cv2.updateMotionHistory(motion_mask, motion_history, timestamp, MHI_DURATION)
mg_mask, mg_orient = cv2.calcMotionGradient( motion_history, MAX_TIME_DELTA, MIN_TIME_DELTA, apertureSize=5 )
seg_mask, seg_bounds = cv2.segmentMotion(motion_history, timestamp, MAX_TIME_DELTA)
visual_name = visuals[cv2.getTrackbarPos('visual', 'motempl')]
if visual_name == 'input':
vis = frame.copy()
elif visual_name == 'frame_diff':
vis = frame_diff.copy()
elif visual_name == 'motion_hist':
vis = np.uint8(np.clip((motion_history-(timestamp-MHI_DURATION)) / MHI_DURATION, 0, 1)*255)
vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)
elif visual_name == 'grad_orient':
hsv[:,:,0] = mg_orient/2
hsv[:,:,2] = mg_mask*255
vis = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
for i, rect in enumerate([(0, 0, w, h)] + list(seg_bounds)):
x, y, rw, rh = rect
area = rw*rh
if area < 64**2:
continue
silh_roi = motion_mask [y:y+rh,x:x+rw]
orient_roi = mg_orient [y:y+rh,x:x+rw]
mask_roi = mg_mask [y:y+rh,x:x+rw]
mhi_roi = motion_history[y:y+rh,x:x+rw]
if cv2.norm(silh_roi, cv2.NORM_L1) < area*0.05:
continue
angle = cv2.calcGlobalOrientation(orient_roi, mask_roi, mhi_roi, timestamp, MHI_DURATION)
color = ((255, 0, 0), (0, 0, 255))[i == 0]
draw_motion_comp(vis, rect, angle, color)
draw_str(vis, (20, 20), visual_name)
cv2.imshow('motempl', vis)
prev_frame = frame.copy()
if 0xFF & cv2.waitKey(5) == 27:
break
cv2.destroyAllWindows()

View File

@ -11,15 +11,15 @@
using namespace std;
using namespace cv;
#define M_MOG 1
#define M_MOG2 2
#define M_KNN 3
int main(int argc, const char** argv)
{
CommandLineParser cmd(argc, argv,
"{ c camera | false | use camera }"
"{ f file | 768x576.avi | input video file }"
"{ t type | mog | method's type (mog, mog2) }"
"{ t type | mog2 | method's type (knn, mog2) }"
"{ h help | false | print help message }"
"{ m cpu_mode | false | press 'm' to switch OpenCL<->CPU}");
@ -41,7 +41,7 @@ int main(int argc, const char** argv)
return EXIT_FAILURE;
}
int m = method == "mog" ? M_MOG : M_MOG2;
int m = method == "mog2" ? M_MOG2 : M_KNN;
VideoCapture cap;
if (useCamera)
@ -59,13 +59,13 @@ int main(int argc, const char** argv)
cap >> frame;
fgimg.create(frame.size(), frame.type());
Ptr<BackgroundSubtractorMOG> mog = createBackgroundSubtractorMOG();
Ptr<BackgroundSubtractorKNN> knn = createBackgroundSubtractorKNN();
Ptr<BackgroundSubtractorMOG2> mog2 = createBackgroundSubtractorMOG2();
switch (m)
{
case M_MOG:
mog->apply(frame, fgmask, 0.01f);
case M_KNN:
knn->apply(frame, fgmask);
break;
case M_MOG2:
@ -86,8 +86,8 @@ int main(int argc, const char** argv)
//update the model
switch (m)
{
case M_MOG:
mog->apply(frame, fgmask, 0.01f);
case M_KNN:
knn->apply(frame, fgmask);
break;
case M_MOG2: