Flutter光学字符识别插件flutter_tesseract_ocr的使用

发布于 1周前 作者 vueper 来自 Flutter

Flutter光学字符识别插件flutter_tesseract_ocr的使用

Tesseract OCR 4.0 for flutter 是一个基于 Tesseract OCR 4 的Flutter插件,它在Android上使用 Tesseract4Android,在iOS上使用 SwiftyTesseract。这个插件可以帮助你在Flutter应用中实现光学字符识别(OCR)功能。

安装

添加依赖

pubspec.yaml文件中添加flutter_tesseract_ocr依赖:

dev_dependencies:
  ...
  flutter_tesseract_ocr:

Web环境

对于Web项目,在./web/index.html中引入Tesseract.js

<body>
  <script src='https://unpkg.com/tesseract.js@v4.0.2/dist/tesseract.min.js'></script>
  <script>
    async function _extractText(imagePath, mapData){
      var worker = await Tesseract.createWorker();
      await worker.load();
      await worker.loadLanguage(mapData.language)
      await worker.initialize(mapData.language)
      await worker.setParameters(mapData.args)
      var rtn = await worker.recognize(imagePath, {}, worker.id);
      await worker.terminate();
      if(mapData.args["tessjs_create_hocr"]){
        return rtn.data.hocr;
      }
      return rtn.data.text;
    }
  </script>
  ...
  ..
  .
</body>

配置训练数据

为了使OCR插件能够识别特定语言的文字,你需要为项目添加相应的训练数据和配置文件。

  1. 在assets目录下创建tessdata文件夹,并将需要的语言包(如eng.traineddata等)放入其中。
  2. 在assets目录下创建tessdata_config.json文件,内容如下:
    {
      "files": [
        "eng.traineddata",
        "<other_language>.traineddata"
      ]
    }
    
  3. 确保在pubspec.yaml中正确配置了资源路径:
    flutter:
      assets:
        - assets/tessdata/
        - assets/tessdata_config.json
    

对于iOS平台,如果遇到初始化失败的问题,可以尝试将tessdata文件夹从assets拖放到Xcode中的Runner文件夹,并选择“Create folder references”。

使用示例

下面是一个完整的Flutter应用示例,展示了如何使用flutter_tesseract_ocr进行OCR操作。此示例允许用户通过图像选择器选择图片或输入图片URL来执行OCR,并支持多语言识别。

import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_tesseract_ocr/flutter_tesseract_ocr.dart';
import 'dart:io';
import 'package:flutter/foundation.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Tesseract Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Tesseract Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _ocrText = '';
  Map<String, String> tessimgs = {
    "kor": "https://raw.githubusercontent.com/khjde1207/tesseract_ocr/master/example/assets/test1.png",
    "en": "https://tesseract.projectnaptha.com/img/eng_bw.png",
    "ch_sim": "https://tesseract.projectnaptha.com/img/chi_sim.png",
    "ru": "https://tesseract.projectnaptha.com/img/rus.png",
  };
  var LangList = ["kor", "eng", "deu", "chi_sim"];
  var selectList = ["eng"];
  String path = "";
  bool bload = false;

  Future<void> writeToFile(ByteData data, String path) async {
    final buffer = data.buffer;
    return File(path).writeAsBytes(
        buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));
  }

  void runFilePicker() async {
    final pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery);
    if (pickedFile != null) {
      _ocr(pickedFile.path);
    }
  }

  void _ocr(String url) async {
    if (selectList.isEmpty) {
      print("Please select language");
      return;
    }
    path = url;
    if (!kIsWeb && (url.startsWith("http://") || url.startsWith("https://"))) {
      Directory tempDir = await getTemporaryDirectory();
      HttpClient httpClient = HttpClient();
      HttpClientRequest request = await httpClient.getUrl(Uri.parse(url));
      HttpClientResponse response = await request.close();
      Uint8List bytes = await consolidateHttpClientResponseBytes(response);
      String dir = tempDir.path;
      File file = File('$dir/test.jpg');
      await file.writeAsBytes(bytes);
      url = file.path;
    }
    var langs = selectList.join("+");

    bload = true;
    setState(() {});

    _ocrText = await FlutterTesseractOcr.extractText(url, language: langs, args: {
      "preserve_interword_spaces": "1",
    });

    bload = false;
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Stack(
        children: [
          Padding(
            padding: EdgeInsets.all(10),
            child: Column(
              children: [
                Row(
                  children: [
                    ElevatedButton(
                        onPressed: () {
                          showDialog(
                              context: context,
                              builder: (BuildContext context) {
                                return SimpleDialog(
                                  title: const Text('Select Url'),
                                  children: tessimgs.entries.map((entry) {
                                    return SimpleDialogOption(
                                        onPressed: () {
                                          TextEditingController().text = entry.value;
                                          setState(() {});
                                          Navigator.pop(context);
                                        },
                                        child: Row(
                                          children: [
                                            Text(entry.key),
                                            Text(" : "),
                                            Flexible(child: Text(entry.value)),
                                          ],
                                        ));
                                  }).toList(),
                                );
                              });
                        },
                        child: Text("urls")),
                    Expanded(
                      child: TextField(
                        decoration: InputDecoration(
                          border: OutlineInputBorder(),
                          labelText: 'input image url',
                        ),
                        controller: TextEditingController(),
                      ),
                    ),
                    ElevatedButton(
                        onPressed: () {
                          _ocr(TextEditingController().text);
                        },
                        child: Text("Run")),
                  ],
                ),
                Row(
                  children: LangList.map((e) {
                    return Row(children: [
                      Checkbox(
                          value: selectList.contains(e),
                          onChanged: (v) async {
                            if (!kIsWeb) {
                              Directory dir = Directory(await FlutterTesseractOcr.getTessdataPath());
                              if (!dir.existsSync()) {
                                dir.createSync();
                              }
                              bool isInstalled = dir.listSync().any((element) => element.path.endsWith('$e.traineddata'));
                              if (!isInstalled) {
                                HttpClient httpClient = HttpClient();
                                HttpClientRequest request = await httpClient.getUrl(Uri.parse('https://github.com/tesseract-ocr/tessdata/raw/main/${e}.traineddata'));
                                HttpClientResponse response = await request.close();
                                Uint8List bytes = await consolidateHttpClientResponseBytes(response);
                                String dir = await FlutterTesseractOcr.getTessdataPath();
                                File file = File('$dir/${e}.traineddata');
                                await file.writeAsBytes(bytes);
                              }
                            }
                            if (selectList.contains(e)) {
                              selectList.remove(e);
                            } else {
                              selectList.add(e);
                            }
                            setState(() {});
                          }),
                      Text(e)
                    ]);
                  }).toList(),
                ),
                Expanded(
                    child: ListView(
                  children: [
                    path.isEmpty
                        ? Container()
                        : path.startsWith("http")
                            ? Image.network(path)
                            : Image.file(File(path)),
                    bload
                        ? CircularProgressIndicator()
                        : Text('$_ocrText'),
                  ],
                ))
              ],
            ),
          ),
        ],
      ),
      floatingActionButton: kIsWeb
          ? Container()
          : FloatingActionButton(
              onPressed: () {
                runFilePicker();
              },
              tooltip: 'OCR',
              child: Icon(Icons.add),
            ),
    );
  }
}

