numpy.astype(np.uint8) 如何转换浮点数组? -1.2997805 变成了 255

how does numpy.astype(np.uint8) convert a float array? -1.2997805 became 255

这是在ipython3

执行
In [81]: r2
Out[81]: 
array([-1.2997805, -1.4251276, -1.3047135, ..., -2.0358603, -1.9741256,
       -1.6412157], dtype=float32)

In [82]: r2.astype(np.uint8)
Out[82]: array([255, 255, 255, ..., 254, 255, 255], dtype=uint8)

-1.2997805如何转换为255?

A​​DD :根据下面的评论(谢谢),我是这样测试的。看起来 float 已转换为 int,并且模 255(将其读取为 unsigned int8)已完成。

is first convereted to int. and the it is cut using modulo(%).  
In [98]: b
Out[98]: array([-1.,  0.,  1.])

In [99]: b.astype(np.uint8)
Out[99]: array([255,   0,   1], dtype=uint8)

您转换为 unsigned int 8,其中 -1 对应 255,-2 对应 254 等。 如果你想得到 -1, -2 你必须使用 np.int8:

把它转换成有符号的 int8
>>> np.float32(-2.0358603).astype(np.uint8)
254                                        
>>> np.float32(-2.0358603).astype(np.int8) 
-2                                         

根据 astype 上的 numpy 文档,这是一个“不安全的转换”,意思是“可以进行任何数据转换”。他们没有说明转换是如何完成的,我在快速搜索文档时也没有找到它,所以它可能取决于实现。

我的猜测如下:首先将 32 位浮点数转换为 8 位有符号整数,默认情况下截断为零,例如。 -1.3 变为 -1。然后从无符号 8 位整数转换为 8 位无符号整数,给出值 255。类似

float x = -1.2997805;  # Assume float is 32-bit
(uint8_t)(int8_t)x;

这与使用 (uint8_t)x 直接转换为 8 位无符号整数不同,它至少在我测试的平台(godbolt 的 x86-64 gcc)上给出 0。

这种事情 very confusing 甚至可能依赖于平台(可能取决于 OS、numpy 版本、FP 硬件决定做什么或者处理器是否使用 2s 补码等),所以在不知道你将 运行 代码放在哪个平台的情况下,永远不要依赖这种行为,无论如何,这是一种糟糕的编码实践。令人惊讶的是,我找不到关于 numpy 的转换规则究竟如何工作的参考。

其他答案已经解决并说明了问题。但是,我可以建议一个可能实际有用的替代方案:

np.uint8(np.clip(x, 0, 255))

其中 x 是您的浮点型数组。

此方法确保负数变为 0,而巨大的正数 (> 255) 变为 255。

例如

>>> x = [223.2, 888.2, -32, 255.3, 255]
>>> np.uint8(np.clip(x, 0, 255))
array([223, 255,   0, 255, 255], dtype=uint8)