├── Licence_Detection_ipynb.ipynb ├── README.md ├── add_missing_data.py ├── main.py ├── sort.py ├── test.csv ├── test_interpolated.csv ├── util.py └── visualize.py /Licence_Detection_ipynb.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [], 7 | "gpuType": "T4" 8 | }, 9 | "kernelspec": { 10 | "name": "python3", 11 | "display_name": "Python 3" 12 | }, 13 | "language_info": { 14 | "name": "python" 15 | }, 16 | "accelerator": "GPU" 17 | }, 18 | "cells": [ 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "metadata": { 23 | "colab": { 24 | "base_uri": "https://localhost:8080/" 25 | }, 26 | "id": "kd2wKH5lrKr1", 27 | "outputId": "e2d788b5-29f3-4205-f0ee-239714e4efd0" 28 | }, 29 | "outputs": [ 30 | { 31 | "output_type": "stream", 32 | "name": "stdout", 33 | "text": [ 34 | "/bin/bash: line 1: nvidia-smi: command not found\n" 35 | ] 36 | } 37 | ], 38 | "source": [ 39 | "!nvidia-smi" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "source": [ 45 | "from google.colab import drive\n", 46 | "drive.mount('/content/drive')" 47 | ], 48 | "metadata": { 49 | "colab": { 50 | "base_uri": "https://localhost:8080/" 51 | }, 52 | "id": "EOxNXXsZrWJa", 53 | "outputId": "3e2b3eb3-29a7-40ea-92d5-7bf83941a829" 54 | }, 55 | "execution_count": null, 56 | "outputs": [ 57 | { 58 | "output_type": "stream", 59 | "name": "stdout", 60 | "text": [ 61 | "Mounted at /content/drive\n" 62 | ] 63 | } 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "source": [ 69 | "mkdir -p /content/drive/MyDrive/Object_Detection/License_Plate_Recognition" 70 | ], 71 | "metadata": { 72 | "id": "P9IlPSs0rZnp" 73 | }, 74 | "execution_count": null, 75 | "outputs": [] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "source": [ 80 | "%cd /content/drive/MyDrive/Object_Detection/License_Plate_Recognition" 81 | ], 82 | "metadata": { 83 | "colab": { 84 | "base_uri": "https://localhost:8080/" 85 | }, 86 | "id": "MlCP1mfxrjgi", 87 | "outputId": "84929bb7-e4a2-4318-869f-9e457ef26748" 88 | }, 89 | "execution_count": null, 90 | "outputs": [ 91 | { 92 | "output_type": "stream", 93 | "name": "stdout", 94 | "text": [ 95 | "/content/drive/MyDrive/Object_Detection/License_Plate_Recognition\n" 96 | ] 97 | } 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "source": [ 103 | "# Check Dir Root\n", 104 | "import os\n", 105 | "Home = os.getcwd()\n", 106 | "print(Home)" 107 | ], 108 | "metadata": { 109 | "colab": { 110 | "base_uri": "https://localhost:8080/" 111 | }, 112 | "id": "BoeSy3fer-aW", 113 | "outputId": "5567b1f8-3d1b-4634-d414-19ece05ac19d" 114 | }, 115 | "execution_count": null, 116 | "outputs": [ 117 | { 118 | "output_type": "stream", 119 | "name": "stdout", 120 | "text": [ 121 | "/content/drive/MyDrive/Object_Detection/License_Plate_Recognition\n" 122 | ] 123 | } 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "source": [ 129 | "!pip install ultralytics\n", 130 | "\n", 131 | "from IPython import display\n", 132 | "display.clear_output()" 133 | ], 134 | "metadata": { 135 | "id": "4RyGjtB9sRrh" 136 | }, 137 | "execution_count": null, 138 | "outputs": [] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "source": [ 143 | "# Check ultralystics\n", 144 | "import ultralytics\n", 145 | "ultralytics.checks()" 146 | ], 147 | "metadata": { 148 | "colab": { 149 | "base_uri": "https://localhost:8080/" 150 | }, 151 | "id": "w99zo6u0sU45", 152 | "outputId": "21dd6e0b-6618-48a1-af9f-01cfec228953" 153 | }, 154 | "execution_count": null, 155 | "outputs": [ 156 | { 157 | "output_type": "stream", 158 | "name": "stderr", 159 | "text": [ 160 | "Ultralytics YOLOv8.0.190 🚀 Python-3.10.12 torch-2.0.1+cu118 CUDA:0 (Tesla T4, 15102MiB)\n", 161 | "Setup complete ✅ (2 CPUs, 12.7 GB RAM, 26.3/78.2 GB disk)\n" 162 | ] 163 | } 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "source": [ 169 | "!pip install roboflow\n", 170 | "display.clear_output()" 171 | ], 172 | "metadata": { 173 | "id": "RP-g0ZDosZWR" 174 | }, 175 | "execution_count": null, 176 | "outputs": [] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "source": [ 181 | "!mkdir {Home}/DataSets\n", 182 | "%cd {Home}/DataSets" 183 | ], 184 | "metadata": { 185 | "colab": { 186 | "base_uri": "https://localhost:8080/" 187 | }, 188 | "id": "4-TPXmu4sn-I", 189 | "outputId": "761ae9ee-f815-4425-aac9-1cb0ebf2300f" 190 | }, 191 | "execution_count": null, 192 | "outputs": [ 193 | { 194 | "output_type": "stream", 195 | "name": "stdout", 196 | "text": [ 197 | "/content/drive/MyDrive/Object_Detection/License_Plate_Recognition/DataSets\n" 198 | ] 199 | } 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "source": [ 205 | "from roboflow import Roboflow\n", 206 | "rf = Roboflow(api_key=\"3xqoQhgk2T2SnBmvFHiE\")\n", 207 | "project = rf.workspace(\"roboflow-universe-projects\").project(\"license-plate-recognition-rxg4e\")\n", 208 | "dataset = project.version(4).download(\"yolov8\")" 209 | ], 210 | "metadata": { 211 | "colab": { 212 | "base_uri": "https://localhost:8080/" 213 | }, 214 | "id": "qj7hD8nCsso7", 215 | "outputId": "bfbd1f51-a5a7-4798-90b0-9a3341821ea5" 216 | }, 217 | "execution_count": null, 218 | "outputs": [ 219 | { 220 | "output_type": "stream", 221 | "name": "stdout", 222 | "text": [ 223 | "loading Roboflow workspace...\n", 224 | "loading Roboflow project...\n", 225 | "Dependency ultralytics==8.0.134 is required but found version=8.0.190, to fix: `pip install ultralytics==8.0.134`\n" 226 | ] 227 | }, 228 | { 229 | "output_type": "stream", 230 | "name": "stderr", 231 | "text": [ 232 | "Downloading Dataset Version Zip in License-Plate-Recognition-4 to yolov8:: 100%|██████████| 974784/974784 [01:30<00:00, 10816.72it/s]" 233 | ] 234 | }, 235 | { 236 | "output_type": "stream", 237 | "name": "stdout", 238 | "text": [ 239 | "\n" 240 | ] 241 | }, 242 | { 243 | "output_type": "stream", 244 | "name": "stderr", 245 | "text": [ 246 | "\n", 247 | "Extracting Dataset Version Zip to License-Plate-Recognition-4 in yolov8:: 100%|██████████| 48488/48488 [07:19<00:00, 110.32it/s]\n" 248 | ] 249 | } 250 | ] 251 | }, 252 | { 253 | "cell_type": "code", 254 | "source": [ 255 | "%cd {Home}\n", 256 | "from ultralytics import YOLO\n", 257 | "# Load a model\n", 258 | "model = YOLO('yolov8m.pt') # load a pretrained model (recommended for training)\n", 259 | "\n", 260 | "data_path= '/content/drive/MyDrive/Object_Detection/License_Plate_Recognition/DataSets/License-Plate-Recognition-4/data.yaml'\n", 261 | "# Train the model\n", 262 | "result = model.train(data= data_path , epochs=25, imgsz=600,plots=True)" 263 | ], 264 | "metadata": { 265 | "colab": { 266 | "base_uri": "https://localhost:8080/" 267 | }, 268 | "id": "N1G1_4Zksvb4", 269 | "outputId": "264fd526-e7d1-4c08-c054-1fe9fc14eb14" 270 | }, 271 | "execution_count": null, 272 | "outputs": [ 273 | { 274 | "output_type": "stream", 275 | "name": "stdout", 276 | "text": [ 277 | "/content/drive/MyDrive/Object_Detection/License_Plate_Recognition\n" 278 | ] 279 | }, 280 | { 281 | "output_type": "stream", 282 | "name": "stderr", 283 | "text": [ 284 | "Ultralytics YOLOv8.0.190 🚀 Python-3.10.12 torch-2.0.1+cu118 CUDA:0 (Tesla T4, 15102MiB)\n", 285 | "\u001b[34m\u001b[1mengine/trainer: \u001b[0mtask=detect, mode=train, model=yolov8m.pt, data=/content/drive/MyDrive/Object_Detection/License_Plate_Recognition/DataSets/License-Plate-Recognition-4/data.yaml, epochs=25, patience=50, batch=16, imgsz=600, save=True, save_period=-1, cache=False, device=None, workers=8, project=None, name=None, exist_ok=False, pretrained=True, optimizer=auto, verbose=True, seed=0, deterministic=True, single_cls=False, rect=False, cos_lr=False, close_mosaic=10, resume=False, amp=True, fraction=1.0, profile=False, freeze=None, overlap_mask=True, mask_ratio=4, dropout=0.0, val=True, split=val, save_json=False, save_hybrid=False, conf=None, iou=0.7, max_det=300, half=False, dnn=False, plots=True, source=None, show=False, save_txt=False, save_conf=False, save_crop=False, show_labels=True, show_conf=True, vid_stride=1, stream_buffer=False, line_width=None, visualize=False, augment=False, agnostic_nms=False, classes=None, retina_masks=False, boxes=True, format=torchscript, keras=False, optimize=False, int8=False, dynamic=False, simplify=False, opset=None, workspace=4, nms=False, lr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=7.5, cls=0.5, dfl=1.5, pose=12.0, kobj=1.0, label_smoothing=0.0, nbs=64, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0, cfg=None, tracker=botsort.yaml, save_dir=runs/detect/train3\n", 286 | "Downloading https://ultralytics.com/assets/Arial.ttf to '/root/.config/Ultralytics/Arial.ttf'...\n", 287 | "100%|██████████| 755k/755k [00:00<00:00, 103MB/s]\n", 288 | "Overriding model.yaml nc=80 with nc=1\n", 289 | "\n", 290 | " from n params module arguments \n", 291 | " 0 -1 1 1392 ultralytics.nn.modules.conv.Conv [3, 48, 3, 2] \n", 292 | " 1 -1 1 41664 ultralytics.nn.modules.conv.Conv [48, 96, 3, 2] \n", 293 | " 2 -1 2 111360 ultralytics.nn.modules.block.C2f [96, 96, 2, True] \n", 294 | " 3 -1 1 166272 ultralytics.nn.modules.conv.Conv [96, 192, 3, 2] \n", 295 | " 4 -1 4 813312 ultralytics.nn.modules.block.C2f [192, 192, 4, True] \n", 296 | " 5 -1 1 664320 ultralytics.nn.modules.conv.Conv [192, 384, 3, 2] \n", 297 | " 6 -1 4 3248640 ultralytics.nn.modules.block.C2f [384, 384, 4, True] \n", 298 | " 7 -1 1 1991808 ultralytics.nn.modules.conv.Conv [384, 576, 3, 2] \n", 299 | " 8 -1 2 3985920 ultralytics.nn.modules.block.C2f [576, 576, 2, True] \n", 300 | " 9 -1 1 831168 ultralytics.nn.modules.block.SPPF [576, 576, 5] \n", 301 | " 10 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", 302 | " 11 [-1, 6] 1 0 ultralytics.nn.modules.conv.Concat [1] \n", 303 | " 12 -1 2 1993728 ultralytics.nn.modules.block.C2f [960, 384, 2] \n", 304 | " 13 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", 305 | " 14 [-1, 4] 1 0 ultralytics.nn.modules.conv.Concat [1] \n", 306 | " 15 -1 2 517632 ultralytics.nn.modules.block.C2f [576, 192, 2] \n", 307 | " 16 -1 1 332160 ultralytics.nn.modules.conv.Conv [192, 192, 3, 2] \n", 308 | " 17 [-1, 12] 1 0 ultralytics.nn.modules.conv.Concat [1] \n", 309 | " 18 -1 2 1846272 ultralytics.nn.modules.block.C2f [576, 384, 2] \n", 310 | " 19 -1 1 1327872 ultralytics.nn.modules.conv.Conv [384, 384, 3, 2] \n", 311 | " 20 [-1, 9] 1 0 ultralytics.nn.modules.conv.Concat [1] \n", 312 | " 21 -1 2 4207104 ultralytics.nn.modules.block.C2f [960, 576, 2] \n", 313 | " 22 [15, 18, 21] 1 3776275 ultralytics.nn.modules.head.Detect [1, [192, 384, 576]] \n", 314 | "Model summary: 295 layers, 25856899 parameters, 25856883 gradients, 79.1 GFLOPs\n", 315 | "\n", 316 | "Transferred 469/475 items from pretrained weights\n", 317 | "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/detect/train3', view at http://localhost:6006/\n", 318 | "Freezing layer 'model.22.dfl.conv.weight'\n", 319 | "\u001b[34m\u001b[1mAMP: \u001b[0mrunning Automatic Mixed Precision (AMP) checks with YOLOv8n...\n", 320 | "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n.pt to 'yolov8n.pt'...\n", 321 | "100%|██████████| 6.23M/6.23M [00:00<00:00, 8.21MB/s]\n", 322 | "\u001b[34m\u001b[1mAMP: \u001b[0mchecks passed ✅\n", 323 | "WARNING ⚠️ imgsz=[600] must be multiple of max stride 32, updating to [608]\n", 324 | "\u001b[34m\u001b[1mtrain: \u001b[0mScanning /content/drive/MyDrive/Object_Detection/License_Plate_Recognition/DataSets/License-Plate-Recognition-4/train/labels... 21173 images, 28 backgrounds, 0 corrupt: 100%|██████████| 21173/21173 [01:51<00:00, 190.46it/s]\n", 325 | "\u001b[34m\u001b[1mtrain: \u001b[0mNew cache created: /content/drive/MyDrive/Object_Detection/License_Plate_Recognition/DataSets/License-Plate-Recognition-4/train/labels.cache\n", 326 | "\u001b[34m\u001b[1malbumentations: \u001b[0mBlur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01), CLAHE(p=0.01, clip_limit=(1, 4.0), tile_grid_size=(8, 8))\n", 327 | "\u001b[34m\u001b[1mval: \u001b[0mScanning /content/drive/MyDrive/Object_Detection/License_Plate_Recognition/DataSets/License-Plate-Recognition-4/valid/labels... 2046 images, 3 backgrounds, 0 corrupt: 100%|██████████| 2046/2046 [00:10<00:00, 199.53it/s]\n", 328 | "\u001b[34m\u001b[1mval: \u001b[0mNew cache created: /content/drive/MyDrive/Object_Detection/License_Plate_Recognition/DataSets/License-Plate-Recognition-4/valid/labels.cache\n", 329 | "Plotting labels to runs/detect/train3/labels.jpg... \n", 330 | "\u001b[34m\u001b[1moptimizer:\u001b[0m 'optimizer=auto' found, ignoring 'lr0=0.01' and 'momentum=0.937' and determining best 'optimizer', 'lr0' and 'momentum' automatically... \n", 331 | "\u001b[34m\u001b[1moptimizer:\u001b[0m AdamW(lr=0.002, momentum=0.9) with parameter groups 77 weight(decay=0.0), 84 weight(decay=0.0005), 83 bias(decay=0.0)\n", 332 | "Image sizes 608 train, 608 val\n", 333 | "Using 2 dataloader workers\n", 334 | "Logging results to \u001b[1mruns/detect/train3\u001b[0m\n", 335 | "Starting training for 25 epochs...\n", 336 | "\n", 337 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 338 | " 1/25 6.32G 1.333 0.9114 1.372 13 608: 100%|██████████| 1324/1324 [11:15<00:00, 1.96it/s]\n", 339 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:34<00:00, 1.84it/s]\n", 340 | " all 2046 2132 0.907 0.836 0.901 0.557\n", 341 | "\n", 342 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 343 | " 2/25 6.53G 1.308 0.8146 1.351 11 608: 100%|██████████| 1324/1324 [10:54<00:00, 2.02it/s]\n", 344 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:32<00:00, 1.96it/s]\n", 345 | " all 2046 2132 0.964 0.887 0.947 0.578\n", 346 | "\n", 347 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 348 | " 3/25 6.57G 1.268 0.7653 1.325 10 608: 100%|██████████| 1324/1324 [10:47<00:00, 2.04it/s]\n", 349 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:32<00:00, 1.96it/s]\n", 350 | " all 2046 2132 0.952 0.907 0.955 0.58\n", 351 | "\n", 352 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 353 | " 4/25 6.58G 1.221 0.7089 1.293 12 608: 100%|██████████| 1324/1324 [10:47<00:00, 2.05it/s]\n", 354 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:32<00:00, 1.94it/s]\n", 355 | " all 2046 2132 0.959 0.912 0.952 0.602\n", 356 | "\n", 357 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 358 | " 5/25 6.59G 1.208 0.6789 1.281 8 608: 100%|██████████| 1324/1324 [10:46<00:00, 2.05it/s]\n", 359 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:33<00:00, 1.92it/s]\n", 360 | " all 2046 2132 0.965 0.929 0.962 0.625\n", 361 | "\n", 362 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 363 | " 6/25 6.59G 1.178 0.646 1.266 8 608: 100%|██████████| 1324/1324 [10:46<00:00, 2.05it/s]\n", 364 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:32<00:00, 1.96it/s]\n", 365 | " all 2046 2132 0.966 0.927 0.966 0.629\n", 366 | "\n", 367 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 368 | " 7/25 6.6G 1.159 0.6189 1.252 9 608: 100%|██████████| 1324/1324 [10:50<00:00, 2.04it/s]\n", 369 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:33<00:00, 1.93it/s]\n", 370 | " all 2046 2132 0.96 0.944 0.971 0.657\n", 371 | "\n", 372 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 373 | " 8/25 6.46G 1.139 0.6033 1.237 11 608: 100%|██████████| 1324/1324 [10:49<00:00, 2.04it/s]\n", 374 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:32<00:00, 2.00it/s]\n", 375 | " all 2046 2132 0.975 0.939 0.977 0.655\n", 376 | "\n", 377 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 378 | " 9/25 6.6G 1.133 0.5832 1.232 11 608: 100%|██████████| 1324/1324 [10:37<00:00, 2.08it/s]\n", 379 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:33<00:00, 1.92it/s]\n", 380 | " all 2046 2132 0.939 0.95 0.972 0.657\n", 381 | "\n", 382 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 383 | " 10/25 6.6G 1.124 0.5673 1.231 15 608: 100%|██████████| 1324/1324 [10:47<00:00, 2.05it/s]\n", 384 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:32<00:00, 1.95it/s]\n", 385 | " all 2046 2132 0.966 0.947 0.971 0.65\n", 386 | "\n", 387 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 388 | " 11/25 6.6G 1.108 0.5569 1.216 11 608: 100%|██████████| 1324/1324 [10:41<00:00, 2.06it/s]\n", 389 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:32<00:00, 1.98it/s]\n", 390 | " all 2046 2132 0.977 0.942 0.976 0.661\n", 391 | "\n", 392 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 393 | " 12/25 6.6G 1.093 0.5394 1.212 8 608: 100%|██████████| 1324/1324 [10:46<00:00, 2.05it/s]\n", 394 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:33<00:00, 1.92it/s]\n", 395 | " all 2046 2132 0.965 0.958 0.98 0.673\n", 396 | "\n", 397 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 398 | " 13/25 6.6G 1.083 0.5274 1.203 8 608: 100%|██████████| 1324/1324 [11:01<00:00, 2.00it/s]\n", 399 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:32<00:00, 1.98it/s]\n", 400 | " all 2046 2132 0.972 0.952 0.979 0.662\n", 401 | "\n", 402 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 403 | " 14/25 6.6G 1.07 0.5142 1.194 8 608: 100%|██████████| 1324/1324 [10:41<00:00, 2.06it/s]\n", 404 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:33<00:00, 1.93it/s]\n", 405 | " all 2046 2132 0.974 0.959 0.98 0.669\n", 406 | "\n", 407 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 408 | " 15/25 6.6G 1.066 0.5054 1.19 7 608: 100%|██████████| 1324/1324 [10:41<00:00, 2.06it/s]\n", 409 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:32<00:00, 1.96it/s]\n", 410 | " all 2046 2132 0.971 0.959 0.982 0.686\n", 411 | "Closing dataloader mosaic\n", 412 | "\u001b[34m\u001b[1malbumentations: \u001b[0mBlur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01), CLAHE(p=0.01, clip_limit=(1, 4.0), tile_grid_size=(8, 8))\n", 413 | "\n", 414 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 415 | " 16/25 6.59G 1.049 0.4291 1.206 5 608: 100%|██████████| 1324/1324 [10:30<00:00, 2.10it/s]\n", 416 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:32<00:00, 1.95it/s]\n", 417 | " all 2046 2132 0.973 0.963 0.984 0.697\n", 418 | "\n", 419 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 420 | " 17/25 6.6G 1.036 0.4164 1.197 5 608: 100%|██████████| 1324/1324 [10:26<00:00, 2.11it/s]\n", 421 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:33<00:00, 1.93it/s]\n", 422 | " all 2046 2132 0.968 0.971 0.985 0.69\n", 423 | "\n", 424 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 425 | " 18/25 6.59G 1.019 0.4036 1.194 7 608: 100%|██████████| 1324/1324 [10:26<00:00, 2.11it/s]\n", 426 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:31<00:00, 2.01it/s]\n", 427 | " all 2046 2132 0.971 0.968 0.985 0.692\n", 428 | "\n", 429 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 430 | " 19/25 6.59G 1.008 0.3952 1.183 5 608: 100%|██████████| 1324/1324 [10:31<00:00, 2.10it/s]\n", 431 | " Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 64/64 [00:32<00:00, 1.96it/s]\n", 432 | " all 2046 2132 0.974 0.967 0.985 0.702\n", 433 | "\n", 434 | " Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size\n", 435 | " 20/25 6.56G 0.9959 0.3816 1.182 14 608: 29%|██▉ | 387/1324 [03:04<07:27, 2.09it/s]\n", 436 | "ERROR:root:Internal Python error in the inspect module.\n", 437 | "Below is the traceback from this internal error.\n", 438 | "\n", 439 | "Custom TB Handler failed, unregistering\n", 440 | "ERROR:root:Internal Python error in the inspect module.\n", 441 | "Below is the traceback from this internal error.\n", 442 | "\n", 443 | "ERROR:root:Internal Python error in the inspect module.\n", 444 | "Below is the traceback from this internal error.\n", 445 | "\n", 446 | "ERROR:root:Internal Python error in the inspect module.\n", 447 | "Below is the traceback from this internal error.\n", 448 | "\n" 449 | ] 450 | }, 451 | { 452 | "output_type": "stream", 453 | "name": "stdout", 454 | "text": [ 455 | "Traceback (most recent call last):\n", 456 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 3553, in run_code\n", 457 | " exec(code_obj, self.user_global_ns, self.user_ns)\n", 458 | " File \"\", line 8, in \n", 459 | " result = model.train(data= data_path , epochs=25, imgsz=600,plots=True)\n", 460 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/engine/model.py\", line 334, in train\n", 461 | " self.trainer.train()\n", 462 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/engine/trainer.py\", line 195, in train\n", 463 | " self._do_train(world_size)\n", 464 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/engine/trainer.py\", line 331, in _do_train\n", 465 | " for i, batch in pbar:\n", 466 | " File \"/usr/local/lib/python3.10/dist-packages/tqdm/std.py\", line 1182, in __iter__\n", 467 | " for obj in iterable:\n", 468 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/build.py\", line 38, in __iter__\n", 469 | " yield next(self.iterator)\n", 470 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py\", line 633, in __next__\n", 471 | " data = self._next_data()\n", 472 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py\", line 1325, in _next_data\n", 473 | " return self._process_data(data)\n", 474 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py\", line 1371, in _process_data\n", 475 | " data.reraise()\n", 476 | " File \"/usr/local/lib/python3.10/dist-packages/torch/_utils.py\", line 644, in reraise\n", 477 | " raise exception\n", 478 | "FileNotFoundError: Caught FileNotFoundError in DataLoader worker process 1.\n", 479 | "Original Traceback (most recent call last):\n", 480 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/_utils/worker.py\", line 308, in _worker_loop\n", 481 | " data = fetcher.fetch(index)\n", 482 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/_utils/fetch.py\", line 51, in fetch\n", 483 | " data = [self.dataset[idx] for idx in possibly_batched_index]\n", 484 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/_utils/fetch.py\", line 51, in \n", 485 | " data = [self.dataset[idx] for idx in possibly_batched_index]\n", 486 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/base.py\", line 241, in __getitem__\n", 487 | " return self.transforms(self.get_image_and_label(index))\n", 488 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/base.py\", line 247, in get_image_and_label\n", 489 | " label['img'], label['ori_shape'], label['resized_shape'] = self.load_image(index)\n", 490 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/base.py\", line 152, in load_image\n", 491 | " raise FileNotFoundError(f'Image Not Found {f}')\n", 492 | "FileNotFoundError: Image Not Found /content/drive/MyDrive/Object_Detection/License_Plate_Recognition/DataSets/License-Plate-Recognition-4/train/images/Car-20License-20Plate-20Detection-20_-20Kaggle_jpg.rf.2300c7376c9d162c31ea0cb34b951a67.jpg\n", 493 | "\n", 494 | "\n", 495 | "During handling of the above exception, another exception occurred:\n", 496 | "\n", 497 | "Traceback (most recent call last):\n", 498 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1101, in get_records\n", 499 | " return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)\n", 500 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 248, in wrapped\n", 501 | " return f(*args, **kwargs)\n", 502 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 281, in _fixed_getinnerframes\n", 503 | " records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))\n", 504 | " File \"/usr/lib/python3.10/inspect.py\", line 1662, in getinnerframes\n", 505 | " frameinfo = (tb.tb_frame,) + getframeinfo(tb, context)\n", 506 | " File \"/usr/lib/python3.10/inspect.py\", line 1620, in getframeinfo\n", 507 | " filename = getsourcefile(frame) or getfile(frame)\n", 508 | " File \"/usr/lib/python3.10/inspect.py\", line 829, in getsourcefile\n", 509 | " module = getmodule(object, filename)\n", 510 | " File \"/usr/lib/python3.10/inspect.py\", line 861, in getmodule\n", 511 | " file = getabsfile(object, _filename)\n", 512 | " File \"/usr/lib/python3.10/inspect.py\", line 845, in getabsfile\n", 513 | " return os.path.normcase(os.path.abspath(_filename))\n", 514 | " File \"/usr/lib/python3.10/posixpath.py\", line 384, in abspath\n", 515 | " cwd = os.getcwd()\n", 516 | "OSError: [Errno 107] Transport endpoint is not connected\n", 517 | "Traceback (most recent call last):\n", 518 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 3553, in run_code\n", 519 | " exec(code_obj, self.user_global_ns, self.user_ns)\n", 520 | " File \"\", line 8, in \n", 521 | " result = model.train(data= data_path , epochs=25, imgsz=600,plots=True)\n", 522 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/engine/model.py\", line 334, in train\n", 523 | " self.trainer.train()\n", 524 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/engine/trainer.py\", line 195, in train\n", 525 | " self._do_train(world_size)\n", 526 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/engine/trainer.py\", line 331, in _do_train\n", 527 | " for i, batch in pbar:\n", 528 | " File \"/usr/local/lib/python3.10/dist-packages/tqdm/std.py\", line 1182, in __iter__\n", 529 | " for obj in iterable:\n", 530 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/build.py\", line 38, in __iter__\n", 531 | " yield next(self.iterator)\n", 532 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py\", line 633, in __next__\n", 533 | " data = self._next_data()\n", 534 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py\", line 1325, in _next_data\n", 535 | " return self._process_data(data)\n", 536 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py\", line 1371, in _process_data\n", 537 | " data.reraise()\n", 538 | " File \"/usr/local/lib/python3.10/dist-packages/torch/_utils.py\", line 644, in reraise\n", 539 | " raise exception\n", 540 | "FileNotFoundError: Caught FileNotFoundError in DataLoader worker process 1.\n", 541 | "Original Traceback (most recent call last):\n", 542 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/_utils/worker.py\", line 308, in _worker_loop\n", 543 | " data = fetcher.fetch(index)\n", 544 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/_utils/fetch.py\", line 51, in fetch\n", 545 | " data = [self.dataset[idx] for idx in possibly_batched_index]\n", 546 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/_utils/fetch.py\", line 51, in \n", 547 | " data = [self.dataset[idx] for idx in possibly_batched_index]\n", 548 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/base.py\", line 241, in __getitem__\n", 549 | " return self.transforms(self.get_image_and_label(index))\n", 550 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/base.py\", line 247, in get_image_and_label\n", 551 | " label['img'], label['ori_shape'], label['resized_shape'] = self.load_image(index)\n", 552 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/base.py\", line 152, in load_image\n", 553 | " raise FileNotFoundError(f'Image Not Found {f}')\n", 554 | "FileNotFoundError: Image Not Found /content/drive/MyDrive/Object_Detection/License_Plate_Recognition/DataSets/License-Plate-Recognition-4/train/images/Car-20License-20Plate-20Detection-20_-20Kaggle_jpg.rf.2300c7376c9d162c31ea0cb34b951a67.jpg\n", 555 | "\n", 556 | "\n", 557 | "During handling of the above exception, another exception occurred:\n", 558 | "\n", 559 | "Traceback (most recent call last):\n", 560 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 1972, in wrapped\n", 561 | " stb = handler(self,etype,value,tb,tb_offset=tb_offset)\n", 562 | " File \"/usr/local/lib/python3.10/dist-packages/dask/base.py\", line 79, in _clean_ipython_traceback\n", 563 | " stb = self.InteractiveTB.structured_traceback(\n", 564 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1367, in structured_traceback\n", 565 | " return FormattedTB.structured_traceback(\n", 566 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1267, in structured_traceback\n", 567 | " return VerboseTB.structured_traceback(\n", 568 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1124, in structured_traceback\n", 569 | " formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,\n", 570 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1082, in format_exception_as_a_whole\n", 571 | " last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)\n", 572 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 382, in find_recursion\n", 573 | " return len(records), 0\n", 574 | "TypeError: object of type 'NoneType' has no len()\n", 575 | "\n", 576 | "During handling of the above exception, another exception occurred:\n", 577 | "\n", 578 | "Traceback (most recent call last):\n", 579 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1101, in get_records\n", 580 | " return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)\n", 581 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 248, in wrapped\n", 582 | " return f(*args, **kwargs)\n", 583 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 281, in _fixed_getinnerframes\n", 584 | " records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))\n", 585 | " File \"/usr/lib/python3.10/inspect.py\", line 1662, in getinnerframes\n", 586 | " frameinfo = (tb.tb_frame,) + getframeinfo(tb, context)\n", 587 | " File \"/usr/lib/python3.10/inspect.py\", line 1620, in getframeinfo\n", 588 | " filename = getsourcefile(frame) or getfile(frame)\n", 589 | " File \"/usr/lib/python3.10/inspect.py\", line 829, in getsourcefile\n", 590 | " module = getmodule(object, filename)\n", 591 | " File \"/usr/lib/python3.10/inspect.py\", line 861, in getmodule\n", 592 | " file = getabsfile(object, _filename)\n", 593 | " File \"/usr/lib/python3.10/inspect.py\", line 845, in getabsfile\n", 594 | " return os.path.normcase(os.path.abspath(_filename))\n", 595 | " File \"/usr/lib/python3.10/posixpath.py\", line 384, in abspath\n", 596 | " cwd = os.getcwd()\n", 597 | "OSError: [Errno 107] Transport endpoint is not connected\n", 598 | "Traceback (most recent call last):\n", 599 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 3553, in run_code\n", 600 | " exec(code_obj, self.user_global_ns, self.user_ns)\n", 601 | " File \"\", line 8, in \n", 602 | " result = model.train(data= data_path , epochs=25, imgsz=600,plots=True)\n", 603 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/engine/model.py\", line 334, in train\n", 604 | " self.trainer.train()\n", 605 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/engine/trainer.py\", line 195, in train\n", 606 | " self._do_train(world_size)\n", 607 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/engine/trainer.py\", line 331, in _do_train\n", 608 | " for i, batch in pbar:\n", 609 | " File \"/usr/local/lib/python3.10/dist-packages/tqdm/std.py\", line 1182, in __iter__\n", 610 | " for obj in iterable:\n", 611 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/build.py\", line 38, in __iter__\n", 612 | " yield next(self.iterator)\n", 613 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py\", line 633, in __next__\n", 614 | " data = self._next_data()\n", 615 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py\", line 1325, in _next_data\n", 616 | " return self._process_data(data)\n", 617 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py\", line 1371, in _process_data\n", 618 | " data.reraise()\n", 619 | " File \"/usr/local/lib/python3.10/dist-packages/torch/_utils.py\", line 644, in reraise\n", 620 | " raise exception\n", 621 | "FileNotFoundError: Caught FileNotFoundError in DataLoader worker process 1.\n", 622 | "Original Traceback (most recent call last):\n", 623 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/_utils/worker.py\", line 308, in _worker_loop\n", 624 | " data = fetcher.fetch(index)\n", 625 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/_utils/fetch.py\", line 51, in fetch\n", 626 | " data = [self.dataset[idx] for idx in possibly_batched_index]\n", 627 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/_utils/fetch.py\", line 51, in \n", 628 | " data = [self.dataset[idx] for idx in possibly_batched_index]\n", 629 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/base.py\", line 241, in __getitem__\n", 630 | " return self.transforms(self.get_image_and_label(index))\n", 631 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/base.py\", line 247, in get_image_and_label\n", 632 | " label['img'], label['ori_shape'], label['resized_shape'] = self.load_image(index)\n", 633 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/base.py\", line 152, in load_image\n", 634 | " raise FileNotFoundError(f'Image Not Found {f}')\n", 635 | "FileNotFoundError: Image Not Found /content/drive/MyDrive/Object_Detection/License_Plate_Recognition/DataSets/License-Plate-Recognition-4/train/images/Car-20License-20Plate-20Detection-20_-20Kaggle_jpg.rf.2300c7376c9d162c31ea0cb34b951a67.jpg\n", 636 | "\n", 637 | "\n", 638 | "During handling of the above exception, another exception occurred:\n", 639 | "\n", 640 | "Traceback (most recent call last):\n", 641 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 1972, in wrapped\n", 642 | " stb = handler(self,etype,value,tb,tb_offset=tb_offset)\n", 643 | " File \"/usr/local/lib/python3.10/dist-packages/dask/base.py\", line 79, in _clean_ipython_traceback\n", 644 | " stb = self.InteractiveTB.structured_traceback(\n", 645 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1367, in structured_traceback\n", 646 | " return FormattedTB.structured_traceback(\n", 647 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1267, in structured_traceback\n", 648 | " return VerboseTB.structured_traceback(\n", 649 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1124, in structured_traceback\n", 650 | " formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,\n", 651 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1082, in format_exception_as_a_whole\n", 652 | " last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)\n", 653 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 382, in find_recursion\n", 654 | " return len(records), 0\n", 655 | "TypeError: object of type 'NoneType' has no len()\n", 656 | "\n", 657 | "During handling of the above exception, another exception occurred:\n", 658 | "\n", 659 | "Traceback (most recent call last):\n", 660 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 3473, in run_ast_nodes\n", 661 | " if (await self.run_code(code, result, async_=asy)):\n", 662 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 3571, in run_code\n", 663 | " self.CustomTB(etype, value, tb)\n", 664 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 1979, in wrapped\n", 665 | " stb = self.InteractiveTB.structured_traceback(*sys.exc_info())\n", 666 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1367, in structured_traceback\n", 667 | " return FormattedTB.structured_traceback(\n", 668 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1267, in structured_traceback\n", 669 | " return VerboseTB.structured_traceback(\n", 670 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1142, in structured_traceback\n", 671 | " formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,\n", 672 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1082, in format_exception_as_a_whole\n", 673 | " last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)\n", 674 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 382, in find_recursion\n", 675 | " return len(records), 0\n", 676 | "TypeError: object of type 'NoneType' has no len()\n", 677 | "\n", 678 | "During handling of the above exception, another exception occurred:\n", 679 | "\n", 680 | "Traceback (most recent call last):\n", 681 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 2099, in showtraceback\n", 682 | " stb = value._render_traceback_()\n", 683 | "AttributeError: 'TypeError' object has no attribute '_render_traceback_'\n", 684 | "\n", 685 | "During handling of the above exception, another exception occurred:\n", 686 | "\n", 687 | "Traceback (most recent call last):\n", 688 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1101, in get_records\n", 689 | " return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)\n", 690 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 248, in wrapped\n", 691 | " return f(*args, **kwargs)\n", 692 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 281, in _fixed_getinnerframes\n", 693 | " records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))\n", 694 | " File \"/usr/lib/python3.10/inspect.py\", line 1662, in getinnerframes\n", 695 | " frameinfo = (tb.tb_frame,) + getframeinfo(tb, context)\n", 696 | " File \"/usr/lib/python3.10/inspect.py\", line 1620, in getframeinfo\n", 697 | " filename = getsourcefile(frame) or getfile(frame)\n", 698 | " File \"/usr/lib/python3.10/inspect.py\", line 829, in getsourcefile\n", 699 | " module = getmodule(object, filename)\n", 700 | " File \"/usr/lib/python3.10/inspect.py\", line 861, in getmodule\n", 701 | " file = getabsfile(object, _filename)\n", 702 | " File \"/usr/lib/python3.10/inspect.py\", line 845, in getabsfile\n", 703 | " return os.path.normcase(os.path.abspath(_filename))\n", 704 | " File \"/usr/lib/python3.10/posixpath.py\", line 384, in abspath\n", 705 | " cwd = os.getcwd()\n", 706 | "OSError: [Errno 107] Transport endpoint is not connected\n", 707 | "Traceback (most recent call last):\n", 708 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 3553, in run_code\n", 709 | " exec(code_obj, self.user_global_ns, self.user_ns)\n", 710 | " File \"\", line 8, in \n", 711 | " result = model.train(data= data_path , epochs=25, imgsz=600,plots=True)\n", 712 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/engine/model.py\", line 334, in train\n", 713 | " self.trainer.train()\n", 714 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/engine/trainer.py\", line 195, in train\n", 715 | " self._do_train(world_size)\n", 716 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/engine/trainer.py\", line 331, in _do_train\n", 717 | " for i, batch in pbar:\n", 718 | " File \"/usr/local/lib/python3.10/dist-packages/tqdm/std.py\", line 1182, in __iter__\n", 719 | " for obj in iterable:\n", 720 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/build.py\", line 38, in __iter__\n", 721 | " yield next(self.iterator)\n", 722 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py\", line 633, in __next__\n", 723 | " data = self._next_data()\n", 724 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py\", line 1325, in _next_data\n", 725 | " return self._process_data(data)\n", 726 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py\", line 1371, in _process_data\n", 727 | " data.reraise()\n", 728 | " File \"/usr/local/lib/python3.10/dist-packages/torch/_utils.py\", line 644, in reraise\n", 729 | " raise exception\n", 730 | "FileNotFoundError: Caught FileNotFoundError in DataLoader worker process 1.\n", 731 | "Original Traceback (most recent call last):\n", 732 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/_utils/worker.py\", line 308, in _worker_loop\n", 733 | " data = fetcher.fetch(index)\n", 734 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/_utils/fetch.py\", line 51, in fetch\n", 735 | " data = [self.dataset[idx] for idx in possibly_batched_index]\n", 736 | " File \"/usr/local/lib/python3.10/dist-packages/torch/utils/data/_utils/fetch.py\", line 51, in \n", 737 | " data = [self.dataset[idx] for idx in possibly_batched_index]\n", 738 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/base.py\", line 241, in __getitem__\n", 739 | " return self.transforms(self.get_image_and_label(index))\n", 740 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/base.py\", line 247, in get_image_and_label\n", 741 | " label['img'], label['ori_shape'], label['resized_shape'] = self.load_image(index)\n", 742 | " File \"/usr/local/lib/python3.10/dist-packages/ultralytics/data/base.py\", line 152, in load_image\n", 743 | " raise FileNotFoundError(f'Image Not Found {f}')\n", 744 | "FileNotFoundError: Image Not Found /content/drive/MyDrive/Object_Detection/License_Plate_Recognition/DataSets/License-Plate-Recognition-4/train/images/Car-20License-20Plate-20Detection-20_-20Kaggle_jpg.rf.2300c7376c9d162c31ea0cb34b951a67.jpg\n", 745 | "\n", 746 | "\n", 747 | "During handling of the above exception, another exception occurred:\n", 748 | "\n", 749 | "Traceback (most recent call last):\n", 750 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 1972, in wrapped\n", 751 | " stb = handler(self,etype,value,tb,tb_offset=tb_offset)\n", 752 | " File \"/usr/local/lib/python3.10/dist-packages/dask/base.py\", line 79, in _clean_ipython_traceback\n", 753 | " stb = self.InteractiveTB.structured_traceback(\n", 754 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1367, in structured_traceback\n", 755 | " return FormattedTB.structured_traceback(\n", 756 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1267, in structured_traceback\n", 757 | " return VerboseTB.structured_traceback(\n", 758 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1124, in structured_traceback\n", 759 | " formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,\n", 760 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1082, in format_exception_as_a_whole\n", 761 | " last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)\n", 762 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 382, in find_recursion\n", 763 | " return len(records), 0\n", 764 | "TypeError: object of type 'NoneType' has no len()\n", 765 | "\n", 766 | "During handling of the above exception, another exception occurred:\n", 767 | "\n", 768 | "Traceback (most recent call last):\n", 769 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 3473, in run_ast_nodes\n", 770 | " if (await self.run_code(code, result, async_=asy)):\n", 771 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 3571, in run_code\n", 772 | " self.CustomTB(etype, value, tb)\n", 773 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 1979, in wrapped\n", 774 | " stb = self.InteractiveTB.structured_traceback(*sys.exc_info())\n", 775 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1367, in structured_traceback\n", 776 | " return FormattedTB.structured_traceback(\n", 777 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1267, in structured_traceback\n", 778 | " return VerboseTB.structured_traceback(\n", 779 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1142, in structured_traceback\n", 780 | " formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,\n", 781 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1082, in format_exception_as_a_whole\n", 782 | " last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)\n", 783 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 382, in find_recursion\n", 784 | " return len(records), 0\n", 785 | "TypeError: object of type 'NoneType' has no len()\n", 786 | "\n", 787 | "During handling of the above exception, another exception occurred:\n", 788 | "\n", 789 | "Traceback (most recent call last):\n", 790 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 2099, in showtraceback\n", 791 | " stb = value._render_traceback_()\n", 792 | "AttributeError: 'TypeError' object has no attribute '_render_traceback_'\n", 793 | "\n", 794 | "During handling of the above exception, another exception occurred:\n", 795 | "\n", 796 | "Traceback (most recent call last):\n", 797 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 3030, in _run_cell\n", 798 | " return runner(coro)\n", 799 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/async_helpers.py\", line 78, in _pseudo_sync_runner\n", 800 | " coro.send(None)\n", 801 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 3257, in run_cell_async\n", 802 | " has_raised = await self.run_ast_nodes(code_ast.body, cell_name,\n", 803 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 3492, in run_ast_nodes\n", 804 | " self.showtraceback()\n", 805 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 2101, in showtraceback\n", 806 | " stb = self.InteractiveTB.structured_traceback(etype,\n", 807 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1367, in structured_traceback\n", 808 | " return FormattedTB.structured_traceback(\n", 809 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1267, in structured_traceback\n", 810 | " return VerboseTB.structured_traceback(\n", 811 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1142, in structured_traceback\n", 812 | " formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,\n", 813 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1082, in format_exception_as_a_whole\n", 814 | " last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)\n", 815 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 382, in find_recursion\n", 816 | " return len(records), 0\n", 817 | "TypeError: object of type 'NoneType' has no len()\n", 818 | "\n", 819 | "During handling of the above exception, another exception occurred:\n", 820 | "\n", 821 | "Traceback (most recent call last):\n", 822 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py\", line 2099, in showtraceback\n", 823 | " stb = value._render_traceback_()\n", 824 | "AttributeError: 'TypeError' object has no attribute '_render_traceback_'\n", 825 | "\n", 826 | "During handling of the above exception, another exception occurred:\n", 827 | "\n", 828 | "Traceback (most recent call last):\n", 829 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 1101, in get_records\n", 830 | " return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)\n", 831 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 248, in wrapped\n", 832 | " return f(*args, **kwargs)\n", 833 | " File \"/usr/local/lib/python3.10/dist-packages/IPython/core/ultratb.py\", line 281, in _fixed_getinnerframes\n", 834 | " records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))\n", 835 | " File \"/usr/lib/python3.10/inspect.py\", line 1662, in getinnerframes\n", 836 | " frameinfo = (tb.tb_frame,) + getframeinfo(tb, context)\n", 837 | " File \"/usr/lib/python3.10/inspect.py\", line 1620, in getframeinfo\n", 838 | " filename = getsourcefile(frame) or getfile(frame)\n", 839 | " File \"/usr/lib/python3.10/inspect.py\", line 829, in getsourcefile\n", 840 | " module = getmodule(object, filename)\n", 841 | " File \"/usr/lib/python3.10/inspect.py\", line 861, in getmodule\n", 842 | " file = getabsfile(object, _filename)\n", 843 | " File \"/usr/lib/python3.10/inspect.py\", line 845, in getabsfile\n", 844 | " return os.path.normcase(os.path.abspath(_filename))\n", 845 | " File \"/usr/lib/python3.10/posixpath.py\", line 384, in abspath\n", 846 | " cwd = os.getcwd()\n", 847 | "OSError: [Errno 107] Transport endpoint is not connected\n" 848 | ] 849 | } 850 | ] 851 | }, 852 | { 853 | "cell_type": "code", 854 | "source": [], 855 | "metadata": { 856 | "id": "wSYIEx1Hu1Ye" 857 | }, 858 | "execution_count": null, 859 | "outputs": [] 860 | } 861 | ] 862 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🚗 Vehicle Detection and License Plate Recognition 🚙 2 | 3 | ## Description 4 | 5 | 📖 This Python code performs vehicle detection and license plate recognition in video footage using the YOLO (You Only Look Once) object detection model and the SORT (Simple Online and Realtime Tracking) algorithm. It reads a video file, detects vehicles and license plates, tracks vehicles across frames, and extracts license plate information. 6 | 7 | ## Features 8 | 9 | 🌟 Key Features: 10 | 11 | - 🚗 Vehicle Detection: Uses the YOLO model to detect vehicles in each frame of the video. 12 | - 🚦 Object Tracking: Applies the SORT algorithm to track vehicles across frames. 13 | - 📝 License Plate Recognition: Detects license plates and reads their text content. 14 | - 💾 Data Export: Stores the results in a CSV file for further analysis. 15 | 16 | ## Output 🚀 17 | 18 | 19 | https://github.com/EmanAbdelWhab/number-plate-recognition-yolov8/assets/103004153/0c60f067-7f0f-4497-8f5a-c59aab292690 20 | 21 | -------------------------------------------------------------------------------- /add_missing_data.py: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "5b25d8b2-e630-4ae8-8002-3638d04d4929", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import csv\n", 11 | "import numpy as np\n", 12 | "from scipy.interpolate import interp1d\n", 13 | "\n", 14 | "\n", 15 | "def interpolate_bounding_boxes(data):\n", 16 | " # Extract necessary data columns from input data\n", 17 | " frame_numbers = np.array([int(row['frame_nmr']) for row in data])\n", 18 | " car_ids = np.array([int(float(row['car_id'])) for row in data])\n", 19 | " car_bboxes = np.array([list(map(float, row['car_bbox'][1:-1].split())) for row in data])\n", 20 | " license_plate_bboxes = np.array([list(map(float, row['license_plate_bbox'][1:-1].split())) for row in data])\n", 21 | "\n", 22 | " interpolated_data = []\n", 23 | " unique_car_ids = np.unique(car_ids)\n", 24 | " for car_id in unique_car_ids:\n", 25 | "\n", 26 | " frame_numbers_ = [p['frame_nmr'] for p in data if int(float(p['car_id'])) == int(float(car_id))]\n", 27 | " print(frame_numbers_, car_id)\n", 28 | "\n", 29 | " # Filter data for a specific car ID\n", 30 | " car_mask = car_ids == car_id\n", 31 | " car_frame_numbers = frame_numbers[car_mask]\n", 32 | " car_bboxes_interpolated = []\n", 33 | " license_plate_bboxes_interpolated = []\n", 34 | "\n", 35 | " first_frame_number = car_frame_numbers[0]\n", 36 | " last_frame_number = car_frame_numbers[-1]\n", 37 | "\n", 38 | " for i in range(len(car_bboxes[car_mask])):\n", 39 | " frame_number = car_frame_numbers[i]\n", 40 | " car_bbox = car_bboxes[car_mask][i]\n", 41 | " license_plate_bbox = license_plate_bboxes[car_mask][i]\n", 42 | "\n", 43 | " if i > 0:\n", 44 | " prev_frame_number = car_frame_numbers[i-1]\n", 45 | " prev_car_bbox = car_bboxes_interpolated[-1]\n", 46 | " prev_license_plate_bbox = license_plate_bboxes_interpolated[-1]\n", 47 | "\n", 48 | " if frame_number - prev_frame_number > 1:\n", 49 | " # Interpolate missing frames' bounding boxes\n", 50 | " frames_gap = frame_number - prev_frame_number\n", 51 | " x = np.array([prev_frame_number, frame_number])\n", 52 | " x_new = np.linspace(prev_frame_number, frame_number, num=frames_gap, endpoint=False)\n", 53 | " interp_func = interp1d(x, np.vstack((prev_car_bbox, car_bbox)), axis=0, kind='linear')\n", 54 | " interpolated_car_bboxes = interp_func(x_new)\n", 55 | " interp_func = interp1d(x, np.vstack((prev_license_plate_bbox, license_plate_bbox)), axis=0, kind='linear')\n", 56 | " interpolated_license_plate_bboxes = interp_func(x_new)\n", 57 | "\n", 58 | " car_bboxes_interpolated.extend(interpolated_car_bboxes[1:])\n", 59 | " license_plate_bboxes_interpolated.extend(interpolated_license_plate_bboxes[1:])\n", 60 | "\n", 61 | " car_bboxes_interpolated.append(car_bbox)\n", 62 | " license_plate_bboxes_interpolated.append(license_plate_bbox)\n", 63 | "\n", 64 | " for i in range(len(car_bboxes_interpolated)):\n", 65 | " frame_number = first_frame_number + i\n", 66 | " row = {}\n", 67 | " row['frame_nmr'] = str(frame_number)\n", 68 | " row['car_id'] = str(car_id)\n", 69 | " row['car_bbox'] = ' '.join(map(str, car_bboxes_interpolated[i]))\n", 70 | " row['license_plate_bbox'] = ' '.join(map(str, license_plate_bboxes_interpolated[i]))\n", 71 | "\n", 72 | " if str(frame_number) not in frame_numbers_:\n", 73 | " # Imputed row, set the following fields to '0'\n", 74 | " row['license_plate_bbox_score'] = '0'\n", 75 | " row['license_number'] = '0'\n", 76 | " row['license_number_score'] = '0'\n", 77 | " else:\n", 78 | " # Original row, retrieve values from the input data if available\n", 79 | " original_row = [p for p in data if int(p['frame_nmr']) == frame_number and int(float(p['car_id'])) == int(float(car_id))][0]\n", 80 | " row['license_plate_bbox_score'] = original_row['license_plate_bbox_score'] if 'license_plate_bbox_score' in original_row else '0'\n", 81 | " row['license_number'] = original_row['license_number'] if 'license_number' in original_row else '0'\n", 82 | " row['license_number_score'] = original_row['license_number_score'] if 'license_number_score' in original_row else '0'\n", 83 | "\n", 84 | " interpolated_data.append(row)\n", 85 | "\n", 86 | " return interpolated_data\n", 87 | "\n", 88 | "\n", 89 | "# Load the CSV file\n", 90 | "with open('test.csv', 'r') as file:\n", 91 | " reader = csv.DictReader(file)\n", 92 | " data = list(reader)\n", 93 | "\n", 94 | "# Interpolate missing data\n", 95 | "interpolated_data = interpolate_bounding_boxes(data)\n", 96 | "\n", 97 | "# Write updated data to a new CSV file\n", 98 | "header = ['frame_nmr', 'car_id', 'car_bbox', 'license_plate_bbox', 'license_plate_bbox_score', 'license_number', 'license_number_score']\n", 99 | "with open('test_interpolated.csv', 'w', newline='') as file:\n", 100 | " writer = csv.DictWriter(file, fieldnames=header)\n", 101 | " writer.writeheader()\n", 102 | " writer.writerows(interpolated_data)" 103 | ] 104 | } 105 | ], 106 | "metadata": { 107 | "kernelspec": { 108 | "display_name": "Python 3 (ipykernel)", 109 | "language": "python", 110 | "name": "python3" 111 | }, 112 | "language_info": { 113 | "codemirror_mode": { 114 | "name": "ipython", 115 | "version": 3 116 | }, 117 | "file_extension": ".py", 118 | "mimetype": "text/x-python", 119 | "name": "python", 120 | "nbconvert_exporter": "python", 121 | "pygments_lexer": "ipython3", 122 | "version": "3.11.5" 123 | } 124 | }, 125 | "nbformat": 4, 126 | "nbformat_minor": 5 127 | } 128 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 5, 6 | "id": "57bb5dcb-6dc4-4720-871c-997601a43951", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "from ultralytics import YOLO\n", 11 | "import cv2\n", 12 | "\n", 13 | "import util\n", 14 | "from sort.sort import *\n", 15 | "from utill import get_car, read_license_plate, write_csv\n", 16 | "\n", 17 | "results= {}\n", 18 | "\n", 19 | "mot_tracker=Sort()\n", 20 | "\n", 21 | "# load models\n", 22 | "coco_model= YOLO('yolov8n.pt')\n", 23 | "license_plate_detector=YOLO('./models/license_plate_detector.pt')\n", 24 | "\n", 25 | "# load video\n", 26 | "cap = cv2.VideoCapture('./sample.mp4')\n", 27 | "\n", 28 | "vehicles = [2, 3, 5, 7] # vehicles classes\n", 29 | "\n", 30 | "# read Frames\n", 31 | "frame_nmr = -1\n", 32 | "ret = True\n", 33 | "while ret:\n", 34 | " frame_nmr += 1\n", 35 | " ret,frame=cap.read()\n", 36 | " if ret:\n", 37 | " results[frame_nmr] = {}\n", 38 | " # detect vehicles\n", 39 | " detections = coco_model(frame)[0]\n", 40 | " detections_ = []\n", 41 | " for detection in detection.boxes.data.tolist():\n", 42 | " x1, y1, x2, y2, score, class_id = detection\n", 43 | " if int(class_id) in vehicles:\n", 44 | " detections_.append([x1, y1, x2, y2, score])\n", 45 | "\n", 46 | " # track vehicles\n", 47 | " track_ids = mot_tracker.update(np.asarray(detections_))\n", 48 | "\n", 49 | " # detect license plates\n", 50 | " license_plates = license_plate_detector(frame)[0]\n", 51 | " for license_plate in license_plates.boxes.data.tolist():\n", 52 | " x1, y1, x2, y2, score, class_id = license_plate\n", 53 | " # assign license plate to car\n", 54 | " xcar1, ycar1, xcar2, ycar2, car_id = get_car(license_plate, track_ids)\n", 55 | "\n", 56 | "\n", 57 | " if car_id != -1 :\n", 58 | "\n", 59 | " # crop license plate\n", 60 | " license_plate_crop = frame[int(y1):int(y2), int(x1): int(x2), :]\n", 61 | "\n", 62 | " # process license plate\n", 63 | " license_plate_crop_gray = cv2.cvtColor(license_plate_crop, cv2.COLOR_BGR2GRAY)\n", 64 | " _, license_plate_crop_thresh = cv2.threshold(license_plate_crop_gray, 64, 255, cv2.THRESH_BINARY_INV)\n", 65 | "\n", 66 | " # read license plate number\n", 67 | " license_plate_text, license_plate_text_score = read_license_plate(license_plate_crop_thresh)\n", 68 | "\n", 69 | " if license_plate_text is not None:\n", 70 | " results[frame_nmr][car_id] = {'car': {'bbox': [xcar1, ycar1, xcar2, ycar2]},\n", 71 | " 'license_plate': {'bbox': [x1, y1, x2, y2],\n", 72 | " 'text': license_plate_text,\n", 73 | " 'bbox_score': score,\n", 74 | " 'text_score': license_plate_text_score}}\n", 75 | "\n", 76 | "# write results\n", 77 | "write_csv(results, './test.csv')" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "id": "996d94da-173d-463c-b340-90629250ad4d", 84 | "metadata": {}, 85 | "outputs": [], 86 | "source": [] 87 | } 88 | ], 89 | "metadata": { 90 | "kernelspec": { 91 | "display_name": "Python 3 (ipykernel)", 92 | "language": "python", 93 | "name": "python3" 94 | }, 95 | "language_info": { 96 | "codemirror_mode": { 97 | "name": "ipython", 98 | "version": 3 99 | }, 100 | "file_extension": ".py", 101 | "mimetype": "text/x-python", 102 | "name": "python", 103 | "nbconvert_exporter": "python", 104 | "pygments_lexer": "ipython3", 105 | "version": "3.11.5" 106 | } 107 | }, 108 | "nbformat": 4, 109 | "nbformat_minor": 5 110 | } 111 | -------------------------------------------------------------------------------- /sort.py: -------------------------------------------------------------------------------- 1 | """ 2 | SORT: A Simple, Online and Realtime Tracker 3 | Copyright (C) 2016-2020 Alex Bewley alex@bewley.ai 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | """ 18 | from __future__ import print_function 19 | 20 | import os 21 | import numpy as np 22 | import matplotlib 23 | matplotlib.use('TkAgg') 24 | import matplotlib.pyplot as plt 25 | import matplotlib.patches as patches 26 | from skimage import io 27 | 28 | import glob 29 | import time 30 | import argparse 31 | from filterpy.kalman import KalmanFilter 32 | 33 | np.random.seed(0) 34 | 35 | 36 | def linear_assignment(cost_matrix): 37 | try: 38 | import lap 39 | _, x, y = lap.lapjv(cost_matrix, extend_cost=True) 40 | return np.array([[y[i],i] for i in x if i >= 0]) # 41 | except ImportError: 42 | from scipy.optimize import linear_sum_assignment 43 | x, y = linear_sum_assignment(cost_matrix) 44 | return np.array(list(zip(x, y))) 45 | 46 | 47 | def iou_batch(bb_test, bb_gt): 48 | """ 49 | From SORT: Computes IOU between two bboxes in the form [x1,y1,x2,y2] 50 | """ 51 | bb_gt = np.expand_dims(bb_gt, 0) 52 | bb_test = np.expand_dims(bb_test, 1) 53 | 54 | xx1 = np.maximum(bb_test[..., 0], bb_gt[..., 0]) 55 | yy1 = np.maximum(bb_test[..., 1], bb_gt[..., 1]) 56 | xx2 = np.minimum(bb_test[..., 2], bb_gt[..., 2]) 57 | yy2 = np.minimum(bb_test[..., 3], bb_gt[..., 3]) 58 | w = np.maximum(0., xx2 - xx1) 59 | h = np.maximum(0., yy2 - yy1) 60 | wh = w * h 61 | o = wh / ((bb_test[..., 2] - bb_test[..., 0]) * (bb_test[..., 3] - bb_test[..., 1]) 62 | + (bb_gt[..., 2] - bb_gt[..., 0]) * (bb_gt[..., 3] - bb_gt[..., 1]) - wh) 63 | return(o) 64 | 65 | 66 | def convert_bbox_to_z(bbox): 67 | """ 68 | Takes a bounding box in the form [x1,y1,x2,y2] and returns z in the form 69 | [x,y,s,r] where x,y is the centre of the box and s is the scale/area and r is 70 | the aspect ratio 71 | """ 72 | w = bbox[2] - bbox[0] 73 | h = bbox[3] - bbox[1] 74 | x = bbox[0] + w/2. 75 | y = bbox[1] + h/2. 76 | s = w * h #scale is just area 77 | r = w / float(h) 78 | return np.array([x, y, s, r]).reshape((4, 1)) 79 | 80 | 81 | def convert_x_to_bbox(x,score=None): 82 | """ 83 | Takes a bounding box in the centre form [x,y,s,r] and returns it in the form 84 | [x1,y1,x2,y2] where x1,y1 is the top left and x2,y2 is the bottom right 85 | """ 86 | w = np.sqrt(x[2] * x[3]) 87 | h = x[2] / w 88 | if(score==None): 89 | return np.array([x[0]-w/2.,x[1]-h/2.,x[0]+w/2.,x[1]+h/2.]).reshape((1,4)) 90 | else: 91 | return np.array([x[0]-w/2.,x[1]-h/2.,x[0]+w/2.,x[1]+h/2.,score]).reshape((1,5)) 92 | 93 | 94 | class KalmanBoxTracker(object): 95 | """ 96 | This class represents the internal state of individual tracked objects observed as bbox. 97 | """ 98 | count = 0 99 | def __init__(self,bbox): 100 | """ 101 | Initialises a tracker using initial bounding box. 102 | """ 103 | #define constant velocity model 104 | self.kf = KalmanFilter(dim_x=7, dim_z=4) 105 | self.kf.F = np.array([[1,0,0,0,1,0,0],[0,1,0,0,0,1,0],[0,0,1,0,0,0,1],[0,0,0,1,0,0,0], [0,0,0,0,1,0,0],[0,0,0,0,0,1,0],[0,0,0,0,0,0,1]]) 106 | self.kf.H = np.array([[1,0,0,0,0,0,0],[0,1,0,0,0,0,0],[0,0,1,0,0,0,0],[0,0,0,1,0,0,0]]) 107 | 108 | self.kf.R[2:,2:] *= 10. 109 | self.kf.P[4:,4:] *= 1000. #give high uncertainty to the unobservable initial velocities 110 | self.kf.P *= 10. 111 | self.kf.Q[-1,-1] *= 0.01 112 | self.kf.Q[4:,4:] *= 0.01 113 | 114 | self.kf.x[:4] = convert_bbox_to_z(bbox) 115 | self.time_since_update = 0 116 | self.id = KalmanBoxTracker.count 117 | KalmanBoxTracker.count += 1 118 | self.history = [] 119 | self.hits = 0 120 | self.hit_streak = 0 121 | self.age = 0 122 | 123 | def update(self,bbox): 124 | """ 125 | Updates the state vector with observed bbox. 126 | """ 127 | self.time_since_update = 0 128 | self.history = [] 129 | self.hits += 1 130 | self.hit_streak += 1 131 | self.kf.update(convert_bbox_to_z(bbox)) 132 | 133 | def predict(self): 134 | """ 135 | Advances the state vector and returns the predicted bounding box estimate. 136 | """ 137 | if((self.kf.x[6]+self.kf.x[2])<=0): 138 | self.kf.x[6] *= 0.0 139 | self.kf.predict() 140 | self.age += 1 141 | if(self.time_since_update>0): 142 | self.hit_streak = 0 143 | self.time_since_update += 1 144 | self.history.append(convert_x_to_bbox(self.kf.x)) 145 | return self.history[-1] 146 | 147 | def get_state(self): 148 | """ 149 | Returns the current bounding box estimate. 150 | """ 151 | return convert_x_to_bbox(self.kf.x) 152 | 153 | 154 | def associate_detections_to_trackers(detections,trackers,iou_threshold = 0.3): 155 | """ 156 | Assigns detections to tracked object (both represented as bounding boxes) 157 | 158 | Returns 3 lists of matches, unmatched_detections and unmatched_trackers 159 | """ 160 | if(len(trackers)==0): 161 | return np.empty((0,2),dtype=int), np.arange(len(detections)), np.empty((0,5),dtype=int) 162 | 163 | iou_matrix = iou_batch(detections, trackers) 164 | 165 | if min(iou_matrix.shape) > 0: 166 | a = (iou_matrix > iou_threshold).astype(np.int32) 167 | if a.sum(1).max() == 1 and a.sum(0).max() == 1: 168 | matched_indices = np.stack(np.where(a), axis=1) 169 | else: 170 | matched_indices = linear_assignment(-iou_matrix) 171 | else: 172 | matched_indices = np.empty(shape=(0,2)) 173 | 174 | unmatched_detections = [] 175 | for d, det in enumerate(detections): 176 | if(d not in matched_indices[:,0]): 177 | unmatched_detections.append(d) 178 | unmatched_trackers = [] 179 | for t, trk in enumerate(trackers): 180 | if(t not in matched_indices[:,1]): 181 | unmatched_trackers.append(t) 182 | 183 | #filter out matched with low IOU 184 | matches = [] 185 | for m in matched_indices: 186 | if(iou_matrix[m[0], m[1]]= self.min_hits or self.frame_count <= self.min_hits): 246 | ret.append(np.concatenate((d,[trk.id+1])).reshape(1,-1)) # +1 as MOT benchmark requires positive 247 | i -= 1 248 | # remove dead tracklet 249 | if(trk.time_since_update > self.max_age): 250 | self.trackers.pop(i) 251 | if(len(ret)>0): 252 | return np.concatenate(ret) 253 | return np.empty((0,5)) 254 | 255 | def parse_args(): 256 | """Parse input arguments.""" 257 | parser = argparse.ArgumentParser(description='SORT demo') 258 | parser.add_argument('--display', dest='display', help='Display online tracker output (slow) [False]',action='store_true') 259 | parser.add_argument("--seq_path", help="Path to detections.", type=str, default='data') 260 | parser.add_argument("--phase", help="Subdirectory in seq_path.", type=str, default='train') 261 | parser.add_argument("--max_age", 262 | help="Maximum number of frames to keep alive a track without associated detections.", 263 | type=int, default=1) 264 | parser.add_argument("--min_hits", 265 | help="Minimum number of associated detections before track is initialised.", 266 | type=int, default=3) 267 | parser.add_argument("--iou_threshold", help="Minimum IOU for match.", type=float, default=0.3) 268 | args = parser.parse_args() 269 | return args 270 | 271 | if __name__ == '__main__': 272 | # all train 273 | args = parse_args() 274 | display = args.display 275 | phase = args.phase 276 | total_time = 0.0 277 | total_frames = 0 278 | colours = np.random.rand(32, 3) #used only for display 279 | if(display): 280 | if not os.path.exists('mot_benchmark'): 281 | print('\n\tERROR: mot_benchmark link not found!\n\n Create a symbolic link to the MOT benchmark\n (https://motchallenge.net/data/2D_MOT_2015/#download). E.g.:\n\n $ ln -s /path/to/MOT2015_challenge/2DMOT2015 mot_benchmark\n\n') 282 | exit() 283 | plt.ion() 284 | fig = plt.figure() 285 | ax1 = fig.add_subplot(111, aspect='equal') 286 | 287 | if not os.path.exists('output'): 288 | os.makedirs('output') 289 | pattern = os.path.join(args.seq_path, phase, '*', 'det', 'det.txt') 290 | for seq_dets_fn in glob.glob(pattern): 291 | mot_tracker = Sort(max_age=args.max_age, 292 | min_hits=args.min_hits, 293 | iou_threshold=args.iou_threshold) #create instance of the SORT tracker 294 | seq_dets = np.loadtxt(seq_dets_fn, delimiter=',') 295 | seq = seq_dets_fn[pattern.find('*'):].split(os.path.sep)[0] 296 | 297 | with open(os.path.join('output', '%s.txt'%(seq)),'w') as out_file: 298 | print("Processing %s."%(seq)) 299 | for frame in range(int(seq_dets[:,0].max())): 300 | frame += 1 #detection and frame numbers begin at 1 301 | dets = seq_dets[seq_dets[:, 0]==frame, 2:7] 302 | dets[:, 2:4] += dets[:, 0:2] #convert to [x1,y1,w,h] to [x1,y1,x2,y2] 303 | total_frames += 1 304 | 305 | if(display): 306 | fn = os.path.join('mot_benchmark', phase, seq, 'img1', '%06d.jpg'%(frame)) 307 | im =io.imread(fn) 308 | ax1.imshow(im) 309 | plt.title(seq + ' Tracked Targets') 310 | 311 | start_time = time.time() 312 | trackers = mot_tracker.update(dets) 313 | cycle_time = time.time() - start_time 314 | total_time += cycle_time 315 | 316 | for d in trackers: 317 | print('%d,%d,%.2f,%.2f,%.2f,%.2f,1,-1,-1,-1'%(frame,d[4],d[0],d[1],d[2]-d[0],d[3]-d[1]),file=out_file) 318 | if(display): 319 | d = d.astype(np.int32) 320 | ax1.add_patch(patches.Rectangle((d[0],d[1]),d[2]-d[0],d[3]-d[1],fill=False,lw=3,ec=colours[d[4]%32,:])) 321 | 322 | if(display): 323 | fig.canvas.flush_events() 324 | plt.draw() 325 | ax1.cla() 326 | 327 | print("Total Tracking took: %.3f seconds for %d frames or %.1f FPS" % (total_time, total_frames, total_frames / total_time)) 328 | 329 | if(display): 330 | print("Note: to get real runtime results run without the option: --display") 331 | -------------------------------------------------------------------------------- /util.py: -------------------------------------------------------------------------------- 1 | import string 2 | import easyocr 3 | 4 | # Initialize the OCR reader 5 | reader = easyocr.Reader(['en'], gpu=False) 6 | 7 | # Mapping dictionaries for character conversion 8 | dict_char_to_int = {'O': '0', 9 | 'I': '1', 10 | 'J': '3', 11 | 'A': '4', 12 | 'G': '6', 13 | 'S': '5'} 14 | 15 | dict_int_to_char = {'0': 'O', 16 | '1': 'I', 17 | '3': 'J', 18 | '4': 'A', 19 | '6': 'G', 20 | '5': 'S'} 21 | 22 | 23 | def write_csv(results, output_path): 24 | """ 25 | Write the results to a CSV file. 26 | 27 | Args: 28 | results (dict): Dictionary containing the results. 29 | output_path (str): Path to the output CSV file. 30 | """ 31 | with open(output_path, 'w') as f: 32 | f.write('{},{},{},{},{},{},{}\n'.format('frame_nmr', 'car_id', 'car_bbox', 33 | 'license_plate_bbox', 'license_plate_bbox_score', 'license_number', 34 | 'license_number_score')) 35 | 36 | for frame_nmr in results.keys(): 37 | for car_id in results[frame_nmr].keys(): 38 | print(results[frame_nmr][car_id]) 39 | if 'car' in results[frame_nmr][car_id].keys() and \ 40 | 'license_plate' in results[frame_nmr][car_id].keys() and \ 41 | 'text' in results[frame_nmr][car_id]['license_plate'].keys(): 42 | f.write('{},{},{},{},{},{},{}\n'.format(frame_nmr, 43 | car_id, 44 | '[{} {} {} {}]'.format( 45 | results[frame_nmr][car_id]['car']['bbox'][0], 46 | results[frame_nmr][car_id]['car']['bbox'][1], 47 | results[frame_nmr][car_id]['car']['bbox'][2], 48 | results[frame_nmr][car_id]['car']['bbox'][3]), 49 | '[{} {} {} {}]'.format( 50 | results[frame_nmr][car_id]['license_plate']['bbox'][0], 51 | results[frame_nmr][car_id]['license_plate']['bbox'][1], 52 | results[frame_nmr][car_id]['license_plate']['bbox'][2], 53 | results[frame_nmr][car_id]['license_plate']['bbox'][3]), 54 | results[frame_nmr][car_id]['license_plate']['bbox_score'], 55 | results[frame_nmr][car_id]['license_plate']['text'], 56 | results[frame_nmr][car_id]['license_plate']['text_score']) 57 | ) 58 | f.close() 59 | 60 | 61 | def license_complies_format(text): 62 | """ 63 | Check if the license plate text complies with the required format. 64 | 65 | Args: 66 | text (str): License plate text. 67 | 68 | Returns: 69 | bool: True if the license plate complies with the format, False otherwise. 70 | """ 71 | if len(text) != 7: 72 | return False 73 | 74 | if (text[0] in string.ascii_uppercase or text[0] in dict_int_to_char.keys()) and \ 75 | (text[1] in string.ascii_uppercase or text[1] in dict_int_to_char.keys()) and \ 76 | (text[2] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] or text[2] in dict_char_to_int.keys()) and \ 77 | (text[3] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] or text[3] in dict_char_to_int.keys()) and \ 78 | (text[4] in string.ascii_uppercase or text[4] in dict_int_to_char.keys()) and \ 79 | (text[5] in string.ascii_uppercase or text[5] in dict_int_to_char.keys()) and \ 80 | (text[6] in string.ascii_uppercase or text[6] in dict_int_to_char.keys()): 81 | return True 82 | else: 83 | return False 84 | 85 | 86 | def format_license(text): 87 | """ 88 | Format the license plate text by converting characters using the mapping dictionaries. 89 | 90 | Args: 91 | text (str): License plate text. 92 | 93 | Returns: 94 | str: Formatted license plate text. 95 | """ 96 | license_plate_ = '' 97 | mapping = {0: dict_int_to_char, 1: dict_int_to_char, 4: dict_int_to_char, 5: dict_int_to_char, 6: dict_int_to_char, 98 | 2: dict_char_to_int, 3: dict_char_to_int} 99 | for j in [0, 1, 2, 3, 4, 5, 6]: 100 | if text[j] in mapping[j].keys(): 101 | license_plate_ += mapping[j][text[j]] 102 | else: 103 | license_plate_ += text[j] 104 | 105 | return license_plate_ 106 | 107 | 108 | def read_license_plate(license_plate_crop): 109 | """ 110 | Read the license plate text from the given cropped image. 111 | 112 | Args: 113 | license_plate_crop (PIL.Image.Image): Cropped image containing the license plate. 114 | 115 | Returns: 116 | tuple: Tuple containing the formatted license plate text and its confidence score. 117 | """ 118 | 119 | detections = reader.readtext(license_plate_crop) 120 | 121 | for detection in detections: 122 | bbox, text, score = detection 123 | 124 | text = text.upper().replace(' ', '') 125 | 126 | if license_complies_format(text): 127 | return format_license(text), score 128 | 129 | return None, None 130 | 131 | 132 | def get_car(license_plate, vehicle_track_ids): 133 | """ 134 | Retrieve the vehicle coordinates and ID based on the license plate coordinates. 135 | 136 | Args: 137 | license_plate (tuple): Tuple containing the coordinates of the license plate (x1, y1, x2, y2, score, class_id). 138 | vehicle_track_ids (list): List of vehicle track IDs and their corresponding coordinates. 139 | 140 | Returns: 141 | tuple: Tuple containing the vehicle coordinates (x1, y1, x2, y2) and ID. 142 | """ 143 | x1, y1, x2, y2, score, class_id = license_plate 144 | 145 | foundIt = False 146 | for j in range(len(vehicle_track_ids)): 147 | xcar1, ycar1, xcar2, ycar2, car_id = vehicle_track_ids[j] 148 | 149 | if x1 > xcar1 and y1 > ycar1 and x2 < xcar2 and y2 < ycar2: 150 | car_indx = j 151 | foundIt = True 152 | break 153 | 154 | if foundIt: 155 | return vehicle_track_ids[car_indx] 156 | 157 | return -1, -1, -1, -1, -1 158 | -------------------------------------------------------------------------------- /visualize.py: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "9487dbe2-b2d7-4e61-a916-60942d26348f", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import ast\n", 11 | "\n", 12 | "import cv2\n", 13 | "import numpy as np\n", 14 | "import pandas as pd\n", 15 | "\n", 16 | "\n", 17 | "def draw_border(img, top_left, bottom_right, color=(0, 255, 0), thickness=10, line_length_x=200, line_length_y=200):\n", 18 | " x1, y1 = top_left\n", 19 | " x2, y2 = bottom_right\n", 20 | "\n", 21 | " cv2.line(img, (x1, y1), (x1, y1 + line_length_y), color, thickness) #-- top-left\n", 22 | " cv2.line(img, (x1, y1), (x1 + line_length_x, y1), color, thickness)\n", 23 | "\n", 24 | " cv2.line(img, (x1, y2), (x1, y2 - line_length_y), color, thickness) #-- bottom-left\n", 25 | " cv2.line(img, (x1, y2), (x1 + line_length_x, y2), color, thickness)\n", 26 | "\n", 27 | " cv2.line(img, (x2, y1), (x2 - line_length_x, y1), color, thickness) #-- top-right\n", 28 | " cv2.line(img, (x2, y1), (x2, y1 + line_length_y), color, thickness)\n", 29 | "\n", 30 | " cv2.line(img, (x2, y2), (x2, y2 - line_length_y), color, thickness) #-- bottom-right\n", 31 | " cv2.line(img, (x2, y2), (x2 - line_length_x, y2), color, thickness)\n", 32 | "\n", 33 | " return img\n", 34 | "\n", 35 | "\n", 36 | "results = pd.read_csv('./test_interpolated.csv')\n", 37 | "\n", 38 | "# load video\n", 39 | "video_path = 'sample.mp4'\n", 40 | "cap = cv2.VideoCapture(video_path)\n", 41 | "\n", 42 | "fourcc = cv2.VideoWriter_fourcc(*'mp4v') # Specify the codec\n", 43 | "fps = cap.get(cv2.CAP_PROP_FPS)\n", 44 | "width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n", 45 | "height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n", 46 | "out = cv2.VideoWriter('./out.mp4', fourcc, fps, (width, height))\n", 47 | "\n", 48 | "license_plate = {}\n", 49 | "for car_id in np.unique(results['car_id']):\n", 50 | " max_ = np.amax(results[results['car_id'] == car_id]['license_number_score'])\n", 51 | " license_plate[car_id] = {'license_crop': None,\n", 52 | " 'license_plate_number': results[(results['car_id'] == car_id) &\n", 53 | " (results['license_number_score'] == max_)]['license_number'].iloc[0]}\n", 54 | " cap.set(cv2.CAP_PROP_POS_FRAMES, results[(results['car_id'] == car_id) &\n", 55 | " (results['license_number_score'] == max_)]['frame_nmr'].iloc[0])\n", 56 | " ret, frame = cap.read()\n", 57 | "\n", 58 | " x1, y1, x2, y2 = ast.literal_eval(results[(results['car_id'] == car_id) &\n", 59 | " (results['license_number_score'] == max_)]['license_plate_bbox'].iloc[0].replace('[ ', '[').replace(' ', ' ').replace(' ', ' ').replace(' ', ','))\n", 60 | "\n", 61 | " license_crop = frame[int(y1):int(y2), int(x1):int(x2), :]\n", 62 | " license_crop = cv2.resize(license_crop, (int((x2 - x1) * 400 / (y2 - y1)), 400))\n", 63 | "\n", 64 | " license_plate[car_id]['license_crop'] = license_crop\n", 65 | "\n", 66 | "\n", 67 | "frame_nmr = -1\n", 68 | "\n", 69 | "cap.set(cv2.CAP_PROP_POS_FRAMES, 0)\n", 70 | "\n", 71 | "# read frames\n", 72 | "ret = True\n", 73 | "while ret:\n", 74 | " ret, frame = cap.read()\n", 75 | " frame_nmr += 1\n", 76 | " if ret:\n", 77 | " df_ = results[results['frame_nmr'] == frame_nmr]\n", 78 | " for row_indx in range(len(df_)):\n", 79 | " # draw car\n", 80 | " car_x1, car_y1, car_x2, car_y2 = ast.literal_eval(df_.iloc[row_indx]['car_bbox'].replace('[ ', '[').replace(' ', ' ').replace(' ', ' ').replace(' ', ','))\n", 81 | " draw_border(frame, (int(car_x1), int(car_y1)), (int(car_x2), int(car_y2)), (0, 255, 0), 25,\n", 82 | " line_length_x=200, line_length_y=200)\n", 83 | "\n", 84 | " # draw license plate\n", 85 | " x1, y1, x2, y2 = ast.literal_eval(df_.iloc[row_indx]['license_plate_bbox'].replace('[ ', '[').replace(' ', ' ').replace(' ', ' ').replace(' ', ','))\n", 86 | " cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 0, 255), 12)\n", 87 | "\n", 88 | " # crop license plate\n", 89 | " license_crop = license_plate[df_.iloc[row_indx]['car_id']]['license_crop']\n", 90 | "\n", 91 | " H, W, _ = license_crop.shape\n", 92 | "\n", 93 | " try:\n", 94 | " frame[int(car_y1) - H - 100:int(car_y1) - 100,\n", 95 | " int((car_x2 + car_x1 - W) / 2):int((car_x2 + car_x1 + W) / 2), :] = license_crop\n", 96 | "\n", 97 | " frame[int(car_y1) - H - 400:int(car_y1) - H - 100,\n", 98 | " int((car_x2 + car_x1 - W) / 2):int((car_x2 + car_x1 + W) / 2), :] = (255, 255, 255)\n", 99 | "\n", 100 | " (text_width, text_height), _ = cv2.getTextSize(\n", 101 | " license_plate[df_.iloc[row_indx]['car_id']]['license_plate_number'],\n", 102 | " cv2.FONT_HERSHEY_SIMPLEX,\n", 103 | " 4.3,\n", 104 | " 17)\n", 105 | "\n", 106 | " cv2.putText(frame,\n", 107 | " license_plate[df_.iloc[row_indx]['car_id']]['license_plate_number'],\n", 108 | " (int((car_x2 + car_x1 - text_width) / 2), int(car_y1 - H - 250 + (text_height / 2))),\n", 109 | " cv2.FONT_HERSHEY_SIMPLEX,\n", 110 | " 4.3,\n", 111 | " (0, 0, 0),\n", 112 | " 17)\n", 113 | "\n", 114 | " except:\n", 115 | " pass\n", 116 | "\n", 117 | " out.write(frame)\n", 118 | " frame = cv2.resize(frame, (1280, 720))\n", 119 | "\n", 120 | " # cv2.imshow('frame', frame)\n", 121 | " # cv2.waitKey(0)\n", 122 | "\n", 123 | "out.release()\n", 124 | "cap.release()" 125 | ] 126 | } 127 | ], 128 | "metadata": { 129 | "kernelspec": { 130 | "display_name": "Python 3 (ipykernel)", 131 | "language": "python", 132 | "name": "python3" 133 | }, 134 | "language_info": { 135 | "codemirror_mode": { 136 | "name": "ipython", 137 | "version": 3 138 | }, 139 | "file_extension": ".py", 140 | "mimetype": "text/x-python", 141 | "name": "python", 142 | "nbconvert_exporter": "python", 143 | "pygments_lexer": "ipython3", 144 | "version": "3.11.5" 145 | } 146 | }, 147 | "nbformat": 4, 148 | "nbformat_minor": 5 149 | } 150 | --------------------------------------------------------------------------------