Upadated include tree to match the rest of opencv. Added install configuration for custom mex compiler
This commit is contained in:
310
modules/matlab/include/opencv2/matlab/bridge.hpp
Normal file
310
modules/matlab/include/opencv2/matlab/bridge.hpp
Normal file
@@ -0,0 +1,310 @@
|
||||
#ifndef OPENCV_BRIDGE_HPP_
|
||||
#define OPENCV_BRIDGE_HPP_
|
||||
|
||||
#include "mxarray.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/calib3d.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;
|
||||
typedef std::vector<float> vector_float;
|
||||
typedef std::vector<cv::String> vector_String;
|
||||
typedef std::vector<unsigned char> vector_uchar;
|
||||
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;
|
||||
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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 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:
|
||||
MxArray ptr_;
|
||||
public:
|
||||
// bridges are default constructible
|
||||
Bridge() {}
|
||||
virtual ~Bridge() {}
|
||||
|
||||
/*! @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)) {
|
||||
error(std::string("Expected class ").append(std::string(name))
|
||||
.append(" but was given ").append(ptr_.className()));
|
||||
}
|
||||
// get the instance field
|
||||
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 {
|
||||
error("Incorrect pointer type stored for architecture");
|
||||
}
|
||||
|
||||
// finally check if the object is NULL
|
||||
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(const mxArray* obj) : ptr_(obj) {}
|
||||
MxArray toMxArray() { return ptr_; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// 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
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// --------------------------- cv::Mat --------------------------------------
|
||||
Bridge& operator=(const cv::Mat& mat) { ptr_ = MxArray::FromMat<Matlab::InheritType>(mat); return *this; }
|
||||
cv::Mat toMat() const { return ptr_.toMat<Matlab::InheritType>(); }
|
||||
operator cv::Mat() const { return toMat(); }
|
||||
|
||||
// -------------------------- 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(); }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// 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(); }
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
46
modules/matlab/include/opencv2/matlab/map.hpp
Normal file
46
modules/matlab/include/opencv2/matlab/map.hpp
Normal file
@@ -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 <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;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
764
modules/matlab/include/opencv2/matlab/mxarray.hpp
Normal file
764
modules/matlab/include/opencv2/matlab/mxarray.hpp
Normal file
@@ -0,0 +1,764 @@
|
||||
#ifndef OPENCV_MXARRAY_HPP_
|
||||
#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"
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* This operation is used extensively to copy between Matlab's column-major
|
||||
* format and OpenCV's row-major format.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
* @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());
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// PREDECLARATIONS
|
||||
// ----------------------------------------------------------------------------
|
||||
class MxArray;
|
||||
|
||||
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;
|
||||
|
||||
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"; }
|
||||
};
|
||||
// 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(1, 1, Matlab::Traits<>::Real)), owns_(true) {}
|
||||
|
||||
/*!
|
||||
* @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) : 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 destructor
|
||||
*
|
||||
* The destructor deallocates any data allocated by mxCreate* methods only
|
||||
* if the object is owned
|
||||
*/
|
||||
virtual ~MxArray() {
|
||||
dealloc();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @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<double>(5, 5); // allocates memory
|
||||
* MxArray B<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_;
|
||||
}
|
||||
|
||||
|
||||
template <typename Scalar>
|
||||
static MxArray FromMat(const cv::Mat& mat) {
|
||||
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: error("Attempted to convert from unknown class");
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
cv::Mat toMat() const {
|
||||
cv::Mat mat(rows(), cols(), 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;
|
||||
}
|
||||
|
||||
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_); }
|
||||
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_); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*! @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<size_t> IndexVector;
|
||||
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;
|
||||
IndexVector order;
|
||||
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();
|
||||
}
|
||||
};
|
||||
void sortArguments(Variant& v, MxArrayVector& in, MxArrayVector& out) {
|
||||
// allocate the output array with ALL arguments
|
||||
out.resize(v.nreq + v.nopt);
|
||||
// reorder the inputs based on the variant ordering
|
||||
for (size_t n = 0; n < v.order.size(); ++n) {
|
||||
swap(in[n], out[v.order[n]]);
|
||||
}
|
||||
}
|
||||
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("\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));
|
||||
}
|
||||
|
||||
return outputs;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* @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 <>
|
||||
MxArray MxArray::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: error("Attempted to convert from unknown class");
|
||||
}
|
||||
return 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 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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// MATRIX TRANSPOSE
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
template <typename InputScalar, typename OutputScalar>
|
||||
void deepCopyAndTranspose(const cv::Mat& in, MxArray& out) {
|
||||
conditionalError(static_cast<size_t>(in.rows) == out.rows(), "Matrices must have the same number of rows");
|
||||
conditionalError(static_cast<size_t>(in.cols) == out.cols(), "Matrices must have the same number of cols");
|
||||
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 MxArray& in, cv::Mat& out) {
|
||||
conditionalError(in.rows() == static_cast<size_t>(out.rows), "Matrices must have the same number of rows");
|
||||
conditionalError(in.cols() == static_cast<size_t>(out.cols), "Matrices must have the same number of cols");
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
99
modules/matlab/include/opencv2/matlab/transpose.hpp
Normal file
99
modules/matlab/include/opencv2/matlab/transpose.hpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#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
|
Reference in New Issue
Block a user