From 504558c0be9811ac3fa20783c61ea1eaab38a51e Mon Sep 17 00:00:00 2001 From: hbristow Date: Mon, 1 Jul 2013 16:33:55 -0700 Subject: [PATCH] Better C++11 and C++98 support/interop. Started writing map interface. Some core functions actually run --- modules/matlab/compile.cmake | 2 +- .../templates/template_function_base.cpp | 1 + modules/matlab/include/bridge.hpp | 94 ++++++++++++------- modules/matlab/include/map.hpp | 46 +++++++++ 4 files changed, 110 insertions(+), 33 deletions(-) create mode 100644 modules/matlab/include/map.hpp diff --git a/modules/matlab/compile.cmake b/modules/matlab/compile.cmake index ae4faf3770..f4e8c84312 100644 --- a/modules/matlab/compile.cmake +++ b/modules/matlab/compile.cmake @@ -3,7 +3,7 @@ macro(listify OUT_LIST IN_STRING) endmacro() listify(MEX_INCLUDE_DIRS_LIST ${MEX_INCLUDE_DIRS}) -set(MEX_CXXFLAGS "CXXFLAGS=\$CXXFLAGS -pedantic -Wall -Wextra -Weffc++ -Wno-unused -Wold-style-cast -Wshadow -Wmissing-declarations -Wmissing-include-dirs -Wnon-virtual-dtor") +set(MEX_CXXFLAGS "CXXFLAGS=\$CXXFLAGS -pedantic -Wall -Wextra -Weffc++ -Wno-unused -Wold-style-cast -Wshadow -Wmissing-declarations -Wmissing-include-dirs -Wnon-virtual-dtor -Wno-newline-eof") file(GLOB SOURCE_FILES "${CMAKE_CURRENT_BINARY_DIR}/src/*.cpp") foreach(SOURCE_FILE ${SOURCE_FILES}) # strip out the filename diff --git a/modules/matlab/generator/templates/template_function_base.cpp b/modules/matlab/generator/templates/template_function_base.cpp index 2b6a59a514..3fb41fe298 100644 --- a/modules/matlab/generator/templates/template_function_base.cpp +++ b/modules/matlab/generator/templates/template_function_base.cpp @@ -53,3 +53,4 @@ void mexFunction(int nlhs, mxArray*{% if fun|noutputs %} plhs[]{% else %}*{% end } {% endif %} } + diff --git a/modules/matlab/include/bridge.hpp b/modules/matlab/include/bridge.hpp index 127b60e343..f976ef657b 100644 --- a/modules/matlab/include/bridge.hpp +++ b/modules/matlab/include/bridge.hpp @@ -2,11 +2,11 @@ #define OPENCV_BRIDGE_HPP_ #include "mex.h" +#include "map.hpp" #include #include #include #include -#include /* * All recent versions of Matlab ship with the MKL library which contains @@ -180,7 +180,7 @@ namespace Matlab { public: static std::string ToString() { return "Inherited type"; } }; -}; +} @@ -205,29 +205,15 @@ private: mxArray* ptr_; bool owns_; - // this function is called exclusively from constructors!! - template - void fromMat(const cv::Mat& mat) { - mwSize dims[] = { static_cast(mat.rows), static_cast(mat.cols), static_cast(mat.channels()) }; - ptr_ = mxCreateNumericArray(3, dims, Matlab::Traits::ScalarType, Matlab::Traits<>::Real); - owns_ = true; - switch (mat.depth()) { - case CV_8U: deepCopyAndTranspose(mat, *this); break; - case CV_8S: deepCopyAndTranspose(mat, *this); break; - case CV_16U: deepCopyAndTranspose(mat, *this); break; - case CV_16S: deepCopyAndTranspose(mat, *this); break; - case CV_32S: deepCopyAndTranspose(mat, *this); break; - case CV_32F: deepCopyAndTranspose(mat, *this); break; - case CV_64F: deepCopyAndTranspose(mat, *this); break; - default: error("Attempted to convert from unknown class"); - } + void dealloc() { + if (owns_ && ptr_) { mxDestroyArray(ptr_); ptr_ = NULL; owns_ = false; } } public: // constructors and destructor MxArray() : ptr_(mxCreateDoubleMatrix(1, 1, Matlab::Traits<>::Real)), owns_(true) {} MxArray(const mxArray* ptr) : ptr_(const_cast(ptr)), owns_(false) {} virtual ~MxArray() { - if (owns_ && ptr_) mxDestroyArray(ptr_); + dealloc(); } // copy constructor // all copies are deep copies @@ -286,9 +272,25 @@ public: ptr_ = mxCreateNumericArray(3, dims, Matlab::Traits::ScalarType, Matlab::Traits<>::Real); } + // this function is called exclusively from constructors!! template - explicit MxArray(const cv::Mat& mat) : owns_(false) { - fromMat(mat); + MxArray& fromMat(const cv::Mat& mat) { + // dealloc any existing storage before reallocating + dealloc(); + mwSize dims[] = { static_cast(mat.rows), static_cast(mat.cols), static_cast(mat.channels()) }; + ptr_ = mxCreateNumericArray(3, dims, Matlab::Traits::ScalarType, Matlab::Traits<>::Real); + owns_ = true; + switch (mat.depth()) { + case CV_8U: deepCopyAndTranspose(mat, *this); break; + case CV_8S: deepCopyAndTranspose(mat, *this); break; + case CV_16U: deepCopyAndTranspose(mat, *this); break; + case CV_16S: deepCopyAndTranspose(mat, *this); break; + case CV_32S: deepCopyAndTranspose(mat, *this); break; + case CV_32F: deepCopyAndTranspose(mat, *this); break; + case CV_64F: deepCopyAndTranspose(mat, *this); break; + default: error("Attempted to convert from unknown class"); + } + return *this; } template @@ -364,17 +366,18 @@ public: * that gets mapped to an unsigned 8-bit value */ template <> -void MxArray::fromMat(const cv::Mat& mat) { +MxArray& MxArray::fromMat(const cv::Mat& mat) { switch (mat.depth()) { - case CV_8U: fromMat(mat); break; - case CV_8S: fromMat(mat); break; - case CV_16U: fromMat(mat); break; - case CV_16S: fromMat(mat); break; - case CV_32S: fromMat(mat); break; - case CV_32F: fromMat(mat); break; //NOTE: Matlab uses double as native type! - case CV_64F: fromMat(mat); break; + case CV_8U: return fromMat(mat); break; + case CV_8S: return fromMat(mat); break; + case CV_16U: return fromMat(mat); break; + case CV_16S: return fromMat(mat); break; + case CV_32S: return fromMat(mat); break; + case CV_32F: return fromMat(mat); break; //NOTE: Matlab uses double as native type! + case CV_64F: return fromMat(mat); break; default: error("Attempted to convert from unknown class"); } + return *this; } /*! @@ -412,13 +415,40 @@ cv::Mat MxArray::toMat() const { // ---------------------------------------------------------------------------- template -void deepCopyAndTranspose(const cv::Mat&, MxArray&) { +void deepCopyAndTranspose(const cv::Mat& in, MxArray& out) { + conditionalError(static_cast(in.rows) == out.rows(), "Matrices must have the same number of rows"); + conditionalError(static_cast(in.cols) == out.cols(), "Matrices must have the same number of cols"); + conditionalError(static_cast(in.channels()) == out.channels(), "Matrices must have the same number of channels"); + OutputScalar* outp = out.real(); + const size_t M = out.rows(); + const size_t N = out.cols(); + for (size_t m = 0; m < M; ++m) { + const InputScalar* inp = in.ptr(m); + for (size_t n = 0; n < N; ++n) { + // copy and transpose + outp[m + n*M] = inp[n]; + } + } } template -void deepCopyAndTranspose(const MxArray&, cv::Mat&) { +void deepCopyAndTranspose(const MxArray& in, cv::Mat& out) { + conditionalError(in.rows() == static_cast(out.rows), "Matrices must have the same number of rows"); + conditionalError(in.cols() == static_cast(out.cols), "Matrices must have the same number of cols"); + conditionalError(in.channels() == static_cast(out.channels()), "Matrices must have the same number of channels"); + const InputScalar* inp = in.real(); + const size_t M = in.rows(); + const size_t N = in.cols(); + for (size_t m = 0; m < M; ++m) { + OutputScalar* outp = out.ptr(m); + for (size_t n = 0; n < N; ++n) { + // copy and transpose + outp[n] = inp[m + n*M]; + } + } } + template <> void deepCopyAndTranspose(const cv::Mat&, MxArray&) { } @@ -583,7 +613,7 @@ public: // -------------------------------------------------------------------------- // --------------------------- cv::Mat -------------------------------------- - Bridge& operator=(const cv::Mat& ) { return *this; } + Bridge& operator=(const cv::Mat& mat) { ptr_ = MxArray().fromMat(mat); return *this; } cv::Mat toMat() const { return ptr_.toMat(); } operator cv::Mat() const { return toMat(); } diff --git a/modules/matlab/include/map.hpp b/modules/matlab/include/map.hpp new file mode 100644 index 0000000000..6a5d9f462a --- /dev/null +++ b/modules/matlab/include/map.hpp @@ -0,0 +1,46 @@ +#ifndef OPENCV_MAP_HPP_ +#define OPENCV_MAP_HPP_ + +#if __cplusplus >= 201103L + + // If we have C++11 support, we just want to use unordered_map +#include +template +using Map = std::unordered_map; + +#else + +// If we don't have C++11 support, we wrap another map implementation +// in the same public API as unordered_map +#include +#include + +template +class Map { +private: + std::map 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::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::const_iterator it; + it = map_.find(k); + if (it == map_.end()) throw std::out_of_range("Key not found"); + return *it; + } +}; + +#endif +#endif