引言
最近項目里要用到 OCR 拍照識別文本的能力答渔。小編一開始想要的是接入百度的 OCR sdk,奈何領(lǐng)導(dǎo)直接說不批任何費(fèi)用侥涵,看來只能另謀出路了沼撕。
于是,小編找到了這個庫 google_mlkit_text_recognition芜飘,該庫支持傳入圖片識別文本务豺,最重要的還是免費(fèi)。
閑話不多說嗦明,先來一張實現(xiàn)的效果圖:
拍照支持局部識別笼沥,下面來說說實現(xiàn)步驟。
實現(xiàn)方式
為了實現(xiàn)拍照識別,分別依賴了下面三個庫:
dependencies:
flutter:
sdk: flutter
camera: ^0.10.2+1
google_mlkit_commons: ^0.5.0
google_mlkit_text_recognition: ^0.9.0
通過 camera 庫實現(xiàn)相機(jī)預(yù)覽能力
CameraPreview(
cameraController,
)
并且相機(jī)開啟預(yù)覽后 cameraController 可以拿到每一幀的圖片數(shù)據(jù)
cameraController.startImageStream(_processCameraImage);
將每一幀的圖片數(shù)據(jù)奔浅,調(diào)用文本識別的google庫馆纳,返回該圖像內(nèi)所有識別到的文本內(nèi)容(注意:這里要自行做節(jié)流處理,我們不需要每幀都進(jìn)行圖像分析的開銷)
Future _processCameraImage(CameraImage image) async {
final WriteBuffer allBytes = WriteBuffer();
for (final Plane plane in image.planes) {
allBytes.putUint8List(plane.bytes);
}
final bytes = allBytes.done().buffer.asUint8List();
final Size imageSize = Size(
image.width.toDouble(),
image.height.toDouble(),
);
final camera = _cameras[0];
final imageRotation = InputImageRotationValue.fromRawValue(
camera.sensorOrientation,
);
if (imageRotation == null) return;
final inputImageFormat = InputImageFormatValue.fromRawValue(
image.format.raw,
);
if (inputImageFormat == null) return;
final planeData = InputImageMetadata(
size: imageSize,
rotation: imageRotation,
format: inputImageFormat,
bytesPerRow: image.planes[0].bytesPerRow,
);
final inputImage = InputImage.fromBytes(
bytes: bytes,
metadata: planeData,
);
processImage(inputImage);
}
Future<void> processImage(InputImage inputImage) async {
final recognizedText = await _textRecognizer.processImage(inputImage);
// 這是識別到的整張圖片的文本
final scanText = recognizedText.text;
}
但是我們要做局部識別又該如何處理呢乘凸?那么我們不能直接拿到 scanText 就直接使用厕诡,我們需要做篩選處理:
recognizedText
會返回識別到的文本內(nèi)容,同時會返回其對應(yīng)的坐標(biāo)信息营勤,使用這些信息于我們示例GIF中繪制的藍(lán)色框框的坐標(biāo)進(jìn)行包含判斷灵嫌,只篩選出坐標(biāo)處于藍(lán)色框框坐標(biāo)范圍內(nèi)的數(shù)據(jù)。
大致代碼如下:
String scannedText = '';
for (final textBunk in recognizedText.blocks) {
for (final element in textBunk.lines) {
for (final textBlock in element.elements) {
final left = translateX(
(textBlock.boundingBox.left),
rotation,
size,
absoluteImageSize,
);
final top = translateY(
(textBlock.boundingBox.top),
rotation,
size,
absoluteImageSize,
);
final right = translateX(
(textBlock.boundingBox.right),
rotation,
size,
absoluteImageSize,
);
// 判斷是否藍(lán)色框框坐標(biāo)范圍內(nèi)
if (left >= boxLeft &&
right <= boxRight &&
(top >= (boxTop + 15) && top <= (boxBottom - 20))) {
scannedText += " ${textBlock.text}";
}
}
}
}
log('藍(lán)色框框內(nèi)識別的文本:$scannedText')
根據(jù)符合篩選范圍的數(shù)據(jù)葛作,自己拼出結(jié)果內(nèi)容寿羞。
如果不使用相機(jī)預(yù)覽,直接從相冊選中識別呢赂蠢?
從上面的代碼可以看到绪穆,文本識別的入?yún)⑹且粋€ inputImage 實例。
final recognizedText = await _textRecognizer.processImage(inputImage);
inputImage 是 google_mlkit_common 中提供的類型虱岂,查看代碼如下:
/// Creates an instance of [InputImage] from path of image stored in device.
factory InputImage.fromFilePath(String path) {
return InputImage._(filePath: path, type: InputImageType.file);
}
/// Creates an instance of [InputImage] by passing a file.
factory InputImage.fromFile(File file) {
return InputImage._(filePath: file.path, type: InputImageType.file);
}
/// Creates an instance of [InputImage] using bytes.
factory InputImage.fromBytes(
{required Uint8List bytes, required InputImageMetadata metadata}) {
return InputImage._(
bytes: bytes, type: InputImageType.bytes, metadata: metadata);
}
其提供根據(jù)文件路徑構(gòu)造實例的方法玖院。
推薦一下寶子,各種功能庫擴(kuò)展
題外話第岖,Google ML Kit提供多種可免費(fèi)使用的實用功能庫难菌。支持 Android、iOS蔑滓,例如:
告別國內(nèi)廠家的收費(fèi)模式郊酒,開發(fā)應(yīng)用變得更加簡潔。
demo 已開源
本篇示例代碼已上傳到 github : https://github.com/liyufengrex/flutter_ocr_text_recognization
該封裝工具庫已開源發(fā)布:flutter_ocr_text_recognization
使用方式:
dependencies:
flutter_ocr_text_recognization: x.x.x
import 'package:flutter_ocr_text_recognization/flutter_ocr_text_recognization.dart';
TextOrcScan(
paintboxCustom: Paint()
..style = PaintingStyle.stroke
..strokeWidth = 4.0
..color = const Color.fromARGB(153, 102, 160, 241),
boxRadius: 12,
painBoxLeftOff: 5,
painBoxBottomOff: 2.5,
painBoxRightOff: 5,
painBoxTopOff: 2.5,
widgetHeight: MediaQuery.of(context).size.height / 3,
getScannedText: (value) {
setText(value);
},
)
參數(shù)說明:
Parameter | Description |
---|---|
painBoxLeftOff |
藍(lán)色框框左偏移量 |
painBoxBottomOff |
藍(lán)色框框下偏移量 |
painBoxRightOff |
藍(lán)色框框右偏移量 |
painBoxTopOff |
藍(lán)色框框上偏移量 |
getScannedText |
返回識別出的文本 |
本庫參考自 https://pub-web.flutter-io.cn/packages/flutter_scalable_ocr 键袱, 因項目需要燎窘,分析內(nèi)部實現(xiàn)后,修復(fù)部分原庫發(fā)現(xiàn)的問題蹄咖,新建的該工具庫褐健。