目次


何が見えますか?視覚面でのアクセシビリティーに対応したコグニティブ・アプリ

スマートフォンで撮った写真に音声による解説を追加する

Comments

スマートフォンを使って写真を撮るのは、今ではごく普通のことになっていますが、視力に問題がある人には、撮った写真がはっきり見えない可能性があります。このチュートリアルでは、視力の悪い人がスマートフォンに保存されている写真を利用しやすくするコグニティブ・アプリを開発する方法を説明します。ユーザーがこのアプリを利用して、スマートフォンのカメラで写真を撮ると、アプリはその写真を音声による解説付きでレンダリングします。

このアプリには、IBM Watson による以下の 2 つのコグニティブ・サービスと IBM Bluemix が不可欠です。

  • Watson の Visual Recognition サービスは、提供された画像を分析して、重み付けしたキーワードのリストを返します。このリストが、アプリによって 1 つの文に変換されます。
  • アプリによって変換された文は、Watson の Text to Speech サービスによって音声ファイルに変換されて、スマートフォンで再生されます。

このコグニティブ・アプリを、フロントエンドには Apache Cordova、バックエンドには Node.js を使用して開発します。このアプリがユーザーのモバイル端末と Watson コグニティブ・サービスとの間のインターフェースになります。

アプリを実行するコードを入手する

Android アプリを実行してみる

Android モバイル端末からこのページにアクセスしている場合は、以下のボタンをクリックすることで、デモ・アプリを端末に直接インストールすることができます。デスクトップ・ブラウザーからこのページにアクセスしている場合は、同じボタンを使って .apk ファイルをダウンロードし、そのファイルを端末に送信してください。

アプリのインストールが完了したら、アプリを開き、スマートフォンの音量を上げてから「Take a Picture (写真を撮る)」をクリックします。撮った写真は分析されて、その写真を解説する文が音声で再生されます。

必要となるもの

ステップ 1. 開発環境を構築する

開発環境を構築するには、以下の手順に従います。

  1. Bluemix のアカウントを作成するか、Bluemix にサインインします。このチュートリアルを作成している時点で、Watson コグニティブ・サービスは無料で利用できるベータ版となっていています。
  2. Node.js のドキュメントで説明されている手順に従って Node.js をインストールします。インストールされたことを確認するには、ターミナル・ソフトまたはコマンド・プロンプトを開いて、node -v を実行します。このコマンドによって、インストールされた Node.js のバージョンが表示されます。
  3. 開いてあるターミナル・ソフトまたはコマンド・プロンプトで、npm install -g cordova を実行します。このコマンドが、Node Package Manager に Apache Cordova コマンド・ラインをローカル環境にインストールするよう指示します。Cordova がインストールされたことを確認するには、コマンド cordova -v を実行します。
  4. Apache Cordova のドキュメントにある「Android プラットフォーム ガイド」で説明されている手順に従って、Cordova に対する Android の依存関係をインストールします。

ステップ 2. アプリをフォークしてデプロイする

次に、アプリをフォークして Bluemix 上にデプロイします。

  1. デモ・アプリをフォークして Bluemix 上にデプロイするために、このリンクをクリックします。
  2. アプリに名前を付けて、「DEPLOY (デプロイ)」をクリックします。この操作により、Git リポジトリーがフォークされ、必要な Watson の サービスがロードされた状態の Node.js サーバー・インスタンスが Bluemix 内に作成されます。フォークされたコードは、新しいサーバーに自動的にデプロイされます。
  3. 「VIEW YOUR APP (アプリを表示)」をクリックして、アプリのバックエンドが稼働中であることを確認します。

以下の画像は、WhatYouSee アプリケーション・コンソールのスクリーン・キャプチャーです。

ステップ 3. プロジェクトのコードをローカル環境にダウンロードする

