Getting started

The SDK works on many platforms and comes with support for many programming languages but this section focus on Android and Java. Please check the previous section for more information on how to use the sample applications.

The C++ API is defined here with Java, C# and Python bindings. Please check the source code for more samples: https://github.com/DoubangoTelecom/ultimateALPR-SDK/tree/master/samples.

Adding the SDK to your project (Android)

The Github repository contains binaries for Android, iOS, Raspberry Pi and Windows. The next sections explain how to add the SDK to an existing project.

So, to make your life easier we’ll not recommend referencing the SDK project in your application but just add references to the sources:

In your build.gradle file add:

android {

 # This is the block to add within "android { } " section
 sourceSets {
  main {
   jniLibs.srcDirs += ['path-to-your-ultimateALPR-SDK/binaries/android/jniLibs']
   java.srcDirs += ['path-to-your-ultimateALPR-SDK/java/android']
   assets.srcDirs += ['path-to-your-ultimateALPR-SDK/assets/models']
  }
 }


}

If you prefer adding the SDK as reference, then we assume you’re an experimented developer and will find how to do it by yourself or just check the sample applications (they are referencing the SDK project instead of including the sources).

Linux, Windows, Raspberry Pi and Others

The shared libraries are under “ultimateALPR-SDK/binaries/**<platform>**”. The header file at “ultimateALPR-SDK/c++”. You can use any C++ compiler/linker.

The samples are under “ultimateALPR-SDK/samples/**<platform>**”.

Using the API on Android (Java)

It’s hard to be lost when you try to use the API as there are only 3 useful functions: init, process and deInit.

The C++ API is defined here.

import org.doubango.ultimateAlpr.Sdk.ULTALPR_SDK_IMAGE_TYPE;
import org.doubango.ultimateAlpr.Sdk.UltAlprSdkEngine;
import org.doubango.ultimateAlpr.Sdk.UltAlprSdkParallelDeliveryCallback;
import org.doubango.ultimateAlpr.Sdk.UltAlprSdkResult;

final static String CONFIG = "{" +
        "\"debug_level\": \"info\"," +
        "\"gpgpu_enabled\": true," +
        "\"openvino_enabled\": true," +
        "\"openvino_device\": \"CPU\"," +

        "\"detect_minscore\": 0.1," +
        "\"detect_quantization_enabled\": true," +

        "\"pyramidal_search_enabled\": true," +
        "\"pyramidal_search_sensitivity\": 0.28," +
        "\"pyramidal_search_minscore\": 0.5," +
        "\"pyramidal_search_quantization_enabled\": true," +

        "\"klass_lpci_enabled\": true," +
        "\"klass_vcr_enabled\": true," +
        "\"klass_vmm_enabled\": true," +

        "\"recogn_score_type\": \"min\"," +
        "\"recogn_minscore\": 0.3," +
        "\"recogn_rectify_enabled\": false," +
        "\"recogn_quantization_enabled\": true" +
"}";

/**
* Parallel callback delivery function used to notify about new results.
* This callback will be called few milliseconds (before next frame is completely processed)
* after process function is called.
*/
static class MyUltAlprSdkParallelDeliveryCallback extends UltAlprSdkParallelDeliveryCallback {
        @Override
        public void onNewResult(UltAlprSdkResult result) { }
}

final MyUltAlprSdkParallelDeliveryCallback mCallback = new MyUltAlprSdkParallelDeliveryCallback(); // set to null to disable parallel mode

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


        // Initialize the engine
        assert UltAlprSdkEngine.init(
                        getAssets(),
                        CONFIG,
                        mCallback
        ).isOK();
}

