0. 简介
之前我们在《经典文献阅读之—R-PCC(基于距离图像的点云压缩方法)》中提到了,我们可以通过一些算法层面来完成数据的压缩,而其实更简单或者说更直接的方法就是使用half这种形式来完成数据压缩。
1. half和float
Half是用16位表示浮点数的一种数据类型,在IEEE 754中也有规定,这种数据类型在深度学习系统中的应用比较广泛。但是在当前主流cpu上,不支持half类型数据的计算和输出,所以需要half和float两个数据类型之间的转换。
图1是16位浮点表示的标准,其中包括了1个符号位,5个指数位和10个尾数位。对于正常的数值,其结果如下表示。
图2是32位浮点数表示的标准,其中包括1个符号位,8个指数位和23个尾数位。对于正常的数值,其结果如下表示。
所以对于half和float之间的转换,除了不同部分的移位之外,还要做注意指数的基数之间的差别(15和127)。要把half类型转换为float类型,主要进行以下几步操作。
- 符号位左移16位。
- 指数部分加112(127与15之间的差距),左移13位(右对齐)。
- 尾数部分左移13位(左对齐)。
2. half与float参考代码
下面是对应的参考代码:
typedef unsigned short ushort;//占用2个字节
typedef unsigned int uint; //占用4个字节
uint as_uint(const float x) {
return *(uint*)&x;
}
float as_float(const uint x) {
return *(float*)&x;
}
float half_to_float(const ushort x) { // IEEE-754 16-bit floating-point format (without infinity): 1-5-10, exp-15, +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits
const uint e = (x&0x7C00)>>10; // exponent
const uint m = (x&0x03FF)<<13; // mantissa
const uint v = as_uint((float)m)>>23; // evil log2 bit hack to count leading zeros in denormalized format
return as_float((x&0x8000)<<16 | (e!=0)*((e+112)<<23|m) | ((e==0)&(m!=0))*((v-37)<<23|((m<<(150-v))&0x007FE000))); // sign : normalized : denormalized
}
ushort float_to_half(const float x) { // IEEE-754 16-bit floating-point format (without infinity): 1-5-10, exp-15, +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits
const uint b = as_uint(x)+0x00001000; // round-to-nearest-even: add last bit after truncated mantissa
const uint e = (b&0x7F800000)>>23; // exponent
const uint m = b&0x007FFFFF; // mantissa; in line below: 0x007FF000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
return (b&0x80000000)>>16 | (e>112)*((((e-112)<<10)&0x7C00)|m>>13) | ((e<113)&(e>101))*((((0x007FF000+m)>>(125-e))+1)>>1) | (e>143)*0x7FFF; // sign : normalized : denormalized : saturate
}
//下面的demo中,yolov5_outputs[0].buf是void *类型的,void *类型不能++,因此先转换成ushort*类型。
float *data0 = (float*)malloc(4 * output_attrs[0].n_elems);
float *data1 = (float*)malloc(4 * output_attrs[1].n_elems);
float *data2 = (float*)malloc(4 * output_attrs[2].n_elems);
unsigned short *temp0 = (ushort*)yolov5_outputs[0].buf;
unsigned short *temp1 = (ushort*)yolov5_outputs[1].buf;
unsigned short *temp2 = (ushort*)yolov5_outputs[2].buf;
for(int i=0; i < output_attrs[0].n_elems;i++)
{
data0[i] = half_to_float(temp0[i]);
}
for(int i=0; i < output_attrs[1].n_elems;i++)
{
data1[i] = half_to_float(temp1[i]);
}
for(int i=0; i < output_attrs[2].n_elems;i++)
{
data2[i] = half_to_float(temp2[i]);
3. float与uint16
求在串口通信时常常会被用到,串口只能以字符型(char)进行通信
atof():将字符串转换为双精度浮点型值。
atoi():将字符串转换为整型值。
浮点转uint16函数
uint16_t float_cov_uint16(float value)
{
const Fp32 f32infty = { 255U << 23 };
const Fp32 f16infty = { 31U << 23 };
const Fp32 magic = { 15U << 23 };
const uint32_t sign_mask = 0x80000000U;
const uint32_t round_mask = ~0xFFFU;
Fp32 in;
uint16_t out;
in.f = value;
uint32_t sign = in.u & sign_mask;
in.u ^= sign;
if (in.u >= f32infty.u) /* Inf or NaN (all exponent bits set) */
{
/* NaN->sNaN and Inf->Inf */
out = (in.u > f32infty.u) ? 0x7FFFU : 0x7C00U;
}
else /* (De)normalized number or zero */
{
in.u &= round_mask;
in.f *= magic.f;
in.u -= round_mask;
if (in.u > f16infty.u)
{
in.u = f16infty.u; /* Clamp to signed infinity if overflowed */
}
out = uint16_t(in.u >> 13); /* Take the bits! */
}
out = uint16_t(out | (sign >> 16));
return out;
}
uint16转float函数
float uint6_cov_float(uint16_t value)
{
const Fp32 magic = { (254U - 15U) << 23 };
const Fp32 was_infnan = { (127U + 16U) << 23 };
Fp32 out;
out.u = (value & 0x7FFFU) << 13; /* exponent/mantissa bits */
out.f *= magic.f; /* exponent adjust */
if (out.f >= was_infnan.f) /* make sure Inf/NaN survive */
{
out.u |= 255U << 23;
}
out.u |= (value & 0x8000U) << 16; /* sign bit */
return out.f;
}
4. PCL简单的转换代码
对于使用PCL而言,我们可以采用另一种形式
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <vector>
#include <iostream>
typedef pcl::PointCloud<pcl::PointXYZ> PointCloudXYZ;
PointCloudXYZ get_pcl(std::vector<unsigned short> points)
{
PointCloudXYZ cloud;
cloud.width = points.size();
cloud.height = 1;
cloud.is_dense = false;
cloud.points.resize(cloud.width * cloud.height);
for (int i = 0; i < points.size()-3; i+=3)
{
cloud.points[i].x = static_cast<float>(points[i]);
cloud.points[i].y = static_cast<float>(points[i+1]);
cloud.points[i].z = static_cast<float>(points[i+2]);
}
return cloud;
}
std::vector<unsigned short> get_point(PointCloudXYZ pcl) {
std::vector<unsigned short> result;
for (const auto &point : pcl.points) {
// convert x, y, z from float to unsigned short
unsigned short x = static_cast<unsigned short>(point.x);
unsigned short y = static_cast<unsigned short>(point.y);
unsigned short z = static_cast<unsigned short>(point.z);
// add to result vector
result.push_back(x);
result.push_back(y);
result.push_back(z);
}
return result;
}
int main(int argc, char** argv)
{
std::vector<unsigned short> points = {1, 2, 3, 4, 5};
PointCloudXYZ cloud = get_pcl(points);
points = get_point(cloud);
// Output the point cloud to verify the conversion
std::cout << "Point cloud data: " << std::endl;
for (int i = 0; i < cloud.points.size(); i++)
std::cout << cloud.points[i].x << " " << cloud.points[i].y << " " << cloud.points[i].z << std::endl;
return 0;
}
评论(0)
您还未登录,请登录后发表或查看评论