/** Implemenation of MxArray.
* @file MxArray.cpp
* @author Kota Yamaguchi
* @date 2012
*/
#include "MxArray.hpp"
namespace { // namespace
/** Field names for cv::Moments.
*/
const char *cv_moments_fields[10] = {"m00", "m10", "m01", "m20", "m11", "m02",
"m30", "m21", "m12", "m03"};
/** Field names for cv::RotatedRect.
*/
const char *cv_rotated_rect_fields[3] = {"center", "size", "angle"};
/** Field names for cv::TermCriteria.
*/
const char *cv_term_criteria_fields[3] = {"type", "maxCount", "epsilon"};
/** Field names for cv::Keypoint.
*/
const char *cv_keypoint_fields[6] = {"pt", "size", "angle", "response",
"octave", "class_id"};
/** Field names for cv::DMatch.
*/
const char *cv_dmatch_fields[4] = {"queryIdx", "trainIdx", "imgIdx",
"distance"};
/** Translates data type definition used in OpenCV to that of Matlab.
* @param classid data type of matlab's mxArray. e.g., mxDOUBLE_CLASS.
* @return opencv's data type. e.g., CV_8U.
*/
const ConstMap<mxClassID, int> DepthOf = ConstMap<mxClassID, int>
(mxDOUBLE_CLASS, CV_64F)
(mxSINGLE_CLASS, CV_32F)
(mxINT8_CLASS, CV_8S)
(mxUINT8_CLASS, CV_8U)
(mxINT16_CLASS, CV_16S)
(mxUINT16_CLASS, CV_16U)
(mxINT32_CLASS, CV_32S)
(mxUINT32_CLASS, CV_32S)
(mxLOGICAL_CLASS, CV_8U);
/** Translates data type definition used in Matlab to that of OpenCV.
* @param depth data depth of opencv's Mat class. e.g., CV_32F.
* @return data type of matlab's mxArray. e.g., mxDOUBLE_CLASS.
*/
const ConstMap<int,mxClassID> ClassIDOf = ConstMap<int,mxClassID>
(CV_64F, mxDOUBLE_CLASS)
(CV_32F, mxSINGLE_CLASS)
(CV_8S, mxINT8_CLASS)
(CV_8U, mxUINT8_CLASS)
(CV_16S, mxINT16_CLASS)
(CV_16U, mxUINT16_CLASS)
(CV_32S, mxINT32_CLASS);
/** Comparison operator for sparse matrix elements.
*/
struct CompareSparseMatNode {
bool operator () (const cv::SparseMat::Node* rhs,
const cv::SparseMat::Node* lhs)
{
if (rhs->idx[1] < lhs->idx[1])
return true;
if (rhs->idx[1] == lhs->idx[1] && rhs->idx[0] < lhs->idx[0])
return true;
return false;
}
};
/** InvTermCritType map for option processing.
*/
const ConstMap<int, std::string> InvTermCritType = ConstMap<int, std::string>
(cv::TermCriteria::COUNT, "Count")
(cv::TermCriteria::EPS, "EPS")
(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, "Count+EPS");
/** TermCritType map for option processing.
*/
const ConstMap<std::string, int> TermCritType = ConstMap<std::string, int>
("Count", cv::TermCriteria::COUNT)
("EPS", cv::TermCriteria::EPS)
("Count+EPS", cv::TermCriteria::COUNT+cv::TermCriteria::EPS);
} // namespace
MxArray& MxArray::operator=(const MxArray& rhs)
{
if (this != &rhs)
this->p_ = rhs.p_;
return *this;
}
MxArray::MxArray(const int i)
: p_(mxCreateDoubleScalar(static_cast<double>(i)))
{
if (!p_)
mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
}
MxArray::MxArray(const double d) : p_(mxCreateDoubleScalar(d))
{
if (!p_)
mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
}
MxArray::MxArray(const bool b) : p_(mxCreateLogicalScalar(b))
{
if (!p_)
mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
}
MxArray::MxArray(const std::string& s) : p_(mxCreateString(s.c_str()))
{
if (!p_)
mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
}
MxArray::MxArray(const cv::Mat& mat, mxClassID classid, bool transpose)
{
if (mat.empty())
{
p_ = mxCreateNumericArray(0, 0, mxDOUBLE_CLASS, mxREAL);
if (!p_)
mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
return;
}
cv::Mat input = (mat.dims == 2 && transpose) ? mat.t() : mat;
// Create a new mxArray.
const int nchannels = input.channels();
const int* dims_ = input.size;
std::vector<mwSize> d(dims_, dims_ + input.dims);
d.push_back(nchannels);
classid = (classid == mxUNKNOWN_CLASS)
? ClassIDOf[input.depth()] : classid;
std::swap(d[0], d[1]);
if (classid == mxLOGICAL_CLASS)
{
// OpenCV's logical true is any nonzero while matlab's true is 1.
cv::compare(input, 0, input, cv::CMP_NE);
input.setTo(1, input);
p_ = mxCreateLogicalArray(d.size(), &d[0]);
}
else {
p_ = mxCreateNumericArray(d.size(), &d[0], classid, mxREAL);
}
if (!p_)
mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
// Copy each channel.
std::vector<cv::Mat> channels;
split(input, channels);
std::vector<mwSize> si(d.size(), 0); // subscript index.
int type = CV_MAKETYPE(DepthOf[classid], 1); // destination type.
for (int i = 0; i < nchannels; ++i)
{
si[si.size() - 1] = i; // last dim is a channel index.
void *ptr = reinterpret_cast<void*>(
reinterpret_cast<size_t>(mxGetData(p_)) +
mxGetElementSize(p_) * subs(si));
cv::Mat m(input.dims, dims_, type, ptr);
channels[i].convertTo(m, type); // Write to mxArray through m.
}
}
MxArray::MxArray(const cv::SparseMat& mat)
{
if (mat.dims() != 2)
mexErrMsgIdAndTxt("mexopencv:error", "cv::Mat is not 2D");
if (mat.type() != CV_32FC1)
mexErrMsgIdAndTxt("mexopencv:error", "cv::Mat is not float");
// Create a sparse array.
int m = mat.size(0), n = mat.size(1), nnz = mat.nzcount();
p_ = mxCreateSparse(m, n, nnz, mxREAL);
if (!p_)
mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
mwIndex *ir = mxGetIr(p_);
mwIndex *jc = mxGetJc(p_);
if (ir == NULL || jc == NULL)
mexErrMsgIdAndTxt("mexopencv:error", "Unknown error");
// Sort nodes before we put elems into mxArray.
std::vector<const cv::SparseMat::Node*> nodes;
nodes.reserve(nnz);
for (cv::SparseMatConstIterator it = mat.begin(); it != mat.end(); ++it)
nodes.push_back(it.node());
std::sort(nodes.begin(), nodes.end(), CompareSparseMatNode());
// Copy data.
double *pr = mxGetPr(p_);
int i = 0;
jc[0] = 0;
for (std::vector<const cv::SparseMat::Node*>::const_iterator
it = nodes.begin(); it != nodes.end(); ++it)
{
mwIndex row = (*it)->idx[0], col = (*it)->idx[1];
ir[i] = row;
jc[col+1] = i+1;
pr[i] = static_cast<double>(mat.value<float>(*it));
++i;
}
}
MxArray::MxArray(const cv::Moments& m) :
p_(mxCreateStructMatrix(1, 1, 10, cv_moments_fields))
{
if (!p_)
mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
set("m00", m.m00);
set("m10", m.m10);
set("m01", m.m01);
set("m20", m.m20);
set("m11", m.m11);
set("m02", m.m02);
set("m30", m.m30);
set("m12", m.m12);
set("m21", m.m21);
set("m03", m.m03);
}
MxArray::MxArray(const cv::KeyPoint& p) :
p_(mxCreateStructMatrix(1, 1, 6, cv_keypoint_fields))
{
if (!p_)
mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
set("pt", p.pt);
set("size", p.size);
set("angle", p.angle);
set("response", p.response);
set("octave", p.octave);
set("class_id", p.class_id);
}
template<>
void MxArray::fromVector(const std::vector<char>& v)
{
mwSize size[] = {1, v.size()};
p_ = mxCreateCharArray(2, size);
if (!p_)
mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
std::copy(v.begin(), v.end(), mxGetChars(p_));
}
template<>
void MxArray::fromVector(const std::vector<bool>& v)
{
p_ = mxCreateLogicalMatrix(1, v.size());
if (!p_)
mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");
std::copy(v.begin(), v.end(), mxGetLogicals(p_));
}
template <>
MxArray::MxArray(const std::vector<cv::KeyPoint>& v) :
p_(mxCreateStructMatrix(1, v.size(), 6, cv_keypoint_fields))
{
if (!p_)
mexErrMsgIdAndTxt("mexopencv:error", "Allocation error");