ぴよぴよエンジニアの日記

クラウドベンダーに勤める見習いSEの日記です。発言は私自身の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

Watson Developer Cloud .NET Standard SDK を Xamarin で使ってみた(Visual Recognition 編)

santea.hateblo.jp

前回に引き続き、Watson Developer Cloud .NET Standard SDK の内容です.


今回は、Visual Recognition の Detect Faces を使ってみます.




実装環境

  • macOS Sierra 10.12.5 (16F73)
  • Visual Studio for Mac 7.0.1 (build 24)
  • IBM.WatsonDeveloperCloud.VisualRecognition.v3 1.1.0
  • Xamarin.Forms 2.3.4.247



XAML

<?xml version="1.0" encoding="UTF-8"?>

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="WatsonSdkSample.VisualRecognition.VisualRecognitionPage1">
    <ContentPage.Content>
        <StackLayout>
            <Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
                <ActivityIndicator x:Name="indicator" 
                                   IsRunning="True" 
                                   IsVisible="False" 
                                   VerticalOptions="Center"
                                   HorizontalOptions="Center" />
                <Image x:Name="image" 
                       HorizontalOptions="Fill" 
                       VerticalOptions="Fill" 
                       Margin="5,12,5,0" />
            </Grid>
            <Label x:Name="label" 
                   HorizontalTextAlignment="Center" />
            <Button BackgroundColor="#2196F3" 
                    TextColor="White" 
                    Text="Pick Photo" 
                    Clicked="Handle_Clicked" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

Image に選択した画像を表示し、Label に画像認識の結果を表示します.



XAML.cs

using System;
using System.Diagnostics;
using System.IO;
using IBM.WatsonDeveloperCloud.VisualRecognition.v3;
using Plugin.Media;
using Xamarin.Forms;

namespace WatsonSdkSample.VisualRecognition
{
	public partial class VisualRecognitionPage1 : ContentPage
	{
		private const string ApiKey = "XXXXXXXXXXXXXXXXXXX";
		private readonly VisualRecognitionService _visualRecognition;

		public VisualRecognitionPage1()
		{
			InitializeComponent();

			_visualRecognition = new VisualRecognitionService();
			_visualRecognition.SetCredential(ApiKey);
		}

		public async void Handle_Clicked(object sender, EventArgs e)
		{
			image.Source = null;
			indicator.IsVisible = true;

			await CrossMedia.Current.Initialize();

			if (!CrossMedia.Current.IsPickPhotoSupported)
			{
				await DisplayAlert("No Auth", "Picking images denied.", "OK");
				return;
			}

			var file = await CrossMedia.Current.PickPhotoAsync();

			if (file == null)
				return;

			/** 画像認識 **/
			var imageByteArray = ReadFully(file.GetStream());

			var result = _visualRecognition.DetectFaces(imageData: imageByteArray, imageDataName: file.AlbumPath,
				imageDataMimeType: "image/jpeg");

			var text = "";
			foreach (var face in result.Images[0].Faces)
			{
				text += string.Format("Left: {0}, Top: {1}, Width: {2}, Height: {3}, " +
									  "Gender: {4}, GenderScore: {5}, AgeMax: {6}, AgeMin: {7}, AgeScore: {8}, " +
									  "IdentifyName: {9}, IdentifyScore: {10}, IdentifyHierarchy: {11}",
							face.FaceLocation.Left,
							face.FaceLocation.Top,
							face.FaceLocation.Width,
							face.FaceLocation.Height,
							face.Gender.Gender,
							face.Gender.Score,
							face.Age.Max,
							face.Age.Min,
							face.Age.Score,
							face.Identity?.Name,
							face.Identity?.Score,
							face.Identity?.TypeHierarchy) + System.Environment.NewLine;
			}

			image.Source = ImageSource.FromStream(() =>
			{
				var stream = file.GetStream();
				file.Dispose();
				return stream;
			});
			label.Text = text;
			indicator.IsVisible = false;
		}

		private static byte[] ReadFully(Stream input)
		{
			using (var ms = new MemoryStream())
			{
				input.CopyTo(ms);
				return ms.ToArray();
			}
		}
	}
}

Visual Recognition の部分を抜粋して説明します.

_visualRecognition = new VisualRecognitionService();
_visualRecognition.SetCredential(ApiKey);

VisualRecognitionService を初期化します.
SetCredential で VisualRecognition の API KEY を設定します.



var result = _visualRecognition.DetectFaces(imageData: imageByteArray, imageDataName: file.AlbumPath,
				imageDataMimeType: "image/jpeg");

imageData に Plugin.Media で取得した Stream を byte[] に変換したものを渡します.

