lucians home

Detect license plates in images using OpenALPR API

Today I wanna talk about detecting objects in images, in particular car plates.

As you can see from my articles, I like this topic because it is very broad and require hard work.
By doing such a task you can test you knowledge in computer vision field and learn more and more at every line of code.
But what I am doing next it’s not that hard; in fact, the hot part is being made by a program on a server. Up to you is to automatize the process of sorting what is interesting and what is not.

I used this to accomplish a small part of a project I am working on and which I hope to share with you as soon as possible.

What is OpenALPR ?

OpenALPR is a service/library which let you, using their API or directly in code using the library, detect a car license plate and some other information about that car.

The OpenALPR Cloud API is a hosted ALPR web service for application integration. Send images to the OpenALPR cloud servers and the response will be a JSON document describing the license plates, and vehicle variables such as color, make, and body type.

The service website is this while the library Github repository can be find here.

openalpr_example

Let’s start as usual with explanations.

First of all, that’s the task to achieve:

  • given some cars images, detect the ones that have a clearly visible plate
  • images with no plates in sight have not to be considered (aka delete them)
  • images with a plate that is visible need to have a clearly readable plate. No false positives are accepted

To do this we need to create a free account on OpenALPR Cloud API site. With a basic account you can complete this tutorial and work with other images but for full access to all features OpenALPR gives you need to upgrade the account to a premium one.

openalpr_api

You need the secret key for the Cloud API to use OpenALPR – On the right you can also see full plans offered

Once you created the account the only thing you need is the Secret Key which you can find under Cloud API section on the left side menu.

After this you need some images. I took mine from various car selling websites, mainly european.

For this tutorial we will use 10 images.

Tip: you can try with various license plate type. OpenALPR cover a wide range of plates from all over the world.

openalpr_plate_types

Before code explanation, I also created two folders in the same directory Python file (this script) is located and I called them “downloadedCars” and “detectedPlates”.

import requests
import base64
import json
import glob
import os

IMAGE_PATH = 'downloadedCars'
DETECTED_PLATES = "detectedPlates"

SECRET_KEY = "YOUR_SECRET_KEY_HERE"

for image in glob.glob(IMAGE_PATH + "\\*.jpg"):
    with open(image, 'rb') as image_file:
        img_base64 = base64.b64encode(image_file.read())

    url = 'https://api.openalpr.com/v2/recognize_bytes?recognize_vehicle=1&country=us&secret_key={}'.format(SECRET_KEY)
    r = requests.post(url, data=img_base64)

    jsonRes = json.dumps(r.json(), indent=2)
    jsonRes = json.loads(jsonRes)

    try:
        plate = jsonRes["results"][0]["plate"]
        confidence = jsonRes["results"][0]["confidence"]
        
        if confidence >= 90:
            os.rename(image, DETECTED_PLATES + "\\" + os.path.basename(image))
            print("Recognized plate, saving image: {} - {} - Confidence: {}".format(image, plate, confidence))
        else:
            os.remove(image)
            print("Plate found but confidence too low. Removing image: {} - Confidence: {}".format(image, confidence))

    except IndexError as index_error:
        print("Plate not found. Removing image: {}".format(image))
        os.remove(image)

As usual we do our imports: requests to comunicate with the API, base64 for image encoding (no OpenCV this time) and json for response parsing.

We declare some variables like folders path and secret key. Here you must paste the one created above together with you account.

To store or transfer an image, we need to convert an image to a string in such a way that the string represents the image. That’s what base64 enconding do.

We start looping images in our folder and, for each one, we encode and send a request to the OpenALPR API link (below and in code).

https://api.openalpr.com/v2/recognize_bytes?recognize_vehicle=1&country=us&secret_key={}’.format(SECRET_KEY)

Tip: other programming languages are supported, not only Python. You can find more on the official Cloud API documentation page.

Next we will take the response (in JSON format) and parse it.

The keys we are interested in are the plate and confidence.

We need the plate for plate recognition (not detection) and the confidence to put some conditions on what is to keep and what to discard.

In the end we just put some IF conditions inside a try/catch block:

  • recognized plates with a confidence higher/equal to 90 are saved (moved) to detectedPlates folder (images 8, 9, 10)
  • recognized plates but with low confidence are discarded (images 2, 3, 4)
  • images with unreadable plates are also discarded (images 1, 5, 6, 7)

Console output for our images is this:

Plate not found. Removing image: downloadedCars\1.jpg
Recognized plate, saving image: downloadedCars\10.jpg - FS546EF - Confidence: 92.65779113769531
Plate found but confidence too low. Removing image: downloadedCars\2.jpg - Confidence: 82.78751373291016
Plate found but confidence too low. Removing image: downloadedCars\3.jpg - Confidence: 65.80176544189453
Plate found but confidence too low. Removing image: downloadedCars\4.jpg - Confidence: 80.2716293334961
Plate not found. Removing image: downloadedCars\5.jpg
Plate not found. Removing image: downloadedCars\6.jpg
Plate not found. Removing image: downloadedCars\7.jpg
Recognized plate, saving image: downloadedCars\8.jpg - FP769EJ - Confidence: 94.5228500366211
Recognized plate, saving image: downloadedCars\9.jpg - FD799YW - Confidence: 92.83892822265625

Surprisingly only 3 images was saved in the end. It’s strange that image 6, for example, has not been recognized using API while no errors appear with the Demo function on Cloud API site:

openalpr_unrecognized

As you can see, and test for yourself, OpenALPR was a good tool for the task I had to do: sort images containing plates from others not containing this object.

A good tool but not perfect. During my use it detected regions that are not plates at all. The good thing is that there is no perfect tool which can do this with so many and variable images.
To achieve nearly perfect detection/recognition you need to use dedicated hardware and/or to have all your images in the same format/lightning/distance/etc.

Think of airport parking cameras: they are all at the same height, maybe also using infrared. It’s easier that way.
For real, the thing I like in OpenALPR is that it can recognize many situations. Thumbs up for this.

There is a topic which has not been covered inside this article: save detected plate (ROI).
This task is not really difficult to achieve as long as you can retrieve the plate coordinates from API response.

Guess what, YOU CAN.

coordinates = jsonRes["results"][0]["coordinates"]

It’s up to you now to try. Give these to OpenCV functions cv2.rectangle() or cv2.polylines() and you solved it.

I hope I helped you.

See you at the next article.