【问题标题】:Convert OpenCV Mat file to Matlab matrix将 OpenCV Mat 文件转换为 Matlab 矩阵
【发布时间】:2015-06-11 11:34:00
【问题描述】:

我创建了一个 Matlab 引擎来将 OpenCV Mat 文件转换为 Matlab 矩阵。但是,我得到了错误的结果。我附上了我的代码,以便您可以直接测试它。

#pragma comment (lib, "libmat.lib")
#pragma comment (lib, "libmx.lib")
#pragma comment (lib, "libmex.lib")
#pragma comment (lib, "libeng.lib")

    void cvLoadMatrixToMatlab(const Mat& m, const string name, Engine *m_pEngine)
    {
        int rows=m.rows;
        int cols=m.cols;  
        string text;
        mxArray *T=mxCreateDoubleMatrix(cols, rows, mxREAL);

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

        mxDestroyArray(T);
    }

    int main(int argc, char **argv)
    {
        /*Open Matlab Engine*/
            Engine *m_pEngine;
            m_pEngine = engOpen("null");

            cv::Mat img = imread("panda.jpg",0);

            cvLoadMatrixToMatlab(img,"imgMatlab", m_pEngine);
            engEvalString(m_pEngine, "imshow(imgMatlab)");
        cv::waitKey(0);

    }

我怀疑下面的代码会导致这个问题,但我不知道如何解决。

memcpy((char*)mxGetPr(T), (char*)m.data, rows*cols*sizeof(char));

【问题讨论】:

  • 如果我没记错的话,memcpy 会以行主要格式复制数据。您可能应该做的是在执行memcpy 之前先转置矩阵。这样,即使复制是以行为主的,在执行以行为主的读出时,数据也会以列为主的格式排列。
  • 嘿@rayryeng。感谢您的回复。我尝试将 transpose 放在 memcpy 函数的前面,但它仍然无法正常工作。您是否能够修改我的代码,以便我可以最终对其进行测试。谢谢!

标签: c++ matlab opencv matrix mixed-programming


【解决方案1】:

在将cv::Mat的数据复制到Matlab的矩阵时,需要注意:

  1. 在 OpenCV 中,所有矩阵都是行优先的,而在 Matlab 中是列优先的。您应该在复制之前转置。

  2. 对于彩色图像的复制,应逐通道传输数据。


当您要将彩色图像cv::Mat 复制到 Matlab 时,您应该执行以下操作:

mwSize dims[] = {rows, cols, 3};
mxArray *T = mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL);
UINT8 *ptr = (UINT8 *) mxGetData(T);

std::vector<cv::Mat> channels; // B, G, R channels
cv::split(m, channels);

// remember to transpose first because MATLAB is col-major!!!
cv::transpose(channels[0], channels[0]);
cv::transpose(channels[1], channels[1]);
cv::transpose(channels[2], channels[2]);

memcpy(ptr, channels[2].ptr(), rows*cols*sizeof(UINT8));
memcpy(ptr+rows*cols, channels[1].ptr(), rows*cols*sizeof(UINT8));
memcpy(ptr+2*rows*cols, channels[0].ptr(), rows*cols*sizeof(UINT8));

engPutVariable(m_pEngine, name.c_str(), T); // put into matlab

更新:如果您要复制灰度图像,它应该是这样的

mwSize dims[] = {rows, cols};
mxArray *T = mxCreateNumericArray(2, dims, mxUINT8_CLASS, mxREAL);
UINT8 *ptr = (UINT8 *) mxGetData(T);

cv::transpose(m, m); // remember to tranpose first because MATLAB is col-major!!!
memcpy(ptr, m.ptr(), rows*cols*sizeof(UINT8));

engPutVariable(m_pEngine, name.c_str(), T); // put into matlab

注意,这里的UINT8 是为了和Matlab 用于图像的uint8 类型一致。

【讨论】:

  • 谢谢!我实际上是在复制灰度数据,因此我的 imread 函数的第二个参数是 0。另外,你的 UINT8 是什么意思?您能否指出我的代码中的哪个位置导致问题?我试图将 transpose 放在 memcpy 函数的前面,但它仍然不起作用。
  • 抱歉,我还是无法通过将 UINT8 替换为 char 来正确运行代码。程序在转置时会导致崩溃。我想你的 rows 和 cols 是 m.rows 和 m.cols,对吧?
  • @JoeWang 用memcpy(ptr, (UINT8 *)m.datastart, rows*cols*sizeof(UINT8)); 替换memcpy(ptr, m.ptr(), rows*cols*sizeof(UINT8)); 怎么样?
  • 嗨,UINT8 不是 OpenCV 中的有效类型
  • @JoeWang 您可以简单地添加typedef unsigned char UINT8; 使其工作,如here 所述。
【解决方案2】:

好的。我使用for循环来复制数据,最后它工作了。

int rows=m.rows;
        int cols=m.cols;  

        mwSize dims[] = {rows, cols};
        mxArray *T = mxCreateNumericArray(2, dims, mxUINT8_CLASS, mxREAL);
        char *ptr = (char *) mxGetData(T);

         for (int i = 0; i < rows; i++)  
        {  
            for (int j = 0; j < cols; j++)  
            {    
            ptr[j*rows + i] =  (* m.row(i).col(j).data);  
             }  
        }  

        engPutVariable(m_pEngine, name.c_str(), T); // put into matlab

对于上面发布的答案,我仍在努力。感谢@herohuyongtao 帮助提及转置问题。

【讨论】:

    猜你喜欢
    • 2012-07-17
    • 2013-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 1970-01-01
    • 2010-12-28
    相关资源
    最近更新 更多