Crop Bounding Box ( part deux! ) for License Plate

Abstract We are pre-processing photos to ultimately enable OCR. Prior step we found the bounding box for license plates. Let’s crop down images to only license plates themselves for OCR next. Step-by-Step Recipe The over-arching goal is to read license plate numbers from images. On that journey, we detected cars in highway image captures, cropped to just cars, and detected license plates on car images. Now we crop to just license plates. And those zoomed-in license plate images are inputs to OCR, which will read license plate numbers into database. Unlike prior cropping step, we can safely assume one license plate per image. It’s not 1:[0,n) it’s 1:[0,1]. Thus, simple step: if we found a license plate (ie have a bounding box), then crop license plate from ultralytics import YOLO import cv2 import imutils import numpy as np from os import path baseDir = '/Users/japollock/Projects/TrainHighwayCarDetector/' inputFilePath = baseDir + 'photos/yolo_licensePlates/licensePlates/IMG_4554_0002.jpg' inputFileName = path.basename(inputFilePath) outputPhotosDir = baseDir + 'photos/yolo_licensePlates/croppedPlates/' model = YOLO(baseDir + 'src/runs/detect/yolov8n_100_16_LP_v27/weights/best.pt') imageOriginal = cv2.imread(inputFilePath) imageScaled = imutils.resize(imageOriginal, width=1280) imgRatio = imageOriginal.shape[1] / imageScaled.shape[1] results = model.predict(source=imageScaled, imgsz=1280) if results is not None and len(results) > 0 and results[0].boxes is not None and len(results[0].boxes) > 0: box = results[0].boxes[0] # bounding box in scaled-down image x1Float = box.xyxy[0][0].item() x2Float = box.xyxy[0][2].item() y1Float = box.xyxy[0][1].item() y2Float = box.xyxy[0][3].item() # calc bounding box in original (scaled-up) image x1 = int(imgRatio * x1Float) y1 = int(imgRatio * y1Float) x2 = int(imgRatio * x2Float) y2 = int(imgRatio * y2Float) # cropped imageCropped = imageOriginal[y1:y2,x1:x2] outputFilePath = outputPhotosDir + inputFileName[0:(len(inputFileName)-4)] + '.jpg' cv2.imwrite(outputFilePath, imageCropped) print('Wrote ' + outputFilePath) At this point we’re enabling from highway to car to license plate, such as the following: Almost there! From highway-view image capture, to car, to license plate. Next up: OCR! Next Link: TBD -- Read license plate with OCR

Mar 4, 2025 - 14:56
 0
Crop Bounding Box ( part deux! ) for License Plate

Abstract

We are pre-processing photos to ultimately enable OCR. Prior step we found the bounding box for license plates. Let’s crop down images to only license plates themselves for OCR next.

Step-by-Step

License plate detection workflow visualized

Recipe

The over-arching goal is to read license plate numbers from images. On that journey, we detected cars in highway image captures, cropped to just cars, and detected license plates on car images. Now we crop to just license plates. And those zoomed-in license plate images are inputs to OCR, which will read license plate numbers into database.

Unlike prior cropping step, we can safely assume one license plate per image. It’s not 1:[0,n) it’s 1:[0,1].

Thus, simple step: if we found a license plate (ie have a bounding box), then crop license plate

from ultralytics import YOLO
import cv2 
import imutils
import numpy as np
from os import path

baseDir = '/Users/japollock/Projects/TrainHighwayCarDetector/'
inputFilePath = baseDir + 'photos/yolo_licensePlates/licensePlates/IMG_4554_0002.jpg'
inputFileName = path.basename(inputFilePath)
outputPhotosDir = baseDir + 'photos/yolo_licensePlates/croppedPlates/'
model = YOLO(baseDir + 'src/runs/detect/yolov8n_100_16_LP_v27/weights/best.pt')

imageOriginal = cv2.imread(inputFilePath)
imageScaled = imutils.resize(imageOriginal, width=1280)

imgRatio = imageOriginal.shape[1] / imageScaled.shape[1]

results = model.predict(source=imageScaled, imgsz=1280)

if results is not None and len(results) > 0 and results[0].boxes is not None and len(results[0].boxes) > 0:
    box = results[0].boxes[0]
    # bounding box in scaled-down image
    x1Float = box.xyxy[0][0].item()
    x2Float = box.xyxy[0][2].item()
    y1Float = box.xyxy[0][1].item()
    y2Float = box.xyxy[0][3].item()

    # calc bounding box in original (scaled-up) image
    x1 = int(imgRatio * x1Float)
    y1 = int(imgRatio * y1Float)
    x2 = int(imgRatio * x2Float)
    y2 = int(imgRatio * y2Float)

    # cropped
    imageCropped = imageOriginal[y1:y2,x1:x2]

    outputFilePath = outputPhotosDir + inputFileName[0:(len(inputFileName)-4)] + '.jpg'
    cv2.imwrite(outputFilePath, imageCropped)
    print('Wrote ' + outputFilePath)

At this point we’re enabling from highway to car to license plate, such as the following:

Highway view

Cropped car, and cropped license plate

Almost there! From highway-view image capture, to car, to license plate. Next up: OCR!

Next Link: TBD -- Read license plate with OCR