Images are NumPy arrays

OpenCV · Essentials · 8 min

Every OpenCV call takes and returns NumPy arrays, so knowing the layout lets you mix cv2 with plain NumPy freely.

OpenCV's Python package is imported as cv2. Unlike the C++ API with its cv::Mat class, the Python bindings use plain NumPy arrays for images. There is no special image type to learn.

The layout is fixed by convention:

  • A colour image has shape (height, width, 3): rows first, then columns, then channels.
  • A grayscale image has shape (height, width), with no channel axis.
  • The usual dtype is uint8, values 0 to 255. Some operations produce float32 or int16, for example gradients.
  • Channels are in BGR order, not RGB. This is a historical choice that every newcomer trips over; pixel img[y, x] returns [blue, green, red].

Because indexing is img[row, col], the y coordinate comes first when you index. But OpenCV functions that take points, sizes or rectangles use (x, y) and (width, height). Keep both conventions in mind: NumPy indexing is (y, x), cv2 arguments are (x, y).

Since an image is an array, you can create one with np.zeros, crop with slicing and adjust brightness with arithmetic. Watch the dtype, though: NumPy uint8 arithmetic wraps around, while cv2.add saturates (clamps at 255).

Example

import cv2
import numpy as np

img = np.zeros((120, 200, 3), dtype=np.uint8)   # black, 200 wide x 120 tall
img[:, :100] = (255, 0, 0)                      # left half BLUE (BGR!)
print(img.shape, img.dtype)                     # (120, 200, 3) uint8
print(img[10, 10])                              # [255   0   0]

h, w = img.shape[:2]
print("width", w, "height", h)                  # width 200 height 120

a = np.array([[250]], dtype=np.uint8)
print(a + np.uint8(10))                         # [[4]]   NumPy wraps
print(cv2.add(a, np.array([[10]], np.uint8)))  # [[255]] OpenCV saturates

Remember

  • An image is an ndarray of shape (h, w) or (h, w, channels), usually uint8
  • Colour channels are BGR, not RGB
  • Index as img[y, x]; cv2 functions take points as (x, y)
  • cv2 arithmetic saturates, NumPy uint8 arithmetic wraps

Watch out for

  • Passing img.shape[:2] (h, w) where cv2 expects a size (w, h), which swaps width and height.

Check yourself

  1. A colour image has shape (480, 640, 3). What is its width in pixels?
  2. `img[5, 2]` on a BGR image returns `[0, 0, 255]`. What colour is that pixel?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.opencv.org/4.x/d3/df2/tutorial_py_basic_ops.html