Introduction to Computer Vision with Python
A beginner-friendly guide to computer vision with Python and OpenCV: image processing, edge detection, object detection and a practical image classifier.

Computer vision enables machines to interpret and understand visual information from images and video. For web developers moving into AI, it is one of the most tangible subfields — you can see the results immediately. From OCR on receipt scanners to face detection in camera apps to quality inspection in manufacturing, computer vision powers applications you interact with daily.
This guide walks through the fundamentals using Python and OpenCV, the most widely used open-source computer vision library. Every concept includes runnable code.
Setting Up the Environment
OpenCV provides both classical computer vision algorithms and interfaces to deep learning models. Start with the Python bindings.
# Install OpenCV with contrib modules (extra algorithms)
pip install opencv-contrib-python numpy matplotlib
# Verify installation
python -c "import cv2; print(cv2.__version__)"
# Expected: 4.x.x# Basic image operations
import cv2
import numpy as np
# Read an image from disk
image = cv2.imread('photo.jpg')
# OpenCV loads images as BGR (not RGB) by default
# Image properties
print(f"Shape: {image.shape}") # (height, width, channels)
print(f"Data type: {image.dtype}") # uint8 (0-255)
print(f"Size: {image.size} pixels") # total pixel count
# Convert color spaces
rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# Resize while maintaining aspect ratio
height, width = image.shape[:2]
target_width = 800
scale = target_width / width
resized = cv2.resize(image, None, fx=scale, fy=scale, interpolation=cv2.INTER_AREA)Image Filtering and Enhancement
Filters are the building blocks of image processing. They reduce noise, sharpen edges, and prepare images for feature extraction.
# Blurring — reduces noise, smooths details
import cv2
import numpy as np
image = cv2.imread('noisy_photo.jpg')
# Gaussian blur — weighted average, good for general noise
gaussian = cv2.GaussianBlur(image, (5, 5), 0)
# Median blur — preserves edges, excellent for salt-and-pepper noise
median = cv2.medianBlur(image, 5)
# Bilateral filter — smooths while preserving edges
bilateral = cv2.bilateralFilter(image, 9, 75, 75)# ❌ Applying edge detection on a noisy image
# Noise creates thousands of false edges
edges_noisy = cv2.Canny(noisy_image, 100, 200)
# Result: edges everywhere — useless
# ✅ Blur first, then detect edges
blurred = cv2.GaussianBlur(noisy_image, (5, 5), 0)
edges_clean = cv2.Canny(blurred, 100, 200)
# Result: meaningful edges only — clean contours# Sharpening — enhances edge contrast
sharpen_kernel = np.array([
[0, -1, 0],
[-1, 5, -1],
[0, -1, 0]
])
sharpened = cv2.filter2D(image, -1, sharpen_kernel)
# Histogram equalization — improves contrast in low-contrast images
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
equalized = cv2.equalizeHist(gray)
# CLAHE — adaptive histogram equalization (better for uneven lighting)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
adaptive_eq = clahe.apply(gray)Edge Detection and Contours
Edge detection finds boundaries between regions in an image. Contours trace those boundaries into connected curves — useful for shape detection and object segmentation.
# Canny edge detection — the most widely used edge detector
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# Two thresholds: lower and upper
# Edges with gradient > upper → strong edges (kept)
# Edges with gradient between lower and upper → kept only if connected to strong edge
# Edges with gradient < lower → discarded
edges = cv2.Canny(blurred, 50, 150)
# Find contours from edges
contours, hierarchy = cv2.findContours(
edges,
cv2.RETR_EXTERNAL, # Only outermost contours
cv2.CHAIN_APPROX_SIMPLE # Compress straight lines
)
# Draw contours on the original image
output = image.copy()
cv2.drawContours(output, contours, -1, (0, 255, 0), 2)
print(f"Found {len(contours)} contours")# Practical example: detecting rectangles (documents, cards)
def find_rectangles(image: np.ndarray) -> list:
"""Find rectangular contours in an image."""
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.Canny(blurred, 50, 150)
contours, _ = cv2.findContours(
edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
rectangles = []
for contour in contours:
# Approximate contour to a polygon
perimeter = cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, 0.02 * perimeter, True)
# If polygon has 4 vertices and is large enough, it's a rectangle
area = cv2.contourArea(contour)
if len(approx) == 4 and area > 1000:
rectangles.append(approx)
return rectangles
rects = find_rectangles(image)
print(f"Found {len(rects)} rectangular regions")Object Detection with Haar Cascades
Haar cascades are pre-trained classifiers for detecting specific objects — faces, eyes, cars. They are fast but less accurate than deep learning models.
# Face detection using pre-trained Haar cascade
face_cascade = cv2.CascadeClassifier(
cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
)
image = cv2.imread('group_photo.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Detect faces
faces = face_cascade.detectMultiScale(
gray,
scaleFactor=1.1, # Image scale reduction at each level
minNeighbors=5, # Minimum neighbor detections to keep
minSize=(30, 30) # Minimum face size in pixels
)
# Draw bounding boxes
output = image.copy()
for (x, y, w, h) in faces:
cv2.rectangle(output, (x, y), (x + w, y + h), (0, 255, 0), 2)
print(f"Detected {len(faces)} faces")
# Save result
cv2.imwrite('faces_detected.jpg', output)# ❌ Running detection at original resolution for real-time video
# 4K frame → detection takes 200ms → 5 FPS maximum
faces = face_cascade.detectMultiScale(full_resolution_frame)
# ✅ Resize for detection, map coordinates back to original
scale = 0.25
small_frame = cv2.resize(frame, None, fx=scale, fy=scale)
small_gray = cv2.cvtColor(small_frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(small_gray)
# Map coordinates back: multiply by 1/scale
faces_original = [(int(x/scale), int(y/scale), int(w/scale), int(h/scale))
for (x, y, w, h) in faces]
# Detection runs at 60+ FPS on downscaled framesBuilding a Simple Image Classifier
For more accurate object recognition, use a pre-trained deep learning model. OpenCV's DNN module can load models from TensorFlow, PyTorch, and ONNX.
# Image classification using a pre-trained MobileNet model
import cv2
import numpy as np
# Load pre-trained MobileNet SSD
model = cv2.dnn.readNetFromTensorflow(
'frozen_inference_graph.pb',
'ssd_mobilenet_v2.pbtxt'
)
CLASSES = [
'background', 'person', 'bicycle', 'car', 'motorcycle',
'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird',
'cat', 'dog', 'horse', 'sheep', 'cow',
]
def detect_objects(image: np.ndarray, confidence_threshold: float = 0.5):
"""Detect objects in an image using MobileNet SSD."""
height, width = image.shape[:2]
# Prepare input blob
blob = cv2.dnn.blobFromImage(
image, 1.0/127.5, (300, 300), (127.5, 127.5, 127.5),
swapRB=True, crop=False
)
model.setInput(blob)
detections = model.forward()
results = []
for i in range(detections.shape[2]):
confidence = detections[0, 0, i, 2]
if confidence > confidence_threshold:
class_id = int(detections[0, 0, i, 1])
box = detections[0, 0, i, 3:7] * np.array(
[width, height, width, height]
)
x1, y1, x2, y2 = box.astype(int)
results.append({
'class': CLASSES[class_id],
'confidence': float(confidence),
'box': (x1, y1, x2, y2),
})
return results
image = cv2.imread('street_scene.jpg')
objects = detect_objects(image)
for obj in objects:
print(f"{obj['class']}: {obj['confidence']:.2f}")Key Takeaways
- OpenCV provides classical and deep-learning-based computer vision — from basic filtering to DNN inference, all in one library
- Always pre-process before analysis — blur to remove noise, convert color spaces, resize for performance
- Edge detection + contour finding solves many practical problems — document scanning, shape detection, and region segmentation
- Haar cascades are fast but limited — use them for real-time face detection; switch to deep learning models for accuracy
- Resize for detection, map coordinates back — running detection on downscaled frames turns 5 FPS into 60+ FPS
- Pre-trained models (MobileNet, YOLO) handle general object detection — fine-tune on your specific use case for production accuracy


