On-Premises ALPR

OpenALPR On-Premises software runs on your hardware/application without any Internet connection. The software can be used for general surveillance purposes or as an engine to add LPR capabilities to other applications.

Use of OpenALPR On-Premises requires a commercial license. Please contact info@openalpr.com to discuss licensing options for your project.

OpenALPR Agent

System Requirements

The OpenALPR agent scales to make use of as many CPU resources as you can provide. For example, OpenALPR can utilize up to 100 percent of the processing power on both low-power devices (such as a Raspberry Pi) and high-end devices (such as an Intel 32 CPU-core Xeon server). High-end devices are capable of processing significantly more video frames per second.

The minimum system requirements for OpenALPR agents are a function of:

  • The speed/angle of vehicles with respect to the camera (i.e., how long a legible license plate is in-frame)
  • The resolution of the input video
  • The number of camera streams analyzed by the agent
  • Other CPU load
  • The volume of vehicles (i.e., whether vehicles are seen constantly or sporadically)

As a rough rule of thumb, an OpenALPR agent running on a latest-generation Intel i5 desktop-class CPU can process roughly 20 frames of 720p video per second. In other words, an agent can handle three cameras for low-speed vehicles, two cameras for medium-speed vehicles, and one camera for high-speed vehicles. Of course, mileage may vary, and it is always best to benchmark performance on your own hardware.

Memory and disk requirements are relatively constant. Once OpenALPR initializes, the process uses roughly 500MB per analysis thread (CPU core), and that memory usage will not increase. The agent records JPEG images to a disk as plates are recognized. However, Disk IO is usually not a bottleneck.

NVIDIA GPU Acceleration

OpenALPR agent performance can also be drastically accelerated by Nvidia GPU hardware. OpenALPR maintains binaries for CUDA 8.0 using CuDNN 6 on 64-bit Ubuntu Linux 16.04. The OpenALPR software has been compiled for CUDA hardware versions 5.2 5.3 6.0 6.1 6.2 – most newer cards are supported. To enable GPU acceleration, first install the GPU binaries:

sudo apt-get update && sudo apt-get install openalprgpu

then edit the /etc/openalpr/openalpr.conf file and set:

hardware_acceleration = 1
gpu_id = 0
gpu_batch_size = 10

The batch size controls how many images are simultaneously processed by the GPU. Setting it to a higher value generally improves performance but also consumes more GPU memory.

Installation

Windows

  • Download the OpenALPR Windows Installer
  • Install the program onto your PC
  • When installation is complete, start the Configure OpenALPR program.
  • Depending on how you wish to use the OpenALPR agent, you may choose one of four options for data destination:
Windows Agent Configuration
  1. OpenALPR Cloud — Data is sent to https://cloud.openalpr.com (requires an active OpenALPR Cloud Account).
  2. OpenALPR On-Premises Web Server — You have installed the OpenALPR web server on a Linux machine and wish to point the agent data to that server.
  3. Generic HTTP Url — You wish to integrate OpenALPR with your own application. You can point the data to your own HTTP endpoint.
  4. Local Queue — You want the OpenALPR data to be stored on a local beanstalkd queue. Your application will programmatically drain the queue to process results.

If you intend to use the agent for surveillance purposes, you will most likely select the “OpenALPR On-Premises Web Server.” Options 3 and 4 are useful if you are an application developer and are integrating OpenALPR data into your own application.

Linux

  1. Download the Ubuntu 16.04 64-bit install DVD image and burn it to a DVD.
  2. Follow this installation guide to install Ubuntu 16.04 64-bit.
  3. Run the following command from the terminal:
