OpenCV Basics: BGR, dtypes and Indexing
Intuition
OpenCV images are plain NumPy arrays, so everything from CV-01 still applies. Two
conventions trip everyone up: OpenCV stores colour channels as B, G, R (not R, G, B), and its
functions take points as (x, y) — column first — while NumPy indexes [row, column].
Precise explanation
import cv2
bgr = cv2.imread("photo.jpg") # (height, width, 3), uint8, channels B, G, R
rgb = cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB) # for matplotlib or PyTorch models
gray = cv2.cvtColor(bgr, cv2.COLOR_BGR2GRAY) # (height, width), uint8
patch = bgr[y:y + h, x:x + w] # rows first: y, then x
- Greyscale uses 0.299 R + 0.587 G + 0.114 B, rounded to the nearest integer — the weights from
CV-02. Passing an RGB image with
COLOR_BGR2GRAYsilently swaps the red and blue weights. - Most OpenCV functions expect
uint8(0–255) orfloat32. Arithmetic onuint8arrays wraps around (250 + 10 = 4), so convert with.astype(np.float32)before doing maths. - A slice such as
bgr[y:y+h, x:x+w]is a view: writing to it changes the original image. Use.copy()when you need an independent crop. cv2.imreadreturnsNone(no exception) when the file is missing.
Worked example
A pure blue pixel in BGR is [255, 0, 0]. Converted to RGB it becomes [0, 0, 255], and to grey
round(0.114 × 255) = 29. The rectangle with top-left corner x = 4, y = 1, width 3 and height 2 is
image[1:3, 4:7].
Common mistakes
- Showing a BGR image with matplotlib and getting blue faces.
- Indexing
image[x, y]. - Adding brightness to a
uint8image without clipping and getting dark wrap-around pixels. - Forgetting to check
cv2.imread's result forNone.
Why this matters
Every later step — thresholds, edges, contours, CNN inputs — starts from a correctly ordered, correctly typed array.
References
- Color conversions (OpenCV 4.13) — OpenCV team (
S115) - OpenCV Tutorials (OpenCV 4.13.0) — OpenCV team (
S023)