MVA · Course notes

Detection Theory and Industrial Applications

M2 MVA · Semester 2 · Modelling · 5 ECTS

Contents

Introduction and overview

Module Detection Theory and Industrial Applications
Official title Detection theory and industrial applications
Instructors R. GROMPONE, Q. BAMMEY (master-mva.com, 2026–2027)
Period Semester 2 · period 2 (04/01/2027 – 02/04/2027)
Credits and volume 5 ECTS · 24 h (lectures 24 h) per the Université Paris-Saclay programme table
Label Modelling · domains on master-mva.com: Image processing
Language French (Université Paris-Saclay course detail, “Langue d’enseignement”); the master-mva.com description is written in English
Assessment 4 homework assignments, including exercises and a report analysing a research paper (master-mva.com, “Mode de validation”); the Université Paris-Saclay course detail states “Evaluation Continue non Intégrale” (continuous assessment, of the “non-integral” kind; the components of the grade are not detailed); no weighting displayed
Prerequisites not displayed on the official pages

Audience: a student with a good M1 in mathematics, computer science or physics who knows elementary probability and wants detection algorithms whose thresholds are justified rather than tuned.

Empirical first: threshold a white-noise image of 512 \times 512 pixels at three standard deviations above its mean and about 350 pixels light up, although there is nothing to see. The eye, on the same image, sees nothing at all. A detector must behave like the eye: it must count how many times the observed event could happen by chance among all the events it looked at, and stay silent on noise.

Detection is the most frequent task of image, video and time-series analysis in industry: find the defect on a wafer, the change in a satellite time series, the pasted region in a photograph. It differs from classification because the objects to detect are rare and seldom come with enough examples to train a classifier.

The course builds one answer, the a-contrario theory. It models the absence of structure (the background), not the structure, and declares a detection when the expected number of such observations under the background model, the number of false alarms (NFA), is small.

The tools come from Probability and Statistics and from the image-processing courses of semester 1, notably Sub-Pixel Image Processing and Mathematical Models for Digital Photography. The applications meet Remote Sensing Data and Machine Learning for Time Series.

What you will be able to do

Official objectives and syllabus (2026–2027)

The course description on master-mva.com, written by the instructors’ team at the Centre Borelli, starts from industrial problems whose goal is the detection of objects or events in images or image series. It stresses that detection is not classification, because detection usually lacks a sufficient number of examples to be reduced to a classification problem.

It introduces the a-contrario theory, a statistical framework that selects detection thresholds automatically, so as to control the expected number of false detections under given background models. It covers the theory and practice of image and video processing needed for automatic detection, through several examples that include real-world applications.

The Université Paris-Saclay course detail sets the learning objective of training students in detection, which it calls one of the most frequent applications of image, video and time-series analysis. Its programme has eight items; master-mva.com lists five themes. The table matches every official item with the section of these notes that teaches it.

Official topic (master-mva.com “Thèmes abordés”; Université Paris-Saclay “Programme / plan / contenus”; course organisation) Course section
Introduction: visual perception, Gestalt theory, discussion of human vision (master-mva.com) ch. 1.1–1.3: what vision does, the Gestalt grouping laws, the Helmholtz principle
1 — Introduction: visual perception, Gestalt theory, definition of vision (Université Paris-Saclay) ch. 1.1 (a definition of vision as grouping), 1.2 (Gestalt laws, Kanizsa’s figures), 1.3
2 — The discrete nature of images: sampling, Shannon theory, Attneave theory ch. 1.4 (sampling, Shannon–Whittaker, the 2×2 gradient of noise), 1.5 (Attneave’s informational view of perception)
3 — Statistical principles leading to the detection of objects that can be modelled ch. 0 (tails, p-values); ch. 2: detection versus classification, Neyman–Pearson lemma, matched filter, multiple testing
A-contrario theory: background model, number of false alarms (NFA), modelling the background and the structure to be detected (master-mva.com) ch. 3: background model (3.1), NFA and its fundamental property (3.2–3.3), thresholds (3.4), maximality (3.6)
4 — A-contrario theory: background model, NFA, Gaussian modelling of the background and of the shape to detect ch. 3.5: Gaussian background, coloured noise, Gaussian shape model and detectability; Code 3.9
Detection of specific geometric structures ch. 4: meaningful alignments (4.1–4.2), the LSD line segment detector (4.3), other structures (4.4); Code 4.6
5 — A generic problem: anomaly detection in images, different theories, contribution of the a-contrario approach ch. 5.1 (families of methods), 5.4 (residuals reduced to noise, multiscale NFA)
6 — Comparison on examples of the classical anomaly detection theories in hyperspectral imaging ch. 5.2–5.3: RX, local RX with the Hotelling correction, mixture RX, matched filter; Code 5.4 compares them
7 — Detection in time series ch. 6.1–6.3: background models of a time series, exact change tests, families of changes
Time series detection in satellite images (master-mva.com) and 8 — Applications to recurrent satellite imaging, cloud detection, detection and temporal categorisation of changes ch. 6.4 (cloud screening, inter-band parallax), 6.3 and 6.5 (families, detection and categorisation of changes); Code 6.4
Detection of image forgery ch. 7: forensic traces (7.1), JPEG grid detection (7.2), mosaic, noise and copy-move traces (7.3–7.4), evaluation (7.5); Code 7.4
Reference: Gordon, Glazko, Qiu and Yakovlev (2007), mean number of false discoveries and Bonferroni ch. 2.5: Proposition 2.7 and Code 2.8
References: Desolneux, Moisan and Morel (2007); Kanizsa (1979) ch. 1.2–1.3 (Kanizsa), ch. 3–4 (Desolneux, Moisan and Morel)
Organisation: weekly 3-hour lectures, theory and particular cases; regular exercises; a final report on a paper; Université Paris-Saclay: experimental reports based on IPOL articles with online demo, at least one in-depth analysis of a detection paper session plan below (theory then a case each session); Exercises; Projects and assessment (IPOL-based reports and paper studies)
“Les intervenants” not covered: the heading of the list of instructors (Rafael Grompone, ENS Paris-Saclay; Quentin Bammey, Télécom Paris), not a topic

Beyond the syllabus, these notes add the exact Student test for changes in a seasonal series (ch. 6.2), the Hotelling correction of local RX (ch. 5.2), and a self-study chapter on learned background models, conformal p-values and the forensics of generated images (ch. 8).

Where this course fits in the programme

The official pages display no prerequisites. The course uses probability at the level of a good M1: discrete and Gaussian distributions, conditional independence, hypothesis tests, and a little linear algebra.

Course outline

Session plan

24 h in class = 8 sessions of 3 h. The volume is the official one of the Université Paris-Saclay programme table (lectures 24 h). master-mva.com announces weekly online lectures of 3 hours combining theory and the discussion of particular cases; the Université Paris-Saclay detail announces 7 to 9 three-hour sessions, each split into theory and a case analysis, and lists distance teaching as “non”.

The split below is a proposal. Each session gives about two hours of theory and one hour of case analysis with the code of the chapter. Level 1 = foundations, 2 = core results and algorithms, 3 = advanced and research-level material; the level never decreases.

Session Hours Level Content Practice
1 3 h 1 ch. 0 Review: tails, Chernoff and Hoeffding bounds, union bound, super-uniform p-values; ch. 1.1–1.3 vision, Gestalt laws, the Helmholtz principle Ex. 1, 2; case: Code 0.8
2 3 h 1 ch. 1.4–1.5 discrete images: sampling, the gradient of noise, Attneave; ch. 2.1–2.3 detection versus classification, Neyman–Pearson lemma, matched filter Ex. 3, 9; case: Code 1.5
3 3 h 2 ch. 2.4–2.5 multiple testing, Bonferroni and the mean number of false discoveries; ch. 3.1–3.3 background model, NFA, fundamental theorem Ex. 4, 10; case: Code 2.8
4 3 h 2 ch. 3.4–3.6 thresholds and their stability, Gaussian background and Gaussian shape, maximality Ex. 5, 11; case: Code 3.9
5 3 h 2 ch. 4 meaningful alignments, maximal segments, the LSD algorithm, other geometric structures Ex. 6, 13; case: Code 4.6
6 3 h 2 ch. 5 anomaly detection: families of methods, RX and its variants, hyperspectral comparison, the a-contrario reduction to noise Ex. 7, 12; case: Code 5.4
7 3 h 3 ch. 6 time series: exact change tests, cloud screening, categorisation of changes in satellite time series Ex. 8; case: Code 6.4
8 3 h 3 ch. 7 image forgeries: JPEG grid, demosaicking, noise and copy-move traces, evaluation Ex. 14, 15; case: Code 7.4

Self-study, outside the 24 h (about 4 h in total): ch. 8 Research directions and open problems (≈ 4 h, with Ex. 16 and Code 8.2).

How to study this module

0. Review: tails, union bounds and p-values

Every detection threshold of this course is a tail probability multiplied by a number of tests. This review gathers the M1-level tools that compute such tails and that count false alarms without any independence assumption between the tests.

0.1 Binomial tails

Many statistics of the course count how many of n independent observations are “aligned”, “voting” or “changed”, each with probability p under the background model.

Definition 0.1 — Binomial tail Let S_n be the sum of n independent Bernoulli variables of parameter p. For 0 \le k \le n, the binomial tail is \mathcal{B}(n, k, p) = \mathbb{P}(S_n \ge k) = \sum_{j=k}^{n} \binom{n}{j} p^j (1-p)^{n-j} .

The exact tail is cheap to compute (SciPy: binom.sf(k - 1, n, p)), but bounds explain how thresholds grow with the number of tests.

Proposition 0.2 — Chernoff and Hoeffding bounds Let a = k/n with p < a < 1, and let \mathrm{KL}(a \,\|\, p) = a \log \frac{a}{p} + (1-a) \log \frac{1-a}{1-p} be the Kullback–Leibler divergence between two Bernoulli laws. Then \mathcal{B}(n, k, p) \le e^{-n\, \mathrm{KL}(a \| p)} \le e^{-2n (a - p)^2} .

Proof. Chernoff. For every \lambda > 0, Markov’s inequality applied to e^{\lambda S_n} and independence give \mathbb{P}(S_n \ge k) \le e^{-\lambda k}\, \mathbb{E}[e^{\lambda S_n}] = \exp\big(-\lambda k + n \log(1 - p + p e^{\lambda})\big).

The exponent is minimal at e^{\lambda} = a(1-p) / (p(1-a)), which is larger than 1 because a > p. Substituting this value gives exactly -n\, \mathrm{KL}(a \| p).

Hoeffding. Let g(a) = \mathrm{KL}(a \| p) - 2(a-p)^2. Then g(p) = 0 and g'(p) = 0. Its second derivative is g''(a) = \frac{1}{a(1-a)} - 4 \ge 0 , since a(1-a) \le 1/4. So g is convex with a minimum at p, hence non-negative. ∎

Example 0.3 — How loose are the bounds? Take n = 100 observations with p = 1/8, so that 12.5 successes are expected. Code 0.8 prints:

k exact \mathcal{B}(100, k, 1/8) Chernoff Hoeffding
20 2.2 \times 10^{-2} 1.1 \times 10^{-1} 3.3 \times 10^{-1}
25 4.8 \times 10^{-4} 3.1 \times 10^{-3} 4.4 \times 10^{-2}
30 3.0 \times 10^{-6} 2.4 \times 10^{-5} 2.2 \times 10^{-3}
40 4.3 \times 10^{-12} 4.2 \times 10^{-11} 2.7 \times 10^{-7}

The Chernoff bound loses one order of magnitude; Hoeffding loses up to five, because it ignores that p is small.

In practice, thresholds are computed with the exact tail; the bounds serve to understand them.

0.2 Gaussian tails and quadratic forms

Let \varphi be the standard normal density and \Phi^c(z) = \mathbb{P}(Z \ge z) the Gaussian tail.

Proposition 0.4 — Mills ratio bounds For every z > 0, \frac{z}{1 + z^2}\, \varphi(z) \le \Phi^c(z) \le \frac{\varphi(z)}{z} . In particular, the threshold z_\delta = (\Phi^c)^{-1}(\delta) behaves like \sqrt{2 \log(1/\delta)} when \delta \to 0.

Proof. Upper bound. For t \ge z we have t / z \ge 1, and \varphi'(t) = -t \varphi(t), so \Phi^c(z) \le \int_z^\infty \frac{t}{z} \varphi(t)\, dt = \frac{\varphi(z)}{z} .

Lower bound. The derivative of -\varphi(t)/t is \varphi(t)(1 + t^{-2}). Integrating from z to \infty, and using 1 + t^{-2} \le 1 + z^{-2} for t \ge z, \frac{\varphi(z)}{z} = \int_z^\infty \varphi(t)\Big(1 + \frac{1}{t^2}\Big) dt \le \Big(1 + \frac{1}{z^2}\Big) \Phi^c(z) . ∎

For instance, \Phi^c(4) = 3.17 \times 10^{-5} lies between the two bounds 3.15 \times 10^{-5} and 3.35 \times 10^{-5}.

In several bands, the Gaussian tail becomes the tail of a quadratic form. If X \sim \mathcal{N}(\mu, \Sigma) in \mathbb{R}^d with \Sigma invertible, then Y = \Sigma^{-1/2}(X - \mu) is standard normal. Hence the squared Mahalanobis distance (X - \mu)^\top \Sigma^{-1} (X - \mu) = \|Y\|^2 follows the chi-square distribution with d degrees of freedom. This is the basis of the RX detector of ch. 5.

0.3 Counting events without independence

The central computation of the course is the expected number of events that occur among many.

