Android License Plate Scanner SDK - Introduction
Introduction
The Scanbot SDK provides the ability to scan car license plates and parse data fields. Scanning is currently limited to common EU license plates (country code on blue background on the left side).
The License plate scanner is available both as an RTU UI and as a classic component (types of components are explained here).
Integration
Take a look at our Example Apps to see how to integrate the License Plate scanner.
- Ready-To-Use UI: ready-to-use-ui-demo
- Classic UI Components: licenseplate-scanner
Add Feature as a Dependency
LicensePlateScanner
is available with SDK Package 4. You have to add the following dependencies for it:
implementation("io.scanbot:sdk-package-4:$latestSdkVersion")
implementation("io.scanbot:sdk-licenseplate-assets:$latestSdkVersion")
Please do not use multiple scanners at the same time. For example, do not combine generic document scanner, health insurance scanner, text data scanner, etc. at the same time! Each scanner instance requires a lot of memory, GPU, and processor resources. Using multiple scanners will lead to performance issues for the entire application.
Initialize the SDK
The License Plate Scanner is based on the OCR feature of the Scanbot SDK. Please check the Optical Character Recognition docs for more details.
In order to use the License Plate Scanner you need to prepare the English OCR language file.
Place the file eng.traineddata
in the assets sub-folder assets/ocr_blobs/
of your app.
Add a call to .prepareOCRLanguagesBlobs(true)
method for ScanbotSDKInitializer in your Application
class.
import io.scanbot.sdk.ScanbotSDKInitializer
...
ScanbotSDKInitializer()
.prepareOCRLanguagesBlobs(true)
...
.initialize(this)
Ready-To-Use UI Component
Ready-To-Use UI Component (activity) that is responsible for scanning license plates is LicensePlateScannerActivity
.
Have a look at our end-to-end working example of the RTU components usage here.
Starting and configuring RTU license plate scanner
First of all, you have to add the SDK package and feature dependencies as described here.
Initialize the SDK as described here. More information about the SDK license initialization can be found here.
To use any of the RTU UI components you need to include the corresponding dependency in your build.gradle
file:
implementation("io.scanbot:sdk-package-ui:$scanbotSdkVersion")
Get the latest $scanbotSdkVersion
from the Changelog.
To start the RTU UI license plate scanner you only have to start a new activity and be ready to process its result later.
Starting from version 1.90.0, the SDK RTU components contain predefined AndroidX Result API contracts. They handle part of the boilerplate for starting the RTU activity component and mapping the result once it finishes.
If your code is bundled with Android's deprecated startActivityForResult
API - check the other approach we offer for this case.
- AndroidX Result API
- old 'startActivityForResult' approach
val licensePlateResult: ActivityResultLauncher<LicensePlateScannerConfiguration>
...
licensePlateResult = registerForActivityResult(LicensePlateScannerActivity.ResultContract()) { resultEntity: LicensePlateScannerActivity.Result ->
if (resultEntity.resultOk) {
Toast.makeText(this@MainActivity, formatResult(resultEntity.result), Toast.LENGTH_LONG).show()
}
}
...
myButton.setOnClickListener {
val configuration = LicensePlateScannerConfiguration()
licensePlateResult.launch(configuration)
}
myButton.setOnClickListener {
val configuration = LicensePlateScannerConfiguration()
val intent = LicensePlateScannerActivity.newIntent(this@MainActivity, configuration)
startActivityForResult(intent, LICENSE_PLATE_REQUEST_CODE_CONSTANT)
}
if (requestCode == LICENSE_PLATE_REQUEST_CODE_CONSTANT) {
val result: LicensePlateScannerActivity.Result = LicensePlateScannerActivity.extractResult(resultCode, data)
if (result.resultOk) {
Toast.makeText(this@MainActivity, formatResult(result), Toast.LENGTH_LONG).show()
}
}
We offer some syntactic sugar for handling the result from RTU components via AndroidX Result API:
every RTU component's activity contains a
Result
class which, in turn, along with theresultCode
value exposes a BooleanresultOk
property. This will be true ifresultCode
equalsActivity.RESULT_OK
;when you only expect
Activity.RESULT_OK
result code - you can use theAppCompatActivity.registerForActivityResultOk
extension method instead ofregisterForActivityResult
- it will be triggered only when there is a non-nullable result entity present.
Always use the corresponding activity's static newIntent
method to create intent when starting the RTU UI activity using deprecated startActivityForResult
approach. Creating android.content.Intent
object using its constructor (passing the activity's class as a parameter) will lead to the RTU UI component malfunctioning.
An instance of LicensePlateScannerConfiguration
is required for starting the RTU UI activity. It allows configuration changes through methods it exposes:
val configuration = LicensePlateScannerConfiguration()
configuration.setFlashEnabled(false)
configuration.setCancelButtonTitle("Stop")
configuration.setConfirmationDialogTitle("Double-check the result")
configuration.setFinderTextHint("Place the plate in the scanning rectangle")
configuration.setScanStrategy(LicensePlateScanStrategy.LicensePlateML)
All parameters in LicensePlateScannerConfiguration
are optional.
API references for all of these methods can be found on this page.
Handling the result
Below is a simple example of presenting the result: LicensePlateScannerResult
fields separated by a newline character, shown in a Toast notification.
val licensePlateString = StringBuilder()
.append("Raw scanned text: ${result.rawText}")
.append("\nCountry code: ${result.countryCode}")
.append("\nLicense plate: ${result.licensePlate}")
.append("\nConfidence level: ${result.confidence}%")
.toString()
Toast.makeText(this@MainActivity, licensePlateString, Toast.LENGTH_LONG).show()
Full API references for the result class are available here.
Classic component
Try our License Plate Scanner Example or check the following step by step integration instructions.
LicensePlateScanner
can only be used in conjunction with ScanbotCameraXView
for live detection with preview. Let's have a look at an example.
Add feature depedencies and initialize the SDK
First of all, you have to add the SDK package and feature dependencies as described here.
Initialize the SDK as described here. More information about the SDK license initialization can be found here.
Add ScanbotCameraXView
to layout
<io.scanbot.sdk.ui.camera.ScanbotCameraXView
android:id="@+id/camera_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Get LicensePlateScanner
instance from ScanbotSDK
, and attach it to ScanbotCameraXView
val scanbotSdk = ScanbotSDK(this)
val licensePlateScanner = scanbotSdk.createLicensePlateScanner()
val licensePlateScannerFrameHandler = LicensePlateScannerFrameHandler.attach(cameraView, licensePlateScanner)
Add a result handler for LicensePlateScannerFrameHandler
:
Add a frame handler which observes successful recognition status and, for example, sets the scanned data to a properly formatted resultTextView
.
licensePlateScannerFrameHandler.addResultHandler(LicensePlateScannerFrameHandler.ResultHandler { result ->
val resultText: String = when (result) {
is FrameHandlerResult.Success -> {
if (result.value.validationSuccessful) {
result.value.rawString
} else {
"License plate not found"
}
}
is FrameHandlerResult.Failure -> "Check your setup or license"
}
// NOTE: 'handle' method runs in background thread - don't forget to switch to main before touching any Views
runOnUiThread { resultTextView.text = resultText }
false
})
As the result of scanning, the user gets the LicensePlateScanResult
class instance, which contains a cropped image of the recognized license plate area and a list of data fields.
The fields represent the license plate country code, license plate number, raw recognized text, scanning confidence value, etc.
Add a Finder Overlay
In addition, it is recommended to add a "Finder Overlay". This feature allows you to predefine a license plate-shaped area over the ScanbotCameraXView
screen. By using this overlay the scanner can skip the time-consuming step "Search for license plate" and perform the recognition directly in the specified "Finder Overlay" area. By using this approach the scanner recognizes and extracts the license plate content much faster.
Details about applying finder view logic in the layout and in the code can be found here.
Want to scan longer than one minute?
Generate a free trial license to test the Scanbot SDK thoroughly.
Get your free Trial LicenseWhat do you think of this documentation?
What can we do to improve it? Please be as detailed as you like.