Automatic License Number Plate Recognition System

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 11

Automatic License Number Plate

Recognition System
Project idea: The objective of this machine learning project is to detect and
recognize the license number plate of a vehicle and read the license
numbers printed on the plate. This could be a good application for security
scans, traffic monitoring, etc.

Automatic License Number Plate


Recognition

OpenCV is an open-source machine learning library and provides a common


infrastructure for computer vision. Whereas Pytesseract is a Tesseract-OCR Engine
to read image types and extract the information present in the image.
Install OpenCV and Pytesseract pip3 python
package:
pip3 install opencv-python

pip3 install pytesseract

In this python project, to identify the number plate in the input image, we will use
following features of openCV:

 Gaussian Blur: Here we use a Gaussian kernel to smoothen the image. This


technique is highly effective to remove Gaussian noise. OpenCV provides a
cv2.GaussianBlur() function for this task.
 Sobel: Here we calculate the derivatives from the image. This feature is
important for many computer vision tasks. Using derivatives we calculate the
gradients, and a high change in gradient indicates a major change in the image.
OpenCV provides a cv2.Sobel() function to calculate Sobel operators.
 Morphological Transformation: These are the operations based on image
shapes and are performed on binary images. The basic morphological
operations are Erosion, Dilation, Opening, Closing. The different functions
provided in OpenCV are:
 cv2.erode()
 cv2.dilate()
 cv2.morphologyEx()
 Contours: Contours are the curves containing all the continuous points of same
intensity. These are very useful tools for object recognition. OpenCV provides
cv2.findContours() functions for this feature.

Now, let’s dive into the number plate recognition code. Follow the steps below:

1. Imports:

For this project we need numpy and pillow python libraries with openCV and
pytesseract

import numpy as np

import cv2
from PIL import Image

import pytesseract as tess

2. Now we will define three functions, to find the unnecessary contours that
openCV may identify but it does not have probability of being a number plate.

2.1. The first function to check the area range and width-height ratio:

def ratioCheck(area, width, height):

ratio = float(width) / float(height)

if ratio < 1:

ratio = 1 / ratio

if (area < 1063.62 or area > 73862.5) or (ratio < 3 or ratio > 6):

return False

return True

2.2. The second function to check average of image matrix:

def isMaxWhite(plate):

avg = np.mean(plate)

if(avg>=115):

return True

else:

return False

2.3. The third function to check the rotation of contours:

def ratio_and_rotation(rect):

(x, y), (width, height), rect_angle = rect

if(width>height):

angle = -rect_angle

else:

angle = 90 + rect_angle
if angle>15:

return False

if height == 0 or width == 0:

return False

area = height*width

if not ratioCheck(area,width,height):

return False

else:

return True

3. Now we will write a function to clean the identified number plate for
preprocessing before feeding to pytesseract:

def clean2_plate(plate):

gray_img = cv2.cvtColor(plate, cv2.COLOR_BGR2GRAY)

_, thresh = cv2.threshold(gray_img, 110, 255, cv2.THRESH_BINARY)

if cv2.waitKey(0) & 0xff == ord('q'):

pass

num_contours,hierarchy = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_NONE)

if num_contours:

contour_area = [cv2.contourArea(c) for c in num_contours]

max_cntr_index = np.argmax(contour_area)

max_cnt = num_contours[max_cntr_index]

max_cntArea = contour_area[max_cntr_index]

x,y,w,h = cv2.boundingRect(max_cnt)

if not ratioCheck(max_cntArea,w,h):

return plate,None

final_img = thresh[y:y+h, x:x+w]


return final_img,[x,y,w,h]

else:

return plate, None

4. In this step, we will take an image input. We will perform Gaussian Blur, Sobel
and morphological operations. After we find contours in the image and loop
through each contour to identify the number plate. We will then clean the image
contour and feed it to pytesseract to recognize the number and characters.

img = cv2.imread("testData/sample15.jpg")

print("Number input image...",)

cv2.imshow("input",img)

if cv2.waitKey(0) & 0xff == ord('q'):

pass

img2 = cv2.GaussianBlur(img, (3,3), 0)

img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

img2 = cv2.Sobel(img2,cv2.CV_8U,1,0,ksize=3)

_,img2 = cv2.threshold(img2,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

element = cv2.getStructuringElement(shape=cv2.MORPH_RECT, ksize=(17, 3))

morph_img_threshold = img2.copy()

cv2.morphologyEx(src=img2, op=cv2.MORPH_CLOSE, kernel=element, dst=morph_img_threshold)

num_contours, hierarchy=
cv2.findContours(morph_img_threshold,mode=cv2.RETR_EXTERNAL,method=cv2.CHAIN_APPROX_NON
E)

cv2.drawContours(img2, num_contours, -1, (0,255,0), 1)

for i,cnt in enumerate(num_contours):

min_rect = cv2.minAreaRect(cnt)

if ratio_and_rotation(min_rect):

x,y,w,h = cv2.boundingRect(cnt)

plate_img = img[y:y+h,x:x+w]
print("Number identified number plate...")

cv2.imshow("num plate image",plate_img)

if cv2.waitKey(0) & 0xff == ord('q'):

pass

if(isMaxWhite(plate_img)):

clean_plate, rect = clean2_plate(plate_img)

if rect:

fg=0

x1,y1,w1,h1 = rect

x,y,w,h = x+x1,y+y1,w1,h1

# cv2.imwrite("clena.png",clean_plate)

plate_im = Image.fromarray(clean_plate)

text = tess.image_to_string(plate_im, lang='eng')

print("Number Detected Plate Text : ",text)

Code for Project GUI


Make a new file gui.py and paste the below code:

import tkinter as tk

from tkinter import filedialog

from tkinter import *

from PIL import ImageTk, Image

from tkinter import PhotoImage

import numpy as np

import cv2

import pytesseract as tess

def clean2_plate(plate):

gray_img = cv2.cvtColor(plate, cv2.COLOR_BGR2GRAY)


_, thresh = cv2.threshold(gray_img, 110, 255, cv2.THRESH_BINARY)

num_contours,hierarchy = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_NONE)