bash <(curl http://deb.openalpr.com/install)
  1. To connect the agent to the OpenALPR Cloud, choose “install_agent”.
  2. If you wish to register the agent with an on-premises web server, do the following: - Type “n” to choose “no” to registering with the OpenALPR Cloud. - Type the command alprlink-register -w http://[ip_address_of_web_server] . - Type in the e-mail address and password that you used to install the web server.

Docker

  1. Run the command docker pull openalpr/commercial-agent to pull the latest OpenALPR docker commercial agent.
  2. Run the following command to register the agent with the service: - docker run -P -v openalpr-vol1-config:/etc/openalpr/ -v openalpr-vol1-images:/var/lib/openalpr/ -it openalpr/commercial-agent alprlink-register
  3. Start the docker container with the following command: - docker run -P -v openalpr-vol1-config:/etc/openalpr/ -v openalpr-vol1-images:/var/lib/openalpr/ -it openalpr/commercial-agent

Configuration

Agent Properties

You can configure each OpenALPR agent manually (by editing the agent configuration files) or through the OpenALPR web server. This section discusses manual configuration. Configuring the agent through the OpenALPR web server is described in the web server section of the documentation.

The primary configuration file for the OpenALPR agent is located in the /etc/openalpr/alprd.conf file. For your reference, you can find a default configuration file containing every default setting for the agent in /usr/share/openalpr/config/alprd.defaults.conf. Any value you change in alprd.conf will take precedence over the default configuration.

The following configuration options can be modified if you edit the alprd.conf file. After adding or changing values in the configuration file, you must restart the OpenALPR agent process.

Image Storage Configuration

The commercial daemon maintains a maximum disk quota and automatically cleans up after itself. Images stored to the disk are removed on a FIFO-basis. These parameters control the location, image quality, and maximum size of local image storage.

store_plates = 1
store_plates_jpeg_quality = 85
store_plates_location = /var/lib/openalpr/plateimages/
store_plates_maxsize_mb = 8000
Upload Configuration

You may enable or disable uploading. When the agent is running, all plate results will first be placed onto a local beanstalkd queue. If the upload_data parameter is set to “1” for enabled, the agent will pull results from the queue and send them to the configured “upload_address” endpoint as an HTTP POST. The upload_threads parameter will specifies the number of simultaneous data uploads. Generally, the number of threads only needs to be increased if the web server is slow to respond or network latency is exceptionally high.

upload_data = 1
upload_address = https://cloud.openalpr.com/push/
upload_threads = 2
Company ID (required)

The company_id value is sent in the JSON payload for all results. If you connect to an OpenALPR web server, this value is configured for you automatically. However, if you configure the agent manually, the value is not used, but it is still required. Any alphanumeric string will suffice.

company_id = abc-123
Motion Detection

Motion detection improves efficiency and draws more plate reads from available processors. The ALPR processing only analyzes frames with movement, ignoring areas of the image that have not changed. This parameter controls whether motion detection is enabled (1) or disabled (0).

motion_detection = 1
Parallel Processing

The ALPR processing occurs in parallel; each thread consumes an entire CPU core. Allocating more CPUs for ALPR processing will linearly increase the number of plate reads per second. If you wish to maximize the ALPR processing on your hardware, this number should map the number of CPU cores available on the system.

analysis_threads = 2
Back-Buffer Processing

With motion detection enabled, you are able to buffer moving images and analyze them as CPU becomes available. For example, if a car moves past the camera over 10 frames but the CPU can only analyze 3 of those frames in that period, the buffer allows you to analyze all 10 frames. When activity ceases, the ALPR process drains the buffer, looking for license plates during the period of movement. Increasing the buffer_size increases the duration of this period but will also consume more memory. The camera_buffer_size unit is the number of image frames.

camera_buffer_size = 60
Plate Grouping

The agent groups similar plate numbers together and sends a JSON post containing the UUIDs of every plate image in the group. These configuration files control the behavior of the plate grouping algorithm:

  • plate_groups_span_cameras – A single agent may have multiple cameras. Depending on how the cameras are positioned, they may view the same vehicles or different ones. If plate_groups_span_cameras is set to “enabled,” the grouping algorithm combines plate events that are seen by different cameras. Otherwise, they are never combined.
  • plate_groups_min_plates_to_group – A plate group must have at least this number of individual plate reads to form a group.
  • plate_groups_min_confidence – The plate read must have at least this confidence to be considered for grouping.
  • plate_groups_max_plates_to_group – At some point, if a plate is seen more than this number of times, it is wrapped into a group and sent even if the plate is still in the frame.
  • plate_groups_time_delta_ms – The plate group waits this long for another plate to be identified with a similar license plate. If a matching plate is seen, this timer is reset.
  • plate_groups_max_delay_to_send – Wait at least this long before sending a plate group event. This function is primarily intended to ensure that any back-log of processing is complete before the group event is finished. Depending on the value for camera_buffer_size, you may want to increase or decrease this value.
plate_groups_enabled = 1
plate_groups_span_cameras = 0
plate_groups_time_delta_ms = 4500
plate_groups_min_plates_to_group = 2
plate_groups_min_confidence = 80.0
plate_groups_max_plates_to_group = 500
plate_groups_max_delay_to_send = 7500
Image Retrieval

The agent may also host a local web server for retreiving images via HTTP GET requests. This web server is turned off, but you may enable it by changing the web_server_enabled parameter to 1.

web_server_enabled = 0
web_server_port = 8355
Vehicle Make/Model Classification

OpenALPR automatically classifies vehicle make/model, color, and body type for each license plate group it detects. If you are not using or do not need this feature, you can disable it to save CPU processing time.

classify_vehicles = 1

Camera Streams

The agent must be configured to connect to one or more camera streams to process license plates. OpenALPR expects to receive a URL specifying the HTTP or RTSP stream location on the IP camera. You should be able to find this URL by consulting your camera’s user manual, or with the help of an ONVIF-capable discovery tool. Once you have found the URL, you can test the stream with a video player such as VLC

To add a camera stream:

  1. Create a new unique file in /etc/openalpr/stream.d/ with the extension ”.conf”. For example, create a file named “my_new_camera.conf”.
  2. Add a line to the file with the following format: - stream = [Camera HTTP/RTSP stream URL]
  3. Restart the OpenALPR agent.

Once restarted, you should see the agent successfully connecting to the camera in the log file (/var/log/alpr.log)

Each camera configuration file may optionally be configured with the following settings:

  • prewarp - A series of numbers that adjusts the rotation/angle of the camera image before processing. The exact value can be obtained through the OpenALPR configuration utility
  • detection_mask_image - The path to a black and white image file that creates a mask over the video stream before processing. Black areas are ignored, white areas are scanned for plates.

Restarting the Agent

The OpenALPR agent must be restarted for any configuration changes to take effect.

To restart the OpenALPR agent:
  • On Windows, use the OpenALPR configuration utility or manually restart the “OpenALPR Agent” Windows service.
  • On Linux, run: sudo systemctl restart openalpr-agent.
  • On Docker, restart the container.

Web Server

Requirements

The OpenALPR web server is a web-based interface that collects, manages, and presents license plate data that has been produced by one or more OpenALPR agents. The server software installs on Ubuntu Linux.

The web server does not process license plate videos; that function is performed by the OpenALPR agent. The web server receives license plate data and stores the data in a local database. When sizing a server for the OpenALPR web server, make sure to select a sufficiently fast hard drive. For web servers supporting up to 200 OpenALPR agents, a single SSD hard drive should be sufficient. For larger installations, the server will likely need multiple hard drives configured as a RAID.

Minimum system requirements:

  • 4GB RAM
  • 250GB SSD hard drive
  • Dual-core or greater CPU
  • Ubuntu Linux 16.04 64-bit

Architecture

The OpenALPR agent reads a video stream from your IP camera, processes the stream, and uploads plate metadata to the OpenALPR web server. The agent also stores all of the plate images in a rolling buffer on the hard drive.

There is a constant stream of data flowing between the camera and the agent, as well as between the agent and the web server. The data sent to the cloud is relatively low-bandwidth because it contains text metadata describing the license plates. The OpenALPR web server does not store your plate images; these are downloaded directly from the agent when you select a plate to view from the web server.

Installation

Download the Ubuntu 16.04 64-bit install DVD image and burn it to a DVD:

Follow this installation guide to install Ubuntu 16.04 64-bit:

Run the following command from the terminal:

bash <(curl http://deb.openalpr.com/install)
OpenALPR VM installation step 4

Choose “install_webserver”:

Configuration

Agent Configuration

The OpenALPR web server may have any number of agents connected to it who send license plate data. Configuration for these agents is managed centrally on the OpenALPR web server. To configure an agent:

  • Log in to the OpenALPR web server.
  • Select Configuration -> Agents from the menu on the left-hand side of the page.
  • You should see your new agent on this screen. Select Configure to set up the camera.
  • Select Add Stream to connect your agent to the camera stream.
OpenALPR VM installation step 4
  • Select the model of IP camera you wish to connect to. Fill in the IP address. If the camera requires credentials, check the box and enter your camera’s username and password.
  • Click Test. After a few seconds, you will see a window indicating whether or not the connection was successful. If it was successful, click Save Camera. If not, try another option (such as H264 Alt1 or MJPEG) and click Test again until you succeed.
OpenALPR VM installation step 4
  • Configure the Agent Parameters.
    • Choose a sensible name for your Site ID, such as the location of the agent system (e.g., headquarters, dallas-branch, or warehouse3). Each agent should be given a unique site ID.
    • Choose the country in which the camera is located. US will recognize North American-style plates (12 inches x 6 inches). EU will recognize European-style plates. Other countries whose plates have different dimensions will also be supported.
    • The number of Processing Cores will control how much CPU will be allocated to the LPR process. The more processing cores you provide (up to the number of CPU cores on the system), the more frames per second (fps) you will be able to process. Higher fps will generally increase accuracy and allow plates on faster-moving vehicles to be detected.
    • Disk Quota will control how much space is reserved for storing vehicle and license plate images. It will operate as a rolling buffer, so when it runs out of space, the oldest images will be removed.
    • For Europe, Pattern is the country in which the camera is located. For the USA, OpenALPR uses a high-accuracy state detection algorithm to detect the state of origin, so it is better to leave the pattern set to “None” for recognition in the USA.
  • Click Update.
OpenALPR VM installation step 4
  • Finally, if you scroll to the bottom of the page, you can watch the agent status. You should now see Video FPS and other information indicating that the video is being pulled from the camera and license plates are being recognized. Now that the agent is configured, it will continue collecting data from the configured video streams. If the agent is rebooted, the OpenALPR agent will automatically start. If the camera goes down or the network becomes temporarily inoperative, the agent will retry until connectivity is restored. All results will be queued, so no data will be lost in an outage.
OpenALPR VM installation step 4

Advanced Agent Configuration

You can also configure the OpenALPR agent manually by modifying the file in /etc/openalpr/alprd.conf. This advanced option may be useful in the management of dozens or hundreds of agents. The default values with descriptions can be found here: /usr/share/openalpr/config/alprd.defaults.conf. You may add any value into the alprd.conf file; to apply changes, restart the agent.

Additional documentation on these configuration options is located in the Configuration.

To restart services, run the following command:

sudo systemctl restart openalpr-agent

To watch the OpenALPR logs, run the following command:

tail -f /var/log/alpr.log

Web Services

The Web Services API can be used to programmatically query your on-premises server for data. The API is documented here

Application Integration

You can integrate OpenALPR with your application in two ways:

  • Use the Commercial SDK to compile OpenALPR code libraries into your application and process individual image frames.
  • Run the OpenALPR Agent to directly pull video feeds and send the plate results and images to your application.

Commercial SDK

OpenALPR is available as a C/C++ library and has bindings in C#, Java, and Python. The SDK receives image frames as input, and it outputs license plate recognition results.

Installation

Windows

The Windows SDK package can be downloaded here: http://deb.openalpr.com/windows-sdk/openalpr64-sdk-latest.zip

Linux

The Linux SDK is available in OpenALPR’s commercial APT repository. The libopenalpr-dev package will install the necessary headers and library packages into your system. To install, run:

bash <(curl http://deb.openalpr.com/install)

Select “install_sdk” from the menu.

C

First, install the OpenALPR library on your target platform. Make sure the software runs by testing it with the alpr command-line executable.

  1. Add “alpr_c.h” as an include file to your project.
  2. Include the libopenalprc.dll (Windows) or libopenalprc.so (Unix) file with your binaries.
  3. Include all other required shared libraries.
  4. Insert the openalpr.conf and runtime_data directory in the same location as the binaries. Alternatively, you can specify the location of the runtime_data in openalpr.conf or directly in the code.
  5. Add a commercial license key to the “license.conf” file in the same location as the binaries.

Below is a simple example of using the OpenALPR library with the C library:

#include <stdio.h>
#include <stdlib.h>
#include <alpr_c.h>

long read_file(const char* file_path, unsigned char** buffer)
{
    FILE *fileptr;
    long filelen;

    fileptr = fopen(file_path, "rb");     // Open the file in binary mode
    if (!fileptr)
        return 0;

    fseek(fileptr, 0, SEEK_END);          // Jump to the end of the file
    filelen = ftell(fileptr);             // Get the current byte offset in the file
    rewind(fileptr);                      // Jump back to the beginning of the file

    *buffer = (unsigned char *)malloc((filelen+1)*sizeof(char)); // Enough memory for file + \0
    fread(*buffer, filelen, 1, fileptr); // Read in the entire file
    fclose(fileptr); // Close the file

    return filelen;
}

int main(int argc, char *argv[])
{
    OPENALPR* alpr_obj;

    if (argc != 2)
    {
        printf("Usage: %s [path to image file]\n", argv[0]);
        return 1;
    }

    const char* file_path = argv[1];

    // Leave the config and runtime directory blank to look for these in the current directory.
    alpr_obj = openalpr_init("us", "", "");

    if (openalpr_is_loaded(alpr_obj))
    {
        // We don't want to restrict the size of the recognition area, so we set this to an extremely large pixel size
        // rather than decode and find the actual image width/height.
        struct AlprCRegionOfInterest roi;
        roi.x = 0;
        roi.y = 0;
        roi.width = 10000;
        roi.height = 10000;

        // Read the image file
        unsigned char* buffer;
        long long length = read_file(file_path, &buffer);

        printf("file size (bytes): %d\n", length);

        if (length > 0)
        {
            char* plate_response = openalpr_recognize_encodedimage(alpr_obj, buffer, length, roi);
            printf("Alpr response:\n%s\n", plate_response);
            openalpr_free_response_string(plate_response);
        }

        free(buffer);


    }

    openalpr_cleanup(alpr_obj);


    return 0;
}

C++

The C++ commercial SDK is available for Linux. For Windows computers, we recommend that you use the C library for both C and C++ because it is ubiquitously supported across all Visual Studio toolchains.

Add “alpr.h” as an include file to your project.

Below is a simple example of using the OpenALPR library with the C library:

#include <alpr.h>

// Initialize the library using United States-style license plates.
// You can use other countries/regions as well (for example: "eu", "au", or "kr").
alpr::Alpr openalpr("us", "/path/to/openalpr.conf");

// Optionally, you can specify the top N possible plates to return (with confidences). The default is ten.
openalpr.setTopN(20);

// Optionally, you can provide the library with a region for pattern matching. This improves accuracy by
// comparing the plate text with the regional pattern.
openalpr.setDefaultRegion("md");

// Make sure the library loads before continuing.
// For example, it could fail if the config/runtime_data is not found.
if (openalpr.isLoaded() == false)
{
    std::cerr << "Error loading OpenALPR" << std::endl;
    return 1;
}

// Recognize an image file. Alternatively, you could provide the image bytes in-memory.
alpr::AlprResults results = openalpr.recognize("/path/to/image.jpg");

// Carefully observe the results. There may be multiple plates in an image,
// and each plate returns the top N candidates.
for (int i = 0; i < results.plates.size(); i++)
{
  alpr::AlprPlateResult plate = results.plates[i];
  std::cout << "plate" << i << ": " << plate.topNPlates.size() << " results" << std::endl;

    for (int k = 0; k < plate.topNPlates.size(); k++)
    {
      alpr::AlprPlate candidate = plate.topNPlates[k];
      std::cout << "    - " << candidate.characters << "\t confidence: " << candidate.overall_confidence;
      std::cout << "\t pattern_match: " << candidate.matches_template << std::endl;
    }
}

C# and VB.NET

Source code: https://github.com/openalpr/openalpr/tree/master/src/bindings/csharp

using openalprnet;

var alpr = new AlprNet("us", "/path/to/openalpr.conf", "/path/to/runtime_data");
if (!alpr.IsLoaded())
{
    Console.WriteLine("OpenAlpr failed to load!");
    return;
}
// Optionally, you can apply pattern matching for a particular region.
alpr.DefaultRegion = "md";

var results = alpr.Recognize("/path/to/image.jpg");

foreach (var result in results.Plates)
{
    Console.WriteLine("Plate {0}: {1} result(s)", i++, result.TopNPlates.Count);
    Console.WriteLine("  Processing Time: {0} msec(s)", result.ProcessingTimeMs);
    foreach (var plate in result.TopNPlates)
    {
        Console.WriteLine("  - {0}\t Confidence: {1}\tMatches Template: {2}", plate.Characters,
                          plate.OverallConfidence, plate.MatchesTemplate);
    }
}

Python

Source code: https://github.com/openalpr/openalpr/tree/master/src/bindings/python

from openalpr import Alpr

alpr = Alpr("us", "/path/to/openalpr.conf", "/path/to/runtime_data")
if not alpr.is_loaded():
    print("Error loading OpenALPR")
    sys.exit(1)

alpr.set_top_n(20)
alpr.set_default_region("md")

results = alpr.recognize_file("/path/to/image.jpg")

i = 0
for plate in results['results']:
    i += 1
    print("Plate #%d" % i)
    print("   %12s %12s" % ("Plate", "Confidence"))
    for candidate in plate['candidates']:
        prefix = "-"
        if candidate['matches_template']:
            prefix = "*"

        print("  %s %12s%12f" % (prefix, candidate['plate'], candidate['confidence']))

# Call when completely done to release memory
alpr.unload()

Java

Source code: https://github.com/openalpr/openalpr/tree/master/src/bindings/java

import com.openalpr.jni.Alpr;
import com.openalpr.jni.AlprPlate;
import com.openalpr.jni.AlprPlateResult;
import com.openalpr.jni.AlprResults;

Alpr alpr = new Alpr("us", "/path/to/openalpr.conf", "/path/to/runtime_data");

// Set top N candidates returned to 20.
alpr.setTopN(20);

// Set pattern to Maryland.
alpr.setDefaultRegion("md");

AlprResults results = alpr.recognize("/path/to/image.jpg");
System.out.format("  %-15s%-8s\n", "Plate Number", "Confidence");
for (AlprPlateResult result : results.getPlates())
{
    for (AlprPlate plate : result.getTopNPlates()) {
        if (plate.isMatchesTemplate())
            System.out.print("  * ");
        else
            System.out.print("  - ");
        System.out.format("%-15s%-8f\n", plate.getCharacters(), plate.getOverallConfidence());
    }
}

// Make sure to call this to release memory.
alpr.unload();

Node.js

A Node.js binding to OpenALPR is available here: https://www.npmjs.com/package/node-openalpr

The source code is available here: https://github.com/netPark/node-openalpr

Integrating With the Agent

The OpenALPR agent runs as either a Windows service (on Windows) or a daemon (on Linux). The process runs constantly in the background, watching the configured video streams for license plates. When a license plate is found, it immediately places JSON data onto a local beanstalkd queue for uploading or processing.

Decide whether your application should receive data from OpenALPR (sent via HTTP POST) or pull data from a queue on demand. Both approaches are equally valid; your choice simply depends on the most appropriate integration method based on your application architecture.

Receiving HTTP POSTs

The OpenALPR agent can be configured to send HTTP POSTs to your HTTP server. To enable this option, set the following parameters in /etc/openalpr/alprd.conf:

upload_data = 1
upload_address = [your HTTP server endpoint]
websockets_enabled = 0
web_server_enabled = 1

In addition, you must add a valid on-premises license to /etc/openalpr/license.conf

Once updated, restart the OpenALPR agent service to allow the settings to take effect. As plates are recognized, the JSON data described in this section will be sent to your HTTP server as an HTTP POST.

Pulling From the Queue

OpenALPR maintains a local Beanstalkd queue. All JSON results are placed onto this queue. Your application can grab and process the latest plate results from this queue .

Beanstalkd maintains client libraries in many popular programming languages. For a complete list, visit: https://github.com/kr/beanstalkd/wiki/Client-Libraries

To configure OpenALPR to make the results available via the local queue, set the following parameters in /etc/openalpr/alprd.conf:

upload_data = 0
websockets_enabled = 0
web_server_enabled = 1

In addition, you must add a valid on-premises license to /etc/openalpr/license.conf

Once updated, restart the OpenALPR agent service to allow the settings to take effect.

Below is a sample Python script that pulls results from the local Beanstalkd queue:

#!/usr/bin/python

import beanstalkc
import json
from pprint import pprint

beanstalk = beanstalkc.Connection(host='localhost', port=11300)

TUBE_NAME='alprd'

# For diagnostics, print out a list of all the tubes available in Beanstalk.
print beanstalk.tubes()

# For diagnostics, print the number of items on the current alprd queue.
try:
    pprint(beanstalk.stats_tube(TUBE_NAME))
except beanstalkc.CommandFailed:
    print "Tube doesn't exist"

# Watch the "alprd" tube; this is where the plate data is.
beanstalk.watch(TUBE_NAME)

# Loop forever
while True:

    # Wait for a second to get a job. If there is a job, process it and delete it from the queue.
    # If not, return to sleep.
    job = beanstalk.reserve(timeout=1.0)

    if job is None:
        print "No plates available right now, waiting..."

    else:
        print "Found a plate!"
        plates_info = json.loads(job.body)

        # Print all the info about this plate to the console.
        pprint(plates_info)

        # Do something with this data (e.g., match a list, open a gate, etc.).
        if 'data_type' not in plates_info:
            print "This shouldn't be here... all OpenALPR data should have a data_type"
        elif plates_info['data_type'] == 'alpr_results':
            print "This is a plate result"
        elif plates_info['data_type'] == 'alpr_group':
            print "This is a group result"
        elif plates_info['data_type'] == 'heartbeat':
            print "This is a heartbeat"

        # Delete the job from the queue when it is processed.
        job.delete()

JSON Plate Results

OpenALPR generates an “alpr_results” JSON value for every frame of video in which a license plate is recognized. This value will be sent multiple times for a single vehicle. For example, as a vehicle drives past the camera over the course of three seconds, OpenALPR may recognize the same license plate fifty times. All fifty recognition results will be recorded as alpr_results JSON values.

The number of recognition results largely depends on the processing speed and number of cameras being processed. A faster processor will produce more of these per vehicle because it is able to process video frames at a faster rate.

Individual plate results are best suited for applications that need to operate on plate data in real time.

JSON Plate results are sent in the following format:

{
  "version": 2,
  "data_type": "alpr_results",
  "epoch_time": 1490574589596,
  "img_width": 1280,
  "img_height": 720,
  "processing_time_ms": 259.132385,
  "error": false,
  "regions_of_interest": [
    {
      "x": 60,
      "y": 600,
      "width": 620,
      "height": 120
    },
    {
      "x": 0,
      "y": 0,
      "width": 1280,
      "height": 570
    }
  ],
  "results": [
    {
      "plate": "AE1T3E",
      "confidence": 93.904076,
      "matches_template": 1,
      "plate_index": 0,
      "region": "mo",
      "region_confidence": 34,
      "processing_time_ms": 17.029213,
      "requested_topn": 10,
      "coordinates": [
        {
          "x": 110,
          "y": 300
        },
        {
          "x": 227,
          "y": 295
        },
        {
          "x": 227,
          "y": 348
        },
        {
          "x": 113,
          "y": 352
        }
      ],
      "vehicle_region": {
        "x": 0,
        "y": 34,
        "width": 433,
        "height": 433
      },
      "candidates": [
        {
          "plate": "AE1T3E",
          "confidence": 93.904076,
          "matches_template": 1
        },
        {
          "plate": "AET3E",
          "confidence": 83.211739,
          "matches_template": 0
        },
        {
          "plate": "A1T3E",
          "confidence": 79.840271,
          "matches_template": 0
        },
        {
          "plate": "AE1T3F",
          "confidence": 79.130386,
          "matches_template": 1
        },
        {
          "plate": "AEIT3E",
          "confidence": 78.878433,
          "matches_template": 0
        },
        {
          "plate": "4E1T3E",
          "confidence": 78.217575,
          "matches_template": 0
        },
        {
          "plate": "AT3E",
          "confidence": 69.147926,
          "matches_template": 0
        },
        {
          "plate": "AET3F",
          "confidence": 68.438042,
          "matches_template": 0
        },
        {
          "plate": "4ET3E",
          "confidence": 67.52523,
          "matches_template": 0
        },
        {
          "plate": "A1T3F",
          "confidence": 65.066574,
          "matches_template": 0
        }
      ]
    }
  ],
  "uuid": "unspecified-cam16488027-1490574589596",
  "camera_id": 16488027,
  "agent_uid": "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
  "agent_version": "2.3.111",
  "agent_type": "alprd",
  "site_id": "unspecified",
  "company_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

JSON Group Results

OpenALPR generates an “alpr_group” JSON value for a collection of similar license plates, generally delegating a single plate group per vehicle. When the plate is not seen for a number of seconds, the plate_group result is sent with a reference (by UUID) to all the individual plate results that make up the group. The group also includes a best estimate for the license plate number based on a weighted score from all the frames included in the group.

Additionally, each plate group includes a detection value for the make/model, color, and vehicle body type.

Group results are most suitable for surveillance-type purposes. When these values are used, results may be delayed up to ten seconds after the vehicle has passed, so it is important that the application is not sensitive to this delay. If more real-time results are needed, it is recommended that you ignore the plate_group value and use only the individual plate results.

ALPR group results are sent in the following JSON format:

{
  "data_type": "alpr_group",
  "version": 2,
  "epoch_start": 1490574595962,
  "epoch_end": 1490574596287,
  "company_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "agent_uid": "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
  "agent_version": "2.3.111",
  "agent_type": "alprd",
  "site_id": "unspecified",
  "camera_id": 16488027,
  "country": "us",
  "uuids": [
    "unspecified-cam16488027-1490574595962",
    "unspecified-cam16488027-1490574596287"
  ],
  "best_plate": {
    "plate": "DA0C7L",
    "confidence": 84.679863,
    "matches_template": 1,
    "plate_index": 1,
    "region": "mo",
    "region_confidence": 96,
    "processing_time_ms": 13.995705,
    "requested_topn": 10,
    "coordinates": [
      {
        "x": 456,
        "y": 267
      },
      {
        "x": 545,
        "y": 264
      },
      {
        "x": 545,
        "y": 309
      },
      {
        "x": 457,
        "y": 312
      }
    ],
    "vehicle_region": {
      "x": 281,
      "y": 0,
      "width": 440,
      "height": 440
    },
    "candidates": [
      {
        "plate": "DAOC7L",
        "confidence": 88.139191,
        "matches_template": 0
      },
      {
        "plate": "DA0C7L",
        "confidence": 84.679863,
        "matches_template": 1
      },
      {
        "plate": "DADC7L",
        "confidence": 79.067734,
        "matches_template": 0
      },
      {
        "plate": "DAOC7U",
        "confidence": 73.676315,
        "matches_template": 0
      },
      {
        "plate": "0AOC7L",
        "confidence": 72.70826,
        "matches_template": 0
      },
      {
        "plate": "DA0C7U",
        "confidence": 70.21698,
        "matches_template": 1
      },
      {
        "plate": "0A0C7L",
        "confidence": 69.248924,
        "matches_template": 0
      },
      {
        "plate": "DADC7U",
        "confidence": 64.604858,
        "matches_template": 0
      },
      {
        "plate": "0ADC7L",
        "confidence": 63.63681,
        "matches_template": 0
      },
      {
        "plate": "0AOC7U",
        "confidence": 58.245377,
        "matches_template": 0
      }
    ]
  },
  "best_confidence": 84.679863,
  "best_uuid": "unspecified-cam16488027-1490574595962",
  "best_plate_number": "DA0C7L",
  "best_region": "mo",
  "best_region_confidence": 97.5,
  "vehicle": {
    "color": [
      {
        "name": "white",
        "confidence": 99.999962
      },
      {
        "name": "silver",
        "confidence": 4.0e-5
      },
      {
        "name": "red",
        "confidence": 5.664504e-7
      },
      {
        "name": "blue",
        "confidence": 3.373436e-7
      },
      {
        "name": "gold",
        "confidence": 2.925424e-7
      }
    ],
    "make": [
      {
        "name": "acura",
        "confidence": 64.059357
      },
      {
        "name": "lincoln",
        "confidence": 24.78327
      },
      {
        "name": "mercury",
        "confidence": 6.1188
      },
      {
        "name": "ford",
        "confidence": 4.258654
      },
      {
        "name": "volvo",
        "confidence": 0.305573
      }
    ],
    "make_model": [
      {
        "name": "acura_tl",
        "confidence": 68.735374
      },
      {
        "name": "lincoln_mks",
        "confidence": 22.445047
      },
      {
        "name": "ford_fusion",
        "confidence": 1.551949
      },
      {
        "name": "acura_rl",
        "confidence": 1.425493
      },
      {
        "name": "mercury_milan",
        "confidence": 0.626989
      }
    ],
    "body_type": [
      {
        "name": "sedan-standard",
        "confidence": 99.998665
      },
      {
        "name": "antique",
        "confidence": 0.000653
      },
      {
        "name": "sedan-compact",
        "confidence": 0.000403
      },
      {
        "name": "suv-crossover",
        "confidence": 0.000167
      },
      {
        "name": "sedan-sport",
        "confidence": 6.5e-5
      }
    ]
  }
}

JSON Heartbeat

Every minute, the OpenALPR agent adds one heartbeat message to the queue. The heartbeat provides general health and status information. The format is as follows:

{
  "data_type": "heartbeat",
  "company_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "agent_uid": "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
  "agent_version": "3.0.1",
  "openalpr_version": "2.3.111",
  "os": "linux",
  "agent_type": "alprd",
  "site_id": "unspecified",
  "timestamp": 1490039466942,
  "system_uptime_seconds": 831550,
  "daemon_uptime_seconds": 60,
  "cpu_cores": 8,
  "cpu_last_update": 1490039462237,
  "cpu_usage_percent": 50.823528,
  "disk_quota_total_bytes": 0,
  "disk_quota_consumed_bytes": 0,
  "disk_quota_last_update": 0,
  "memory_consumed_bytes": 65590419456,
  "memory_last_update": 1490039462237,
  "memory_swapused_bytes": 0,
  "memory_swaptotal_bytes": 12813594624,
  "memory_total_bytes": 67482710016,
  "processing_threads_active": 1,
  "processing_threads_configured": 1,
  "beanstalk_queue_size": -1,
  "video_streams": [
    {
      "camera_id": 16488027,
      "fps": 12,
      "is_streaming": true,
      "url": "rtsp://10.1.1.1/video.h264",
      "last_update": 1490039466541
    }
  ]
}

Local Image Retrieval

The OpenALPR agent exposes a simple web service for retrieving license plate images. Each image is referenced by a UUID that is sent along with the JSON metadata.

By default, this web server is disabled on the agent, but you can turn it on by adding “web_server_enabled = 1” to the alprd.conf file.

Assuming that the daemon port is set to the default (8355), the full image is referenced with the following URL:

  • http://[Agent_IP]:8355/img/[plate_event_uuid].jpg

In some cases, you may prefer to retrieve a cropped image of just the license plate. This requires significantly less bandwidth than downloading the entire source image. The X and Y coordinates can be computed from the JSON metadata x/y coordinates of the license plate. The x1/y1 coordinates reference the top left of the license plate crop region, and the x2/y2 coordinates reference the bottom right. For example, assuming the crop is located at (477,258), (632,297):

  • http://[Agent_IP]:8355/crop/[plate_event_uuid]?x1=477&y1=258&x2=632&y2=297

In addition, the web server exposes a web service API for searching license plates and groups. Detailed documentation is available in the web server section

Video Processing

The Forensic Plate Finder processes video or image files (e.g., MPG, AVI, or MP4) to find all of the license plates. The output is a CSV file that lists the license plate information

Installation

To use this utility, you must have a commercial license key. Contact info@openalpr.com to request an evaluation key. The license key must be saved in /etc/openalpr/license.conf.

Windows

The alpr video utility is included in the latest OpenALPR Forensic Plate Finder Installer.

After the agent is installed, the Forensic Plate Finder will be located in the [install_directory]bin directory.

Linux

Install the OpenALPR agent following the install procedure in the OpenALPR agent section.

Run the following command to install the OpenALPR video utility:

` sudo apt update && sudo apt install openalpr-video `

After the install is complete, you can execute the alpr_video utility directly on the command line.

GUI Usage

Launch the Forensic Plate Finder by clicking the “OpenALPR Forensic Plate Finder” shortcut created by the installer.

OpenALPR Forensic Plate Finder

Once launched, choose Edit->Preferences to select the country, number of processing threads, and the output directory.

Click “Open video...” to select files for processing. The utility can accept:

  • One or more video files
  • One or more JPG image files

Once you’ve selected one or more files to process, click the “Start” button to begin processing. Each file will be processed in order. A spreadsheet for each video file will be placed in the output folder that you specified in the preferences.

Command-Line Usage

Launch the alpr_video program with a path to a video file. In addition include an output directory; this is where the CSV and SQLite files are saved. The threads option provides more threads to process the video simmultaneously. This should not exceed the number of CPU cores on the machine.

USAGE:

   ./alpr_video  --output_dir <output_dir> [-c <country_code>] [--config
                 <config_file>] [-n <topN>] [--threads <num_threads>] [-p
                 <pattern code>] [--save_frames] [--debug] [--motion] [--]
                 [--version] [-h] <video_file_path>



Where:

   --output_dir <output_dir>
     (required)  Path to the output directory

   -c <country_code>,  --country <country_code>
     Country code to identify (either us for USA or eu for Europe).
     Default=us

   --config <config_file>
     Path to the openalpr.conf file

   -n <topN>,  --topn <topN>
     Max number of possible plate numbers to return.  Default=10

   --threads <num_threads>
     Number of simmultaneous processing threads. Default=1

   -p <pattern code>,  --pattern <pattern code>
     Attempt to match the plate number against a plate pattern (e.g., md
     for Maryland, ca for California)

   --save_frames
     Save the image frames for recognized license plates.  Default=off

   --debug
     Print diagnostic information to the console.  Default=off

   --motion
     Use motion detection on video file or stream.  Default=on

   --,  --ignore_rest
     Ignores the rest of the labeled arguments following this flag.

   --version
     Displays version information and exits.

   -h,  --help
     Displays usage information and exits.

   <video_file_path>
     (required)  Video file containing license plates


   OpenAlpr Forensic Plate Finder

Results

The results are made available in CSV files as well as a SQLite database for querying. The image frames in which license plates were found are also optionally saved to a folder on the disk.

The CSV data is exported in two files. One file shows the individual plate reads, while the other shows the plate groups. For example:

Plate Results:

Plate Results
id group_id country plate_number confidence frame_num video_time_s matches_pattern tracking_hash x1 y1 x2 y2 x3 y3 x4 y4 img_name region region_confidence
1 2 gb CV60UWK 78.4882 70 2.84 1   36 235 176 280 169 314 29 267   gb 0
2 2 gb CV60UWK 75.4025 73 2.96 1   134 180 269 220 260 251 127 209   gb 0
3 2 gb CV60UWK 83.4606 74 3 1   167 159 310 199 300 238 159 196   gb 0
4 2 gb CV60UWK 82.3763 75 3.04 1   198 141 332 180 322 215 189 177   gb 0

Plate groups:

Plate Groups
id country plate_number matches_pattern plate_count frame_start frame_end video_time_start_s video_time_end_s best_plate_id confidence region region_confidence
2 gb CV60UK 0 6 70 77 2.84 3.12 6 82.6058 gb 0
1 gb GP0VZC 0 9 199 211 8 8.48 18 84.4312 gb 0
4 gb GR15RYT 1 2 981 994 39.28 39.8 39 82.4912 gb 0