Siddhant Kumar
Project 098 · Retail

Queue Length Counter.

A camera that counts how many people are waiting in line and turns it into live staffing signals — open another till before the queue gets ugly.

Advanced 14–22 hours 26 min read VisionAnalyticsRetail
Jump to source Bill of materials
Queue Length Counter — reference build illustration MCU VCC · GND · SIG · NC
Difficulty
Advanced
Build time
14–22 hours
Indicative cost
₹6,000 – ₹10,000
Platform
Raspberry Pi 4 Model B (4 GB)
Category
Retail
Last updated
28 July 2026
Contents — 27 sections

Project Overview

A camera that counts how many people are waiting in line and turns it into live staffing signals — open another till before the queue gets ugly.

Long checkout queues are one of the biggest drivers of customer frustration and walked-away sales, and stores usually react to them too late — a supervisor notices a queue building, then scrambles to open another till by which point customers are already annoyed or gone. The missing ingredient is a live, objective measure of how many people are waiting. This project builds one: a camera that watches the queue area, counts the people in line with computer vision, and turns that count into a real-time staffing signal — open another checkout before the queue gets long, not after.

The core is people detection and counting in a defined region. A camera views the queue zone; a computer-vision model detects people in the frame, and the system counts how many are within the marked queue area, tracking the number over time. From the live count (and its trend) it derives the signals a manager actually needs: current queue length, whether it is growing, and when it crosses thresholds that should trigger opening or closing a till. Aggregated, it also yields analytics — queue lengths by time of day, peak periods, average wait — that inform staffing schedules.

The value is replacing gut-feel, too-late queue management with continuous, objective data: tills open in time, waits shorten, and staffing is planned from real patterns. It is honest about doing this responsibly — the goal is counting, not identifying anyone, so it should run on-device, count rather than recognise faces, and respect privacy and notice requirements — and about the vision limits (crowding, occlusion, defining where the queue is). But as an on-device people-counting queue monitor that produces live staffing signals and queue analytics, it gives retail an objective handle on one of its most visible customer-experience problems.

Stocked shelves in a supermarket aisle
A camera counts people waiting in line and turns the live count into a signal to open a till before the queue gets long. Photograph sourced from Wikimedia Commons — Supermarket shelves.jpg. Reused under the licence stated on that page; please check it before republishing.

What this project does

  • Counts people waiting in a defined queue area with vision
  • Tracks live queue length and its trend over time
  • Signals when to open or close a checkout
  • Produces queue analytics (peaks, by time of day, waits)
  • Runs on-device — counting, not identifying people
  • Replaces too-late, gut-feel queue management with data
  • Shortens waits and reduces walked-away sales

Real-World Applications

SettingHow it is used
Checkout staffingLive signals to open/close tills before queues build.
Queue analyticsPeak times and average waits to plan staffing.
Service countersAny queue — banks, pharmacies, help desks.
Customer-experience KPIsObjective wait/queue metrics for operations.

Deployment contexts where a build of this kind earns its keep.

Features & Capabilities

  • Computer-vision people detection + counting
  • Region-of-interest queue counting
  • Live count, trend and threshold signals
  • Open/close-till staffing recommendations
  • Queue analytics for scheduling
  • On-device, privacy-respecting design
  • Honest about crowding/occlusion and privacy

Difficulty, Time & Required Skills

AttributeValue
Difficulty levelAdvanced
Estimated completion time14–22 hours
Indicative build cost₹6,000 – ₹10,000
Primary disciplineRetail
Reference platformRaspberry Pi 4 Model B (4 GB)

Skills you should have (or will pick up)

  • People detection with a CV model (e.g. lightweight detector)
  • Region-of-interest counting and temporal tracking
  • Threshold/trend logic for staffing signals
  • On-device, privacy-respecting deployment
  • Queue analytics aggregation

Bill of Materials

Every part below is commonly available from Indian and international hobby-electronics suppliers. Prices are indicative 2026 retail figures in Indian rupees and will drift — treat them as a budgeting guide, not a quotation.

