flutter:【实战篇】实现OCR文本识别,再也不用付费了
引言
最近项目里要用到 OCR 拍照识别文本的能力。小编一开始想要的是接入百度的 OCR sdk,奈何领导直接说不批任何费用,看来只能另谋出路了。
于是,小编找到了这个库 google_mlkit_text_recognition,该库支持传入图片识别文本,最重要的还是 免费。
闲话不多说,先来一张实现的效果图:
拍照支持局部识别,下面来说说实现步骤。
实现方式
为了实现拍照识别,分别依赖了下面三个库:
1dependencies:
2 flutter:
3 sdk: flutter
4 camera: ^0.10.2+1
5 google_mlkit_commons: ^0.5.0
6 google_mlkit_text_recognition: ^0.9.0
7
通过 camera 库实现相机预览能力
1CameraPreview(
2 cameraController,
3)
4
并且相机开启预览后 cameraController 可以拿到每一帧的图片数据
1cameraController.startImageStream(_processCameraImage);
2
将每一帧的图片数据,调用文本识别的google库,返回该图像内所有识别到的文本内容(注意:这里要自行做节流处理,我们不需要每帧都进行图像分析的开销)
1Future _processCameraImage(CameraImage image) async {
2 final WriteBuffer allBytes = WriteBuffer();
3 for (final Plane plane in image.planes) {
4 allBytes.putUint8List(plane.bytes);
5 }
6 final bytes = allBytes.done().buffer.asUint8List();
7
8 final Size imageSize = Size(
9 image.width.toDouble(),
10 image.height.toDouble(),
11 );
12
13 final camera = _cameras[0];
14 final imageRotation = InputImageRotationValue.fromRawValue(
15 camera.sensorOrientation,
16 );
17 if (imageRotation == null) return;
18
19 final inputImageFormat = InputImageFormatValue.fromRawValue(
20 image.format.raw,
21 );
22 if (inputImageFormat == null) return;
23
24 final planeData = InputImageMetadata(
25 size: imageSize,
26 rotation: imageRotation,
27 format: inputImageFormat,
28 bytesPerRow: image.planes[0].bytesPerRow,
29 );
30 final inputImage = InputImage.fromBytes(
31 bytes: bytes,
32 metadata: planeData,
33 );
34 processImage(inputImage);
35}
36
1Future<void> processImage(InputImage inputImage) async {
2 final recognizedText = await _textRecognizer.processImage(inputImage);
3 // 这是识别到的整张图片的文本
4 final scanText = recognizedText.text;
5}
6
但是我们要做局部识别又该如何处理呢?那么我们不能直接拿到 scanText 就直接使用,我们需要做筛选处理:
recognizedText
会返回识别到的文本内容,同时会返回其对应的坐标信息,使用这些信息于我们示例GIF中绘制的蓝色框框的坐标进行包含判断,只筛选出坐标处于蓝色框框坐标范围内的数据。
大致代码如下:
1String scannedText = '';
2for (final textBunk in recognizedText.blocks) {
3 for (final element in textBunk.lines) {
4 for (final textBlock in element.elements) {
5 final left = translateX(
6 (textBlock.boundingBox.left),
7 rotation,
8 size,
9 absoluteImageSize,
10 );
11 final top = translateY(
12 (textBlock.boundingBox.top),
13 rotation,
14 size,
15 absoluteImageSize,
16 );
17 final right = translateX(
18 (textBlock.boundingBox.right),
19 rotation,
20 size,
21 absoluteImageSize,
22 );
23
24 // 判断是否蓝色框框坐标范围内
25 if (left >= boxLeft &&
26 right <= boxRight &&
27 (top >= (boxTop + 15) && top <= (boxBottom - 20))) {
28 scannedText += " ${textBlock.text}";
29 }
30 }
31 }
32}
33log('蓝色框框内识别的文本:$scannedText')
34
根据符合筛选范围的数据,自己拼出结果内容。
如果不使用相机预览,直接从相册选中识别呢?
从上面的代码可以看到,文本识别的入参是一个 inputImage 实例。
1final recognizedText = await _textRecognizer.processImage(inputImage);
2
inputImage 是 google_mlkit_common 中提供的类型,查看代码如下:
1/// Creates an instance of [InputImage] from path of image stored in device.
2factory InputImage.fromFilePath(String path) {
3 return InputImage._(filePath: path, type: InputImageType.file);
4}
5
6/// Creates an instance of [InputImage] by passing a file.
7factory InputImage.fromFile(File file) {
8 return InputImage._(filePath: file.path, type: InputImageType.file);
9}
10
11/// Creates an instance of [InputImage] using bytes.
12factory InputImage.fromBytes(
13 {required Uint8List bytes, required InputImageMetadata metadata}) {
14 return InputImage._(
15 bytes: bytes, type: InputImageType.bytes, metadata: metadata);
16}
17
其提供根据文件路径构造实例的方法。
推荐一下宝子,各种功能库扩展
题外话,Google ML Kit提供多种可免费使用的实用功能库。支持 Android、iOS,例如:
告别国内厂家的收费模式,开发应用变得更加简洁。
demo 已开源
本篇示例代码已上传到 github : github.com/liyufengrex…
该封装工具库已开源发布:flutter_ocr_text_recognization
使用方式:
1dependencies:
2 flutter_ocr_text_recognization: x.x.x
3
1import 'package:flutter_ocr_text_recognization/flutter_ocr_text_recognization.dart';
2
1TextOrcScan(
2 paintboxCustom: Paint()
3 ..style = PaintingStyle.stroke
4 ..strokeWidth = 4.0
5 ..color = const Color.fromARGB(153, 102, 160, 241),
6 boxRadius: 12,
7 painBoxLeftOff: 5,
8 painBoxBottomOff: 2.5,
9 painBoxRightOff: 5,
10 painBoxTopOff: 2.5,
11 widgetHeight: MediaQuery.of(context).size.height / 3,
12 getScannedText: (value) {
13 setText(value);
14 },
15)
16
参数说明:
Parameter | Description |
---|---|
painBoxLeftOff |
蓝色框框左偏移量 |
painBoxBottomOff |
蓝色框框下偏移量 |
painBoxRightOff |
蓝色框框右偏移量 |
painBoxTopOff |
蓝色框框上偏移量 |
getScannedText |
返回识别出的文本 |
本库参考自 pub-web.flutter-io.cn/packages/fl… , 因项目需要,分析内部实现后,修复部分原库发现的问题,新建的该工具库。