Contents — 27 sections
Project Overview
Reads vehicle number plates at a gate to log and automate entry and exit — with the OCR, whitelist and privacy realities of real ANPR handled honestly.
Automatic number-plate recognition (ANPR) turns a gate into something that recognises vehicles: it reads the plate of an approaching car, logs the entry or exit with a timestamp and image, and — for known vehicles on a whitelist — opens the gate automatically, so residents or staff never stop while visitors are handled by exception. It is one of the most visibly useful pieces of computer vision, and also one where the gap between a demo and a dependable system is wide, because plates in the real world are dirty, angled, glared, motion-blurred, and lit by headlights at night. This project builds a gate logger that treats those realities — and the privacy implications of recording vehicle movements — as core design problems, not afterthoughts.
The pipeline is a classic two-stage vision problem: first detect where the plate is in the camera frame (a small object-detection step that finds the plate region against a busy scene), then read the characters on it (an OCR step, ideally a recogniser trained on plates rather than generic text). Doing detection first is what makes the OCR reliable — feeding a tightly-cropped, deskewed plate to the recogniser instead of a whole noisy frame dramatically cuts errors. The result is matched against a whitelist of authorised plates to decide whether to open the gate, and every read — recognised or not — is logged with its confidence and a captured image so a human can verify or override.
The honesty is in the edges. OCR is never perfect, so the system reports a confidence and is designed to fail gracefully: a low-confidence or unrecognised read does not fling the gate open or slam it shut — it falls back to a human (an intercom, a guard, a visitor flow) rather than trusting a shaky guess, and near-matches (one ambiguous character) are handled deliberately. Because ANPR records where and when specific vehicles go, it is personal data, so the design keeps the plate database and logs access-controlled, is explicit about retention, and is framed for legitimate access control on private premises — not covert tracking. It is candid that lighting, angle and plate condition set a hard ceiling on accuracy, and that a good camera, IR illumination and a controlled approach geometry matter as much as the model. But built with those constraints respected, a plate-reading gate is a genuinely convenient, well-logged, and responsibly-run piece of access automation.
What this project does
- Detects the number plate in the camera frame, then reads its characters (OCR)
- Matches the plate against a whitelist to automate gate entry/exit
- Logs every read (recognised or not) with confidence, time and image
- Falls back to a human on low-confidence/unknown plates instead of guessing
- Handles day and night with a suitable camera and IR illumination
- Treats plate data as personal data — access-controlled, retention-explicit
- Automates known vehicles while visitors are handled by exception
Real-World Applications
| Setting | How it is used |
|---|---|
| Residential society / gated community gates | Auto-opening for residents' registered vehicles, logged entry/exit, and a visitor exception flow. |
| Office / campus parking | Staff whitelist automation and complete vehicle logs for a controlled car park. |
| Small toll / access barriers | Automated barrier operation for authorised vehicles with an audited fallback. |
| Fleet / yard access | Logging and gating company vehicles in and out of a depot or yard. |
Deployment contexts where a build of this kind earns its keep.
Features & Capabilities
- Two-stage detect-then-read pipeline for reliable OCR
- Confidence-gated decisions with graceful human fallback
- Whitelist automation for residents/staff; exception flow for visitors
- Full audit log with captured images
- Day/night operation with IR and controlled approach geometry
- Privacy-aware: access-controlled data, explicit retention
- Honest about accuracy limits (lighting, angle, plate condition)
Difficulty, Time & Required Skills
| Attribute | Value |
|---|---|
| Difficulty level | Advanced |
| Estimated completion time | 16–24 hours |
| Indicative build cost | ₹6,000 – ₹10,000 |
| Primary discipline | Security |
| Reference platform | Raspberry Pi 4 Model B (4 GB) |
Skills you should have (or will pick up)
- Building a plate-detection + OCR (ANPR) pipeline
- Camera/geometry/lighting setup for readable plates
- Confidence gating and graceful fallback logic
- Whitelist matching with near-match handling
- Privacy-aware data handling and retention
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.
| Component | Key specification | Qty | Approx. 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 GPIO | 1 | ₹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 ribbon | 1 | ₹2,600 |
| 5 V single-channel opto-isolated relay module Cut the JD-VCC jumper and feed the coil separately for true isolation. | SPDT contacts rated 10 A @ 250 VAC / 10 A @ 30 VDC, opto-isolated input | 1 | ₹90 |
| ESP32 DevKit V1 (ESP-WROOM-32) Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly. | Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC | 1 | ₹450 |
| microSD card 32 GB A1 class For 24/7 loggers buy a high-endurance card — normal cards die in months. | A1 rated, 10 MB/s random write, UHS-I, endurance-grade recommended | 1 | ₹450 |
| 5 V 3 A regulated SMPS adapter Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A. | 100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection | 1 | ₹350 |
| ANPR-suitable camera + IR Motion blur and night are the main failure sources | Global-shutter or fast camera with IR-pass/illumination for night plates | 1 | ₹2,500 |
| Gate/barrier interface | Relay/dry-contact to the gate motor controller, with safety interlocks | 1 | ₹600 |
| Vehicle-present trigger Trigger capture when a vehicle is in position | Loop detector / IR beam to capture at the right moment | 1 | ₹700 |
| Weatherproof camera housing | IP-rated, sun-hooded, positioned for a controlled plate view | 1 | ₹500 |
Estimated total: ₹14,040, 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
| Part | Specification | Supply | Interface | Reference |
|---|---|---|---|---|
| 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 GPIO | 5 V / 3 A USB-C | GPIO, SPI, I²C, UART, CSI, DSI | Datasheet |
| Raspberry Pi Camera Module 3 | 12 MP IMX708, autofocus, HDR, 1080p50, CSI-2 ribbon | 3.3 V via CSI | CSI-2 | Datasheet |
| 5 V single-channel opto-isolated relay module | SPDT contacts rated 10 A @ 250 VAC / 10 A @ 30 VDC, opto-isolated input | 5 V coil | Digital (active-low) | Datasheet |
| ESP32 DevKit V1 (ESP-WROOM-32) | Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC | 3.3 V logic / 5 V USB | UART, SPI, I²C, I²S, CAN, PWM | Datasheet |
| microSD card 32 GB A1 class | A1 rated, 10 MB/s random write, UHS-I, endurance-grade recommended | 3.3 V | SDIO / SPI | Datasheet |
| 5 V 3 A regulated SMPS adapter | 100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection | 5 V | DC barrel / USB | 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.
| Load | Supply rail | Typical current (mA) | Notes |
|---|---|---|---|
| Raspberry Pi 4 Model B (4 GB) | 5 V / 3 A USB-C | 1200 | Use an official 5 V 3 A supply — brown-outs from phone chargers corrupt SD cards. |
| Raspberry Pi Camera Module 3 | 3.3 V via CSI | 250 | Pi 5 uses a narrower 22-pin CSI cable — the old 15-pin ribbon will not fit. |
| 5 V single-channel opto-isolated relay module | 5 V coil | 70 | Cut the JD-VCC jumper and feed the coil separately for true isolation. |
| ESP32 DevKit V1 (ESP-WROOM-32) | 3.3 V logic / 5 V USB | 160 | Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly. |
| microSD card 32 GB A1 class | 3.3 V | 100 | For 24/7 loggers buy a high-endurance card — normal cards die in months. |
| 5 V 3 A regulated SMPS adapter | 5 V | 3000 | Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A. |
Summed typical draw is 4780 mA. With a 1.5× design margin the supply should deliver at least 7200 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-widepip installby 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
| Library | Why it is needed | Install |
|---|---|---|
| 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 |
| PyTorch 2.4+ | Model definition, autograd and GPU training. | pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 |
| Ultralytics YOLO 8.3+ | Training and inference API for YOLOv8/v11 detectors. | pip install ultralytics |
| FastAPI + Uvicorn 0.115+ | Typed async REST API with automatic OpenAPI docs. | pip install fastapi uvicorn[standard] |
| SQLite 3.45+ | Zero-configuration embedded database for local logs. | Bundled with Python (`import sqlite3`) |
| Picamera2 0.3.20+ | libcamera-based capture API for Pi Camera modules. | sudo apt install python3-picamera2 |
Block Diagram
The block diagram shows the functional decomposition of the system — what senses, what decides, what acts, and where the data ends up.
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.
| Peripheral | Peripheral pin | Controller pin | Signal |
|---|---|---|---|
| Pi camera | CSI | CSI | Plate image capture |
| Vehicle trigger | OUT | GPIO | Capture-now (loop/beam) |
| IR illuminator | EN | GPIO | Night lighting |
| Gate relay | IN | GPIO | Open barrier (whitelisted) |
| ESP32 (gate I/O) | UART | GPIO | Barrier control + interlocks |
| microSD/SSD | bus | — | Log + image store |
| 5V supply | +/– | — | Pi power |
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
- Trigger capture from a loop detector or IR beam when the vehicle is in the read position, rather than processing video continuously — cleaner images, less compute.
- Add IR illumination for night plates (many plates are retroreflective and read well under IR) and control camera exposure to freeze motion.
- Interface the gate through a relay/dry-contact to the barrier's own controller, keeping the barrier's safety interlocks (obstruction sensing) intact.
- Position and hood the camera for a controlled, near-frontal plate view at the trigger point; geometry is half the accuracy.
- Store images and logs on reliable local storage (SD/SSD); treat them as personal data with access control.
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.
Working Principle
ANPR is a pipeline, and its reliability comes from doing the easy discriminative step before the hard generative one. Detection first: a lightweight object detector finds the plate's bounding box in the frame — a well-defined, robust task even in a cluttered scene. Only then does the OCR run, and it runs on a small, tightly-cropped, deskewed image of just the plate. This ordering matters enormously: a character recogniser fed a whole scene must cope with background text, varied scale and clutter and fails often, while the same recogniser fed a clean plate crop is far more accurate. Detection also lets the system normalise geometry (rotate/warp the plate to a canonical front-on view) before reading, removing much of the angle-induced error.
The OCR stage is where real-world plates fight back. Plates are read by a model that maps the cropped image to a character string, ideally one trained on plates (their fonts, spacing, regional formats) rather than generic text. Its accuracy is bounded by the input: motion blur from a moving car, glare and low contrast in bright sun, darkness and headlight flare at night, and dirt or damage on the plate itself all degrade the read. This is why the physical setup — a fast enough exposure to freeze motion, IR illumination that exploits plates' retroreflectivity at night, and a controlled approach geometry so the plate is near-frontal at the trigger point — is not optional polish but a determinant of accuracy equal to the model. The system also uses format priors (a region's plates follow patterns) to catch and correct impossible reads.
Because OCR is probabilistic, the whole system is designed around confidence and graceful failure. Every read carries a confidence, and the gate logic is gated on it: a high-confidence match to a whitelisted plate opens the gate automatically; anything below the confidence bar, or not on the whitelist, does not trigger a blind action but falls back to a human path — an intercom to a guard, a visitor-registration flow, a manual open. Near-matches (a single ambiguous character, an O/0 or 8/B confusion) are handled deliberately, either by choosing the whitelist entry within an edit-distance of one if unambiguous, or by escalating to a human. This "automate the confident majority, human-handle the uncertain minority" design is what makes ANPR useful without being dangerous — it never lets a shaky guess open a barrier or wrongly turn a resident away, and it always logs the captured image so a person can adjudicate.
ANPR also carries a duty because it is surveillance of people via their vehicles. A log of which plates passed a gate, when, is personal data that reveals movements and patterns, so responsible design keeps the plate database and the read logs access-controlled, sets an explicit retention policy (keep what the access-control purpose needs, no more), and frames the system for legitimate premises access rather than covert tracking of individuals. Combined with the accuracy honesty — that lighting, angle and plate condition impose a real ceiling and a good camera and geometry matter as much as any model — this yields a system that is convenient and well-logged where it works, safe where it is unsure, and respectful of the fact that reading plates means recording people.
The maths behind it
Two-stage recognition
frame → detector → plate box → crop+deskew → OCR → string,conf
Detection localises; OCR reads the CROP, not the frame.
Geometry normalisation (perspective warp to front-on)
before OCR removes much angle-induced error.
Confidence-gated decision
read (plate P, confidence c):
if c > C_HI and P ∈ whitelist → open gate, log entry
elif c > C_HI and dist(P, whitelist)=1 (unambiguous) → open, flag
else → human fallback, log read
Never open on low confidence or a blind guess.
Near-match (edit distance) handling
For read P and whitelist W:
best = argmin_{w∈W} levenshtein(P, w)
d = levenshtein(P, best)
d = 0 → exact match
d = 1 & unique → likely OCR slip (O/0, 8/B): accept w/ flag
d ≥ 2 or tie → treat as unknown → human fallback
Format priors (regional plate pattern) reject impossible reads.
Program Flowchart
The firmware is a single cooperative loop. Nothing blocks for long, so networking, sensing and the user interface all stay responsive.
Assembly Instructions
Build on a breadboard first and only commit to solder once the whole system has run for an hour without a fault.
Set up capture geometry and trigger
Mount the camera for a controlled, near-frontal view of the plate at the point a vehicle stops, hooded against sun. Add a loop detector or IR beam to trigger capture when the vehicle is in position.
Add IR illumination for night, and set the exposure fast enough to freeze approach motion.
Build the detect-then-read pipeline
Run a plate detector to localise and crop the plate, deskew it to a front-on view, then OCR the crop to a string with a confidence. Apply regional format priors to sanity-check the read.
Wire the gate and logging
Interface the barrier through a relay to its own controller (keeping its safety interlocks), and store every read — image, string, confidence, decision — to access-controlled local storage.
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.
Decide with confidence gating and fallback
Match the read against the whitelist with near-match handling, open the gate only on a confident (exact or unambiguous near) match, and otherwise fall back to a human — logging the image and result either way.
pythongate-decision.pyfrom Levenshtein import distance C_HI = 0.85 # confidence bar for automatic action def decide(plate, conf, whitelist): if conf < C_HI: return "human", "low confidence" # never guess the gate open if plate in whitelist: return "open", "exact match" # tolerate a single unambiguous OCR slip (O/0, 8/B, ...) near = [w for w in whitelist if distance(plate, w) == 1] if len(near) == 1: return "open", f"near match -> {near[0]} (flagged)" return "human", "unknown vehicle" def handle_read(plate, conf, image, whitelist, log, gate): action, reason = decide(plate, conf, whitelist) log.append(plate=plate, conf=conf, action=action, reason=reason, image=image) # always log + image if action == "open": gate.open() else: gate.request_human() # intercom / visitor flowif conf < C_HI:Any read below the confidence bar goes straight to a human — a shaky OCR result never operates the barrier.if plate in whitelist:A confident exact match to an authorised vehicle opens the gate automatically — the convenient common case.near = [w for w in whitelist if distance(plate, w) == 1]A single unambiguous character slip (a classic O/0 or 8/B confusion) is tolerated and flagged, so common OCR errors do not needlessly turn a resident away.log.append(Every read — automatic or human-handled — is logged with its image, so decisions are auditable and a person can verify or correct.gate.request_human()The uncertain minority falls back to an intercom or visitor flow rather than a blind action, the graceful-failure design at the heart of usable ANPR.Log, store and respect privacy
Store the image, plate, confidence and decision to access-controlled storage with an explicit retention policy, and expose logs only to authorised operators.
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.
#!/usr/bin/env python3
"""
Number-Plate Gate Logger — Raspberry Pi ANPR
Two-stage detect-then-read pipeline, confidence-gated gate control with
human fallback, whitelist (with near-match) matching, and audited,
privacy-aware logging with captured images.
"""
import time, cv2
from Levenshtein import distance
from ultralytics import YOLO # plate detector (fine-tuned)
from plate_ocr import read_plate # OCR model returning (text, conf)
C_HI = 0.85
detector = YOLO("plate_detect.pt")
def capture():
# triggered by loop/beam when a vehicle is in position
return picam_capture() # returns a BGR frame
def detect_and_read(frame):
res = detector(frame, verbose=False)[0]
if not len(res.boxes):
return None, 0.0, None
# take the most confident plate box
box = max(res.boxes, key=lambda b: float(b.conf))
x1, y1, x2, y2 = map(int, box.xyxy[0])
crop = frame[y1:y2, x1:x2]
crop = deskew(crop) # warp to a front-on view
text, conf = read_plate(crop) # OCR the clean crop
return normalise(text), conf, crop
def decide(plate, conf, whitelist):
if plate is None or conf < C_HI:
return "human", "low confidence / no plate"
if plate in whitelist:
return "open", "exact match"
near = [w for w in whitelist if distance(plate, w) == 1]
if len(near) == 1:
return "open", f"near match -> {near[0]} (flagged)"
return "human", "unknown vehicle"
def main(whitelist, gate, db):
while True:
wait_for_vehicle_trigger() # loop/beam
set_ir(is_dark())
frame = capture()
plate, conf, crop = detect_and_read(frame)
action, reason = decide(plate, conf, whitelist)
db.log(plate=plate, conf=conf, action=action,
reason=reason, image=crop, ts=time.time()) # audit + image
if action == "open":
gate.open() # barrier keeps its interlocks
else:
gate.request_human() # intercom / visitor flow
db.enforce_retention() # purge beyond policy
if __name__ == "__main__":
main(load_whitelist(), Gate(), PlateDB())
Configuration & Calibration
Configuration steps
- Set the confidence bar (C_HI), the whitelist, and regional plate-format priors.
- Configure the camera exposure/IR and the vehicle trigger for your gate geometry.
- Set the retention policy and access controls for the plate database and image logs.
- Configure the gate interface and ensure the barrier's own safety interlocks remain active.
Calibration procedure
An uncalibrated sensor produces confident, precise, wrong numbers. Do this once per physical unit and record the constants.
Geometry and exposure
Tune camera position, angle and exposure at the trigger point until day plates are captured sharp and near-frontal; verify IR gives readable night plates.
Confidence bar
Set C_HI by reviewing real captures: high enough that wrong-opens are ~zero, low enough that most known vehicles auto-open.
Whitelist / near-match
Validate that exact and single-slip near-matches behave as intended and that ambiguous cases go to a human.
Dataset, Model & Training
Dataset
ANPR uses two learned components: a plate detector and a character recogniser. Both benefit from data matching your region's plates and your camera's conditions (angle, night IR), so fine-tuning on locally-captured plates markedly improves accuracy over a generic model.
Regional plate formats (character counts, allowed patterns) act as strong priors that catch impossible reads.
| Dataset | Size | Licence | Use here |
|---|---|---|---|
| Open ANPR / plate datasets | Thousands–tens of thousands | Varies (check per set) | Base plate detection + OCR |
| Your-gate capture set | Hundreds–thousands | Your own footage | Fine-tune to camera, angle, night |
| Synthetic plates | Generated | Self-generated | Augment character coverage/formats |
Data preprocessing
- Crop to the detected plate box and deskew/warp to a canonical front-on rectangle.
- Normalise contrast (and handle IR imagery for night), then resize to the OCR model's input.
- Apply regional format priors to validate/repair the character string.
Model architecture
A compact object detector (e.g. a small YOLO) localises the plate; a sequence recogniser (CNN + CTC, or a small transformer OCR) reads the characters from the crop.
On a Raspberry Pi, use lightweight/quantised models and trigger inference only on a vehicle event to stay real-time.
| Layer / stage | Shape or configuration | Purpose |
|---|---|---|
| Detector | small YOLO (plate class) | Localise the plate region robustly |
| Rectify | perspective warp | Front-on normalisation before OCR |
| OCR | CNN + CTC / small OCR transformer | Read variable-length plate strings |
| Priors | regional format regex | Reject/repair impossible reads |
Hyperparameters
| Hyperparameter | Value | Why |
|---|---|---|
| detector input | ~640 px | Balance speed and small-plate recall |
| OCR input | ~normalised 32×128 | Standard plate-crop size |
| C_HI (confidence bar) | ~0.85 | Trade auto-open rate vs wrong-open risk |
| near-match edit distance | 1 | Tolerate a single unambiguous OCR slip |
Training process
- Fine-tune the detector on plates in your scene geometry and lighting; train/fine-tune the OCR on plate crops including night-IR imagery.
- Augment with blur, glare, rotation and partial occlusion so the models are robust to real approach conditions.
- Validate on held-out real gate captures, tracking read accuracy separately for day and night.
Evaluation, Metrics & Deployment
The decisive metrics are end-to-end plate-read accuracy and, operationally, the auto-open rate versus the wrong-open rate.
| Metric | Value | What it tells you |
|---|---|---|
| Plate read accuracy (day) | ~95%+ | Exact-string accuracy on good day captures |
| Plate read accuracy (night) | lower | IR/exposure dependent; the hard case |
| Auto-open rate | target high for known | Fraction of known vehicles handled without a human |
| Wrong-open rate | target ~0 | The costly error — gated hard by confidence |
Figures from the reference training run described above — reproduce them before trusting your own changes.
Deployment
- Run detection + OCR on the Pi triggered by a vehicle event; keep models quantised for real-time performance.
- Keep the plate database and image logs on access-controlled local storage with enforced retention.
- Provide a human-in-the-loop path for low-confidence/unknown reads and a way to correct/label captures to improve the models.
Inference example
# End-to-end read for one capture (detect -> deskew -> OCR -> validate).
def read(frame, region_regex):
box = detect_plate(frame) # localise
if box is None:
return None, 0.0
crop = deskew(frame[box.slice]) # front-on warp
text, conf = ocr(crop) # chars + confidence
text = repair_with_prior(text, region_regex) # format validation
return text, conf
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.
| Test | What you should see |
|---|---|
| Known plate, good day light | Read confidently, gate auto-opens, logged with image |
| Known plate with one OCR slip | Near-match accepted and flagged; gate opens |
| Unknown plate | Human fallback; read logged with image |
| Low-confidence/blurred read | No auto action; falls back to human |
| Night capture | IR gives a readable plate; day-only model may need night data |
| Check retention/access | Old records purged; logs only accessible to authorised operators |
Bench-test checklist. If a row fails, stop and fix it before moving on.
Expected output
The dashboard shows a log of entries/exits with plate, confidence, time, decision and a captured image, and lets an operator handle fallbacks and correct reads.
{
"plate": "MH12AB1234",
"confidence": 0.93,
"action": "open",
"reason": "exact match",
"time": "2026-07-27T09:02:41",
"image": "/logs/20260727-090241.jpg"
}
A confident exact match auto-opens for a resident and is logged with its image; a low-confidence or unknown read would instead route to a human, still logged, never blindly acted on.
Troubleshooting: Common Errors & Fixes
Performance Optimisation
- Trigger inference on a vehicle event, not on continuous video, to save compute and get cleaner frames.
- Detect then OCR the crop; do not OCR whole frames.
- Use quantised/lightweight models on the Pi for real-time reads.
- Store images efficiently and enforce retention so storage does not grow unbounded.
- Pin the hot loop to one core with
tasksetand 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
systemdwithRestart=alwaysso a crash never means a dead deployment. - For battery builds use deep sleep between samples: an ESP32 drops from ~160 mA awake to about 10 µA asleep, which is the difference between days and months of runtime.
- Profile before optimising — print
micros()deltas around each stage and fix the slowest one first.
Safety Precautions
- Plate/movement data is personal data — access-control it, set explicit retention, and use it for legitimate premises access, not covert tracking.
- Keep the barrier's own safety interlocks (obstruction sensing) active; ANPR only requests open/close.
- Never auto-act on a low-confidence read; always provide a human fallback and an audit image.
- Comply with local ANPR/CCTV and data-protection law, including signage where required.
- Mains voltage kills. Anything on the load side of the relay is at 230 V. Do not work on a powered circuit, and never leave exposed mains wiring on a bench where someone could touch it.
- Keep at least 6 mm of creepage between the mains and low-voltage sides of any board you make, and never route mains tracks under the microcontroller.
- Have a qualified electrician do the final installation into a consumer unit or wall fitting. In most jurisdictions this is a legal requirement, not a suggestion.
- Fit an RCD/RCBO upstream and fuse the load appropriately for its rating.
- 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
- Clean the camera/IR optics; dirt and glare degrade reads.
- Re-tune geometry/exposure seasonally and after any camera movement.
- Retrain/fine-tune the models with corrected captures, especially for night.
- Review retention/access and purge as policy requires.
- Re-check every screw terminal and header after the first week — thermal cycling loosens connections that felt tight on day one.
- Rotate the microSD card annually and keep an image of the working system. Cards used as loggers wear out silently.
- 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.
- Add make/model/colour as corroborating features to catch cloned plates.
- Add a resident self-service portal to register/deregister vehicles.
- Add two-camera capture (front/rear) for higher read reliability.
- Federate multiple gates with a shared, access-controlled vehicle registry.
- 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
References & Learning Resources
These are the primary sources worth reading in full. Manufacturer datasheets always outrank forum posts when the two disagree.
- Automatic number-plate recognition — overviewReference
- Optical character recognitionReference
- YOLO object detectionUltralytics
- CTC sequence recognition (OCR)Reference
- ANPR and data protection considerationsICO