Reading, writing and inspecting images
Load an image into a NumPy array, understand its shape and colour order, crop regions, and save results without losing data.
Load and save
An OpenCV image is a NumPy array - height first, then width, then channels. Reading returns None on failure instead of raising, so the first thing every script should do is check for it.
import cv2
img = cv2.imread("photo.jpg") # BGR order, dtype uint8
if img is None:
raise SystemExit("could not read photo.jpg - missing file, wrong path or unsupported format")
print(img.shape, img.dtype) # (1080, 1920, 3) uint8
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # shape (1080, 1920)
ok = cv2.imwrite("out/gray.png", gray) # returns True/False, never raises
print(ok)| Call | Returns | Notes |
|---|---|---|
| imread(path) | Array or None | Always check for None; OpenCV reports errors by return value |
| imread(path, IMREAD_COLOR) | 3-channel BGR | Drops alpha; the default |
| imread(path, IMREAD_GRAYSCALE) | Single channel | Fastest path for most classical CV work |
| imread(path, IMREAD_UNCHANGED) | As stored | Keeps alpha and 16-bit depth; use for measurement |
| imwrite(path, img) | bool | Extension decides the format; a bad path returns False |
💡
OpenCV loads colour images as BGR, while PIL, matplotlib and most browser APIs use RGB. If reds and blues look swapped in a preview, you forgot a conversion - the classic one-liner is
cv2.cvtColor(img, cv2.COLOR_BGR2RGB).Indexing, colour and resizing
# Slicing is (y, x) - rows first, then columns
crop = img[100:250, 300:500] # region of interest, a view not a copy
cv2.rectangle(img, (300, 100), (500, 250), (0, 255, 0), 2) # (x1, y1), (x2, y2)
cv2.putText(img, "plate", (300, 92), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 1)
small = cv2.resize(img, (640, 360), interpolation=cv2.INTER_AREA) # shrink
big = cv2.resize(small, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC) # enlarge- Use
INTER_AREAwhen shrinking - it averages pixels and avoids aliasing. - Use
INTER_CUBICorINTER_LINEARwhen enlarging; nearest-neighbour gives blocky edges. - Slicing returns a view, so writing into a crop also writes into the original. Call
.copy()when you intend to modify one independently. - Resize is a coordinate change: bounding boxes and calibration values computed for the old size no longer apply.
FAQ
Why does my matplotlib preview look colour-shifted?
matplotlib assumes RGB and OpenCV gives BGR. Convert with
cv2.cvtColor(img, cv2.COLOR_BGR2RGB) before plotting, or display with cv2.imshow.cv2.imread returns None for a file I can open.
Check the working directory first - a relative path resolves from wherever the process started, not from the script. Then check the extension is supported and that the path has no characters your build cannot encode.
Related
Filters and edge detection Opening, inspecting and saving images
Last refreshed 2026-09-18.