Proposition 0.5 — Linearity and the union bound Let A_1, \dots, A_N be events of a probability space, dependent in any way, and V = \sum_i \mathbf{1}_{A_i} the number of those that occur. Then \mathbb{E}[V] = \sum_{i=1}^N \mathbb{P}(A_i) \qquad \text{and} \qquad \mathbb{P}(V \ge 1) \le \mathbb{E}[V] .

Proof. The first identity is the linearity of expectation applied to indicator functions. The second is Markov’s inequality for the non-negative integer variable V, since \mathbf{1}_{V \ge 1} \le V. ∎

The second inequality is the union bound. Neither statement needs the events to be independent: this is why the a-contrario theory can test millions of overlapping candidates.

0.4 Super-uniform p-values

Definition 0.6 — Super-uniform variable, p-value A random variable U with values in [0, 1] is super-uniform if \mathbb{P}(U \le t) \le t \quad \text{for every } t \in [0, 1].

For a real statistic X with survival function S(x) = \mathbb{P}(X \ge x), the p-value of an observation x is S(x).

Proposition 0.7 — The p-value is super-uniform For every real random variable X, the variable S(X) is super-uniform. It is uniform when the distribution of X is continuous.

Proof. Fix t \in [0, 1]. Since S is non-increasing, the set \{x : S(x) \le t\} is a half-line with left end x^*.

  • If the half-line is closed, [x^*, \infty), then \{S(X) \le t\} = \{X \ge x^*\}, whose probability is S(x^*) \le t.
  • If it is open, (x^*, \infty), then \mathbb{P}(S(X) \le t) = \mathbb{P}(X > x^*). This is the limit of S(x) for x \downarrow x^*, and each S(x) in that limit is at most t.

If the distribution of X is continuous, S(X) = 1 - F(X), where F is the distribution function, and F(X) is uniform. ∎

The proposition matters for discrete statistics such as binomial counts. The test “reject when the p-value is at most \alpha” never has a level larger than \alpha, even though the p-value takes only finitely many values.

Code 0.8 — Binomial tails and their bounds. The script reproduces the table of Example 0.3.

import numpy as np
from scipy.stats import binom

def tail(n, k, p):
    """B(n, k, p) = P(S >= k) for S ~ Binomial(n, p)."""
    return binom.sf(k - 1, n, p)

def kl(a, p):
    """Kullback-Leibler divergence between Bernoulli(a) and Bernoulli(p)."""
    return a * np.log(a / p) + (1 - a) * np.log((1 - a) / (1 - p))

n, p = 100, 1 / 8
for k in (20, 25, 30, 40):
    a = k / n
    print(f"k={k}: exact {tail(n, k, p):.2e}   "
          f"Chernoff {np.exp(-n * kl(a, p)):.2e}   "
          f"Hoeffding {np.exp(-2 * n * (a - p) ** 2):.2e}")

Key takeaways — chapter 0

  • Binomial tails are computed exactly; the Chernoff bound loses about one order of magnitude, Hoeffding much more when p is small.
  • Gaussian tails decay like e^{-z^2/2}: a threshold grows like the square root of the logarithm of the inverse probability.
  • The Mahalanobis distance of a Gaussian vector follows a chi-square law.
  • The expected number of events that occur is the sum of their probabilities, whatever their dependence.
  • A p-value is super-uniform, even for discrete statistics.

1. Perception, Gestalt theory and the discrete image

This chapter asks what a detector should detect. Human vision gives the qualitative answer, the Gestalt laws; the Helmholtz principle makes it quantitative; the discrete nature of images tells which measurements can be treated as independent.

1.1 What vision does

An image is an array of a few million numbers. Seeing consists in interpreting this array in terms of objects, their boundaries and their arrangement. The first step of this interpretation is a grouping: local elements (dots, edge pieces, regions of similar colour) are gathered into wholes that are perceived at once.

Definition 1.1 — Vision as grouping (working definition) In this course, vision is the process that selects, among all the groups that can be formed from the local elements of an image, those that stand out. The rest of the chapter makes “stand out” precise.

Human vision has striking properties that a detection theory must explain.

1.2 The Gestalt laws

Gestalt psychology, from Wertheimer’s 1923 article to the work of Kanizsa (1979), described the grouping laws of perception. Each law, called a partial gestalt, groups elements that share one quality.

Grouping is recursive. A group, for instance a line formed by aligned dots, becomes an element of a higher-level group, for instance a pair of parallel lines.

Several laws can act together and reinforce each other, or conflict. Kanizsa showed that a figure disappears when it is masked, for example when it is embedded in a texture or when added lines create a stronger gestalt that absorbs it.

The Gestalt laws are qualitative. They do not say how close is “close” or how aligned is “aligned”. A computational theory must provide these thresholds, and it must do so without tuning them for each image.

1.3 The Helmholtz principle

The quantitative answer of Desolneux, Moisan and Morel (2007) is a principle that they attribute to Helmholtz: we perceive at once any structure that is too regular to be there by chance. The same idea appears in computer vision as the non-accidentalness of configurations (Lowe, 1985).

Definition 1.2 — Helmholtz principle (quantitative form) Fix a model of images without structure, called the background model, and a list of candidate groups. A group is perceptually meaningful if the expected number of groups at least as regular, in an image drawn from the background model, is small.

Example 1.3 — Dots in a strip Throw 100 points uniformly in the unit square. A strip of area 0.01 contains on average one point. Suppose that we examine N_T = 10^4 strips (100 directions times 100 offsets) and find one with k points.

By Proposition 0.5, the expected number of strips with at least k points is at most 10^4\, \mathcal{B}(100, k, 0.01) .

This gives 5.3 for k = 6 and 0.71 for k = 7. A strip with 7 points is therefore meaningful: in a structureless set of points, fewer than one strip that full is expected.

A strip with 6 points is not: about five such strips appear by chance.

The example contains the whole method of the course: a background model (uniform points), a list of tests (the strips), a statistic (the count) and a threshold derived from a bound on the expected number of false detections.

1.4 The discrete nature of images

A digital image is a set of samples u(k), k \in \mathbb{Z}^2, of a continuous image blurred by the optics. If the continuous image is band-limited, its spectrum being supported in [-\pi, \pi]^2, the Shannon–Whittaker theorem says that it is determined by its samples: u(x) = \sum_{k \in \mathbb{Z}^2} u(k)\, \mathrm{sinc}(x_1 - k_1)\, \mathrm{sinc}(x_2 - k_2) . Here \mathrm{sinc}(t) = \sin(\pi t) / (\pi t). The theorem and its proof are in Sub-Pixel Image Processing.

Three consequences matter for detection.

The gradient used by the LSD detector of ch. 4 makes the second point exact. With a = u(i, j), b = u(i, j+1), c = u(i+1, j) and d = u(i+1, j+1), it is g_x = \frac{b + d - a - c}{2}, \qquad g_y = \frac{c + d - a - b}{2} .

Proposition 1.4 — The gradient of white noise Let u be a white Gaussian noise of variance \sigma^2.

  1. At each pixel, (g_x, g_y) is a centred Gaussian vector with covariance \sigma^2 I_2; hence the gradient orientation is uniform on the circle.
  2. Gradients computed on disjoint 2 \times 2 windows are independent.
  3. For two horizontally adjacent windows, the correlation of the two values of g_x is -1/2.

Proof.

  1. Each of g_x and g_y is a combination of four independent samples with coefficients \pm 1/2, so its variance is 4 \cdot \sigma^2/4 = \sigma^2. Multiplying the coefficients of the four samples, their covariance is \frac{\sigma^2}{4}(1 - 1 - 1 + 1) = 0 . A centred Gaussian vector with covariance \sigma^2 I_2 is invariant by rotation, so its angle is uniform.
  2. Gradients on disjoint windows are functions of disjoint sets of independent samples.
  3. The windows share the column j + 1, which enters the first g_x with coefficient +1/2 and the second with -1/2. The covariance is 2 \cdot (-\frac14)\sigma^2 = -\sigma^2/2, and both variances are \sigma^2. ∎

This is why the alignment detector of ch. 4.1 samples orientations at points two pixels apart. The script below checks the three statements: the empirical covariance matrix is close to the identity, the orientation histogram passes a chi-square test of uniformity, and the correlation of \cos\theta is -0.41 at distance 1 and 0.00 at distance 2.

Code 1.5 — Orientations of a noise image.

import numpy as np
from scipy.stats import chisquare

rng = np.random.default_rng(0)
u = rng.normal(size=(512, 512))                      # white Gaussian noise image

# 2x2 gradient (the scheme of LSD): differences averaged over a 2x2 window
gx = (u[:-1, 1:] + u[1:, 1:] - u[:-1, :-1] - u[1:, :-1]) / 2
gy = (u[1:, :-1] + u[1:, 1:] - u[:-1, :-1] - u[:-1, 1:]) / 2
theta = np.arctan2(gy, gx)

print("var gx, var gy, cov:", np.round([gx.var(), gy.var(), np.mean(gx * gy)], 3))
counts, _ = np.histogram(theta, bins=16, range=(-np.pi, np.pi))
print("chi-square p-value of uniformity: %.2f" % chisquare(counts).pvalue)

# dependence: correlation of cos(theta) between neighbours at distance 1 and 2
c = np.cos(theta)
for d in (1, 2):
    r = np.corrcoef(c[:, :-d].ravel(), c[:, d:].ravel())[0, 1]
    print(f"corr(cos theta) at horizontal distance {d}: {r:+.3f}")

1.5 Attneave’s informational view of perception

Attneave (1954) applied Shannon’s information theory to perception. His observation is that images are highly redundant. A uniform region is predictable from a few of its pixels; information concentrates where the image changes, on the contours. Along a contour, it concentrates where the direction changes most, at the points of maximal curvature.

He illustrated the claim with a drawing of a sleeping cat made of 38 points of maximal curvature joined by straight segments, which remains immediately recognisable.

Two lessons follow for detection.

Key takeaways — chapter 1

  • Perception groups local elements by the Gestalt laws; the laws are qualitative and need thresholds.
  • The Helmholtz principle: a group is perceived when fewer than about one group as regular is expected in a structureless image.
  • An image has as many degrees of freedom as pixels; measurements on overlapping windows are dependent.
  • The 2 \times 2 gradient of white noise has a uniform orientation, independent on disjoint windows and correlated on adjacent ones.
  • Information concentrates on contours and on their curvature extrema (Attneave).

2. Statistical principles of detection

Detection is a statistical decision. This chapter recalls the classical theory of tests, shows what it gives when the object to detect can be modelled, and explains why testing many candidates at once changes the question from “is this test significant?” to “how many false detections do I expect?”.

2.1 Detection is not classification

A classifier learns from labelled examples of every class and minimises a misclassification risk. Detection problems in industry rarely fit this frame.

The theory of this course therefore models the background only, and controls the false alarms first.

2.2 Tests and the Neyman–Pearson lemma

Definition 2.1 — Test, level, power Let the data x have density f_0 under the null hypothesis H_0 and f_1 under the alternative H_1.

A (randomised) test is a function \phi(x) \in [0, 1], the probability of rejecting H_0.

Its level \mathbb{E}_0[\phi] is the probability of a false alarm, and its power \mathbb{E}_1[\phi] is the probability of detection.

Theorem 2.2 — Neyman–Pearson lemma Let \eta \ge 0 and let \phi^* be a test equal to 1 where f_1 > \eta f_0 and to 0 where f_1 < \eta f_0. Then every test \phi with \mathbb{E}_0[\phi] \le \mathbb{E}_0[\phi^*] satisfies \mathbb{E}_1[\phi] \le \mathbb{E}_1[\phi^*] . The likelihood-ratio test is the most powerful test at its level.

Proof. The function (\phi^* - \phi)(f_1 - \eta f_0) is non-negative everywhere. Where f_1 > \eta f_0, the first factor is 1 - \phi \ge 0; where f_1 < \eta f_0, it is -\phi \le 0, and so is the second factor. Integrating, \mathbb{E}_1[\phi^*] - \mathbb{E}_1[\phi] \ge \eta \big(\mathbb{E}_0[\phi^*] - \mathbb{E}_0[\phi]\big) \ge 0 . ∎

2.3 Detecting a known shape: the matched filter

When the object can be modelled, the lemma gives the optimal detector.

Example 2.3 — The matched filter Observe x = a s + w in \mathbb{R}^n, where s is a known shape, a \ge 0 an amplitude and w \sim \mathcal{N}(0, \sigma^2 I_n).

Test H_0: a = 0 against H_1: a = a_1 > 0.

  • The log-likelihood ratio is (a_1 \langle s, x\rangle - a_1^2 \|s\|^2/2)/\sigma^2, an increasing function of \langle s, x \rangle. The optimal test thresholds the normalised correlation T(x) = \frac{\langle s, x \rangle}{\sigma \|s\|} .
  • Under H_0, T \sim \mathcal{N}(0, 1). Under H_1, T \sim \mathcal{N}(d, 1) with the detectability index d = a_1 \|s\| / \sigma.
  • At level \alpha, the threshold is z_\alpha = (\Phi^c)^{-1}(\alpha) and the power is \Phi^c(z_\alpha - d).

The test does not depend on a_1: it is uniformly most powerful against all positive amplitudes.

For \alpha = 10^{-3}, z_\alpha = 3.09; with d = 4 the power is \Phi^c(3.09 - 4) = 0.82 .

Two extensions are used later.

When nothing is known about the object, only H_0 remains. Fisher’s significance test then rejects H_0 when the p-value of a statistic is small. Proposition 0.7 guarantees its level, whatever the alternative.

2.4 Multiple testing

An image of 512 \times 512 pixels tested at four scales gives about a million tests. At level 10^{-3} each, a thousand false alarms are expected on pure noise. This is the phenomenon of the empirical-first example.

