 Flutterの記事を整理し本にしました
 Flutterの記事を整理し本にしました  
- 本稿の記事を含む様々な記事を体系的に整理し本にまとめました
- 今後はこちらを最新化するため、最新情報はこちらをご確認ください
- 25万文字を超える超大作になっています!!
まとめ記事
はじめに
- VisionAPIを使ったことがあったので、それと親しいFirebaseのMLをFlutterと組み合わせて動かしてみました。
概要
Firebase MachineLearning(以下ML)は機械学習の画像認識APIを用いて、判定やクラス分け、ラベリングなどを行う環境を提供します。
自前で学習やモデル作成を行えば、より幅広い機械学習の識別が実現できます。
有効化手順
MLの有効化は、Firebaseの左側のメニューのMachineLearningを選択し、始めるをクリックします。
機械学習には、以下の3種類があります。
- APIs:GCPのVisionAPIのように、画像認識を基本にテキスト認識や、ラベリング、顔検知などを行えます
- Custom:TensorFlowなどのtfliteの学習モデルを使って処理を行えます
- AutoML:CloudAutoMLでGCP上での機械学習と連携することができます。
 me
以後は、事前のモデル作成が不要なAPIsについて解説していきます
APIsには、いくつかの種類が用意されていますので、使いたい目的に合わせて使用するAPIを選択します。
処理には、デバイスで行うオンデバイスと、クラウドで行う2種類があります。
APIによって利用できる形態や機能に制約がありますので、ご注意ください。
クラウドベースを行う際には、プランをBlazeにアップグレードする必要があります。
なお、今回解説するテキスト認識の日本語は、クラウドでないと使えないため、プランをアップグレードしています。
準備
  firebase_core: ^1.1.0
  firebase_ml_vision: ^0.12.0+1
  image_picker: ^0.7.4
MLを使うためのパッケージがfirebase_ml_visionとfirebase_coreになります。
image_pickerは画像やカメラを選択するために使っています。
実装
デバイス内の画面を選択してテキスト認識(OCR)をするものと、カメラを使って取った写真のラベリングを行うものの2種類を実装しています。
どちらもクラウド側で処理を行っています。
import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_ml_vision/firebase_ml_vision.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo'),
    );
  }
}
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  Text _text;
  Image _image;
  Future<void> _ocr() async {
    PickedFile pickerFile =
        await ImagePicker().getImage(source: ImageSource.gallery);
    final File imageFile = File(pickerFile.path);
    final FirebaseVisionImage visionImage =
        FirebaseVisionImage.fromFile(imageFile);
    TextRecognizer textRecognizer =
        FirebaseVision.instance.cloudTextRecognizer();
    final VisionText visionText =
        await textRecognizer.processImage(visionImage);
    String text = visionText.text;
    for (TextBlock block in visionText.blocks) {
      print(block.text);
    }
    // 画面に反映
    setState(() {
      _text = Text(text);
      _image = Image.file(File(pickerFile.path));
    });
    // リソースの開放
    textRecognizer.close();
  }
  Future<void> _labeling() async {
    PickedFile pickerFile =
        await ImagePicker().getImage(source: ImageSource.camera);
    final File imageFile = File(pickerFile.path);
    final FirebaseVisionImage visionImage =
        FirebaseVisionImage.fromFile(imageFile);
    ImageLabeler labeler = FirebaseVision.instance.imageLabeler();
    List<ImageLabel> labels = await labeler.processImage(visionImage);
    String text = "";
    for (ImageLabel label in labels) {
      print(label.text);
      text += label.text + " ";
      print(label.confidence);
    }
    // 画面に反映
    setState(() {
      _text = Text(text);
      _image = Image.file(File(pickerFile.path));
    });
    // リソースの開放
    labeler.close();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              if (_text != null) _text,
              if (_image != null) SafeArea(child: _image),
            ],
          ),
        ),
        floatingActionButton:
            Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
          FloatingActionButton(onPressed: _ocr, child: Icon(Icons.photo_album)),
          FloatingActionButton(
              onPressed: _labeling, child: Icon(Icons.photo_camera))
        ]));
  }
}
まず、firebaseを利用するために以下の2行で初期化処理をしています。
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
テキスト認識用とラベリング用のボタンがあり、それぞれが_ocrと_labelingに対応しています。
基本的な流れは同じですが、使用するAPIによって使用するインスタンスが異なります。
テキスト認識(OCR)×写真ギャラリー
まず、ImagePickerを使って、ギャラリーからOCRで文字を読み取りたい画像を選択します。
その後、VisionImageとTextRecognizerのインスタンスを作成し、TextRecognizerに画像を与えて解析を行います。
そして、結果からtextで文字や詳細情報を取得します。
最後に、画面に表示させたあとリソースを開放しています。
オブジェクトラベリング×カメラ
こちらも、まず、ImagePickerを使って、ギャラリーからOCRで文字を読み取りたい画像を選択します。
その後、VisionImageとImageLabelerのインスタンスを作成し、ImageLabelerに画像を与えて解析を行います。
そして、結果(Labelのリスト)から認識されたラベルテキストを取得します。
最後に、画面に表示させたあとリソースを開放しています。
動作イメージ
ギャラリーのアイコンをタップした後、ストレージから本書の帯を選択したときの例
テキスト認識(OCR)×写真ギャラリー
I/flutter (14560): Flutter実践入門
I/flutter (14560): 環境構築からAndroid/iOS/Webに
I/flutter (14560): 広告を付けて同時にリリース!!
コンソール及び画面に、写真から識別した文字が、1字の誤字もなく高い精度で変換されていることが分かります。
オブジェクトラベリング×カメラ
カメラのアイコンをタップした後、時計を撮影したときの例
I/flutter (18593): Clock
I/flutter (18593): 0.8892788887023926
写真が約90%の確率で時計であると認識されています。
今回は、時計のみの識別ですが、写真のとり方によってはいくつかの選択肢が提示されたりします。
また、複数のオブジェクトが写っている場合は、それぞれに識別が行われます。




