Saving a Numpy array as an image
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When working with image data in Python, you frequently represent images as NumPy arrays. Whether you are processing photographs, generating visualizations, or working with scientific imaging data, at some point you need to save that array back to disk as an image file. Python offers several libraries for this task, each with different strengths and data format expectations. Understanding which library to use and how to prepare your array data will prevent corrupted or incorrectly colored output images.
Data Type Considerations
Before saving any array as an image, you need to understand the expected data format. Most image formats expect pixel values as unsigned 8-bit integers (uint8) in the range 0 to 255. If your array uses floating-point values (common in scientific computing), you must convert it first:
Skipping this conversion is the single most common mistake. Libraries handle mismatched types differently: some silently produce garbled images, others throw errors.
Using Pillow (PIL)
Pillow is the most widely used library for basic image I/O in Python. The Image.fromarray() method converts a NumPy array to a PIL Image, which you can then save:
For grayscale images, pass a 2D array or specify the mode:
For RGBA images (with transparency), use a shape of (height, width, 4):
Pillow requires the array to be uint8. If you pass a float array, you will get unexpected results or an error.
Using Matplotlib
Matplotlib's imsave function is convenient when you are already using matplotlib for plotting. It handles float arrays in the 0.0-1.0 range natively:
One important detail: plt.imsave always saves RGBA PNGs by default, even for grayscale input. This means the file size may be larger than expected. Matplotlib also clips float values outside the 0.0-1.0 range, which can silently alter your data.
Using OpenCV
OpenCV is the standard for computer vision tasks. Its imwrite function saves arrays to disk. The critical difference is that OpenCV uses BGR channel ordering by default, not RGB:
If you skip the RGB-to-BGR conversion, your reds and blues will be swapped in the saved image. For grayscale, no conversion is needed:
OpenCV also supports saving 16-bit images, which is useful for scientific and medical imaging:
Deprecated Approach: scipy.misc.imsave
Older code and tutorials may reference scipy.misc.imsave. This function was deprecated in SciPy 1.0 and removed in SciPy 1.2. If you encounter it, replace with Pillow:
Common Pitfalls
- Saving a float array without converting to
uint8first, producing an all-black or garbled image - Forgetting the BGR channel order when using OpenCV, resulting in swapped red and blue channels
- Using matplotlib's
imsaveon uint8 arrays in the 0-255 range without realizing it expects 0.0-1.0 for floats - Passing a 2D array to
Image.fromarraywithout specifyingmode='L', which can misinterpret the data - Using the deprecated
scipy.misc.imsavein modern Python environments where it no longer exists - Not matching array shape to the intended format (e.g.,
(height, width, 3)for RGB vs(height, width)for grayscale)
Summary
- Use Pillow (
Image.fromarray) for general-purpose image saving withuint8arrays - Use matplotlib (
plt.imsave) when working with float arrays in the 0.0-1.0 range or when you need colormap support - Use OpenCV (
cv2.imwrite) for computer vision workflows, but remember the BGR channel order - Always verify your array's dtype and value range before saving
- Convert float arrays to
uint8with(array * 255).astype(np.uint8)when using Pillow - Avoid
scipy.misc.imsaveas it has been removed from modern SciPy versions

