Reputation: 71
I'm also new to flutter and tesseract so might be a problem with my understanding.
I am wanting to make an app that takes an image from my gallery and can read the text from them.
I'm using Google ML Kit Text Recognition V2 for this, however I want to account for cases where text is not correctly facing and so need the OSD, specifically the orientation.
I have been able to get this using the CLI and pytesseract
with a simple python script but have been having trouble doing the same with flutter.
I'm pretty sure that the tessdata
is in the correct directory. I've created a assets/tessdata/tessdata_config.json
and added the necessary traineddata files into assets/tessdata
directory and added both to the pubspec.yaml
.
"main.dart"
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import 'package:google_mlkit_text_recognition/google_mlkit_text_recognition.dart';
import 'package:flutter_application_cards/preprocess_img.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key, this.imgPicker});
final ImagePicker? imgPicker;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FF photos',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: MyHomePage(
title: 'FF photos',
imagePicker: imgPicker ?? ImagePicker(),
),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title, required this.imagePicker});
final String title;
final ImagePicker imagePicker;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
XFile? _mediaFile;
String _recognizedText = '';
/// Picks an image from the selected source (Gallery or Camera)
Future<void> _pickImage(ImageSource source) async {
try {
final XFile? pickedFile = await widget.imagePicker.pickImage(source: source);
if (pickedFile != null) {
setState(() {
_mediaFile = pickedFile;
});
_processImage(File(pickedFile.path));
}
} catch (e) {
print('Error picking image: $e');
}
}
/// Processes the image and extracts text using Google ML Kit
Future<void> _processImage(File imageFile) async {
// Put preprocessing function in here
await isImgBlurry(imageFile);
final inputImage = InputImage.fromFile(imageFile);
final textRecognizer = TextRecognizer();
try {
final RecognizedText recognizedText = await textRecognizer.processImage(inputImage);
setState(() {
_recognizedText = recognizedText.text;
});
print('Recognized Text:\n$_recognizedText');
} catch (e) {
print('Error recognizing text: $e');
} finally {
textRecognizer.close();
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_mediaFile == null
? const Text('No image selected.')
: Image.file(File(_mediaFile!.path), height: 250),
const SizedBox(height: 20),
ElevatedButton.icon(
onPressed: () => _pickImage(ImageSource.gallery),
icon: const Icon(Icons.photo_library),
label: const Text('Pick from Gallery'),
),
const SizedBox(height: 10),
ElevatedButton.icon(
onPressed: () => _pickImage(ImageSource.camera),
icon: const Icon(Icons.camera_alt),
label: const Text('Take Photo'),
),
const SizedBox(height: 20),
_recognizedText.isNotEmpty
? Padding(
padding: const EdgeInsets.all(16.0),
child: Text(_recognizedText),
)
: Container(),
],
),
),
);
}
}
"preprocess_img.dart"
import 'dart:io';
import 'package:opencv_core/opencv.dart';
import 'package:flutter_tesseract_ocr/flutter_tesseract_ocr.dart';
Future<void> isImgBlurry(File img, {double threshold = 100.0}) async {
final test = imread(img.path);
// Convert to grayscale
final Mat grayImg = cvtColor(test, COLOR_BGR2GRAY);
// Use laplacian method
Mat lapImg = laplacian(grayImg, MatType.CV_64F);
final double variance = lapImg.variance().val1;
if (variance < threshold) {
print("$variance, blurry");
}
else {
print("Not blurry");
}
String osdData = await FlutterTesseractOcr.extractText(img.path, language: 'eng', args: {"psm": "0"});
// psm 0 = Orientation and script detection (OSD) only.
// String is empty
print("Image osd:\n$osdData");
int orientation = 0;
int rotate = 0;
String script = "N/A";
RegExp orientationRegExp = RegExp(r'Orientation in degrees: (\d+)');
RegExp rotateRegExp = RegExp(r'Rotate: (\d+)');
RegExp scriptRegExp = RegExp(r'Script: (\w+)');
Match? orientationMatch = orientationRegExp.firstMatch(osdData);
Match? rotateMatch = rotateRegExp.firstMatch(osdData);
Match? scriptMatch = scriptRegExp.firstMatch(osdData);
if (orientationMatch != null) {
orientation = int.parse(orientationMatch.group(1)!);
}
if (rotateMatch != null) {
rotate = int.parse(rotateMatch.group(1)!);
}
if (scriptMatch != null) {
script = scriptMatch.group(1)!;
}
// Output the extracted information
print("Detected Orientation: $orientation degrees");
print("Rotate by: $rotate degrees to correct");
print("Detected Script: $script");
}
Upvotes: 0
Views: 28