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

Abstract

So close! We now have cropped images with just license plate numbers. This is derived from highway-view, down to car-view, down to license plate. In this step, we pre-process the image to improve OCR, and we read the characters from image.

ToC (Step-by-Step)

Recipe

The following pre-processing steps helps focus OCR on just the important image information, and reduces everything else (eg RBG color, grays, small contours). For clarity this sequence of pre-processing prior to OCR is fairly typical pattern prior to OCR taught in computer vision. I’m not inventing or discovering something new here. At the bottom of article, we run OCR with no pre-processing to illustrate the difference.

Before pre-processing – cropped image of license plate from prior steps:

  1. Pre-process step: desaturate colors. Go gray.

    RGB color is not helpful here for OCR. Doesn’t matter if license plate numbers are magenta or cyan. Thus discard color information.

  2. Pre-process step: gaussian blur to reduce noise / artifacts slightly.

    Nevermind the “gaussian” part. This is just applying a blur filter to the image. That blur filter softens the small differences. And because small differences are reduced (eg dirty-ish license plate), then the big differences are easier to distinguish (eg dark-numbers on white-background).

  3. Pre-process step: threshold to really highlight license plate characters

    Thresholding further highlights where we have big differences such as dark-numbers on white-background.

  4. OCR license plate

    I experimented with a bunch of OCR libraries here. I found best for this use case was PaddleOCR, better than Tesseract and some others. Run PaddleOCR on thresholded image, and get string text, license plate number, back from the image!

  5. Profit!

<span>import</span> <span>cv2</span>
<span>from</span> <span>paddleocr</span> <span>import</span> <span>PaddleOCR</span><span>,</span> <span>draw_ocr</span>
<span>from</span> <span>ppocr</span><span>.</span><span>utils</span><span>.</span><span>logging</span> <span>import</span> <span>get_logger</span>
<span>import</span> <span>logging</span>
<span># Initialize PaddleOCR </span><span>ocr</span> <span>=</span> <span>PaddleOCR</span><span>(</span><span>use_angle_cls</span><span>=</span><span>True</span><span>,</span> <span>lang</span><span>=</span><span>'</span><span>en</span><span>'</span><span>,</span> <span>use_space_char</span><span>=</span><span>True</span><span>)</span>
<span>logger</span> <span>=</span> <span>get_logger</span><span>()</span>
<span>logger</span><span>.</span><span>setLevel</span><span>(</span><span>logging</span><span>.</span><span>ERROR</span><span>)</span> <span>#</span> <span>avoid</span> <span>debug</span> <span>statements</span> <span>in</span> <span>OCR</span> <span>results</span>
<span>#baseDir = '/Users/japollock/Projects/TrainHighwayCarDetector/' </span><span>baseDir</span> <span>=</span> <span>'</span><span>/</span><span>home</span><span>/</span><span>pi</span><span>/</span><span>Projects</span><span>/</span><span>TrainHighwayCarDetector</span><span>/</span><span>'</span>
<span>img_path</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>IMG_4554_0002</span><span>.</span><span>jpg</span><span>'</span>
<span>print</span><span>(</span><span>"Human readable is CEZ2594"</span><span>)</span>
<span>img</span> <span>=</span> <span>cv2</span><span>.</span><span>imread</span><span>(</span><span>img_path</span><span>)</span>
<span>gray</span> <span>=</span> <span>cv2</span><span>.</span><span>cvtColor</span><span>(</span><span>img</span><span>,</span> <span>cv2</span><span>.</span><span>COLOR_RGB2GRAY</span><span>)</span>
<span>blur</span> <span>=</span> <span>cv2</span><span>.</span><span>GaussianBlur</span><span>(</span><span>gray</span><span>,</span> <span>(</span><span>5</span><span>,</span><span>5</span><span>),</span> <span>0</span><span>)</span>
<span>ret</span><span>,</span> <span>thresh</span> <span>=</span> <span>cv2</span><span>.</span><span>threshold</span><span>(</span><span>blur</span><span>,</span> <span>0</span><span>,</span> <span>255</span><span>,</span> <span>cv2</span><span>.</span><span>THRESH_OTSU</span> <span>|</span> <span>cv2</span><span>.</span><span>THRESH_BINARY_INV</span><span>)</span>
<span># Perform OCR </span><span>result</span> <span>=</span> <span>ocr</span><span>.</span><span>ocr</span><span>(</span><span>thresh</span><span>,</span> <span>cls</span><span>=</span><span>True</span><span>)</span>
<span>for</span> <span>line</span> <span>in</span> <span>result</span><span>:</span>
<span>print</span><span>(</span><span>line</span><span>)</span>
<span>import</span> <span>cv2</span>
<span>from</span> <span>paddleocr</span> <span>import</span> <span>PaddleOCR</span><span>,</span> <span>draw_ocr</span>
<span>from</span> <span>ppocr</span><span>.</span><span>utils</span><span>.</span><span>logging</span> <span>import</span> <span>get_logger</span>
<span>import</span> <span>logging</span>