ComponentKey specificationQtyApprox. cost
Raspberry Pi 4 Model B (4 GB)
Use an official 5 V 3 A supply — brown-outs from phone chargers corrupt SD cards.
Quad-core Cortex-A72 @ 1.8 GHz, 4 GB LPDDR4, Gigabit Ethernet, Wi-Fi 5, BT 5.0, 2× USB 3.0, 40-pin GPIO1₹5,800
Raspberry Pi Camera Module 3
Pi 5 uses a narrower 22-pin CSI cable — the old 15-pin ribbon will not fit.
12 MP IMX708, autofocus, HDR, 1080p50, CSI-2 ribbon1₹2,600
0.96″ SSD1306 OLED display
Static images burn in — invert or scroll the screen periodically.
128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C1₹250
Camera + edge compute
On-device inference for privacy
Raspberry Pi (or Jetson) + camera viewing the queue area1₹5,000
MountOverhead/angled mount covering the queue zone1₹400
Staff signalLight/screen or dashboard for open-till signals1₹500
NetworkWi-Fi/Ethernet for signals/analytics (not video)1₹200

Estimated total: ₹14,750, excluding tools, shipping and consumables.

Tools and consumables

  • Soldering iron (temperature controlled, 350 °C) with 0.8 mm 60/40 or lead-free solder
  • Digital multimeter — continuity, DC volts and current ranges
  • Wire strippers, flush cutters and a small set of precision screwdrivers
  • Heat-shrink tubing and a heat gun (or a lighter, carefully)
  • A laptop with a USB port and the toolchain listed above

Hardware Specifications

PartSpecificationSupplyInterfaceReference
Raspberry Pi 4 Model B (4 GB)Quad-core Cortex-A72 @ 1.8 GHz, 4 GB LPDDR4, Gigabit Ethernet, Wi-Fi 5, BT 5.0, 2× USB 3.0, 40-pin GPIO5 V / 3 A USB-CGPIO, SPI, I²C, UART, CSI, DSIDatasheet
Raspberry Pi Camera Module 312 MP IMX708, autofocus, HDR, 1080p50, CSI-2 ribbon3.3 V via CSICSI-2Datasheet
0.96″ SSD1306 OLED display128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C3.3–5 VI²C (0x3C)Datasheet

Consolidated electrical and interface specifications for every active part in the build.

Power Budget & Supply Sizing

Add up the typical active current of every part, then size the supply with at least 50 % headroom so transmit bursts and motor inrush never brown out the controller.

LoadSupply railTypical current (mA)Notes
Raspberry Pi 4 Model B (4 GB)5 V / 3 A USB-C1200Use an official 5 V 3 A supply — brown-outs from phone chargers corrupt SD cards.
Raspberry Pi Camera Module 33.3 V via CSI250Pi 5 uses a narrower 22-pin CSI cable — the old 15-pin ribbon will not fit.
0.96″ SSD1306 OLED display3.3–5 V20Static images burn in — invert or scroll the screen periodically.

Summed typical draw is 1470 mA. With a 1.5× design margin the supply should deliver at least 2300 mA continuously at the stated rail voltage.

Software Requirements & Development Environment

Reference toolchain: Raspberry Pi OS Bookworm (64-bit) + Python 3.11 + VS Code Remote-SSH. Anything newer normally works; anything older may lack the board definitions used here.

  • Flash Raspberry Pi OS (64-bit) with Raspberry Pi Imager; pre-configure Wi-Fi, hostname and SSH in the Imager settings so the board comes up headless.
  • Update first: sudo apt update && sudo apt full-upgrade -y, then reboot.
  • Work inside a virtual environment — python3 -m venv ~/venv && source ~/venv/bin/activate. Bookworm blocks system-wide pip install by design.
  • Enable the buses you need with sudo raspi-config → Interface Options (I²C, SPI, Serial, Camera).
  • Develop over VS Code Remote-SSH so you edit on your laptop but run on the Pi.

Required libraries

LibraryWhy it is neededInstall
Python 3.11+Runtime for the analysis, training and service code.sudo apt install python3 python3-venv python3-pip
OpenCV 4.10+Frame capture, colour conversion, drawing and classical CV operators.pip install opencv-python
TensorFlow / Keras 2.17+High-level model building and the TFLite converter.pip install tensorflow
Ultralytics YOLO 8.3+Training and inference API for YOLOv8/v11 detectors.pip install ultralytics
Picamera2 0.3.20+libcamera-based capture API for Pi Camera modules.sudo apt install python3-picamera2
Flask 3.0+Minimal HTTP API and dashboard server.pip install flask

