2014-11-14 58 views
3

是否可以從存儲爲MatND的3D數據立方體中獲取2D Mat對象在opencv中?基本上我使用「mexopencv」將3D矩陣傳遞給MexFile。我使用MxArray(prhs [0])。toMatND()將矩陣轉換爲MatND對象。現在我想將這個第三維的數據立方體分解成一個cv :: Mat矩陣的向量。因此我需要對這些二維矩陣進行運算,從而迭代第三維。 是否有根據需要拆分數據立方體的功能?或者,也許有辦法獲得一個指向3D數據立方體的二維矩陣的指針?將3D MatND拆分爲2D Mat的矢量opencv

編輯:這是我的代碼,它使用mexopencv將Matlab輸入參數轉換爲MatND數組。我實現了@ chappjc將3D數據代碼分解成2D矩陣矢量的方法。除了切換x和y尺寸的事實,一切都很好。

#include "mexopencv.hpp" 
#include <iostream> 

void mexFunction(int nlhs, mxArray *plhs[], 
       int nrhs, const mxArray *prhs[]) 
{ 
    // Check arguments 
    if (nlhs!=1 || nrhs!=1) 
     mexErrMsgIdAndTxt("myfunc:invalidArgs", "Wrong number of arguments"); 

    // 1) Convert MxArray to cv::Mat 
    cv::MatND matnd = MxArray(prhs[0]).toMatND(); 

    // Extract planes from matrix 
    int dims[] = { matnd.size[0],matnd.size[1],matnd.size[2]}; 
    std::vector<cv::Mat> matVec; 
    for (int p = 0; p < dims[2]; ++p) { 
     double *ind = (double*)matnd.data + p * dims[0] * dims[1]; // sub-matrix pointer 
     matVec.push_back(cv::Mat(2, dims, CV_64F, ind).clone()); // clone if mnd goes away 
    } 

    std::cout << "\nmatVec[0]:\n" << matVec[0] << std::endl; 
    std::cout << "\nmatVec[1]:\n" << matVec[1] << std::endl; 

    // Here I will do some stuff with the 2D submatrices from matVec 
    // ... 


    // 2) Here I want to pass the 3D matrix back to Matlab 
    // I only know how to convert cv::Mat back to mxArray* using mexopencv: 
    plhs[0] = MxArray(matnd); 
} 

2nd編輯。實際上尺寸切換爲「matVec」這一事實非常煩人。有沒有人有更好的解決方案?

這是一個小[5×4×2]實施例的輸出:

>> b 

b(:,:,1) = 

    1  6 11 16 
    2  7 12 17 
    3  8 13 18 
    4  9 14 19 
    5 10 15 20 


b(:,:,2) = 

    101 106 111 116 
    102 107 112 117 
    103 108 113 118 
    104 109 114 119 
    105 110 115 120 

>> c = cv.myFunc(b) 

matVec[0]: 
[1, 2, 3, 4, 5; 
    6, 7, 8, 9, 10; 
    11, 12, 13, 14, 15; 
    16, 17, 18, 19, 20] 

matVec[1]: 
[101, 102, 103, 104, 105; 
    106, 107, 108, 109, 110; 
    111, 112, 113, 114, 115; 
    116, 117, 118, 119, 120] 

c(:,:,1) = 

    1  6 11 16 
    2  7 12 17 
    3  8 13 18 
    4  9 14 19 
    5 10 15 20 


c(:,:,2) = 

    101 106 111 116 
    102 107 112 117 
    103 108 113 118 
    104 109 114 119 
    105 110 115 120 

回答

6

聰明法師曾經說過:不要試圖分裂MatND。這不可能。相反......只是嘗試意識到事實。沒有MatND


MatND是過時的,它現在typedef倒是給Mat。在opencv2 /核心/ core.hpp:

typedef Mat MatND; 

這意味着你可以把它就像一個Mat和手動砍碎。我相信atptr方法不能按預期的方式工作,因爲dims> 2,因此您只需抓住Mat::data指針並計算子矩陣的位置。有一個ptr(int i0, int i1, int i2)方法,但我沒有多少運氣,因爲多維數組的step[]是奇怪的。

// create 3D matrix with element index as content 
int dims[] = { 5, 5, 3 }; 
cv::Mat mnd(3, dims, CV_64F); 
for (int i = 0; i < mnd.total(); ++i) 
    *((double*)mnd.data+i) = (double)i; 

// extract planes from matrix 
std::vector<cv::Mat> matVec; 
for (int p = 0; p < dims[2]; ++p) { 
    double *ind = (double*)mnd.data + p * dims[0] * dims[1]; // sub-matrix pointer 
    matVec.push_back(cv::Mat(2, dims, CV_64F, ind).clone()); // clone if mnd goes away 
} 

std::cout << "Size of matVec: " << matVec.size() << std::endl; 
std::cout << "Size of first Mat: " << matVec[0].size() << std::endl; 

std::cout << "\nmatVec[0]:\n" << matVec[0] << std::endl; 
std::cout << "\nmatVec[1]:\n" << matVec[1] << std::endl; 
std::cout << "\nmatVec[2]:\n" << matVec[2] << std::endl; 

輸出

Size of matVec: 3 
Size of first Mat: [5 x 5] 

matVec[0]: 
[0, 1, 2, 3, 4; 
    5, 6, 7, 8, 9; 
    10, 11, 12, 13, 14; 
    15, 16, 17, 18, 19; 
    20, 21, 22, 23, 24] 

matVec[1]: 
[25, 26, 27, 28, 29; 
    30, 31, 32, 33, 34; 
    35, 36, 37, 38, 39; 
    40, 41, 42, 43, 44; 
    45, 46, 47, 48, 49] 

matVec[2]: 
[50, 51, 52, 53, 54; 
    55, 56, 57, 58, 59; 
    60, 61, 62, 63, 64; 
    65, 66, 67, 68, 69; 
    70, 71, 72, 73, 74] 
+0

1 - I在你的[基質]暗暗(http://en.wikipedia.org/wiki/The_Matrix)參考: ) – rayryeng 2014-11-16 20:09:31

+0

@rayryeng它剛鑽進我的腦海。 :)。 Re:答案,還有一個'Range'函數,就像MATLAB的''''一樣,但我從來沒有用過它。你通常也可以通過'cv:Rect'使用ROI,但我認爲這只是2D。無論如何,我並不經常使用多維'Mat',但我知道'MatND'' typedef'。 – chappjc 2014-11-16 20:29:58

+0

謝謝你的回答。你得到二維子矩陣指針的方法似乎工作:)。儘管在mexopencv中發生的事情仍然很奇怪:雖然不贊成使用cv :: MatND和prhs [0])。toMatND()似乎是必要的,因爲當您嘗試使用matlab將大型3D矩陣傳遞給mexopencv時會崩潰prhs [0])。toMat()(cv :: Mat將第三維存儲爲「通道」,最大通道數爲4)。 – mcExchange 2014-11-17 13:54:47