File size: 9,911 Bytes
05a48f3
 
 
 
bc5afe1
05a48f3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4857170
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72a51ab
4857170
 
 
 
 
 
05a48f3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bc5afe1
 
 
 
05a48f3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7850a64
05a48f3
7850a64
05a48f3
 
 
 
 
 
 
 
 
 
4857170
 
05a48f3
c4c9855
05a48f3
 
 
 
 
 
 
 
 
 
470dd17
05a48f3
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
import streamlit as st
from streamlit_image_select import image_select
import tensorflow as tf
import datetime
from pytz import timezone
import os
import pandas as pd
import numpy as np
import cv2 
from PIL import Image


# trained model files and paths
files = {
    "label_map_ssd" : os.path.join('eported_models','ssd_mobilnet_numberplate_region_detection','label_map.pbtxt'),
    "label_map_efficientdet" : os.path.join('eported_models','efficientdet_d0_ocr_numberplate','label_map.pbtxt')
}

paths = {
    "saved_model_path_ssd" : os.path.join('eported_models','ssd_mobilnet_numberplate_region_detection','saved_model'),
    "saved_model_path_efficientdet" : os.path.join('eported_models','efficientdet_d0_ocr_numberplate','saved_model')
}

def read_label_map(label_map_path):
    item_id = None
    item_name = None
    items = {}
    with open(label_map_path, "r") as file:
        for line in file:
            line.replace(" ", "")
            if line == "item{":
                pass
            elif line == "}":
                pass
            elif "id" in line:
                item_id = int(line.split(":", 1)[1].strip())
            elif "name" in line:
                item_name = {line.split(":")[0].replace("\"", " ").strip() : line.split(":")[1].replace("'", '').strip()}
            if item_id is not None and item_name is not None:
                items[item_id] = item_name
                item_id = None
                item_name = None
    return items

#load model
@st.cache(allow_output_mutation = True)
def cache_model(path1, path2):
    model1 = tf.saved_model.load(path1)
    model2 = tf.saved_model.load(path2)
    return (model1, model2)
detect_fn_ssd, detect_fn_efficientdet = cache_model(paths["saved_model_path_ssd"], paths["saved_model_path_efficientdet"])

# Creating category index
category_index_ssd = read_label_map(files["label_map_ssd"])
category_index_efficientdet = read_label_map(files["label_map_efficientdet"])

def image_resize_with_padding(image):
    image = np.array(image)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    old_size = image.shape[:2] # old_size is in (height, width) format
    
    if max(old_size) > 256:
        desired_size = 512
    else:
        desired_size = 256
        
    ratio = float(desired_size)/max(old_size)
    new_size = tuple([int(x*ratio) for x in old_size])
    # resize the image
    resized = cv2.resize(image, (new_size[1],new_size[0]))

    delta_w = desired_size - new_size[1]
    delta_h = desired_size - new_size[0]
    top, bottom = delta_h//2, delta_h-(delta_h//2)
    left, right = delta_w//2, delta_w-(delta_w//2)
    # print(top,bottom,left,right)

    color = [255, 255, 255]
    new_im = cv2.copyMakeBorder(resized, top, bottom, left, right, cv2.BORDER_CONSTANT,value=color)
    
    return new_im

def image_resize(image):
    image = np.array(image)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    old_size = image.shape[:2] # old_size is in (height, width) format
    print(old_size)
    
    if max(old_size) >= 1080:
        desired_size = 1080
    else:
        desired_size = max(old_size)
        
    if desired_size == 1080:
        ratio = float(desired_size)/ max(old_size)
        new_size = tuple([int(x*ratio) for x in old_size])
        resized = cv2.resize(image, (new_size[1],new_size[0]))
        
        if new_size[0] == 1080:
            height = 1080
            width = 810
        else:
            height = 810
            width = 1080
    
    
        delta_w = width - new_size[1]
        delta_h = height - new_size[0]
        top, bottom = delta_h//2, delta_h-(delta_h//2)
        left, right = delta_w//2, delta_w-(delta_w//2)
        # print(top,bottom,left,right)

        color = [255, 255, 255]
        image = cv2.copyMakeBorder(resized, top, bottom, left, right, cv2.BORDER_CONSTANT,value=color)

        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

    return image

def ExtractBBoxes(bboxes, bclasses, bscores, im_width, im_height, threshold, category_index):
    bbox = []
    class_labels = []
    for idx in range(len(bboxes)):
        if bscores[idx] >= threshold:
          y_min = int(bboxes[idx][0] * im_height)
          x_min = int(bboxes[idx][1] * im_width)
          y_max = int(bboxes[idx][2] * im_height)
          x_max = int(bboxes[idx][3] * im_width)
          class_label = category_index[int(bclasses[idx])]['name']
          class_labels.append(class_label)
          bbox.append([x_min, y_min, x_max, y_max, class_label, float(bscores[idx])])
    return (bbox, class_labels)

