NumPy Image Arrays

Every image you have ever opened is a grid of numbers, and NumPy is how Python holds that grid. Once you know the shape convention and the right data type, creating a blank canvas, reading a pixel, or isolating a colour channel all become ordinary array operations.

Create a 210x210 black image with np.zeros((210, 210, 3), dtype=np.uint8). The height-width-channels rule, why uint8 matters, and how to address pixels and…

Part of the free Numpy course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

We will start with the question people most often arrive at NumPy asking — how do I make a 210×210 black image? — and build out from there.

What You'll Learn in This Lesson

1 The Shape Rule: Height, Width, Channels

So a 210×210 image is (210, 210, 3) — square, so the swap does not bite here, which is exactly why square examples hide the bug until you try a rectangle.

2 Why uint8 — and the np.ones() Trap

Each channel stores a whole number from 0 (none) to 255 (full) . That is precisely one byte, which is what np.uint8 gives you — and what every image format and viewer expects.

The memory difference is not trivial. A 4K RGB frame is about 25 MB as uint8, and nearly 200 MB as the float64 NumPy would otherwise default to — eight times the memory for data that only ever holds whole numbers 0-255.

To make any flat colour, fill with a three-value list. Remember the order is red, green, blue — so pure red is [255, 0, 0] .

3 Pixels, Regions and Channels

Because it is just an array, ordinary indexing does everything:

Slicing returns a view , not a copy, so assigning into a slice edits the original image directly — which is exactly what you want when drawing.

4 Two Bugs That Turn Images Black

1. uint8 overflow. Brightening with img + 50 looks sensible until a channel already at 230 wraps past 255 and comes back near zero — bright areas turn dark and speckled. Do the arithmetic in a wider type and clip:

np.clip(img.astype(np.int16) + 50, 0, 255).astype(np.uint8)

2. Float-to-uint8 without scaling. Many libraries hand back floats in the range 0–1. Casting straight to uint8 truncates every one of them to 0 — a perfectly black image. Multiply by 255 first.

5 🎯 Your Turn

Build a small flag: a black canvas, a white horizontal band across the middle, and a red square in the top-left corner. Then confirm the shape and a couple of pixels.

❓ Frequently Asked Questions

Lesson complete — images are just arrays now!

You can create a canvas at any size, pick the right dtype, address pixels and channels by index, and recognise the two dtype bugs that turn an image unexpectedly black.

🚀 Up next: Array Data Types — go deeper on dtypes, precision and memory.

Practice quiz

What shape does a 210x210 colour image have as a NumPy array?

  • (210, 210)
  • (210, 210, 3)
  • (3, 210, 210)
  • (210, 3)

Answer: (210, 210, 3). Height, then width, then one value per colour channel — (210, 210, 3) for RGB.

Which call creates a 210x210 black RGB image?

  • np.zeros((210, 210, 3), dtype=np.uint8)
  • np.empty((210, 210))
  • np.ones((210, 210, 3))
  • np.zeros(210)

Answer: np.zeros((210, 210, 3), dtype=np.uint8). Black is zero in every channel, and uint8 is the standard image data type.

Why use dtype=np.uint8 for images?

  • It is faster to type
  • It matches the 0-255 range each channel uses, at one byte per value
  • It supports negative numbers
  • It is required by NumPy

Answer: It matches the 0-255 range each channel uses, at one byte per value. uint8 holds exactly 0-255, which is the range image formats and viewers expect.

How do you make a pure white RGB image?

  • np.ones((h, w, 3), dtype=np.uint8)
  • np.full((h, w, 3), 255, dtype=np.uint8)
  • np.zeros((h, w, 3)) + 1
  • np.white((h, w, 3))

Answer: np.full((h, w, 3), 255, dtype=np.uint8). White is 255 in every channel; np.ones would give you a near-black value of 1.

In img[50, 100], what does 50 refer to?

  • The x coordinate
  • The row (y coordinate)
  • The colour channel
  • The width

Answer: The row (y coordinate). NumPy indexes rows first, so img[y, x] — the opposite order to most graphics APIs.

What shape does a grayscale image have?

  • (height, width)
  • (height, width, 1) only
  • (height, width, 3)
  • (width, height)

Answer: (height, width). Grayscale needs one value per pixel, so it is a plain 2-D array.

What does img[:, :, 0] select in an RGB image?

  • The first row
  • The red channel of every pixel
  • The first pixel
  • The alpha channel

Answer: The red channel of every pixel. Take all rows, all columns, channel index 0 — the red plane.

With uint8, what is 250 + 10?

  • 260
  • 255
  • 4
  • An error

Answer: 4. uint8 wraps around: it overflows past 255 and comes back to 4. Cast to a wider type before arithmetic.

How do you convert a float image in the range 0-1 to uint8?

  • img.astype(np.uint8)
  • (img * 255).astype(np.uint8)
  • np.round(img)
  • img.tolist()

Answer: (img * 255).astype(np.uint8). Scale to 0-255 first — casting straight away would turn every value below 1.0 into 0.

How many channels does an RGBA image have?

  • 3
  • 4
  • 2
  • 1

Answer: 4. Red, green, blue plus alpha for transparency — shape (h, w, 4).

Continue this course