<span># Initialize PaddleOCR </span><span>ocr</span> <span>=</span> <span>PaddleOCR</span><span>(</span><span>use_angle_cls</span><span>=</span><span>True</span><span>,</span> <span>lang</span><span>=</span><span>'</span><span>en</span><span>'</span><span>,</span> <span>use_space_char</span><span>=</span><span>True</span><span>)</span>
<span>logger</span> <span>=</span> <span>get_logger</span><span>()</span>
<span>logger</span><span>.</span><span>setLevel</span><span>(</span><span>logging</span><span>.</span><span>ERROR</span><span>)</span> <span>#</span> <span>avoid</span> <span>debug</span> <span>statements</span> <span>in</span> <span>OCR</span> <span>results</span>

<span>#baseDir = '/Users/japollock/Projects/TrainHighwayCarDetector/' </span><span>baseDir</span> <span>=</span> <span>'</span><span>/</span><span>home</span><span>/</span><span>pi</span><span>/</span><span>Projects</span><span>/</span><span>TrainHighwayCarDetector</span><span>/</span><span>'</span>
<span>img_path</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>IMG_4554_0002</span><span>.</span><span>jpg</span><span>'</span>

<span>print</span><span>(</span><span>"Human readable is CEZ2594"</span><span>)</span>

<span>img</span> <span>=</span> <span>cv2</span><span>.</span><span>imread</span><span>(</span><span>img_path</span><span>)</span>

<span>gray</span> <span>=</span> <span>cv2</span><span>.</span><span>cvtColor</span><span>(</span><span>img</span><span>,</span> <span>cv2</span><span>.</span><span>COLOR_RGB2GRAY</span><span>)</span>

<span>blur</span> <span>=</span> <span>cv2</span><span>.</span><span>GaussianBlur</span><span>(</span><span>gray</span><span>,</span> <span>(</span><span>5</span><span>,</span><span>5</span><span>),</span> <span>0</span><span>)</span>

<span>ret</span><span>,</span> <span>thresh</span> <span>=</span> <span>cv2</span><span>.</span><span>threshold</span><span>(</span><span>blur</span><span>,</span> <span>0</span><span>,</span> <span>255</span><span>,</span> <span>cv2</span><span>.</span><span>THRESH_OTSU</span> <span>|</span> <span>cv2</span><span>.</span><span>THRESH_BINARY_INV</span><span>)</span>

<span># Perform OCR </span><span>result</span> <span>=</span> <span>ocr</span><span>.</span><span>ocr</span><span>(</span><span>thresh</span><span>,</span> <span>cls</span><span>=</span><span>True</span><span>)</span>

<span>for</span> <span>line</span> <span>in</span> <span>result</span><span>:</span>
    <span>print</span><span>(</span><span>line</span><span>)</span>
import cv2 from paddleocr import PaddleOCR, draw_ocr from ppocr.utils.logging import get_logger import logging # Initialize PaddleOCR ocr = PaddleOCR(use_angle_cls=True, lang='en', use_space_char=True) logger = get_logger() logger.setLevel(logging.ERROR) # avoid debug statements in OCR results #baseDir = '/Users/japollock/Projects/TrainHighwayCarDetector/' baseDir = '/home/pi/Projects/TrainHighwayCarDetector/' img_path = baseDir + 'photos/yolo_licensePlates/croppedPlates/IMG_4554_0002.jpg' print("Human readable is CEZ2594") img = cv2.imread(img_path) gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) blur = cv2.GaussianBlur(gray, (5,5), 0) ret, thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV) # Perform OCR result = ocr.ocr(thresh, cls=True) for line in result: print(line)

Enter fullscreen mode Exit fullscreen mode

Print statement outputs

[[[[14.0, 29.0], [181.0, 22.0], [184.0, 76.0], [17.0, 83.0]], ('CEZ2594', 0.9654235243797302)]]

We read the license plate! Number to the right of string is confidence ie ~96.5% confident string is correct. And the left side numbers is bounding box coordinates. 🥳

Next Link: Tie it all together: End-to-end License Plate Detection

Appendix: References

Appendix: Interesting Points

Folks might wonder: why not just OCR the original image? You can. But this is what you get:

Note the right hand side not the red bounding box. Firstly, three of seven characters are wrong. This is the same input we just demonstrated, same license plate same image, only without pre-processing steps. Secondly, confidence score is low. This is why the pre-processing steps.

Next Link: TBD — End-to-end real-time detection of license plates

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

原文链接:Read license plate with OCR

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
Life is simple.You make choices and you don't look back.
人生很简单,做了决定就不要后悔
评论 抢沙发

请登录后发表评论

    暂无评论内容