我是一名计算机视觉工程师,经常使用OpenCV库。我经常使用unsigned short
类型的原始数据,必须将其分配给OpenCV的cv::Mat
对象。
这个cv::Mat
对象有一个名为data的字段,无论数据的类型如何,该字段都是unsigned char*
类型。
因此,我将unsigned short*
数据分配给unsigned char*
Mat.data的操作如下:
// Obtain raw data from the hardware
const unsigned short* rawData = engine->getRawData();
// Create Mat with right dimensions and of type 16 Bit unsigned and 1 channel (unsigned short)
cv::Mat Test = cv::Mat::zeros(480, 640, CV_16UC1);
// Assign data by casting rawData to unsigned char* type
Test.data = (unsigned char*) rawData;
// Convert Test to 8Bit unsigned so I can visualize it
Test.convertTo(irIm, CV_8UC1);
我在很多情况下使用这个方法,它工作得很好,但我从来没有真正理解它为什么工作。我有一个unsigned short类型的数据块,然后我把它转换为unsigned char*
,程序不会崩溃,也没有数据丢失。
谁能帮我理解这个?
编辑:关于我得到的答案。我知道这些数据仍然是有效的,但解释不同,但它在我的脑海里仍然没有意义。
假设我有以下短代码:0010000100001000。现在,我用计算器算出这个短表示8456的十进制形式。如果我把它解释为unsigned char,我将把它读成两个字节,然后我有00100001字节,然后是00001000,这绝不代表之前的短值。
所以我的问题仍然成立。在我的脑海中唯一有意义的是,OpenCV在某种程度上期待这些类型转换,并将在内部转换数据,这样它就不会失去意义。
人们通常将原始字节缓冲区定义为unsigned char*
,因为unsigned char
在语义上是一个字节。更好的方法可能是使用标准化的整数类型,如uint8_t
,但两者都可以看到。
从一种指针类型转换为另一种指针类型只是改变了它所指向数据的解释。它不触及数据本身。
与void*
类似的情况有时人们使用这种类型来传递未指定内容的缓冲区。然而,对于void*
,您不能使用指针算术的标准语法,在内部这样的指针通常被强制转换为适当的类型(或作为单独的字节处理)。
c++有一个内存模型,它认为计算机内存是字节可寻址的:
c++程序可用的内存由一个或多个连续字节序列组成。每个字节都有一个唯一的地址。c++标准
, [intro.memory] /1
由于历史原因,c++使用字符类型 char
, unsigned char
和signed char
,而不是使用byte
类型来按字节访问内存字节:
类型为
T
的对象的对象表示是占用的N
unsigned char
对象的序列类型为T
的对象,其中N
=sizeof(T)
。
——同上,[basic.types]/4
这意味着通过将数据指针强制转换为unsigned char *
来访问程序内存始终是合法的。
data
字段是指向矩阵数据的指针。
在(unsigned char*)
中是预期的。可以将不同类型的指针强制转换为(unsigned char*)
。它们仍然指向存储rawData
的相同内存地址。
但重要的是,当您创建矩阵时,您指定数据类型为CV_16UC1
。(其中一个元素是16位的无符号。见文档)。
因此,如果在您的机器中short
是2字节,那么(unsigned short*)
可以转换为(unsigned char*)
,并且矩阵仍然有效。