Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,216 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import matplotlib.pyplot as plt
|
2 |
+
import numpy as np
|
3 |
+
import cv2
|
4 |
+
import tensorflow as tf
|
5 |
+
from sklearn.metrics import f1_score
|
6 |
+
from tensorflow.keras import optimizers
|
7 |
+
from tensorflow.keras.models import Sequential
|
8 |
+
from tensorflow.keras.preprocessing.image import ImageDataGenerator
|
9 |
+
from tensorflow.keras.layers import Dense, Flatten, MaxPooling2D, Dropout, Conv2D
|
10 |
+
import streamlit as st
|
11 |
+
|
12 |
+
|
13 |
+
# Loads the data required for detecting the license plates from cascade classifier.
|
14 |
+
plate_cascade = cv2.CascadeClassifier('../input/ai-indian-license-plate-recognition-data/indian_license_plate.xml')
|
15 |
+
# add the path to 'india_license_plate.xml' file.
|
16 |
+
|
17 |
+
|
18 |
+
|
19 |
+
model = load_model('.h5', compile=False)
|
20 |
+
|
21 |
+
|
22 |
+
|
23 |
+
|
24 |
+
|
25 |
+
|
26 |
+
|
27 |
+
def detect_plate(img, text=''): # the function detects and perfors blurring on the number plate.
|
28 |
+
plate_img = img.copy()
|
29 |
+
roi = img.copy()
|
30 |
+
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.
|
31 |
+
for (x,y,w,h) in plate_rect:
|
32 |
+
roi_ = roi[y:y+h, x:x+w, :] # extracting the Region of Interest of license plate for blurring.
|
33 |
+
plate = roi[y:y+h, x:x+w, :]
|
34 |
+
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.
|
35 |
+
if text!='':
|
36 |
+
plate_img = cv2.putText(plate_img, text, (x-w//2,y-h//2),
|
37 |
+
cv2.FONT_HERSHEY_COMPLEX_SMALL , 0.5, (51,181,155), 1, cv2.LINE_AA)
|
38 |
+
|
39 |
+
return plate_img, plate # returning the processed image.
|
40 |
+
|
41 |
+
|
42 |
+
|
43 |
+
|
44 |
+
# Testing the above function
|
45 |
+
def display(img_, title=''):
|
46 |
+
img = cv2.cvtColor(img_, cv2.COLOR_BGR2RGB)
|
47 |
+
fig = plt.figure(figsize=(10,6))
|
48 |
+
ax = plt.subplot(111)
|
49 |
+
ax.imshow(img)
|
50 |
+
plt.axis('off')
|
51 |
+
plt.title(title)
|
52 |
+
plt.show()
|
53 |
+
|
54 |
+
# img = cv2.imread('../input/ai-indian-license-plate-recognition-data/car.jpg')
|
55 |
+
display(img, 'input image')
|
56 |
+
|
57 |
+
|
58 |
+
|
59 |
+
# Getting plate prom the processed image
|
60 |
+
output_img, plate = detect_plate(img)
|
61 |
+
|
62 |
+
|
63 |
+
|
64 |
+
display(output_img, 'detected license plate in the input image')
|
65 |
+
|
66 |
+
|
67 |
+
|
68 |
+
display(plate, 'extracted license plate from the image')
|
69 |
+
|
70 |
+
|
71 |
+
|
72 |
+
|
73 |
+
# Match contours to license plate or character template
|
74 |
+
def find_contours(dimensions, img) :
|
75 |
+
|
76 |
+
# Find all contours in the image
|
77 |
+
cntrs, _ = cv2.findContours(img.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
|
78 |
+
|
79 |
+
# Retrieve potential dimensions
|
80 |
+
lower_width = dimensions[0]
|
81 |
+
upper_width = dimensions[1]
|
82 |
+
lower_height = dimensions[2]
|
83 |
+
upper_height = dimensions[3]
|
84 |
+
|
85 |
+
# Check largest 5 or 15 contours for license plate or character respectively
|
86 |
+
cntrs = sorted(cntrs, key=cv2.contourArea, reverse=True)[:15]
|
87 |
+
|
88 |
+
ii = cv2.imread('contour.jpg')
|
89 |
+
|
90 |
+
x_cntr_list = []
|
91 |
+
target_contours = []
|
92 |
+
img_res = []
|
93 |
+
for cntr in cntrs :
|
94 |
+
# detects contour in binary image and returns the coordinates of rectangle enclosing it
|
95 |
+
intX, intY, intWidth, intHeight = cv2.boundingRect(cntr)
|
96 |
+
|
97 |
+
# checking the dimensions of the contour to filter out the characters by contour's size
|
98 |
+
if intWidth > lower_width and intWidth < upper_width and intHeight > lower_height and intHeight < upper_height :
|
99 |
+
x_cntr_list.append(intX) #stores the x coordinate of the character's contour, to used later for indexing the contours
|
100 |
+
|
101 |
+
char_copy = np.zeros((44,24))
|
102 |
+
# extracting each character using the enclosing rectangle's coordinates.
|
103 |
+
char = img[intY:intY+intHeight, intX:intX+intWidth]
|
104 |
+
char = cv2.resize(char, (20, 40))
|
105 |
+
|
106 |
+
cv2.rectangle(ii, (intX,intY), (intWidth+intX, intY+intHeight), (50,21,200), 2)
|
107 |
+
plt.imshow(ii, cmap='gray')
|
108 |
+
|
109 |
+
# Make result formatted for classification: invert colors
|
110 |
+
char = cv2.subtract(255, char)
|
111 |
+
|
112 |
+
# Resize the image to 24x44 with black border
|
113 |
+
char_copy[2:42, 2:22] = char
|
114 |
+
char_copy[0:2, :] = 0
|
115 |
+
char_copy[:, 0:2] = 0
|
116 |
+
char_copy[42:44, :] = 0
|
117 |
+
char_copy[:, 22:24] = 0
|
118 |
+
|
119 |
+
img_res.append(char_copy) # List that stores the character's binary image (unsorted)
|
120 |
+
|
121 |
+
# Return characters on ascending order with respect to the x-coordinate (most-left character first)
|
122 |
+
|
123 |
+
plt.show()
|
124 |
+
# arbitrary function that stores sorted list of character indeces
|
125 |
+
indices = sorted(range(len(x_cntr_list)), key=lambda k: x_cntr_list[k])
|
126 |
+
img_res_copy = []
|
127 |
+
for idx in indices:
|
128 |
+
img_res_copy.append(img_res[idx])# stores character images according to their index
|
129 |
+
img_res = np.array(img_res_copy)
|
130 |
+
|
131 |
+
return img_res
|
132 |
+
|
133 |
+
|
134 |
+
|
135 |
+
|
136 |
+
|
137 |
+
# Find characters in the resulting images
|
138 |
+
def segment_characters(image) :
|
139 |
+
|
140 |
+
# Preprocess cropped license plate image
|
141 |
+
img_lp = cv2.resize(image, (333, 75))
|
142 |
+
img_gray_lp = cv2.cvtColor(img_lp, cv2.COLOR_BGR2GRAY)
|
143 |
+
_, img_binary_lp = cv2.threshold(img_gray_lp, 200, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
|
144 |
+
img_binary_lp = cv2.erode(img_binary_lp, (3,3))
|
145 |
+
img_binary_lp = cv2.dilate(img_binary_lp, (3,3))
|
146 |
+
|
147 |
+
LP_WIDTH = img_binary_lp.shape[0]
|
148 |
+
LP_HEIGHT = img_binary_lp.shape[1]
|
149 |
+
|
150 |
+
# Make borders white
|
151 |
+
img_binary_lp[0:3,:] = 255
|
152 |
+
img_binary_lp[:,0:3] = 255
|
153 |
+
img_binary_lp[72:75,:] = 255
|
154 |
+
img_binary_lp[:,330:333] = 255
|
155 |
+
|
156 |
+
# Estimations of character contours sizes of cropped license plates
|
157 |
+
dimensions = [LP_WIDTH/6,
|
158 |
+
LP_WIDTH/2,
|
159 |
+
LP_HEIGHT/10,
|
160 |
+
2*LP_HEIGHT/3]
|
161 |
+
plt.imshow(img_binary_lp, cmap='gray')
|
162 |
+
plt.show()
|
163 |
+
cv2.imwrite('contour.jpg',img_binary_lp)
|
164 |
+
|
165 |
+
# Get contours within cropped license plate
|
166 |
+
char_list = find_contours(dimensions, img_binary_lp)
|
167 |
+
|
168 |
+
return char_list
|
169 |
+
|
170 |
+
|
171 |
+
|
172 |
+
# Let's see the segmented characters
|
173 |
+
char = segment_characters(plate)
|
174 |
+
|
175 |
+
|
176 |
+
|
177 |
+
|
178 |
+
for i in range(10):
|
179 |
+
plt.subplot(1, 10, i+1)
|
180 |
+
plt.imshow(char[i], cmap='gray')
|
181 |
+
plt.axis('off')
|
182 |
+
|
183 |
+
|
184 |
+
|
185 |
+
|
186 |
+
|
187 |
+
# Predicting the output
|
188 |
+
def fix_dimension(img):
|
189 |
+
new_img = np.zeros((28,28,3))
|
190 |
+
for i in range(3):
|
191 |
+
new_img[:,:,i] = img
|
192 |
+
return new_img
|
193 |
+
|
194 |
+
def show_results():
|
195 |
+
dic = {}
|
196 |
+
characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
197 |
+
for i,c in enumerate(characters):
|
198 |
+
dic[i] = c
|
199 |
+
|
200 |
+
output = []
|
201 |
+
for i,ch in enumerate(char): #iterating over the characters
|
202 |
+
img_ = cv2.resize(ch, (28,28), interpolation=cv2.INTER_AREA)
|
203 |
+
img = fix_dimension(img_)
|
204 |
+
img = img.reshape(1,28,28,3) #preparing image for the model
|
205 |
+
y_ = model.predict_classes(img)[0] #predicting the class
|
206 |
+
character = dic[y_] #
|
207 |
+
output.append(character) #storing the result in a list
|
208 |
+
|
209 |
+
plate_number = ''.join(output)
|
210 |
+
|
211 |
+
return plate_number
|
212 |
+
|
213 |
+
print(show_results())
|
214 |
+
|
215 |
+
|
216 |
+
|