Block Diagram

The block diagram shows the functional decomposition of the system — what senses, what decides, what acts, and where the data ends up.

Queue Length Counter — system block diagramFunctional block diagram of the Queue Length Counter system. SeeCameraqueue areaDetect peopleCV modelCountIn queue ROIcountTrack trendover timeSignalThresholdopen/closeStaffact earlyAnalysePeaks/waitsby timeSchedulestaffingrightrightnone
Queue Length Counter — system block diagram

Circuit Diagram & Wiring

Every signal line in the build is shown below, followed by a pin-by-pin connection table you can work through with a multimeter in hand.

Queue Length Counter — wiring schematicConnection schematic showing which controller pin drives each peripheral. Sensors / InputsControllerActuators / OutputsRaspberry Pi 4 ModelB (4 GB)5 V / 3 A USB-CCameraQueue-area video(on-device)Staff signalOpen/close tillNetworkCounts/analytics(not video)Local displayGPIOLive count
Queue Length Counter — wiring schematic
PeripheralPeripheral pinController pinSignal
CameraCSI/USBQueue-area video (on-device)
Staff signalGPIO/HDMIOpen/close till
NetworkWi-Fi/EthCounts/analytics (not video)
Local displayI2CGPIOLive count

Wire one row at a time and tick it off — most "it does not work" reports trace back to a single swapped pair.

Wiring explanation

  • Mount the camera overhead or angled to see the queue area clearly, minimising occlusion.
  • Run inference on-device so raw video never leaves the unit — only counts/signals do.
  • Drive a staff light/screen or dashboard with the open/close-till signal.
  • Network carries counts and analytics, not video, for privacy and bandwidth.
  • Define the queue region-of-interest in the camera view during setup.
A wall-mounted CCTV surveillance camera
People are detected on-device and counted only within the queue region — counting, never identifying. Photograph sourced from Wikimedia Commons — CCTV camera.jpg. Reused under the licence stated on that page; please check it before republishing.

System Architecture

Read the stack from the bottom up: physical hardware, the firmware that drives it, the transport that moves data off the device, and the software a human actually looks at.

Queue Length Counter — architecture stackLayered architecture from hardware to user interface. Hardware layerRaspberry Pi 4 Model B (4 GB) · Raspberry Pi Camera Module 3Driver layerpython · opencv · tf · ultralyticsApplication logicsampling loop · filtering · thresholds · state machinePresentation layerlocal display · serial console · logged output
Queue Length Counter — architecture stack

Working Principle

Queue management fails for a simple reason: stores manage queues by human noticing, which is inconsistent and always a step behind. By the time a supervisor sees a queue has grown and reacts, customers have already been waiting too long, and some have abandoned their baskets. The fix is not more vigilance but a continuous, objective measurement of queue length that the store can act on the moment it starts to build — converting queue management from a reactive judgement call into a data-driven signal.

Producing that measurement is a computer-vision counting problem. A camera views the queue area, and a people-detection model finds the people in each frame. The key refinement is counting within a defined region of interest — the marked queue zone — so passers-by and shoppers elsewhere are not counted, only those actually waiting. Counting over successive frames (with light temporal smoothing/tracking) gives a stable live count and, importantly, its trend: a queue of five that is growing needs a different response from a queue of five that is clearing.

From the count and trend come the staffing signals that are the point of the system. Simple thresholds turn the number into action: above an open-till threshold (or when the trend shows a queue building toward it), signal staff to open another checkout before the wait becomes painful; below a close-till threshold, signal that a till can close, saving labour. Because the signal is early and objective, tills open in time and waits stay short. Aggregated over time, the same counts become analytics — queue length by hour and day, peak periods, estimated average waits — which let managers schedule staffing to demand rather than merely react to it.

What makes this system acceptable to deploy is doing it responsibly, and the design is explicit about it. The goal is strictly counting, not identification: the system needs to know how many people are waiting, never who they are. So it runs on-device (raw video never leaves the unit — only counts and signals do), it counts people rather than recognising faces, and it respects privacy expectations and any notice/consent requirements for cameras in the space. It is also honest about the vision limits: crowding and occlusion (people hidden behind others) make dense queues hard to count exactly, defining where "the queue" is can be ambiguous, and lighting and camera angle matter. Within those honest bounds — an approximate but continuous and objective count, kept private by design — it gives retail exactly what queue management has always lacked: a live, trustworthy handle on how many people are waiting, early enough to do something about it.

