Author: Raj Aryan | Published: May 05, 2025
In this blog, I'll walk you through how I developed a Number Plate Detection System using Python and OpenCV. This system is capable of automatically detecting vehicle number plates from images or video streams, extracting the plate region, and preparing it for further recognition or OCR processing.
In recent years, the integration of computer vision technologies with everyday applications has led to
significant advancements in various fields, ranging from surveillance and security to transportation and
automation. One such application is the development of a Number Plate Recognition System, which employs a
combination of image processing techniques and optical character recognition (OCR) to automatically identify and
recognize number plates in real-time video streams. This system holds immense potential for enhancing traffic
management, law enforcement, and parking systems by providing efficient and accurate vehicle identification
capabilities.
Key components of the Number Plate Recognition System include a Haar cascade classifier for number plate
detection, Tesseract OCR for character recognition, and MongoDB for storing and managing vehicle information.
The system architecture is designed to facilitate real-time processing of video streams, ensuring prompt
identification of vehicles as they pass through the monitored area. Additionally, a user-friendly web interface
built with Flask framework allows for functionalities such as adding new vehicles to the database and viewing
recognized plate records.
This project aims to address several challenges associated with Number plate recognition, including variations
in plate appearance due to factors such as lighting conditions, viewing angle, and occlusions. Advanced image
processing techniques are employed to enhance the robustness and accuracy of plate detection and character
recognition, thereby improving the overall performance of the system. Furthermore, the integration of user
authentication mechanisms ensures secure access to system functionalities, preventing unauthorized users from
tampering with the database or system settings.
Install all the libraries and required dependencies.
import os
from unittest import result
import cv2
from datetime import datetime, timedelta, timezone
import pytesseract
import requests
from PIL import Image
from flask import Flask, jsonify, redirect, render_template, Response, request, session, url_for
import threading
from pymongo import MongoClient
The application connects to a MongoDB database. MongoDB Atlas is used for cloud-hosted MongoDB, allowing easy scaling and management.
client = MongoClient("<mongodb server url>")
db = client['vehicle_database']
vehicles_collection = db['vehicle']
history_collection = db['history']
def load_vehicle_database():
database = {}
vehicles_collection = db['vehicle']
for vehicle in vehicles_collection.find():
plate_number = vehicle['plate_number']
database[plate_number] = {
"owner_name": vehicle['owner_name'],
"make": vehicle['make'],
"model": vehicle['model'],
"color": vehicle['color']
}
print("Vehicle database loaded successfully.")
return database
vehicle_database = load_vehicle_database()
This function queries all vehicle records from MongoDB and stores them in a dictionary where the plate number is the
key.
The process_videofunction captures video frames from the camera, detects license plates using OpenCV, and performs OCR using Tesseract to recognize the plate numbers.
plate_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_russian_plate_number.xml')
# for ubuntu
pytesseract.pytesseract.tesseract_cmd = r'/usr/bin/tesseract'
# for windows paste the path where it is installed
def perform_ocr(img):
custom_config = r'--oem 3 --psm 6'
plate_number = pytesseract.image_to_string(img, config=custom_config)
return plate_number.strip()
def process_video():
cap = cv2.VideoCapture(-1)
while True:
ret, frame = cap.read()
if not ret:
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
plates = plate_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
for (x, y, w, h) in plates:
plate_roi = frame[y:y + h, x:x + w]
pil_image = Image.fromarray(cv2.cvtColor(plate_roi, cv2.COLOR_BGR2RGB))
plate_number = perform_ocr(pil_image)
if plate_number in vehicle_database:
vehicle_info = vehicle_database[plate_number]
if plate_number not in [plate['plate_number'] for plate in recognized_plates]:
timestamp = datetime.now()
recognized_plates.append({
"plate_number": plate_number,
"owner_name": vehicle_info['owner_name'],
"make": vehicle_info['make'],
"model": vehicle_info['model'],
"color": vehicle_info['color'],
"timestamp": timestamp
})
history_collection.insert_one({
"plate_number": plate_number,
"owner_name": vehicle_info['owner_name'],
"make": vehicle_info['make'],
"model": vehicle_info['model'],
"color": vehicle_info['color'],
"timestamp": timestamp
})
info_text = f"Owner: {vehicle_info['owner_name']}, Make: {vehicle_info['make']}, Model: {vehicle_info['model']}, Color: {vehicle_info['color']}"
cv2.putText(frame, info_text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
ret, jpeg = cv2.imencode('.jpg', frame)
frame_bytes = jpeg.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n\r\n')
cap.release()
@app.route('/video_feed')
def video_feed():
return Response(process_video(), mimetype='multipart/x-mixed-replace; boundary=frame')
The video_feed route returns a video stream using the process_video generator
function.
Basic user authentication is implemented to restrict access to certain routes. The login system uses Flask's session management to keep track of logged-in users.
@app.route('/add_vehicle', methods=['POST'])
def add_vehicle():
if 'logged_in' not in session:
return redirect(url_for('login'))
plate_number = request.form['plate_number']
owner_name = request.form['owner_name']
make = request.form['make']
model = request.form['model']
color = request.form['color']
vehicles_collection.insert_one({
"plate_number": plate_number,
"owner_name": owner_name,
"make": make,
"model": model,
"color": color
})
return redirect(url_for('index'))
app.route('/recognized_plates')
def recognized_plates_page():
return render_template('recognized_plates.html', recognized_plates=recognized_plates)
The application provides a dashboard to display recognized plates and vehicle records.
@app.route('/index')
def index():
try:
past_24_hours = datetime.now() - timedelta(hours=24)
data = history_collection.find({"timestamp": {"$gte": past_24_hours}})
return render_template('index.html', data=data)
except Exception as e:
app.logger.error(f"An error occurred while fetching data from the database: {e}")
return "An error occurred while fetching data from the database. Please check the logsfor more information."
@app.route('/records')
def records():
try:
database = {}
records_collection = db['vehicle']
database = records_collection.find()
app.logger.info("Records fetched successfully")
return render_template('records.html', rec=database)
except Exception as e:
app.logger.error(f"An error occurred while fetching records from the database: {e}")
return "An error occurred while fetching records from the database. Please check the logs for more information."
The Flask application is started, and video processing is run in a separate thread to avoid blocking the main thread.
def run_video_processing():
with app.app_context():
app.video_thread = threading.Thread(target=process_video)
app.video_thread.start()
if __name__ == '__main__':
run_video_processing()
app.run(debug=True)
The run_video_processing function initializes and starts the video processing thread,
ensuring the application remains responsive while processing video frames.
This number plate detection system integrates real-time video processing with a web-based interface, leveraging OpenCV, Tesseract OCR, and MongoDB. It demonstrates the practical application of computer vision and web technologies for automated license plate recognition and vehicle management.
Full Code: GitHub