Saving a Numpy Array as an Image

Saving a Numpy array as an image

You can use PyPNG. It's a pure Python (no dependencies) open source PNG encoder/decoder and it supports writing NumPy arrays as images.

Saving a Numpy array as an image (instructions)

You might be better off using PIL:

from PIL import Image
import numpy as np

data = np.random.random((100,100))

#Rescale to 0-255 and convert to uint8
rescaled = (255.0 / data.max() * (data - data.min())).astype(np.uint8)

im = Image.fromarray(rescaled)
im.save('test.png')

Saving an image as a numpy array in a file and loading it back from the file as an image using Python

I was able to figure the solution out after a lot of trial and error. This is what helped me solve my problem-

from PIL import Image

# Create an empty text file before this step
with open('image_array.txt', 'w') as outfile:
for slice_2d in numpyimg:
np.savetxt(outfile, slice_2d)

new_data = np.loadtxt('image_array.txt')

new_data=new_data.reshape((780,1040,3))

img = Image.fromarray(new_data.astype(np.uint8),'RGB')
img.save('try.jpg')
img.show()

How to save a 3 channel numpy array as image

The @Dietrich answer is valid, however in some cases it will flip the image. Since the transpose operator reverses the index, if the image is stored in RGB x rows x cols the transpose operator will yield cols x rows x RGB (which is the rotated image and not the desired result).

>>> arr = np.random.uniform(size=(3,256,257))*255

Note the 257 for visualization purposes.

>>> arr.T.shape
(257, 256, 3)

>>> arr.transpose(1, 2, 0).shape
(256, 257, 3)

The last one is what you might want in some cases, since it reorders the image (rows x cols x RGB in the example) instead of fully transpose it.

>>> arr = np.random.uniform(size=(3,256,256))*255
>>> arr = np.ascontiguousarray(arr.transpose(1,2,0))
>>> img = Image.fromarray(arr, 'RGB')
>>> img.save('out.png')

Probably the cast to contiguous array is not even needed, but is better to be sure that the image is contiguous before saving it.

How to save numpy array images and put them into a single folder?

I tried writing 50,000 images of 28x28 to disk as JPEG using:

  • sequential code (25seconds)
  • multi-threaded code (19 seconds)
  • multi-processing code (5 seconds)

on a 12-core MacBook Pro with SSDs. Times are given in parentheses after each item in list above.

#!/usr/bin/env python3

import numpy as np
import imageio
from multiprocessing import Pool
from multiprocessing.pool import ThreadPool

def WriteOne(i,data):
"""Write a single image to disk"""
#print(f"WriteOne called with i={i}")
imageio.imwrite(f"image-{i:04d}.jpg", data)

def WriteSequential(images):
"""Write all images sequentially to disk"""
print("Sequential")
for i, data in enumerate(images):
WriteOne(i, data)
return

def WriteIndices(p):
"""Write given index to disk as JPEG"""
#print(f"WriteIndices {p[0]}")
WriteOne(p[0], p[1])
return

def WriteMultiThread(images):
"""Write all images to disk with multi-threading"""
print("MultiThread")
nThreads = 8
with ThreadPool(nThreads) as pool:
pool.map(WriteIndices, list(enumerate(images)))
return

def WriteMultiProcess(images):
"""Write all images to disk with multi-processing"""
print("MultiProcess")
nProcesses = 8
with Pool(nProcesses) as pool:
pool.map(WriteIndices, list(enumerate(images)))
return

if __name__ == '__main__':

# Synthesize 50000 images, each 28x28
N = 50000
images = np.random.randint(0,256,(N,28,28), dtype=np.uint8)

WriteSequential(images)

WriteMultiThread(images)

WriteMultiProcess(images)

How to save a very large numpy array as an image, loading as little as possible into memory

Standard TIFF cannot be used to store a 100000x100000 RGB image unless maybe if it is extremely compressible. The size of TIFF files is limited to 4 GB due to the usage of 32-bit offsets. BigTIFF uses 64-bit offsets. To enable tifffile writing BigTIFF, use the bigtiff=True parameter with memmap or imwrite. However, not many software/libraries will be able to read the files because BigTIFF and/or large strip sizes are not supported.

Images this large are commonly stored tiled, often with compression and multiple resolutions (pyramids). Tifffile can create tiled (Big)TIFF from a memory-mapped numpy array or a generator of tiles, e.g.:

import numpy
import h5py
import tifffile

dtype = 'uint8'
shape = 100000, 100000, 3
tileshape = 1024, 1024

f = h5py.File('test.hdf5', 'w')
data = f.create_dataset('test', shape, dtype=dtype, compression='gzip')

def tile_generator(data, tileshape):
for y in range(0, data.shape[0], tileshape[0]):
for x in range(0, data.shape[1], tileshape[1]):
tile = data[y: y+tileshape[0], x: x+tileshape[1], :]
if tile.shape[:2] != tileshape:
pad = (
(0, tileshape[0] - tile.shape[0]),
(0, tileshape[1] - tile.shape[1]),
(0, 0)
)
tile = numpy.pad(tile, pad, 'constant')
yield tile

tifffile.imwrite(
'temp.tif',
tile_generator(data, tileshape),
dtype=dtype,
shape=shape,
tile=tileshape,
bigtiff=True,
# compress='jpeg'
)

tifffile supports several compression options via the imagecodecs library, e.g. DEFLATE, LZMA, ZStd, JPEG, JPEG2000, JPEGXR, WebP...

There are dedicated TIFF "sub-formats", libraries, and tools to deal with pyramidal TIFF, often depending on the application domain, e.g. libvips, OpenSlide, GDAL, or BioFormats.

Python: How to save EXACT numpy array data to image using matplotlib.image.imsave()

Can somebody explain why the RGB values change in this process?

RGB values are integers in the range 0-255. Your float is interpreted as:

>>> .123 * 255
31.365
>>> int(.123 * 255)
31

Thirty-one is being written to that pixel. Then the reverse..

>>>
>>> 31 / 255
0.12156862745098039
>>>

Delving into the source for imsave() the array passed to imsave() is converted to RGBA values using matplotlib.cm.ScalarMappable().to_rgba(bytes=True)

>>> from matplotlib import cm
>>> sm = cm.ScalarMappable()
>>> rgba = sm.to_rgba(s_pic, bytes=True)
>>> rgba
array([[[ 31, 116, 201, 255]]], dtype=uint8)
>>>

Saving Image in tensor array as jpg or png

torch.save(faces, "faces.torch")

that wont be saved as an image, if you want to save it as an image:

img = Image.fromarray(faces.cpu().detach().numpy()[0])
img.save("faces.png")


Related Topics



Leave a reply



Submit