The maths behind it

Queue count in a region

plainQueue count in a region
For each frame: detect people {boxes}.

  queue_count = | { p in people : center(p) ∈ ROI_queue } |

Count only inside the marked queue zone — ignore passers-by.
Smooth over frames to steady the number.

Trend (is it building?)

plainTrend (is it building?)
Track count over a short window:

  trend = d(count)/dt   (rising / falling)

A rising queue near the threshold warrants opening a till
BEFORE it crosses — act early, not late.

Staffing signal

plainStaffing signal
if count ≥ OPEN_TH  (or rising toward it):  OPEN a till
if count ≤ CLOSE_TH for a while:            CLOSE a till

Estimated wait ≈ count / service_rate
Set thresholds from acceptable wait times.

Program Flowchart

The firmware is a single cooperative loop. Nothing blocks for long, so networking, sensing and the user interface all stay responsive.

Queue Length Counter — firmware flowchartControl flow through the main program loop. Capture queue-area frame(on-device)Detect people; count withinqueue ROIUpdate live count + trendCount over open-tillthreshold?Signal: open a tillUnder close threshold?Signal: open a tillUnder close threshold?Signal: can close a tillHoldSignal: can close a tillHoldLog for analytics
Queue Length Counter — firmware flowchart

Assembly Instructions

Build on a breadboard first and only commit to solder once the whole system has run for an hour without a fault.

  1. Set up on-device vision over the queue area

    Mount the camera to see the queue clearly, run the people detector on-device, and define the queue region of interest.

  2. Count in the region and track the trend

    Count only people inside the queue ROI, smooth over frames, and track the trend so you can act before thresholds are crossed.

  3. Produce signals and analytics

    Turn count/trend into open/close-till signals with sensible thresholds, and log counts for queue analytics and staffing schedules.

Step-by-Step Implementation Guide

Work through these in order. Each step ends in something you can observe, so a failure is always localised to the step you just finished.

  1. Count people in the queue region

    Detect people on-device and count only those inside the queue ROI, smoothing for a stable live count.

    pythoncount.py
    import numpy as np
    
    def queue_count(detector, frame, roi, history):
        people = detector.detect(frame, classes=["person"])   # on-device only
        n = sum(1 for p in people if point_in_poly(center(p), roi))  # in the queue
        history.append(n); del history[:-10]                  # keep last 10
        return int(round(np.median(history)))                 # smoothed live count
    people = detector.detect(frame, classes=["person"]) # on-device onlyPeople are detected on the device itself, so raw video never leaves the unit — counting, not identification.
    n = sum(1 for p in people if point_in_poly(center(p), roi)) # in the queueOnly people inside the defined queue region are counted, so passers-by and other shoppers are excluded.
    return int(round(np.median(history))) # smoothed live countMedian smoothing over recent frames gives a steady count instead of a number that flickers frame to frame.
  2. Signal staffing and log analytics

    Turn count and trend into open/close-till signals early, and log counts for peak-time analytics and staffing schedules.

Complete Source Code

The listing below is complete and compiles as written — there are no elided sections. Read the annotations under each block before you upload it.

pythonqueue_counter.py
#!/usr/bin/env python3
"""
Queue Length Counter — on-device people counting for staffing

Counts people within a defined queue region from a camera, tracks the
live count and trend, and signals when to open/close a checkout BEFORE
waits get long. Logs counts for queue analytics. Counts, never
identifies: inference on-device; only counts/signals leave the unit.
"""
import time, numpy as np

