1

I'm doing some computer vision stuff in C++, working with JPG images. In C++, I'm calling computer vision functions from Piotr Dollar's Toolbox, which were originally designed for Matlab compatibility. I'm trying to figure out how to quickly load images from files in C++, and arrange them in a Matlab-style data layout.


Matlab-style data layout
Since Piotr's Toolbox is designed to play nicely with Matlab MEX files, Piotr typically uses this image data layout in his C++ functions:

image = imread('img.jpg') //in Matlab

//flattened array notation:
image[x*width+ y + channel*width*height]

//unflattened C++ array notation:
image[channel][x][y] //typically: 3-channel color images

C++-style data layout
Most of the image file I/O libraries for C++ (e.g. OpenCV imread) provide this data layout when loading a JPG image from file:

Mat image = cv::imread("img.jpg") //in C++ with OpenCV

//flattened array notation:
image.data[x*nChannels + y*width*d + channel]

//unflattened C++ array notation:
image.data[y][x][channel]

Questions:

  1. Is there a C++ function (possibly from a library) that loads images from file into the Matlab-style [channel][width][height] data layout? (It doesn't have to use OpenCV. After loading in the image, I use raw pointers anyway.)
  2. Is there a C++ function that would quickly transpose the C++-style layout into a Matlab-style layout? I coded a naive transpose function, but it's quite slow:


//this implementation also converts char* to float*, but that's not too important for this question
float* transpose_opencv_to_matlab(Mat img){
    assert(img.type() == CV_8UC3);
    int h = img.rows; //height
    int w = img.cols; //width
    int d = 3; //nChannels
    float multiplier = 1 / 255.0f; //rescale pixels to range [0 to 1]

    uchar* img_data = &img.data[0];
    float* I = (float*)malloc(h * w * d * sizeof(float)); //img transposed to Matlab data layout. 
    for(int y=0; y<h; y++){
        for(int x=0; x<w; x++){
            for(int ch=0; ch<d; ch++){
                I[x*h + y + ch*w*h] = img_data[x*d + y*w*d + ch] * multiplier; 
            }
        }
    }
    return I;
}
solvingPuzzles
  • 8,541
  • 16
  • 69
  • 112
  • cv::split() is probably the closest thing – berak Sep 23 '13 at 20:44
  • Just googling this there appears to be a `cv::transpose()` function. Have you tried this yet? From this answer: http://stackoverflow.com/questions/2259678/easiest-way-to-transpose-an-image-rotate-by-90-degrees-using-opencv. – JustinBlaber Sep 23 '13 at 21:09
  • @jucestain `cv::transpose` can do `[y][x][channel]` to `[x][y][channel]`. But, `cv::transpose` doesn't appear to make `channel` the longest-stride dimension, e.g. `[channel][x][y]`. Doing `cv::split`, then `cv::transpose` may work, though. Also, I'm not sure whether `cv::transpose` actually permutes the data, or if it just changes the indexing when using the `image<>.at(y,x)` pixel access interface. – solvingPuzzles Sep 23 '13 at 22:18
  • Just to clarify, you are not actually using MATLAB, you just want to use Piotr's C++ that is designed to work with MATLAB data? – chappjc Sep 23 '13 at 22:48
  • @chappjc Precisely, yes. :) – solvingPuzzles Sep 23 '13 at 23:22

1 Answers1

0

The MatlabOpenCV utility contains functions to convert between Matlab format and OpenCV format. It has worked well for me in MEX code using OpenCV.

For example to convert from Matlab to OpenCV is as simple as

IplImage* iplImg = mxArr_to_new_IplImage(argin[0]);
cv::Mat matImg(iplImg , false);
...
cvReleaseImage(&iplImg);

To convert from OpenCV to Matlab, you could use (untested):

Mat img = cv::imread("img.jpg");
IplImage ipl_image = img;
mxArray* matlab_fmt_image = IplImage_to_new_mxArr (&img);

The only issues I had (possibly not present in the latest version) were that MatlabOpenCV only supported the legacy (IplImage/CvMat) interface to OpenCV, and that there were some compatibility problems when transitioning from Visual Studio 2010 to VS2012.

Bull
  • 11,771
  • 9
  • 42
  • 53