Improved bridge. Fixed I/O problem in function template

This commit is contained in:
hbristow 2013-06-29 00:19:08 -07:00
parent 53c9c40eba
commit 53a7fbf74b
2 changed files with 164 additions and 26 deletions

View File

@ -35,7 +35,7 @@ void mexFunction(int nlhs, mxArray* plhs[],
conditionalError(nlhs <= {{ fun.rtp|void|not + fun.req|outputs|length + fun.opt|outputs|length}}, "Too many output arguments specified");
// setup
std::vector<Bridge> inputs(plhs, plhs+nrhs);
std::vector<Bridge> inputs(prhs, prhs+nrhs);
{% set noutputs = fun.rtp|void|not + fun.req|outputs|length + fun.opt|outputs|length %}
{%- if noutputs %}
std::vector<Bridge> outputs({{noutputs}});

View File

@ -46,93 +46,139 @@ typedef cv::Ptr<cv::StereoSGBM> Ptr_StereoSGBM;
typedef cv::Ptr<cv::FeatureDetector> Ptr_FeatureDetector;
/*!
* @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
*/
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
*/
void error(const std::string& str) {
mexErrMsgTxt(str.c_str());
}
// ----------------------------------------------------------------------------
// PREDECLARATIONS
// ----------------------------------------------------------------------------
class MxArray;
class Bridge;
template <typename InputScalar, typename OutputScalar>
void deepCopyAndTranspose(const cv::Mat& src, MxArray& dst);
template <typename InputScalar, typename OutputScalar>
void deepCopyAndTranspose(const MxArray& src, cv::Mat& dst);
// ----------------------------------------------------------------------------
// MATLAB TRAITS
// ----------------------------------------------------------------------------
namespace Matlab {
class DefaultTraits {};
class InheritType {};
static const int Dynamic = -1;
// --------------------------------------------------------------------------
// INTERNAL TRAITS CLASS
// --------------------------------------------------------------------------
template<typename _Tp = DefaultTraits> class Traits {
public:
static const mxClassID ScalarType = mxUNKNOWN_CLASS;
static const mxComplexity Complex = mxCOMPLEX;
static const mxComplexity Real = mxCOMPLEX;
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"; }
};
// size_t
template<> class Traits<size_t> {
public:
static const mxClassID ScalarType = (sizeof(size_t) == 4) ? mxUINT32_CLASS : mxUINT64_CLASS;
static std::string ToString() { return "size_t"; }
};
// char
template<> class Traits<char> {
public:
static const mxClassID ScalarType = mxCHAR_CLASS;
static std::string ToString() { return "char"; }
};
// char
template<> class Traits<Matlab::InheritType> {
public:
static std::string ToString() { return "Inherited type"; }
};
};
@ -149,18 +195,63 @@ namespace Matlab {
*
* 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.
* 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
*/
class MxArray {
private:
mxArray* ptr_;
bool owns_;
// this function is called exclusively from constructors!!
template <typename Scalar>
void fromMat(const cv::Mat& mat) {
mwSize dims[] = { mat.rows, mat.cols, mat.channels() };
ptr_ = mxCreateNumericArray(3, dims, Matlab::Traits<Scalar>::ScalarType, Matlab::Traits<>::Real);
owns_ = true;
switch (mat.depth()) {
case CV_8U: deepCopyAndTranspose<uint8_t, Scalar>(mat, *this); break;
case CV_8S: deepCopyAndTranspose<int8_t, Scalar>(mat, *this); break;
case CV_16U: deepCopyAndTranspose<uint16_t, Scalar>(mat, *this); break;
case CV_16S: deepCopyAndTranspose<int16_t, Scalar>(mat, *this); break;
case CV_32S: deepCopyAndTranspose<int32_t, Scalar>(mat, *this); break;
case CV_32F: deepCopyAndTranspose<float, Scalar>(mat, *this); break;
case CV_64F: deepCopyAndTranspose<double, Scalar>(mat, *this); break;
default: error("Attempted to convert from unknown class");
}
}
public:
MxArray() : ptr_(NULL), owns_(false) {}
// constructors and destructor
MxArray() : ptr_(mxCreateDoubleMatrix(1, 1, Matlab::Traits<>::Real)), owns_(true) {}
MxArray(const mxArray* ptr) : ptr_(const_cast<mxArray *>(ptr)), owns_(false) {}
~MxArray() {
virtual ~MxArray() {
if (owns_ && ptr_) mxDestroyArray(ptr_);
}
// copy constructor
// all copies are deep copies
MxArray(const MxArray& other) : ptr_(mxDuplicateArray(other.ptr_)), owns_(true) {}
// swap
friend void swap(MxArray& first, MxArray& second) {
using std::swap;
swap(first.ptr_, second.ptr_);
swap(first.owns_, second.owns_);
}
// assignment operator
// copy-and-swap idiom
// all copies are deep copies
MxArray& operator=(MxArray other) {
swap(*this, other);
return *this;
}
#if __cplusplus >= 201103L
// move constructor, if C++11
// default construct and swap
MxArray(MxArray&& other) : MxArray() {
swap(*this, other);
}
#endif
/*
* @brief release ownership to allow return into Matlab workspace
@ -189,7 +280,6 @@ public:
}
// TODO: Make sure NULL pointers are checked in all functions!
template <typename Scalar>
explicit MxArray(size_t m, size_t n, size_t k=1) : owns_(true) {
mwSize dims[] = {m, n, k};
@ -197,26 +287,31 @@ public:
}
template <typename Scalar>
explicit MxArray(const cv::Mat& mat) : owns_(true) {
mwSize dims[] = { mat.rows, mat.cols, mat.channels() };
if (mat.channels() == 2) {
ptr_ = mxCreateNumericArray(2, dims, Matlab::Traits<Scalar>::ScalarType, Matlab::Traits<>::Complex);
} else {
ptr_ = mxCreateNumericArray(2, dims, Matlab::Traits<Scalar>::ScalarType, Matlab::Traits<>::Real);
}
explicit MxArray(const cv::Mat& mat) : owns_(false) {
fromMat<Scalar>(mat);
}
template <typename Scalar>
cv::Mat toMat() const {
cv::Mat mat(cols(), rows(), CV_MAKETYPE(cv::DataType<Scalar>::type, channels()));
switch (ID()) {
case mxINT8_CLASS: deepCopyAndTranspose<int8_t, Scalar>(*this, mat); break;
case mxUINT8_CLASS: deepCopyAndTranspose<uint8_t, Scalar>(*this, mat); break;
case mxINT16_CLASS: deepCopyAndTranspose<int16_t, Scalar>(*this, mat); break;
case mxUINT16_CLASS: deepCopyAndTranspose<uint16_t, Scalar>(*this, mat); break;
case mxINT32_CLASS: deepCopyAndTranspose<int32_t, Scalar>(*this, mat); break;
case mxUINT32_CLASS: deepCopyAndTranspose<uint32_t, Scalar>(*this, mat); break;
case mxINT64_CLASS: deepCopyAndTranspose<int64_t, Scalar>(*this, mat); break;
case mxUINT64_CLASS: deepCopyAndTranspose<uint64_t, Scalar>(*this, mat); break;
case mxSINGLE_CLASS: deepCopyAndTranspose<float, Scalar>(*this, mat); break;
case mxDOUBLE_CLASS: deepCopyAndTranspose<double, Scalar>(*this, mat); break;
case mxCHAR_CLASS: deepCopyAndTranspose<char, Scalar>(*this, mat); break;
case mxLOGICAL_CLASS: deepCopyAndTranspose<int8_t, Scalar>(*this, mat); break;
default: error("Attempted to convert from unknown class");
}
return mat;
}
template <typename Scalar>
void fromMat(const cv::Mat& mat) {
}
MxArray field(const std::string& name) { return MxArray(mxGetField(ptr_, 0, name.c_str())); }
template <typename Scalar>
@ -259,14 +354,55 @@ public:
};
template <>
cv::Mat MxArray::toMat<Matlab::InheritType>() const {
return cv::Mat();
}
/*!
* @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 <>
void MxArray::fromMat<Matlab::InheritType>(const cv::Mat& mat) {
switch (mat.depth()) {
case CV_8U: fromMat<uint8_t>(mat); break;
case CV_8S: fromMat<int8_t>(mat); break;
case CV_16U: fromMat<uint16_t>(mat); break;
case CV_16S: fromMat<int16_t>(mat); break;
case CV_32S: fromMat<int32_t>(mat); break;
case CV_32F: fromMat<double>(mat); break; //NOTE: Matlab uses double as native type!
case CV_64F: fromMat<double>(mat); break;
default: error("Attempted to convert from unknown class");
}
}
/*!
* @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 MxArray::toMat<Matlab::InheritType>() const {
switch (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: error("Attempted to convert from unknown class");
}
return cv::Mat();
}
@ -293,10 +429,12 @@ void deepCopyAndTranspose<double, double>(const cv::Mat& src, MxArray& dst) {
template <>
void deepCopyAndTranspose<float, float>(const MxArray& src, cv::Mat& dst) {
// use mkl
}
template <>
void deepCopyAndTranspose<double, double>(const MxArray& src, cv::Mat& dst) {
// use mkl
}
@ -560,7 +698,7 @@ public:
// --------------------------------------------------------------------------
// OPENCV COMPLEX TYPES
// OPENCV COMPOUND TYPES
// --------------------------------------------------------------------------
// --------------------------- Ptr_StereoBM -----------------------------