繁体   English   中英

我可以使用“普通”(Enthought)python将numpy数组保存为16位图像吗?

[英]Can I save a numpy array as a 16-bit image using “normal” (Enthought) python?

有没有办法使用任何常用的python包将numpy数组保存为16位图像(tif,png)? 是我过去可以开始工作的唯一方法,但我需要安装FreeImage包,这有点烦人。

这似乎是一个非常基本的任务,所以我希望它应该被scipy覆盖,但是scipy.misc.imsave只能做8位。

有任何想法吗?

一种选择是使用pypng 你仍然需要安装另一个软件包,但它是纯Python,因此应该很容易。 (在pypng源中实际上有一个Cython文件,但它的使用是可选的。)

这是使用pypng将numpy数组写入PNG的示例:

import png

import numpy as np

# The following import is just for creating an interesting array
# of data.  It is not necessary for writing a PNG file with PyPNG.
from scipy.ndimage import gaussian_filter


# Make an image in a numpy array for this demonstration.
nrows = 240
ncols = 320
np.random.seed(12345)
x = np.random.randn(nrows, ncols, 3)

# y is our floating point demonstration data.
y = gaussian_filter(x, (16, 16, 0))

# Convert y to 16 bit unsigned integers.
z = (65535*((y - y.min())/y.ptp())).astype(np.uint16)

# Use pypng to write z as a color PNG.
with open('foo_color.png', 'wb') as f:
    writer = png.Writer(width=z.shape[1], height=z.shape[0], bitdepth=16)
    # Convert z to the Python list of lists expected by
    # the png writer.
    z2list = z.reshape(-1, z.shape[1]*z.shape[2]).tolist()
    writer.write(f, z2list)

# Here's a grayscale example.
zgray = z[:, :, 0]

# Use pypng to write zgray as a grayscale PNG.
with open('foo_gray.png', 'wb') as f:
    writer = png.Writer(width=z.shape[1], height=z.shape[0], bitdepth=16, greyscale=True)
    zgray2list = zgray.tolist()
    writer.write(f, zgray2list)

这是颜色输出:

foo_color.png

这是灰度输出:

foo_gray.png


更新 :我最近为一个名为numpngw的模块创建了一个github存储库,它提供了一个将numpy数组写入PNG文件的函数。 存储库有一个setup.py文件,用于将其作为软件包安装,但基本代码位于单个文件numpngw.py ,可以复制到任何方便的位置。 numpngw的唯一依赖是numpy。

这是一个脚本,它生成与上面显示的相同的16位图像:

import numpy as np
import numpngw

# The following import is just for creating an interesting array
# of data.  It is not necessary for writing a PNG file with PyPNG.
from scipy.ndimage import gaussian_filter


# Make an image in a numpy array for this demonstration.
nrows = 240
ncols = 320
np.random.seed(12345)
x = np.random.randn(nrows, ncols, 3)

# y is our floating point demonstration data.
y = gaussian_filter(x, (16, 16, 0))

# Convert y to 16 bit unsigned integers.
z = (65535*((y - y.min())/y.ptp())).astype(np.uint16)

# Use numpngw to write z as a color PNG.
numpngw.write_png('foo_color.png', z)

# Here's a grayscale example.
zgray = z[:, :, 0]

# Use numpngw to write zgray as a grayscale PNG.
numpngw.write_png('foo_gray.png', zgray)

png和numpngw的这个解释非常有用! 但是,我认为应该提到一个小的“错误”。 在转换为16位无符号整数时,y.max()应该是y.min()。 对于随机颜色的图片,它并不重要,但对于真实的图片,我们需要做得对。 这是更正后的代码行......

z = (65535*((y - y.min())/y.ptp())).astype(np.uint16)

您可以将16位阵列转换为双通道图像(甚至是24位阵列转换为3通道图像)。 像这样的东西工作正常,只需要numpy:

import numpy as np
arr = np.random.randint(0, 2 ** 16, (128, 128), dtype=np.uint16)  # 16-bit array
print(arr.min(), arr.max(), arr.dtype)
img_bgr = np.zeros((*arr.shape, 3), np.int)
img_bgr[:, :, 0] = arr // 256
img_bgr[:, :, 1] = arr % 256
cv2.imwrite('arr.png', img_bgr)
# Read image and check if our array is restored without losing precision
img_bgr_read = cv2.imread('arr.png')
B, G, R = np.split(img_bgr_read, [1, 2], 2)
arr_read = (B * 256 + G).astype(np.uint16).squeeze()
print(np.allclose(arr, arr_read), np.max(np.abs(arr_read - arr)))

结果:

0 65523 uint16
True 0

如上所述,PyPNG非常有用。 对于Enthought用户,它可以安装为例如:

conda install -c eaton-lab pypng

我将使用架子的from_array方法:

import png
import numpy as np

bit_depth = 16

my_array = np.ones((800, 800, 3)) 

png.from_array(my_array*2**bit_depth-1, 'RGB;%s'%bit_depth).save('foo.png')

模式使用PIL样式格式,例如'L','LA','RGB'或'RGBA',然后是'; 16'或'; 8'也设置位深度。 如果省略位深度,则使用数组的dtype。

在这里阅读更多。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM