読者です 読者をやめる 読者になる 読者になる

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

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

Xamarin で Watson Visual Recognition を使ってみた

IBM Watson には .NET Standard 用の SDK があります(α版).

santea.hateblo.jp


しかし、残念ながら現状では Xamarin で使用することはできません.
(Issue を上げたのでそのうち改善されるかと思います)
Is it possible to support Xamarin? · Issue #91 · watson-developer-cloud/dotnet-standard-sdk · GitHub


そこで今回は、Web API を直接叩く形で Watson API を Xamarin で使ってみます.

使用する Watson API は画像認識を行う Visual Recognition で、
画像中の文字を認識する Recognize Text を使ってみます.





Bluemix 上で Watson Visual Recognition の作成

Bluemix で サービズの中の Watson を選びます.

f:id:Santea:20170502231917p:plain:w280


Watson サービスの作成ボタンをクリックします.

f:id:Santea:20170502232103p:plain:w200


一覧の中から Visual Recognition を選びます.

f:id:Santea:20170502232658j:plain


価格プランを選んで作成ボタンを押します.

f:id:Santea:20170502233233p:plain


作成したインスタンスのサービス資格情報の中の API KEY を控えておきましょう.

f:id:Santea:20170502234201j:plain


以上が Bluemix 上の操作です.



Xamarin の実装

Xamarin の実装として、今回はカメラで撮影した画像に対し文字認識を行います.

以下 MainPage のコードビハインドです.

using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using Plugin.Media;
using Plugin.Media.Abstractions;
using Xamarin.Forms;

namespace FlipChartRecognitionApp
{
	public partial class FlipChartRecognitionAppPage : ContentPage
	{
		private static readonly string Url = "https://gateway-a.watsonplatform.net/visual-recognition/api/v3/recognize_text?api_key=...&version=2016-05-20";

		public FlipChartRecognitionAppPage()
		{
			InitializeComponent();
		}

		public async void Handle_Clicked(object sender, EventArgs e)
		{
			await CrossMedia.Current.Initialize();

			if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
			{

				await DisplayAlert("No Camera", "No camera available.", "OK");
				return;
			}

			var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
			{
				Directory = "Sample",
				Name = $"{DateTime.Now.ToString("yyMMdd-hhmmss")}.jpg",
				PhotoSize = PhotoSize.Small
			});

			if (file == null)
				return;

			RecognizeImage(file);

			image.Source = ImageSource.FromStream(() =>
			{
				var stream = file.GetStream();
				file.Dispose();
				return stream;
			});
		}

		void RecognizeImage(MediaFile file)
		{
			var content = new MultipartFormDataContent();

			var imageContent = new ByteArrayContent(ReadFully(file.GetStream()));
			imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
			content.Add(imageContent);

			var httpClient = new HttpClient();
			var response = httpClient.PostAsync(Url, content).Result;

                       DisplayAlert("Result", response.Content.ReadAsStringAsync().Result, "OK");
		}

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

ひとつずつ解説していきます.

コールする API は下記のようになっているので、{API KEY} の部分を先ほど作成したインスタンスAPI KEY に書き換えてください. 

private static readonly string Url = "https://gateway-a.watsonplatform.net/visual-recognition/api/v3/recognize_text?api_key={API KEY}&version=2016-05-20";


カメラの撮影部分では拡張子に .jpg を指定します.
また、PhotoSize を Samll にしたほうが無難です.
(Medium の場合、何度か送信に失敗しました)

var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
{
	Directory = "Sample",
	Name = $"{DateTime.Now.ToString("yyMMdd-hhmmss")}.jpg",
	PhotoSize = PhotoSize.Small
});


画像認識部分です.

送信するファイルは、Image を Byte配列に変換した上で ByteArrayContent に渡します.

ByteArrayContent.Headers.ContentType には、先ほど保存した .jpg ファイルと整合を取る形で、image/jpeg を指定します.

MultipartFormDataContent に ByteArrayContent を追加し、HttpClient.PostAsync をコールすれば画像認識が行えます.

void RecognizeImage(MediaFile file)
{
	var content = new MultipartFormDataContent();

	var imageContent = new ByteArrayContent(ReadFully(file.GetStream()));
	imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
	content.Add(imageContent);

	var httpClient = new HttpClient();
	var response = httpClient.PostAsync(Url, content).Result;
        
	DisplayAlert("Result", response.Content.ReadAsStringAsync().Result, "OK");
}



実装結果

こちらが実装結果です.

f:id:Santea:20170503001302j:plain

VOX のアンプラグを撮影してみました.

JSON の score という部分は Watson の回答に対する自信度を表しています.

  • VOX のロゴは装飾が入っていて判別しずらい
  • NIGHT は塗装が剥がれて判別しずらい

上記2点が score に表れていますね.
反対に TRAIN はかなりの自信度で判別しているようです.



まとめ

今回は Watson API を Xamarin で使ってみました.

Web API なので特に工夫なく、普通に使えることがお分かりいただけたかと思います.

通信部やモデルを自前で書かないといけないのは多少おっくうですが、
冒頭でも述べたように、近い将来 Xamarin に対応した .NET Standard の SDK がリリースされると思いますので、ぜひそれを楽しみにしていただければと思います!


以上です.