Definition 2.4 — Error rates of a family of tests Run N tests, of which N_0 have a true null hypothesis. Let R be the number of rejections and V the number of false rejections. Three error rates are used:

  • the family-wise error rate \mathrm{FWER} = \mathbb{P}(V \ge 1);
  • the per-family error rate, the mean number of false discoveries, \mathrm{PFER} = \mathbb{E}[V];
  • the false discovery rate \mathrm{FDR} = \mathbb{E}[V / \max(R, 1)].

Proposition 2.5 — Bonferroni rule Let p_1, \dots, p_N be p-values, super-uniform under their null hypotheses and dependent in any way. Rejecting H_{0,i} when p_i \le \varepsilon / N guarantees \mathbb{E}[V] \le \varepsilon\, \frac{N_0}{N} \le \varepsilon \qquad \text{and} \qquad \mathrm{FWER} \le \varepsilon .

Proof. By Proposition 0.5, \mathbb{E}[V] is the sum over the true nulls of \mathbb{P}(p_i \le \varepsilon / N). Each term is at most \varepsilon / N by super-uniformity, and there are N_0 terms. The FWER is at most \mathbb{E}[V] by the union bound. ∎

Theorem 2.6 — Benjamini–Hochberg procedure (1995) Sort the p-values, p_{(1)} \le \dots \le p_{(N)}, and let k be the largest index such that p_{(k)} \le q k / N. Rejecting the k smallest p-values gives, for independent p-values, \mathrm{FDR} \le q\, \frac{N_0}{N} . Benjamini and Yekutieli (2001) extended the guarantee to positively dependent p-values. The proof is in their articles and in Lehmann and Romano (2005).

The FDR adapts to the number of discoveries: it rejects more when many signals are present. The Bonferroni rule is often called conservative, but this depends on which error rate it is asked to control.

2.5 The mean number of false discoveries (Gordon et al., 2007)

Gordon, Glazko, Qiu and Yakovlev (2007) argued that the reputation of Bonferroni comes from asking it to control the FWER at a small level. They advocate reading the Bonferroni rule as a control of the PFER, \mathbb{E}[V] \le \varepsilon. A level that is not small, such as \varepsilon = 1, then makes sense.

They also reported the first study of the stability of the two procedures. The Bonferroni rule showed a smaller variance of the number of true discoveries and of the total number of discoveries than Benjamini–Hochberg, which matters most when the p-values are correlated.

Proposition 2.7 — PFER and FWER If \mathbb{E}[V] \le \varepsilon, then \mathrm{FWER} \le \varepsilon. For \varepsilon = 1 the second statement is empty, but the first still says that one false discovery is expected at most, on average over the experiments.

Proof. Proposition 0.5 gives \mathbb{P}(V \ge 1) \le \mathbb{E}[V]. ∎

Code 2.8 reproduces the phenomenon on 2000 Gaussian tests, 100 of them with a signal of 3.5 standard deviations, with the Bonferroni rule at \varepsilon = 1 and Benjamini–Hochberg at q = 0.05. The correlation is introduced by a common factor shared by all the tests.

Correlation Rule \mathbb{E}[V] sd of V \mathbb{E}[R] sd of R
0 Bonferroni 0.95 0.97 59.2 5.0
0 Benjamini–Hochberg 3.69 2.05 76.6 5.9
0.5 Bonferroni 0.93 6.62 59.5 31.1
0.5 Benjamini–Hochberg 13.31 88.47 82.4 98.3

The Bonferroni rule keeps \mathbb{E}[V] = N_0 / N = 0.95 whatever the correlation, as Proposition 2.5 predicts. Its number of discoveries is three times more stable than that of Benjamini–Hochberg under correlation, at the price of fewer discoveries.

The mean number of false discoveries is exactly the quantity that the a-contrario theory controls in images, where the tests are always strongly correlated.

Code 2.8 — Bonferroni and Benjamini–Hochberg under correlation.

import numpy as np
from scipy.stats import norm

rng = np.random.default_rng(1)
m, m1, shift, runs = 2000, 100, 3.5, 4000
eps, q = 1.0, 0.05                                   # PFER target, FDR target

def bh(pv, q):
    """Benjamini-Hochberg step-up: boolean mask of rejections."""
    order = np.argsort(pv)
    ok = pv[order] <= q * np.arange(1, len(pv) + 1) / len(pv)
    k = ok.nonzero()[0].max() + 1 if ok.any() else 0
    rej = np.zeros(len(pv), bool)
    rej[order[:k]] = True
    return rej

truth = np.zeros(m, bool); truth[:m1] = True
for rho in (0.0, 0.5):
    V = {"Bonferroni": [], "BH": []}; R = {"Bonferroni": [], "BH": []}
    for _ in range(runs):
        common = rng.normal()                         # one-factor equicorrelation
        z = np.sqrt(rho) * common + np.sqrt(1 - rho) * rng.normal(size=m) + shift * truth
        pv = norm.sf(z)                               # one-sided p-values
        for name, rej in (("Bonferroni", pv <= eps / m), ("BH", bh(pv, q))):
            V[name].append(np.sum(rej & ~truth)); R[name].append(rej.sum())
    for name in V:
        print(f"rho={rho}  {name:10s}  E[V]={np.mean(V[name]):5.2f}  sd(V)={np.std(V[name]):5.2f}"
              f"  E[R]={np.mean(R[name]):6.1f}  sd(R)={np.std(R[name]):5.1f}")

Key takeaways — chapter 2

  • Detection differs from classification: the objects are rare, and false alarms must be controlled first.
  • The likelihood-ratio test is the most powerful at its level (Neyman–Pearson); for a known shape in Gaussian noise it is the matched filter.
  • Testing many candidates multiplies false alarms; the Bonferroni rule controls the mean number of false discoveries under any dependence.
  • Gordon et al. (2007): read as a control of the PFER, the Bonferroni rule is not overly conservative and is more stable than FDR control under correlation.

3. The a-contrario framework: background model and NFA

This chapter turns the Helmholtz principle of ch. 1 and the Bonferroni rule of ch. 2 into one definition, the number of false alarms. It proves the fundamental property of the definition and computes the thresholds it produces.

3.1 The background model

Definition 3.1 — Background model A background model H_0 is a probability distribution on the data (an image, a set of points, a time series) under which the structures sought are absent. It is a model of the absence of structure, not a model of the real background.

A good background model follows three principles.

Typical choices are independent uniform orientations (justified for noise by Proposition 1.4), independent uniform points, Gaussian white or coloured noise, and exchangeable residuals.

3.2 The number of false alarms

Let the candidates be indexed by i \in \{1, \dots, N_T\}, where N_T is the number of tests. To each candidate is attached a statistic X_i, larger when the candidate is more structured.

Definition 3.2 — Number of false alarms The number of false alarms of candidate i, with observed statistic x_i, is \mathrm{NFA}(i, x) = N_T \cdot \mathbb{P}_{H_0}(X_i \ge x_i) . The candidate is \varepsilon-meaningful when \mathrm{NFA}(i, x) \le \varepsilon.

More generally, any function of the candidate and the data is called an NFA if it satisfies the property of the next theorem.

