Transferring images from Matlab to OpenCV IplImage

I have an image in Matlab:

img = imopen('image.jpg')

which returns the height of the uint8 height x width x channels array (3 channels: RGB).

Now I want to use openCV to perform some manipulations, so I am writing a MEX file that takes an image as a parameter and builds an IplImage from it:

#include "mex.h"
#include "cv.h"

void mexFunction(int nlhs, mxArray **plhs, int nrhs, const mxArray **prhs) {
    char *matlabImage = (char *)mxGetData(prhs[0]);
    const mwSize *dim = mxGetDimensions(prhs[0]);

    CvSize size;
    size.height = dim[0];
    size.width = dim[1];

    IplImage *iplImage = cvCreateImageHeader(size, IPL_DEPTH_8U, dim[2]);
    iplImage->imageData = matlabImage;
    iplImage->imageDataOrigin = iplImage->imageData;

    /* Show the openCV image */
    cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);
    cvShowImage("mainWin", iplImage);
}

This result looks completely wrong, because openCV uses conventions other than matlab to store the image (for example, they alternate color channels).

Can someone explain what the differences are in the conventions and give some guidance on the proper display of the image?

+5
source share
4 answers

, </sarcasm>, .

Matlab : × ×
OpenCV 2- : ( × ) ×

, OpenCV , 32- .

Matlab:

function [cv_img, dim, depth, width_step] = convert_to_cv(img)

% Exchange rows and columns (handles 3D cases as well)
img2 = permute( img(:,end:-1:1,:), [2 1 3] );

dim = [size(img2,1), size(img2,2)];

% Convert double precision to single precision if necessary
if( isa(img2, 'double') )
    img2 = single(img2);
end

% Determine image depth
if( ndims(img2) == 3 && size(img2,3) == 3 )
    depth = 3;
else
    depth = 1;
end

% Handle color images
if(depth == 3 )
    % Switch from RGB to BGR
    img2(:,:,[3 2 1]) = img2;

    % Interleave the colors
    img2 = reshape( permute(img2, [3 1 2]), [size(img2,1)*size(img2,3) size(img2,2)] );
end

% Pad the image
width_step = size(img2,1) + mod( size(img2,1), 4 );
img3 = uint8(zeros(width_step, size(img2,2)));
img3(1:size(img2,1), 1:size(img2,2)) = img2;

cv_img = img3;

% Output to openCV
cv_display(cv_img, dim, depth, width_step);

IplImage MEX:

#include "mex.h"
#include "cv.h"
#include "highgui.h"

#define IN_IMAGE prhs[0]
#define IN_DIMENSIONS prhs[1]
#define IN_DEPTH prhs[2]
#define IN_WIDTH_STEP prhs[3]

void mexFunction(int nlhs, mxArray **plhs, int nrhs, const mxArray **prhs) {
    bool intInput = true;

    if(nrhs != 4)
        mexErrMsgTxt("Usage: cv_disp(image, dimensions, depth, width_step)");

    if( mxIsUint8(IN_IMAGE) )
        intInput = true;
    else if( mxIsSingle(IN_IMAGE) )
        intInput = false;
    else 
        mexErrMsgTxt("Input should be a matrix of uint8 or single precision floats.");

    if( mxGetNumberOfElements(IN_DIMENSIONS) != 2 )
        mexErrMsgTxt("Dimension vector should contain two elements: [width, height].");

    char *matlabImage = (char *)mxGetData(IN_IMAGE);

    double *imgSize = mxGetPr(IN_DIMENSIONS);
    size_t width = (size_t) imgSize[0];
    size_t height = (size_t) imgSize[1];

    size_t depth = (size_t) *mxGetPr(IN_DEPTH);
    size_t widthStep = (size_t) *mxGetPr(IN_WIDTH_STEP) * (intInput ? sizeof(unsigned char):sizeof(float));

    CvSize size;
    size.height = height;
    size.width = width;

    IplImage *iplImage = cvCreateImageHeader(size, intInput ? IPL_DEPTH_8U:IPL_DEPTH_32F, depth);
    iplImage->imageData = matlabImage;
    iplImage->widthStep = widthStep;
    iplImage->imageDataOrigin = iplImage->imageData;

    /* Show the openCV image */
    cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);
    cvShowImage("mainWin", iplImage);
}
+12

mxGetDimensions mxGetNumberOfDimensions, mxGetClassID .

, , , matlab dll calllib. opencv Matlab, . MATLAB openCV. , opencv2.2 . , , opencv , . - ++ opencv.

+1

, : http://github.com/kyamagu/mexopencv "MxArray", MATLAB mxArray OpenCV ( OpenCV MATLAB). , mxArray cv:: Mat. Btw, IplImage , ++ API OpenCV, cv:: Mat .

: , , mex- MxArray.cpp ; MATLAB :

    mex yourmexfile.cpp MxArray.cpp
+1

Based on the answer and How the image matrix is ​​stored in memory on OpenCV , we can only do this with the Opencv Mat operation!

C++: Mat::Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0)
C++: void merge(const Mat* mv, size_t count, OutputArray dst)

Then mex C / C ++ code:

#include "mex.h"
#include <opencv2/opencv.hpp>
#define uint8 unsigned char

 void mexFunction(int nlhs, mxArray *out[], int nrhs, const mxArray *input[])
{

    // assume the type of image is  uint8
    if(!mxIsClass(input[0], "uint8"))
    {
        mexErrMsgTxt("Only image arrays of the UINT8 class are allowed.");
        return;
    }

    uint8* rgb = (uint8*) mxGetPr(input[0]);
    int* dims = (int*) mxGetDimensions(input[0]);

    int height = dims[0];
    int width = dims[1];
    int imsize = height * width;


    cv::Mat imR(1, imsize, cv::DataType<uint8>::type, rgb);
    cv::Mat imG(1, imsize, cv::DataType<uint8>::type, rgb+imsize);
    cv::Mat imB(1, imsize, cv::DataType<uint8>::type, rgb+imsize + imsize);

    // opencv is BGR and matlab is column-major order
    cv::Mat imA[3];
    imA[2] = imR.reshape(1,width).t();
    imA[1] = imG.reshape(1,width).t();
    imA[0] = imB.reshape(1,width).t();

    // done! imf is what we want!
    cv::Mat imf; 
    merge(imA,3,imf);

}

+1
source

All Articles