Search code examples
c++opencvmat

Two-channel cv::Mat object filled with row-col indexes without for cycle


I want to create a two-channel matrix in OpenCV, whose values are the corresponding pair of row and column indexes. I can easily do that in the following way:

for (int i = 0 ; i< img_height ; ++ i){
    for (int j = 0 ; j < img_width ; ++ j){
        src.ptr<Point2f>(i)[j] = Point2f(j,i);
    }
}

I wonder if there is a way in OpenCV to initialize such a matrix in a faster and more compact way, without necessarily using this element-wise approach. I searched on the documentation, but I didn't find anything that could help me for this purpose.

I ask that because I do need my application to be faster, so I'm looking for any possible improvements I can apply on my code.

Thanks in advance


Solution

  • There's no builtin function to to this. You can eventually mimic the Matlab function meshgrid using repeat, but in this case is going to be much slower.

    You can however improve a few things:

    • get the pointer to the beginning of the line out of the inner loop, since it will be the same for each line.
    • avoid to create a temporary object to store values.
    • I think you swapped i and j.

    Have a look at this code:

    Mat2f src(img_height, img_width);
    
    for (int i = 0; i < img_height; ++i) {
        Vec2f* ptr = src.ptr<Vec2f>(i);
        for (int j = 0; j < img_width; ++j) {
            ptr[j][0] = i;
            ptr[j][1] = j;
        }
    }
    

    This snippet is a little faster (time in ms):

    @MarcoFerro:    1.22755
    @Miki:          0.818491
    

    Testing code:

    #include <opencv2/opencv.hpp>
    using namespace cv;
    using namespace std;
    
    int main()
    {
        int img_height = 480;
        int img_width = 640;
    
        {
            Mat2f src(img_height, img_width);
    
            double tic = double(getTickCount());
            for (int i = 0; i< img_height; ++i){
                for (int j = 0; j < img_width; ++j){
                    src.ptr<Point2f>(i)[j] = Point2f(i, j);
                }
            }
    
            double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
            cout << "@MarcoFerro: \t" << toc << endl;
        }
        {
            Mat2f src(img_height, img_width);
    
            double tic = double(getTickCount());
            for (int i = 0; i < img_height; ++i) {
                Vec2f* ptr = src.ptr<Vec2f>(i);
                for (int j = 0; j < img_width; ++j) {
                    ptr[j][0] = i;
                    ptr[j][1] = j;
                }
            }
    
            double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
            cout << "@Miki: \t\t" << toc << endl;
        }
    
        getchar();
        return 0;
    }