Building a license plate recognition system using Python and OpenCV in India is one of the most rewarding computer vision projects you can tackle. Whether you are working on a smart parking system, a vehicle entry gate, or a traffic monitoring solution, automatic number plate recognition (ANPR) is both practical and highly sought after. In this guide, we walk through the complete project — hardware selection, OpenCV pipeline, OCR integration, and tips specific to Indian number plates.
Why Build ANPR for India?
India has over 300 million registered vehicles and that number grows every year. Smart parking lots, residential societies, toll booths, and factory gates all need automated vehicle identification. The Indian number plate follows the BH series (Bharat series) and the older state-based format (e.g., MH 12 AB 1234). Unlike Western plates, Indian plates often have yellow background (commercial), white background (private), green background (electric), or black text on yellow (taxis) — adding colour-based detection as an extra tool in your pipeline.
A Python + OpenCV ANPR system running on a Raspberry Pi 5 or a laptop with a USB camera can handle 95%+ accuracy under good lighting conditions. With a higher-resolution camera and GPU-based inference (NVIDIA Jetson), accuracy approaches near-perfect for stationary or slow-moving vehicles.
Hardware Requirements
You need a compute platform, a camera, and optionally a display or network output. Here are the recommended components available in India:
Raspberry Pi 5 Model 4GB RAM
The ideal compute platform for real-time OpenCV processing. The Pi 5’s faster CPU dramatically reduces inference time compared to Pi 4, handling 720p video at 10+ FPS comfortably.
Arducam 12MP IMX477 Pan Tilt Zoom IR-Cut Camera
12 megapixel resolution with pan-tilt-zoom gives you the flexibility to capture plates at distance. The IR-cut filter enables both day and night operation — essential for 24×7 gate deployments.
1/4 CMOS 640×480 USB Camera with Collapsible Cable for Raspberry Pi
A budget-friendly USB camera for prototype builds. Works plug-and-play with OpenCV’s VideoCapture. Good for indoor or close-range (under 3 m) plate detection experiments.
OpenCV Detection Pipeline
The classic ANPR pipeline in OpenCV consists of these stages:
- Frame Capture — Grab a frame from the camera using
cv2.VideoCapture(). - Preprocessing — Convert to grayscale, apply Gaussian blur, then edge detection (Canny).
- Contour Detection — Find rectangular contours that match the aspect ratio of Indian plates (~4.5:1 for standard plates, ~2:1 for high-security plates).
- Perspective Transform — Warp the detected region to a flat rectangle using
cv2.getPerspectiveTransform(). - Thresholding — Apply Otsu’s thresholding or adaptive thresholding to binarise the plate.
- Character Segmentation — Either use contour-based segmentation or feed the binarised plate directly to an OCR engine.
- OCR — Extract text using Tesseract or EasyOCR.
Install the required libraries:
pip install opencv-python imutils pytesseract easyocr numpy
On Raspberry Pi OS, also install Tesseract:
sudo apt install tesseract-ocr
OCR with Tesseract and EasyOCR
Tesseract is the go-to choice for simple pipelines. Configure it with --psm 7 (single text line) and a whitelist of characters typical in Indian plates:
import pytesseract
config = r'--oem 3 --psm 7 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
text = pytesseract.image_to_string(plate_img, config=config)
EasyOCR is a newer deep-learning based alternative that often outperforms Tesseract on messy or partially occluded plates. It supports Hindi characters too, useful for state codes:
import easyocr
reader = easyocr.Reader(['en'])
result = reader.readtext(plate_img, detail=0)
For best results, combine both: use EasyOCR as the primary engine and fall back to Tesseract if EasyOCR confidence is below 0.7.
Challenges Specific to Indian Number Plates
Indian plates present unique challenges that Western ANPR tutorials do not address:
- Dual-line plates: High-security registration plates (HSRP) sometimes split state code and number across two lines.
- Colour variety: White, yellow, green, and black backgrounds mean you cannot rely on a single threshold value. Use adaptive thresholding or HSV-based masking.
- Dirt and damage: Indian roads and weather conditions mean plates are frequently dirty. Morphological operations (dilation + erosion) help reconnect broken characters.
- Font variation: Older plates use hand-painted fonts. Train a custom Tesseract LSTM model on Indian plate fonts for better accuracy.
- Stickers and decorations: Religious stickers and dealer frames can obscure part of the plate. Use a confidence threshold and flag ambiguous readings for human review.
- Night conditions: Use an IR illuminator alongside a night-vision capable camera for 24-hour operation.
Complete Python Code
Below is a complete, well-commented Python script for Indian ANPR:
import cv2
import pytesseract
import re
import numpy as np
INDIAN_PLATE_REGEX = re.compile(
r'^[A-Z]{2}[0-9]{1,2}[A-Z]{1,3}[0-9]{4}$|^BH[0-9]{4}[A-Z]{1,2}[0-9]{1,2}$'
)
def preprocess(frame):
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.Canny(blur, 50, 200)
return edges
def find_plate_contour(edges, frame):
contours, _ = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:20]
for cnt in contours:
peri = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.018 * peri, True)
if len(approx) == 4:
x, y, w, h = cv2.boundingRect(approx)
aspect = w / float(h)
if 2.0 < aspect < 6.5:
return frame[y:y+h, x:x+w]
return None
def read_plate(roi):
gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
config = r'--oem 3 --psm 7 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
text = pytesseract.image_to_string(thresh, config=config).strip().replace(' ', '')
return text
def validate(text):
return bool(INDIAN_PLATE_REGEX.match(text))
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
edges = preprocess(frame)
roi = find_plate_contour(edges, frame)
if roi is not None:
plate_text = read_plate(roi)
if validate(plate_text):
print(f'Detected: {plate_text}')
cv2.putText(frame, plate_text, (30, 50),
cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 255, 0), 3)
cv2.imshow('ANPR', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Deploying the System
Once your prototype works on a laptop, move it to a production board. For indoor deployments (parking lots, society gates), the Raspberry Pi 5 with 4GB RAM is sufficient. For outdoor, high-traffic deployments requiring simultaneous multiple-lane detection, consider the NVIDIA Jetson Nano or Jetson Orin with a YOLOv8 plate detector replacing the contour pipeline — accuracy jumps dramatically and real-time processing at 30 FPS becomes feasible.
Integrate the detected plate text with a SQLite or MySQL database to log entry/exit times. Use Flask or FastAPI to create a web dashboard accessible over your local network. Add a relay module controlled via GPIO to open a barrier gate automatically upon plate match.
Power the outdoor unit with a weatherproof enclosure and a UPS-backed power supply. For remote sites, an LTE modem with a SIM card allows cloud sync of the plate log.
Raspberry Pi 5 Model 16GB RAM
For high-throughput deployments running multiple camera streams simultaneously, the 16GB Pi 5 handles heavier OpenCV workloads and can run EasyOCR without thrashing memory.
Arducam 5MP 1080p Pan Tilt Zoom PTZ Camera for Raspberry Pi
Full 1080p resolution with motorised pan-tilt-zoom, perfect for monitoring entry lanes where vehicles stop at varying distances from the camera.
Frequently Asked Questions
What accuracy can I expect with Python + OpenCV ANPR on Indian plates?
Under controlled lighting (well-lit, stationary vehicle, clean plate) you can achieve 90–95% accuracy with the Tesseract-based pipeline. EasyOCR pushes this to 95–98%. For moving vehicles or poor lighting, accuracy drops to 70–80% without additional preprocessing or a dedicated YOLO-based detector.
Do I need a GPU for license plate recognition in Python?
No, a CPU-based setup on Raspberry Pi 5 works fine for single-lane, controlled environments. A GPU (Jetson Nano or a PC with NVIDIA card) is needed only for high-speed (>30 km/h) or multi-lane detection in real time.
Is it legal to build an ANPR system in India?
For private premises (your society gate, factory, parking lot) it is legal. Public road surveillance requires government authorisation. Always ensure data privacy compliance and do not share plate logs publicly.
What is the HSRP format in India?
High Security Registration Plates (HSRP) follow the format: State Code (2 letters) + District Code (2 digits) + Series (1–3 letters) + Number (4 digits). The BH (Bharat) series uses: BH + Year (2 digits) + Number (4 digits) + Category (2 letters).
Can I run the project on a Raspberry Pi Zero?
The Pi Zero W is too slow for real-time OpenCV (it processes roughly 1–2 FPS). Use it only for snapshot-based detection (capture a frame every few seconds). For real-time, use at minimum a Raspberry Pi 4 or preferably a Pi 5.
Ready to start your license plate recognition Python OpenCV India project? Grab a Raspberry Pi 5 and a high-quality camera from Zbotic and follow this guide step by step. The combination of OpenCV’s contour detection and EasyOCR’s deep-learning engine gives you a robust, locally running ANPR system without any cloud dependency — ideal for privacy-sensitive deployments in Indian homes, societies, and businesses.
Add comment