Skip to main content

Integration Guide

This guide walks you through integrating the Plate Recognizer Android SDK into your existing Android application. Follow these steps to add license plate recognition capabilities to your app.

1. Project Setup​

Copy Native Libraries​

  1. Copy the .so files from the provided project's app/src/main/jniLibs/arm64-v8a/ directory
  2. Place them in the same directory structure in your application:
your-app/
└── app/
└── src/
└── main/
└── jniLibs/
└── arm64-v8a/
├── libPlateRec.so
├── libssl.so
├── libcrypto.so
└── libtensorflowlite.so

Copy Model Assets​

  1. Copy the .dat files from the provided project's app/src/main/assets/ directory
  2. Place them in your application's assets directory:
your-app/
└── app/
└── src/
└── main/
└── assets/
├── asset0.dat
└── asset1.dat

Add Permissions​

Add the following permissions to your AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
tip

For devices running Android 6.0 (API 23) or higher, request these permissions at runtime using ActivityCompat.requestPermissions() before initializing the SDK to avoid crashes.

Configure build.gradle​

Ensure your app's build.gradle file is configured for ARM64 and a minimum SDK version of 24:

android {
defaultConfig {
minSdkVersion 24
ndk {
abiFilters 'arm64-v8a'
}
}
}

2. SDK Initialization​

Initialize the SDK once when your application starts. A good place for this is in your Application class.

import com.parkpow.platerec.Snapshot

class YourApplication : Application() {
override fun onCreate() {
super.onCreate()

val success = Snapshot.enginePrepare(
context = applicationContext,
token = "YOUR_TOKEN", // See Getting Started for credential setup
licenseKey = "YOUR_LICENSE_KEY", // See Getting Started for credential setup
writablePath = applicationContext.filesDir.absolutePath,
assetManager = applicationContext.assets
)

if (!success) {
Log.e("PlateRecognizer", "SDK initialization failed")
}
}
}
danger

For information on obtaining your credentials, see the Obtaining Your Credentials section.

Initialization Parameters​

Refer to the Snapshot.enginePrepare() for detailed information about the parameters used.

3. Image Processing​

To process an image, call Snapshot.engineProc(). This method is thread-safe and should be called on a background thread to avoid blocking the UI.

Basic Image Processing​

warning

The doMmc and doDirection parameters require the MMC (Make, Model, Color) package. If you don't have the MMC package, set both to false. See MMC Package Requirements for details.

import com.parkpow.platerec.Snapshot
import org.json.JSONObject

// Process an image from a file path
val resultJson = Snapshot.engineProc(
filename = "/path/to/your/image.jpg",
configJson = "{}", // Optional JSON configuration
regions = arrayOf("us", "eu"), // Specify regions
doMmc = true, // Enable Make, Model, Color detection (requires MMC package)
doDirection = true, // Enable direction detection (requires MMC package)
cameraId = "front-camera", // Optional
timestamp = System.currentTimeMillis().toString() // Optional
)

// Parse the JSON response
val jsonObject = JSONObject(resultJson)

Processing Parameters​

Refer to the Snapshot.engineProc() for detailed information about the parameters used.

Advanced Configuration​

You can provide custom configuration in the configJson parameter:

val config = """
{
"threshold_d": 0.1,
"threshold_o": 0.3,
"detect_alphabets": ["A-Z", "0-9"],
"region": "us"
}
"""

val resultJson = Snapshot.engineProc(
filename = "/path/to/your/image.jpg",
configJson = config,
regions = arrayOf("us"),
doMmc = true, // Requires MMC package
doDirection = false,
cameraId = "entrance-camera",
timestamp = System.currentTimeMillis().toString()
)

Background Processing Example​

class PlateRecognitionWorker(private val context: Context) {

fun processImageAsync(imagePath: String, callback: (String) -> Unit) {
Thread {
try {
val result = Snapshot.engineProc(
filename = imagePath,
configJson = "{}",
regions = arrayOf("us", "ca"),
doMmc = true, // Requires MMC package
doDirection = false,
cameraId = "worker-camera",
timestamp = System.currentTimeMillis().toString()
)

// Return result on main thread
Handler(Looper.getMainLooper()).post {
callback(result)
}
} catch (e: Exception) {
Log.e("PlateRecognition", "Processing failed", e)
Handler(Looper.getMainLooper()).post {
callback("{\"error\": \"${e.message}\"}")
}
}
}.start()
}
}

4. Sample Response​

A successful call to engineProc() returns a JSON string with the recognition results:

{
"processing_time": 0.123,
"results": [
{
"box": {
"xmin": 316,
"ymin": 187,
"xmax": 466,
"ymax": 227
},
"plate": "ABC123",
"score": 0.901,
"candidates": [
{
"score": 0.901,
"plate": "ABC123"
}
]
}
],
"usage": {
"calls": 1,
"max_calls": 1000
}
}

Response Fields​

  • processing_time: Time taken to process the image in seconds
  • results: Array of detected license plates
    • box: Bounding box coordinates of the detected plate
    • plate: The recognized license plate text
    • score: Confidence score (0.0 to 1.0)
    • candidates: Alternative plate possibilities
  • usage: API usage statistics
tip

For detailed information about the response format, refer to Snapshot SDK Response Format.

5. Cleanup​

Call engineOnStop() when your application is shutting down to ensure all data is saved correctly:

class MainActivity : Activity() {
override fun onDestroy() {
super.onDestroy()
Snapshot.engineOnStop(this)
}
}

Error Handling​

Wrap calls to engineProc() in a try-catch block to handle potential exceptions:

try {
val result = Snapshot.engineProc(...)
// Process result
} catch (e: Exception) {
Log.e("PlateRecognizer", "Recognition failed", e)
// Handle error
}

Additionally, check the JSON response from engineProc() for error fields:

val jsonObject = JSONObject(resultJson)
if (jsonObject.has("error")) {
val errorCode = jsonObject.getString("error")
Log.e("PlateRecognizer", "Recognition error: $errorCode")
// Handle specific error codes
}

Best Practices​

  1. Initialize Once: Call enginePrepare() once at application startup
  2. Background Processing: Always run engineProc() on a background thread
  3. Error Handling: Implement robust error handling for all SDK calls
  4. Resource Management: Call engineOnStop() when the app is destroyed
  5. Image Quality: Pre-process camera frames to ensure good image quality
  6. Memory Management: Process one image at a time per thread

Next Steps​

Now that you have successfully integrated the SDK, explore the API Reference for detailed information about all available methods and parameters.