# Which Answers to Believe

*Task 4 of 5 · [Optical Flow](https://gpu.rocks/learn/optical-flow-e85c6dfa.md) · GPU.js Learn*

Task 3 returned a number for every pixel it could solve, and some of those numbers
are worthless. A useful tracker does not just answer — it says *how much* it should be
believed, and the material for that is already sitting in the window matrix
`M = [[Sxx, Sxy], [Sxy, Syy]]`.

`M`'s two eigenvalues measure how much intensity change the window sees in its
two principal directions. Three cases, and they are the whole story:

```js
        λmax     λmin    verdict
flat    ≈ 0      ≈ 0     nothing to track
edge    large    ≈ 0     one direction
corner  large    large   trustworthy
```

The middle row is task 2's aperture problem wearing a matrix. So the
**smaller** eigenvalue is the confidence score: it is large only when the window
is pinned down in *both* directions. That measure has a name — it is the
Shi–Tomasi score, and thresholding it is literally what "good features to track" means. A
2×2 symmetric matrix has a closed-form spectrum, so this is one line of arithmetic, not an
eigensolver:

```js
trace = Sxx + Syy
det   = Sxx·Syy − Sxy²
λmin  = (trace − √(trace² − 4·det)) / 2
```

## Figures

- **flat says nothing, an edge says half of it, only a corner says both** — Three windows side by side. A flat patch with no gradients scores zero on both eigenvalues; a straight edge scores high on the larger and zero on the smaller; a corner scores high on both and is the only one marked trustworthy.

## Goal

**Goal:** produce a 64×64 confidence map — the smaller eigenvalue of each
pixel's 5×5 window matrix.

## Requirements

- Reuse the 5×5 window sums from task 3, but only the three you need: `Sxx`, `Sxy`, `Syy`
- Output is plain 2D — `output: [64, 64]`, one number per pixel
- Return the **smaller** root: `(trace - Math.sqrt(disc)) / 2`, where `disc = trace * trace - 4 * det`
- Clamp the discriminant with `Math.max(0, …)` before the square root — it is mathematically non-negative, but float32 rounding can nudge it below zero and hand you a NaN

## Hint 1 — three sums, not five

`It` plays no part here. Confidence is a property of the
*window*, not of the motion — you can decide a pixel is untrackable before you
look at the second frame at all.

## Hint 2 — the closed form

```js
const trace = sxx + syy;
const det = sxx * syy - sxy * sxy;
const disc = Math.max(0, trace * trace - 4 * det);
return (trace - Math.sqrt(disc)) / 2;
```

Both roots share everything but a sign; `+` gives the larger eigenvalue,
`−` the smaller. Take the smaller one — an edge scores well on the larger and
is exactly what you are trying to reject.

## Same idea elsewhere

Every corner detector is this matrix with a different scalar squeezed out of it:
Shi–Tomasi takes `λmin`, Harris takes `det − k·trace²` to dodge the
square root, FAST skips the matrix entirely and tests a pixel ring instead. OpenCV's
`goodFeaturesToTrack`, the corner pass in ARKit and ARCore, and every
visual-odometry front end run this per-pixel score and then keep the local maxima — which is
a reduction, then a compaction, over a map you just computed in one launch.

## Starter code

```js
// Confidence, not just answers: the smaller eigenvalue of the window matrix.
const gpu = new GPU({ mode });

const confidence = gpu.createKernel(function (derivs) {
  const x = this.thread.x;
  const y = this.thread.y;

  let sxx = 0;
  let sxy = 0;
  let syy = 0;

  // TODO: the same clamped 5×5 window as task 3, accumulating the three
  // sums that do not involve It.

  // TODO: trace = sxx + syy;  det = sxx * syy - sxy * sxy;
  //       return the SMALLER root of the 2×2 spectrum.
  return 0;
}, {
  output: [64, 64],
  constants: { last: 63 },
});

const map = await confidence(derivs);
console.log('flat band:', map[20][6]);
console.log('stripe band:', map[20][24]);
console.log('textured band:', map[30][45]);
```

---

Interactive version: https://gpu.rocks/learn/optical-flow-e85c6dfa/4

[Previous task](https://gpu.rocks/learn/optical-flow-e85c6dfa/3.md) · [Next task](https://gpu.rocks/learn/optical-flow-e85c6dfa/5.md)
