{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\n\nimport json\nimport string\nimport cv2\n\nimport numpy as np \nimport pandas as pd \nimport matplotlib.pyplot as plt\nimport matplotlib.patches as patches\n\n\nfrom PIL import Image, ImageDraw, ImageFont, ImageOps\nfrom difflib import SequenceMatcher","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-05-05T08:06:01.526813Z","iopub.execute_input":"2023-05-05T08:06:01.527232Z","iopub.status.idle":"2023-05-05T08:06:01.713324Z","shell.execute_reply.started":"2023-05-05T08:06:01.527176Z","shell.execute_reply":"2023-05-05T08:06:01.712145Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# GENERATE SYNTHETIC DATA","metadata":{}},{"cell_type":"code","source":"examples = 70000\n# examples = 50\n\nimage_directory = '/kaggle/input/imagenet-object-localization-challenge/ILSVRC/Data/CLS-LOC/train/n01632777'\n# images = os.listdir(image_directory)\n\nimages = []\nfor dirname, _, filenames in os.walk(image_directory):\n    for filename in filenames:\n        images.append(os.path.join(dirname, filename))\n        \nimage_save_directory = '/kaggle/working/images'\ncheckpoint_filepath = '/kaggle/working/checkpoint'\n\nos.makedirs(image_save_directory,  exist_ok=True)\nos.makedirs(checkpoint_filepath,  exist_ok=True)\n\n\nalphabets = string.digits + string.ascii_uppercase + \" -\"\n\n\nwidth = 200\nheight = 31\nnum_of_timestamps = 50\nmax_str_len = num_of_timestamps\nrnn_steps_to_discard = 2\n\nbatch_size = 32\n\nfonts_path = '/kaggle/input/poular-fonts/fonts'\n# all_fonts = os.listdir(fonts_path)\n# all_fonts = [\n# #     'century.ttf'\n#     'arial.ttf',\n#     'belli.ttf',\n#     \"bookosbi.ttf\",\n#     'calibril.ttf',\n#     'century.ttf',\n#     'cour.ttf',\n#     'constan.ttf', \n#     'consolai.ttf',\n#     'corbell.ttf',\n#     \"ebrima.ttf\",\n#     'ebrimabd.ttf',\n#     'freescpt.ttf',\n#     'gabriola.ttf',\n#     'inkfree.ttf',\n#     'leelauib.ttf',\n#     \"lhandw.ttf\", \n#     'lbrite.ttf',\n#     \"micross.ttf\",\n#     'mvboli.ttf',\n#     'nirmala.ttf',\n#     'ntailub.ttf',\n#     'onyx.ttf',\n#     \"segoeuib.ttf\",\n#     'showg.ttf',\n#     'seguibli.ttf',\n#     \"segoeuisl.ttf\",\n#     'segoesc.ttf',\n#     'times.ttf',\n#     'taile.ttf',\n#     'trebucit.ttf',\n#     \"unispace bd.ttf\",\n#     'verdanaz.ttf',\n# ]\n\nall_fonts = [\n    'century.ttf',\n    'seguibli.ttf',\n    'cour.ttf',\n    'gabriola.ttf',\n    'consolai.ttf',\n    'ntailub.ttf',\n    'lbrite.ttf',\n    'showg.ttf',\n    'arial.ttf',\n    # 'showg.ttf',\n    'century.ttf',\n    'calibrili.ttf',\n    'nirmala.ttf',\n    'leelauib.ttf',\n    'times.ttf',\n    'lbrite.ttf',\n    \n]\n\ncolores = [\n    (0,   0, 0),\n    (255, 0, 0),\n    (0, 255, 0),\n    (0, 0, 255),\n    (255, 255, 0),\n    (255, 255, 255),\n    (0, 255, 255),\n    (255, 0, 255),\n]","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:07:37.234475Z","iopub.execute_input":"2023-05-04T11:07:37.235205Z","iopub.status.idle":"2023-05-04T11:07:37.264334Z","shell.execute_reply.started":"2023-05-04T11:07:37.23514Z","shell.execute_reply":"2023-05-04T11:07:37.262455Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_image(path, file):\n    f = np.random.randint(0, len(file)-1)\n#     cmp_path = os.path.join(path, file[f])\n    cmp_path = file[f]\n    img = cv2.imread(cmp_path)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    return img\n\ndef select_font(path, fonts):\n    f = fonts[np.random.randint(0, len(fonts)-1)]\n    return os.path.join(path, f)\n    \ndef generate_string(max_string_lengths, dictionary):\n    \n    str_length = np.random.randint(3, max_string_lengths)\n    s = np.random.randint(0, len(dictionary)-2, str_length)\n    string = ''.join([dictionary[i] for i in s])\n    ## insert - at rendom place at random time\n    if np.random.uniform(0,1) > 0.5:\n        index = np.random.randint(1, len(string)-1)\n        string = string[0:index] + '-' + string[index:]\n\n    return string\n","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:07:37.265786Z","iopub.execute_input":"2023-05-04T11:07:37.266755Z","iopub.status.idle":"2023-05-04T11:07:37.276922Z","shell.execute_reply.started":"2023-05-04T11:07:37.266692Z","shell.execute_reply":"2023-05-04T11:07:37.275021Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Generate synthetic images","metadata":{}},{"cell_type":"code","source":"scale = 0.2\nsyn_record = []\nfor i in range(examples):\n    message = generate_string(10, alphabets)\n    font_selected = select_font(fonts_path, all_fonts)\n    path_to_save = f\"/kaggle/working/images/{message}.jpg\"\n    \n    font = ImageFont.truetype(font_selected,40)# size=np.random.randint(10, 40))\n    image = get_image(image_directory, images)\n    h, w,_ = image.shape    \n\n    img = Image.fromarray(np.round(image *(1-scale)).astype(np.uint8))\n#     img = Image.new('RGB', (width, height), color='black')\n#     with Image.open(\"hopper.jpg\") as im:\n#         im.rotate(45).show()\n#     txt = Image.new('L', font.getbbox(message)[2:4])\n    text_img_size = (np.array(font.getbbox(message)[2:4])*1.5).astype('int')\n    txt = Image.new('L', text_img_size.tolist())# ,color='white')\n    imgDraw = ImageDraw.Draw(txt)\n\n    textbbox = imgDraw.textbbox((0, 0), message, font)\n    text_width = textbbox[2] - textbbox[0]\n    text_height = textbbox[3] - textbbox[1]\n    xText = (w - text_width) // 2\n    yText = (h - text_height) // 2\n    \n#     imgDraw.text((xText, yText), message, font=font, fill=colores[np.random.randint(0, len(colores)-1)], stroke_fill=0.2)\n    imgDraw.text((20, 5), message,  font=font, fill=255, stroke_fill=np.random.uniform(0.2,4))\n    textbbox = np.array(textbbox) * np.array([0.3,0.3,1.3,1.4])\n    imgDraw.rounded_rectangle((textbbox), outline=\"white\",  width=3, radius=7)\n\n    rot = np.random.randint(-10, 10)\n    w = txt.rotate(rot,  expand=1,fillcolor='white')\n\n    img.paste( ImageOps.colorize(w, (0,0,0), colores[np.random.randint(0, len(colores)-1)]), (xText,yText),  w)    \n#     img.paste( w, (xText,yText),w)    \n\n    rot_cor =  abs(rot)*len(message)/4\n    shape = np.array([xText, yText, xText + textbbox[2], yText + textbbox[3]+textbbox[1]+rot_cor])\n        \n    im1 = img.crop(shape)\n#     break\n    im1.save(path_to_save)\n    syn_record.append(dict(label=message, font=font_selected, file=path_to_save))\n","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:12:48.154775Z","iopub.execute_input":"2023-05-04T11:12:48.155229Z","iopub.status.idle":"2023-05-04T11:12:49.111556Z","shell.execute_reply.started":"2023-05-04T11:12:48.155191Z","shell.execute_reply":"2023-05-04T11:12:49.110114Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"im1","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:12:49.113577Z","iopub.execute_input":"2023-05-04T11:12:49.113997Z","iopub.status.idle":"2023-05-04T11:12:49.125073Z","shell.execute_reply.started":"2023-05-04T11:12:49.113958Z","shell.execute_reply":"2023-05-04T11:12:49.123757Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.DataFrame(syn_record)\ndf.to_csv('/kaggle/working/labels.csv')\n","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:12:49.126863Z","iopub.execute_input":"2023-05-04T11:12:49.12727Z","iopub.status.idle":"2023-05-04T11:12:49.13709Z","shell.execute_reply.started":"2023-05-04T11:12:49.127234Z","shell.execute_reply":"2023-05-04T11:12:49.13531Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.head()","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:12:49.1394Z","iopub.execute_input":"2023-05-04T11:12:49.139787Z","iopub.status.idle":"2023-05-04T11:12:49.157444Z","shell.execute_reply.started":"2023-05-04T11:12:49.13975Z","shell.execute_reply":"2023-05-04T11:12:49.155988Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ADD real data for corrections","metadata":{}},{"cell_type":"code","source":"from bs4 import BeautifulSoup \n\ndef get_string(file):\n    with open(file, 'r') as f:\n        data = f.read() \n\n    # Passing the stored data inside the beautifulsoup parser \n    bs_data = BeautifulSoup(data, 'xml') \n\n    # Finding all instances of tag   \n    b_unique = bs_data.find_all('object') \n    return ''.join([i.find('name').text for i in b_unique])\n\ndef yolo_to_abs(data_dict):#, scale=100.0):\n    cord = {}\n\n    original_width = data_dict['original_width']\n    original_height = data_dict['original_height']\n    \n    pixel_x = int(data_dict['x']/100. * original_width)\n    pixel_y = int(data_dict['y']/100. * original_height)\n    pixel_width = int(data_dict['width']/100. * original_width)\n    pixel_height = int(data_dict['height']/100. * original_height)\n#     return[pixel_x, pixel_y, pixel_width, pixel_height]\n    cord['x1'] = pixel_x #- pixel_width #/2)*original_width\n    cord['y1'] = pixel_y #- pixel_height#/2)*original_height\n    cord['x2'] = pixel_x + pixel_width#/2)*original_width\n    cord['y2'] = pixel_y + pixel_height#/2)*original_height\n    return cord","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:12:51.06338Z","iopub.execute_input":"2023-05-04T11:12:51.063903Z","iopub.status.idle":"2023-05-04T11:12:51.074757Z","shell.execute_reply.started":"2023-05-04T11:12:51.063855Z","shell.execute_reply":"2023-05-04T11:12:51.073062Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"license_no_data = pd.read_csv('/kaggle/input/tags-licenseplate/ocr-licence-plate.csv')\n# license_no_data = license_no_data.sample(frac = 1)\nlicense_no_data['ocr'] = license_no_data['ocr'].apply(lambda x: x.split('-')[-1])\n\nlicense_no_data.head()","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:12:51.506032Z","iopub.execute_input":"2023-05-04T11:12:51.506496Z","iopub.status.idle":"2023-05-04T11:12:51.532089Z","shell.execute_reply.started":"2023-05-04T11:12:51.506458Z","shell.execute_reply":"2023-05-04T11:12:51.530765Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# lic_record = []\n# path_car_img = \"/kaggle/input/car-plate-detection/images\"\n# for row, val in  license_no_data.iterrows():                         # need improvement\n#     img_dir = os.path.join(path_car_img, val['ocr'])\n#     image = cv2.imread(img_dir, cv2.IMREAD_ANYCOLOR)\n#     try:\n#         label_s = json.loads(val['transcription'])\n#     except ValueError:\n#         label_s = str(val['transcription'])\n#     for num, bbox in enumerate(json.loads(val['bbox'])):\n#         path_to_save = f\"/kaggle/working/images/{val['ocr']}_{num}.jpg\"\n\n#         cart_cord = yolo_to_abs(bbox)\n#         crop_img = image[cart_cord['y1']:cart_cord['y2'],\n#                          cart_cord['x1']:cart_cord['x2']]\n# #         process_img = cv2.cvtColor(crop_img, cv2.COLOR_RGB2GRAY) #.astype(\"float32\")[..., np.newaxis]\n#         im_croped = Image.fromarray(crop_img)\n        \n#         im_croped.save(path_to_save)\n#         if isinstance(label_s, list):\n#             lic_record.append( dict(label=str(label_s[num]), font='real', file=path_to_save))\n#         else:\n#             lic_record.append(dict(label=str(label_s), font='real', file = path_to_save))\n","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:12:52.170677Z","iopub.execute_input":"2023-05-04T11:12:52.172126Z","iopub.status.idle":"2023-05-04T11:12:52.179415Z","shell.execute_reply.started":"2023-05-04T11:12:52.172047Z","shell.execute_reply":"2023-05-04T11:12:52.17783Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# lic_df = pd.DataFrame(lic_record)\n# lic_df.to_csv('/kaggle/working/lic_labels.csv')\n# lic_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:12:52.816747Z","iopub.execute_input":"2023-05-04T11:12:52.817537Z","iopub.status.idle":"2023-05-04T11:12:52.82333Z","shell.execute_reply.started":"2023-05-04T11:12:52.817477Z","shell.execute_reply":"2023-05-04T11:12:52.821943Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_dir = '/kaggle/input/license-plate-characters-detection-ocr/LP-characters/images'\nannotations_dir = '/kaggle/input/license-plate-characters-detection-ocr/LP-characters/annotations'\n    \nlic_record = []\n\nfor im_name in os.listdir(image_dir):\n    image_path = os.path.join(image_dir, im_name)\n\n    annot_path = os.path.join(annotations_dir, im_name.split('.')[0]+'.xml')      \n    label_string = get_string(annot_path)\n\n    lic_record.append(dict(label=str(label_string), font='real', file = image_path))\n    ","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:12:53.130455Z","iopub.execute_input":"2023-05-04T11:12:53.130895Z","iopub.status.idle":"2023-05-04T11:12:54.927588Z","shell.execute_reply.started":"2023-05-04T11:12:53.130859Z","shell.execute_reply":"2023-05-04T11:12:54.926193Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lic_df = pd.DataFrame(lic_record)\nlic_df.to_csv('/kaggle/working/lic_labels.csv')\nlic_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:12:54.929295Z","iopub.execute_input":"2023-05-04T11:12:54.929645Z","iopub.status.idle":"2023-05-04T11:12:54.948836Z","shell.execute_reply.started":"2023-05-04T11:12:54.929611Z","shell.execute_reply":"2023-05-04T11:12:54.947431Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Build Model","metadata":{}},{"cell_type":"code","source":"\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.callbacks import EarlyStopping\n\ntf.config.run_functions_eagerly(True)","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:12:54.950614Z","iopub.execute_input":"2023-05-04T11:12:54.950969Z","iopub.status.idle":"2023-05-04T11:13:06.987043Z","shell.execute_reply.started":"2023-05-04T11:12:54.950935Z","shell.execute_reply":"2023-05-04T11:13:06.985414Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DEFAULT_BUILD_PARAMS = {\n    'height': 31,\n    'width': 200,\n    'color': False,\n    'filters': (64, 128, 256, 256, 512, 512, 512),\n    'rnn_units': (128, 128),\n    'dropout': 0.25,\n    'rnn_steps_to_discard': 2,\n    'pool_size': 2,\n    'stn': True,\n}\n\n# DEFAULT_ALPHABET = alphabets\n\nPRETRAINED_WEIGHTS = {\n    'kurapan': {\n        'alphabet': alphabets,\n        'build_params': DEFAULT_BUILD_PARAMS,\n        'weights': {\n            'notop': {\n                'url':\n                'https://github.com/faustomorales/keras-ocr/releases/download/v0.8.4/crnn_kurapan_notop.h5',\n                'filename': 'crnn_kurapan_notop.h5',\n                'sha256': '027fd2cced3cbea0c4f5894bb8e9e85bac04f11daf96b8fdcf1e4ee95dcf51b9'\n            },\n            'top': {\n                'url':\n                'https://github.com/faustomorales/keras-ocr/releases/download/v0.8.4/crnn_kurapan.h5',\n                'filename': 'crnn_kurapan.h5',\n                'sha256': 'a7d8086ac8f5c3d6a0a828f7d6fbabcaf815415dd125c32533013f85603be46d'\n            }\n        }\n    }\n}\n","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:13:28.922268Z","iopub.execute_input":"2023-05-04T11:13:28.92306Z","iopub.status.idle":"2023-05-04T11:13:28.93216Z","shell.execute_reply.started":"2023-05-04T11:13:28.923015Z","shell.execute_reply":"2023-05-04T11:13:28.930287Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def CTCDecoder():\n    def decoder(y_pred):\n        input_shape = tf.keras.backend.shape(y_pred)\n        input_length = tf.ones(shape=input_shape[0]) * tf.keras.backend.cast(\n            input_shape[1], 'float32')\n        unpadded = tf.keras.backend.ctc_decode(y_pred, input_length)[0][0]\n        unpadded_shape = tf.keras.backend.shape(unpadded)\n        padded = tf.pad(unpadded,\n                        paddings=[[0, 0], [0, input_shape[1] - unpadded_shape[1]]],\n                        constant_values=-1)\n        return padded\n\n    return tf.keras.layers.Lambda(decoder, name='decode')","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:13:30.522265Z","iopub.execute_input":"2023-05-04T11:13:30.52371Z","iopub.status.idle":"2023-05-04T11:13:30.532019Z","shell.execute_reply.started":"2023-05-04T11:13:30.523644Z","shell.execute_reply":"2023-05-04T11:13:30.530953Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def build_model(alphabet, height, width, color, filters, rnn_units, dropout, rnn_steps_to_discard, pool_size, stn=True):\n    \"\"\"Build a Keras CRNN model for character recognition.\n    Args:\n        height: The height of cropped images\n        width: The width of cropped images\n      predict  color: Whether the inputs should be in color (RGB)\n        filters: The number of filters to use for each of the 7 convolutional layers\n        rnn_units: The number of units for each of the RNN layers\n        dropout: The dropout to use for the final layer\n        rnn_steps_to_discard: The number of initial RNN steps to discard\n        pool_size: The size of the pooling steps\n        stn: Whether to add a Spatial Transformer layer\n    \"\"\"\n    assert len(filters) == 7, '7 CNN filters must be provided.'\n    assert len(rnn_units) == 2, '2 RNN filters must be provided.'\n    inputs = keras.layers.Input((height, width, 3 if color else 1), name='input', batch_size=1)\n    x = keras.layers.Permute((2, 1, 3))(inputs)\n    x = keras.layers.Lambda(lambda x: x[:, :, ::-1])(x)\n    x = keras.layers.Conv2D(filters[0], (3, 3), activation='relu', padding='same', name='conv_1')(x)\n    x = keras.layers.Conv2D(filters[1], (3, 3), activation='relu', padding='same', name='conv_2')(x)\n    x = keras.layers.Conv2D(filters[2], (3, 3), activation='relu', padding='same', name='conv_3')(x)\n    x = keras.layers.BatchNormalization(name='bn_3')(x)\n    x = keras.layers.MaxPooling2D(pool_size=(pool_size, pool_size), name='maxpool_3')(x)\n    x = keras.layers.Conv2D(filters[3], (3, 3), activation='relu', padding='same', name='conv_4')(x)\n    x = keras.layers.Conv2D(filters[4], (3, 3), activation='relu', padding='same', name='conv_5')(x)\n    x = keras.layers.BatchNormalization(name='bn_5')(x)\n    x = keras.layers.MaxPooling2D(pool_size=(pool_size, pool_size), name='maxpool_5')(x)\n    x = keras.layers.Conv2D(filters[5], (3, 3), activation='relu', padding='same', name='conv_6')(x)\n    x = keras.layers.Conv2D(filters[6], (3, 3), activation='relu', padding='same', name='conv_7')(x)\n    x = keras.layers.BatchNormalization(name='bn_7')(x)\n    \n    x = keras.layers.Reshape(target_shape=(width // pool_size**2,\n                                           (height // pool_size**2) * filters[-1]),\n                             name='reshape')(x)\n\n    x = keras.layers.Dense(rnn_units[0], activation='relu', name='fc_9')(x)\n\n    rnn_1_forward = keras.layers.LSTM(rnn_units[0],\n                                      kernel_initializer=\"he_normal\",\n                                      return_sequences=True,\n                                      name='lstm_10')(x)\n    rnn_1_back = keras.layers.LSTM(rnn_units[0],\n                                   kernel_initializer=\"he_normal\",\n                                   go_backwards=True,\n                                   return_sequences=True,\n                                   name='lstm_10_back')(x)\n    rnn_1_add = keras.layers.Add()([rnn_1_forward, rnn_1_back])\n    rnn_2_forward = keras.layers.LSTM(rnn_units[1],\n                                      kernel_initializer=\"he_normal\",\n                                      return_sequences=True,\n                                      name='lstm_11')(rnn_1_add)\n    rnn_2_back = keras.layers.LSTM(rnn_units[1],\n                                   kernel_initializer=\"he_normal\",\n                                   go_backwards=True,\n                                   return_sequences=True,\n                                   name='lstm_11_back')(rnn_1_add)\n    x = keras.layers.Concatenate()([rnn_2_forward, rnn_2_back])\n    backbone = keras.models.Model(inputs=inputs, outputs=x)\n    x = keras.layers.Dropout(dropout, name='dropout')(x)\n    x = keras.layers.Dense(len(alphabet) + 1,\n                           kernel_initializer='he_normal',\n                           activation='softmax',\n                           name='fc_12')(x)\n    x = keras.layers.Lambda(lambda x: x[:, rnn_steps_to_discard:])(x)\n    model = keras.models.Model(inputs=inputs, outputs=x)\n    prediction_model = keras.models.Model(inputs=inputs, outputs=CTCDecoder()(model.output))\n    \n    labels = keras.layers.Input(name=\"labels\", shape=[model.output_shape[1]], dtype=\"float32\")\n\n    label_length = keras.layers.Input(shape=[1])\n    input_length = keras.layers.Input(shape=[1])\n\n    loss = keras.layers.Lambda(lambda x: keras.backend.ctc_batch_cost(y_true=x[0], y_pred=x[1], input_length=x[2], label_length=x[3])\n                              )([labels, model.output, input_length, label_length])\n    training_model = keras.models.Model(inputs=[model.input, labels, input_length, label_length], outputs=loss)\n    \n    return model, prediction_model, training_model","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:13:31.389905Z","iopub.execute_input":"2023-05-04T11:13:31.390576Z","iopub.status.idle":"2023-05-04T11:13:31.417933Z","shell.execute_reply.started":"2023-05-04T11:13:31.390536Z","shell.execute_reply":"2023-05-04T11:13:31.415994Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# build_params = DEFAULT_BUILD_PARAMS\n# alphabets = DEFAULT_ALPHABET\n# blank_index = len(alphabets)\n\nmodel, prediction_model, training_model = build_model(alphabet=alphabets, **DEFAULT_BUILD_PARAMS)\n\ntraining_model.compile(loss = lambda _, y_pred: y_pred, optimizer='Adam')      # RMSprop\n","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:13:32.216104Z","iopub.execute_input":"2023-05-04T11:13:32.216505Z","iopub.status.idle":"2023-05-04T11:13:34.22178Z","shell.execute_reply.started":"2023-05-04T11:13:32.216471Z","shell.execute_reply":"2023-05-04T11:13:34.219964Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def label_to_num(label):\n    label_num = []\n    for ch in label:\n            label_num.append(alphabets.find(ch))\n        \n    return np.array(label_num)\n\ndef num_to_label(num):\n    ret = \"\"\n    for ch in num:\n        if ch == -1:  # CTC Blank\n            break\n        else:\n            ret+=alphabets[ch]\n    return ret","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:13:35.97867Z","iopub.execute_input":"2023-05-04T11:13:35.979171Z","iopub.status.idle":"2023-05-04T11:13:35.987739Z","shell.execute_reply.started":"2023-05-04T11:13:35.979128Z","shell.execute_reply":"2023-05-04T11:13:35.985916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def preprocess(image, width: int, height: int, cval: int = 255, mode=\"letterbox\", return_scale=False,):\n    \"\"\"Obtain a new image, fit to the specified size.\n    Args:\n        image: The input image\n        width: The new width\n        height: The new height\n        cval: The constant value to use to fill the remaining areas of\n            the image\n        return_scale: Whether to return the scale used for the image\n    Returns:\n        The new image\n    \"\"\"\n    fitted = None\n    x_scale = width / image.shape[1]\n    y_scale = height / image.shape[0]\n    if x_scale == 1 and y_scale == 1:\n        fitted = image\n        scale = 1\n    elif (x_scale <= y_scale and mode == \"letterbox\") or (\n        x_scale >= y_scale and mode == \"crop\"\n    ):\n        scale = width / image.shape[1]\n        resize_width = width\n        resize_height = (width / image.shape[1]) * image.shape[0]\n    else:\n        scale = height / image.shape[0]\n        resize_height = height\n        resize_width = scale * image.shape[1]\n    if fitted is None:\n        resize_width, resize_height = map(int, [resize_width, resize_height])\n        if mode == \"letterbox\":\n            fitted = np.zeros((height, width, 3), dtype=\"uint8\") + cval\n            image = cv2.resize(image, dsize=(resize_width, resize_height))\n            fitted[: image.shape[0], : image.shape[1]] = image[:height, :width]\n        elif mode == \"crop\":\n            image = cv2.resize(image, dsize=(resize_width, resize_height))\n            fitted = image[:height, :width]\n        else:\n            raise NotImplementedError(f\"Unsupported mode: {mode}\")\n    if not return_scale:\n        return fitted\n    return fitted, scale","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:13:36.83548Z","iopub.execute_input":"2023-05-04T11:13:36.835973Z","iopub.status.idle":"2023-05-04T11:13:36.849936Z","shell.execute_reply.started":"2023-05-04T11:13:36.835935Z","shell.execute_reply":"2023-05-04T11:13:36.847926Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def image_generator(data, im_w, im_h,):\n    for row, val in  data.iterrows(): #need improvement\n        \n        img_dir = val['file']\n        image = cv2.imread(img_dir, cv2.IMREAD_ANYCOLOR) #IMREAD_ANYCOLOR, IMREAD_GRAYSCALE\n        image = preprocess(image,width=im_w, height=im_h)\n        image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY).astype(\"float32\")[..., np.newaxis]\n\n        image = image/255.\n        \n#         if image.shape !=(256,64,1):\n#             break\n        if (len(val['label'])>max_str_len):\n            continue\n        labels = label_to_num(val['label'])   \n        \n        yield (image, labels)\n        \n        \ndef data_joiner(*val):\n    xl = val[0]\n    lab = val[1]\n    lab_len = len(lab)\n    one_pad = -tf.ones((max_str_len - lab_len - rnn_steps_to_discard),dtype=tf.int32)#*(-1)\n    y = tf.concat([lab, one_pad], -1)\n    \n    return xl, y, [max_str_len-2], [lab_len], [0]","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:13:37.782395Z","iopub.execute_input":"2023-05-04T11:13:37.782851Z","iopub.status.idle":"2023-05-04T11:13:37.795557Z","shell.execute_reply.started":"2023-05-04T11:13:37.782799Z","shell.execute_reply":"2023-05-04T11:13:37.793367Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Build Train Test and Validataion set","metadata":{}},{"cell_type":"code","source":"# train_data = df\n\ntrain_range = int(examples * 0.8)\ntest_range = train_range + int(examples * 0.15)\n\ntrain_data = df.iloc[:train_range]\n\nvalid_data = df.iloc[train_range:test_range]\n# test_data = df.iloc[test_range:]\n\ndata_len = int(lic_df.shape[0]*0.5)\ndata_len_val = data_len * int(lic_df.shape[0]*0.25)\n### join /concatinate syntetic data with real data\n\ntrain_data = pd.concat((train_data, lic_df.iloc[:data_len])).reset_index(drop=True)\nvalid_data = pd.concat((valid_data, lic_df.iloc[data_len:data_len_val])).reset_index(drop=True)\n# test_data = pd.concat((test_data, lic_df.iloc[200:])).reset_index(drop=True)\ntest_data = lic_df.iloc[data_len_val:].reset_index(drop=True)","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:14:02.85962Z","iopub.execute_input":"2023-05-04T11:14:02.860075Z","iopub.status.idle":"2023-05-04T11:14:02.874253Z","shell.execute_reply.started":"2023-05-04T11:14:02.86004Z","shell.execute_reply":"2023-05-04T11:14:02.872672Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"height = DEFAULT_BUILD_PARAMS['height']\nwidth = DEFAULT_BUILD_PARAMS['width']\n\ndataset_tr = tf.data.Dataset.from_generator(lambda: image_generator(train_data, width, height),\n                                        (tf.float32, tf.int32))# , ([256, 64,1], [None]))\ndataset_tr = dataset_tr.map(data_joiner).batch(batch_size)\ndataset_train= dataset_tr.map(lambda *x: (x[0:-1],x[-1]))\n\n\ndataset_vl = tf.data.Dataset.from_generator(lambda: image_generator(valid_data, width, height),\n                                        (tf.float32, tf.int32))# , ([256, 64,1], [None]))\ndataset_vl = dataset_vl.map(data_joiner).batch(batch_size)\ndataset_valid = dataset_vl.map(lambda *x: (x[0:-1],x[-1]))","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:14:04.160988Z","iopub.execute_input":"2023-05-04T11:14:04.162247Z","iopub.status.idle":"2023-05-04T11:14:04.480782Z","shell.execute_reply.started":"2023-05-04T11:14:04.162192Z","shell.execute_reply":"2023-05-04T11:14:04.479478Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train Model","metadata":{}},{"cell_type":"code","source":"\nearly_stopping = EarlyStopping(patience=4, restore_best_weights=True)\nmodel_checkpoint_callback = tf.keras.callbacks.ModelCheckpoint(\n    filepath=checkpoint_filepath,\n    save_weights_only=True,\n    monitor='val_loss',\n    save_best_only=True)\n\nhistory = training_model.fit(dataset_train,\n                   validation_data=dataset_valid,  \n                   epochs=100,\n#                    verbose=2,\n                   callbacks=[early_stopping]\n                  )#, validation_split=0.1,callbacks=callbacks)","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:14:07.645151Z","iopub.execute_input":"2023-05-04T11:14:07.645672Z","iopub.status.idle":"2023-05-04T11:18:42.26043Z","shell.execute_reply.started":"2023-05-04T11:14:07.64563Z","shell.execute_reply":"2023-05-04T11:18:42.257995Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.save('/kaggle/working/ocr-model.h5', save_format='h5')","metadata":{"execution":{"iopub.status.busy":"2023-04-27T12:00:23.993605Z","iopub.status.idle":"2023-04-27T12:00:23.994214Z","shell.execute_reply.started":"2023-04-27T12:00:23.993966Z","shell.execute_reply":"2023-04-27T12:00:23.993993Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def compare_string(true_label, pred_label):\n    \n    true_label = true_label.replace(\" \", \"\").replace('-','')\n    pred_label =  pred_label.replace(\" \", \"\").replace('-','')\n    \n    if pred_label == true_label:\n        return True\n    \n    return False","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:18:48.414496Z","iopub.execute_input":"2023-05-04T11:18:48.415105Z","iopub.status.idle":"2023-05-04T11:18:48.4235Z","shell.execute_reply.started":"2023-05-04T11:18:48.415054Z","shell.execute_reply":"2023-05-04T11:18:48.421872Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Performance on valid","metadata":{}},{"cell_type":"code","source":"correct_char = 0\ntotal_char = 0\ncorrect = 0\n\n                  \ndataset_score = tf.data.Dataset.from_generator(lambda: image_generator(valid_data, width, height), (tf.float32, tf.int32))\n\nfor img, lab in dataset_score:\n    pred = prediction_model.predict(img[np.newaxis, ...], verbose=0)    \n    true_label = num_to_label(lab.numpy())    \n    pred_label = num_to_label(pred[0])   \n\n#     pr = prediction[i]\n#     tr = y_true[i]\n    total_char += len(true_label)\n    correct_char += SequenceMatcher(None, true_label, pred_label).ratio()\n    \n#     for j in range(min(len(true_label), len(pred_label))):\n#         if true_label[j] == pred_label[j]:\n#             correct_char += 1\n            \n    if compare_string(true_label, pred_label) :\n        correct += 1\n    else:\n        plt.imshow(img, cmap='gray')\n        plt.show()\n        print('true_label',true_label)\n        print('pred_label',pred_label)","metadata":{"execution":{"iopub.status.busy":"2023-05-04T11:18:50.155534Z","iopub.execute_input":"2023-05-04T11:18:50.156587Z","iopub.status.idle":"2023-05-04T11:18:59.61945Z","shell.execute_reply.started":"2023-05-04T11:18:50.156534Z","shell.execute_reply":"2023-05-04T11:18:59.616911Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Result on Validation","metadata":{}},{"cell_type":"code","source":"print('performance on valid syntheric data')\nprint('Correct characters predicted : %.2f%%' %(correct_char*100/valid_data.shape[0]))\nprint('Correct words predicted      : %.2f%%' %(correct*100/valid_data.shape[0]))","metadata":{"execution":{"iopub.status.busy":"2023-04-28T10:06:51.42269Z","iopub.status.idle":"2023-04-28T10:06:51.423312Z","shell.execute_reply.started":"2023-04-28T10:06:51.423094Z","shell.execute_reply":"2023-04-28T10:06:51.423119Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Performance on Test","metadata":{}},{"cell_type":"code","source":"correct_char = 0\ntotal_char = 0\ncorrect = 0\n\n                  \ndataset_score = tf.data.Dataset.from_generator(lambda: image_generator(test_data, width, height), (tf.float32, tf.int32))\n\nfor img, lab in dataset_score:\n    pred = prediction_model.predict(img[np.newaxis, ...], verbose=0)    \n    true_label = num_to_label(lab.numpy())    \n    pred_label = num_to_label(pred[0])   \n\n#     pr = prediction[i]\n#     tr = y_true[i]\n    total_char += len(true_label)\n    \n    correct_char += SequenceMatcher(None, true_label, pred_label).ratio()\n#     for j in range(min(len(true_label), len(pred_label))):\n#         if true_label[j] == pred_label[j]:\n#             correct_char += 1\n            \n    if compare_string(true_label, pred_label) :\n        correct += 1\n    else:\n        plt.imshow(img, cmap='gray')\n        plt.show()\n        print('true_label',true_label)\n        print('pred_label',pred_label)\n","metadata":{"execution":{"iopub.status.busy":"2023-04-28T10:06:51.424554Z","iopub.status.idle":"2023-04-28T10:06:51.424929Z","shell.execute_reply.started":"2023-04-28T10:06:51.424742Z","shell.execute_reply":"2023-04-28T10:06:51.424762Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Performance on test","metadata":{}},{"cell_type":"code","source":"print('performance on test original data')\nprint('Correct characters predicted : %.2f%%' %(correct_char*100/test_data.shape[0]))\nprint('Correct words predicted      : %.2f%%' %(correct*100/test_data.shape[0]))","metadata":{"execution":{"iopub.status.busy":"2023-04-28T10:06:51.426493Z","iopub.status.idle":"2023-04-28T10:06:51.427421Z","shell.execute_reply.started":"2023-04-28T10:06:51.4272Z","shell.execute_reply":"2023-04-28T10:06:51.427226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}