3

My task is to periodically update a cv::Mat m of r rows and c cols, in this way:

  1. shift by 1 column the whole m to the right, dropping away the last column at position c-1
  2. randomly generate the new column at position 0
  3. refresh the plot of m

This will result in a sort of belt conveyor simulation, for the sake of clarity. However, the problem arises in point 1 when m has to be shifted.

I found two different solutions, namely A and B, both ending in the same result. This suggests me that I'm doing something wrong.

Method A follows:

int offset = 1;
cv::Mat tmp = cv::Mat::zeros(m.size(), m.type());
cv::Rect rect_src(0, 0, m.cols-offset, m.rows);
cv::Rect rect_dst(offset, 0, m.cols-offset, m.rows);

cv::Mat in = m(rect_src);
cv::Mat out = tmp(rect_dst);

in.copyTo(out);
m = temp;

Method B follows:

int offset = 1;
cv::Mat trans_mat = (cv::Mat_<double>(2, 3) << 1, 0, offset, 0, 1, 0);
cv::Mat warped;
warpAffine(m, warped, trans_mat, m.size());
m = warped;

And here's the output as an example small m (random values are spawning on the left):

cycle 1

90      0       0       0       0       0       0       0       0
143     0       0       0       0       0       0       0       0
0       0       0       0       0       0       0       0       0

cycle 2

0       0       90      0       0       0       0       0       0
0       0       143     0       0       0       0       0       0
0       0       0       0       0       0       0       0       0

cycle 3

0       0       144     0       90      0       0       0       0
0       0       161     0       143     0       0       0       0
0       0       0       0       0       0       0       0       0

it is clear that an extra column made of zeros appears somehow... and I really cannot figure how.

P.S. If I set offset = 3 the output scales by a factor 2, and so on.

90      0       0       0       0       0       0       0       0
143     0       0       0       0       0       0       0       0
0       0       0       0       0       0       0       0       0

cycle 2

0       0       0       0       0       0       90      0       0
0       0       0       0       0       0       143     0       0
0       0       0       0       0       0       0       0       0
Patrizio Bertoni
  • 2,582
  • 31
  • 43

1 Answers1

2

Both approach work ok, even if using an affine transform is an overkill here. You probably have an error in the code you didn't show in the question.

Also, you can use colRange, which will simplify your code.

Check that results of both approaches are equivalent, and no extra unwanted columns appears:

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;

int main()
{
    Mat1b img(3, 10);
    randu(img, Scalar(0), Scalar(255));

    Mat1b img2 = img.clone();

    //imshow("img", img);
    //waitKey();

    cout << img << endl << endl;

    int offset = 1;
    Mat trans_mat = (Mat_<double>(2, 3) << 1, 0, offset, 0, 1, 0);

    for (int i = 0; i < 100; ++i)
    {
        // Random data
        Mat1b randomData(img.rows, offset);
        randu(randomData, Scalar(0), Scalar(255));

        // Copying roi
        img.colRange(0, img.cols - offset).copyTo(img.colRange(offset, img.cols));
        randomData.copyTo(img.colRange(0, offset));
        //randu(img.colRange(0, offset), Scalar(0), Scalar(255));

        // Warping
        cv::Mat warped;
        warpAffine(img2, warped, trans_mat, img2.size());

        img2 = warped.clone();
        randomData.copyTo(img2.colRange(0, offset));
        //randu(img2.colRange(0, offset), Scalar(0), Scalar(255));

        //imshow("img", img2);
        //waitKey();

        cout << img << endl << endl;
        cout << img2 << endl << endl;

    }   
    return 0;
}

This are the data of the first iteration.

Original data

[ 91,   2,  79, 179,  52, 205, 236,   8, 181, 239;
  26, 248, 207, 218,  45, 183, 158, 101, 102,  18;
 118,  68, 210, 139, 198, 207, 211, 181, 162, 197]

Data shifted by copying roi

[191,  91,   2,  79, 179,  52, 205, 236,   8, 181;
 196,  26, 248, 207, 218,  45, 183, 158, 101, 102;
  40, 118,  68, 210, 139, 198, 207, 211, 181, 162]

Data shifted by warping

[191,  91,   2,  79, 179,  52, 205, 236,   8, 181;
 196,  26, 248, 207, 218,  45, 183, 158, 101, 102;
  40, 118,  68, 210, 139, 198, 207, 211, 181, 162]
Miki
  • 40,887
  • 13
  • 123
  • 202
  • Great solution!!! but I'm afraid that the "Copying roi" method still have a bug. In facts, my second-last column (which should become the last of the shifted `Mat`) gets lost, while the previous third-last column is now both the second-last and the last. Please check it out at this screenshot https://www.dropbox.com/s/oxhnpn835qk7hpr/screen.PNG?dl=0 – Patrizio Bertoni Nov 17 '15 at 15:51
  • @alpenwolf It works ok for me. Did you changed or added something to this code? – Miki Nov 17 '15 at 15:59
  • I'm afraid I didn't... compiling with MVSC14, opencv 3.0, Win32 platform. – Patrizio Bertoni Nov 17 '15 at 16:19
  • @alpenwolf it works for me with both OpenCV 2.4.9 and OpenCV 3.0, VC12 (Visual Studio 2013). Check data in the answer. – Miki Nov 17 '15 at 16:25
  • Solved... just messing around with other code, he ;) – Patrizio Bertoni Nov 18 '15 at 09:42