Images as Arrays
How a digital image is just a NumPy array — H×W for grayscale, H×W×3 for colour — with uint8 pixel values, channels, and weighted grayscale conversion.
Watch the lesson
1 video on CodeWithMunnaX
Every photo on your phone — a stadium shot, a player's portrait, a TV frame of a six — is stored as a grid of numbers. Once you load an image, it is a NumPy array, and everything you learned (indexing, slicing, broadcasting, aggregation) becomes image processing. Libraries like OpenCV, Pillow, scikit-image and every deep-learning framework hand images to you as NumPy arrays.
Definition
A digital image is a 2D grid of pixels (picture elements). In NumPy a grayscale image is a 2D array of shape
(H, W)— height × width — where each value is a brightness. A colour (RGB) image is a 3D array of shape(H, W, 3), where the last axis holds the Red, Green and Blue intensities of each pixel.
- Pixel — one cell of the grid;
img[row, col]. - H, W — rows first, then columns. A 1920×1080 "Full HD" frame is shape
(1080, 1920, 3)— height comes first! - Channel — one colour layer.
img[:, :, 0]is the red channel,1green,2blue. uint8— "unsigned 8-bit integer": whole numbers from 0 to 255. 0 = black (no light), 255 = full brightness. This is the standard image dtype.- Some images have a 4th alpha channel (transparency): shape
(H, W, 4), RGBA.
text
Grayscale (H, W) RGB (H, W, 3)
col→ 0 1 2 each pixel = [R, G, B]
row 0 [ 0 50 100] [255, 0, 0] = red
row 1 [ 50 100 150] [ 0, 255, 0] = green
row 2 [100 150 200] [ 0, 0, 255] = blue
[255, 255, 255] = white, [0, 0, 0] = blackSyntax
python
img.shape # (H, W) or (H, W, 3)
img.dtype # usually uint8
img[r, c] # one pixel (a number, or [R, G, B])
img[:, :, 0] # red channel (H, W)
gray = (rgb @ np.array([0.299, 0.587, 0.114])).round().astype(np.uint8)| Attribute / operation | Meaning | Example result |
|---|---|---|
img.shape | dimensions | (4, 4) gray, (2, 3, 3) RGB |
img.ndim | 2 = grayscale, 3 = colour | 2 |
img.dtype | pixel type | uint8 (0–255) |
img.size | number of values (pixels × channels) | 16 |
img[r, c] | one pixel | 250 or [255 0 0] |
img[..., k] | channel k of every pixel | 2D array |
Example — a tiny grayscale image
python
import numpy as np
gray = np.array([[ 0, 50, 100, 150],
[ 50, 100, 150, 200],
[100, 150, 200, 250],
[150, 200, 250, 255]], dtype=np.uint8)
print(gray)
print("shape:", gray.shape, " dtype:", gray.dtype, " size:", gray.size)
print("pixel at row 2, col 3:", gray[2, 3])
print("min/max/mean:", gray.min(), gray.max(), gray.mean())text
[[ 0 50 100 150]
[ 50 100 150 200]
[100 150 200 250]
[150 200 250 255]]
shape: (4, 4) dtype: uint8 size: 16
pixel at row 2, col 3: 250
min/max/mean: 0 255 147.1875How it works: this is a 4×4 diagonal gradient — black in the top-left corner, white in the bottom-right. gray.mean() is the average brightness of the picture, a real metric used to detect under-exposed photos.
Example — a tiny RGB image and its channels
python
rgb = np.zeros((2, 3, 3), dtype=np.uint8)
rgb[0, 0] = [255, 0, 0] # red
rgb[0, 1] = [0, 255, 0] # green
rgb[0, 2] = [0, 0, 255] # blue
rgb[1, 0] = [255, 255, 0] # yellow
rgb[1, 1] = [255, 255, 255] # white
rgb[1, 2] = [128, 128, 128] # grey
print("shape:", rgb.shape)
print("top-left pixel:", rgb[0, 0])
print("red channel:")
print(rgb[:, :, 0])text
shape: (2, 3, 3)
top-left pixel: [255 0 0]
red channel:
[[255 0 0]
[255 255 128]]The red channel is a normal 2D grayscale-looking array: it is bright wherever the pixel contains red (red, yellow = red + green, white, grey).
Converting colour to grayscale
The simple idea is to average R, G and B. But the human eye is much more sensitive to green and least sensitive to blue, so the standard (ITU-R BT.601 "luma") formula uses weights:
gray = 0.299 × R + 0.587 × G + 0.114 × B
That is a weighted sum over the last axis — exactly the @ you learned in Linear Algebra: (H, W, 3) @ (3,) → (H, W).
python
rgb = np.array([[[255, 0, 0], [0, 255, 0], [0, 0, 255]],
[[255, 255, 0], [255, 255, 255], [128, 128, 128]]], dtype=np.uint8)
weights = np.array([0.299, 0.587, 0.114])
gray = (rgb @ weights).round().astype(np.uint8)
print(gray)
print(rgb.mean(axis=2).round().astype(np.uint8))text
[[ 76 150 29]
[226 255 128]]
[[ 85 85 85]
[170 255 128]]How it works: with weights, pure green becomes bright (150) and pure blue dark (29) — just as our eyes see them. The plain average (second array) makes red, green and blue all the same grey (85), which looks wrong. White stays 255 and grey stays 128 either way because the weights sum to 1.
Loading a real image (outside the browser)
In the playground there are no files, so we build images by hand. On your own computer you would load a JPG/PNG like this:
python
from PIL import Image # pip install pillow
import numpy as np
img = np.array(Image.open("stadium.jpg")) # -> shape (H, W, 3), dtype uint8
Image.fromarray(img[::-1]).save("upside_down.jpg")matplotlib.pyplot.imread, cv2.imread (OpenCV — note it returns BGR order!) and imageio also return NumPy arrays.
Common mistakes
- ❌ Thinking shape is
(W, H). ✅ NumPy is(rows, cols)=(H, W)— height first. - ❌ Doing maths directly on
uint8(200 + 100wraps around to44). ✅ Convert to a bigger type first andnp.clipback to 0–255 (next topic). - ❌ Averaging R, G, B for grayscale. ✅ Use the 0.299 / 0.587 / 0.114 weights.
- ❌ Forgetting
.astype(np.uint8)after float maths — the result staysfloat64and many libraries reject it.
Interview tip
Q: What is the shape and dtype of a 640×480 colour photo loaded with Pillow into NumPy?
A: (480, 640, 3) with dtype uint8 — 480 rows (height), 640 columns (width), 3 colour channels, each value 0–255.
Key points to remember
- An image is a NumPy array: grayscale is (H, W), colour RGB is (H, W, 3); height comes first.
- Pixel values are usually uint8 integers from 0 (black) to 255 (full brightness).
- img[r, c] is one pixel; img[:, :, k] is one colour channel (0 = R, 1 = G, 2 = B).
- Grayscale = 0.299 R + 0.587 G + 0.114 B — a weighted sum: rgb @ weights.
- Plain averaging of channels ignores how the eye perceives green vs blue.
- Real images are loaded with Pillow, OpenCV (BGR order!) or matplotlib — all return NumPy arrays.
Try it yourself
Inspect a grayscale image
RGB to grayscale with weights
Practice: draw the Indian flag
Revision Flashcards
Tap a card to flip it and see the answer.
