License Plate Detection (8 Part Series)
1 OpenCV in Python for End-to-end License Plate Detection
2 Camera and Computer Setup
… 4 more parts…
3 Capturing Images from DSLR to RPi
4 Model for Detecting Cars
5 Crop Bounding Box + Rotate
6 Model for Detecting License Plates in Cropped Image
7 Crop Bounding Box ( part deux! ) for License Plate
8 Read license plate with OCR
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
<span>from</span> <span>ultralytics</span> <span>import</span> <span>YOLO</span><span>import</span> <span>cv2</span><span>import</span> <span>imutils</span><span>import</span> <span>numpy</span> <span>as</span> <span>np</span><span>from</span> <span>os</span> <span>import</span> <span>path</span><span>baseDir</span> <span>=</span> <span>'</span><span>/</span><span>Users</span><span>/</span><span>japollock</span><span>/</span><span>Projects</span><span>/</span><span>TrainHighwayCarDetector</span><span>/</span><span>'</span><span>inputFilePath</span> <span>=</span> <span>baseDir</span> <span>+</span> <span>'</span><span>photos</span><span>/</span><span>yolo_licensePlates</span><span>/</span><span>licensePlates</span><span>/</span><span>IMG_4554_0002</span><span>.</span><span>jpg</span><span>'</span><span>inputFileName</span> <span>=</span> <span>path</span><span>.</span><span>basename</span><span>(</span><span>inputFilePath</span><span>)</span><span>outputPhotosDir</span> <span>=</span> <span>baseDir</span> <span>+</span> <span>'</span><span>photos</span><span>/</span><span>yolo_licensePlates</span><span>/</span><span>croppedPlates</span><span>/</span><span>'</span><span>model</span> <span>=</span> <span>YOLO</span><span>(</span><span>baseDir</span> <span>+</span> <span>'</span><span>src</span><span>/</span><span>runs</span><span>/</span><span>detect</span><span>/</span><span>yolov8n_100_16_LP_v27</span><span>/</span><span>weights</span><span>/</span><span>best</span><span>.</span><span>pt</span><span>'</span><span>)</span><span>imageOriginal</span> <span>=</span> <span>cv2</span><span>.</span><span>imread</span><span>(</span><span>inputFilePath</span><span>)</span><span>imageScaled</span> <span>=</span> <span>imutils</span><span>.</span><span>resize</span><span>(</span><span>imageOriginal</span><span>,</span> <span>width</span><span>=</span><span>1280</span><span>)</span><span>imgRatio</span> <span>=</span> <span>imageOriginal</span><span>.</span><span>shape</span><span>[</span><span>1</span><span>]</span> <span>/</span> <span>imageScaled</span><span>.</span><span>shape</span><span>[</span><span>1</span><span>]</span><span>results</span> <span>=</span> <span>model</span><span>.</span><span>predict</span><span>(</span><span>source</span><span>=</span><span>imageScaled</span><span>,</span> <span>imgsz</span><span>=</span><span>1280</span><span>)</span><span>if</span> <span>results</span> <span>is</span> <span>not</span> <span>None</span> <span>and</span> <span>len</span><span>(</span><span>results</span><span>)</span> <span>></span> <span>0</span> <span>and</span> <span>results</span><span>[</span><span>0</span><span>].</span><span>boxes</span> <span>is</span> <span>not</span> <span>None</span> <span>and</span> <span>len</span><span>(</span><span>results</span><span>[</span><span>0</span><span>].</span><span>boxes</span><span>)</span> <span>></span> <span>0</span><span>:</span><span>box</span> <span>=</span> <span>results</span><span>[</span><span>0</span><span>].</span><span>boxes</span><span>[</span><span>0</span><span>]</span><span># bounding box in scaled-down image </span> <span>x1Float</span> <span>=</span> <span>box</span><span>.</span><span>xyxy</span><span>[</span><span>0</span><span>][</span><span>0</span><span>].</span><span>item</span><span>()</span><span>x2Float</span> <span>=</span> <span>box</span><span>.</span><span>xyxy</span><span>[</span><span>0</span><span>][</span><span>2</span><span>].</span><span>item</span><span>()</span><span>y1Float</span> <span>=</span> <span>box</span><span>.</span><span>xyxy</span><span>[</span><span>0</span><span>][</span><span>1</span><span>].</span><span>item</span><span>()</span><span>y2Float</span> <span>=</span> <span>box</span><span>.</span><span>xyxy</span><span>[</span><span>0</span><span>][</span><span>3</span><span>].</span><span>item</span><span>()</span><span># calc bounding box in original (scaled-up) image </span> <span>x1</span> <span>=</span> <span>int</span><span>(</span><span>imgRatio</span> <span>*</span> <span>x1Float</span><span>)</span><span>y1</span> <span>=</span> <span>int</span><span>(</span><span>imgRatio</span> <span>*</span> <span>y1Float</span><span>)</span><span>x2</span> <span>=</span> <span>int</span><span>(</span><span>imgRatio</span> <span>*</span> <span>x2Float</span><span>)</span><span>y2</span> <span>=</span> <span>int</span><span>(</span><span>imgRatio</span> <span>*</span> <span>y2Float</span><span>)</span><span># cropped </span> <span>imageCropped</span> <span>=</span> <span>imageOriginal</span><span>[</span><span>y1</span><span>:</span><span>y2</span><span>,</span><span>x1</span><span>:</span><span>x2</span><span>]</span><span>outputFilePath</span> <span>=</span> <span>outputPhotosDir</span> <span>+</span> <span>inputFileName</span><span>[</span><span>0</span><span>:</span><span>(</span><span>len</span><span>(</span><span>inputFileName</span><span>)</span><span>-</span><span>4</span><span>)]</span> <span>+</span> <span>'</span><span>.</span><span>jpg</span><span>'</span><span>cv2</span><span>.</span><span>imwrite</span><span>(</span><span>outputFilePath</span><span>,</span> <span>imageCropped</span><span>)</span><span>print</span><span>(</span><span>'</span><span>Wrote</span> <span>'</span> <span>+</span> <span>outputFilePath</span><span>)</span><span>from</span> <span>ultralytics</span> <span>import</span> <span>YOLO</span> <span>import</span> <span>cv2</span> <span>import</span> <span>imutils</span> <span>import</span> <span>numpy</span> <span>as</span> <span>np</span> <span>from</span> <span>os</span> <span>import</span> <span>path</span> <span>baseDir</span> <span>=</span> <span>'</span><span>/</span><span>Users</span><span>/</span><span>japollock</span><span>/</span><span>Projects</span><span>/</span><span>TrainHighwayCarDetector</span><span>/</span><span>'</span> <span>inputFilePath</span> <span>=</span> <span>baseDir</span> <span>+</span> <span>'</span><span>photos</span><span>/</span><span>yolo_licensePlates</span><span>/</span><span>licensePlates</span><span>/</span><span>IMG_4554_0002</span><span>.</span><span>jpg</span><span>'</span> <span>inputFileName</span> <span>=</span> <span>path</span><span>.</span><span>basename</span><span>(</span><span>inputFilePath</span><span>)</span> <span>outputPhotosDir</span> <span>=</span> <span>baseDir</span> <span>+</span> <span>'</span><span>photos</span><span>/</span><span>yolo_licensePlates</span><span>/</span><span>croppedPlates</span><span>/</span><span>'</span> <span>model</span> <span>=</span> <span>YOLO</span><span>(</span><span>baseDir</span> <span>+</span> <span>'</span><span>src</span><span>/</span><span>runs</span><span>/</span><span>detect</span><span>/</span><span>yolov8n_100_16_LP_v27</span><span>/</span><span>weights</span><span>/</span><span>best</span><span>.</span><span>pt</span><span>'</span><span>)</span> <span>imageOriginal</span> <span>=</span> <span>cv2</span><span>.</span><span>imread</span><span>(</span><span>inputFilePath</span><span>)</span> <span>imageScaled</span> <span>=</span> <span>imutils</span><span>.</span><span>resize</span><span>(</span><span>imageOriginal</span><span>,</span> <span>width</span><span>=</span><span>1280</span><span>)</span> <span>imgRatio</span> <span>=</span> <span>imageOriginal</span><span>.</span><span>shape</span><span>[</span><span>1</span><span>]</span> <span>/</span> <span>imageScaled</span><span>.</span><span>shape</span><span>[</span><span>1</span><span>]</span> <span>results</span> <span>=</span> <span>model</span><span>.</span><span>predict</span><span>(</span><span>source</span><span>=</span><span>imageScaled</span><span>,</span> <span>imgsz</span><span>=</span><span>1280</span><span>)</span> <span>if</span> <span>results</span> <span>is</span> <span>not</span> <span>None</span> <span>and</span> <span>len</span><span>(</span><span>results</span><span>)</span> <span>></span> <span>0</span> <span>and</span> <span>results</span><span>[</span><span>0</span><span>].</span><span>boxes</span> <span>is</span> <span>not</span> <span>None</span> <span>and</span> <span>len</span><span>(</span><span>results</span><span>[</span><span>0</span><span>].</span><span>boxes</span><span>)</span> <span>></span> <span>0</span><span>:</span> <span>box</span> <span>=</span> <span>results</span><span>[</span><span>0</span><span>].</span><span>boxes</span><span>[</span><span>0</span><span>]</span> <span># bounding box in scaled-down image </span> <span>x1Float</span> <span>=</span> <span>box</span><span>.</span><span>xyxy</span><span>[</span><span>0</span><span>][</span><span>0</span><span>].</span><span>item</span><span>()</span> <span>x2Float</span> <span>=</span> <span>box</span><span>.</span><span>xyxy</span><span>[</span><span>0</span><span>][</span><span>2</span><span>].</span><span>item</span><span>()</span> <span>y1Float</span> <span>=</span> <span>box</span><span>.</span><span>xyxy</span><span>[</span><span>0</span><span>][</span><span>1</span><span>].</span><span>item</span><span>()</span> <span>y2Float</span> <span>=</span> <span>box</span><span>.</span><span>xyxy</span><span>[</span><span>0</span><span>][</span><span>3</span><span>].</span><span>item</span><span>()</span> <span># calc bounding box in original (scaled-up) image </span> <span>x1</span> <span>=</span> <span>int</span><span>(</span><span>imgRatio</span> <span>*</span> <span>x1Float</span><span>)</span> <span>y1</span> <span>=</span> <span>int</span><span>(</span><span>imgRatio</span> <span>*</span> <span>y1Float</span><span>)</span> <span>x2</span> <span>=</span> <span>int</span><span>(</span><span>imgRatio</span> <span>*</span> <span>x2Float</span><span>)</span> <span>y2</span> <span>=</span> <span>int</span><span>(</span><span>imgRatio</span> <span>*</span> <span>y2Float</span><span>)</span> <span># cropped </span> <span>imageCropped</span> <span>=</span> <span>imageOriginal</span><span>[</span><span>y1</span><span>:</span><span>y2</span><span>,</span><span>x1</span><span>:</span><span>x2</span><span>]</span> <span>outputFilePath</span> <span>=</span> <span>outputPhotosDir</span> <span>+</span> <span>inputFileName</span><span>[</span><span>0</span><span>:</span><span>(</span><span>len</span><span>(</span><span>inputFileName</span><span>)</span><span>-</span><span>4</span><span>)]</span> <span>+</span> <span>'</span><span>.</span><span>jpg</span><span>'</span> <span>cv2</span><span>.</span><span>imwrite</span><span>(</span><span>outputFilePath</span><span>,</span> <span>imageCropped</span><span>)</span> <span>print</span><span>(</span><span>'</span><span>Wrote</span> <span>'</span> <span>+</span> <span>outputFilePath</span><span>)</span>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)
Enter fullscreen mode Exit fullscreen mode
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: Read license plate with OCR
License Plate Detection (8 Part Series)
1 OpenCV in Python for End-to-end License Plate Detection
2 Camera and Computer Setup
… 4 more parts…
3 Capturing Images from DSLR to RPi
4 Model for Detecting Cars
5 Crop Bounding Box + Rotate
6 Model for Detecting License Plates in Cropped Image
7 Crop Bounding Box ( part deux! ) for License Plate
8 Read license plate with OCR
暂无评论内容