⚠️本記事はMLKitの公式チュートリアルを参考にしています
MLKitの概要
✅ Googleが提供するモバイルアプリに特化した機械学習フレームワーク
✅ 既存のTensorflowモデル(学習済み)を端末で手軽に利用可能
✅ iOS, Androidのクロスプラットフォーム開発が可能
✅ 大きく分けて”Vision”(画像認識)と”Natural Language”(テキスト認識)の2つの機能がある
✅ FlutterではFirebaseのPluginを通じて利用可能
MLKitの機能
基本機能
✅ Vision APIs
・顔検出・物体検出・文字認識・バーコード認識・イメージラベリング
✅ Natural Language APIs
・言語識別・翻訳・メッセージの自動返答
✅ 機械学習のオリジナルモデルの利用
・Tensorflow Lite・Auto ML Vision Edge
推論の方法は2通り
✅クラウド上での推論
・⭕️ 高性能 ❌ 時間がかかる
・FirebaseMLではクラウド上での訓練・推論が可能
✅デバイス上での推論
・⭕️ 時間が短い ❌ 精度は比較的低い
本記事で使用するデモアプリ
※公式チュートリアル引用
✅訓練済みのモデルを使用し、顔検出するアプリ
✅デバイス内の画像、またはカメラで撮影した写真を使う
早速アプリを立ち上げていこうと思います、Android Studioを使ってのやり方を下記の記事にまとめましたので、やり方がわからない方は確認をお願いします👇
アプリケーションの実装1(画像の取得と表示→ギャラリーorカメラで撮った写真をUIに表示)1<途中まで>
👇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 |
/* face recognition app*/ 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: "Face Finder App", theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: FaceFinder(), ); } } class FaceFinder extends StatefulWidget { @override _FaceFinderState createState() => _FaceFinderState(); } class _FaceFinderState extends State<FaceFinder> { File? _imageFile; // nullを許容するように?を付ける(nullの時の場合分けができるように) final ImagePicker _picker = ImagePicker(); void _getImageAndFindFace(ImageSource imageSource) async { setState(() { _imageFile = null; }); final PickedFile pickedImage = await _picker.getImage(source: imageSource); final File imageFile = File(pickedImage.path); setState(() { _imageFile = imageFile; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Face Finder App"), centerTitle: true), body: _imageFile == null // 三項演算子 ? Center( child: Text( "No image selected", style: TextStyle(fontSize: 20), ), ) : _makeImage(), //写真が選択されたらUIに表示するウィジェットを作成 floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ FloatingActionButton( onPressed: () { _getImageAndFindFace(ImageSource.gallery); }, tooltip: "Select image", // Tooltip:長押しした際に表示されるテキストメッセージ child: Icon(Icons.add_photo_alternate), ), Padding(padding: EdgeInsets.all(10)), FloatingActionButton( onPressed: () { _getImageAndFindFace(ImageSource.camera); }, tooltip: "Take photo", // Tooltip:長押しした際に表示されるテキストメッセージ child: Icon(Icons.add_a_photo)), ], ), ); } Widget _makeImage() { return Container( constraints: BoxConstraints.expand(), // 制約をExpandに設定 decoration: BoxDecoration( image: DecorationImage( image: Image.file(_imageFile!).image, fit: BoxFit.contain, // contain:アスペクト比を維持した状態を設定 )), ); } } |
基本設定
“/mlkit_face/pubspec.yaml”の編集
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<pubspec.yaml> ...省略... cupertino_icons: ^1.0.2 firebase_core: ^0.5.0 # 追記 firebase_ml_vision: ^0.9.6+2 # 追記 image_picker: ^0.6.0 # 追記 camera: ^0.5.6+1 # 追記 dev_dependencies: flutter_test: sdk: flutter <meta charset="utf-8">...省略... |
Firebase でプロジェクト作成
👇Firebaseコンソールのトップページから”プロジェクト追加”をクリックして新しいプロジェクトを作成していきます。
この作成方法のフローに関しては、下記の記事の『Firebaseの設定<初期設定>』に詳細を載せていますので、各自で確認してみて下さい👇
プライバシーの設定(カメラ及び端末内の写真へのアクセス許可の付与)
👇”Runner/Runner/Info.plist”をXcodeで開き、下記のように記述を2つ追加し編集します
設定 -iOS-
“/mlkit_face/ios/Runner.xcworkspace”の編集
Cocoapodsを使ったライブラリのインストールができるようにdeploymentターゲットの設定をしていきます。Runner.xcworkspaceをXcodeで開き、プロジェクトのDeployment TargetとターゲットのDeployment infoのiOSバージョンを確認し、Flutterでの設定と合わせます。今回は9.0に合わせて設定します。
“/mlkit_face/ios/Podfile”の編集
👇Firebase/MLVisionFaceModelの追記を行います
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<mlkit_face_recognition/ios/Podfile> ...省略... target 'Runner' do use_frameworks! use_modular_headers! flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) pod 'Firebase/MLVisionFaceModel' # 追記 end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) end end |
👇ターミナルでiosフォルダに移動し、アップデートをします
1 2 3 |
<Command> [~/AndroidStudioProjects/mlkit_face_recognition] $ cd ios [~/AndroidStudioProjects/mlkit_face_recognition/ios] $ pod update |
👇このように”/mlkit_face_recognition/Pods/FirebaseMLVision”がインストールされているのが確認できます
👇設定を終え、”コンソールに進む”をクリックすれば完了です
設定 -Android-
FirebaseのAndroid側の設定も同様に行なっていきます。詳細は下記の記事の『Firebaseの設定<Android>』で説明していますので、各自で確認してみて下さい👇
👇設定を終え、”コンソールに進む”をクリックすれば完了です
Androidファイルの追記
👇”~/AndroidStudioProjects/voting_app/android/app/build.gradle”に追加していきます
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<mlkit_face_recognition/android/app/build.gradle> android { ...省略... defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "jp.co.sailab.mlkit_app_proto1" minSdkVersion 21 // 変更 targetSdkVersion 28 versionCode flutterVersionCode.toInteger() versionName flutterVersionName multiDexEnabled true // 追記 } ...省略... dependencies { api 'com.google.mlkit:image-labeling:17.0.1' // 追記 api 'com.google.android.gms:play-services-mlkit-face-detection:16.1.2' // 追記 } } ...省略... apply plugin: 'com.google.gms.google-services' // 追記 |
👇”~/AndroidStudioProjects/voting_app/android/build.gradle”に追記していきます
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<meta charset="utf-8"><mlkit_face_recognition/android/build.gradle> buildscript { ext.kotlin_version = '1.3.50' repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.5.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.3' // 追記 } } ...省略... |
MLKitの導入
アプリケーションの実装2(選択した写真を顔検出できるようMLKitを使いコードを作成)
👇先ほどのコードの続きで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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
/* face recognition app*/ import 'dart:io'; // 外部ファイルのやり取りに利用 import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:firebase_ml_vision/firebase_ml_vision.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: "Face Finder App", theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: FaceFinder(), ); } } class FaceFinder extends StatefulWidget { @override _FaceFinderState createState() => _FaceFinderState(); } class _FaceFinderState extends State<FaceFinder> { File? _imageFile; // nullを許容するように?を付ける(nullの時の場合分けができるように) Size? _imageSize; List<Face>? _faceResults; final ImagePicker _picker = ImagePicker(); final FaceDetector _faceDetector = FirebaseVision.instance.faceDetector(); // 顔の検出を行うメソッド void _getImageAndFindFace(ImageSource imageSource) async { setState(() { _imageFile = null; _imageSize = null; }); final PickedFile pickedImage = await _picker.getImage(source: imageSource); final File imageFile = File(pickedImage.path); if (imageFile != null) { _findFace(imageFile); _getImageSize(imageFile); } setState(() { _imageFile = imageFile; }); } void _findFace(File imageFile) async { setState(() { _faceResults = null; }); final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(imageFile); List<Face> results = await _faceDetector.processImage(visionImage); setState(() { _faceResults = results; }); } void _getImageSize(File imageFile) { final Image image = Image.file(imageFile); image.image.resolve(ImageConfiguration()).addListener( //resolve:streamを返す ImageStreamListener((ImageInfo info, bool _) { //ImageStreamListener:画像の読み込みに関する通知を受信するためのインターフェース setState(() { _imageSize = Size( info.image.width.toDouble(), info.image.height.toDouble(), ); }); }), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Face Finder App"), centerTitle: true), body: _imageFile == null // 三項演算子 ? Center( child: Text( "No image selected", style: TextStyle(fontSize: 20), ), ) : _makeImage(), //写真が選択されたらUIに表示するウィジェットを作成 floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ FloatingActionButton( onPressed: () { _getImageAndFindFace(ImageSource.gallery); }, tooltip: "Select image", // Tooltip:長押しした際に表示されるテキストメッセージ child: Icon(Icons.add_photo_alternate), ), Padding(padding: EdgeInsets.all(10)), FloatingActionButton( onPressed: () { _getImageAndFindFace(ImageSource.camera); }, tooltip: "Take photo", // Tooltip:長押しした際に表示されるテキストメッセージ child: Icon(Icons.add_a_photo)), ], ), ); } Widget _makeImage() { return Container( constraints: BoxConstraints.expand(), // 制約をExpandに設定 decoration: BoxDecoration( image: DecorationImage( image: Image.file(_imageFile!).image, fit: BoxFit.contain, // contain:アスペクト比を維持した状態を設定 )), child: _imageSize == null || _faceResults == null ? Center( child: Text("Detecting now ...", style: TextStyle(color: Colors.lightBlue, fontSize: 32))) : CustomPaint( painter: FaceBorderDrawer(_imageSize!, _faceResults!))); } @override void dispose() { _faceDetector.close(); super.dispose(); } } class FaceBorderDrawer extends CustomPainter { final Size originalImageSize; final List<Face> faces; FaceBorderDrawer(this.originalImageSize, this.faces); @override void paint(Canvas canvas, Size size) { final double scale = size.width / originalImageSize.width; final double vSpace = (size.height - size.width * originalImageSize.height / originalImageSize.width) / 2.0; final Paint paint = Paint(); paint.style = PaintingStyle.stroke; paint.strokeWidth = 2.0; paint.color = Colors.red; for (Face face in faces) { canvas.drawRect( Rect.fromLTRB( face.boundingBox.left * scale, face.boundingBox.top * scale + vSpace, face.boundingBox.right * scale, face.boundingBox.bottom * scale + vSpace), paint, ); } } @override bool shouldRepaint(FaceBorderDrawer oldDelegate) { return oldDelegate.originalImageSize != originalImageSize || oldDelegate.faces != faces; } } |
“MLKitの概要”は以上になります、いかがだったでしょうか?今回は写真から顔を検出する機能を実装してみました。MLKitはこれ以外にも様々な機械学習を用いた機能を実装することができます。
難しい機械学習アルゴリズムを必要としないアプリなら、MLKitを使えば比較簡単に実装できるので、個人アプリで採用するのもいいと思いますし、色々試してみるのも楽しいですよね✊
今回はこの辺で、ばいばい👋
Greetings! Very helpful advice in this particular post! It is the little changes that produce the largest changes. Thanks for sharing!
Hello, thank you for your comment!!
I hope I can continue to give useful information.