indian_number_plate_ocr 🇮🇳 🚗
A powerful, high-precision Flutter & Dart package for OCR and automatic extraction of Indian vehicle registration number plates using Google ML Kit.
Designed specifically to handle the complexities of Indian number plates—including HSRP watermarks, two-line / multi-line layouts, side-by-side plates, Bharat (BH) series, Military vehicles, and common OCR visual misreads.
✨ Key Features
- 🚘 Standard Civilian & Commercial Plates: Fully supports 2-letter State codes (
DL,MH,KA, etc.), RTO codes (up to 3 characters including alphanumeric series likeDL 8C), series letters, and 4-digit numbers. - 🇮🇳 Bharat (BH) Series: Native detection and extraction of Bharat series registrations (e.g.,
22 BH 6517 A). - ⚔️ Military & Armed Forces Plates: Extracts Indian defense vehicle plates (e.g.,
03D153874W,14A1478T) while preventing false positive tails. - 🛡️ HSRP Watermark & Noise Filtering: Automatically strips out background text, camera timestamps, watermark text (
IND,INDIA,BHARAT,SARKAR,SHUTTERSTOCK), and Hindi text (न भारत सरकार). - 📐 Multi-Line & Side-by-Side Plate Assembly: Intelligently groups 2-line or 3-line plates mounted on vehicles, and uses ordinal prefix-pairing to accurately separate multiple cars parked side-by-side without cross-contamination.
- 🧠 Smart OCR Error Recovery: Automatically corrects common camera misreads:
- Digit
0vs letterOin RTO and series codes. - Digit
1vsI/l/|. - Common state code visual confusions (e.g., reading
WHasMH,SNasTN,HHasMH,OL/QLasDL). - Specific multi-letter misreads like
FO$\rightarrow$FQ,C0$\rightarrow$CQ, andOV$\rightarrow$DV, while strictly preserving legitimate'O'series vehicle registrations (e.g.,DL 7C O 2314).
- Digit
📦 Installation
Add indian_number_plate_ocr to your pubspec.yaml:
dependencies:
flutter:
sdk: flutter
indian_number_plate_ocr: ^1.0.0
Then run:
flutter pub get
🚀 How to Use
1. Basic Setup & Initialization
Import the package in your Dart file and initialize the IndianPlateOcrService:
import 'package:indian_number_plate_ocr/indian_number_plate_ocr.dart';
class MyScanner {
final IndianPlateOcrService _ocrService = IndianPlateOcrService();
void dispose() {
// Remember to dispose the OCR service when your widget or controller is destroyed!
_ocrService.dispose();
}
}
2. Extracting from Camera or Image File (extractPlatesFromImage)
You can directly pass the path of a photo taken via image_picker or camera:
import 'package:image_picker/image_picker.dart';
import 'package:indian_number_plate_ocr/indian_number_plate_ocr.dart';
Future<void> scanCarPhoto() async {
final picker = ImagePicker();
final XFile? photo = await picker.pickImage(source: ImageSource.camera);
if (photo != null) {
final IndianPlateOcrService ocrService = IndianPlateOcrService();
// Scans image using Google ML Kit and extracts validated Indian number plates
final List<String> extractedPlates = await ocrService.extractPlatesFromImage(photo.path);
print('Found Number Plates: $extractedPlates');
// Example Output: ['DL7CQ1939', 'MH10DV3465']
ocrService.dispose();
}
}
3. Extracting from Raw OCR Text (extractPlatesFromText)
If you are already performing text recognition or receiving string data from a backend or scanner, use extractPlatesFromText:
final IndianPlateOcrService ocrService = IndianPlateOcrService();
const String rawTextFromCamera = '''
IND DL 7C Q IND DL 7C O
न भारत सरकार न भारत सरकार
AA123456789 AA123456789
1939 2314
''';
final List<String> plates = ocrService.extractPlatesFromText(rawTextFromCamera);
print(plates);
// Output: ['DL7CQ1939', 'DL7CO2314']
4. Extracting Raw OCR Text (extractRawText)
If you need the raw unedited string recognized by Google ML Kit from an image before plate validation:
final String? rawText = await ocrService.extractRawText(photo.path);
print('Raw OCR string: $rawText');
🏗️ Supported Plate Formats
| Plate Category | Sample Input Text | Extracted Normalized Output |
|---|---|---|
| Standard Civilian | WB 06 F 5977, KA 19 P 8488 |
WB06F5977, KA19P8488 |
| Alphanumeric RTO | DL 8C AC 4194, DL 7C Q 1939 |
DL8CAC4194, DL7CQ1939 |
| Bharat (BH) Series | 22 BH 6517 A |
22BH6517A |
| Military / Defense | ^03D153874W, KA 19 EQ 1316 E |
03D153874W, KA19EQ1316 |
| Two-Line / Stacked | PB 10 GN 4497 |
PB10GN4497 |
| Side-by-Side (2 Cars) | IND DL 7C Q IND DL 7C O 1939 2314 |
DL7CQ1939, DL7CO2314 |
🛠️ Best Practices & Tips
- Camera Resolution & Focus: Ensure the number plate occupies a reasonable portion of the camera frame.
- Dispose Resource: Always call
ocrService.dispose()inside your widget'sdispose()method to release ML Kit native resources. - Hot Restart in Flutter: If you modify OCR logic or update package dependencies in an actively running app, perform a Hot Restart (
Shift + F5orR) instead of Hot Reload so that the underlying service binaries reload into device memory.
📄 License
This project is licensed under the MIT License.