ANPR on Existing CCTV: How We Built Acasa Sentinel

ANPR on existing CCTV: ingest RTSP or HLS, track before reading, vote across frames, match fuzzily, run locally. In a sandbox, 24 of 24 plates matched.

white security camera at daytime
Photo by Nathy dog / Unsplash

You can run ANPR on existing CCTV cameras if the software reads standard streams such as RTSP and HLS, tracks each vehicle before reading its plate, votes across frames for one reading per vehicle, matches plates with OCR-aware fuzzy rules, and runs inference locally. Wide-area cameras still miss plates, so add appearance search as a fallback.

TL;DR: Plate recognition works on ordinary CCTV when you track first, read second, and vote across frames. Our hackathon build, Acasa Sentinel, matched 24 of 24 plates on its proof clip with zero false alarms across 100,000 unrelated plates. Those are sandbox numbers, not production ones. Measure on your own cameras before trusting any figure.

Acasa Sentinel is the system this post walks through. We built it for the Gujarat Police Hackathon Innovation Challenge 2026: give it a number plate and it returns the vehicle's route across a CCTV network. It's a hackathon build and a case study, not a production deployment, and every number below was measured on the running system against the hackathon sandbox.

Can you run ANPR on existing CCTV cameras?

Usually, yes. If a camera, or the video management system behind it, can hand out an RTSP or HLS stream, software can read plates from it. What you can't change in software is the camera's angle, height, and zoom. Those decide which plates are readable at all, so expect good results at gates and junctions and patchy ones on wide views.

Why isn't plate reading alone enough?

Because on wide-area cameras the plate is often a few blurred pixels. A vehicle can cross five cameras and be readable at only one of them. A system that depends only on plates loses the vehicle at every unreadable camera, which is exactly where an investigator needs it.

So a useful system needs two things: good plate reading where plates are readable, and another way to follow a vehicle where they aren't. The plate gives you a confident anchor; appearance search carries the trail between anchors.

What are the stages of an ANPR pipeline on existing CCTV?

Sentinel splits the work into eight stages, from pulling video off the camera to putting a candidate alert in front of a person. Each stage has one job, which makes failures easy to locate when a vehicle goes missing from a route.

Stage What Sentinel does
Ingest RTSP and HLS behind one interface; a worker per camera under a supervisor
Timing Timestamps from the video stream itself, not from when frames arrive
Detection and tracking YOLOv8 with ByteTrack, for vehicles and people
Plate reading Plate detection and ONNX OCR per track, with a multi-frame vote
Appearance A 768-dimension DINOv2 embedding per sighting, in Postgres with pgvector
Matching OCR-aware fuzzy matching against the watchlist
Routes Reconstruction that rejects physically implausible hops and says why
Alerts A queue for an operator to confirm or reject, with evidence crops and an audit trail

These are the models we built with, not a recommendation: YOLOv8 dates from January 2023, and newer versions exist (Ultralytics docs). The stage layout matters more than any one model.

Ingest from any camera vendor

Read the standard protocols instead of a vendor SDK. RTSP is the IETF's protocol for setting up and controlling real-time audio and video delivery (RFC 7826), and HLS is the HTTP-based streaming format many video systems re-stream in (RFC 8216). Support both and most IP cameras are covered.

Sentinel puts both behind one interface, with a worker per camera under a supervisor, so one bad camera can't take down the rest. Two details matter:

  1. Timing from the stream. Frames arrive late or in bursts over a network, so Sentinel takes time from the video stream itself. Route reconstruction depends on it.
  2. Bounded stream timeouts. A stalled camera returns in seconds instead of wedging a thread. Cameras go offline all the time; the system should notice and move on.

Arrival time is the trap. Stamp a frame when it reaches the server and, on a congested link, the stamp drifts, making a car look like it drove impossibly fast between two cameras. Stream time avoids that whole class of bug.

Track the vehicle, then read the plate

One car passing a camera spans dozens of frames, and reading every frame gives dozens of slightly different plates. Tracking ties those frames to one vehicle first. The plate reader then works per track, so each vehicle yields one sighting instead of hundreds of near-duplicates.

Sentinel detects vehicles and people with YOLOv8 and follows them with ByteTrack. ByteTrack's idea is to keep low-confidence detections, such as a half-hidden car, and link them to existing tracks rather than throw them away (ByteTrack paper). That keeps a track alive through a passing bus.

What does the multi-frame vote buy you? A plate is often sharp in three frames and smeared in the rest. Combining readings across the track gives a steadier result than trusting any single frame.

How does fuzzy matching handle OCR mistakes?

It treats characters OCR commonly confuses as near-equal. O and 0, I and 1, B and 8 get misread predictably, so an exact match would miss a vehicle over one character. Sentinel's OCR-aware fuzzy matching lets a plate read with an O for a 0 still hit the watchlist.

Fuzzy matching raises the risk of false matches, so Sentinel measured both sides. On the hackathon sandbox it matched 24 of 24 plates on the proof clip and raised 0 false alarms across 100,000 unrelated plates. The first is about finding the right vehicle; the second about not flagging the wrong one. Neither is a production figure, and a real deployment needs its own measurement, in its own light and weather.

