如何将 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 类型的图像inputushort 类型的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.datauchar 类型的指针,指向图像像素块。 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&lt;T*&gt; 而不是 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] 而不会造成任何损失?的主要内容,如果未能解决你的问题,请参考以下文章

C语言中 无符号变量的值赋给有符号的变量

类型转换

我们不能将一个以0(零)开头的值赋给变量吗?例如:a = 0123。抛出错误“无效令牌”[重复]

如何将JS里变量的值赋给文本框

VC中如何将一个二维数组的值赋给另一个二维数组?只能用一行。

66.类型转换