Counting on a Moving Belt
The line crossing trick.
If you count apples in each frame, you'll count the same fruit twenty times. Each apple stays in view for a while. So how do you count each one once? You draw an invisible line, and count when a track crosses it.

- Each apple appears in many frames
- Don't count it twenty times
- Draw an invisible line
Counting crossings
We keep each track's last position. If it was before the line, and now it's on or past it, that's one crossing. Tracks come from the tracker you built earlier. Here are six frames, with two apples. Run it. It printed three, but there are only two apples. Why? Look at apple two. It goes back to two hundred and eighty, then crosses again. Apples roll backwards sometimes. Our counter needs one more rule. Each track ID may only be counted once. That's what testing on real data is for.
class LineCounter:
def __init__(self, x):
self.x, self.last, self.count = x, {}, 0
def update(self, tracks):
for track_id, cx in tracks.items():
before = self.last.get(track_id)
if before is not None and before < self.x <= cx:
self.count += 1
self.last[track_id] = cx
counter = LineCounter(x=300)
frames = [{1: 250, 2: 120}, {1: 290, 2: 180}, {1: 330, 2: 240}, {1: 370, 2: 300}, {2: 280}, {2: 320}]
for f in frames:
counter.update(f)
print("Apples past the line:", counter.count)Apples past the line: 3
Reliable counting
Real counters need a few protections. Count each track once, as we just saw. Use a line in the middle of the view, where tracks are stable. Compare the daily count with a real weighbridge, to catch drift. And log the track ID with a small image for each count, so that you can check any disputes later.
Summary
Track, cross, and count once. You've finished the classic toolbox. Next, we're going to train a bruise detector from nothing, and learn what really goes wrong.
Key takeaways- Count crossings, not frames
- Only count each ID once
- Cross-check with weight