2012-01-12 38 views
7

Tôi muốn gửi Ma trận đến Matlab bằng cách sử dụng "engine.h" trong mã C++. Thực tế là tôi có dữ liệu bên trong cv :: Mat, và tôi cần gửi một mxArray. Tôi đã cố gắng sử dụng cụm từ này nhưng nó không hoạt động:Chuyển đổi dữ liệu từ cv :: Mat thành mxArray

cv::Mat _priorP; 
_priorP = Mat::eye(13, 13, CV_32FC1); 
mxArray *mat; 
mat = mxCreateDoubleMatrix(13, 13, mxREAL); 

memcpy(mxGetPr(mat),_priorP.data, 13*13*sizeof(double)); 

Bất kỳ ai biết đúng cách để thực hiện chuyển đổi? Bất kỳ trợ giúp sẽ được apreciated. Cảm ơn.

EDIT

tôi thấy cách này: https://stackoverflow.com/a/8848711/744859

Trả lời

4

This thread cho thấy làm thế nào để chuyển đổi một CvMat để mxArray. Mặc dù nó không chính xác mã chuyển đổi bạn đang tìm kiếm, nó khá gần.

Đây là một chuyển đổi đơn giản và bạn sẽ có thể điều chỉnh mã để hoạt động với cv::Mat thay vì CvMat. Nếu bạn không thể, một cách nhanh chóng hack là để chuyển đổi cv::Mat dữ liệu của bạn để CvMat và sau đó sử dụng mã dưới đây như là (lấy từ các liên kết tôi đã gợi ý):

mxArray* CvMat_to_new_mxArr (const CvMat* mat) 
{ 
    const int TYPE = cvGetElemType (mat); 

    // 2-d image 
    if (CV_64FC1 == TYPE) { 
    return helper_2dcvmat_to_mat<CV_64FC1> (mat); 
    } 
    else if (CV_32FC1 == TYPE) { 
    return helper_2dcvmat_to_mat<CV_32FC1> (mat); 
    } 
    else if (CV_32SC1 == TYPE) { 
    return helper_2dcvmat_to_mat<CV_32SC1> (mat); 
    } 
    else if (CV_16SC1 == TYPE) { 
    return helper_2dcvmat_to_mat<CV_16SC1> (mat); 
    } 
    else if (CV_16UC1 == TYPE) { 
    return helper_2dcvmat_to_mat<CV_16UC1> (mat); 
    } 
    else if (CV_8UC1 == TYPE) { 
    return helper_2dcvmat_to_mat<CV_8UC1> (mat); 
    } 
    else if (CV_8SC1 == TYPE) { 
    return helper_2dcvmat_to_mat<CV_8SC1> (mat); 
    } 

    //Multi-dimensional arrays not supported, yet. 
    /* 
    // 3-d image 
    else if (CV_64FC3 == TYPE) { 
    return helper_rgbimage_to_mat<IPL_DEPTH_64F> (img); 
    } 
    else if (CV_32FC3 == TYPE) { 
    return helper_rgbimage_to_mat<IPL_DEPTH_32F> (img); 
    } 
    else if (CV_8UC3 == TYPE) { 
    return helper_rgbimage_to_mat<IPL_DEPTH_8U> (img); 
    } 
    */ 

    // unsupported conversion, return null mxArray 
    return mxCreateDoubleMatrix(0,0,mxREAL);  
} 


template<int TYPE> 
mxArray* helper_2dcvmat_to_mat (const CvMat* mat) 
{ 
    void* pBeg; 
    int pitch; 
    cvGetRawData(mat, (uchar**)&pBeg,&pitch); 

    CvSize size = cvGetSize (mat); 
    const mxClassID cid = cvm_traits<TYPE>::CID; 
    mxArray* pArrOut = 
    mxCreateNumericMatrix(size.height,size.width,cid,mxREAL); 
    void* pBegOut = mxGetData(pArrOut); 

    typedef mc_traits<cid>::CT T; 
    pix_iterator_2d<T,eRowWise> it_src1(static_cast<T*>(pBeg), 
    size.width,size.height,pitch); 
    pix_iterator_2d<T,eRowWise> it_src2(static_cast<T*>(pBeg), 
    size.width,size.height,pitch); 
    it_src2.end(); 
    pix_iterator_2d<T,eColWise> it_dest(static_cast<T*>(pBegOut), 
    size.width,size.height); 

    std::copy (it_src1,it_src2,it_dest); 

    return pArrOut; 
} 
+0

