【问题标题】:Why do values in my 3D numpy array change when I write it to file?为什么将 3D numpy 数组中的值写入文件时会发生变化?
【发布时间】:2016-09-25 20:08:23
【问题描述】:

奇怪的问题在于我有一个 3D 数组,其中包含名为 labelled_stack 的标签(比如说从 1 到 36)。这些只是数组中的值等于给定标签的区域。一个带有 5 个标签的快速 2D 示例如下所示:

labelled_stack = (0 0 0 0 0 0 0 0 0 0)
                 (0 1 1 0 0 0 2 2 2 0)
                 (0 1 0 0 3 0 0 2 2 0)
                 (0 0 0 3 3 0 0 0 0 0)
                 (0 4 0 0 3 0 0 0 5 0)
                 (0 4 0 0 0 0 5 5 5 0)
                 (0 0 0 0 0 0 0 0 0 0)

但想象一下它是一个 numpy 数组...

我尝试使用 cv2.imwrite 和 scipy.misc.imsave 来保存堆栈,但是当我这样做然后打开它们时,它们的值已经改变,因此值 = 5,现在等于 255,并且值等于到 1,等于 51 等。这是不可接受的。我需要这些值保持原样.. 以 1 为步长增加整数值。我知道 cv2 和 scipy.misc 都写为 8 位图像,但这不应该意味着我得到这个错误。

我什至将图像重新读回 python 以检查这是怎么回事。

我的 labelled_stack 是 np.uint32 类型

编辑以包含保存命令:
for j in np.arange(0,l,1):
     misc.imsave(save_path+Folder+'/Labelled/slice_{:04d}of{:}.tif'.format(j+1,l),labelled_stack[:,:,j])

或者...

cv2.imwrite(save_path+Folder+'/Labelled/slice_{:04d}of{:}.tif'.format(j+1,l),labelled_stack[:,:,j])

【问题讨论】:

  • 为什么不用numpy的方法来保存numpy数组呢? savetxt 之类的东西可以处理将一个 numpy 数组输出到文件。
  • 你能展示你如何调用 imwrite 吗?并且发布您输出的图像也可能很有用。
  • 对不起,我应该清楚,我需要 tif 格式的图像用于下一阶段的处理。 Sunreef,您建议以什么方式发布 3D 数组?

标签: python arrays opencv numpy scipy


【解决方案1】:

函数imwrite 以8 位格式保存数据。当该函数将您的 32 位数据转换为 8 位时,它会缩放数据以使用 8 位的完整位深度,例如,您的数据的最大值被缩放到 255。另一个示例请参见 scipy imsave saves wrong values

为避免这种情况,请在保存之前将您的数据转换为 numpy.uint8。在以下示例中,a 的数据类型为 numpy.uint32

In [98]: from scipy.misc import imsave, imread

In [99]: a
Out[99]: 
array([[0, 3, 2, 2, 4, 0, 3, 0],
       [2, 0, 0, 3, 3, 1, 3, 0],
       [2, 4, 4, 0, 2, 3, 1, 3],
       [0, 1, 3, 1, 0, 0, 0, 4],
       [2, 1, 1, 2, 1, 1, 3, 1],
       [0, 4, 0, 1, 0, 0, 2, 3],
       [3, 1, 3, 3, 3, 2, 3, 4],
       [0, 4, 1, 4, 2, 2, 0, 2]], dtype=uint32)

astype 方法用于将数组转换为numpy.uint8,然后再将其传递给imsave 函数。

In [100]: imsave("a.tif", a.astype(np.uint8))  # Convert to 8 bit before saving

回读scipy.misc.imread:

In [101]: b = imread("a.tif")

In [102]: b
Out[102]: 
array([[0, 3, 2, 2, 4, 0, 3, 0],
       [2, 0, 0, 3, 3, 1, 3, 0],
       [2, 4, 4, 0, 2, 3, 1, 3],
       [0, 1, 3, 1, 0, 0, 0, 4],
       [2, 1, 1, 2, 1, 1, 3, 1],
       [0, 4, 0, 1, 0, 0, 2, 3],
       [3, 1, 3, 3, 3, 2, 3, 4],
       [0, 4, 1, 4, 2, 2, 0, 2]], dtype=uint8)

注意,当使用scipy.misc.imread读取数据时,结果的数据类型为numpy.uint8


另一个推荐的选项是使用tifffile,尤其是在您尝试保留需要 16 位或 32 位的数据时。

在此示例中,a 的数据类型为 numpy.uint32,其中一些值大于无符号 8 位数。

In [152]: from tifffile import imsave, imread

In [153]: a
Out[153]: 
array([[  0,   5,  10,  15,  20,  25,  30,  35,  40,  45],
       [ 50,  55,  60,  65,  70,  75,  80,  85,  90,  95],
       [100, 105, 110, 115, 120, 125, 130, 135, 140, 145],
       [150, 155, 160, 165, 170, 175, 180, 185, 190, 195],
       [200, 205, 210, 215, 220, 225, 230, 235, 240, 245],
       [250, 255, 260, 265, 270, 275, 280, 285, 290, 295],
       [300, 305, 310, 315, 320, 325, 330, 335, 340, 345],
       [350, 355, 360, 365, 370, 375, 380, 385, 390, 395],
       [400, 405, 410, 415, 420, 425, 430, 435, 440, 445],
       [450, 455, 460, 465, 470, 475, 480, 485, 490, 495]], dtype=uint32)

In [154]: imsave("a.tif", a)

In [155]: b = imread("a.tif")

In [156]: b
Out[156]: 
array([[  0,   5,  10,  15,  20,  25,  30,  35,  40,  45],
       [ 50,  55,  60,  65,  70,  75,  80,  85,  90,  95],
       [100, 105, 110, 115, 120, 125, 130, 135, 140, 145],
       [150, 155, 160, 165, 170, 175, 180, 185, 190, 195],
       [200, 205, 210, 215, 220, 225, 230, 235, 240, 245],
       [250, 255, 260, 265, 270, 275, 280, 285, 290, 295],
       [300, 305, 310, 315, 320, 325, 330, 335, 340, 345],
       [350, 355, 360, 365, 370, 375, 380, 385, 390, 395],
       [400, 405, 410, 415, 420, 425, 430, 435, 440, 445],
       [450, 455, 460, 465, 470, 475, 480, 485, 490, 495]], dtype=uint32)

【讨论】:

  • 你有什么建议什么时候没有。标签的数量在每种情况下都是未知的,很容易小于 255 或大于 255??
  • @ScottAlistair 对于 tiff 文件,一个不错的选择是 tifffile 包。它支持 16 位和 32 位文件,无需特殊编码。我已经用一个例子更新了我的答案。
  • 这是我今天也发现的东西,但担心这会像我的原始代码一样起作用并扩大数据,但我很高兴看到它没有!太好了,谢谢
【解决方案2】:

正如您在documentation 中看到的那样:

函数 imwrite 将图像保存到指定文件。图像格式是根据文件扩展名选择的(有关扩展名列表,请参见 imread())。 仅 8 位(或 16 位无符号 (CV_16U),在 PNG、JPEG 2000 和 TIFF 的情况下)单通道或 3 通道(具有“BGR”通道顺序)图像可以使用此功能保存

您说“labelled_stack 的类型为 np.uint32”(32 位无符号整数)。那就是问题所在。你需要自己处理类型转换。

【讨论】:

  • 把它改成什么,int?
  • @ScottAlistair uint8 或 uint16(阅读文档中描述的限制)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 2016-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-30
相关资源
最近更新 更多