Matlab bindings now only building once rather than every call to make, via the use of some proxies. Matlab build currently only happens in one thread, so it can be pretty slow

This commit is contained in:
hbristow 2013-06-22 23:26:27 -07:00
parent 3b4814a52e
commit 755ce9d654
6 changed files with 159 additions and 38 deletions

View File

@ -56,6 +56,10 @@ prepend("-I" MEX_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include)
prepend("-L" MEX_LIB_DIR ${CMAKE_BINARY_DIR}/lib)
set(MEX_OPTS "-largeArrayDims")
if (ENABLE_SOLUTION_FOLDERS)
set_target_properties(${the_module} PROPERTIES FOLDER "Matlab bindings")
endif()
if (BUILD_TESTS)
add_subdirectory(test)
endif()
@ -63,11 +67,23 @@ endif()
# ----------------------------------------------------------------------------
# Configure time components
# ----------------------------------------------------------------------------
string(REPLACE "opencv_" "" OPENCV_MATLAB_MODULES "${OPENCV_MODULE_${the_module}_REQ_DEPS};
${OPENCV_MODULE_${the_module}_OPT_DEPS}")
foreach(module ${OPENCV_MATLAB_MODULES})
if (HAVE_opencv_${module})
list(APPEND opencv_hdrs "${OPENCV_MODULE_opencv_${module}_LOCATION}/include/opencv2/${module}.hpp")
prepend("-I" MEX_INCLUDE_DIRS "${OPENCV_MODULE_opencv_${module}_LOCATION}/include")
prepend("-l" MEX_LIBS "opencv_${module}")
endif()
endforeach()
# attempt to generate a gateway for a function
message("-- Trying to generate Matlab code")
execute_process(
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_SOURCE_DIR}/test/trigger.cpp
COMMAND ${PYTHON_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/generator/gen_matlab_caller.py ${HDR_PARSER_PATH}
${CMAKE_CURRENT_SOURCE_DIR}/test/test_generator.hpp ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/test/test_generator.hpp ${CMAKE_BINARY_DIR}/junk
ERROR_VARIABLE GEN_ERROR
OUTPUT_QUIET
)
@ -80,12 +96,12 @@ else()
message("-- Trying to generate Matlab code - OK")
endif()
# attempt to compile the file using mex
# attempt to compile a gateway using mex
message("-- Trying to compile mex file")
execute_process(
COMMAND ${MATLAB_MEX_SCRIPT} ${MEX_OPTS} ${MEX_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/test/test_compiler.cpp
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/src
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/junk
ERROR_VARIABLE MEX_ERROR
OUTPUT_QUIET
)
@ -104,36 +120,39 @@ set_property(GLOBAL PROPERTY MEX_WORKS TRUE)
# ----------------------------------------------------------------------------
# Build time components
# ----------------------------------------------------------------------------
string(REPLACE "opencv_" "" OPENCV_MATLAB_MODULES "${OPENCV_MODULE_${the_module}_REQ_DEPS};
${OPENCV_MODULE_${the_module}_OPT_DEPS}")
foreach(module ${OPENCV_MATLAB_MODULES})
if (HAVE_opencv_${module})
list(APPEND opencv_hdrs "${OPENCV_MODULE_opencv_${module}_LOCATION}/include/opencv2/${module}.hpp")
prepend("-I" MEX_INCLUDE_DIRS "${OPENCV_MODULE_opencv_${module}_LOCATION}/include")
prepend("-l" MEX_LIBS "opencv_${module}")
endif()
endforeach()
set(GENERATE_PROXY ${CMAKE_CURRENT_BINARY_DIR}/generate.proxy)
set(COMPILE_PROXY ${CMAKE_CURRENT_BINARY_DIR}/compile.proxy)
# synthesise the matlab sources
add_custom_target(opencv_matlab_sources
add_custom_command(
OUTPUT ${GENERATE_PROXY}
COMMAND ${PYTHON_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/generator/gen_matlab_caller.py ${HDR_PARSER_PATH}
${opencv_hdrs} ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E touch ${GENERATE_PROXY}
COMMENT "Generating matlab source files"
)
# compile the matlab sources to mex
add_custom_target(opencv_matlab ALL DEPENDS opencv_matlab_sources)
file(GLOB SOURCE_FILES "${CMAKE_CURRENT_BINARY_DIR}/src/*.cpp")
foreach(SOURCE_FILE ${SOURCE_FILES})
get_filename_component(FILENAME ${SOURCE_FILE} NAME_WE)
# compile the source file using mex
add_custom_command(TARGET opencv_matlab PRE_BUILD
COMMAND ${MATLAB_MEX_SCRIPT} ${MEX_OPTS} ${MEX_INCLUDE_DIRS}
${MEX_LIB_DIR} ${MEX_LIBS} ${SOURCE_FILE}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/src
)
endforeach()
add_custom_command(
OUTPUT ${COMPILE_PROXY}
COMMAND ${CMAKE_COMMAND} -DMATLAB_MEX_SCRIPT=${MATLAB_MEX_SCRIPT}
-DMEX_OPTS=${MEX_OPTS}
-DMEX_INCLUDE_DIRS="${MEX_INCLUDE_DIRS}"
-DMEX_LIB_DIR=${MEX_LIB_DIR}
-DMEX_LIBS="${MEX_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..."
)
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)
# ----------------------------------------------------------------------------
# Install time components
# ----------------------------------------------------------------------------
file(GLOB MATLAB_FUNCTIONS "${CMAKE_CURRENT_BINARY_DIR}/src/*.mex*")
file(GLOB MATLAB_CLASSES "${CMAKE_CURRENT_BINARY_DIR}/src/private/*.mex*" "${CMAKE_CURRENT_BINARY_DIR}/+cv/*.m")
install(FILES ${MATLAB_FUNCTIONS} ${MATLAB_CLASSES}
DESTINATION ${CMAKE_INSTALL_PREFIX}/matlab/+cv
)

View File

@ -0,0 +1,14 @@
macro(listify OUT_LIST IN_STRING)
string(REPLACE " " ";" ${OUT_LIST} ${IN_STRING})
endmacro()
listify(MEX_INCLUDE_DIRS_LIST ${MEX_INCLUDE_DIRS})
file(GLOB SOURCE_FILES "${CMAKE_CURRENT_BINARY_DIR}/src/*.cpp")
foreach(SOURCE_FILE ${SOURCE_FILES})
# compile the source file using mex
execute_process(
COMMAND ${MATLAB_MEX_SCRIPT} ${MEX_OPTS} ${MEX_INCLUDE_DIRS_LIST}
${MEX_LIB_DIR} ${MEX_LIBS} ${SOURCE_FILE}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/src
)
endforeach()

View File

@ -43,12 +43,15 @@ def noutputs(args):
'''Counts the number of output arguments in the input list'''
return len(outputs(args))
def toUpperCamelCase(text):
def capitalizeFirst(text):
return text[0].upper() + text[1:]
def toUpperCamelCase(text):
return ''.join([capitalizeFirst(word) for word in text.split('_')])
def toLowerCamelCase(text):
return text[0].lower() + text[1:]
upper_camel = toUpperCamelCase(test)
return upper_camel[0].lower() + upper_camel[1:]
def toUnderCase(text):
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', text)

View File

@ -8,7 +8,7 @@
{% macro compose(fun) %}
{# ----------- Return type ------------- #}
{%- if not fun.rtp|void -%} retval = {% endif -%}
{%- if fun.clss -%}inst.{%- else -%} cv:: {% endif -%}
{%- if fun.clss -%}inst.{%- else -%} cv:: {%- endif -%}
{{fun.name}}(
{#- ----------- Required ------------- -#}
{%- for arg in fun.req -%}
@ -32,10 +32,10 @@
// unpack the arguments
{# ----------- Inputs ------------- #}
{% for arg in fun.req|inputs %}
{{arg.tp}} {{arg.name}} = inputs[{{ loop.index0 }}];
{{arg.tp}} {{arg.name}} = inputs[{{ loop.index0 }}].to{{arg.tp|toUpperCamelCase}}();
{% endfor %}
{% for opt in fun.opt|inputs %}
{{opt.tp}} {{opt.name}} = (nrhs > {{loop.index0 + fun.req|inputs|length}}) ? ({{opt.tp}})inputs[{{loop.index0 + fun.req|inputs|length}}] : {{opt.default}};
{{opt.tp}} {{opt.name}} = (nrhs > {{loop.index0 + fun.req|inputs|length}}) ? inputs[{{loop.index0 + fun.req|inputs|length}}].to{{opt.tp|toUpperCamelCase}}() : {% if opt.ref == '*' -%} {{opt.tp}}() {%- else -%} {{opt.default}} {%- endif %};
{% endfor %}
{# ----------- Outputs ------------ #}
{% for arg in fun.req|only|outputs %}

View File

@ -42,8 +42,10 @@ void mexFunction(int nlhs, mxArray* plhs[],
{{ functional.generate(fun) }}
{%- if noutputs %}
// push the outputs back to matlab
for (size_t n = 0; n < nlhs; ++n) {
plhs[n] = outputs[n].mxArray();
plhs[n] = outputs[n].toMxArray();
}
{% endif %}
}

View File

@ -2,8 +2,17 @@
#define OPENCV_BRIDGE_HPP_
#include "mex.h"
#include <vector>
#include <opencv2/core.hpp>
/*
* 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;
/*!
* @class Bridge
* @brief Type conversion class for converting OpenCV and native C++ types
@ -17,12 +26,20 @@
* // implicit conversion from Bridge --> ObjectType
* operator ObjectType();
* // explicit conversion from Bridge --> ObjectType
* ObjectType toObjectType
* 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.
*
* 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:
@ -39,19 +56,85 @@ public:
virtual ~Bridge() {}
// --------------------------- mxArray --------------------------------------
Bridge& operator=(const mxArray* obj) {}
Bridge& operator=(const mxArray* obj) { return *this; }
Bridge(const mxArray* obj) {}
mxArray* mxArray() { return NULL; }
mxArray* toMxArray() { return NULL; }
// --------------------------- cv::Mat --------------------------------------
Bridge& operator=(const cv::Mat& obj) {}
Bridge& operator=(const cv::Mat& obj) { return *this; }
operator cv::Mat() { return cv::Mat(); }
cv::Mat toMat() { return cv::Mat(); }
// -------------------- vector_Mat --------------------------------
Bridge& operator=(const vector_Mat& obj) { return *this; }
operator vector_Mat() { return vector_Mat(); }
vector_Mat toVectorMat() { return vector_Mat(); }
// --------------------------- int --------------------------------------
Bridge& operator=(const int& obj) {}
Bridge& operator=(const int& obj) { return *this; }
operator int() { return 0; }
int toInt() { return 0; }
// --------------------------- vector_int ----------------------------------
Bridge& operator=(const vector_int& obj) { return *this; }
operator vector_int() { return vector_int(); }
vector_int toVectorInt() { return vector_int(); }
// --------------------------- string --------------------------------------
Bridge& operator=(const std::string& obj) { return *this; }
operator std::string() { return ""; }
std::string toString() { return ""; }
// --------------------------- bool --------------------------------------
Bridge& operator=(const bool& obj) { return *this; }
operator bool() { return 0; }
bool toBool() { return 0; }
// --------------------------- double --------------------------------------
Bridge& operator=(const double& obj) { return *this; }
operator double() { return 0; }
double toDouble() { return 0; }
// -------------------------- Point --------------------------------------
Bridge& operator=(const cv::Point& obj) { return *this; }
operator cv::Point() { return cv::Point(); }
cv::Point toPoint() { return cv::Point(); }
// -------------------------- Size ---------------------------------------
Bridge& operator=(const cv::Size& obj) { return *this; }
operator cv::Size() { return cv::Size(); }
cv::Size toSize() { return cv::Size(); }
// ------------------------ vector_Point ------------------------------------
Bridge& operator=(const vector_Point& obj) { return *this; }
operator vector_Point() { return vector_Point(); }
vector_Point toVectorPoint() { return vector_Point(); }
// -------------------------- Scalar --------------------------------------
Bridge& operator=(const cv::Scalar& obj) { return *this; }
operator cv::Scalar() { return cv::Scalar(); }
cv::Scalar toScalar() { return cv::Scalar(); }
// -------------------------- Rect --------------------------------------
Bridge& operator=(const cv::Rect& obj) { return *this; }
operator cv::Rect() { return cv::Rect(); }
cv::Rect toRect() { return cv::Rect(); }
// ---------------------- RotatedRect ------------------------------------
Bridge& operator=(const cv::RotatedRect& obj) { return *this; }
operator cv::RotatedRect() { return cv::RotatedRect(); }
cv::RotatedRect toRotatedRect() { return cv::RotatedRect(); }
// ---------------------- TermCriteria -----------------------------------
Bridge& operator=(const cv::TermCriteria& obj) { return *this; }
operator cv::TermCriteria() { return cv::TermCriteria(); }
cv::TermCriteria toTermCriteria() { return cv::TermCriteria(); }
// ---------------------- RNG -----------------------------------
Bridge& operator=(const cv::RNG& obj) { return *this; }
operator cv::RNG() { return cv::RNG(); }
cv::RNG toRNG() { return cv::RNG(); }
};
#endif