class QueueCounter:
    def __init__(self, detector, roi, open_th=4, close_th=1, sink=None):
        self.det = detector; self.roi = roi
        self.open_th, self.close_th = open_th, close_th
        self.hist = []; self.sink = sink

    def count(self, frame):
        people = self.det.detect(frame, classes=["person"])   # on-device
        n = sum(1 for p in people if point_in_poly(center(p), self.roi))
        self.hist.append(n); self.hist = self.hist[-10:]
        return int(round(np.median(self.hist)))               # smoothed

    def trend(self):
        return self.hist[-1] - self.hist[0] if len(self.hist) > 1 else 0

    def step(self, frame):
        c = self.count(frame); t = self.trend()
        if c >= self.open_th or (c >= self.open_th-1 and t > 0):
            sig = "OPEN_TILL"                    # early: before waits build
        elif c <= self.close_th:
            sig = "CAN_CLOSE_TILL"
        else:
            sig = "HOLD"
        # ONLY the count + signal leave the device — never video or identities
        if self.sink:
            self.sink.publish("queue/status",
                {"count": c, "trend": t, "signal": sig, "ts": time.time()})
        return c, sig

    def run(self, camera):
        for frame in camera.frames():           # raw frames stay on-device
            self.step(frame)
            time.sleep(0.5)                      # counting needs only a few FPS

if __name__ == "__main__":
    QueueCounter(PersonDetector(), QUEUE_ROI, sink=Dashboard()).run(Camera())
people = self.det.detect(frame, classes=["person"]) # on-deviceDetection runs on-device on raw frames that never leave the unit — the foundation of the privacy-respecting design.
n = sum(1 for p in people if point_in_poly(center(p), self.roi))Counting is restricted to the queue region so only people actually waiting are counted.
if c >= self.open_th or (c >= self.open_th-1 and t > 0):The open-till signal fires early — on a building trend near the threshold — so a till opens before the wait gets long.
# ONLY the count + signal leave the device — never video or identitiesOnly the aggregate count and signal are published; video and any identity information stay on the device — counting, not identifying.
time.sleep(0.5) # counting needs only a few FPSQueue counting needs only a few frames per second, which keeps it comfortably real-time on modest edge hardware.

Configuration & Calibration

Configuration steps

  • Configure the camera, on-device detector and the queue region of interest.
  • Configure smoothing, open/close-till thresholds and trend sensitivity.
  • Configure the staff signal and analytics logging (counts only).
  • Configure privacy: on-device inference, no video egress, notice/consent.

Calibration procedure

An uncalibrated sensor produces confident, precise, wrong numbers. Do this once per physical unit and record the constants.

  1. ROI + counting

    Define the queue region and verify the count matches a manual count at several lengths.

  2. Thresholds

    Set open/close thresholds from acceptable wait times and the service rate.

  3. Robustness

    Check counting under crowding/occlusion and different lighting; accept approximate counts when dense.

Dataset, Model & Training

DatasetSizeLicenceUse here
Person-detection data (e.g. COCO person class)LargeVaries (check terms)Base people detector
Site queue-area frames (ROI-annotated)Small–MediumOn-siteTune ROI / thresholds
Crowd/occlusion samplesMediumVariesRobustness in dense queues
Time-stamped count logsGrowingOn-siteQueue analytics / scheduling
Queue Length Counter — ML pipelineFrom raw data through training to deployed inference. 1Framecamera (on-device)2Detect peopleCV model3Filter to ROIqueue zone4Count + smoothlive length5Signalopen/close till6Loganalytics
Queue Length Counter — ML pipeline
Layer / stageShape or configurationPurpose
Detectorlightweight person detector (YOLO-class / MobileNet-SSD)Runs on-device (Pi/Jetson)
ROI filtercount detections inside the queue regionIgnores passers-by
Tracker/smoothertemporal smoothing / light trackingStable count + trend
Signal logicthresholds + trend on the countOpen/close-till signals
Privacyon-device; counts out, video staysCount, don't identify

Hyperparameters

HyperparameterValueWhy
Detector input size≈ 416–640 pxSpeed vs small-person recall
Confidence threshold≈ 0.4–0.5Miss vs false people
Smoothing window≈ 3–10 sSteady count vs responsiveness
Open/close thresholdsfrom wait targetsSite-specific

Evaluation, Metrics & Deployment

MetricValueWhat it tells you
Counting error (MAE)Low at typical lengthsRises with crowding/occlusion
Signal timelinessFires before waits get longThe operational goal
PrivacyNo identification; video on-deviceBy design
FPS on-deviceReal-time enough (few FPS)Counting needs modest rate

Figures from the reference training run described above — reproduce them before trusting your own changes.

Where the accuracy goesCounting error grows with queue density and occlusion — accurate for short/medium queues, approximate for dense crowds. Short queue (≤5)95Medium (6–12)88Long/dense (13+)72Heavy occlusion60
Where the accuracy goes

