LoginSignup
12
14

More than 5 years have passed since last update.

Xamarin で 機械学習を利用した表情分析アプリを作ろう! (Emotion API × Xamarin.Forms 編)

Last updated at Posted at 2017-07-05

この記事の内容

  • 機械学習を利用した機能を簡単に使える 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 を選択して 次へ をクリックします。

スクリーンショット 2017-09-13 11.48.10.png

任意のアプリ名を入力して(ここでは「XamEmotion」としました。) 共有コード>ポータブルクラスライブラリの使用 を選択して 次へ をクリックします。

スクリーンショット 2017-09-13 11.50.48.png

そのまま 作成 をクリックします。

スクリーンショット 2017-09-13 11.51.37.png

Xamarin.Forms のプロジェクトが作成されました

スクリーンショット 2017-09-13 12.01.42.png

※ Visual Studio for Mac では UWP プロジェクトは作成されません。

Nuget Package

Xamarin の開発では、通常の .NET 開発と同じようにパッケージ管理システムに NuGet を利用します。

Visual Studio 2017 の場合はソリューションを右クリックして ソリューションのNuGetパッケージの管理 から NuGet パッケージマネージャーを起動してソリューション全体に対して一括で NuGet パッケージを追加/削除ができます。

Visual Studio for Mac の場合は、各プロジェクトを右クリックして 追加>NuGetパッケージの追加 で NuGet パッケージマネージャーを起動します。

スクリーンショット 2017-09-13 12.03.18.png

スクリーンショット 2017-09-13 12.04.46.png

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 となっていることを確認してください。

スクリーンショット 2017-09-13 12.12.57.png

Emotion API 用クライアントライブラリのインストール

ソリューションのパッケージの管理ウィンドウの参照タブで「Emotion」や「Microsoft.ProjectOxford.Emotion」と検索して Microsoft.ProjectOxford.Emotion をインストールします。

スクリーンショット 2017-09-13 12.17.52.png

PCL Storage のインストール

PCL Storage は Xamarin.Forms でファイルの読み書きをする処理を共通コードで簡潔に記述するため行うために使用するライブラリです。
(Xamarin.Forms の PCL プロジェクトの名前空間に System.IO.File がないため、その代わりにとなるもの)
PCL Storage は、 Xamarin Plugin と呼ばれる公式ライブラリのうちの1つで、これらの Plugin ライブラリを使用すれば、簡単にカメラとか位置情報とかを使うことが出来ます。

ソリューションのパッケージの管理ウィンドウの参照タブで「PCLStorage」と検索してインストールします。

スクリーンショット 2017-09-13 12.19.21.png

Media Plugin for Xamarin and Windows をインストール

カメラの使用やギャラリーから画像をピックアップするために使います。

ソリューションのパッケージの管理ウィンドウの参照タブで「Xam.Plugin.Media」と検索してインストールします。

スクリーンショット 2017-09-13 12.20.57.png

Media Plugin for Xamarin and Windows をインストールすると、Readme.txt が表示されます。iOS/Android/UWP でそれぞれ必要な処理が書いてありますので、実行します。

Android

プロジェクトのターゲットフレームワークを API 25(Android 7.1)にします。Android プロジェクトを右クリックして、プロジェクトのプロパティ>アプリケーション>ターゲットフレームワーク が 7.1 以上になっていることを確認します。

Surface_2017-09-13 15_00_19.png

この時に Visual Studio 2017 の場合は Androidマニフェスト タブを開き、パッケージ名、アイコン、バージョン番号、バージョン名を入力しておきます。

image.png

Visual Studio for Mac の場合は、Android プロジェクトを右クリックして オプション を選択し、ダイアログの ビルド>Androidアプリケーション>対象のAndroidバージョン が API 25 になっていることを確認します。

スクリーンショット 2017-09-13 15.05.38.png

次に Android プロジェクトの MainActivity.cs を開き OnCreate メソッドの下に次のオーバーライドメソッドを追加します。

MainActivity.cs
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
    PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}

次に Properties フォルダの AndroidManifest.xml をダブルクリックで開きます。

image.png

スクリーンショット 2017-09-13 15.07.57.png

Visual Studio for Mac の場合は、開いた後で画面下の ソース(見づらいですがw)をクリックして XML を表示します。

スクリーンショット 2017-09-13 15.09.29.png

<application></application> タグの中に次を追加します。

Before
AndroidManifest.xml
<!-- 略 -->
<application android:label="XamEmotion.Android" android:icon="@drawable/icon"></application>
<!-- 略 -->
After
AndroidManifest.xml
<!-- 略 -->
<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 ファイル を選択します。

image.png

Visual Studio for Mac の場合はフォルダを右クリックして 追加>新しいファイル で表示されるダイアログで XML>空のXMLファイル を選択します。

スクリーンショット 2017-09-13 15.27.22.png

作成された XML の中身を次で置き換えます。

file_path.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

プライバシーポリシーに対応

  1. Info.plist を開きます。

Visual Studio の場合は、右クリックメニューから ファイルを開くアプリケーションの選択 をクリックします。

image.png

XML (テキスト) エディタを選択し開きます。

image.png

Visual Studio for Mac の場合は Info.plist を右クリックして プログラムから開く>任意のテキストエディタ を選択します。

スクリーンショット 2017-09-13 15.31.53.png

  1. 内の要素の最後に以下の要素を入力します。
<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 カメラを使うと宣言します。(ローカルでデバッグ実行する分には問題がないはずです)

image.png

コーディング

ロジックの作成

カメラを撮影するクラスの作成

プロジェクトを右クリックして、 新しいクラスを作成します。

PhotoClient という名前のクラスを作成

Visual Studio for Mac では、プロジェクトを右クリックして、追加>新しいファイル からダイアログで General>空のクラス を選択し、名前を「PhotoClient」にして 新規 ボタンをクリックします。

スクリーンショット 2017-09-13 13.08.31.png

Before

PhotoClient.cs
// 略

class PhotoClient
{
}

After

PhotoClient.cs
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

EmotionApiClient.cs
// 略

class EmotionApiClient
{
}

After

EmotionApiClient.cs
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 ですので、ご注意ください。
スクリーンショット 2017-09-13 12.24.55.png

before

MainPage.xaml
<Label Text="Welcome to Xamarin Forms!" 
           VerticalOptions="Center" 
           HorizontalOptions="Center" />

After

MainPage.xaml
<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

MainPage.xaml.cs
// 略

public MainPage()
{
    InitializeComponent();
}

After

MainPage.xaml.cs
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 にて公開しています。もしうごかなければ、参考にしてみてください!

Github

追加課題

  • 複数人の表情を見れるようにしよう
  • MVVM の形に書きなおしてみよう
  • 撮影・選択した画像の顔の部分に枠を描画してみよう
  • Xamarin.Forms から Xamarin.Tradional へ書き直してみよう
12
14
0

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
12
14