Understand orthogonality as the independence of two vector directions, and show that mean subtraction is exactly orthogonal projection onto the [1, 1, \ldots, 1] brightness direction — making brightness and pattern independent components.
32.2 Orthogonality
Two vectors are orthogonal (perpendicular) when their dot product is zero:
\vec a \cdot \vec b \;=\; 0
\quad \Longleftrightarrow \quad \vec a \perp \vec b
Geometrically, they point in completely independent directions — knowing one tells you nothing about the other.
Why this matters for normalisation: mean subtraction splits a patch vector into two orthogonal parts — a brightness component and a pattern component. Because they’re orthogonal, changing brightness cannot affect the pattern. That independence is the whole reason normalisation works.
The orthogonality that matters here is between:
The uniform brightness vector[1, 1, 1, \ldots, 1] — equal value everywhere, encodes only brightness, zero spatial pattern.
The mean-subtracted residual of any vector.
Any scalar multiple of [1, 1, \ldots, 1] is a flat grey image. Mean subtraction removes exactly this component.
32.3 Orthogonal projection
Orthogonal projection splits a vector into two perpendicular parts:
\vec v \;=\; \underbrace{\operatorname{proj}_{\vec u} \vec v}_{\text{component along } \vec u}
\;+\; \underbrace{(\vec v - \operatorname{proj}_{\vec u} \vec v)}_{\text{component perpendicular to } \vec u}
The projection formula onto a unit vector \hat u:
\operatorname{proj}_{\hat u} \vec v \;=\; (\vec v \cdot \hat u)\,\hat u
32.4 Mean subtraction is orthogonal projection
Let \vec u = [1, 1, \ldots, 1] with n elements. Its unit vector is:
\hat u \;=\; \frac{[1, 1, \ldots, 1]}{\sqrt n}
The projection of \vec v onto \hat u:
\operatorname{proj}_{\hat u} \vec v
\;=\; (\vec v \cdot \hat u)\,\hat u
\;=\; \left(\frac{\sum v_i}{\sqrt n}\right)\,\frac{[1, 1, \ldots, 1]}{\sqrt n}
\;=\; \frac{\sum v_i}{n}\,[1, 1, \ldots, 1]
\;=\; \bar v \cdot [1, 1, \ldots, 1]
So the projection is just the mean of the pixel values, broadcast to every element. Mean subtraction removes this projection, leaving only the perpendicular (pattern) component.
Consequence: a brightness offset only changes the brightness component, not the pattern component. After mean subtraction, patterns are identical regardless of uniform lighting shifts.
32.5 Decomposition in code
import numpy as npimport matplotlib.pyplot as pltCOLORS = {"primary": "#2196F3","secondary": "#4CAF50","highlight": "#F44336","transform": "#9C27B0","gradient": "#FF9800",}def decompose(v):"""Split v into brightness and pattern components.""" n =len(v) ones = np.ones(n) brightness = v.mean() * ones # along [1,1,...,1] pattern = v - brightness # perpendicular to itreturn brightness, patterntemplate = np.array([ 50, 150, 250], dtype=float)brightness, pattern = decompose(template)print("template :", template)print("brightness :", brightness)print("pattern :", pattern)print()print(f"brightness · pattern = {np.dot(brightness, pattern):+.6e}")print("(should be ~ 0 — they are orthogonal)")
template : [ 50. 150. 250.]
brightness : [150. 150. 150.]
pattern : [-100. 0. 100.]
brightness · pattern = +0.000000e+00
(should be ~ 0 — they are orthogonal)
32.6 Brightness offset only moves the brightness component
Original, brightness component, and pattern (mean-subtracted) component for the template and a brightness-shifted copy.
The pattern bars are identical between the two rows. Only the brightness bars change.
32.8 Pearson correlation as a normalised dot product
Once you’ve subtracted the mean from both signals, the cosine similarity of the residuals is exactly Pearson’s correlation coefficientr. That’s why every classical similarity score that “handles brightness changes” — TM_CCOEFF_NORMED in OpenCV, the NCC denoising in BM3D, the score in cross-correlation tracking — is, under the hood: subtract the mean, normalise, take the dot product.
32.9 Exercises
For \vec v = [4, 8, 12], compute brightness and pattern components. Verify orthogonality.
Show by simulation that for any random \vec v, the pattern component sums to zero.
Implement pearson_r(a, b) from scratch using mean subtraction and cosine similarity. Compare to numpy.corrcoef.
Two patches differ only by an additive constant. Show that Pearson’s r between them is exactly 1.
32.10 Glossary
orthogonal — perpendicular; dot product = 0.
projection — component of one vector along another.
mean subtraction — subtracting the per-vector mean from each element.
brightness component — the projection of a patch onto [1, 1,
\ldots, 1].
pattern component — the residual after removing the brightness component.
Pearson’s r — cosine similarity of mean-subtracted vectors.