Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Split OpenCV Mat without copying the data

Tags:

c++

opencv

I have a RGB image and I trying to do some modification on R channel. So I do similar to the following:

Mat img;
vector<Mat> chs;
//.... 
split(img, chs);
//some modification on chs[2]
imshow("Result", img);

But it seems that OpenCV copy data to chs by value (not by reference). As a result the img matrix not changed. But due to memory limitations I don't prefer to use merge function.

Is there any alternative to split the matrix in-place?

like image 825
ma.mehralian Avatar asked Mar 15 '23 07:03

ma.mehralian


1 Answers

split will always copy the data, since it's creating new matrices.

The simplest way to work on, say, red channel will be using split and merge:

Mat3b img(10,10,Vec3b(1,2,3));

vector<Mat1b> planes;
split(img, planes);

// Work on red plane
planes[2](2,3) = 5;

merge(planes, img);

Note that merge doesn't allocate any new memory, so if you're ok with split, there isn't any good reason not to call also merge.


You can always work on the R channel directly:

Mat3b img(10,10,Vec3b(1,2,3));

// Work on red channel, [2]
img(2,3)[2] = 5;

If you want to save the memory used by split, you can work directly on the red channel, but it's more cumbersome:

#include <opencv2\opencv.hpp>
using namespace cv;

int main()
{
    Mat3b img(10,10,Vec3b(1,2,3));

    // Create a column matrix header with red plane unwound
    // No copies here
    Mat1b R = img.reshape(1, img.rows*img.cols).colRange(2, 3);

    // Work on red plane
    int r = 2;
    int c = 3;

    // You need to access by index, not by (row, col).
    // This will also modify img
    R(img.rows * r + c) = 5;

    return 0;
}

You can probably find a good compromise by copying the red channel only in a new matrix (avoiding to allocate space also for other channels), and then by copying the result back into original image:

#include <opencv2\opencv.hpp>
using namespace cv;

int main()
{
    Mat3b img(10,10,Vec3b(1,2,3));

    // Allocate space only for red channel
    Mat1b R(img.rows, img.cols);
    for (int r=0; r<img.rows; ++r)
        for(int c=0; c<img.cols; ++c)
            R(r, c) = img(r, c)[2];

    // Work on red plane
    R(2,3) = 5;

    // Copy back into img
    for (int r = 0; r<img.rows; ++r)
        for (int c = 0; c<img.cols; ++c)
            img(r, c)[2] = R(r,c);


    return 0;
}

Thanks to @sturkmen for reviewing the answer

like image 172
Miki Avatar answered Mar 28 '23 09:03

Miki