Task 3 of 5

The Midpoint of 350° and 10°

Hue is an angle, and angles wrap. That one fact quietly breaks arithmetic you have been doing safely your entire career.

Take two readings of the same pixel, from two frames: 350° and 10°. Both are red. They are 20° apart on the wheel. Average them the obvious way and you get 180° — cyan. Not a slightly-off red: the opposite colour, out of two inputs that were nearly identical. Every mean, every interpolation, every blur that touches a hue channel has this hole in it.

The repair is to stop pretending the number line has no seam. Take b − a, fold it onto the short way round by adding or subtracting 360 until it lands in −180 … 180, walk half of it from a, and fold the answer back into 0 … 360. Four lines, no cleverness — just refusing to subtract two angles as if they were distances.

far apart on a line, neighbours on a wheel — and only one of those is true
Goal: return the midpoint of hueA[i] and hueB[i] the short way round, as an angle in 0 … 360.

Requirements

Hint 1 — the short way round

The difference between two angles is only ever at most 180°. If the plain subtraction gives you more than that, you went the long way round:

let d = b[this.thread.x] - a[this.thread.x];
if (d > 180) { d = d - 360; }
if (d < -180) { d = d + 360; }
Hint 2 — half a step, then home

Walk half of that difference from a, then bring the result back onto the wheel. One check each way is enough, because a is already in range and you moved it by at most 90°:

let m = a[this.thread.x] + d / 2;
if (m < 0) { m = m + 360; }
if (m >= 360) { m = m - 360; }
return m;
Hint 3 — check the first four

The first eight pairs of the input straddle the seam deliberately. (350, 10) and (10, 350) must both give 0, (358.5, 4.5) gives 1.5, and (340, 20) gives 0 as well. If those four come out near 180, the fold is missing.

Same idea elsewhere

Wrapping quantities are everywhere in vision and nowhere in your standard library: gradient orientation in HOG and SIFT, optical-flow direction, the phase channel of an FFT, compass bearings, the time of day. The standard fix for averaging many of them is prettier than this one and just as parallel — turn each angle into a unit vector, sum the vectors (which is a plain reduction), and take atan2 of the total. That is what circular statistics libraries do, what CUDA and WGSL kernels do, and it removes the branches entirely, which on a GPU is worth having.

All tasks in Colour Spaces

  1. Three Greys, One Pixel
  2. Hue, Saturation, Value
  3. The Midpoint of 350° and 10°
  4. Select by Colour
  5. Payoff: What Colour Is This Picture?

This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.