こんにちは、鈴木商店の鎌倉です。
Firebse の ML Kit Text Recognition が日本語にも対応されていたので、
Flutter を用いてiPhone実機で画像からテキストを抽出してみたいと思います。
https://developers.google.com/ml-kit/vision/text-recognition/v2
前提
予め以下をインストール、作成した前提で進めていきます。
- Flutter
https://docs.flutter.dev/get-started/install - Xcode
https://developer.apple.com/jp/xcode/ - Firebase CLI
https://firebase.google.com/docs/cli?authuser=1#install-cli-mac-linux - Firebaseプロジェクトの作成
https://console.firebase.google.com/u/1/
環境 | バージョン |
---|---|
Flutter | 3.48.0 |
Xcode | 14.0 |
iOS | 16.0 |
アプリケーション雛形作成
VScodeで開発していきます。
コマンドパレットを開き、Flutter: New Project
でアプリケーションを作成し、作成された雛形を元に進めます。
なおこちらの拡張機能を使用しています。
コマンドにより画像の雛形が作成されます。
Firebase の設定
次にFirebaseの設定を行なっていきます。
以下のコマンドを実施してアプリケーションとの接続や必要なパッケージのインストール等を行なっていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# Firebase にログイン firebase login # FlutterFire CLI をインストール dart pub global activate flutterfire_cli # Firebase を初期化 flutter pub add firebase_core # Firebase に接続 (今回はiOSのみ選択) flutterfire configure # パッケージのインストール flutter pub add firebase_core flutter pub add google_mlkit_text_recognition flutter pub add firebase_ml_model_downloader |
パッケージのインストールによりpubspec.yaml
ファイルが更新されます。
1 2 3 4 5 6 7 8 9 10 |
dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 firebase_core: ^1.23.0 # 追加される google_mlkit_text_recognition: ^0.4.0 # 追加される firebase_ml_model_downloader: ^0.1.1+8 # 追加される |
これでFirebaseの設定は終了です。
カメラとフォトライブラリの読み込み設定
flutter pub add image_picker
を叩き image_picker
パッケージをインストールしておきます。
https://pub.dev/packages/image_picker/install
今回は以下の最低限の機能を満たすよう進めます。
- カメラで撮影した画像とフォトライブラリの画像からテキストを抽出
- 抽出したテキストの選択
SelectionArea
を使用 - 画面内スクロール
SingleChildScrollView
を使用
以下はmain.dart
のソースです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
import 'package:flutter/material.dart'; import 'dart:io'; import 'package:image_picker/image_picker.dart'; import 'package:flutter/services.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:google_mlkit_text_recognition/google_mlkit_text_recognition.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'ML Text Recognition'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { Text? _text; Image? _image; Future<void> scan(bool isGallery) async { final pickerFile = await ImagePicker().pickImage( source: isGallery == true ? ImageSource.gallery : ImageSource.camera); if (pickerFile == null) { return; } final InputImage imageFile = InputImage.fromFilePath(pickerFile.path); final textRecognizer = TextRecognizer(script: TextRecognitionScript.japanese); final RecognizedText recognizedText = await textRecognizer.processImage(imageFile); final String text = recognizedText.text; setState(() { _text = Text(text); _image = Image.file(File(pickerFile.path)); }); textRecognizer.close(); } @override Widget build(BuildContext context) { return SelectionArea( child: Scaffold( appBar: AppBar( title: Text(widget.title), ), body: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ if (_image != null) SafeArea(child: _image!), _text == null ? Text('No Image') : _text!, ], ), ), floatingActionButton: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ FloatingActionButton( onPressed: () async { await scan(true); }, child: const Icon(Icons.photo_album)), FloatingActionButton( onPressed: () async { await scan(false); }, child: const Icon(Icons.photo_camera)) ], ))); } } |
iOSでカメラやフォトライブラリにアクセスできるように (ios/Runner/)info.plistファイルに以下を追記しておきます。
1 2 3 4 |
<key>NSCameraUsageDescription</key> <string>テキストを抽出する画像をアップロードするためにカメラを使用します</string> <key>NSPhotoLibraryUsageDescription</key> <string>テキストを抽出する画像をアップロードするためにフォトライブラリを開きます</string> |
Xcode設定と実機でビルド
Xcodeを起動し、以下の手順で実機にてアプリケーションを立ち上げてみます。
1 open a project or file (Xcode)
– iOS→Runner.xcworkspace を選択
-
TARGETS RUNNER 設定
- General
iOS 16.0
- DisplayName を
pubspec.yaml
ファイルのname
と同じアプリ名で設定
- Signinig & Capabilities
- Team を選択する
- Bundle Identifierを設定
- com.example.
Generalで設定しているDisplayName
- com.example.
- General
-
TARFETS Pods 設定
- Signinig & Capabilities
- 以下のそれぞれのディレクトリで Team を選択する
- MLKitTextRecognition-LatinOCRResources
- MLKitTextRecognitionChinese-ChineseOCRResources
- MLKitTextRecognitionDevanagari-DevanagariOCRResources
- MLKitTextRecognitionJapanese-JapaneseOCRResources
- MLKitTextRecognitionKorean-KoreanOCRResources
- 以下のそれぞれのディレクトリで Team を選択する
- Signinig & Capabilities
-
iPhoneの開発モードをオンにする
設定
→プライバシーとセキュリティ
→デベロッパモード
をオン
-
VScode でデバッグ開始
- 実行→デバッグの開始
抽出したテキストです。
1 2 3 4 5 6 7 8 9 10 |
1920030014008 医学的に正しい 最強のサウナ術 ロ 「サウナ→水風呂一→外気浴」を3~4セットが基本 ロ80~90度のフィンランド式サウナが最強 ロ水風呂を出る目安は、気道がスースーしたら ロサウナ室を出る時間は心拍数を目安にするのがベスト ロ水風呂の温度は16~17度がベスト ロ外気浴は「気持ちよさ」最優先でなるべく横になる ロ真正「ととのい」 タイムは約2分 |
抽出できました!
まとめ
今回 Flutter と Firebase ML を使って実機にて画像からテキストを抽出してみました!
Flutterを触るのは初めてで実機でのビルド等で詰まることもありましたが、テキストの抽出まで行うことができてよかったです。
別の機会にアプリケーションをリリースしてみたいと思います。
- 参考
https://developers.google.com/ml-kit/vision/text-recognition/v2
https://zenn.dev/kazutxt/books/flutter_practice_introduction/viewer/34_chapter4_ml
https://firebase.flutter.dev/
https://api.flutter.dev/flutter/material/SelectionArea-class.html