'Performane issue for matlab-like reshape in OpenCV

I am translating a Matlab code to OpenCV. The Code Involves lots of reshaping of large Matrices. As the matlab reshape differs from OpenCV you can't just use OpenCV reshape. Here is why: Let's suppose we have a 2x4x3 matrix such as this:

a(:,:,1) =

     1     3     5     7
     2     4     6     8

a(:,:,2) =

     9    11    13    15
    10    12    14    16

a(:,:,3) =

    17    19    21    23
    18    20    22    24

when we perform reshape(a,4,3,2) the result is

ans(:,:,1) =

     1     5     9
     2     6    10
     3     7    11
     4     8    12

ans(:,:,2) =

    13    17    21
    14    18    22
    15    19    23
    16    20    24

But if we perform a similar reshape in OpenCV we get

ans(:,:,1) =

     1     17   11
     5     21   15
     2     18   12
     6     22   16

ans(:,:,2) =

    9     3     19
    13    7     23
    10    4     20
    14    8     24

This is due to the different ways of traversing the Matrix in OpenCV and Matlab. Matlab first traverse columns then rows and last depth. OpenCV first traverse depth then rows and last columns. So I have written a function to do a Matlab-like reshape for 3D Matrices. First I reshape the input matrix to a row matrix. For the matrix mentioned above the result matrix will be [1 2 3 ... 24] then I reshape the row Matrix to the desired channels. But as You see this code Involves lots of creating auxiliary matrices and copying and transposing that will not be good for the performance.

Mat matlab_reshape(const Mat &m, int new_row, int new_col, int new_ch)
{
    int old_row, old_col, old_ch;
    old_row = m.size().height;
    old_col = m.size().width;
    old_ch = m.channels();

    Mat m1 ( 1, new_row*new_col*new_ch, m.depth() );

    vector <Mat> p(old_ch);
    split(m,p);
    for ( int i=0; i<p.size(); ++i ){
        Mat t ( p[i].size().height, p[i].size().width, m1.type() );
        t = p[i].t();
        Mat aux = m1.colRange(i*old_row*old_col,(i+1)*old_row*old_col).rowRange(0,1);
        t.reshape(0,1).copyTo(aux);
    }

    vector <Mat> r(new_ch);
    for ( int i=0; i<r.size(); ++i ){
        Mat aux = m1.colRange(i*new_row*new_col,(i+1)*new_row*new_col).rowRange(0,1);
        r[i] = aux.reshape(0, new_col);
        r[i] = r[i].t();
    }

    Mat result;
    merge(r, result);
    return result;
} 

Here is an example:

Mat_ <Vec3b> m(2,4);
m(0,0) = Vec3b(1,9,17);
m(0,1) = Vec3b(3,11,19);
m(0,2) = Vec3b(5.1,13,21);
m(0,3) = Vec3b(7,15,23);
m(1,0) = Vec3b(2,10,18);
m(1,1) = Vec3b(4,12,20);
m(1,2) = Vec3b(6,14,22);
m(1,3) = Vec3b(8,16,24);
cout << m << endl;
cout << m.reshape(2,4) << endl;
cout << matlab_reshape(m,4,3,2) << endl;

Performance Comparison of reshaping matrices of [24700 X 10 X 1]size to matrices of [130 X 190 X 10] size

MY_CODE      MATLAB
0.006222     0.000039 
0.006528     0.000036
0.006716     0.000042
0.006733     0.000035
0.006508     0.000031

I appreciate any suggestion to make my code faster.



Solution 1:[1]

The difference b/w MATLAB and Opencv reshape is, MATLAB reads src_vals columns wise and fills columns wise, but in OpenCV, it reads src_vals rows wise and fills rows wise.

cv::Mat reshape(cv::Mat src, int cn, int rows, int cols)
{
    const std::vector<int> newshape = {cols, rows};
    cv::Mat result = src.reshape(cn, newshape).t();//OpenCV function reshape.
    return result;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1