次は、フォークした Git リポジトリーから、Cordova プロジェクトのコードを Bluemix にダウンロードします。

  1. Bluemix の自分のホーム・ページで「DASHBOARD (ダッシュボード)」ボタンをクリックして、Bluemix ダッシュボードを開きます。
  2. ステップ 2 で名前を指定したアプリを見つけて、その URL をクリックします。
  3. これにより、アプリの管理コンソールが開きます。このコンソールから、Node.js サーバーを管理することや、Watson の サービスの詳細を表示すること、そしてプロジェクトの Git リポジトリーにアクセスすることができます。
  4. コンソールの右上隅に表示されている Git の URL をクリックして、Git リポジトリーを開きます。
  5. 「Download (ダウンロード)」アイコンをクリックします。これによって、プロジェクト全体が .zip ファイルとしてダウンロードされます。

    プロジェクトのソースをダウンロードするのに代わる方法としては、Bluemix の Git リポジトリーをローカル環境に複製するという方法もあります。手順については、Bluemix に用意されている Git の資料を参照してください。

  6. ローカル・マシンにダウンロードされた .zip ファイルを解凍します。このモバイル・アプリの Cordova プロジェクトは、whatyousee-cordova ディレクトリーに格納されています。

ステップ 4. モバイル・アプリをビルドして実行する

次は、アプリをビルドして実行します。

  1. お好きな IDE またはテキスト・エディターを使用して、whatyousee-cordova/www/js/index.js に置かれている index.js ファイルを開きます。
  2. Bluemix アプリの URL を指すように serverURL 変数の値を変更します。
    var app = {
        //Nodejs app URL
        serverURL:"http://<appname>.mybluemix.net",
  3. プロジェクトをセットアップするために、コマンド cordova prepare を実行します。このコマンドは、必要となるすべての Apache Cordova プラグインをダウンロードしてインストールし、platforms/android ディレクトリー内に Android プロジェクトを作成します。
  4. Android 端末をコンピューターの USB ポートに接続します (デスクトップ PC またはノート PC で作業していることを前提としています)。
  5. Android 端末でアプリを実行するには、コマンド cordova run device -android を実行します。

    Android のトラブルシューティング: Android 端末でアプリを正常に実行できない場合は、Android 開発者向けドキュメントを調べてください。

このアプリの仕組み

このコグニティブ・アプリのバックボーンとなるのは、以下に記載する Watson の 2 つのサービスです。

  • Visual Recognition サービス: このサービスが提供する API によって、このアプリで画像や動画フレームを分析して、そのコンテンツにラベルを付けることが可能になります。画像をアップロードすると、このサービスの API によって、キーワードのリストと各キーワードに対応するスコアが含まれた JSON レスポンスが生成されます。スコアは、キーワード (つまり、ラベル) がその画像をどれだけ正確に説明しているかを表す数値です。
  • Text to Speech サービス: テキストと自然言語を解析し、適切なリズムとイントネーションで仕上げた合成音声出力を生成します。このサービスの API は入力としてテキストを受け取り、そのテキストを基に音声ファイルを生成します。

その他のコンポーネント

アプリのバックエンドは Node.js 内で作成されていて、Watson コグニティブ・サービスにアクセスするために Watson Developer Cloud Node.js SDK を使用します。この SDK は、npm モジュールとしてダウンロードすることができます (watson-developer-cloud)。あるいは NPM レジストリーから、この SDK にアクセスすることもできます。

アプリでは、以下に記載する 2 つの Apache Cordova プラグインも使用しています。

それでは、コーディングを始めましょう。

ステップ 5. Visual Recognition サービスを接続する

まずは、Node.js 内で画像認識を行うバックエンドのコードから取り掛かります。以下の JavaScript コードは、画像を /api/visual-recognition POST エンドポイントにアップロードし、アップロードした画像が Watson の Visual Recognition サービスへ送られるようにします。

var express = require('express'),
  app       = express(),
  request   = require('request'),
  path      = require('path'),
  bluemix   = require('./config/bluemix'),
  validator = require('validator'),
  watson    = require('watson-developer-cloud'),
  extend    = require('util')._extend,
  fs        = require('fs'),
  multer    = require('multer');

//multer is used to handle image upload
var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, './uploads/');
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + '-' + file.originalname);
  }
});

var upload = multer({ storage: storage });

// if bluemix credentials exist, then override local
var visualRecognitionCredentials = 
{ version: 'v1',
  url: "<url>",
  username: "<username>",
  password: "<password>"
}
// Create the service wrapper
var visualRecognition = watson.visual_recognition(visualRecognitionCredentials);

app.post('/api/visual-recognition', upload.single('image'), function(req, res, next) {
  // Classifiers are 0 = all or a json = {label_groups:['<classifier-name>']}
  var classifier = req.body.classifier || '0';  // All
  if (classifier !== '0') {
    classifier = JSON.stringify({label_groups:[classifier]});
  }

  var imgFile;
  if (req.file) {
    // file image
    imgFile = fs.createReadStream(req.file.path);
  } else if(req.body.url && validator.isURL(req.body.url)) {
    // web image
    imgFile = request(req.body.url.split('?')[0]);
  } else if (req.body.url && req.body.url.indexOf('images') === 0) {
    // local image
    imgFile = fs.createReadStream(path.join('public', req.body.url));
  } else {
    // malformed url
    return next({ error: 'Malformed URL', code: 400 });
  }

  var formData = {
    labels_to_check: classifier,
    image_file: imgFile
  };

  visualRecognition.recognize(formData, function(err, result) {
    // delete the recognized file
    if(req.file)
      fs.unlink(imgFile.path);

    if (err)
      next(err);
    else
      return res.json(result);
  });
});

var port = process.env.VCAP_APP_PORT || 3000;
app.listen(port);
console.log('listening at:', port);

ステップ 6. Text to Speech サービスを接続する

続いて、Node.js 内で音声変換機能を管理する JavaScript を作成します。以下のコードは、合成音声を (/api/synthesize GET エンドポイントを利用して) 生成する基になるテキストを受け取り、受け取ったテキストが Watson の Text to Speech サービス (音声レスポンスが返されます) へ送られるようにします。

var express = require('express'),
  app       = express(),
  watson    = require('watson-developer-cloud'),

// For local development, replace username and password
var textToSpeech = watson.text_to_speech({
  version: 'v1',
  url: '<url>',
  username: '<username>',
  password: '<password>'
});

app.get('/api/synthesize', function(req, res, next) {
  //example of query object
  //{"voice":"en-US_MichaelVoice","text":"This is what I see in the picture: Food, Burning, and, Fabric","download":"true","accept":"audio/flac"
  var transcript = textToSpeech.synthesize(req.query);
  transcript.on('response', function(response) {
    if (req.query.download) {
      response.headers['content-disposition'] = 'attachment; filename=transcript.flac';
    }
  });
  transcript.on('error', function(error) {
    console.log("error " + error);
    next(error);
  });
  transcript.pipe(res);
});

var port = process.env.VCAP_APP_PORT || 3000;
app.listen(port);
console.log('listening at:', port);

ステップ 7. UI を作成する

Cordova を使用して、このモバイル・アプリのフロントエンドを作成します。アプリのユーザー・インターフェースは、1 つのボタンと写真用の <img> プレースホルダーからなるシンプルなものです。

<body>
	<div data-role="page">			
		<div role="main" class="ui-content">
			<input  type="button" value="Take Picture" id="btn_takePicture"></input>
			<div>
                  <img id="picture"/>
             </div>
		</div>
	</div>
</body>

ステップ 8. Cordova Camera プラグインを接続する

ユーザーが端末のカメラを使って写真を撮れるようにする必要もあります。以下の JavaScript コードが、Cordova Camera プラグインです。

takePicture: function(){
		console.log("take picture");		
		navigator.camera.getPicture(app.onTakePictureSuccess, app.onTakePictureFail, 
			{ 	
				quality: 50,
				destinationType: Camera.DestinationType.FILE_URI
			});
	},
	onTakePictureSuccess: function(imageData) {
		var image = document.getElementById('picture');
		image.src = imageData;
		app.showLoading();
		app.getLabels(imageData);
	},
	onTakePictureFail:function(message) {
		var errorAudioPath=(cordova.file.applicationDirectory+"www/audio/picturefail.flac");
		app.playAudio(errorAudioPath);
	},

ステップ 9. Visual Recognition サービスを呼び出す

以下のコードは、写真を /api/visual-recognition エンドポイントにアップロードするほか、Visual Recognition サービスによって生成されたラベルとスコアのリストを受け取ります。ラベルを受け取った後、getSentenceToSpeak を呼び出すことで、リストに含まれるラベルを 1 つの文に変換します。