// Camera listener: https://developer.android.com/reference/android/media/ImageReader.OnImageAvailableListener
final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {

        @Override
        public void onImageAvailable(ImageReader reader) {
                        try {
                            final Image image = reader.acquireLatestImage();
                            if (image == null) {
                                return;
                            }

                            // ANPR/ALPR recognition
                            final Image.Plane[] planes = image.getPlanes();
                            final UltAlprSdkResult result = UltAlprSdkEngine.process(
                                ULTALPR_SDK_IMAGE_TYPE.ULTALPR_SDK_IMAGE_TYPE_YUV420P,
                                planes[0].getBuffer(),
                                planes[1].getBuffer(),
                                planes[2].getBuffer(),
                                image.getWidth(),
                                image.getHeight(),
                                planes[0].getRowStride(),
                                planes[1].getRowStride(),
                                planes[2].getRowStride(),
                                planes[1].getPixelStride()
                            );
                            assert result.isOK();

                            image.close();

                        } catch (final Exception e) {
                           e.printStackTrace();
                        }
        }
};

@Override
public void onDestroy() {
        // DeInitialize the engine
        assert UltAlprSdkEngine.deInit().isOK();

        super.onDestroy();
}

Again, please check the sample applications for more information.

Using the C++ API

The C++ code may look like this:

#include <ultimateALPR-SDK-API-PUBLIC.h> // Include the API header file

    // JSON configuration string
    // More info at https://www.doubango.org/SDKs/anpr/docs/Configuration_options.html
    static const char* __jsonConfig =
    "{"
    "\"debug_level\": \"info\","
    "\"debug_write_input_image_enabled\": false,"
    "\"debug_internal_data_path\": \".\","
    ""
    "\"num_threads\": -1,"
    "\"gpgpu_enabled\": true,"
    "\"openvino_enabled\": true,"
    "\"openvino_device\": \"CPU\","
    ""
    "\"detect_roi\": [0, 0, 0, 0],"
    "\"detect_minscore\": 0.1,"
    ""
    "\"pyramidal_search_enabled\": true,"
    "\"pyramidal_search_sensitivity\": 0.28,"
    "\"pyramidal_search_minscore\": 0.3,"
    "\"pyramidal_search_min_image_size_inpixels\": 800,"
    ""
    "\"klass_lpci_enabled\": true,"
    "\"klass_vcr_enabled\": true,"
    "\"klass_vmm_enabled\": true,"
    ""
    "\"recogn_minscore\": 0.3,"
    "\"recogn_score_type\": \"min\""
    "}";

    // Local variable
    UltAlprSdkResult result;

    // Initialize the engine (should be done once)
    ULTALPR_SDK_ASSERT((result = UltAlprSdkEngine::init(
            __jsonConfig
    )).isOK());

    // Processing (detection + recognition)
    // Call this function for every video frame. See below on how to use the process function
    // with FFmpeg or OpenCV.
    const void* imageData = nullptr;
    ULTALPR_SDK_ASSERT((result = UltAlprSdkEngine::process(
                    ULTMICR_SDK_IMAGE_TYPE_RGB24,
                    imageData,
                    imageWidth,
                    imageHeight
            )).isOK());

    // DeInit
    // Call this function before exiting the app to free the allocate resources
    // You must not call process() after calling this function
    ULTALPR_SDK_ASSERT((result = UltAlprSdkEngine::deInit()).isOK());

FFmpeg

If you’re using FFmpeg and reading YUV420P frames from a camera, then the process function could be used like this:

AVFrame* frame = ...;

ULTALPR_SDK_ASSERT((result = UltAlprSdkEngine::process(
    ULTALPR_SDK_IMAGE_TYPE_YUV420P,
    frame->data[0], // Y
    frame->data[1], // U
    frame->data[2], // V
    frame->width, // Width
    frame->height, // Height
    frame->linesize[0], // Y-stride
    frame->linesize[1], // U-stride
    frame->linesize[2] // V-stride
)).isOK());

OpenCV

If you’re using OpenCV to capture images from the camera or RTSP stream, then the process function could be used like this:

VideoCapture cap(....);

while (1) {
    Mat frame;
    cap >> frame;

    if (frame.empty()) {
        break;
    }

    ULTALPR_SDK_ASSERT((result = UltAlprSdkEngine::process(
        ULTALPR_SDK_IMAGE_TYPE_BGR24,
        frame.ptr(),
        frame.size().width,
        frame.size().height
    )).isOK());
}