flutter:【實戰(zhàn)篇】MLKIT 實現(xiàn)OCR文本識別绣张,再也不用付費(fèi)SDK了

引言

最近項目里要用到 OCR 拍照識別文本的能力答渔。小編一開始想要的是接入百度的 OCR sdk,奈何領(lǐng)導(dǎo)直接說不批任何費(fèi)用侥涵,看來只能另謀出路了沼撕。

于是,小編找到了這個庫 google_mlkit_text_recognition芜飘,該庫支持傳入圖片識別文本务豺,最重要的還是免費(fèi)

閑話不多說嗦明,先來一張實現(xiàn)的效果圖:

image.png

拍照支持局部識別笼沥,下面來說說實現(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)的問題蹄咖,新建的該工具庫褐健。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市澜汤,隨后出現(xiàn)的幾起案子铝量,更是在濱河造成了極大的恐慌,老刑警劉巖银亲,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異纽匙,居然都是意外死亡务蝠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門烛缔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來馏段,“玉大人轩拨,你說我怎么就攤上這事≡合玻” “怎么了亡蓉?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長喷舀。 經(jīng)常有香客問我砍濒,道長,這世上最難降的妖魔是什么硫麻? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任爸邢,我火速辦了婚禮,結(jié)果婚禮上拿愧,老公的妹妹穿的比我還像新娘杠河。我一直安慰自己,他們只是感情好浇辜,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布券敌。 她就那樣靜靜地躺著,像睡著了一般柳洋。 火紅的嫁衣襯著肌膚如雪待诅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天膳灶,我揣著相機(jī)與錄音咱士,去河邊找鬼。 笑死轧钓,一個胖子當(dāng)著我的面吹牛序厉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播毕箍,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼弛房,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了而柑?” 一聲冷哼從身側(cè)響起文捶,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎媒咳,沒想到半個月后粹排,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡涩澡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年顽耳,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡射富,死狀恐怖膝迎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胰耗,我是刑警寧澤限次,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站柴灯,受9級特大地震影響卖漫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜弛槐,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一懊亡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧乎串,春花似錦店枣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至长豁,卻和暖如春钧唐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背匠襟。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工钝侠, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人酸舍。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓帅韧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親啃勉。 傳聞我的和親對象是個殘疾皇子忽舟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容