Unit 01.00: An image is a grid of numbers
Everything in computer vision follows from one fact: an image is a grid of numbers, and nothing in it knows what it depicts.
Height, then width, then channels
A colour image is a three-dimensional array. The first axis is rows, the second is columns, the third is colour channels.
The code builds a tiny image and prints its parts.
import numpy as np
image = np.zeros((4, 6, 3), dtype="uint8")
image[1:3, 2:5] = [40, 180, 220]
print("shape:", image.shape, "-> (height, width, channels)")
print("dtype:", image.dtype, "-> values 0-255")
print("\nthe blue channel, as numbers:")
print(image[:, :, 2])
print(f"\none pixel: {image[1, 2]} (a 3-value array, not a colour)")
print(f"mean brightness: {image.mean():.1f}")
# Height comes first, then width. Every off-by-one in a vision pipeline starts
# here: numpy indexes rows before columns, and almost every drawing API takes
# x before y.
Height comes first. Almost every drawing API takes x before y, and numpy indexes rows before columns, so the two conventions are transposed with respect to each other.
That is where a large share of off-by-one and transposed-image bugs originate. A pixel is image[y, x] and a point is usually (x, y), and both are correct in their own context.
The mistake this prevents
The mistake is reasoning about images as pictures rather than arrays. A picture has a left and a top; an array has axis 0 and axis 1, and which one is vertical is a convention you have to keep track of deliberately.
Takeaway
An image is a (height, width, channels) array of numbers. Rows before columns in numpy, x before y almost everywhere else.
