A corner is where two edges meet — and you can find it without ever tracing an edge. Sum the
local gradient outer products into a 2×2 structure tensor M; its two eigenvalues say what is here.
Two large → a corner. One large, one small → an edge. Both near zero → flat. The cornerness
R = det(M) − k·trace(M)² reads that verdict off M without ever solving for the eigenvalues.
Rendered, not quoted.
source Harris, C. & Stephens, M., A Combined Corner and Edge Detector, Proc. 4th Alvey Vision Conference, Manchester, 1988, pp. 147–151 — Semantic Scholar · AMBER: conference proceedings, no canonical DOI
Over a window, form the structure tensor of the Sobel gradients
(Ix, Iy):
M = ∑ [ Ix² IxIy ; IxIy Iy² ]
M is symmetric positive-semidefinite, so its eigenvalues
λ₁ ≥ λ₂ ≥ 0 are the principal gradient energies.
Cornerness R = det(M) − k·trace², with k = 0.04, is
>0 at a corner, <0 on an edge,
≈0 when flat. It never solves the eigenproblem —
det = λ₁λ₂, trace = λ₁+λ₂ carry the same information.
The gradients summed here are the-sobel derivatives of the same neighbouring sphere. Harris & Stephens (1988) took Moravec's interest operator and replaced its discrete shifted-window sums with this differential structure tensor.
Downstream: the corner is the feature that the-optical-flow can actually track. Lucas–Kanade needs a well-conditioned M to solve for motion — and a well-conditioned M (two large eigenvalues) is a Harris corner. A plain edge leaves the aperture ambiguity unsolved.
Live re-check: classify the edge patch by the sign of its response, right now.
···The edge has one huge eigenvalue and one tiny one; honest cornerness
must call it edge. If window 6 swaps in det alone, this flips
red the instant the edge is mislabelled a corner.
Three constructed 5×5 patches, run through real Sobel: a corner (bright lower-right quadrant), an edge (a near-straight staircase step), and a flat field. Same detector, no tuning per patch.
Structure tensor, exact 2×2 eigenvalues, and cornerness for each patch — computed live:
Verdict by sign of R:
corner · edge · flat —
classified correctly, rotation-invariant to 1e−9, peaking on the corner.
wallThe detector reads gradients, not objects. Attacks that live at the wall:
· Scale. A single fixed window has no scale; a corner blurred wider than the window reads as flat. Harris is not scale-invariant (that needs Harris–Laplace / SIFT).
· Junctions & texture. A T-junction or dense texture gives two large eigenvalues too — R fires on things that are not the object corner you wanted.
· Contrast. R scales with gradient magnitude²; global brightness/contrast changes move every score, so a fixed threshold is fragile.
“A corner is just a pixel where the edge map bends.”
→ No edge map is built. Cornerness comes from the eigenvalue structure of M;
an edge detector would have to be thresholded and traced first.
“det(M) alone measures cornerness.”
→ det = λ₁λ₂ is huge whenever a real edge has any curvature
(λ₂>0), so det alone flags edges as corners. The −k·trace²
penalty is exactly what pushes edges negative. This is window 6.
“Rotate the image and the corners move.”
→ Eigenvalues are rotation-invariant; R is unchanged (exact under a 90° grid rotation).
The disclosed planted void: drop the trace penalty and score by det(M) alone.
The edge (det = λ₁λ₂ > 0) is then wrongly called a corner.
Window 7 catches it live.