C ++中的逐位数学运算(Bitwise math operations in C++)

编程入门 行业动态 更新时间:2024-10-28 06:21:27
C ++中的逐位数学运算(Bitwise math operations in C++)

我正在尝试理解一个读取和转换存储为16位png文件的深度数据的函数 。

首先,他们将文件加载到CV_16UC1类型的opencv Mat中

cv::Mat depth_image = cv::imread(filename.c_str(), CV_LOAD_IMAGE_ANYDEPTH);

然后他们分配

unsigned short * depth_raw = new unsigned short[frame_height * frame_width]; for (int i = 0; i < frame_height * frame_width; ++i) { depth_raw[i] = ((((unsigned short)depth_image.data[i * 2 + 1]) << 8) + ((unsigned short)depth_image.data[i * 2 + 0])); depth_raw[i] = (depth_raw[i] << 13 | depth_raw[i] >> 3); depth_data[i] = float((float)depth_raw[i] / 1000.0f); }

现在我知道C ++中的“<<”运算符类似于位移,意味着5 << 1对应于下面的位移:“00000101”(二进制为5) - >“00001010”(这是10二进制)。 因此,可以使用“<< n”或“>> n”进行乘法和除法2 ^ n。

我仍然觉得很难理解上面的转变。 以下是上述转换的数字示例(将cout应用于每个步骤):

depth_image.data[i] = 192 depth_image.data[2*i+1] = 47 depth_image.data[2*i+0] = 192 (((unsigned short)depth_image.data[i * 2 + 1]) << 8) = 12032 ((unsigned short)depth_image.data[i * 2 + 0]) = 192 depth_raw[i] = 12224 depth_raw[i] << 13 = 0 depth_raw[i] >> 3 = 191 depth_raw[i] << 13 | depth_raw[i] >> 3 = 191 depth_data[i] = 1.528

真正奇怪的是最后一行:似乎从unsigned short转换为float将数字191转换为1528 ???

任何帮助或提示将不胜感激。

编辑: 我找到了一些Matlab代码,显示了作者之前如何保存深度图像:

% resave depth map with bit shifting depthRaw = double(imread(filename))/1000; saveDepth (depthRaw,newFilename); function saveDepth (depth,filename) depth(isnan(depth)) =0; depth =single(depth)*1000; depthVis = uint16(depth); depthVis = bitor(bitshift(depthVis,3), bitshift(depthVis,3-16)); imwrite(depthVis,filename); end

所以它看起来像一个奇怪的节约......

EDIT2: 作者的回复: “深度贴图以3位移动的方式保存,使PNG格式的深度更加令人赏心悦目。因此,我们需要在文件读取过程中将其移回”。

I'm trying to understand a function that reads and transforms depth data stored as 16-bit png file.

First they load the file into a opencv Mat of type CV_16UC1

cv::Mat depth_image = cv::imread(filename.c_str(), CV_LOAD_IMAGE_ANYDEPTH);

Then they assign

unsigned short * depth_raw = new unsigned short[frame_height * frame_width]; for (int i = 0; i < frame_height * frame_width; ++i) { depth_raw[i] = ((((unsigned short)depth_image.data[i * 2 + 1]) << 8) + ((unsigned short)depth_image.data[i * 2 + 0])); depth_raw[i] = (depth_raw[i] << 13 | depth_raw[i] >> 3); depth_data[i] = float((float)depth_raw[i] / 1000.0f); }

Now I know that the "<<" operator in C++ is something like a bit shift, meaning 5 << 1 corresponds to the following bit-shift: "00000101" (which is 5 in binary) -> "00001010" (which is 10 in binary). So apparantly one can do multiplications and divisions by 2^n using "<< n" or ">> n".

Still I find it hard to understand the transformation above. Here is an example with numbers (applying cout to every step) for the above transformation:

depth_image.data[i] = 192 depth_image.data[2*i+1] = 47 depth_image.data[2*i+0] = 192 (((unsigned short)depth_image.data[i * 2 + 1]) << 8) = 12032 ((unsigned short)depth_image.data[i * 2 + 0]) = 192 depth_raw[i] = 12224 depth_raw[i] << 13 = 0 depth_raw[i] >> 3 = 191 depth_raw[i] << 13 | depth_raw[i] >> 3 = 191 depth_data[i] = 1.528

What is really weird is the last line: It seems like the conversion from unsigned short to float is converting the number 191 into 1528 ???

Any help or hint will be appreciated.

Edit: I found some Matlab code that shows how the authors saved the depth image previously:

% resave depth map with bit shifting depthRaw = double(imread(filename))/1000; saveDepth (depthRaw,newFilename); function saveDepth (depth,filename) depth(isnan(depth)) =0; depth =single(depth)*1000; depthVis = uint16(depth); depthVis = bitor(bitshift(depthVis,3), bitshift(depthVis,3-16)); imwrite(depthVis,filename); end

So it looks like a weird saving...

Edit2: Reply from the authors: "The depth map is saved in a way that it shifts 3 bits to make the depth in PNG format more pleasing to human eyes. Therefore we need to shift it back during file reading".

最满意答案

没有共同的规范,如何存储数据。 因此,可能需要从小端转换为大端或相反的方式。 要了解endianess,请访问: https : //en.wikipedia.org/wiki/Endianness

depth_raw[i] = ((((unsigned short)depth_image.data[i * 2 + 1]) << 8) + ((unsigned short)depth_image.data[i * 2 + 0]));

这句话是对结尾的转换。 第一个字节转换为无符号短路(从8位到16位),然后向右移动,然后在低端添加第二个字节。 它基本上交换两个字节并将其转换为unsigned int。

depth_raw[i] = (depth_raw[i] << 13 | depth_raw[i] >> 3); depth_data[i] = float((float)depth_raw[i] / 1000.0f);

在转换endianess之后,必须解释数据。 确定作者在此处打算做什么的唯一方法是查看深度图的文档。 第一行将3个最低有效位移到前面,其他位向下移动。 我不知道为什么要这样做。 我认为在此之后除以1000只是为了校正单位(可能是以mm为单位的m或km),或者是某种固定点语义。 (在整数数据类型中重新理解有理数)。

there is no common norm, how data is stored. Therefore it may be neccessary to convert from little to big endian or the other way around. To understand endianess have a look here: https://en.wikipedia.org/wiki/Endianness

depth_raw[i] = ((((unsigned short)depth_image.data[i * 2 + 1]) << 8) + ((unsigned short)depth_image.data[i * 2 + 0]));

This statement is a convertion of endianess. the first byte is cast to unsigned short (from 8 to 16 bit) and then shifted right and then the second byte is added at the lower end. It basically swaps two bytes and converts it to an unsigned int.

depth_raw[i] = (depth_raw[i] << 13 | depth_raw[i] >> 3); depth_data[i] = float((float)depth_raw[i] / 1000.0f);

After the convertion of endianess, the data has to be interpreted. The only way to be sure what the authors inteded to do here is to have a look at the documentation of the depth map. The first line moves the 3 least significant bits to the front and the others down. I have no idea, why this is done. I think the division by 1000 after that is only to correct for units (maybe m in mm or km in m), or it some kind of fixed point semantic. (represantion of rational number in interger data type).

更多推荐

本文发布于:2023-08-07 20:38:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1465656.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:位数   Bitwise   operations   math

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!