Corner detector

A corner is an image location where the intensity changes significantly in multiple directions. Corners are stable, repeatable landmarks: unlike flat regions (no gradient) or edges (gradient in only one direction), a corner can be localized unambiguously in 2D, which makes it ideal for tracking and matching. The classic detector is the Harris corner detector.

Structure Tensor

The structure tensor (second-moment matrix) at a pixel, computed over a local window WW weighted by w(x,y)w(x,y) (often a Gaussian):

M=(x,y)Ww(x,y)[Ix2IxIyIxIyIy2]M = \sum_{(x,y) \in W} w(x,y) \begin{bmatrix} I_x^2 & I_x I_y \\ I_x I_y & I_y^2 \end{bmatrix}

where Ix=IxI_x = \frac{\partial I}{\partial x} and Iy=IyI_y = \frac{\partial I}{\partial y} are image gradients (computed with Sobel operators). The eigenvalues λ1,λ2\lambda_1, \lambda_2 of MM characterize the local structure:

λ1\lambda_1λ2\lambda_2Interpretation
0\approx 00\approx 0Flat region (no gradients)
0\gg 00\approx 0Edge (gradient in one direction only)
0\gg 00\gg 0Corner (gradients in both directions)

The intuition: MM summarizes how the sum of squared intensity differences changes when the window is shifted. A corner is a point where any shift direction produces a large change — which is precisely the condition “both eigenvalues large”.

Corner Response Function

Rather than computing eigenvalues directly (expensive), Harris proposed the response:

R=det(M)k(trace(M))2=λ1λ2k(λ1+λ2)2R = \det(M) - k\,(\mathrm{trace}(M))^2 = \lambda_1\lambda_2 - k(\lambda_1 + \lambda_2)^2

with k[0.04,0.06]k \in [0.04, 0.06] empirically. R>0R > 0 indicates a corner, R<0R < 0 an edge, and small R|R| a flat region. Non-maximum suppression then selects the strongest local maxima as the final corners.

The closely related Shi-Tomasi criterion (“Good Features to Track”) scores each pixel by min(λ1,λ2)\min(\lambda_1, \lambda_2) directly — the worst-case trackability of the patch — and is what OpenCV’s cv::goodFeaturesToTrack implements.

A from-scratch sketch

Implementing Harris in a few lines of NumPy/OpenCV is one of the best beginner exercises:

import cv2, numpy as np

I  = cv2.imread("frame.png", cv2.IMREAD_GRAYSCALE).astype(np.float32)
Ix = cv2.Sobel(I, cv2.CV_32F, 1, 0)
Iy = cv2.Sobel(I, cv2.CV_32F, 0, 1)

# window-averaged structure tensor entries
Sxx = cv2.GaussianBlur(Ix * Ix, (5, 5), 1.0)
Syy = cv2.GaussianBlur(Iy * Iy, (5, 5), 1.0)
Sxy = cv2.GaussianBlur(Ix * Iy, (5, 5), 1.0)

k = 0.04
R = (Sxx * Syy - Sxy**2) - k * (Sxx + Syy)**2   # Harris response
corners = R > 0.01 * R.max()                    # threshold before NMS

Practical notes for SLAM front-ends

Common pitfalls

Why it matters for SLAM

Corners are the raw material of feature-based SLAM front-ends: they become the keypoints that get described, matched, and triangulated into map points. The structure tensor reappears almost verbatim in Lucas-Kanade optical flow — a corner (both eigenvalues large) is exactly the kind of point that can be tracked reliably, which is why “good features to track” and Harris corners are so closely related. Later detectors used in real-time SLAM (FAST, ORB’s oriented FAST) are faster heirs of the same idea.