【问题标题】:What is an efficient way to scale a int16 numpy array to a int8 numpy array将 int16 numpy 数组缩放为 int8 numpy 数组的有效方法是什么
【发布时间】:2013-06-18 16:40:49
【问题描述】:

我试图找到一种使用特定缩放函数将 2 字节 (-32K -> +32K) numpy int 数组缩放为 8 位 (0 -> 255) 的有效方法。 有效的非常低效的方法是(其中 minVal 和 maxVal 是原始 2 字节 numpy 数组中的最小值和最大值,原始中的 paddingVal 将设置为 0):

...

pixel_array = np.zeros( length, dtype=np.int16)
byte_array = np.zeros( length, dtype=np.uint8)

....

i = 0
for val in np.nditer(pixel_array):
    value = 0.0
    if val == paddingVal:
        byte_array[i] = 0
    else:
        value = 255.0 * ( val - minVal ) / (maxVal - minVal - 1.0)    
        byte_array[i] = (round(value))
    i += 1  

我不知道如何避免循环并仍然执行 if... 并应用缩放功能。

谢谢

【问题讨论】:

  • 仅供参考:绝对不需要循环。如果您没有严格的内存限制,只需执行byte_array = (255.0 * (pixel_array - minVal) / (maxVal - minVal - 1.0)).astype(np.uint8)。之后您可以使用byte_array[pixel_array == paddingVal] = 0 设置“填充”值。它的内存效率不高,但它会比你目前正在做的要快得多。
  • 那肯定更快。可爱的蟒蛇可以做到这一点。
  • 请注意,我在评论中发布的版本隐含地采用了值的下限而不是四舍五入。如果您对此感到满意,它会比调用 numpy.round 快​​一点,但它与您的原始代码不同(不过,@jorgeca 的答案应该与您的原始解决方案给出相同的结果)。

标签: python numpy casting


【解决方案1】:

试试:

byte_array[i] = (((val << 16) >> 8) & 0xFF0000) >> 16

假设 val 是 0 到 65535 之间的 32 位整数

【讨论】:

  • val 在这种情况下是一个负符号的 16 位整数,所以上面的方法不能解决问题。无论如何,性能与原版并没有根本不同。不知何故,我认为必须摆脱显式循环。
  • @thefog 您可以使用(int + 0x10000) &amp; 0xFFFEFFFF-3276832767 之间的32 位整数转换为065535 之间的32 位整数。这意味着在缩放 -1 之后(因为它在 2 的补码中已满位)变为 255 等等。
  • @thefog 它避免了浮点运算、乘法和对舍入的调用。我猜如果代码执行相同,代码不会运行得太接近硬件:P
【解决方案2】:

您可以使用掩码从 numpy 的矢量化(隐式循环)中受益,这会更快:

mask = pixel_array == paddingVal
byte_array[mask] = 0
byte_array[~mask] = np.round(255.0 * (pixel_array[~mask] - minVal) / (maxVal - minVal - 1.0))

也可以这样做,这样更简洁,因为您不必事先创建byte_array

byte_array = np.round(255.0 * (pixel_array - minVal) / (maxVal - minVal - 1.0)).astype(np.uint8)
byte_array[pixel_array == paddingVal] = 0

编辑:正如乔金顿在对该问题的评论中指出的那样,这是以记忆换取速度。

【讨论】:

  • 失败并出现错误,我尝试了类似之前的操作并得到: byte_array[~mask] = round(255.0 * (pixel_array[~mask] - minVal) / (maxVal - minVal - 1.0)) TypeError: 只有长度为 1 的数组可以转换为 Python 标量
  • 抱歉,round 是一个内置的 Python,仅适用于标量。我会解决的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-27
  • 2017-07-21
  • 1970-01-01
相关资源
最近更新 更多