Cảm ơn. Vì vậy, nó luôn luôn là lộn xộn để sử dụng engine.h với openCV, phải không? Tôi đã mong đợi một cái gì đó trực tiếp hơn, nhưng nếu không có giải pháp đơn giản, tôi sẽ cố gắng này. –

+1

Một câu hỏi. Bạn có xem xét rằng opencv lưu trữ dữ liệu theo hàng và MATLAB theo cột? –

+1

Tôi phải nhấn mạnh rằng bạn mở chuỗi mà tôi đề xuất và xem xét mã nguồn ** hoàn chỉnh ** có sẵn ở đó. Theo những người dùng khác, mã đó hoạt động. Nhưng nếu nó không, ít nhất là một sự khởi đầu cho bạn. – karlphillip

3

Tôi tìm thấy một phương pháp đơn giản để làm chuyển đổi này sau một vài nỗ lực. Những gì tôi làm là tạo ra một chức năng như thế này:

void arithmetic::cvLoadMatrixToMatlab(Engine *ep, const Mat& m, string name) 
{ 
    int rows=m.rows; 
    int cols=m.cols; 
    //Mat data is float, and mxArray uses double, so we need to convert. 
    mxArray *T=mxCreateDoubleMatrix(cols, rows, mxREAL); 
    double *buffer=(double*)mxGetPr(T); 
    for(int i=0; i<rows; i++){ 
     for(int j=0; j<cols; j++){ 
      buffer[i*(cols)+j]= (double)m.at<float>(i, j); 
     } 
    } 

    //memcpy((char*)mxGetPr(T), (char*)m.data, rows*cols*sizeof(double)); 
    engPutVariable(ep, name.c_str(), T); 
    name=name+"="+name+"'";     // Column major to row major (mat=mat') 
    engEvalString(ep, name.c_str()); 

    mxDestroyArray(T); 
} 
9

Có một thư viện phát triển bởi Kota Yamaguchi tại http://github.com/kyamagu/mexopencv Các gói phần mềm có chứa một lớp C++ (được gọi là MxArray) có thể chuyển đổi giữa các kiểu dữ liệu có nguồn gốc của Matlab (mxArray) và Các kiểu dữ liệu OpenCV. Thư viện trực tiếp hỗ trợ C++ API cho OpenCV (Mở CV phiên bản 2.0 trở lên), do đó không cần phải thực hiện thêm chuyển đổi (ví dụ: từ cvMat sang cv :: Mat hoặc từ IplImage sang cv :: Mat). Sử dụng mẫu:

#include "mexopencv.hpp" // include the library 
#include "highgui.h"  

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 
{ 
    cv::Mat image; 
    image = imread("filename"); // read an image from file 
    plhs[0] = MxArray(image); // convert from cv::Mat to mxArray 
} 

Vậy đó. Đảm bảo biên dịch hàm mex của bạn cùng nhau với tệp MxArray.cpp từ thư viện; bạn có thể làm như vậy trong dòng lệnh MATLAB:

mex yourmexfile.cpp MxArray.cpp 
+0

Mã nguồn là đủ cho tôi, tôi chỉ muốn làm cho chức năng của riêng tôi. Cảm ơn rất nhiều, rất hữu ích thực sự .. –

+1

@Jav_Rock Rất vui khi được nghe! MxArray.cpp cũng rất hữu ích với tôi. Hãy xem xét bỏ phiếu cho câu trả lời này, vì vậy những người khác có thể thấy giải pháp này. – Alexey

+3

vâng tôi đã làm điều đó! –

Các vấn đề liên quan