What happens when the plate is unreadable?

Sentinel falls back to appearance. Every sighting gets a 768-dimension DINOv2 embedding, a numeric fingerprint of how the vehicle looks. A car seen clearly at one camera can then be found at nearby cameras by similarity, even where its plate is a smudge.

The vectors live in Postgres with pgvector, which stores vectors alongside the rest of your data and supports cosine distance and HNSW indexes (pgvector). We chose it so sightings, camera locations in PostGIS, and similarity search sit in one database. One system to back up, one to secure.

Is a separate vector database ever the better call? At larger scale it can be; see Qdrant vs pgvector and our vector databases page.

Candidates, not verdicts

Sentinel never acts on its own. Route reconstruction rejects physically implausible hops and says why: two cameras 40 km apart a minute apart can't be the same car, however alike they look. Watchlist hits go to a queue for an operator to confirm or reject, with evidence crops and an audit trail.

The system proposes; a person decides. For anything involving enforcement, that's the only acceptable design.

Does ANPR inference need the cloud or a big GPU?

No. In Sentinel all inference runs locally, and no footage or number plate is sent to a third-party API. The same pipeline falls back from CUDA to Apple Silicon to CPU, so it runs on whatever hardware is on site. On the sandbox the detector took 5.7 ms per 1080p frame on Apple Silicon.

What does "local only" mean in practice? Every model runs on the machine running the pipeline: YOLOv8 for detection, an ONNX model for plate OCR, DINOv2 for embeddings. Footage never has to leave the site to be analysed.

Sentinel detector time per 1080p frame compared with the gap between frames at 30 and 25 frames per second Detector time vs gap between frames (ms) Sentinel detector, 1080p 5.7 Frame gap at 30 fps 33.3 Frame gap at 25 fps 40
Frame gap is 1000 ms divided by frame rate. Source: Acasa Sentinel, measured against the hackathon sandbox on Apple Silicon, not a production deployment.

That's headroom for one stage on one stream, not total capacity. The sandbox had 30 cameras registered, and tracking, OCR, and embeddings all add time, so size real deployments per camera count and frame rate.

One events table for every analytic

Plates aren't the only thing operators want. Sentinel stores plate sightings, crowd counts, and zone intrusion in one events table, so a new alert type needs no schema change. If you plan to add analytics over time, design for it on day one. We cover the wider set on the CCTV video analytics page.

What does an operator actually do?

The pipeline exists to give one person at a console a short workflow: searches and reviews, each with evidence attached, ending in a recorded human decision. The console is Next.js, with Leaflet for the map:

  1. Enter a plate. Fuzzy matching allows for the characters OCR tends to misread.
  2. See every matching sighting on a map, with times and evidence crops.
  3. Pick a clear sighting and ask for similar-looking vehicles at nearby cameras, to fill gaps where the plate was unreadable.
  4. Review the reconstructed route, including any hops the system rejected and why.
  5. Confirm or reject any watchlist hits in the queue, leaving an audit trail.

What should you check before deploying ANPR in India?

Start with the law. Plate sightings tied to people are personal data, and India's Digital Personal Data Protection Act, 2023 now has its Rules, notified on 14 November 2025 with an eighteen-month phased compliance period (PIB backgrounder). Get legal advice for your deployment.

The backgrounder lists storage limitation and security safeguards among the Act's core principles. In engineering terms:

  1. Approvals. Surveillance approval is the operator's responsibility.
  2. Measurement. Test on your own cameras, by day, at night, and in rain.
  3. Retention. Decide how long sightings, crops, and embeddings are kept.
  4. Access. Define who can search, who confirms alerts, and how searches are audited.
  5. Failure. Plan for cameras going offline.

FAQ

Do we need new cameras to start reading plates?

Not to start. Run a pilot on the cameras you have, with streams pulled over RTSP or HLS, and measure which ones produce readable plates. Cameras at gates and junctions usually do. Wide views often don't, and appearance search covers some of that gap.

How many cameras can one machine handle?

It depends on resolution, frame rate, and which stages run per frame. Sentinel's detector took 5.7 ms per 1080p frame on Apple Silicon, with 30 cameras registered in the hackathon sandbox, but that's one stage and not a production load test. Measure the full pipeline on your hardware.

How long should plate sightings be kept?

As briefly as the purpose allows. Set separate retention periods for sightings, evidence crops, and appearance embeddings, write them down, and delete on a schedule rather than by hand. India's DPDP framework names storage limitation as a core principle, so write the rule down.

Can appearance search replace plate reading?

No. Appearance search finds similar-looking vehicles, and many cars look alike. It's best used to bridge gaps between confident plate sightings at nearby cameras, then filtered by travel-time checks and confirmed by a person. Treat each appearance match as a lead to verify, never as an identification.

Need plate recognition on cameras you already run? See our ANPR software page or our wider computer vision development work, and tell us about your camera network.