如何将 T 类型的值赋给 uchar 类型的 data[i] 而不会造成任何损失?
Posted
技术标签:
【中文标题】如何将 T 类型的值赋给 uchar 类型的 data[i] 而不会造成任何损失?【英文标题】:How to assign a value of type T to data[i] of type uchar without any loss? 【发布时间】:2019-04-09 22:15:50 【问题描述】:场景
我想创建我自己的SetChannel
函数来设置图像的特定通道。例如,我有一个CV_16UC3
类型的图像input
(ushort
类型的BGR 图像),我想将绿色通道(=1,由于基于零的索引)更改为ushort
值@987654326 @。为此,我调用了SetChannel(input,1,32768)
。
template<typename T>
void SetChannel(Mat mat, uint channel, T value)
const uint channels = mat.channels();
if (channel + 1 > channels)
return;
T * data = (T*)mat.data;
// MBPR : number of Memory Block Per Row
// Mat.step : number of byte per row
// Mat.elemSize1() : number of byte per channel
const unsigned int MBPR = mat.step / mat.elemSize1();
// N : total number of memory blocks
const unsigned int N = mat.rows * MBPR;
for (uint i = channel; i < N; i += channels)
data[i] = value;
我更喜欢在单个循环中工作而不是嵌套循环,所以我定义了上面给出的迭代次数N
。
上面的代码按预期工作但是其他人说的部分
T * data = (T*)mat.data;
是一种代码味道,被认为是设计糟糕的程序。
现在我想用另一种方法重写新的,如下所示。
它没有按预期工作,因为我不知道如何将 T value
分配给 data[i]
类型的 uchar
。
template<typename T>
void SetChannel(Mat mat, uint channel, T value)
const uint channels = mat.channels();
if (channel + 1 > channels)
return;
uchar * data = mat.data;
const unsigned int N = mat.rows * mat.step;// byte per image
const unsigned int bpc = mat.elemSize1();// byte per channel
const unsigned int bpp = mat.elemSize(); // byte per pixel
for (uint i = channel * bpc; i < N; i += bpp)
//data[i] = value;
问题
如何将T
类型的value
分配给uchar
类型的data[i]
而不会有任何损失?
对于那些不知道Mat
是怎样的人,以下内容可能有用。
关于OpenCVMat
类
OpenCV 提供了一堆类型的图像。例如,
CV_8UC1
表示灰度图像类型,其中每个像素都有一个uchar
类型的通道。
CV_8UC3
表示 BGR(不是 RGB)图像类型,其中每个像素有三个通道,每个通道类型为 uchar
。
CV_16UC3
代表BGR(不是RGB)图像类型,其中每个像素有三个通道,每个通道类型为ushort
。
等
Mat
是封装图像的类。它有几个属性和功能。让我列出一些我将在这个问题中使用的内容,以便您更好地理解我的场景。
Mat.data
:uchar
类型的指针,指向图像像素块。
Mat.rows
: 行数
Mat.channels()
: 每个像素的通道数
Mat.elemSize1()
(以 1 结尾):每个通道的字节数
Mat.elemSize()
:每个像素的字节数。
Mat.elemSize() = Mat.channels() * Mat.elemSize1()
。
Mat.step
: 每行字节数
这里Mat.step
可以认为是
- 每行的“有效”像素数(让我将其命名为 EPPR),
- 每个像素的通道数或Mat.channels()
,以及
- 每个通道的字节数或Mat.elemSize1()
。
数学上,
Mat.step = EPPR * Mat.elemSize()
Mat.step = EPPR * Mat.channels() * Mat.elemSize1()
让我将EPPR * Mat.channels()
定义为每行的内存块 (MBPR
)。如果你知道MBPR
的正确术语,请告诉我。
因此,MBPR = Mat.step / Mat.elemSize1()
。
【问题讨论】:
您应该在模板中有一个测试来检查 T 以确保它与 uchar 兼容,然后使用static_cast<T*>
而不是 C-casting。
【参考方案1】:
我是从某个离线的人那里得到的。希望它对其他人也有用。
template<typename T>
void SetChannel(Mat mat, uint channel, T value)
const uint channels = mat.channels();
if (channel + 1 > channels)
return;
uchar * data = mat.data;
const unsigned int N = mat.rows * mat.step;// byte per image
const unsigned int bpc = mat.elemSize1();// byte per channel
const unsigned int bpp = mat.elemSize(); // byte per pixel
const unsigned int bpu = CHAR_BIT * sizeof(uchar);// bits per uchar
for (uint i = channel * bpc; i < N; i += bpp)
for (uint j = 0; j < bpc; j++)
data[i + j] = value >> bpu * j;
【讨论】:
不幸的是,由于嵌套循环,这种新方法的运行速度比前一种方法慢了大约 2 倍。以上是关于如何将 T 类型的值赋给 uchar 类型的 data[i] 而不会造成任何损失?的主要内容,如果未能解决你的问题,请参考以下文章
我们不能将一个以0(零)开头的值赋给变量吗?例如:a = 0123。抛出错误“无效令牌”[重复]