def ocr_predict(img,threshold):

    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    image_np = tf.convert_to_tensor(img, dtype=tf.uint8)
    input_tensor = np.expand_dims(image_np, 0)
    image_height, image_width, _ = image_np.shape
    detections = detect_fn_efficientdet(input_tensor)
    bboxes = detections['detection_boxes'][0].numpy()
    bclasses = detections['detection_classes'][0].numpy().astype(np.int32)
    bscores = detections['detection_scores'][0].numpy()
    det_boxes, class_labels = ExtractBBoxes(bboxes, bclasses, bscores, image_width, image_height, threshold, category_index_efficientdet)
    output = []
    for detection in det_boxes:
        x_min, y_min, x_max, y_max, label, score = detection[0], detection[1], detection[2], detection[3], detection[4], round(detection[5])
        
        output.append((label, int(x_min*image_width), int(y_min*image_height),
                      int(x_max*image_width), int(y_max*image_height), score))

    df = pd.DataFrame(output, columns = ['label','xmin','ymin','xmax','ymax', 'score'])
   
    df_up = df[df.ymin < (df.ymin.min()*1.2)].sort_values(by  = ['xmin'])
    df_down = df[df.ymin > (df.ymin.min()*1.2)].sort_values(by  = ['xmin'])
    df = pd.concat([df_up,df_down])
    vehicle_number = "".join(df["label"])
    
    
    
    current_date_time = datetime.datetime.now()
    now_asia = current_date_time.astimezone(timezone('Asia/Kolkata'))
    day = now_asia.strftime("%A")
    date = now_asia.strftime("%d/%m/%Y")
    time = now_asia.strftime("%I:%M:%S %p")
    data = [(vehicle_number,day,date,time)]

    return (data)

def predict(img,threshold):
    image_np = np.array(img)
    img = cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB)
    image = tf.convert_to_tensor(img, dtype=tf.uint8)
    input_tensor = np.expand_dims(image, 0)
    # image = tf.image.decode_image(open(file, 'rb').read(), channels=3)
    # img = cv2.imread(file)
    image_height, image_width, _ = image.shape
    
    
    
    # input_tensor = np.expand_dims(image, 0)
    detections = detect_fn_ssd(input_tensor)

    bboxes = detections['detection_boxes'][0].numpy()
    bclasses = detections['detection_classes'][0].numpy().astype(np.int32)
    bscores = detections['detection_scores'][0].numpy()
    det_boxes, class_labels = ExtractBBoxes(bboxes, bclasses, bscores, image_width, image_height, threshold, category_index_ssd)
    output = []
    for detection in det_boxes:
        x_min, y_min, x_max, y_max, label, score = detection[0], detection[1], detection[2], detection[3], detection[4], round(detection[5])
        
        output.append((label, x_min, y_min, x_max, y_max, score))
        
    image_np_with_detections = image_np.copy()

    data_list = []
    for l, x_min, y_min, x_max, y_max, score in output:

        array = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
        image = Image.fromarray(array)

        cropped_img = image.crop((x_min, y_min, x_max, y_max))
        input_ocr_image = image_resize_with_padding(cropped_img)

        data = ocr_predict(input_ocr_image,threshold)
        data_list.append(data)

    for l, x_min, y_min, x_max, y_max, score in output:
        

        x1 = x_min
        y1 = y_min
        x2 = x_max
        y2 = y_max
        # For bounding box
        color = (0,255,0)

        img = cv2.rectangle(img, (x1, y1), (x2, y2),color, 2)

        label = f"{l} : {round(score,2)}"
        text_color = (0,0,255)
        # For the text background
        # Finds space required by the text so that we can put a background with that amount of width.
        (w, h), _ = cv2.getTextSize(
                label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 1)

        # Prints the text.    
        img = cv2.rectangle(img, (x1, y1 - 20), (x1 + w, y1), color, -1)
        img = cv2.putText(img, label, (x1, y1 - 5),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.6, text_color, 1)
        # plt.imshow(img)


    im_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    return (im_rgb, data_list)

st.write("""
         # Automated Number Plate Recognition
         """
         )

st.write("""
        **For full code implementation and sub modules please visit the [Github link](https://github.com/gourav300/Automated-Number-plate-Recognition-for-Indian-Vehicles)**
        """)

### load file
uploaded_file = st.file_uploader("Upload an image file for a vehicle with standard number plate", type=["jpg", "png", "jpeg"])

st.write("Note -: if you have uploaded an image please click X to enable below images")
test_img = image_select(
    label='''Select an image to get number plate data''',
    images=[
        "test_images/test1.jpg",
        "test_images/test2.png",
        "test_images/test3.png",
        "test_images/test4.jpg",
        "test_images/test5.jpg",
        "test_images/test6.jpg",
        "test_images/test7.jpg",
        "test_images/test8.jpg",
    ])


if uploaded_file is not None:
    image = Image.open(uploaded_file)
    scale_image = image_resize(image)
    img, data = predict(scale_image, 0.6)
    # image = Image.open(uploaded_file)
    st.image(img, use_column_width=True)
    st.write(f'''
    Vehicle details : 

    {data}

    ''')
else:

    image = Image.open(test_img)
    img, data = predict(image, 0.6)
    st.image(img, use_column_width=True)
    st.write(f'''
    Vehicle details : 

    {data}

    ''')