拆分OpenCV Mat而不复制数据

ma.*_*ian 2 c++ opencv

我有一个RGB图像,我试图在R通道上做一些修改.所以我做了以下类似的事情:

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

但似乎OpenCV chs按值复制数据(不是通过引用).结果img矩阵没有改变.但由于内存限制,我不喜欢使用merge功能.

有没有其他方法可以将矩阵就地分割?

Mik*_*iki 5

split 将始终复制数据,因为它正在创建新的矩阵.

比如说,红色频道最简单的工作方式是使用splitmerge:

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);
Run Code Online (Sandbox Code Playgroud)

请注意,merge不会分配任何新的内存,所以如果你split没问题,没有任何理由不打电话merge.


您可以直接在R通道上工作:

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

// Work on red channel, [2]
img(2,3)[2] = 5;
Run Code Online (Sandbox Code Playgroud)

如果你想保存使用的内存split,你可以直接在红色通道上工作,但它更麻烦:

#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;
}
Run Code Online (Sandbox Code Playgroud)

您可以通过仅在新矩阵中复制红色通道(避免为其他通道分配空间),然后将结果复制回原始图像来找到一个很好的折衷方案:

#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;
}
Run Code Online (Sandbox Code Playgroud)

感谢 @sturkmen审核答案