C++ 中的按位数学运算

Bitwise math operations in C++

我正在尝试理解 function 读取和转换存储为 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 shortfloat的转换是将数字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

所以它看起来像一个奇怪的储蓄...

编辑2:
作者回复:
"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"。

数据的存储方式没有共同的规范。因此,可能需要从小端转换为大端或相反。要了解字节顺序,请看这里: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]));

这个语句是字节序的转换。第一个字节转换为 unsigned short(从 8 位到 16 位),然后右移,然后在低端添加第二个字节。它基本上交换两个字节并将其转换为无符号整数。

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

字节序转换后,需要对数据进行解释。确定作者在这里打算做什么的唯一方法是查看深度图的文档。第一行将 3 个最低有效位移到前面,将其他位移到后面。我不知道,为什么这样做。我认为之后除以 1000 只是为了校正单位(可能是毫米单位的米或米单位的公里),或者它是某种固定点语义。 (整数数据类型中有理数的表示)。