python4 min read

OpenCV Python Tutorial: Learn Computer Vision from Scratch (2026)

OpenCV Python Tutorial: Learn Computer Vision from Scratch (2026)

Published:  |  Category: Python  |  Reading time: ~15 min
OpenCV Python Tutorial: Learn Computer Vision from Scratch (2026)

I started using OpenCV when I needed to read license plates from parking lot camera feeds. The library has bindings for Python that give you access to hundreds of computer vision algorithms — filtering, edge detection, feature matching, object tracking — all running on NumPy arrays under the hood. The learning curve isn't OpenCV itself (the API is consistent), but understanding the image-as-tensor paradigm and coordinate conventions.

This tutorial covers the operations I use most: reading and writing images, color space conversions, geometric transformations, edge detection, contour finding, and face detection with Haar cascades. Each section has a clear visual outcome so you can see exactly what each function does.

Reading, Displaying, and Writing Images

OpenCV reads images as BGR (not RGB) NumPy arrays — a common gotcha. imread loads from disk, imshow displays in a window, and imwrite saves. When using Matplotlib to display OpenCV images, convert BGR to RGB first with cv2.cvtColor. I keep a utility function that wraps this conversion so I don't forget it mid-analysis.

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('photo.jpg')
print(img.shape)  # (height, width, channels)

# Convert BGR to RGB for matplotlib
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)
plt.axis('off')
plt.show()

# Save a grayscale version
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite('photo_gray.jpg', gray)

Color Space Conversions and Thresholding

Many vision tasks are easier in a different color space. HSV (Hue, Saturation, Value) separates color information from brightness, making it ideal for color-based segmentation. Thresholding converts a grayscale image to binary using a cutoff value. Otsu's method automatically calculates the optimal threshold for bimodal histograms.

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# Define blue range in HSV
lower_blue = (100, 50, 50)
upper_blue = (130, 255, 255)
mask = cv2.inRange(hsv, lower_blue, upper_blue)

# Apply mask to isolate blue regions
result = cv2.bitwise_and(img, img, mask=mask)

# Otsu thresholding
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

Geometric Transformations: Resize, Rotate, Crop

Resizing is straightforward with cv2.resize, but interpolation matters — cv2.INTER_AREA for shrinking, cv2.INTER_LINEAR or cv2.INTER_CUBIC for enlarging. Rotation requires a warp matrix from cv2.getRotationMatrix2D, then cv2.warpAffine. Cropping is just NumPy slicing, which makes it zero-overhead.

# Resize
resized = cv2.resize(img, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)

# Crop (numpy slicing)
cropped = img[100:400, 200:500]

# Rotate around center
h, w = img.shape[:2]
center = (w // 2, h // 2)
matrix = cv2.getRotationMatrix2D(center, 45, 1.0)
rotated = cv2.warpAffine(img, matrix, (w, h))

Edge Detection with Canny

Canny edge detection is a multi-stage algorithm that finds sharp intensity changes. The two threshold parameters control sensitivity: lower thresholds detect weaker edges, higher thresholds suppress false positives. I usually start with ratios of 1:2 or 1:3 between thresholds. Blurring with GaussianBlur before Canny reduces noise artifacts.

# Apply Gaussian blur to reduce noise
blurred = cv2.GaussianBlur(gray, (5, 5), 1.5)

# Canny edge detection
edges = cv2.Canny(blurred, 50, 150)

# Visualize
plt.subplot(1, 2, 1), plt.imshow(gray, cmap='gray'), plt.title('Original')
plt.subplot(1, 2, 2), plt.imshow(edges, cmap='gray'), plt.title('Edges')
plt.show()

Contour Detection and Shape Analysis

Contours are curves joining continuous points along a boundary. cv2.findContours returns a list of contours from a binary image. I use RETR_EXTERNAL to get only outer boundaries and CHAIN_APPROX_SIMPLE to compress redundant points. cv2.contourArea and cv2.arcLength filter contours by size, and cv2.approxPolyDP approximates shapes for classification.

contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

for cnt in contours:
    area = cv2.contourArea(cnt)
    if area < 500:
        continue

    perimeter = cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, 0.02 * perimeter, True)
    x, y, w, h = cv2.boundingRect(cnt)
    cv2.rectangle(img_rgb, (x, y), (x + w, y + h), (0, 255, 0), 2)

plt.imshow(img_rgb)
plt.show()

Face Detection with Haar Cascades

OpenCV ships with pre-trained Haar cascade classifiers for face, eye, and smile detection. The cascade is an XML file loaded with cv2.CascadeClassifier. detectMultiScale returns bounding boxes. It's not as accurate as deep learning models, but it runs in real-time on a CPU and is perfect for prototyping detection pipelines.

face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

faces = face_cascade.detectMultiScale(
    gray,
    scaleFactor=1.1,
    minNeighbors=5,
    minSize=(30, 30)
)

for (x, y, w, h) in faces:
    cv2.rectangle(img_rgb, (x, y), (x + w, y + h), (255, 0, 0), 2)

print(f"Detected {len(faces)} face(s)")
plt.imshow(img_rgb)
plt.axis('off')
plt.show()

Frequently Asked Questions

Why does OpenCV use BGR instead of RGB?

Historical reason — early versions of OpenCV used BGR because it was the native format of Windows bitmaps and some camera drivers. You'll always need to convert for correct display in other libraries.

Is OpenCV thread-safe?

OpenCV's C++ core is thread-safe for reading, but Python's GIL means multi-threaded image processing doesn't parallelize well. Use multiprocessing instead. Some OpenCV functions use internal parallelism via TBB or OpenMP.

How do I process video frames in real-time?

Use cv2.VideoCapture to open a camera or video file. Loop reading frames and processing them. Keep the processing fast enough to maintain the frame rate — for real-time systems, optimize with lower resolution and simpler algorithms.

Does OpenCV support deep learning models?

Yes, the cv2.dnn module loads models from Caffe, TensorFlow, Darknet, and ONNX. You can run inference with pre-trained object detection models like YOLO, SSD, or MobileNet without needing a separate DL framework.

Originally published on Ayodhyyya. Last updated June 1, 2026.