imageDataName にファイルパスを、imageDataMimeType に "image/jpeg" を渡します.
(本来は、imageDataName, imageDataMimeType どちらかを指定すればいい気がしますが、この辺はもう少しソースを読んで確認します)



foreach (var face in result.Images[0].Faces)
{
	text += string.Format("Left: {0}, Top: {1}, Width: {2}, Height: {3}, " +
						"Gender: {4}, GenderScore: {5}, AgeMax: {6}, AgeMin: {7}, AgeScore: {8}, " +
						"IdentifyName: {9}, IdentifyScore: {10}, IdentifyHierarchy: {11}",
				face.FaceLocation.Left,
				face.FaceLocation.Top,
				face.FaceLocation.Width,
				face.FaceLocation.Height,
				face.Gender.Gender,
				face.Gender.Score,
				face.Age.Max,
				face.Age.Min,
				face.Age.Score,
				face.Identity?.Name,
				face.Identity?.Score,
				face.Identity?.TypeHierarchy) + System.Environment.NewLine;
}

取得できる要素として、以下の情報が取得できます.

  • 認識した顔の座標情報
  • 性別
  • 年齢
  • 有名人の場合は名前およびタグ情報



実装結果

f:id:Santea:20170717221840p:plain:w450

私の写真で恐縮ですが、実装結果です.

私は25歳なので、少し若めの分析結果ですね.


github.com
ソースコードはこちらでご確認いただけます.



まとめ

今回は Watson Developer Cloud .NET Standard SDK の Visual Recognition の中の DetectFaces を使ってみました.

SDK が使えることで、余計な POCO を実装しなくてよかったり、HttpClient 回りを書かなくてよいので、スピーディーに実装できますね.

一つ気になったところとしては、async メソッドがあるとより使い方の幅が広がる気がしました.




以上です.

Watson Developer Cloud .NET Standard SDK を Xamarin プロジェクトに追加してみた

Watson Developer Cloud .NET Standard SDK ver 1.1.0 が 7月4日にリリースされました.

www.nuget.org


今まで表記上は .NET Standard 1.6 対応だったのですが、実際は Xamarin や .NET Core では使えないという状態でした.

しかしながら、今回のアップデートで名実ともに .NET Standard 1.3 対応となっています.
もちろん Xamarin でも使えます!


docs.microsoft.com

リンク先のバージョン対応表でご確認いただけますが、.NET Standard 1.3 では Xamarin.iOS 10.0, Xamarin.Android 7.0, UWP 10.0 などでお使いいただけます.(UWP で使えるのは嬉しい方もいらっしゃるのではないでしょうか)


今回は Xamarin の Shared Project に Watson Developer Cloud の SDK を追加するまでの流れをやってみます.



ビルド環境



NuGet パッケージの追加

Android / iOS プロジェクトに NuGet パッケージを追加します.

f:id:Santea:20170715143253p:plain

NuGet パッケージの検索で "Watson Developer Cloud" と検索します.

検索結果の一番上にある "IBM.Watson Developer Cloud" はそれぞれの API パッケージが依存するコアパッケージです.
特定の API を使用する場合は、各 API 名のパッケージを追加してください.

今回はコアパッケージのインストールを試してみます.

For adding package 'IBM.WatsonDeveloperCloud.1.1.0' to project 'WatsonSdkSample.Droid' that targets 'monoandroid70'.
Package 'IBM.WatsonDeveloperCloud.1.1.0' already exists in folder '/Users/DaikiKawanuma/Projects/WatsonSdkSample/packages'
Added reference 'IBM.WatsonDeveloperCloud' to project 'WatsonSdkSample.Droid'.
Added package 'IBM.WatsonDeveloperCloud.1.1.0' to 'packages.config'
Added file 'packages.config' to project 'WatsonSdkSample.Droid'.
Successfully installed 'IBM.WatsonDeveloperCloud 1.1.0' to WatsonSdkSample.Droid
Executing nuget actions took 2.96 sec

IBM.WatsonDeveloperCloud successfully added.
For adding package 'IBM.WatsonDeveloperCloud.1.1.0' to project 'WatsonSdkSample.iOS' that targets 'xamarinios10'.
Package 'IBM.WatsonDeveloperCloud.1.1.0' already exists in folder '/Users/DaikiKawanuma/Projects/WatsonSdkSample/packages'
Added reference 'IBM.WatsonDeveloperCloud' to project 'WatsonSdkSample.iOS'.
Added package 'IBM.WatsonDeveloperCloud.1.1.0' to 'packages.config'
Added file 'packages.config' to project 'WatsonSdkSample.iOS'.
Successfully installed 'IBM.WatsonDeveloperCloud 1.1.0' to WatsonSdkSample.iOS
Executing nuget actions took 408.5 ms

IBM.WatsonDeveloperCloud successfully added.

無事追加されました.




以上です.