Computer Vision Chapter 10

Feature detection (intro)

Local features describe small patches that are distinctive and repeatable under viewpoint and lighting changes. A keypoint is a location (often with scale and orientation); a descriptor is a fixed-length vector summarizing local appearance. Match descriptors between images to align scenes, build panoramas, or bootstrap object recognition. This page introduces corner detectors and a full ORB detect→describe→match pipeline; later chapters dive into Harris, SIFT, and HOG.

Keypoint + descriptor + matcher

  1. Detect interesting points (corners, blobs).
  2. Compute a descriptor per keypoint (sometimes using a canonical orientation and scale).
  3. Match descriptors with a distance (L2 for float vectors, Hamming for binary).
  4. Filter false matches (ratio test, geometric checks with homography or fundamental matrix).
MethodDescriptorSpeedNotes
Shi-Tomasi / goodFeaturesToTrackNone (points only)FastGreat for optical flow and tracking
FASTOptional (e.g. ORB)Very fastCorner score on circle of pixels
ORBBinary (BRIEF-like)FastFree; rotation-aware
SIFT128-D floatSlowerStrong invariance; check build/license

Shi-Tomasi corners — goodFeaturesToTrack

Returns up to maxCorners 2D points with high corner response—no descriptor. Often used with cv2.calcOpticalFlowPyrLK for video tracking.

import cv2
import numpy as np

gray = cv2.imread("room.jpg", cv2.IMREAD_GRAYSCALE)
pts = cv2.goodFeaturesToTrack(
    gray, maxCorners=200, qualityLevel=0.01, minDistance=10, blockSize=7)

if pts is not None:
    for p in pts:
        x, y = p.ravel()
        cv2.circle(gray, (int(x), int(y)), 3, 255, -1)

Tighter quality, larger separation

pts2 = cv2.goodFeaturesToTrack(
    gray, maxCorners=80, qualityLevel=0.05, minDistance=20, blockSize=9)

FAST keypoints

cv2.FastFeatureDetector_create (or constructor) flags corners by comparing intensity on a Bresenham circle. Very fast; combine with ORB or BRIEF for descriptors.

import cv2

gray = cv2.imread("scene.jpg", cv2.IMREAD_GRAYSCALE)
fast = cv2.FastFeatureDetector_create(threshold=40, nonmaxSuppression=True)
kps = fast.detect(gray, None)

vis = cv2.drawKeypoints(gray, kps, None, color=(255, 0, 0),
                        flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

ORB — detect, compute, draw

ORB builds oriented FAST keypoints and binary descriptors. Default is 256 bits; Hamming distance applies. Free to use in typical OpenCV builds.

import cv2

img = cv2.imread("book.jpg", cv2.IMREAD_GRAYSCALE)
orb = cv2.ORB_create(nfeatures=500, scaleFactor=1.2, nlevels=8)
kp, des = orb.detectAndCompute(img, None)

img_bgr = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
img_kp = cv2.drawKeypoints(img_bgr, kp, None, color=(0, 255, 0),
                           flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

des is None if no keypoints; shape (N, 32) for 256-bit ORB (8 bits per byte × 32).

Brute-force matching

BFMatcher with NORM_HAMMING for ORB. Use knnMatch and Lowe’s ratio test to reject ambiguous pairs.

import cv2

im1 = cv2.imread("obj1.jpg", cv2.IMREAD_GRAYSCALE)
im2 = cv2.imread("obj2.jpg", cv2.IMREAD_GRAYSCALE)
orb = cv2.ORB_create(800)
k1, d1 = orb.detectAndCompute(im1, None)
k2, d2 = orb.detectAndCompute(im2, None)

bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=False)
pairs = bf.knnMatch(d1, d2, k=2)

good = []
for m, n in pairs:
    if m.distance < 0.75 * n.distance:
        good.append(m)

vis = cv2.drawMatches(im1, k1, im2, k2, good[:50], None, flags=2)

flags=2 is NOT_DRAW_SINGLE_POINTS (hide unmatched keypoints). On newer OpenCV you can write cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS.

Cross-check (mutual nearest neighbor)

bf_strict = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf_strict.match(d1, d2)
matches = sorted(matches, key=lambda m: m.distance)

Practical tips

  • Work in grayscale for classical detectors unless you use a color-aware variant.
  • Resize very large images before matching—scale affects keypoint count and runtime.
  • For panorama stitching, follow matching with RANSAC homography to kill outliers (covered in geometry topics).
  • SIFT may live in opencv-contrib-python and has patent/history considerations; ORB is the default free baseline.

Takeaways

  • goodFeaturesToTrack → points only; pair with optical flow.
  • ORB gives keypoints + binary descriptors + fast Hamming match.
  • Use ratio test or crossCheck before trusting correspondences.

Quick FAQ

Repeated texture, symmetry, and clutter produce similar descriptors. Tighten ratio threshold, increase minDistance at detection, or enforce geometric consistency (homography/fundamental matrix inliers).

Start with ORB: no extra modules, fast, enough for many alignment demos. Move to SIFT when you need stronger scale/view invariance and can install contrib builds.