numpy
image processing
data visualization
python
array conversion

How do I convert a numpy array to and display an image?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

To turn a NumPy array into an image, you need to match the array’s shape and value type to what image libraries expect. Once the array has the right dimensions and numeric range, you can display it directly with Matplotlib or convert it to an image object with Pillow.

Understand Shape and Value Ranges

Image libraries usually expect one of these shapes:

  • grayscale: height by width
  • RGB: height by width by 3
  • RGBA: height by width by 4

For many libraries, the most common dtype is uint8 with values from 0 to 255.

python
1import numpy as np
2
3gray = np.random.randint(0, 256, size=(100, 100), dtype=np.uint8)
4rgb = np.random.randint(0, 256, size=(100, 100, 3), dtype=np.uint8)
5
6print(gray.shape, gray.dtype)
7print(rgb.shape, rgb.dtype)

If your array contains floats in the range 0 to 1, that can still be displayed by some tools, but it is safer to know which convention you are using.

Display with Matplotlib

For quick inspection, Matplotlib is the easiest choice.

python
1import numpy as np
2import matplotlib.pyplot as plt
3
4img = np.random.randint(0, 256, size=(120, 160, 3), dtype=np.uint8)
5
6plt.imshow(img)
7plt.axis("off")
8plt.show()

For grayscale images:

python
1gray = np.random.randint(0, 256, size=(120, 160), dtype=np.uint8)
2
3plt.imshow(gray, cmap="gray")
4plt.axis("off")
5plt.show()

This is perfect for debugging intermediate model outputs or processed arrays.

Convert to a Pillow Image

If you want an actual image object you can save to disk, use Pillow.

python
1from PIL import Image
2import numpy as np
3
4arr = np.random.randint(0, 256, size=(100, 150, 3), dtype=np.uint8)
5image = Image.fromarray(arr, mode="RGB")
6image.save("output.png")
7image.show()

For grayscale:

python
gray = np.random.randint(0, 256, size=(100, 150), dtype=np.uint8)
Image.fromarray(gray, mode="L").save("gray.png")

The mode matters. RGB is for three color channels, while L is the common grayscale mode.

Normalizing Float Arrays

Model outputs often come as floating-point arrays that are not already in display range. In that case, normalize them before conversion.

python
1import numpy as np
2
3def to_uint8(arr):
4    arr = np.asarray(arr, dtype=np.float32)
5    arr_min = arr.min()
6    arr_max = arr.max()
7
8    if arr_max == arr_min:
9        return np.zeros_like(arr, dtype=np.uint8)
10
11    scaled = (arr - arr_min) / (arr_max - arr_min)
12    return (scaled * 255).astype(np.uint8)
13
14raw = np.random.normal(size=(64, 64))
15img = to_uint8(raw)
16print(img.dtype, img.min(), img.max())

Without normalization, the image may appear all black, all white, or badly clipped.

Watch Out for Channel Order

If you use OpenCV alongside Pillow or Matplotlib, remember that OpenCV often uses BGR order instead of RGB. A red image can appear blue if the channel order is wrong.

python
1import cv2
2import numpy as np
3
4rgb = np.zeros((100, 100, 3), dtype=np.uint8)
5rgb[..., 0] = 255
6
7bgr = cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR)
8cv2.imwrite("converted.png", bgr)

That is not a NumPy problem; it is a library convention mismatch.

A Practical Utility Function

python
1import numpy as np
2from PIL import Image
3
4def array_to_image(arr):
5    arr = np.asarray(arr)
6    if arr.dtype != np.uint8:
7        arr = to_uint8(arr)
8
9    if arr.ndim == 2:
10        return Image.fromarray(arr, mode="L")
11    if arr.ndim == 3 and arr.shape[2] == 3:
12        return Image.fromarray(arr, mode="RGB")
13
14    raise ValueError(f"Unsupported shape: {arr.shape}")

Having one conversion helper reduces repeated mistakes across notebooks and scripts.

Common Pitfalls

One common mistake is passing arrays with the wrong shape, such as height by width by one, when the target library expects plain height by width for grayscale.

Another issue is forgetting dtype conversion. Many libraries display uint8 arrays more predictably than arbitrary float arrays.

A third pitfall is ignoring channel order when switching between Matplotlib, Pillow, and OpenCV.

Summary

  • Match the array shape to grayscale or RGB image expectations.
  • Use Matplotlib for quick display and Pillow for image objects and file output.
  • Normalize float arrays before converting them to uint8.
  • Check channel order when moving between imaging libraries.
  • Centralizing conversion logic makes image debugging much easier.

Course illustration
Course illustration

All Rights Reserved.