如何有效地将cv::Mat的给定通道设置为给定值,而不更改其他通道
How to set given channel of a cv::Mat to a given value efficiently without changing other channels?
如何在不更改其他通道的情况下有效地将cv::Mat
的给定通道设置为给定值?例如,我想将其第四个通道(alpha通道(值设置为120
(即半透明(,类似于:
cv::Mat mat; // with type CV_BGRA
...
mat.getChannel(3) = Scalar(120); // <- this is what I want to do
第页。S.:我目前的解决方案是首先将mat
拆分为多个通道并设置alpha通道,然后将它们合并回来。
第页。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 int channel, 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.:值得注意的是,根据文档,使用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%的加速。否则时间性能将相同。
Mat img;
[...]
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
for (int x = 0; x < cols; x++) {
*p_row = value;
p_row += step; //Goes to the next byte to be changed
}
}
注意:根据opencv术语的使用,这适用于连续矩阵和不连续矩阵:http://docs.opencv.org/modules/core/doc/basic_structures.html#bool%20Mat::isContinuous%28%29%20const
关于直接Mat::数据访问(我很确定setTo((或oother opencv-Mat-api使用类似的解决方案(:
template<int N>
void SetChannel(Mat &img, unsigned char newVal) {
for(int x=0;x<img.cols;x++) {
for(int y=0;y<img.rows;y++) {
*(img.data + (y * img.cols + x) * img.channels() + N) = newVal;
}
}
}
int main() {
Mat img = Mat::zeros(1000, 1000, CV_8UC4);
SetChannel<3>(img, 120);
imwrite("out.jpg", img);
return 0;
}
简单算法:
void SetChannel(Mat mat, uint channel, uchar value)
{
const uint channels = mat.channels();
if (channel > channels - 1)
return;
uchar * data = mat.data;
uint N = mat.rows * mat.step / mat.elemSize1();
for (uint i = channel; i < N; i += channels)
data[i] = value;
}
- 在执行其他功能的同时播放动画(LED矩阵和Arduino/ESP8266)
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- GL_SHADERSTORAGE_BUFFER位置是否与其他着色器位置冲突
- 为什么我不能在 C++ 中的特定函数重载中调用同一函数的任何其他重载?
- 在其他文件中创建类时在 c++ 项目中不起作用
- 类与私有变量的其他类之间的线程安全性
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- GlobalAlloc而不是其他分配方法
- C++从其他 constexpr 创建 lambda 不能按顺序执行 Constexpr
- 断言中的Fold表达式在某些计算机上编译,但在其他计算机上不编译
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- 结构和双指针隐藏在其他结构中,多层混淆
- UE4在OnComponentBeginOverlap上铸造其他actor
- 当我在其中一个线程执行中(在activemq-cpp中)捕获到特定值时,我如何终止/停止所有其他线程
- MESI协议和std::atomic-它是否确保所有写入立即对其他线程可见?
- 保留对其他类的成员函数的引用
- 为什么将值返回函数传递给重载=运算符对运算符函数有效,而对其他运算符无效
- 具有包含其他对象的类的对象创建顺序
- 如何有效地将cv::Mat的给定通道设置为给定值,而不更改其他通道