Inference example

pythonqueue_count.py
import numpy as np

class QueueCounter:
    def __init__(self, detector, roi_polygon, open_th=4, close_th=1):
        self.det = detector; self.roi = roi_polygon
        self.open_th, self.close_th = open_th, close_th
        self.history = []                       # recent counts (smoothing/trend)

    def count_frame(self, frame):
        people = self.det.detect(frame, classes=["person"])   # on-device
        # count only people whose center is inside the queue region
        n = sum(1 for p in people if point_in_poly(center(p), self.roi))
        self.history.append(n); self.history = self.history[-10:]
        return int(round(np.median(self.history)))            # smoothed

    def signal(self, frame):
        count = self.count_frame(frame)
        trend = self.history[-1] - self.history[0] if len(self.history) > 1 else 0
        if count >= self.open_th or (count >= self.open_th-1 and trend > 0):
            return count, "OPEN_TILL"           # act BEFORE it gets long
        if count <= self.close_th:
            return count, "CAN_CLOSE_TILL"
        return count, "HOLD"
        # NOTE: only 'count' + signal leave the device — never the video/faces.

Testing Procedure & Expected Output

Test from the bottom up. Confirm power, then each sensor in isolation, then the integrated loop — the first failing step tells you exactly where to look.

TestWhat you should see
Short queue formsAccurate live count
Queue builds toward thresholdOPEN_TILL signal fires early (trend)
Queue clearsCAN_CLOSE_TILL signal
People pass by outside the ROINot counted
Dense, occluded queueApproximate count — note the limit
Check data egressOnly counts/signals leave; no video/identities

Bench-test checklist. If a row fails, stop and fix it before moving on.

Expected output

Live queue length, early open/close-till signals, and queue analytics — with only counts leaving the device.

jsonqueue-status.json
{
  "count": 5,
  "trend": 2,
  "signal": "OPEN_TILL",
  "est_wait_min": 6,
  "ts": "2026-07-28T17:12:00"
}

Five people and growing (+2), so the system signalled OPEN_TILL with an estimated 6-minute wait — the till is staffed before the queue becomes a problem; no video or identities ever left the device.

A schematic of a feed-forward artificial neural network
Aggregated counts become queue analytics — peak times and waits — for scheduling staff to real demand. Photograph sourced from Wikimedia Commons — Artificial neural network.svg. Reused under the licence stated on that page; please check it before republishing.

Troubleshooting: Common Errors & Fixes

Counts passers-by

Likely cause. ROI too broad

Fix. Tighten the queue region; count centres inside it

Count flickers

Likely cause. No smoothing

Fix. Median/temporal smoothing over frames

Under-counts dense queues

Likely cause. Occlusion

Fix. Better angle/overhead; accept approximate at high density

Signals too late

Likely cause. Instant-only thresholds

Fix. Act on the trend; open before crossing

Misses people in low light

Likely cause. Lighting/model

Fix. Improve lighting; lower confidence; retrain if needed

Privacy concern

Likely cause. Video/identity egress

Fix. On-device only; publish counts; count, don't identify

The Python script crashes with "externally-managed-environment" on pip install

Likely cause. Raspberry Pi OS Bookworm marks the system Python as managed by apt, and refuses global pip installs.

Fix. Create and activate a virtual environment — python3 -m venv ~/venv && source ~/venv/bin/activate — and install there. Use --system-site-packages if you also need apt-installed modules such as picamera2.

The Pi reboots or shows a lightning-bolt icon under load

Likely cause. Under-voltage. The supply sags below 4.63 V when the CPU and peripherals ramp up.

Fix. Use the official supply for your model (5 V 3 A for Pi 4, 5 V 5 A for Pi 5) and a short, thick USB-C cable. Check with vcgencmd get_throttled — anything other than 0x0 means power problems.

An I²C device is not detected

Likely cause. Wrong address, missing pull-ups, swapped SDA/SCL, or a bus too long for the pull-up value.

Fix. Run an I²C scanner sketch first — it should print the device address. Most breakout boards include 4.7 kΩ pull-ups, but if you have chained four of them the parallel resistance is too low; remove the pull-ups from all but one board. Keep the bus under 30 cm at 100 kHz.

