c – 如何有效地将cv :: Mat的给定通道设置为给定值而不改变其他通道?

如何有效地将cv :: Mat的给定通道设置为给定值而不改变其他通道?例如,我想将其第四个通道(Alpha通道)值设置为120(即半透明),如下所示:
cv::Mat mat; // with type CV_BGRA
...
mat.getChannel(3) = Scalar(120); // <- this is what I want to do

P.S .:我的当前解决方案首先将mat拆分成多个通道,并设置alpha通道,然后将它们合并.

P.S.2:我知道如果我也想改变其他渠道,我可以快速做到这一点:

mat.setTo(Scalar(54,154,65,120));

更新与广义解决方案:

两种方法都可用于将给定通道上的所有垫值设置为给定值.并且它们将适用于所有矩阵,无论它们是否连续.

方法1 – 更有效率

– >基于@ Antonio的答案,并由@MichaelBurdinov进一步改进

// set all mat values at given channel to given value
void setChannel(Mat &mat,unsigned int channel,unsigned char value)
{
    // make sure have enough channels
    if (mat.channels() < channel + 1)
        return;

    const int cols = mat.cols;
    const int step = mat.channels();
    const int rows = mat.rows;
    for (int y = 0; y < rows; y++) {
        // get pointer to the first byte to be changed in this row
        unsigned char *p_row = mat.ptr(y) + channel; 
        unsigned char *row_end = p_row + cols*step;
        for (; p_row != row_end; p_row += step)
            *p_row = value;
    }
}

方法2 – 更优雅

– >基于@ MichaelBurdinov的答案

// set all mat values at given channel to given value
void setChannel(Mat &mat,unsigned char value)
{
    // make sure have enough channels
    if (mat.channels() < channel+1)
        return;

    // check mat is continuous or not
    if (mat.isContinuous())
        mat.reshape(1,mat.rows*mat.cols).col(channel).setTo(Scalar(value));
    else{
        for (int i = 0; i < mat.rows; i++)
            mat.row(i).reshape(1,mat.cols).col(channel).setTo(Scalar(value));
    }
}

P.S .:值得注意的是,根据documentation,使用Mat :: create()创建的矩阵始终是连续的.但是,如果使用Mat :: col(),Mat :: diag()等提取矩阵的一部分,或者为外部分配的数据构造矩阵头,则此类矩阵可能不再具有此属性.

解决方法

如果您的图像在内存中是连续的,您可以使用以下技巧:
mat.reshape(1,mat.rows*mat.cols).col(3).setTo(Scalar(120));

如果不连续:

for(int i=0; i<mat.rows; i++)
    mat.row(i).reshape(1,mat.cols).col(3).setTo(Scalar(120));

编辑(感谢Antonio发表评论):

请注意,这段代码可能是最短的,它没有分配新的内存,但根本没有效率.它可能甚至比分割/合并方法更慢.当OpenCV对于连续1个像素的非连续矩阵执行操作时,效率是非常低的.如果时间性能很重要,您应该使用@Antonio提出的解决方案.

只是他的解决方案略有改进:

const int cols = img.cols;
const int step = img.channels();
const int rows = img.rows;
for (int y = 0; y < rows; y++) {
    unsigned char* p_row = img.ptr(y) + SELECTED_CHANNEL_NUMBER; //gets pointer to the first byte to be changed in this row,SELECTED_CHANNEL_NUMBER is 3 for alpha
    unsigned char* row_end = p_row + cols*step;
    for(; p_row != row_end; p_row += step)
         *p_row = value;
    }
}

这可以节省x的增量操作和一个较小的寄存器值.在资源有限的系统上,可以提供〜5%的加速.否则时间表现将是一样的.

相关文章

一.C语言中的static关键字 在C语言中,static可以用来修饰局...
浅谈C/C++中的指针和数组(二) 前面已经讨论了指针...
浅谈C/C++中的指针和数组(一)指针是C/C++...
从两个例子分析C语言的声明 在读《C专家编程》一书的第三章时...
C语言文件操作解析(一)在讨论C语言文件操作之前,先了解一下...
C语言文件操作解析(三) 在前面已经讨论了文件打开操作,下面...