if num_contours:

contour_area = [cv2.contourArea(c) for c in num_contours]

max_cntr_index = np.argmax(contour_area)

max_cnt = num_contours[max_cntr_index]

max_cntArea = contour_area[max_cntr_index]

x,y,w,h = cv2.boundingRect(max_cnt)

if not ratioCheck(max_cntArea,w,h):

return plate,None

final_img = thresh[y:y+h, x:x+w]

return final_img,[x,y,w,h]

else:

return plate,None

def ratioCheck(area, width, height):

ratio = float(width) / float(height)

if ratio < 1:

ratio = 1 / ratio

if (area < 1063.62 or area > 73862.5) or (ratio < 3 or ratio > 6):

return False

return True

def isMaxWhite(plate):

avg = np.mean(plate)

if(avg>=115):

return True

else:
return False

def ratio_and_rotation(rect):

(x, y), (width, height), rect_angle = rect

if(width>height):

angle = -rect_angle

else:

angle = 90 + rect_angle

if angle>15:

return False

if height == 0 or width == 0:

return False

area = height*width

if not ratioCheck(area,width,height):

return False

else:

return True

top=tk.Tk()

top.geometry('900x700')

top.title('Number Plate Recognition')

top.iconphoto(True, PhotoImage(file="/home/shivam/Dataflair/Keras Projects_CIFAR/GUI/logo.png"))

img = ImageTk.PhotoImage(Image.open("logo.png"))

top.configure(background='#CDCDCD')

label=Label(top,background='#CDCDCD', font=('arial',35,'bold'))

# label.grid(row=0,column=1)

sign_image = Label(top,bd=10)

plate_image=Label(top,bd=10)

def classify(file_path):
res_text=[0]

res_img=[0]

img = cv2.imread(file_path)

img2 = cv2.GaussianBlur(img, (3,3), 0)

img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

img2 = cv2.Sobel(img2,cv2.CV_8U,1,0,ksize=3)

_,img2 = cv2.threshold(img2,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

element = cv2.getStructuringElement(shape=cv2.MORPH_RECT, ksize=(17, 3))

morph_img_threshold = img2.copy()

cv2.morphologyEx(src=img2, op=cv2.MORPH_CLOSE, kernel=element, dst=morph_img_threshold)

num_contours, hierarchy=
cv2.findContours(morph_img_threshold,mode=cv2.RETR_EXTERNAL,method=cv2.CHAIN_APPROX_NON
E)

cv2.drawContours(img2, num_contours, -1, (0,255,0), 1)

for i,cnt in enumerate(num_contours):

min_rect = cv2.minAreaRect(cnt)

if ratio_and_rotation(min_rect):

x,y,w,h = cv2.boundingRect(cnt)

plate_img = img[y:y+h,x:x+w]

print("Number identified number plate...")

res_img[0]=plate_img

cv2.imwrite("result.png",plate_img)

if(isMaxWhite(plate_img)):

clean_plate, rect = clean2_plate(plate_img)

if rect:

fg=0

x1,y1,w1,h1 = rect
x,y,w,h = x+x1,y+y1,w1,h1

plate_im = Image.fromarray(clean_plate)

text = tess.image_to_string(plate_im, lang='eng')

res_text[0]=text

if text:

break

label.configure(foreground='#011638', text=res_text[0])

uploaded=Image.open("result.png")

im=ImageTk.PhotoImage(uploaded)

plate_image.configure(image=im)

plate_image.image=im

plate_image.pack()

plate_image.place(x=560,y=320)

def show_classify_button(file_path):

classify_b=Button(top,text="Classify Image",command=lambda: classify(file_path),padx=10,pady=5)

classify_b.configure(background='#364156', foreground='white',font=('arial',15,'bold'))

classify_b.place(x=490,y=550)

def upload_image():

try:

file_path=filedialog.askopenfilename()

uploaded=Image.open(file_path)

uploaded.thumbnail(((top.winfo_width()/2.25),(top.winfo_height()/2.25)))

im=ImageTk.PhotoImage(uploaded)

sign_image.configure(image=im)

sign_image.image=im

label.configure(text='')

show_classify_button(file_path)
except:

pass

upload=Button(top,text="Upload an image",command=upload_image,padx=10,pady=5)

upload.configure(background='#364156', foreground='white',font=('arial',15,'bold'))

upload.pack()

upload.place(x=210,y=550)

sign_image.pack()

sign_image.place(x=70,y=200)

label.pack()

label.place(x=500,y=220)

heading = Label(top,image=img)

heading.configure(background='#CDCDCD',foreground='#364156')

heading.pack()

top.mainloop()

Summary
In this article, we have developed a deep learning project to recognize license
number plate. We discussed some important features of openCV like Gaussian
blur, Sobel operators, Morphological transformations. The application detects
number plate text from an image. We have identified and cleaned the number plate
using openCV. To identify the number plate digits and characters we used
pytesseract.
:

You might also like