Key result — the fundamental property of the NFA \mathbb{E}_{H_0}\Big[\#\{ i : \mathrm{NFA}(i, X) \le \varepsilon \}\Big] \le \varepsilon \quad \text{for every } \varepsilon > 0

Theorem 3.3 — Control of the number of false detections The NFA of Definition 3.2 satisfies the key property: under the background model, the expected number of \varepsilon-meaningful candidates is at most \varepsilon. No independence between the statistics X_i is required.

Proof. Let S_i(x) = \mathbb{P}_{H_0}(X_i \ge x) be the survival function of X_i. By Proposition 0.5, \mathbb{E}_{H_0}\big[\#\{i : \mathrm{NFA}(i, X) \le \varepsilon\}\big] = \sum_{i=1}^{N_T} \mathbb{P}_{H_0}\Big( S_i(X_i) \le \frac{\varepsilon}{N_T} \Big) . By Proposition 0.7, S_i(X_i) is super-uniform, so each term is at most \varepsilon / N_T. The sum is at most \varepsilon. ∎

The NFA is the Bonferroni rule of Proposition 2.5 written as a single number per candidate. The threshold \varepsilon is the mean number of false detections that the user accepts per image; the default is \varepsilon = 1.

Different families of candidates often have different sizes, for instance segments of different lengths. The tests can then be weighted.

Proposition 3.4 — Weighted tests Let w_i > 0 be weights with \sum_i w_i \le 1. Then \mathrm{NFA}_w(i, x) = \frac{\mathbb{P}_{H_0}(X_i \ge x_i)}{w_i} satisfies the key property.

With K families of sizes N_1, \dots, N_K, take w_i = 1/(K N_k) for i in family k. The NFA of a candidate of family k is then K N_k \cdot \mathbb{P}_{H_0}(X_i \ge x_i) .

Proof. As in Theorem 3.3, the expectation is the sum over i of \mathbb{P}(S_i(X_i) \le \varepsilon w_i), which is at most \varepsilon \sum_i w_i \le \varepsilon. ∎

3.3 What the NFA is and is not

Example 3.5 — A cluster of points Throw n = 1000 points uniformly in the unit square and test N_T = 5 \times 10^4 discs of area a = 0.01, centred at the nodes of a fine grid. Each disc contains \mathrm{Binomial}(1000, 0.01) points under H_0, ten on average.

The NFA of a disc with k points is 5 \times 10^4 \cdot \mathcal{B}(1000, k, 0.01).

The smallest k with \mathrm{NFA} \le 1 is k = 26; for \varepsilon = 0.01 it is k = 31.

The Chernoff bound of Proposition 0.2 predicts the threshold 27.8, while Hoeffding predicts 83.6: with a small p, only the exact tail or the Chernoff bound are usable.

3.4 Thresholds and their stability

Detection thresholds depend on \varepsilon and on N_T only through \log(N_T / \varepsilon).

Proposition 3.6 — Threshold growth

  1. Gaussian statistic. If X_i \sim \mathcal{N}(0, 1) under H_0, the detection threshold is z(\varepsilon) = (\Phi^c)^{-1}(\varepsilon / N_T), and for N_T / \varepsilon \ge 2, z(\varepsilon) \le \sqrt{2 \log(N_T / \varepsilon)} .
  2. Binomial statistic. If X_i \sim \mathrm{Binomial}(n, p), every count k with k \ge np + \sqrt{\tfrac{n}{2} \log(N_T / \varepsilon)} is \varepsilon-meaningful.

Proof.

  1. Let z_0 = \sqrt{2 \log(N_T / \varepsilon)} \ge 1.17. By Proposition 0.4, \Phi^c(z_0) \le \frac{\varphi(z_0)}{z_0} = \frac{e^{-z_0^2/2}}{z_0 \sqrt{2\pi}} . The factor 1/(z_0 \sqrt{2 \pi}) is smaller than 1, so \Phi^c(z_0) \le \varepsilon / N_T and the threshold is at most z_0.
  2. By Hoeffding’s bound, \mathcal{B}(n, k, p) \le \exp(-2(k - np)^2 / n), which is at most \varepsilon / N_T under the stated condition. ∎

For N_T = 65\,536 tests, the Gaussian thresholds are:

\varepsilon 0.01 0.1 1 10 100
z(\varepsilon) 5.12 4.67 4.17 3.61 2.96

Multiplying \varepsilon by 10^4 moves the threshold by about two standard deviations. This weak dependence is why \varepsilon = 1 is used everywhere, and why a-contrario detectors are often said to have no detection parameter: the user fixes the accepted number of false alarms, not a threshold on the statistic.

3.5 Gaussian models of the background and of the shape

The Université Paris-Saclay programme asks for Gaussian modelling of the background and of the shape to be detected. Both appear naturally.

The background alone defines the NFA. For a template s_i in white noise, T_i = \frac{\langle s_i, u - \mu \rangle}{\sigma \|s_i\|}, \qquad \mathrm{NFA}(i) = N_T\, \Phi^c(T_i) . For coloured noise, T_i is the whitened statistic of ch. 2.3.

The shape model gives the detectability: under the shape model, T_i \sim \mathcal{N}(a\|s_i\|/\sigma, 1). The probability of detection at level \varepsilon is \mathbb{P}(\text{detect}) = \Phi^c\big(z(\varepsilon) - a \|s_i\| / \sigma\big), and an object is detected with probability one half when its amplitude reaches a_{\min} = \sigma z(\varepsilon) / \|s_i\|.

Example 3.7 — Detecting a faint spot In a 128 \times 128 image, test discs of radius 1 to 4 at every pixel: N_T = 128^2 \times 4 = 65\,536 and z(1) = 4.17.

  • A disc of radius 3 contains 29 pixels, so \|s\| = \sqrt{29} for the indicator template.
  • The minimal contrast is a_{\min} = 4.17 / \sqrt{29} = 0.77 noise standard deviations.
  • A spot of contrast 1 is detected with probability \Phi^c(4.17 - 5.39) = 0.89, although no pixel of it is visible in the noise.

Code 3.9 checks these numbers on simulated images; its output is discussed in § 3.6.

3.6 Redundancy and maximality

Overlapping candidates see the same object several times. A bright spot is detected at several neighbouring centres and radii; a long alignment contains many meaningful sub-segments.

Definition 3.8 — Maximal meaningful candidate Let candidates be related by inclusion or overlap. A meaningful candidate is maximal if no related candidate has a strictly smaller NFA. A detector reports maximal candidates only, or applies an exclusion principle: each local element (pixel, point) is assigned to at most one detected group, the most meaningful one.

Reporting maximal candidates does not increase the number of false detections, since it only removes candidates from the list.

In Code 3.9, the mean number of 1-meaningful tests on pure noise is 1.05, close to \varepsilon, as Theorem 3.3 predicts. After grouping connected detections, the mean number of detected spots is 0.80, because some false detections come in clusters.

With a spot of contrast 0.5, below a_{\min}, the true spot is missed (\log_{10} \mathrm{NFA} = 0.77) and one false spot appears elsewhere. With contrast 1, the spot is found with \log_{10} \mathrm{NFA} = -7.2 and no false spot appears.

Code 3.9 — A-contrario detection of spots in Gaussian noise.

import numpy as np
from scipy.stats import norm
from scipy.ndimage import label

rng = np.random.default_rng(5)
n, radii = 128, (1, 2, 3, 4)
yy, xx = np.mgrid[:n, :n]
dist2 = np.minimum(yy, n - yy) ** 2 + np.minimum(xx, n - xx) ** 2   # periodic distance to 0
discs = [(dist2 <= r * r).astype(float) for r in radii]
fft_discs = [np.fft.fft2(d) for d in discs]
N_tests = n * n * len(radii)

def log10_nfa(u):
    """log10 NFA of a bright disc centred at each pixel, for each radius (sigma = 1 known)."""
    U = np.fft.fft2(u)
    out = []
    for d, D in zip(discs, fft_discs):
        t = np.real(np.fft.ifft2(U * np.conj(D))) / np.sqrt(d.sum())   # ~ N(0,1) under H0
        out.append(np.log10(N_tests) + norm.logsf(t) / np.log(10))
    return np.array(out)

print("N_tests =", N_tests, " threshold z(eps=1) = %.2f" % norm.isf(1 / N_tests))
for eps in (0.1, 1.0, 10.0):
    tests, groups = [], []
    for _ in range(200):
        det = log10_nfa(rng.normal(size=(n, n))) <= np.log10(eps)
        tests.append(det.sum()); groups.append(label(det.any(axis=0))[1])
    print(f"eps={eps:5}: mean detected tests {np.mean(tests):6.3f}, "
          f"mean detected spots {np.mean(groups):6.3f}")

# a faint spot of radius 3 and contrast a (in units of the noise sigma)
for a in (0.5, 1.0):
    u = rng.normal(size=(n, n)); u[(xx - 64) ** 2 + (yy - 64) ** 2 <= 9] += a
    L = log10_nfa(u)
    near = (xx - 64) ** 2 + (yy - 64) ** 2 <= 25            # within 5 pixels of the spot
    lab, k = label((L <= 0).any(axis=0))
    false = len(set(np.unique(lab[~near])) - set(np.unique(lab[near])) - {0})
    print(f"contrast {a}: best log10 NFA near the spot = {L[:, near].min():5.2f}, "
          f"false spots elsewhere = {false}")

Key takeaways — chapter 3

  • A background model describes the absence of structure; the NFA of a candidate is the number of tests times the tail probability of its statistic.
  • Under the background model, the expected number of \varepsilon-meaningful candidates is at most \varepsilon, with no independence between tests.
  • Tests can be weighted to share the budget between families of different sizes.
  • Thresholds depend on \log(N_T / \varepsilon) only; \varepsilon = 1 is the universal default.
  • A Gaussian background gives the NFA; a Gaussian shape model gives the detectability and the minimal contrast.
  • Report maximal meaningful candidates to remove redundant detections.

4. Detection of geometric structures

Alignments are the simplest Gestalt and the most frequent structure of man-made scenes. This chapter detects them a contrario, first as alignments of orientations (Desolneux, Moisan and Morel, 2000), then as line segments with the LSD algorithm.

4.1 Meaningful alignments

Consider an image of N \times N pixels and its level-line orientation \theta(x), the gradient direction rotated by \pi/2. Orientations are sampled at points two pixels apart, so that by Proposition 1.4 they are independent on noise.

Definition 4.1 — NFA of a segment There are about N^4 segments (pairs of endpoints). The NFA of a segment with k aligned points among l is \mathrm{NFA}(S) = N^4\, \mathcal{B}(l, k, p) .

By Theorem 3.3, fewer than \varepsilon segments are \varepsilon-meaningful on average in a noise image.

Proposition 4.2 — Thresholds of alignments

  1. A segment of l points is \varepsilon-meaningful as soon as k \ge pl + \sqrt{\tfrac{l}{2} \log(N^4 / \varepsilon)} .
  2. A segment whose points are all aligned is \varepsilon-meaningful if and only if l \ge \frac{\log(N^4 / \varepsilon)}{\log(1/p)} .

Proof.

  1. This is Proposition 3.6 with N_T = N^4.
  2. For k = l, the tail is \mathcal{B}(l, l, p) = p^l, and N^4 p^l \le \varepsilon is the stated inequality. ∎

Example 4.3 — How long must an alignment be? For N = 512 and p = 1/16, a perfect alignment needs l \ge \frac{4 \log 512}{\log 16} = 9 points, a segment about 18 pixels long. For p = 1/8 it needs 12 points, and for N = 1024 and p = 1/16, 10 points. The exact tail gives the thresholds for imperfect alignments: with p = 1/16 and N = 512, 13 aligned points out of 20, 16 out of 30 and 20 out of 50.

The threshold grows only logarithmically with the size of the image: at p = 1/16, doubling the image side adds one point.

4.2 Maximal meaningful segments

When a long alignment is present, many of its sub-segments and super-segments are meaningful too. Following Definition 3.8, a meaningful segment is maximal if it contains no segment with a strictly smaller NFA, and no segment containing it has an NFA smaller than or equal to its own.

Maximal segments locate the endpoints of the alignment: extending a segment into non-aligned points increases its NFA, and cutting aligned points also increases it. The script of § 4.4 reports, for a planted alignment, the segment of smallest NFA, which is the maximal one.

4.3 The LSD line segment detector

LSD (Grompone von Gioi, Jakubowicz, Morel and Randall, 2010) detects line segments in linear time, with the a-contrario validation of § 4.1 adapted to rectangles of pixels.

Algorithm 4.4 — LSD

  1. Scale. Filter the image with a Gaussian and sub-sample it to 80 % of its size, which reduces aliasing and quantisation artefacts.
  2. Gradient. Compute the 2 \times 2 gradient of Proposition 1.4 and the level-line angle at each pixel. Discard pixels whose gradient is too small for a reliable orientation, given the quantisation of grey levels.
  3. Pseudo-ordering. Sort the pixels by decreasing gradient magnitude, with a bucket sort.
  4. Region growing. From each unused seed, add the neighbours whose angle is within \tau = 22.5° of the region angle, updated as pixels are added.
  5. Rectangle. Approximate the region by a rectangle: its centre is the centroid weighted by the gradient magnitude, and its direction is the principal axis of the weighted inertia matrix. Rectangles with too few aligned pixels are cut.
  6. Validation. Compute the NFA of the rectangle, try a few refinements (smaller precision or width), and keep the rectangle if \mathrm{NFA} \le \varepsilon = 1.

Definition 4.5 — NFA of a rectangle in LSD In an image of N \times M pixels, a rectangle containing n pixels, k of them aligned at precision p = \tau/\pi = 1/8, has \mathrm{NFA}(r) = (NM)^{5/2}\, \gamma\, \mathcal{B}(n, k, p) . The factor (NM)^{5/2} counts the rectangles: NM starting points, NM end points and \sqrt{NM} widths. The factor \gamma = 11 counts the precisions tried during refinement.

For a 512 \times 512 image, N_T = 3.9 \times 10^{14}. A perfectly aligned rectangle one pixel wide must contain at least 17 pixels, since \log_{10} N_T / \log_{10} 8 = 16.2. A rectangle of 60 pixels needs at least 34 aligned ones.

LSD counts every pixel of the rectangle, although adjacent 2 \times 2 gradients are dependent (Proposition 1.4, point 3). The experiments of its authors on noise images show essentially no detection, and the method has no parameter to tune for each image.

4.4 Other geometric structures

The same three ingredients, background model, statistic and number of tests, give detectors for many structures.

Structure Background model Statistic Reference
Edges along level lines independent gradient magnitudes minimal contrast along the curve Desolneux, Moisan and Morel (2001)
Alignments of points uniform points points in a thin strip, compared with its neighbourhood Lezama, Morel, Randall and Grompone von Gioi (2015)
Circles and ellipses uniform orientations orientations aligned with the conic Pătrăucean, Gurdjos and Grompone von Gioi (2017)
Rigid point matches independent uniform points residuals of the epipolar constraint Moisan and Stival (2004)

In each case, most of the work goes into the number of tests: it must count every candidate the algorithm could have examined, including the parameters tuned on the data.

Code 4.6 — Alignments on an orientation grid. The script tests every segment of every row, column and diagonal of a 64 \times 64 grid of orientations, in both directions, at precision p = 1/8. On pure noise, the mean number of 1-meaningful segments over 50 grids is 0.20, below \varepsilon = 1. A planted diagonal segment of 30 sites, with orientations spread by 0.25 rad around the right direction, is detected with \log_{10} \mathrm{NFA} = -13.3 on exactly its 30 sites.

import numpy as np
from scipy.stats import binom

rng = np.random.default_rng(3)
n, p = 64, 1 / 8                     # grid of n x n orientations, precision p
logB = np.full((n + 1, n + 1), 0.0)  # log10 B(l, k, p), lookup table
for l in range(1, n + 1):
    logB[l, :l + 1] = binom.logsf(np.arange(l + 1) - 1, l, p) / np.log(10)

def grid_lines(n):
    """Rows, columns, diagonals and anti-diagonals: (rows, cols) of the sites, direction."""
    i = np.arange(n)
    out = []
    for r in range(n):
        out += [((np.full(n, r), i), 0.0), ((i, np.full(n, r)), np.pi / 2)]
    for d in range(-n + 1, n):
        j = i[(i + d >= 0) & (i + d < n)]
        out.append(((j, j + d), np.pi / 4))            # y - x = -d
    for s in range(2 * n - 1):
        j = i[(s - i >= 0) & (s - i < n)]
        out.append(((j, s - j), 3 * np.pi / 4))        # y + x = s
    return out

LINES = grid_lines(n)
N_tests = sum(2 * len(y) * (len(y) + 1) // 2 for (y, x), _ in LINES)

def meaningful(theta, eps=1.0):
    """List of (log10 NFA, line index, start, end) of eps-meaningful segments."""
    out = []
    for idx, ((y, x), phi) in enumerate(LINES):
        for direction in (phi, phi + np.pi):
            diff = np.angle(np.exp(1j * (theta[y, x] - direction)))
            c = np.concatenate([[0], np.cumsum(np.abs(diff) <= p * np.pi)])
            s, e = np.triu_indices(len(y))            # segment = sites s..e
            l, k = e - s + 1, c[e + 1] - c[s]
            lnfa = np.log10(N_tests) + logB[l, k]
            for t in np.nonzero(lnfa <= np.log10(eps))[0]:
                out.append((lnfa[t], idx, s[t], e[t]))
    return out

print("number of tests N_T =", N_tests)
counts = [len(meaningful(rng.uniform(0, 2 * np.pi, (n, n)))) for _ in range(50)]
print("pure noise: mean number of 1-meaningful segments = %.2f" % np.mean(counts))

theta = rng.uniform(0, 2 * np.pi, (n, n))
j = np.arange(10, 40)                                  # a diagonal segment of 30 sites
theta[j, j] = np.pi / 4 + rng.normal(0, 0.25, j.size)   # ~88% within p*pi = 22.5 deg
best = min(meaningful(theta))
print("planted segment: best log10 NFA = %.1f, sites %d..%d" % (best[0], best[2], best[3]))

Key takeaways — chapter 4

  • An alignment is tested by counting orientations within p\pi of the segment direction; its NFA is N^4 \mathcal{B}(l, k, p).
  • A perfect alignment needs about \log(N^4) / \log(1/p) independent points: 9 points for N = 512, p = 1/16.
  • Maximal meaningful segments locate the endpoints of the alignment.
  • LSD grows regions of aligned pixels, fits rectangles and validates them with the NFA of Definition 4.5, which counts (NM)^{5/2} rectangles.
  • Every structure detector follows the same pattern; counting the tests honestly is the hard part.

5. Anomaly detection in images and hyperspectral data

An anomaly is whatever the model of normal data does not explain: a defect on a textile, a lesion, a rare material in a hyperspectral scene. This chapter reviews the families of anomaly detectors, compares the classical Gaussian detectors of hyperspectral imaging, and shows what the a-contrario approach adds: a threshold that means the same thing on every data set.

5.1 A generic problem and its families of methods

Ehret, Davy, Morel and Delbracio (2019) review image anomaly detectors and group them by the model of normality they use.

Every family produces an anomaly score per pixel. The decision threshold is the weak point: it is usually tuned on each data set, often with labelled anomalies that detection problems lack.

5.2 The Gaussian background in several bands: RX

In a hyperspectral image, each pixel is a vector x \in \mathbb{R}^d of reflectances in d bands, with d from tens to hundreds.

Proposition 5.1 — The RX detector (Reed and Yu, 1990) Let the background pixels follow \mathcal{N}(\mu, \Sigma), and consider the alternative x \sim \mathcal{N}(\mu + b, \Sigma) with an unknown shift b.

  1. The generalised likelihood ratio statistic is the squared Mahalanobis distance D(x) = (x - \mu)^\top \Sigma^{-1} (x - \mu) .
  2. Under the background model, D(x) follows a chi-square law with d degrees of freedom.

Proof.

  1. The log-likelihood ratio at shift b is \tfrac12 D(x) - \tfrac12 (x - \mu - b)^\top \Sigma^{-1} (x - \mu - b) . Its maximum over b is attained at b = x - \mu and equals D(x)/2.
  2. This is the quadratic form of ch. 0.2. ∎

The a-contrario threshold follows: with N pixels, \mathrm{NFA}(x) = N \cdot \mathbb{P}(\chi^2_d \ge D(x)). For N = 10^4 and d = 10, the threshold is D \ge 35.6, for a mean of 10 under H_0.

The global RX detector uses one mean and one covariance for the whole image. Local RX estimates them in a window around each pixel, which adapts to a changing background but adds estimation noise.

Proposition 5.2 — Local RX with estimated statistics Let y_1, \dots, y_n and x be independent \mathcal{N}(\mu, \Sigma) vectors of \mathbb{R}^d, with n > d.

Let \bar y be the mean of the y_j, S their unbiased covariance, and \hat D = (x - \bar y)^\top S^{-1} (x - \bar y). Then \frac{n - d}{d\,(n-1)} \cdot \frac{n}{n+1}\, \hat D \sim F(d,\, n - d) .

Proof. The vector x - \bar y is Gaussian, centred, with covariance (1 + 1/n)\Sigma, and it is independent of S, because the sample mean and covariance of Gaussian vectors are independent. (n-1) S is a Wishart matrix with n - 1 degrees of freedom.

So \hat D / (1 + 1/n) is Hotelling’s T^2 statistic with parameters (d, n-1). Its classical relation to the Fisher law, proved in Anderson (2003), gives the result. ∎

With a window of n = 50 pixels and d = 10 bands, the threshold for a false alarm probability of 10^{-4} is \hat D \ge 62.9, not 35.6. Using the chi-square threshold would give a false alarm rate of about 1 %, a hundred times the nominal one; a simulation of 2 \times 10^4 draws confirms the Fisher law.

5.3 Comparing classical detectors on a hyperspectral example

Two more detectors complete the classical toolbox.

Example 5.3 — A synthetic scene Code 5.4 builds a 100 \times 100 scene with d = 10 bands: two fields of different materials, a one-pixel-wide road of a third material (1 % of the pixels), multiplicative illumination noise and sensor noise. Twelve sub-pixel targets mix 15 % of a target spectrum into the background. All thresholds are set by \mathrm{NFA} \le 1.

Detector Targets found False alarms AUC
global RX 2 / 12 100 0.985
mixture RX (K = 3) 10 / 12 0 1.000
matched filter 11 / 12 0 1.000

Global RX flags all 100 road pixels: the road is rare but normal, and a single Gaussian cannot explain it. Its covariance, inflated by the mixture of materials, also hides the faint targets.

The mixture model explains the road and recovers the targets. The matched filter, which knows the target, is the most powerful, as Neyman–Pearson predicts.

The lesson of the comparison is that anomaly is not the same as target. An anomaly detector is only as good as its background model, and the NFA tells when that model is wrong: on a target-free scene, many more than \varepsilon detections mean that the background model must be enriched.

Code 5.4 — RX, mixture RX and matched filter with a-contrario thresholds.

import numpy as np
from scipy.stats import chi2, norm
from sklearn.mixture import GaussianMixture
from sklearn.metrics import roc_auc_score

rng = np.random.default_rng(4)
H = W = 100; d = 10; N = H * W
bands = np.linspace(0, 1, d)
spec = lambda c, w: 0.4 + 0.3 * np.exp(-(bands - c) ** 2 / w)  # smooth reflectance curves
mA, mB, mC, tgt = spec(0.2, 0.05), spec(0.7, 0.08), spec(0.5, 0.3), spec(0.9, 0.02)

cls = np.where(np.arange(W) < W // 2, 0, 1)[None, :].repeat(H, 0)  # two fields
cls[:, 30] = 2                                                     # a road: 1 % of pixels
M = np.stack([mA, mB, mC])[cls]                                    # H x W x d
X = M * (1 + 0.05 * rng.normal(size=(H, W, 1))) + 0.01 * rng.normal(size=(H, W, d))
truth = np.zeros((H, W), bool)
pos = rng.choice(np.flatnonzero(cls.ravel() != 2), 12, replace=False)
truth.flat[pos] = True
X[truth] = 0.85 * X[truth] + 0.15 * tgt                            # sub-pixel targets
X, truth = X.reshape(N, d), truth.ravel()

def rx(X, mu, S):
    Y = X - mu
    return np.einsum("ij,jk,ik->i", Y, np.linalg.inv(S), Y)

def report(name, log10nfa, score):
    det = log10nfa <= 0                                            # eps = 1
    print(f"{name:12s} targets found {np.sum(det & truth):2d}/12, false alarms "
          f"{np.sum(det & ~truth):4d}, AUC {roc_auc_score(truth, score):.3f}")

D = rx(X, X.mean(0), np.cov(X.T))                       # global RX, chi2(d) under H0
report("global RX", np.log10(N) + chi2.logsf(D, d) / np.log(10), D)

K = 3                                                   # Gaussian mixture background
gm = GaussianMixture(K, covariance_type="full", n_init=3, random_state=0).fit(X)
Dk = np.min([rx(X, gm.means_[c], gm.covariances_[c]) for c in range(K)], axis=0)
report("mixture RX", np.log10(N) + chi2.logsf(Dk, d) / np.log(10), Dk)

mu, Si = X.mean(0), np.linalg.inv(np.cov(X.T))          # matched filter, known target
s = tgt - mu
T = (X - mu) @ Si @ s / np.sqrt(s @ Si @ s)
report("matched filt", np.log10(N) + norm.logsf(T) / np.log(10), T)

5.4 The a-contrario contribution: reducing anomalies to detection in noise

Davy, Ehret, Morel and Delbracio (2018) proposed a generic way to give any background model a calibrated threshold.

  1. Model the background with a method that reconstructs normal content well and anomalies badly, for instance by replacing each patch with an average of its most similar patches elsewhere in the image (self-similarity), possibly in the feature space of a neural network.
  2. Compute the residual, the image minus its reconstruction. Under the background, the residual is close to a structureless noise; normalise it to zero mean and unit variance.
  3. Detect a contrario in the residual, as in ch. 3.5: average the residual over discs of several radii; a deviation in either direction is tested with \mathrm{NFA} = N_{\text{pix}}\, N_{\text{scales}} \cdot 2\, \Phi^c(|T|) .

The reconstruction step carries the knowledge of the data; the detection step is always the same and is calibrated by \varepsilon. When the residual is a coloured rather than white noise, it is whitened first, as Grosjean and Moisan (2009) do for spots in textured backgrounds.

Key takeaways — chapter 5

  • Anomaly detectors differ by their model of normality; their weak point is the decision threshold.
  • RX is the generalised likelihood ratio for a Gaussian background; its statistic follows a chi-square law with d degrees of freedom.
  • With locally estimated statistics, the Fisher law replaces the chi-square law; ignoring it multiplies false alarms.
  • A rare but normal material is an anomaly for a poor background model: anomaly is not target.
  • Reconstruct the background, normalise the residual, and detect a contrario in the residual.

6. Detection in time series and recurrent satellite imaging

Satellite constellations now image every place on Earth every few days; the two Sentinel-2 satellites, for instance, revisit the equator every five days. Each pixel becomes a time series, and the questions become temporal: was there a change, when, and of which kind? This chapter builds exact a-contrario tests for changes in seasonal series, screens clouds, and categorises the changes.

6.1 Background models of a time series

Let y = (y_1, \dots, y_T) be the series of a vegetation index at one pixel, for instance the NDVI, the normalised difference of the near-infrared and red reflectances.

The parameters \beta and \sigma are nuisances: the test must be exact whatever their values.

6.2 An exact test for a change

Theorem 6.1 — Student test of a change profile Let y = A\beta + w with A of rank q, w \sim \mathcal{N}(0, \sigma^2 I_T), and let c \notin \mathrm{span}(A).

Let Q = I - A A^{+} be the orthogonal projector onto \mathrm{span}(A)^\perp and define \pi = \frac{c^\top Q y}{\|Qc\|}, \qquad s^2 = \frac{\|Qy\|^2 - \pi^2}{T - q - 1}, \qquad z = \frac{\pi}{s} . Then, whatever \beta and \sigma, z follows a Student law with T - q - 1 degrees of freedom.

Proof. Since QA = 0, Qy = Qw. Let e_1 = Qc / \|Qc\|, and complete it into an orthonormal basis e_1, \dots, e_{T-q} of \mathrm{span}(A)^\perp.

  • The coordinates \langle e_j, w \rangle are independent \mathcal{N}(0, \sigma^2), because w is isotropic.
  • \pi = \langle e_1, Qw \rangle = \langle e_1, w \rangle.
  • \|Qy\|^2 - \pi^2 = \sum_{j \ge 2} \langle e_j, w \rangle^2, which is \sigma^2 times a \chi^2_{T-q-1} variable, independent of \pi.

The ratio of a standard normal variable to the square root of an independent \chi^2_m / m variable is Student with m degrees of freedom. ∎

The statistic is the t-statistic of the coefficient of c in the regression on [A, c]. Over N_{\text{pix}} pixels, K families of change profiles and n_f profiles in family f, Proposition 3.4 gives the two-sided NFA \mathrm{NFA} = N_{\text{pix}}\, K\, n_f \cdot 2\, \mathbb{P}(t_{T-q-1} \ge |z|) .

Example 6.2 — The smallest detectable step Take T = 100 dates, a constant background (q = 1), noise \sigma = 0.04, and a step in the middle of the series. Then Qc = c - \frac12, so \|Qc\| = 5, and a step of height \delta gives a statistic of mean about \frac{\delta}{\sigma \sqrt{1/50 + 1/50}} = \frac{5\,\delta}{\sigma} , that is 12.5 for \delta = 0.1.

With N_T \approx 10^5 tests (1000 pixels, 99 dates) and the two-sided NFA, the threshold is |z| \ge 4.7. The smallest step detected half of the time is \delta_{\min} \approx 4.7 \times 0.04 \times 0.2 = 0.037 , less than one noise standard deviation.

Classical alternatives exist. CUSUM (Page, 1954) detects changes sequentially, PELT (Killick, Fearnhead and Eckley, 2012) segments a series into many pieces, and BFAST (Verbesselt et al., 2010) and CCDC (Zhu and Woodcock, 2014) are standard tools for satellite series. The a-contrario version adds a calibrated threshold across millions of pixel series.

6.3 Families of changes and their categorisation

Three families of profiles describe the usual changes, each indexed by a start date s.

Definition 6.3 — A-contrario categorisation For each pixel, compute the smallest NFA in each family. If none is at most \varepsilon, the pixel is stable. Otherwise its change belongs to the family of smallest NFA, and the date of the change is the corresponding s.

The factor n_f in the NFA acts as a complexity penalty: a family with more profiles, here the transients with three durations, must explain the data better to be chosen.

6.4 Cloud detection in recurrent satellite imaging

Clouds and their shadows are the main source of false changes. Single-date methods such as Fmask (Zhu and Woodcock, 2012) test spectral properties: clouds are bright, white and cold. Recurrent imaging adds two sources of evidence.

6.5 Detection and temporal categorisation of changes: a case

Code 6.4 simulates 1000 NDVI series of 100 dates with a seasonal cycle and noise \sigma = 0.04. 850 pixels are stable, and 50 each have an abrupt, a transient and a gradual change of amplitude 0.25. Clouds hit 8 % of the dates.

  1. Clouds are screened on the blue band with N_T = 10^5 tests: 8.0 % of the dates are flagged, for 8.0 % truly cloudy.
  2. On the remaining dates, Theorem 6.1 tests every profile of the three families, with \varepsilon = 1 for the whole image.
Truth \ decision stable abrupt transient gradual
stable (850) 849 0 1 0
abrupt (50) 0 50 0 0
transient (50) 0 0 50 0
gradual (50) 0 0 0 50

One stable pixel out of 850 is declared changed, consistent with the guarantee of at most one false alarm on average per image. All changes are found and correctly categorised.

Code 6.4 — Cloud screening, change detection and categorisation.

import numpy as np
from scipy.stats import norm, t as student

rng = np.random.default_rng(5)
T, P, npix, sig = 100, 50, 1000, 0.04          # dates, season period, pixels, noise
t = np.arange(T)
kind = np.repeat([0, 1, 2, 3], [850, 50, 50, 50])   # stable, abrupt, transient, gradual
t0 = rng.integers(20, 80, npix)
ndvi = 0.5 + 0.2 * np.sin(2 * np.pi * t / P) + sig * rng.normal(size=(npix, T))
ndvi -= np.where(kind[:, None] == 1, 0.25 * (t >= t0[:, None]), 0)
ndvi -= np.where(kind[:, None] == 2, 0.25 * ((t >= t0[:, None]) & (t < t0[:, None] + 8)), 0)
ndvi -= np.where(kind[:, None] == 3, 0.25 * np.clip((t - t0[:, None]) / 20, 0, 1), 0)
cloud = rng.random((npix, T)) < 0.08
ndvi[cloud] -= 0.5                                  # clouds darken NDVI ...
blue = 0.05 + 0.005 * rng.normal(size=(npix, T)) + 0.3 * cloud   # ... and brighten blue

# 1. cloud screening: a-contrario test of a bright blue value, N_T = npix * T tests
zb = (blue - np.median(blue, 1, keepdims=True)) / 0.005
valid = np.log10(npix * T) + norm.logsf(zb) / np.log(10) > 0

# 2. change families: contrast vectors c (one per row), with their family index
C, fam = [], []
for s in range(1, T):
    C.append(t >= s); fam.append(0)                              # abrupt
    C.append(np.clip((t - s) / 20, 0, 1)); fam.append(2)         # gradual (ramp)
    for w in (4, 8, 16):
        C.append((t >= s) & (t < s + w)); fam.append(1)          # transient
C, fam = np.array(C, float), np.array(fam)
n_f = np.bincount(fam)                                           # tests per family
A = np.stack([np.ones(T), np.sin(2 * np.pi * t / P), np.cos(2 * np.pi * t / P)], 1)

pred = np.zeros(npix, int)                                       # 0 = no change
for i in range(npix):
    v = valid[i]
    Q = np.eye(v.sum()) - A[v] @ np.linalg.pinv(A[v])            # residual projector
    y, Rc = ndvi[i, v], C[:, v] @ Q
    nc = np.maximum(np.linalg.norm(Rc, axis=1), 1e-9)
    proj = Rc @ y / nc                                           # component of y along Qc
    dof = v.sum() - 4                                            # model [A, c] has 4 columns
    s2 = (np.sum((Q @ y) ** 2) - proj ** 2) / dof                # residual variance of [A, c]
    z = proj / np.sqrt(s2)                                       # Student t(dof) under H0
    lnfa = np.log10(npix * 3 * n_f[fam] * 2) + student.logsf(np.abs(z), dof) / np.log(10)
    lnfa[nc < 1e-6] = np.inf
    if lnfa.min() <= 0:
        pred[i] = 1 + fam[np.argmin(lnfa)]                       # 1 abrupt, 2 transient, 3 gradual

print("cloudy dates flagged: %.1f %% (true %.1f %%)" % (100 * (~valid).mean(), 100 * cloud.mean()))
names = ["stable", "abrupt", "transient", "gradual"]
conf = np.zeros((4, 4), int)
np.add.at(conf, (kind, pred), 1)
print("rows = truth, columns = decision (none, abrupt, transient, gradual)")
for k in range(4):
    print(f"{names[k]:9s}", conf[k])

Key takeaways — chapter 6

  • A pixel series is modelled as a seasonal regression plus Gaussian noise; the change is a known profile with unknown amplitude.
  • The t-statistic of the change profile is exactly Student under the background, whatever the seasonal parameters and the noise level.
  • Families of profiles (abrupt, transient, gradual) are compared through their NFAs, which penalise the larger families.
  • Clouds are screened with temporal tests and, for push-broom sensors, with inter-band parallax.
  • On simulated series, the categorisation is perfect and the false alarms stay at the level \varepsilon.

7. Detection of image forgeries

A forged photograph usually looks right: the semantic content gives nothing away. What betrays it are the traces of the camera and of the processing chain, which the forgery breaks locally. This chapter detects such inconsistencies a contrario, where a false alarm means accusing an authentic image.

7.1 Forensic traces

Common forgeries are splicing (a region from another image), copy-move (a region duplicated within the image), removal by inpainting, and, increasingly, regions produced by generative models. The traces used to detect them come from the acquisition pipeline.

Each forgery type has too many variants to be learned from examples. The a-contrario approach takes the traces of the image itself as background and detects regions whose traces are too inconsistent to be due to chance.

7.2 JPEG grid detection

JPEG quantises the DCT coefficients of each block with a table Q; decoding applies the inverse DCT and rounds to integers. Many high-frequency coefficients are quantised to zero.

Proposition 7.1 — Zeros on the grid Let v be a decoded JPEG image and B an 8 \times 8 block aligned with the JPEG grid. The DCT of B, after removing the offset 128, equals the quantised coefficients plus the DCT of the rounding error. If the rounding errors are modelled as independent uniform variables on [-\frac12, \frac12], every coefficient quantised to zero satisfies |c| < 0.5 with probability about \mathbb{P}\big(|\mathcal{N}(0, 1/12)| < 0.5\big) = 0.92 .

Proof. The decoded block is the inverse DCT of the quantised coefficients plus a rounding error e (clipping is neglected). The DCT is orthonormal, so the DCT of e has covariance I / 12, the variance of a uniform variable on an interval of length 1. Each coefficient of the DCT of e is a sum of 64 independent terms, which is approximately Gaussian. ∎

A block that is not aligned with the grid straddles two to four JPEG blocks; in textured regions, its DCT has many coefficients above 0.5. Nikoukhah, Anger, Ehret, Colom, Morel and Grompone von Gioi (2019) build a detector on this contrast.

Definition 7.2 — Grid votes and their NFA Each pixel belongs to 64 blocks, one per grid origin g \in \{0, \dots, 7\}^2. It votes for the origin of the block with the most DCT zeros, and abstains in case of a tie.

  • Background model: the votes are independent and uniform over the 64 origins.
  • Main grid: the most voted origin, with \mathrm{NFA} = 64\, \mathcal{B}(n, k, 1/64) for k votes among n.
  • Foreign grid: in each window W of a list of N_W windows, the most voted origin g other than the main one, with \mathrm{NFA} = 63 N_W\, \mathcal{B}(n_W, k_W, 1/64).

The 64 pixels of an 8 \times 8 cell share most of their blocks and vote together, which violates the independence of the background model. Code 7.4 therefore keeps one vote per cell; Exercise 14 shows what happens otherwise.

Example 7.3 — A spliced region Code 7.4 compresses a 256 \times 256 synthetic image at quality 75 and pastes into it a 64 \times 80 region of another JPEG image whose grid origin is (5, 3). Windows of 4 \times 4 cells give N_W = 841 windows of 16 votes; a window is meaningful with 5 foreign votes or more.

  • Authentic image: main grid (0, 0) with 1022 votes out of 1023, \log_{10} \mathrm{NFA} \le -1841; no meaningful foreign window.
  • Forged image: the main grid is still (0, 0), with 942 votes out of 1022. 76 windows reveal the foreign origin (5, 3), and none of them is disjoint from the pasted region.

7.3 Demosaicking traces

In a Bayer filter array, the colours repeat with period 2 in each direction, so the array has four possible positions relative to the image. Demosaicking leaves the measured samples and the interpolated ones with different statistics, and the position can be estimated locally. Popescu and Farid (2005) estimate the interpolation correlations with an EM algorithm; Bammey, Grompone von Gioi and Morel (2020) train a small network on the image itself to recognise the position of each pixel in the pattern.

The a-contrario step is the one of Definition 7.2 with four positions instead of 64: a region whose votes favour another position, or no position, is detected with a binomial NFA.

7.4 Noise and copy-move traces

7.5 Evaluation

A forensic tool is judged on two numbers: the localisation quality on forged images, and the number of false detections on authentic ones. The NFA bounds the second by \varepsilon per image, under the background model.

Bammey and coauthors (2022) built a benchmark of forgeries that cannot be detected from the semantic content alone, so that a method is evaluated on the traces it claims to use. Deep forensic detectors are powerful, but most return scores without a false-alarm guarantee (ch. 8).

Code 7.4 — JPEG grid votes and a-contrario detection of a spliced region.

import numpy as np
from scipy.fft import dct, idct
from scipy.ndimage import gaussian_filter
from scipy.stats import binom
from scipy.special import xlogy
from numpy.lib.stride_tricks import sliding_window_view

rng = np.random.default_rng(6)
Q50 = np.array([[16,11,10,16,24,40,51,61],[12,12,14,19,26,58,60,55],
                [14,13,16,24,40,57,69,56],[14,17,22,29,51,87,80,62],
                [18,22,37,56,68,109,103,77],[24,35,55,64,81,104,113,92],
                [49,64,78,87,103,121,120,101],[72,92,95,98,112,100,103,99]])
Q = np.maximum(np.round(Q50 * 0.5), 1)                 # quality 75 luminance table
dct2 = lambda b: dct(dct(b, axis=-1, norm="ortho"), axis=-2, norm="ortho")
idct2 = lambda b: idct(idct(b, axis=-1, norm="ortho"), axis=-2, norm="ortho")

def scene(n):
    u = gaussian_filter(rng.normal(size=(n, n)), 3) * 400 + 128
    return np.clip(u + 8 * rng.normal(size=(n, n)), 0, 255)   # smooth content + texture

def jpeg(u):
    """Quantise 8x8 block DCTs on the grid anchored at (0, 0); decode to integers."""
    n = u.shape[0]
    B = (u - 128).reshape(n // 8, 8, n // 8, 8).transpose(0, 2, 1, 3)
    B = idct2(np.round(dct2(B) / Q) * Q)
    return np.clip(np.round(B.transpose(0, 2, 1, 3).reshape(n, n) + 128), 0, 255)

def votes(v):
    """Each pixel votes for the grid origin of the 8x8 block (among the 64 containing it)
    with the most DCT coefficients rounding to zero; ties give no vote (-1)."""
    n = v.shape[0]
    Z = (np.abs(dct2(sliding_window_view(v - 128, (8, 8)))) < 0.5).sum((-1, -2))
    m = Z.shape[0]
    stack = np.full((64, n, n), -1)
    for a in range(8):
        for b in range(8):                        # pixel at offset (a, b) inside the block
            stack[8 * a + b, a:a + m, b:b + m] = Z
    best = stack.max(0)
    arg = stack.argmax(0)
    x, y = np.mgrid[:n, :n]
    origin = 8 * ((x - arg // 8) % 8) + (y - arg % 8) % 8
    return np.where((stack == best).sum(0) == 1, origin, -1)

n = 256
img = jpeg(scene(n))                                   # authentic image, grid origin (0, 0)
other = jpeg(scene(n + 8))[3:3 + n, 5:5 + n]           # another JPEG, grid origin (5, 3)
forged = img.copy(); forged[96:160, 64:144] = other[96:160, 64:144]

def log10_tail(k, N, p):
    """log10 B(N, k, p), with the Chernoff bound when the exact value underflows."""
    exact = binom.logsf(k - 1, N, p) / np.log(10)
    if np.isfinite(exact):
        return exact
    a = k / N                                          # xlogy(0, .) = 0 covers k = N
    return -N * (xlogy(a, a / p) + xlogy(1 - a, (1 - a) / (1 - p))) / np.log(10)

for name, v in (("authentic", img), ("forged", forged)):
    V = votes(v)[4::8, 4::8]                           # one vote per 8 x 8 cell
    main = np.bincount(V[V >= 0], minlength=64).argmax()
    k, N = np.sum(V == main), np.sum(V >= 0)
    print(f"{name}: main grid origin {divmod(int(main), 8)}, {k}/{N} votes, "
          f"log10 NFA <= {np.log10(64) + log10_tail(k, N, 1 / 64):.0f}")
    W = 4                                              # windows of 4 x 4 cells (32 x 32 pixels)
    m = V.shape[0] - W + 1
    n_tests = m * m * 63
    hits = []
    for i in range(m):
        for j in range(m):
            w = V[i:i + W, j:j + W]
            c = np.bincount(w[w >= 0], minlength=64); c[main] = 0
            g = c.argmax()
            if c[g] and np.log10(n_tests) + log10_tail(c[g], np.sum(w >= 0), 1 / 64) <= 0:
                hits.append((8 * i, 8 * j, divmod(int(g), 8)))
    apart = sum(not (i < 160 and i + 32 > 96 and j < 144 and j + 32 > 64) for i, j, _ in hits)
    print(f"   meaningful foreign-grid windows: {len(hits)} (of {m * m}), disjoint from the"
          f" pasted region: {apart}, origins {sorted({h[2] for h in hits})}")

Key takeaways — chapter 7

  • Forgeries are detected through inconsistencies of acquisition traces: demosaicking, noise, JPEG grid and quantisation.
  • On the JPEG grid, the DCT of a decoded block has many coefficients close to zero; misaligned blocks have fewer in textured regions.
  • Grid votes are tested against a uniform background with binomial NFAs; dependent votes must be thinned to one per cell.
  • The same scheme applies to the demosaicking pattern, the noise level and copy-move matches.
  • The NFA bounds the number of false accusations per authentic image.

8. Research directions and open problems

This chapter is for self-study. It surveys questions on which current work focuses, with pointers to papers; the statements about each work summarise its abstract-level claims.

8.1 Dependence and the number of tests

Theorem 3.3 holds whatever the dependence between tests, but each tail is computed under independence inside a test. Real features are correlated: adjacent gradients (Proposition 1.4), grid votes of one cell (ch. 7.2), residuals of a reconstruction. When the dependence is positive, the true tail is typically heavier than the binomial one, and false alarms exceed \varepsilon (Exercise 13).

Myaskouvskey, Gousseau and Lindenbaum (2013) extend the a-contrario decision to dependent features. Two questions remain open in general.

8.2 Learned background models

The reduction of ch. 5.4 separates a reconstruction step, which carries the knowledge of the data, from a calibrated detection step. Davy, Ehret, Morel and Delbracio (2018) apply it with self-similarity in the feature space of pretrained networks. In forensics, Bammey, Grompone von Gioi and Morel (2020) train a network on the very image under analysis.

The open point is the hypothesis of the detection step: the residual of a learned model must be structureless noise on normal data. No general test of this hypothesis exists; when it fails, the NFA is no longer calibrated.

When the background parameters are estimated on the image itself (a mixture model, a noise level), the tests become data-dependent. The guarantee then holds only approximately, a question studied in statistics under the name of selective inference.

8.3 Conformal p-values and the NFA of learned scores

Any anomaly score can be turned into a super-uniform p-value by calibration on normal data.

Proposition 8.1 — Conformal p-value Let s_1, \dots, s_n be the scores of n normal calibration samples and s the score of a test sample. If the n + 1 scores are exchangeable, the conformal p-value p = \frac{1 + \#\{j : s_j \ge s\}}{n + 1} is super-uniform. Consequently, N \cdot p is an NFA for N test samples.

Proof. Assume first that there are no ties. Then R = 1 + \#\{j : s_j \ge s\} is the rank of s among the n + 1 scores sorted in decreasing order, and by exchangeability R is uniform on \{1, \dots, n+1\}. Hence \mathbb{P}(p \le t) = \mathbb{P}\big(R \le t(n+1)\big) = \frac{\lfloor t(n+1) \rfloor}{n+1} \le t .

Ties can only increase p, which keeps the inequality. Theorem 3.3 then applies to the N tests. ∎

Bates, Candès, Lei, Romano and Sesia (2023) study these p-values for outlier detection, including their dependence through the shared calibration set.

Their limitation for images is the smallest attainable value: p \ge 1/(n+1), so \mathrm{NFA} \ge N / (n+1). Testing 10^6 pixels at \varepsilon = 1 needs at least 10^6 normal calibration samples. Combining conformal calibration with parametric or extreme-value tails, as in Statistical Learning with Extreme Values, is an open direction.

Code 8.2 — An NFA for an isolation forest. With 5000 calibration samples and 1020 test points, the smallest attainable NFA is 0.204. The detector finds 18 of the 20 anomalies with no false alarm among the 1000 normal points.

import numpy as np
from sklearn.ensemble import IsolationForest

rng = np.random.default_rng(8)
d = 5
train, calib = rng.normal(size=(2000, d)), rng.normal(size=(5000, d))
test = np.vstack([rng.normal(size=(1000, d)),                 # 1000 normal points
                  rng.normal(size=(20, d)) + 2.5])            # 20 anomalies, shifted mean
is_anom = np.r_[np.zeros(1000, bool), np.ones(20, bool)]

model = IsolationForest(n_estimators=200, random_state=0).fit(train)
s_cal = -model.score_samples(calib)                           # large = anomalous
s_test = -model.score_samples(test)

# conformal p-value: super-uniform as soon as calibration and test normals are exchangeable
p = (1 + (s_cal[None, :] >= s_test[:, None]).sum(1)) / (len(s_cal) + 1)
nfa = len(test) * p
det = nfa <= 1
print("smallest attainable NFA: %.3f" % (len(test) / (len(s_cal) + 1)))
print(f"detections: {det[is_anom].sum()}/20 anomalies, {det[~is_anom].sum()} false alarms")

8.4 Forensics in the age of generative models

Images produced or edited by diffusion models are a new kind of forgery. Corvi, Cozzolino, Zingarini, Poggi, Nagano and Verdoliva (2023) studied detectors of images generated by diffusion models. Guillaro, Cozzolino, Sud, Dufour and Verdoliva (2023) proposed TruFor, a network that localises many kinds of forgeries and outputs a reliability map.

Two problems stay open: generalisation to generators unseen in training, and calibrated false-alarm rates on authentic images. Whether the traces of generative pipelines, such as up-sampling layers and auto-encoder decoders, can serve as background models for a-contrario tests is an active question.

8.5 Deep detectors and a-contrario validation

Learned detectors now compete with LSD and with classical change detection: Huang and coauthors (2018) parse wireframes of man-made scenes with a network, and Daudt, Le Saux and Boulch (2018) detect changes between satellite images with fully convolutional siamese networks. Their outputs are scores. Validating their proposals a contrario, by an NFA computed on the image measurements, would give them the false-detection control they lack.

8.6 Open problems

  1. Compute the effective number of tests of a detector under a realistic dependence model.
  2. Choose the weights of Proposition 3.4 optimally across families of candidates (lengths, scales, change types).
  3. Reach small NFAs with finite calibration sets for learned scores.
  4. Give calibrated false-alarm guarantees for forensic detection of generated content.
  5. Test, on normal data, the hypothesis that a learned residual is structureless.

Key takeaways — chapter 8

  • Dependence inside a test is the main source of miscalibration; dependence between tests only makes the count pessimistic.
  • Learned reconstructions can feed a calibrated a-contrario test if their residual is noise-like on normal data.
  • Conformal p-values give an NFA for any score, but the calibration set limits the smallest attainable NFA.
  • Generated images and deep detectors are the current frontier; their false alarms are not yet controlled.

Exercises

  1. ★ Binomial tails and their bounds. For n = 50 observations with p = 1/8, compute \mathcal{B}(50, 20, 1/8) exactly, then its Chernoff and Hoeffding bounds (Proposition 0.2). Which bound would you use to explain a threshold, and which to compute it?

    Solution: the exact tail is 9.3 \times 10^{-7}. The Chernoff bound, with a = 0.4, is e^{-50\, \mathrm{KL}(0.4 \| 0.125)} = 6.5 \times 10^{-6} , and Hoeffding gives e^{-100 \times 0.275^2} = 5.2 \times 10^{-4}.

    Thresholds are computed with the exact tail. The Chernoff bound, within a factor 7 here, explains how they scale; Hoeffding is too loose because it ignores the small variance np(1-p).

  2. ★ A discrete p-value. Let X \sim \mathrm{Binomial}(2, 1/2) and S(x) = \mathbb{P}(X \ge x). Compute S at 0, 1 and 2, then \mathbb{P}(S(X) \le t) for t \in \{0.25, 0.3, 0.8\}. Check Proposition 0.7 and say when equality holds.

    Solution: S(0) = 1, S(1) = 3/4, S(2) = 1/4. Then \mathbb{P}(S(X) \le 0.25) = \mathbb{P}(X = 2) = 0.25, with equality; \mathbb{P}(S(X) \le 0.3) = 0.25 < 0.3; and \mathbb{P}(S(X) \le 0.8) = \mathbb{P}(X \ge 1) = 0.75 < 0.8.

    Equality holds exactly at the values taken by S; in between, the p-value is conservative.

  3. ★ Gradients of white noise. With the notation of Proposition 1.4, compute the covariance between g_x at pixel (i, j) and g_y at pixel (i, j+1). Then explain why orientations sampled every two pixels are independent, while orientations at adjacent pixels are not.

    Solution: the two windows share two samples.

    • The sample b = u(i, j+1) enters g_x(i, j) with coefficient +1/2 and g_y(i, j+1) with coefficient -1/2.
    • The sample d = u(i+1, j+1) enters both with coefficient +1/2.

    The other samples appear in only one of the two components, so the covariance is \sigma^2 \big(-\tfrac14 + \tfrac14\big) = 0 .

    These two components are uncorrelated, but g_x at adjacent pixels has correlation -1/2, so adjacent orientations are dependent. Windows two pixels apart are disjoint, and the gradients are functions of disjoint sets of independent samples.

  4. ★ Bonferroni in numbers. A 1000 \times 1000 image is tested pixel by pixel with Gaussian statistics. Give the Bonferroni thresholds for \varepsilon = 1 and \varepsilon = 0.05, and the expected number of false alarms of a per-pixel threshold at 3\sigma. What does \varepsilon = 1 guarantee on the FWER?

    Solution: z = (\Phi^c)^{-1}(10^{-6}) = 4.75 for \varepsilon = 1 and (\Phi^c)^{-1}(5 \times 10^{-8}) = 5.33 for \varepsilon = 0.05. A 3\sigma threshold gives 10^6 \times 1.35 \times 10^{-3} = 1350 false alarms.

    For \varepsilon = 1, the FWER bound \mathbb{P}(V \ge 1) \le 1 is empty, but \mathbb{E}[V] \le 1 remains a useful guarantee (Proposition 2.7).

  5. ★ Gaussian thresholds and minimal contrasts. With N_T = 65\,536 as in Example 3.7, compare z(1) = 4.17 with the bound of Proposition 3.6. Then compute the minimal contrast a_{\min} for discs of radius 2 (13 pixels) and 4 (49 pixels).

    Solution: \sqrt{2 \log 65\,536} = 4.71, an upper bound 0.54 above the exact threshold. The minimal contrasts are 4.17 / \sqrt{13} = 1.16 and 4.17 / 7 = 0.60 noise standard deviations: larger objects can be fainter.

  6. ★ Minimal length of an alignment. For an image of 1024 \times 1024 pixels, compute the minimal number of perfectly aligned points of a meaningful alignment for p = 1/16 and p = 1/8 (Proposition 4.2). For LSD on the same image, compute the minimal length of a perfectly aligned rectangle one pixel wide.

    Solution: \log(1024^4) / \log 16 = 10 points and \log(1024^4) / \log 8 = 13.3, so 14 points. For LSD, \log_{10} N_T = 2.5 \log_{10}(2^{20}) + \log_{10} 11 = 16.09 , and 16.09 / \log_{10} 8 = 17.8: 18 pixels, one more than for a 512 \times 512 image.

  7. ★ RX thresholds. A hyperspectral image has N = 10^6 pixels and d = 10 bands. Give the RX threshold on D for \varepsilon = 1 with known background statistics, then with statistics estimated in windows of n = 50 pixels (Proposition 5.2).

    Solution: the chi-square threshold is \chi^2_{10} at tail 10^{-6}, that is D \ge 46.9. With estimated statistics, the Fisher law at tail 10^{-6} gives \hat D \ge 96.6 . The second threshold is twice the first: a 50-pixel window estimates a 10 \times 10 covariance poorly.

  8. ★ The smallest detectable step. A series of T = 60 dates with constant background has a step after date 20, noise \sigma = 0.03, and a detection threshold |z| \ge 5. Compute \|Qc\| and the smallest step detected half of the time.

    Solution: Qc = c - \bar c, so \|Qc\|^2 = n_a n_b / T with n_b = 20 dates before and n_a = 40 after: \|Qc\| = \sqrt{800/60} = 3.65. The mean statistic is \delta \|Qc\| / \sigma, so \delta_{\min} = \frac{5 \times 0.03}{3.65} = 0.041 .

  9. ★★ The matched filter in coloured noise. Let x = as + w with w \sim \mathcal{N}(0, C). Prove that the Neyman–Pearson test thresholds s^\top C^{-1} x, and give its power at level \alpha. Show that among all linear statistics \langle h, x \rangle, the ratio of the mean shift to the standard deviation is maximal for h \propto C^{-1}s.

    Solution: the log-likelihood ratio is a\, s^\top C^{-1} x - \frac{a^2}{2} s^\top C^{-1} s. With d = a \sqrt{s^\top C^{-1} s}, the power is \Phi^c(z_\alpha - d), for example 0.82 for \alpha = 10^{-3} and d = 4.

    For a linear statistic, the ratio is a \langle h, s \rangle / \sqrt{h^\top C h}. Writing \langle h, s \rangle = \langle C^{1/2} h, C^{-1/2} s \rangle, Cauchy–Schwarz bounds it by a \sqrt{s^\top C^{-1} s}, with equality for C^{1/2} h \propto C^{-1/2} s.

  10. ★★ Weighted tests by length. Candidates are segments with lengths l = 1, \dots, L, and N_l segments have length l. Show that, for a segment S of length l with k aligned points, \mathrm{NFA}(S) = L\, N_l\, \mathcal{B}(l, k, p) is an NFA. When is it smaller than the unweighted NFA N_T \mathcal{B}(l, k, p), where N_T = \sum_l N_l?

    Solution: apply Proposition 3.4 with weights w_S = 1/(L N_l), whose sum over all segments is \sum_l N_l / (L N_l) = 1.

    The weighted NFA is smaller exactly when L N_l < N_T, that is when length l has fewer candidates than the average length.

    On the grid lines of Code 4.6, a line of n sites holds n - l + 1 segments of length l. Long segments are therefore rarer than short ones, and weighting favours long alignments, whose detection matters most.

  11. ★★ Why Hoeffding fails for clusters. In Example 3.5, write the Chernoff threshold as the solution of n\, \mathrm{KL}(k/n \| a) = \log N_T and the Hoeffding threshold explicitly. Explain the gap between 27.8 and 83.6 with the variance of the count.

    Solution: Hoeffding gives k \ge na + \sqrt{\frac{n}{2} \log N_T} = 10 + 73.6 = 83.6. The Chernoff equation, solved numerically, gives k = 27.8, close to the exact 26.

    Hoeffding’s bound holds for any variable in [0, 1] and therefore uses the worst variance 1/4 per observation, 250 in total. The actual variance of the count is na(1-a) = 9.9, so deviations are about five times smaller than Hoeffding assumes.

  12. ★★ The bias of local RX. In the setting of Proposition 5.2, prove that x - \bar y \sim \mathcal{N}(0, (1 + 1/n)\Sigma) and is independent of S. Then use the moment of the inverse Wishart matrix, valid for n > d + 2, \mathbb{E}[S^{-1}] = \frac{n-1}{n-d-2}\, \Sigma^{-1} , to compute \mathbb{E}[\hat D], and evaluate it for n = 50 and d = 10.

    Solution: x - \bar y is a linear combination of independent Gaussian vectors with covariance \Sigma + \Sigma / n. The sample mean and covariance of a Gaussian sample are independent, and x is independent of the sample. Conditioning on S, \mathbb{E}[\hat D] = \Big(1 + \frac1n\Big) \mathrm{tr}\big(\mathbb{E}[S^{-1}]\Sigma\big) = \Big(1 + \frac1n\Big) \frac{d\,(n-1)}{n - d - 2} . For n = 50 and d = 10, this is 13.2 instead of d = 10: the estimated distance is inflated, hence the larger threshold.

  13. ★★ Alignments on dependent orientations (Python). Modify Code 4.6 to estimate the mean number of meaningful segments on noise for \varepsilon \in \{0.1, 1, 10\}. Then replace the independent orientations by the level-line orientations of the 2 \times 2 gradient of a white noise image, computed (a) at every pixel and (b) at every other pixel. Explain the results.

    Hints and expected result: use the level-line angle, the gradient angle plus \pi/2. Average over at least 200 grids, because one chance alignment produces many overlapping meaningful segments and the counts are heavy-tailed. Typical means for the three values of \varepsilon (they vary by about 30 % with the seed) are:

    • independent orientations: about 0.05, 0.5 and 4 segments, below \varepsilon each time;
    • orientations at every pixel: about 1.5, 8 and 45, well above \varepsilon each time;
    • orientations at every other pixel: about 0, 0.06 and 1.6, below \varepsilon again.

    At every pixel the guarantee fails, because the tail of each test is computed as if adjacent orientations were independent. Along a row, a horizontal segment tests the sign and size of g_y. The computation of Proposition 1.4, point 3, shows that g_y has correlation +1/2 between adjacent windows of a row, and this positive dependence makes the tail heavier.

    With the raw gradient angle, the same segments test g_x, of correlation -1/2, and almost nothing is detected. On a noise image smoothed by a Gaussian of standard deviation 1, a grid typically holds tens of 1-meaningful segments, sometimes more than a hundred: smoothing creates genuine local alignments, which the background model excludes.

  14. ★★ Dependent votes in JPEG grid detection (Python). In Code 7.4, use all pixel votes instead of one vote per 8 \times 8 cell, with windows of 32 \times 32 pixels at stride 8. Count the meaningful foreign-grid windows on the authentic image and explain.

    Hints and expected result: false detections appear on the authentic image, voting for origins adjacent to the main grid such as (0, 7). The 64 pixels of a cell share most of their blocks and vote almost identically, so a window of 1024 votes holds about 16 independent ones. The binomial tail with n = 1024 then underestimates the probability of a cluster of foreign votes.

  15. ★★★ An effective number of observations for LSD. LSD counts every pixel of a rectangle, although adjacent gradients are dependent. Propose a corrected count, for instance using only a sub-grid of step 2 or an effective number n_{\text{eff}} < n. Implement it on noise images and on synthetic segments, and compare the false detections and the shortest detectable segment with the original count.

    Hints: on noise, the sub-grid count is calibrated (Exercise 13) but needs about twice the length to detect a segment. An intermediate count, such as a binomial on n/c observations, can be calibrated by simulation. Discuss the trade-off with the experiments on noise reported by the LSD authors and with Myaskouvskey, Gousseau and Lindenbaum (2013).

  16. ★★★ An NFA from a learned score. With Code 8.2: (a) explain why the NFA stays valid when the isolation forest is badly trained; (b) compute how many calibration samples are needed to test every pixel of a 512 \times 512 image at \varepsilon = 1; (c) propose a way to reach smaller NFAs, for instance by fitting a generalised Pareto tail to the largest calibration scores, and say which guarantee is lost.

    Hints: (a) Proposition 8.1 only needs exchangeability; a bad score loses power, not calibration. (b) N / (n+1) \le 1 requires n \ge 262\,143. (c) A parametric tail extrapolates beyond the calibration range; the guarantee becomes asymptotic and depends on the tail model, which can itself be tested on held-out normal data.

Projects and assessment

The official assessment is continuous. master-mva.com announces 4 homework assignments, including exercises and a report analysing a research paper; the Université Paris-Saclay detail adds experimental reports based on IPOL articles with an online demo, and at least one in-depth analysis of a detection paper. No weighting is displayed.

The subjects below are proposals for that report and for personal training, in the MVA tradition of studying and reimplementing a research paper. The written exam is not part of the official assessment: it shows what a timed test on these notes could look like, and serves as a self-test.

Solo projects

  1. [Solo · ≈ 20 h] Paper study: the LSD line segment detector (Grompone von Gioi, Jakubowicz, Morel and Randall, 2010; IPOL 2012). Does a reimplementation keep the false-detection control that the paper claims, and what does the dependence of adjacent gradients cost?
    • Implement: a simplified LSD in NumPy (Algorithm 4.4): the 2 \times 2 gradient, region growing at \tau = 22.5°, the rectangle fit and the NFA of Definition 4.5. Compare it with the reference C code published with the IPOL article.
    • Data: 100 white-noise images of 512 \times 512 pixels; synthetic images of segments of controlled length and contrast; the sample photographs bundled with scikit-learn (sklearn.datasets.load_sample_image).
    • Success criterion: at most one detection per noise image on average; on noiseless synthetic images, a shortest detected segment within two pixels of the bound of ch. 4.3 (17 pixels).
    • Deliverables and evaluation: code, a 4–6 page report in the format of an IPOL experimental report, a 10-minute talk; rubric below. Chapters used: ch. 1, 3, 4.
  2. [Solo · ≈ 20 h] Paper study: JPEG grid detection (Nikoukhah, Anger, Ehret, Colom, Morel and Grompone von Gioi, 2019). How small and how compressed can a spliced region be and still be found, with no false accusation of authentic images?
    • Implement: Code 7.4 with real JPEG compression (the Pillow library installed with Matplotlib), one vote per 8 \times 8 cell, and the main-grid and foreign-grid NFAs of Definition 7.2.
    • Data: crops of the scikit-learn sample images, compressed at qualities 60 to 95; splices whose grid origin differs from the host’s, with sizes from 32 \times 32 to 128 \times 128 pixels.
    • Success criterion: fewer than one meaningful foreign window per authentic image on average over 100 crops; a detection rate plotted against quality and region size.
    • Deliverables and evaluation: code, report, talk; rubric below. Chapters used: ch. 0, 3, 7.
  3. [Solo · ≈ 15 h] Paper study: stability of multiple testing (Gordon, Glazko, Qiu and Yakovlev, 2007). Does the Bonferroni rule keep its advantage in stability when the tests are as correlated as image tests?
    • Implement: Code 2.8 with three correlation structures: equicorrelation, block correlation, and the spatial correlation of a smoothed Gaussian random field tested pixel by pixel.
    • Prove: \mathbb{E}[V] \le \varepsilon N_0 / N under any dependence (Proposition 2.5), and show by an example that the FDR bound of Theorem 2.6 can fail under negative dependence (two null p-values, coupled so that \{p_1 \le q/2\} and \{p_2 \le q/2\} are disjoint and both lie in (q/2, q] with probability q/2, give an FDR of 3q/2).
    • Success criterion: the paper’s qualitative finding reproduced, a smaller variance of the numbers of true and of total discoveries for Bonferroni, with intervals over 4000 runs.
    • Deliverables and evaluation: code, a 4-page report, a 10-minute talk; rubric below. Chapters used: ch. 0, 2, 3.

Group projects

  1. [Group of 2–3 · ≈ 30 h each] Change detection and categorisation in satellite image time series. Can the exact tests of ch. 6 date and classify changes on real series, with a false-alarm level that matches \varepsilon?
    • Implement: temporal cloud screening; the Student test of Theorem 6.1 with yearly harmonics; the families and the categorisation of Definition 6.3; a CUSUM baseline (Page, 1954) whose threshold is tuned on the simulator.
    • Data: the simulator of Code 6.4, with known truth; a public Sentinel-2 Level-2A time series of one tile, downloaded from the Copernicus Data Space Ecosystem, around a documented event (a harvest, a clear-cut, a flood).
    • Success criterion: on the simulator, the number of false changes per 10^6 stable series stays below 10^6 \varepsilon / N_{\text{pix}} for three values of \varepsilon, and the categorisation accuracy is reported against the change amplitude.
    • Split: member 1 builds cloud screening and data loading; member 2 builds the tests and the NFA; member 3 runs the evaluation and the baseline.
    • Deliverables and evaluation: code, a joint 6–8 page report, a 15-minute talk with an individual question per member; rubric below. Chapters used: ch. 3, 6.
  2. [Group of 2–3 · ≈ 30 h each] Paper study: reducing anomaly detection in images to detection in noise (Davy, Ehret, Morel and Delbracio, 2018). Does a self-similarity reconstruction leave a residual on which the NFA is calibrated?
    • Implement: the three steps of ch. 5.4 — a non-local patch reconstruction that excludes a neighbourhood of each patch, the normalisation of the residual, and the multiscale two-sided NFA. Compare with global RX on 5 \times 5 patch vectors.
    • Data: synthetic textures (periodic patterns, filtered noise) with planted defects of controlled size and contrast; defect-free crops of the scikit-learn sample images.
    • Success criterion: on defect-free textures, the mean number of detections stays within a factor 2 of \varepsilon; on textures with defects, a detection-rate curve against the defect contrast.
    • Split: reconstruction; detection and calibration (including a test of the whiteness of the residual); evaluation and comparison with RX.
    • Deliverables and evaluation: code, joint report, talk; rubric below. Chapters used: ch. 3, 5.
  3. [Group of 3 · ≈ 30 h each] Mosaic consistency as a forensic trace (after Popescu and Farid, 2005, and Bammey, Grompone von Gioi and Morel, 2020). Can a simple interpolation residual locate a region whose colour filter array is shifted, with a binomial NFA over the four positions?
    • Implement: a synthetic camera pipeline (Bayer mosaic at a chosen offset, bilinear demosaicking, optional JPEG compression); a per-block vote for the most likely of the four mosaic positions; the NFA of ch. 7.3.
    • Data: the scikit-learn sample images, mosaicked and demosaicked; splices with a shifted mosaic.
    • Success criterion: fewer than one false region per authentic image on average; the size of the smallest detected splice, before and after JPEG compression at quality 90.
    • Split: pipeline and data; detector and NFA; evaluation, robustness and comparison with the JPEG-grid detector of Code 7.4.
    • Deliverables and evaluation: code, joint report, talk; rubric below. Chapters used: ch. 3, 7.

Written exam (proposal)

Two hours, one handwritten A4 sheet allowed, no electronic device; four exercises on 20 points.

  1. Question (5 points). Define a background model and the number of false alarms of a family of N_T tests. State and prove the fundamental property of the NFA. Explain where independence is used and where it is not, and what a detection means when the background model is wrong.

    Expected:

    • Definitions 3.1 and 3.2, with the property that the expected number of \varepsilon-meaningful candidates is at most \varepsilon (1 pt).
    • The proof of Theorem 3.3: linearity of expectation over the indicators, then the super-uniformity of each S_i(X_i) (2 pts).
    • Independence is needed inside a test, to compute the tail; it is not needed between tests (1 pt).
    • A detection is a local rejection of the background model, not the proof that an object exists (1 pt).
  2. Question (5 points). An image has 256 \times 256 pixels, and alignments are tested at precision p = 1/16 with N_T = N^4 segments. (a) Find the minimal length of a perfectly aligned 1-meaningful segment. (b) For a segment of l = 20 independent points, give the number of aligned points that Hoeffding’s bound declares sufficient. (c) The exact threshold is 13 aligned points; explain the gap.

    Expected:

      1. N^4 = 2^{32} and p^l = 2^{-4l}, so l \ge 8 points; with 8 points the NFA equals 1 exactly (2 pts).
      1. Proposition 3.6 gives k \ge 1.25 + \sqrt{10 \log 2^{32}} = 1.25 + 14.9, so 17 points (1.5 pts).
      1. Hoeffding uses the worst variance 1/4 per point, while the true variance p(1-p) \approx 0.06 is four times smaller; the exact tail or the Chernoff bound must be used when p is small (1.5 pts).
  3. Question (5 points). (a) Prove that for every real random variable X with survival function S, the variable S(X) is super-uniform. (b) Let w_i > 0 be weights of sum at most 1. Prove that \mathrm{NFA}_w(i, x) = \mathbb{P}_{H_0}(X_i \ge x_i) / w_i is an NFA. (c) Deduce an NFA for K families of candidates of sizes N_1, \dots, N_K.

    Expected:

      1. The set where S \le t is a half-line; the closed case gives a probability S(x^*) \le t, and the open case a limit of values at most t (Proposition 0.7) (2 pts).
      1. Linearity of expectation and super-uniformity give at most \varepsilon \sum_i w_i \le \varepsilon false detections (2 pts).
      1. The weights w_i = 1/(K N_k) give the NFA K N_k\, \mathbb{P}_{H_0}(X_i \ge x_i) for a candidate of family k (1 pt).
  4. Question (5 points). A vegetation series has T = 40 dates, a constant background of unknown level, Gaussian noise of unknown standard deviation \sigma, and a possible step after date 10. (a) Give the law of the test statistic of Theorem 6.1 under the background model, with its number of degrees of freedom. (b) Compute \|Qc\|. (c) The image holds 10^5 tests, and the threshold for \varepsilon = 1 is |z| \ge 5.1 . Find the smallest step detected half of the time when \sigma = 0.05.

    Expected:

      1. A Student law with T - q - 1 = 38 degrees of freedom, exactly, whatever the level and \sigma, because the projection removes the level and the ratio removes \sigma (2 pts).
      1. Qc = c - \bar c, so \|Qc\|^2 = 10 \times 30 / 40 = 7.5 and \|Qc\| = 2.74 (1.5 pts).
      1. The statistic has mean about \delta \|Qc\| / \sigma, so \delta_{\min} = 5.1 \times 0.05 / 2.74 = 0.093 (1.5 pts).

Grading rubric (proposal)

Criterion Weight What earns the marks
Understanding of the paper 20 % background model, statistic and number of tests of the method stated explicitly, with the hypotheses the guarantee needs
Mathematical correctness 20 % NFAs, tails and proofs right; the number of tests counts every candidate, including the parameters tuned on the data
Calibration on noise 25 % the mean number of detections on data without structure measured against \varepsilon, with error bars; any excess explained (dependence, wrong background)
Detection results and analysis 20 % the success criterion reached or its failure explained; failure cases shown, not hidden; comparison with a baseline
Reproducibility and communication 15 % runnable code with fixed seeds; a report within the page limit and a talk with readable figures

References

Official references of the course (master-mva.com)

Textbooks

Perception and the Helmholtz principle (ch. 1)

Multiple testing (ch. 2)

A-contrario detection and geometric structures (ch. 3–4)

Anomaly detection (ch. 5)

Time series and satellite imaging (ch. 6)

Image forensics (ch. 7)

Research directions (ch. 8)