getLabels:function(imageURI) {
		var options = new FileUploadOptions();
		options.fileKey="image";
		options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
		options.mimeType="image/jpeg";

		var ft = new FileTransfer();
		ft.upload(imageURI,app.serverURL+"/api/visual-recognition", app.getLabelsSuccess, app.getLabelsFail, options);
	},

	getLabelsSuccess:function(r) {
		console.log("Code = " + r.responseCode);
		console.log("Response = " + r.response);
		console.log("Sent = " + r.bytesSent);
		var responseJSON = JSON.parse(r.response);
		var sentenceToSpeak =  app.getSentenceToSpeak(responseJSON.images[0].labels);
		app.downloadAudioFile(sentenceToSpeak,app.playAudio);
	},

	getLabelsFail:function(error) {
		alert("Check your connection to the internet");
		console.log("An error has occurred while getting labels: Code = " + error.code);
		console.log("upload error source " + error.source);
		console.log("upload error target " + error.target);
		app.hideLoading();
		app.errormessage();
	},

	getSentenceToSpeak:function(labelsJSON){
		console.log("labelsJSON:("+labelsJSON.length+")"+JSON.stringify(labelsJSON));
		var sentence="";
		for (var i=0;i<labelsJSON.length;i++){
			console.log("label_name:"+labelsJSON[i].label_name);
			if(i==0){
				//first label
				sentence = "This is what I see in the picture and the corresponding scores: " + labelsJSON[i].label_name + ", "+Math.round(labelsJSON[i].label_score*100) + " percent";
			}
			else if(i==labelsJSON.length-1){
				//last label
				sentence=sentence+", and, " + labelsJSON[i].label_name  + ", "+Math.round(labelsJSON[i].label_score*100) + " percent";
			}
			else{
				sentence=sentence+", " + labelsJSON[i].label_name  + ", "+Math.round(labelsJSON[i].label_score*100) + " percent";
			}
			
		}
		console.log("Sentence:"+sentence);
		return sentence;
	}

ステップ 10. Text to Speech サービスを呼び出す

Cordova File Transfer プラグインを使用して /api/synthesize エンドポイントから音声トランスクリプトをダウンロードし、音声テキスト変換の結果をコールバック関数に渡します。

downloadAudioFile:function(sentence,calback){
		var uri = encodeURI(app.serverURL+"/api/synthesize?voice=en-US_MichaelVoice&text="+sentence+"&download=true&accept=audio/flac");
		var audioCachePath=cordova.file.cacheDirectory+app.makeid()+".flac";
		
		console.log("Audio Download URI:"+uri);
		console.log("Audoi Cache filesystem path:"+audioCachePath);
		var fileTransfer = new FileTransfer();

		fileTransfer.download(
			uri,
			audioCachePath,
			function(entry) {
				console.log("download complete: " + entry.toURL());
				console.log("entry: " + JSON.stringify(entry));
				app.hideLoading();
				calback(entry.toURL());
			},
			function(error) {
				console.log("download error source " + error.source);
				console.log("download error target " + error.target);
				console.log("error code" + error.code);
				app.hideLoading();
				app.errormessage();
			},
			false
		);
	}

ステップ 11. 音声ファイルを実行する

最後に、受け取った音声ファイルを Cordova Media プラグインによって実行します。

playAudio:function(audioURI){
		audioURI=audioURI.replace("file://","");
		console.log("Play audio URI:"+audioURI);
			// Play the audio file at url
			var my_media = new Media(audioURI,
				// success callback
				function () {
					console.log("playAudio():Audio Success");
				},
				// error callback
				function (err) {
					console.log("playAudio():Audio Error: " + err.code+" "+ err.message);
				}
			);
			// Play audio
			my_media.play();
	}

まとめ

このチュートリアルでは、Node.js と Apache Cordova を IBM Watson コグニティブ・サービスとともに使用してモバイル・アプリを作成する方法を説明しました。このアプリは、スマートフォンのカメラで撮った写真を音声で解説します。

Cordova と Node.js の両方を同じソリューションで使用するメリットは、すべてのコードを JavaScript で作成できるため、複数の言語でソリューションを作成する必要がなくなることです。さらに、Node.js モジュールで Watson のサービスにアクセスできるので、コグニティブ機能を備えた Node.js アプリをとても簡単に作成することができます。

このデモ・アプリでは Android をモバイル・プラットフォームとして使用しましたが、Cordova を使用すれば、iOS や Windows Phone でも同じく簡単にアプリを作成することができます。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Mobile development
ArticleID=1032264
ArticleTitle=何が見えますか?視覚面でのアクセシビリティーに対応したコグニティブ・アプリ
publish-date=06092016