この記事の内容
- 機械学習を利用した機能を簡単に使える Emotion API について知れる。
- 機械学習を利用し表情分析するアプリを Xamarin を利用し作成する方法について学べる。
この記事の対象者
- Xamarin とか触ったことないけど、とりあえずアプリを作ってみたい人。
- 機械学習を利用して表情分析する Emotion API を試してみたい人
1. 機械学習を利用して表情分析とは?
世の中は機械学習ブームです。
自前で学習モデルを用意しても良いですが、この記事では機械学習ができない人でも簡単に機能を使うことができるサービスを利用します。
Azure Cognitive Services
Azure Cognitive Services とは、Microsoftが提供しているサービスです。
機械学習を利用して 視覚・音声・言語・知識・検索 などの分野のサービスを提供しています。
サービスを利用する側は、(REST API, SDK) などを利用するだけで、機械学習を知らなくても機械学習の恩恵を受けることができちゃうサービスです。
https://azure.microsoft.com/ja-jp/services/cognitive-services/
Face API - 顔に関する分析機能を使えるサービス
今回の目標である表情分析機能を実現するためのサービスも Azure Cognitive Services には含まれています。
顔に関する様々な分析機能を使える Face API を使います。
https://azure.microsoft.com/ja-jp/services/cognitive-services/face/
Xamarin とは?
C# でクロスプラットフォームな開発ができるツールです。
今回は、 iOS, Android を対象に作成していきます。
Xamarin について詳しく知りたくなった方は、こちらへどうぞ
https://qiita.com/amay077/items/38ee79b3e3e88cf751b9
今回作るもの
今回は、Xamarin.Forms を使い、スマホから写真を撮影し、感情分析するモバイルアプリを作成していきます。
完成図
Xamarin.Forms & Cognitive Services の利用に必要な環境セットアップ
Visual Studio
Xamarin の開発を行うためには、 Visual Studio 2017(or Visual Studio for Mac) が必要です。
また、 Visual Studio 2017 のセットアップ時に .net によるモバイル開発 を選択している必要があります。
インストール手順は Xamarin やりたい人向け Visual Studio 2017 インストール手引書 - Xamarin 日本語情報 を参考にしてください。
Microsoft Account, Microsoft Azure Account
Microsoft Cognitive Services を利用するために必要です。
詳しくは、日本マイクロソフト テクニカルエバンジェリスト 大森彩子 氏の Qiita をご覧ください
また、 Emotion API の keyをリンク先に書いてある通りに取得してください!
Xamarin.Forms による実装
Visual Studio 2017 による Xamarin.Forms のプロジェクトの作成(Windows)
Visual Studio のテンプレートから Xamarin.Forms のプロジェクトを作成
※ Visual Studio を起動し、上部のメニューバーから ファイル>新規作成>プロジェクト を選択します。
テンプレートから Visual C#>Cross-Platform>Cross Platform App (Xamarin) を選択し、任意のプロジェクト名を入力します。ここでは「XamEmotion」としました。
作成する Xamarin.Forms プロジェクトのタイプを選択
空のアプリ、Xamarin.Forms、ポータブルクラスライブラリ (PCL) を選択して OK をクリックします。
作成する UWP のバージョンはそのままでOKボタンをクリックしてください
Visual Studio for Mac による Xamarin.Forms プロジェクトの作成(macOS)
Visual Studio for Mac のテンプレートから Xamarin.Forms のプロジェクトを作成
※ Visual Studio for Mac を起動し、メニューバーから ファイル>新しいソリューション を選択します。
Multiplatform>アプリ>Blank Forms App を選択して 次へ をクリックします。
任意のアプリ名を入力して(ここでは「XamEmotion」としました。) 共有コード>ポータブルクラスライブラリの使用 を選択して 次へ をクリックします。
そのまま 作成 をクリックします。
Xamarin.Forms のプロジェクトが作成されました
※ Visual Studio for Mac では UWP プロジェクトは作成されません。
Nuget Package
Xamarin の開発では、通常の .NET 開発と同じようにパッケージ管理システムに NuGet を利用します。
Visual Studio 2017 の場合はソリューションを右クリックして ソリューションのNuGetパッケージの管理 から NuGet パッケージマネージャーを起動してソリューション全体に対して一括で NuGet パッケージを追加/削除ができます。
Visual Studio for Mac の場合は、各プロジェクトを右クリックして 追加>NuGetパッケージの追加 で NuGet パッケージマネージャーを起動します。
Microsoft.BCL.Build パッケージのインストール
Emotion API のクライアントライブラリの依存関係に存在する Microsoft.BCL.Build
はこの後の Emotion API 用クライアントライブラリのインストールで同時にインストールされるのですが、Xamarin.Forms のプロジェクトではそれより高いバージョンが必要なため、先に個別でインストールしておく必要があります。
※ 執筆時は 1.0.21
ソリューションのパッケージの管理ウィンドウの参照タブで「bcl.build」と検索して Microsoft.Bcl.Build
をインストールします。
Visual Studio for Mac では、Microsoft BCL Build Components
と表示されています。ID が Microsoft.Bcl.Build となっていることを確認してください。
Emotion API 用クライアントライブラリのインストール
ソリューションのパッケージの管理ウィンドウの参照タブで「Emotion」や「Microsoft.ProjectOxford.Emotion」と検索して Microsoft.ProjectOxford.Emotion
をインストールします。
PCL Storage のインストール
PCL Storage は Xamarin.Forms でファイルの読み書きをする処理を共通コードで簡潔に記述するため行うために使用するライブラリです。
(Xamarin.Forms の PCL プロジェクトの名前空間に System.IO.File がないため、その代わりにとなるもの)
PCL Storage は、 Xamarin Plugin と呼ばれる公式ライブラリのうちの1つで、これらの Plugin ライブラリを使用すれば、簡単にカメラとか位置情報とかを使うことが出来ます。
ソリューションのパッケージの管理ウィンドウの参照タブで「PCLStorage」と検索してインストールします。
Media Plugin for Xamarin and Windows をインストール
カメラの使用やギャラリーから画像をピックアップするために使います。
ソリューションのパッケージの管理ウィンドウの参照タブで「Xam.Plugin.Media」と検索してインストールします。
Media Plugin for Xamarin and Windows をインストールすると、Readme.txt
が表示されます。iOS/Android/UWP でそれぞれ必要な処理が書いてありますので、実行します。
Android
プロジェクトのターゲットフレームワークを API 25(Android 7.1)にします。Android プロジェクトを右クリックして、プロジェクトのプロパティ>アプリケーション>ターゲットフレームワーク が 7.1 以上になっていることを確認します。
この時に Visual Studio 2017 の場合は Androidマニフェスト タブを開き、パッケージ名、アイコン、バージョン番号、バージョン名を入力しておきます。
Visual Studio for Mac の場合は、Android プロジェクトを右クリックして オプション を選択し、ダイアログの ビルド>Androidアプリケーション>対象のAndroidバージョン が API 25 になっていることを確認します。
次に Android プロジェクトの MainActivity.cs
を開き OnCreate
メソッドの下に次のオーバーライドメソッドを追加します。
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
次に Properties
フォルダの AndroidManifest.xml
をダブルクリックで開きます。
Visual Studio for Mac の場合は、開いた後で画面下の ソース(見づらいですがw)をクリックして XML を表示します。
<application></application>
タグの中に次を追加します。
Before
<!-- 略 -->
<application android:label="XamEmotion.Android" android:icon="@drawable/icon"></application>
<!-- 略 -->
After
<!-- 略 -->
<application android:label="XamEmotion.Android" android:icon="@drawable/icon">
<provider android:name="android.support.v4.content.FileProvider"
android:authorities="YOUR_APP_PACKAGE_NAME.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
</application>
<!-- 略 -->
YOUR_APP_PACKAGE_NAME
はアプリのパッケージ名で置き換えてください。
次に Resources
フォルダ内に xml
フォルダを作成し、その中に file_path.xml
ファイルを作成します。
Visual Studio 2017 の場合はフォルダを右クリックして、追加>新しい項目 で表示されるダイアログで データ>XML ファイル を選択します。
Visual Studio for Mac の場合はフォルダを右クリックして 追加>新しいファイル で表示されるダイアログで XML>空のXMLファイル を選択します。
作成された XML の中身を次で置き換えます。
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="my_images" path="Pictures" />
<external-files-path name="my_movies" path="Movies" />
</paths>
iOS
プライバシーポリシーに対応
-
Info.plist
を開きます。
Visual Studio の場合は、右クリックメニューから ファイルを開くアプリケーションの選択 をクリックします。
XML (テキスト) エディタを選択し開きます。
Visual Studio for Mac の場合は Info.plist
を右クリックして プログラムから開く>任意のテキストエディタ を選択します。
- 内の要素の最後に以下の要素を入力します。
<key>NSPhotoLibraryUsageDescription</key>
<string>This app accesses the photo library to analyze facial expressions.</string>
<key>NSCameraUsageDescription</key>
<string>This app accesses the camera to analyze facial expressions.</string>
UWP
アプリマニフェスト>機能>Webカメラ にチェックを入れ、UWP アプリから Web カメラを使うと宣言します。(ローカルでデバッグ実行する分には問題がないはずです)
コーディング
ロジックの作成
カメラを撮影するクラスの作成
プロジェクトを右クリックして、 新しいクラスを作成します。
PhotoClient という名前のクラスを作成
Visual Studio for Mac では、プロジェクトを右クリックして、追加>新しいファイル からダイアログで General>空のクラス を選択し、名前を「PhotoClient」にして 新規 ボタンをクリックします。
Before
// 略
class PhotoClient
{
}
After
using System;
using System.Threading.Tasks;
using Plugin.Media;
using Plugin.Media.Abstractions;
// 略
public static class PhotoClient
{
public static async Task<string> TakePhotoAsync()
{
// カメラを初期化
await CrossMedia.Current.Initialize();
// カメラを使えるかどうか判定
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
throw new NotSupportedException("You should Set up camera");
}
// 撮影し、保存したファイルを取得
var photo = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions());
// 保存したファイルのパスを取得
return photo.Path;
}
}
カメラロール/ギャラリーから画像を選択するクラスを作成
上と同じように GalleryClient という名前でクラスを新規作成してください。
Before:GalleryClient.cs
// 略
class GalleryClient
{
}
After:GalleryClient.cs
using Plugin.Media;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 略
public static class GalleryClient
{
public static async Task<string> PickPhotoAsync()
{
<<<<<<< HEAD
public static async Task<string> PickPhotoA()
{
// galleryから写真を選択させる
var photo = await CrossMedia.Current.PickPhotoAsync();
=======
// galleryから写真を選択させる
var photo = await CrossMedia.Current.PickPhotoAsync();
>>>>>>> EDIT_REQUEST
// 保存したファイルのパスを取得
return photo.Path;
}
}
Emotion API を叩くクラスを作成
上と同じように EmotionApiClient という名前で、新規クラスを作成してください。
Before
// 略
class EmotionApiClient
{
}
After
using System.Threading.Tasks;
using Microsoft.ProjectOxford.Common.Contract;
using Microsoft.ProjectOxford.Emotion;
using PCLStorage;
// 略
public static class EmotionApiClient
{
// ここにEmotion APIのsubscribeキーを入力してください
private static readonly string SubscribeKey = "YOUR_Subscribe_KEY";
public static async Task<EmotionScores> AnalyzeAsync(string photoURL)
{
var client = new EmotionServiceClient(SubscribeKey);
var file = await FileSystem.Current.GetFileFromPathAsync(photoURL);
var imageStream = await file.OpenAsync(FileAccess.Read);
var result = await client.RecognizeAsync(imageStream);
return result[0].Scores;
}
}
View の作成
最後に作成したロジックを使用する View を作成します。
※ Visual Studio for Mac の場合は、<プロジェクト名>Page.xaml となり、XamEmotion で作成した場合は XamEmotionPage.xaml
ですので、ご注意ください。
before
<Label Text="Welcome to Xamarin Forms!"
VerticalOptions="Center"
HorizontalOptions="Center" />
After
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image x:Name="ImagePreview" Grid.Row="0" />
<Button Grid.Row="1"
Clicked="Button_OnClicked"
Text="解析" />
<StackLayout Grid.Row="2" HorizontalOptions="Center">
<Label x:Name="Anger">怒り</Label>
<Label x:Name="Contempt">軽蔑</Label>
<Label x:Name="Disgust">むかつき</Label>
<Label x:Name="Fear">恐れ</Label>
<Label x:Name="Happiness">喜び</Label>
<Label x:Name="Neutral">無表情</Label>
<Label x:Name="Sadness">悲しみ</Label>
<Label x:Name="Surprise">驚き</Label>
</StackLayout>
</Grid>
コードビハインドも修正します。
Before
// 略
public MainPage()
{
InitializeComponent();
}
After
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ProjectOxford.Common.Contract;
using Xamarin.Forms;
// 略
public MainPage()
{
InitializeComponent();
}
private async void Button_OnClicked(object sender, EventArgs e)
{
var photoUrl = "";
var imageChoiceResult = await DisplayAlert("画像の元を選択してください", "", "カメラ", "ギャラリー");
try
{
if (imageChoiceResult)
{
// 写真を撮影し、保存したURLを取得
photoUrl = await PhotoClient.TakePhotoAsync();
}
else
{
// ギャラリーから選んだ写真のURLを取得
photoUrl = await GalleryClient.PickPhotoAsync();
}
}
catch (Exception exception)
{
await DisplayAlert("Error", exception.Message, "OK");
}
// 画像を表示
ImagePreview.Source = photoUrl;
EmotionScores emotionResult;
try
{
// Cognitive Services - Emotion API を叩く
emotionResult = await EmotionApiClient.AnalyzeAsync(photoUrl);
}
catch (Exception exception)
{
await DisplayAlert("Error", exception.Message, "OK");
return;
}
// 表示するためにビューにセットしていく
Anger.Text = $"怒り: {(emotionResult.Anger * 100).ToString("0.000")}%";
Contempt.Text = $"軽蔑: {(emotionResult.Contempt * 100).ToString("0.000")}%";
Disgust.Text = $"むかつき: {(emotionResult.Disgust * 100).ToString("0.000")}%";
Fear.Text = $"恐れ: {(emotionResult.Fear * 100).ToString("0.000")}%";
Happiness.Text = $"喜び: {(emotionResult.Happiness * 100).ToString("0.000")}%";
Neutral.Text = $"無表情: {(emotionResult.Neutral * 100).ToString("0.000")}%";
Sadness.Text = $"悲しみ: {(emotionResult.Sadness * 100).ToString("0.000")}%";
Surprise.Text = $"驚き: {(emotionResult.Surprise * 100).ToString("0.000")}%";
}
アプリケーションの動作確認
F5 または デバック>デバックの開始 をクリックして、プロジェクトのビルドおよび起動を行います。
Windows 環境で開発をしている人は UWP 版を実行してください。環境のせいで動かない。といったことが少なくなります。
無事に完成させることは出来ましたか?
ソース公開
今回作成したものの完成品を Github にて公開しています。もしうごかなければ、参考にしてみてください!
追加課題
- 複数人の表情を見れるようにしよう
- MVVM の形に書きなおしてみよう
- 撮影・選択した画像の顔の部分に枠を描画してみよう
- Xamarin.Forms から Xamarin.Tradional へ書き直してみよう