Performance Optimisation

  • Count within the queue ROI and smooth for a steady live number.
  • Act on the trend so tills open before waits build.
  • Run on-device at a few FPS — counting does not need high frame rates.
  • Publish counts/signals only; keep video on the device.
  • Pin the hot loop to one core with taskset and leave the others free for the OS.
  • Prefer MJPEG over raw YUY2 when capturing from USB cameras — the decode cost is far lower than the USB bandwidth cost.
  • Log to a tmpfs RAM disk and flush to the SD card once a minute; per-sample SD writes are what kills cards.
  • Run the service under systemd with Restart=always so a crash never means a dead deployment.
  • Profile before optimising — print micros() deltas around each stage and fix the slowest one first.

Safety Precautions

  • Count, do not identify — run on-device, publish only counts/signals, keep video local.
  • Respect privacy and notice/consent rules for cameras in the space.
  • Do not repurpose the feed for surveillance/recognition — that breaks the design's premise.
  • Treat counts as operational metrics, not judgements about individuals.
  • Wear eye protection when soldering or cutting, and solder in a ventilated space — rosin flux fumes are a respiratory irritant.
  • Power the circuit through a bench supply with a current limit while you are testing. A 300 mA limit turns a wiring mistake into a beep instead of a dead board.
  • Disconnect power before changing any wiring. Hot-plugging a sensor onto a live bus is the fastest way to lose a controller.

Maintenance

  • Re-verify the ROI and counting accuracy after camera/layout changes.
  • Re-tune thresholds as service rates/targets change.
  • Keep the model and lighting adequate for reliable detection.
  • Audit that only counts/signals leave the device.
  • Re-check every screw terminal and header after the first week — thermal cycling loosens connections that felt tight on day one.
  • Recalibrate at the interval given in the calibration section, and keep the constants in a text file next to the firmware — not only in flash.
  • Keep a short logbook of firmware versions and what changed. Six months later you will not remember why that constant is 1.083.

Future Improvements & Upgrades

A working v1 is a platform, not a finish line. These are the upgrades that add the most capability for the least rework.

  • Estimate waits from count + measured service rate.
  • Add multi-queue / whole-store coverage and load balancing.
  • Add heat-map analytics for layout optimisation.
  • Integrate with workforce scheduling from historical peaks.
  • Design a proper PCB. Once the breadboard version has run for a month, moving to a two-layer board removes the intermittent-contact failures that dominate prototype faults.
  • Add connectivity — an ESP32 and an MQTT publish turn a local gadget into something you can graph, alert on and analyse over months.
  • Add persistent local storage (microSD or the on-chip flash) so a network outage does not create a hole in your data.
  • Move configuration out of the source: a captive-portal setup page or a JSON config file makes the build reusable without a recompile.
  • Add a battery and solar option so the unit survives a power cut and can be sited away from a socket.
  • Write a small test harness that feeds synthetic sensor values through the decision logic, so you can validate thresholds without physically triggering the event.

Frequently Asked Questions

What problem does it solve?

Stores manage queues by human noticing, which is inconsistent and always late. A live, objective count of people waiting lets the store open a till before the wait gets long — shortening waits and reducing walked-away sales.

How does it count only the queue?

It counts people whose position falls inside a defined queue region of interest, so passers-by and shoppers elsewhere are ignored. Counting over frames with smoothing gives a stable number and its trend.

Is it watching individual customers?

No. The goal is counting, not identification. It runs on-device so raw video never leaves the unit, it counts people rather than recognising faces, and only counts and signals are published — privacy-respecting by design.

Why act on the trend, not just the count?

Because opening a till takes time. If you wait until the count crosses the threshold, customers already wait too long. Acting when a queue is building toward the threshold staffs the till before the wait becomes painful.

How accurate is it?

Accurate for short and medium queues; approximate for dense, occluded crowds where people hide behind one another. For staffing decisions an approximate but continuous count is far better than the too-late human judgement it replaces.

References & Learning Resources

These are the primary sources worth reading in full. Manufacturer datasheets always outrank forum posts when the two disagree.

  1. Object detection (people)Reference
  2. Crowd countingReference
  3. Queueing theory / waiting linesReference
  4. Edge AI / on-device inferenceReference
  5. Privacy by designReference