这是 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?
ADD:根据下面的评论(谢谢),我是这样测试的。看起来 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 位无符号 int 不同,后者至少在我测试的平台(godbolt 的 x86-64 gcc)上给出 0。
这种事情是非常令人困惑,甚至可能依赖于平台(可能取决于操作系统、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)
在我的平台中,我猜你的平台也是一样的,算法似乎如下:
func(x) {
var x_new = truncate_decimal(x);
return x_new % 256;
}
疯狂,但它似乎只是截断浮动部分,然后用 256 取模或您要转换为的任何类型的大小(我猜对于 16 位,它会对 65536 取模)。