请注意,上述代码片段中的一些逻辑已经被简化以提高可读性。例如,TextEditingController()应替换为实际的控制器实例,以便正确处理用户输入。此外,对于动态加载语言包的部分,确保网络请求和文件写入操作都在异步上下文中执行,以避免阻塞主线程。


更多关于Flutter光学字符识别插件flutter_tesseract_ocr的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter光学字符识别插件flutter_tesseract_ocr的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用flutter_tesseract_ocr插件进行光学字符识别(OCR)的示例代码。这个插件允许你从图像中提取文本。

首先,确保你的Flutter项目中已经添加了flutter_tesseract_ocr依赖。在你的pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_tesseract_ocr: ^0.3.2  # 请检查最新版本号

然后运行flutter pub get来安装依赖。

接下来,你需要确保在Android和iOS项目中配置了必要的权限和设置。

Android配置

android/app/src/main/AndroidManifest.xml中添加权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

iOS配置

ios/Runner/Info.plist中添加权限:

<key>NSPhotoLibraryUsageDescription</key>
<string>App needs access to photo library to perform OCR</string>
<key>NSCameraUsageDescription</key>
<string>App needs access to camera to capture images for OCR</string>

Flutter代码示例

以下是一个完整的Flutter应用示例,展示如何使用flutter_tesseract_ocr插件从图像中提取文本:

import 'package:flutter/material.dart';
import 'package:flutter_tesseract_ocr/flutter_tesseract_ocr.dart';
import 'package:image_picker/image_picker.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: OcrScreen(),
    );
  }
}

class OcrScreen extends StatefulWidget {
  @override
  _OcrScreenState createState() => _OcrScreenState();
}

class _OcrScreenState extends State<OcrScreen> {
  final ImagePicker _picker = ImagePicker();
  File? _imageFile;
  String _ocrResult = '';

  Future<void> _pickImage() async {
    final pickedFile = await _picker.pickImage(source: ImageSource.camera);

    if (pickedFile != null) {
      setState(() {
        _imageFile = File(pickedFile.path);
      });

      _performOCR();
    }
  }

  Future<void> _performOCR() async {
    if (_imageFile != null) {
      try {
        String result = await TesseractOcr.recognizeText(
          image: _imageFile!,
          language: 'eng'  // 你可以指定其他语言代码,比如 'chi_sim' 表示简体中文
        );

        setState(() {
          _ocrResult = result;
        });
      } catch (e) {
        print('OCR error: $e');
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Tesseract OCR Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            _imageFile == null
              ? Text('No image selected.')
              : Image.file(_imageFile!),
            SizedBox(height: 20),
            Text('OCR Result:'),
            Text(_ocrResult, style: TextStyle(fontSize: 18)),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _pickImage,
              child: Text('Pick Image'),
            ),
          ],
        ),
      ),
    );
  }
}

注意事项

  1. 权限处理:在实际应用中,你需要处理权限请求,特别是在Android 6.0及以上版本和iOS 10.0及以上版本中。
  2. 错误处理:示例代码中的错误处理非常基础,在实际应用中你可能需要更详细的错误处理逻辑。
  3. 语言支持flutter_tesseract_ocr插件支持多种语言,你可以根据需要调整language参数。

这个示例应该能帮助你开始在Flutter项目中使用flutter_tesseract_ocr插件进行光学字符识别。如果你遇到任何问题,请查阅该插件的官方文档或相关资源。

回到顶部