Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
52dc51a6
Commit
52dc51a6
authored
Aug 28, 2013
by
hbristow
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added custom OpenCV mex compiler
parent
ef2c1e1a
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
396 additions
and
21 deletions
+396
-21
CMakeLists.txt
modules/matlab/CMakeLists.txt
+35
-8
compile.cmake
modules/matlab/compile.cmake
+17
-1
build_info.py
modules/matlab/generator/build_info.py
+2
-2
cvmex.py
modules/matlab/generator/cvmex.py
+58
-0
filters.py
modules/matlab/generator/filters.py
+8
-0
template_build_info.m
modules/matlab/generator/templates/template_build_info.m
+2
-0
template_cvmex_base.m
modules/matlab/generator/templates/template_cvmex_base.m
+46
-0
mxarray.hpp
modules/matlab/include/mxarray.hpp
+224
-6
cv_exception.cpp
modules/matlab/test/cv_exception.cpp
+4
-4
No files found.
modules/matlab/CMakeLists.txt
View file @
52dc51a6
...
...
@@ -34,21 +34,30 @@ macro(PREPEND TOKEN OUT IN)
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
}
Mixed preicision pointers are not supported. Disabling Matlab bindings..
."
)
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 OR NOT PYTHONLIBS_FOUND
)
if
(
IOS OR ANDROID OR NOT MATLAB_FOUND
)
ocv_module_disable
(
matlab
)
return
()
elseif
(
NOT PYTHONLIBS_FOUND
)
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.
...
...
@@ -63,6 +72,16 @@ elseif (${ARCH} EQUAL 64 AND NOT ${MATLAB_ARCH} MATCHES "64")
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
...
...
@@ -93,9 +112,9 @@ endif()
include_directories
(
${
CMAKE_CURRENT_SOURCE_DIR
}
/include
)
#
----------------------------------------------------------------------------
#
Configure time components
#
----------------------------------------------------------------------------
#
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
}
)
...
...
@@ -114,7 +133,7 @@ list(APPEND opencv_extra_hdrs "core=${OPENCV_MODULE_opencv_core_LOCATION}/includ
# 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}")
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.
...
...
@@ -149,7 +168,7 @@ if (NOT MEX_WORKS)
# 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_CXXFLAGS
}
"
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
...
...
@@ -208,6 +227,14 @@ add_custom_command(
--modules
${
opencv_modules
}
--configuration
"$(Configuration)"
${
CMAKE_BUILD_TYPE
}
--outdir
${
CMAKE_CURRENT_BINARY_DIR
}
COMMAND
${
PYTHON_EXECUTABLE
}
${
CMAKE_CURRENT_SOURCE_DIR
}
/generator/cvmex.py
--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"
...
...
@@ -222,7 +249,7 @@ add_custom_command(
COMMAND
${
CMAKE_COMMAND
}
-DMATLAB_MEX_SCRIPT=
${
MATLAB_MEX_SCRIPT
}
-DMATLAB_MEXEXT=
${
MATLAB_MEXEXT
}
-DMEX_OPTS=
${
MEX_OPTS
}
-DMEX_CXXFLAGS=
${
MEX_CXXFLAGS
}
-DMEX_CXXFLAGS=
${
MEX_CXX
_
FLAGS
}
-DMEX_INCLUDE_DIRS=
"
${
MEX_INCLUDE_DIRS
}
"
-DMEX_LIB_DIR=
${
MEX_LIB_DIR
}
-DCONFIGURATION=
"$(Configuration)"
...
...
modules/matlab/compile.cmake
View file @
52dc51a6
# 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
}
)
...
...
@@ -9,11 +14,22 @@ 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
()
# 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
)
# compie the source file using mex
# compile the source file using mex
execute_process
(
COMMAND echo
${
FILENAME
}
)
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
}
...
...
modules/matlab/generator/build_info.py
View file @
52dc51a6
...
...
@@ -19,7 +19,7 @@ def substitute(build, output_dir):
os
.
mkdir
(
output_dir
)
# populate template
populated
=
template
.
render
(
build
=
build
)
populated
=
template
.
render
(
build
=
build
,
time
=
time
)
with
open
(
os
.
path
.
join
(
output_dir
,
'buildInformation.m'
),
'wb'
)
as
f
:
f
.
write
(
populated
)
...
...
@@ -46,7 +46,7 @@ if __name__ == "__main__":
"""
# parse the input options
import
sys
,
re
,
os
import
sys
,
re
,
os
,
time
from
argparse
import
ArgumentParser
parser
=
ArgumentParser
()
parser
.
add_argument
(
'--os'
)
...
...
modules/matlab/generator/cvmex.py
0 → 100644
View file @
52dc51a6
#!/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
)
if
__name__
==
"__main__"
:
"""
Usage: python cvmex.py --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
(
'--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
()
from
filters
import
*
from
jinja2
import
Environment
,
FileSystemLoader
# populate the mex base template
substitute
(
cv
,
cv
.
outdir
)
modules/matlab/generator/filters.py
View file @
52dc51a6
...
...
@@ -139,10 +139,18 @@ def filename(fullpath):
'''
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'''
...
...
modules/matlab/generator/templates/template_build_info.m
View file @
52dc51a6
...
...
@@ -6,6 +6,8 @@ function buildInformation()
% 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>'
...
...
modules/matlab/generator/templates/template_cvmex_base.m
0 → 100644
View file @
52dc51a6
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
modules/matlab/include/mxarray.hpp
View file @
52dc51a6
...
...
@@ -2,9 +2,19 @@
#define OPENCV_MXARRAY_HPP_
#include <stdint.h>
#include <cstdarg>
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>
#include <opencv2/core.hpp>
#if __cplusplus > 201103
#include <unordered_set>
typedef
std
::
unordered_set
<
std
::
string
>
StringSet
;
#else
#include <set>
typedef
std
::
set
<
std
::
string
>
StringSet
;
#endif
#include "mex.h"
#include "transpose.hpp"
...
...
@@ -274,10 +284,10 @@ public:
* Explicitly construct a scalar of given type. Since constructors cannot
* be explicitly templated, this is a static factory method
*/
template
<
typename
Scalar
>
static
MxArray
Scalar
(
Scalar
value
=
0
)
{
MxArray
s
(
1
,
1
,
1
,
Matlab
::
Traits
<
Scalar
>::
ScalarType
);
s
.
real
<
Scalar
>
()[
0
]
=
value
;
template
<
typename
Scalar
Type
>
static
MxArray
Scalar
(
Scalar
Type
value
=
0
)
{
MxArray
s
(
1
,
1
,
1
,
Matlab
::
Traits
<
Scalar
Type
>::
ScalarType
);
s
.
real
<
Scalar
Type
>
()[
0
]
=
value
;
return
s
;
}
...
...
@@ -410,8 +420,8 @@ public:
std
::
string
toString
()
const
{
conditionalError
(
isString
(),
"Attempted to convert non-string type to string"
);
std
::
string
str
(
size
()
+
1
,
'\0'
);
mxGetString
(
ptr_
,
const_cast
<
char
*>
(
str
.
data
()),
str
.
size
());
std
::
string
str
(
size
(),
'\0'
);
mxGetString
(
ptr_
,
const_cast
<
char
*>
(
str
.
data
()),
str
.
size
()
+
1
);
return
str
;
}
...
...
@@ -432,6 +442,214 @@ public:
};
/*! @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()
* }
*/
class
ArgumentParser
{
private
:
struct
Variant
;
typedef
std
::
string
String
;
typedef
std
::
vector
<
std
::
string
>
StringVector
;
typedef
std
::
vector
<
MxArray
>
MxArrayVector
;
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
{
public
:
Variant
(
const
String
&
_name
,
size_t
_nreq
,
size_t
_nopt
,
const
StringVector
&
_keys
)
:
name
(
_name
),
nreq
(
_nreq
),
nopt
(
_nopt
),
keys
(
_keys
),
using_named
(
false
)
{}
String
name
;
size_t
nreq
;
size_t
nopt
;
StringVector
keys
;
bool
using_named
;
/*! @brief return true if the named-argument is in the Variant */
bool
count
(
const
String
&
key
)
{
return
std
::
find
(
keys
.
begin
(),
keys
.
end
(),
key
)
!=
keys
.
end
();
}
/*! @brief remove a key by index from the Variant */
void
erase
(
const
size_t
idx
)
{
keys
.
erase
(
keys
.
begin
()
+
idx
);
}
/*! @brief remove a key by name from the Variant */
void
erase
(
const
String
&
key
)
{
keys
.
erase
(
std
::
find
(
keys
.
begin
(),
keys
.
end
(),
key
));
}
/*! @brief convert a Variant to a string representation */
String
toString
(
const
String
&
method_name
=
String
(
"f"
))
const
{
std
::
ostringstream
s
;
s
<<
method_name
<<
"("
;
for
(
size_t
n
=
0
;
n
<
nreq
;
++
n
)
{
s
<<
"src"
<<
n
+
1
;
if
(
n
!=
nreq
-
1
)
s
<<
", "
;
}
if
(
nreq
&&
nopt
)
s
<<
", "
;
for
(
size_t
n
=
0
;
n
<
keys
.
size
();
++
n
)
{
s
<<
"'"
<<
keys
[
n
]
<<
"', "
<<
keys
[
n
];
if
(
n
!=
keys
.
size
()
-
1
)
s
<<
", "
;
}
s
<<
");"
;
return
s
.
str
();
}
};
MxArrayVector
filled_
;
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
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
)
{
// check if the input is a key
bool
key
=
candidate
->
count
(
name
);
/*
* FAILURE CASES
* 1. too many inputs, or
* 2. name is not a key and we're expecting a key
* 3. name is a key, and
* we're still expecting required arguments, or
* we're expecting an argument for a previous key
*/
if
((
!
candidate
->
nreq
&&
!
candidate
->
nopt
)
||
(
!
key
&&
!
candidate
->
nreq
&&
candidate
->
keys
.
size
()
==
candidate
->
nopt
&&
candidate
->
using_named
)
||
(
key
&&
(
candidate
->
nreq
||
candidate
->
keys
.
size
()
<
candidate
->
nopt
)))
{
candidate
=
candidates
.
erase
(
candidate
)
--
;
}
// VALID CASES
// Still parsing required argments (input is not a key)
else
if
(
!
key
&&
candidate
->
nreq
)
{
candidate
->
nreq
--
;
}
// Parsing optional arguments and a named argument is encountered
else
if
(
key
&&
!
candidate
->
nreq
&&
candidate
->
nopt
>
0
&&
candidate
->
keys
.
size
()
==
candidate
->
nopt
)
{
candidate
->
erase
(
name
);
candidate
->
using_named
=
true
;
}
// Parsing input for a named argument
else
if
(
!
key
&&
candidate
->
keys
.
size
()
<
candidate
->
nopt
)
{
candidate
->
nopt
--
;
}
// Parsing un-named optional arguments
else
if
(
!
key
&&
!
candidate
->
nreq
&&
candidate
->
nopt
&&
candidate
->
keys
.
size
()
&&
!
candidate
->
using_named
)
{
candidate
->
erase
(
0
);
candidate
->
nopt
--
;
}
}
}
// if any candidates remain, check that they have been fully parsed
for
(
VariantVector
::
iterator
candidate
=
candidates
.
begin
();
candidate
<
candidates
.
end
();
++
candidate
)
{
if
(
candidate
->
nreq
||
candidate
->
keys
.
size
()
<
candidate
->
nopt
)
{
candidate
=
candidates
.
erase
(
candidate
)
--
;
}
}
// if there is not a unique candidate, throw an error
String
variant_string
;
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
(
"
\n
Use named arguments to disambiguate call"
));
}
if
(
candidates
.
size
()
==
0
)
{
error
(
String
(
"No matching method signatures for given arguments. Valid variants are:"
).
append
(
variant_string
));
}
return
outputs
;
}
};
/*!
* @brief template specialization for inheriting types
*
...
...
modules/matlab/test/cv_exception.cpp
View file @
52dc51a6
...
...
@@ -7,7 +7,7 @@
* Copyright 2013 The OpenCV Foundation
*/
#include <exception>
//
#include <opencv2/core.hpp>
#include <opencv2/core.hpp>
#include "mex.h"
/*
...
...
@@ -24,9 +24,9 @@ void mexFunction(int nlhs, mxArray* plhs[],
// call the opencv function
// [out =] namespace.fun(src1, ..., srcn, dst1, ..., dstn, opt1, ..., optn);
try
{
// throw cv::exception
;
//} catch(cv::e
xception& e) {
//
mexErrMsgTxt(e.what());
throw
cv
::
Exception
(
-
1
,
"OpenCV exception thrown"
,
__func__
,
__FILE__
,
__LINE__
)
;
}
catch
(
cv
::
E
xception
&
e
)
{
mexErrMsgTxt
(
e
.
what
());
}
catch
(...)
{
mexErrMsgTxt
(
"Incorrect exception caught!"
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment