如何有效地将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%的加速.否则时间表现将是一样的.