Spaces:
Sleeping
Sleeping
import matplotlib.pyplot as plt | |
import numpy as np | |
import cv2 | |
import tensorflow as tf | |
from sklearn.metrics import f1_score | |
from tensorflow.keras import optimizers | |
from tensorflow.keras.models import Sequential | |
from tensorflow.keras.preprocessing.image import ImageDataGenerator | |
from tensorflow.keras.layers import Dense, Flatten, MaxPooling2D, Dropout, Conv2D | |
import streamlit as st | |
# Loads the data required for detecting the license plates from cascade classifier. | |
plate_cascade = cv2.CascadeClassifier('../input/ai-indian-license-plate-recognition-data/indian_license_plate.xml') | |
# add the path to 'india_license_plate.xml' file. | |
model = load_model('.h5', compile=False) | |
def detect_plate(img, text=''): # the function detects and perfors blurring on the number plate. | |
plate_img = img.copy() | |
roi = img.copy() | |
plate_rect = plate_cascade.detectMultiScale(plate_img, scaleFactor = 1.2, minNeighbors = 7) # detects numberplates and returns the coordinates and dimensions of detected license plate's contours. | |
for (x,y,w,h) in plate_rect: | |
roi_ = roi[y:y+h, x:x+w, :] # extracting the Region of Interest of license plate for blurring. | |
plate = roi[y:y+h, x:x+w, :] | |
cv2.rectangle(plate_img, (x+2,y), (x+w-3, y+h-5), (51,181,155), 3) # finally representing the detected contours by drawing rectangles around the edges. | |
if text!='': | |
plate_img = cv2.putText(plate_img, text, (x-w//2,y-h//2), | |
cv2.FONT_HERSHEY_COMPLEX_SMALL , 0.5, (51,181,155), 1, cv2.LINE_AA) | |
return plate_img, plate # returning the processed image. | |
# Testing the above function | |
def display(img_, title=''): | |
img = cv2.cvtColor(img_, cv2.COLOR_BGR2RGB) | |
fig = plt.figure(figsize=(10,6)) | |
ax = plt.subplot(111) | |
ax.imshow(img) | |
plt.axis('off') | |
plt.title(title) | |
plt.show() | |
# img = cv2.imread('../input/ai-indian-license-plate-recognition-data/car.jpg') | |
display(img, 'input image') | |
# Getting plate prom the processed image | |
output_img, plate = detect_plate(img) | |
display(output_img, 'detected license plate in the input image') | |
display(plate, 'extracted license plate from the image') | |
# Match contours to license plate or character template | |
def find_contours(dimensions, img) : | |
# Find all contours in the image | |
cntrs, _ = cv2.findContours(img.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) | |
# Retrieve potential dimensions | |
lower_width = dimensions[0] | |
upper_width = dimensions[1] | |
lower_height = dimensions[2] | |
upper_height = dimensions[3] | |
# Check largest 5 or 15 contours for license plate or character respectively | |
cntrs = sorted(cntrs, key=cv2.contourArea, reverse=True)[:15] | |
ii = cv2.imread('contour.jpg') | |
x_cntr_list = [] | |
target_contours = [] | |
img_res = [] | |
for cntr in cntrs : | |
# detects contour in binary image and returns the coordinates of rectangle enclosing it | |
intX, intY, intWidth, intHeight = cv2.boundingRect(cntr) | |
# checking the dimensions of the contour to filter out the characters by contour's size | |
if intWidth > lower_width and intWidth < upper_width and intHeight > lower_height and intHeight < upper_height : | |
x_cntr_list.append(intX) #stores the x coordinate of the character's contour, to used later for indexing the contours | |
char_copy = np.zeros((44,24)) | |
# extracting each character using the enclosing rectangle's coordinates. | |
char = img[intY:intY+intHeight, intX:intX+intWidth] | |
char = cv2.resize(char, (20, 40)) | |
cv2.rectangle(ii, (intX,intY), (intWidth+intX, intY+intHeight), (50,21,200), 2) | |
plt.imshow(ii, cmap='gray') | |
# Make result formatted for classification: invert colors | |
char = cv2.subtract(255, char) | |
# Resize the image to 24x44 with black border | |
char_copy[2:42, 2:22] = char | |
char_copy[0:2, :] = 0 | |
char_copy[:, 0:2] = 0 | |
char_copy[42:44, :] = 0 | |
char_copy[:, 22:24] = 0 | |
img_res.append(char_copy) # List that stores the character's binary image (unsorted) | |
# Return characters on ascending order with respect to the x-coordinate (most-left character first) | |
plt.show() | |
# arbitrary function that stores sorted list of character indeces | |
indices = sorted(range(len(x_cntr_list)), key=lambda k: x_cntr_list[k]) | |
img_res_copy = [] | |
for idx in indices: | |
img_res_copy.append(img_res[idx])# stores character images according to their index | |
img_res = np.array(img_res_copy) | |
return img_res | |
# Find characters in the resulting images | |
def segment_characters(image) : | |
# Preprocess cropped license plate image | |
img_lp = cv2.resize(image, (333, 75)) | |
img_gray_lp = cv2.cvtColor(img_lp, cv2.COLOR_BGR2GRAY) | |
_, img_binary_lp = cv2.threshold(img_gray_lp, 200, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) | |
img_binary_lp = cv2.erode(img_binary_lp, (3,3)) | |
img_binary_lp = cv2.dilate(img_binary_lp, (3,3)) | |
LP_WIDTH = img_binary_lp.shape[0] | |
LP_HEIGHT = img_binary_lp.shape[1] | |
# Make borders white | |
img_binary_lp[0:3,:] = 255 | |
img_binary_lp[:,0:3] = 255 | |
img_binary_lp[72:75,:] = 255 | |
img_binary_lp[:,330:333] = 255 | |
# Estimations of character contours sizes of cropped license plates | |
dimensions = [LP_WIDTH/6, | |
LP_WIDTH/2, | |
LP_HEIGHT/10, | |
2*LP_HEIGHT/3] | |
plt.imshow(img_binary_lp, cmap='gray') | |
plt.show() | |
cv2.imwrite('contour.jpg',img_binary_lp) | |
# Get contours within cropped license plate | |
char_list = find_contours(dimensions, img_binary_lp) | |
return char_list | |
# Let's see the segmented characters | |
char = segment_characters(plate) | |
for i in range(10): | |
plt.subplot(1, 10, i+1) | |
plt.imshow(char[i], cmap='gray') | |
plt.axis('off') | |
# Predicting the output | |
def fix_dimension(img): | |
new_img = np.zeros((28,28,3)) | |
for i in range(3): | |
new_img[:,:,i] = img | |
return new_img | |
def show_results(): | |
dic = {} | |
characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' | |
for i,c in enumerate(characters): | |
dic[i] = c | |
output = [] | |
for i,ch in enumerate(char): #iterating over the characters | |
img_ = cv2.resize(ch, (28,28), interpolation=cv2.INTER_AREA) | |
img = fix_dimension(img_) | |
img = img.reshape(1,28,28,3) #preparing image for the model | |
y_ = model.predict_classes(img)[0] #predicting the class | |
character = dic[y_] # | |
output.append(character) #storing the result in a list | |
plate_number = ''.join(output) | |
return plate_number | |
print(show_results()) | |