LoginSignup
18
13

More than 3 years have passed since last update.

【初心者向け】最速でFlutterにFirebase MLを導入する

Last updated at Posted at 2020-06-15

これはなに?

Firebase Machine LearningをFlutterに導入の仕方について書かれたもの

Firebase ConsoleにあるMachine Learningの画像

Firebase Machine Learningとは

そもそもFirebase Machine Learningとはなんなのか

ML Kit は、Google の機械学習の機能を Android アプリや iOS アプリとして提供するモバイル SDK です。その強力で使いやすいパッケージは、機械学習の経験の有無を問わず、わずか数行のコードで実装できます。ニューラル ネットワークやモデルの最適化に関する詳しい知識は必要ありません。経験豊富な ML のデベロッパーの方は、ML Kit の便利な API を利用することで、モバイルアプリにおいてカスタム TensorFlow Lite モデルを簡単に採用できます。
~Firebase 向け ML Kit ガイドから引用~

はい、ドキュメントが説明してくれました。

要約すると、

機械学習の経験の有無を問わず、わずか数行のコードで実装できます。

ここに収まります。

機械学習の知識がなくてもGoogleが作った学習モデルを使って数行でモバイルorWebアプリに導入できる、というもの(便利な時代になったな...)。

※自分で学習モデルを作ることも可能なようです。

今回はその中の顔検出を使ってみました。

作ったもの

カメラ撮影した画像を使って顔認識するアプリを作成しました。

導入手順

下の記事以上にうまく説明できないで導入手順についてはコチラを参考にしてください↓
FlutterでFirestoreと連携してみた

パッケージの導入

今回は顔認識をするのでそれに応じたパッケージが必要になります。
具体的には以下になります。

実装

以下の手順に沿って説明していきます
①写真撮影機能の実装
②撮影した画像で顔認識をさせて認識した顔の数を表示する

①写真撮影機能の実装

フローティングボタンをタップした時に_onPickImageSelected()を実行し、カメラで撮影しています。
この段階ではカメラで撮影した画像をただそのまま表示させているだけです。

main.dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Firebase ML kitで遊んでみた'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  File _image;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
        centerTitle: true,
      ),
      body: Center(
        child: _image == null
            ? Text("画像を撮影してください")
            : Image.file(_image),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _onPickImageSelected();
        },
        child: Icon(
          Icons.camera_alt,
          color: Colors.white,
        ),
      ),
    );
  }

  void _onPickImageSelected() async {
    var imageSource = ImageSource.camera;

    try {
      final file = await ImagePicker().getImage(source: ImageSource.camera);
      setState(() {
        _image = File(file.path);
      });
      if(file == null) {
        throw Exception('ファイルを取得できませんでした');
      }
    } catch (e) {
    }
  }
}

②撮影した画像で顔認識をさせて認識した顔の数を表示する

次に撮影した画像を使って顔認識をさせていきます。
下は全体のコードになります。

main.dart(全体)
import 'dart:io';
import 'package:firebase_ml_vision/firebase_ml_vision.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Firebase ML kitで遊んでみた'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  File _image;
  bool _loading = false;
  bool _isChecked = false;
  bool _isFaceRecognition = false;
  int _numOfFaces;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            _image == null
                ? Text("画像を撮影してください")
                : Image.file(_image),
            Visibility(
              visible: _image != null,
              child: verificationButton(),
            ),
            Visibility(
              visible: _isChecked,
              child: _isFaceRecognition
                  ? Text("$_numOfFaces人の顔が認識されました")
                  : Text("顔が認識できませんでした"),
            ),
          ]
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _onPickImageSelected();
        },
        child: Icon(
          Icons.add_a_photo,
          color: Colors.white,
        ),
      ),
    );
  }
  Widget verificationButton() {
    return RaisedButton(

      child: verificationButtonChild(),
      color: Colors.blue,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(10.0),
      ),
      onPressed: () {
        !_isChecked
            ? _startVerification()
            : _resetVerification();
      },
    );
  }
  Widget verificationButtonChild() {
    if (!_isChecked && _loading) {
      return Container(
        height: 20,
        width: 20,
        margin: EdgeInsets.all(5),
        child: CircularProgressIndicator(
          strokeWidth: 2.0,
          valueColor: AlwaysStoppedAnimation(Colors.white),
        ),
      );
    }else if (!_isChecked) {
      return Text("顔認識", style: TextStyle(color: Colors.white),);
    }else {
      return Text("リセット", style: TextStyle(color: Colors.white),);
    }
  }
  void _onPickImageSelected() async {
    try {
      final file = await ImagePicker().getImage(source: ImageSource.camera);
      setState(() {
        _image = File(file.path);
      });
      if(file == null) {
        throw Exception('ファイルを取得できませんでした');
      }
    } catch (e) {
    }
  }
  void _startVerification() async {
    setState(() {
      _loading = true;
    });
    final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(_image);
    final FaceDetector faceDetector = FirebaseVision.instance.faceDetector();
    final List<Face> faces = await faceDetector.processImage(visionImage);
    setState(() {
      _isChecked = !_isChecked;
      _loading = !_loading;
      _numOfFaces = faces.length != null
          ? faces.length
          : 0;
      _isFaceRecognition = faces.length > 0
          ? true
          : false;
    });
    faceDetector.close();
  }
  void _resetVerification() {
    setState(() {
      _image = null;
      _isChecked = false;
      _isFaceRecognition = false;
    });
  }
}

_startVerification()が顔認証の処理部分です。
_numOfFacesで認識した顔の数を取得しています。

main.dart(顔認証部分)
  void _startVerification() async {
    setState(() {
      _loading = true;
    });
    final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(_image);
    final FaceDetector faceDetector = FirebaseVision.instance.faceDetector();
    final List<Face> faces = await faceDetector.processImage(visionImage);
    setState(() {
      _isChecked = !_isChecked;
      _loading = !_loading;
      _numOfFaces = faces.length != null
          ? faces.length
          : 0;
      _isFaceRecognition = faces.length > 0
          ? true
          : false;
    });
    faceDetector.close();
  }
  void _resetVerification() {
    setState(() {
      _image = null;
      _isChecked = false;
      _isFaceRecognition = false;
    });
  }

まとめ

Firebase Machine Learningは初めて使ってみたけど、これを応用すればSnowみたいなアプリやマッチングアプリの本人認証に支えたりするんじゃないかなーと思いました。

そもそもすごいけどやっぱりFirebaseは偉大だなーと改めて感じました。
顔検出は他にも表情を認識して笑顔かどうかを返せたりするので、引き続き使ってみようかと思います。

参考

18
13
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
13