まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:bluemix

先日、HTML5 Canvas のサーバーサイド版である Node-Canvas を紹介しました:
Node.js から使えるサーバーサイド Canvas : node-canvas


HTML5 Canvas と互換性のある API を使って動的に Canvas 上に描画をします。実際には単に描画をするだけでなく、描画した内容を画像として取り出したりすることで、サーバー側の JavaScript で動的に画像ファイルを生成することができるようになり、とても便利なライブラリです。

実際に使っていて、1点問題気になることがありました。開発中は(日本語環境バッチリな)自分のマシンを使って動作テストなどを行うので気が付きにくいのですが、実際の本番サーバー上で動かした際にキャンバス上に描画した日本語文字列が化けてしまうケースを発見しました。

例えばこのようなコードを実行して、サーバーサイドで画像を動的に生成したとします:
  :
var fs = require( 'fs' );
var Canvas = require( 'canvas' ),
    Image = Canvas.Image;

  :

var canvas = new Canvas( 300, 300 );
var ctx = canvas.getContext( '2d' );

//. 赤い直線を1本描画する
ctx.beginPath();
ctx.moveTo( 100, 100 );
ctx.lineTo( 200, 200 );
ctx.strokeStyle = 'red';
ctx.stroke();

//. 文字列を表示する
ctx.fillText( 'ハローワールド!', 10, 30 );

//. 画像データをファイルにして保存する
var b64 = canvas.toDataURL().split( ',' )[1];
var buf = new Buffer( b64, 'base64' );
fs.writeFileSync( __dirname + '/images/aaa.png', buf );

  :


このコードを Node.js で実行すると、./images/aaa.png というファイル名で動的に画像ファイルが生成されて保存されます。が、その時に生成される画像で「ハローワールド!」と明示されている文字列はサーバー実行環境によって正しく表示されたり、されなかったりします:

(正しく表示される場合)
2017052901

(文字化けを起こす場合)
2017052902


これはサーバー OS 側に日本語フォントが導入されているかどうかで決まります。特にクラウド環境においては OS は(デフォルトでは)英語版が用意されることが多く、そのまま利用しても日本語フォントが用意されていないため、「ハローワールド」という文字列を正しく描画できず、結果として文字化けを起こしてしまうことになります。

ということは、仮に文字化けを起こしても、OS に日本語フォントを導入した上でアプリケーションサーバーを再起動すれば回避できる、ということになります。

が、ここで問題が発生します。IBM Bluemix のような PaaS 環境の場合、OS 環境設定の自由度が低く、用意されたプラットフォームをカスタマイズして使うハードルが高くなります。現に SSH でログインすることはできますが apt-get などは使えません。またフォントファイルを後から無理やりコピーしてもアプリケーションサーバーを再起動するとそのファイルは消えてしまいます。このような自由度があまり高くないプラットフォーム上で日本語を正しく表示させることが結構難しかったりします。

そしてなんと更に、Node-Canvas の Issue ボードによると、この部分にはどうもバグがあるらしく、(2017/May/29 現在)ステータスが Open になっているので、まだ解決できていない模様でした:
https://github.com/Automattic/node-canvas/issues/783


・・・と、とても困った状況なのですが、結論から言うとなんとかアプリケーション側の工夫で回避することができました。まずは日本語フォントが必要になるので、フリーの日本語フォントを適当にダウンロードしてきます。例えば eFont プロジェクトから配布されているさざなみフォントの最新版を使うことにします。アーカイブファイル(*.tar.bz2)をダウンロード&展開し、sazanami-***.ttf というファイルをアプリケーション内の fonts/ ディレクトリに格納しておきます:
2017052903

(以下のコードではゴシックフォントしか使いませんが、とりあえず明朝フォントと合わせて展開しておきます)


そしてコードの該当部分を以下のように変更します:
  :
var fs = require( 'fs' );
var Canvas = require( 'canvas' ),
    Image = Canvas.Image;

  :

var canvas = new Canvas( 300, 300 );
var ctx = canvas.getContext( '2d' );

//. 赤い直線を1本描画する
ctx.beginPath();
ctx.moveTo( 100, 100 );
ctx.lineTo( 200, 200 );
ctx.strokeStyle = 'red';
ctx.stroke();

//. フォントを強制指定する
var Font = Canvas.Font;
var myFont = new Font( 'myFont', 'fonts/sazanami-gothic.ttf' );
ctx.addFont( myFont );
ctx.font = '20px myFont';

//. 文字列を表示する
ctx.fillText( 'ハローワールド!', 10, 30 );

//. 画像データをファイルにして保存する
var b64 = canvas.toDataURL().split( ',' )[1];
var buf = new Buffer( b64, 'base64' );
fs.writeFileSync( __dirname + '/images/aaa.png', buf );

  :


これで実行すると、フォントが指定のものに強制指定され、日本語が化けずに表示できるようになります(下図は IBM Bluemix 環境下で実行した結果です):
2017052904


なお、上記の方法を使う場合、Ubuntu はこのままでも動くのですが、Mac OS X 環境においては Pango ライブラリを無効にした上で実行する必要があります。具体的には Node-Canvas を npm install した後で、node_modules/canvas/binding.gyp ファイルを編集し、15行目の値を 'false' にする(8行目と同じにする)作業を行い、再度 npm rebuild した上で node コマンドを実行する必要がありました。ご注意ください。


Watson API の1つで、複数の選択肢の中から自分の与えた条件に合うアイテムをトレードオフ判断で絞り込んでくれる、という便利な Tradeoff Analytics API があります(ありました)が、残念ながら5月11日をもって新規インスタンスの生成ができなくなってしまいました(作成済みインスタンスは2018年4月まで使えるようです。詳しくはこちら)。

Bluemix に Watson API が追加された当初から存在していた API の1つであるだけでなく、個人的にもデモなどで使っていて、非常にわかりやすくて便利な API だっただけに残念でした。

このアナウンスがされたタイミングから準備はしていたのですが、実はこの Tradeoff Analytics と同様の(近い互換性を持つ)API を自分でオープンソース化前提で作っています。まだ途中といえば途中ですが、制約付きで一応動く状態にはなっています。新インスタンスが生成できなくなったこのタイミングで一旦公開してみようと思いました:
https://github.com/dotnsf/yatradeoff


なお、この API を実際にアプリケーションサーバー上で稼働させているものもこちらに用意しました。ただ API だけ使いたい人はこちらをどうぞ:
https://yatradeoff.au-syd.mybluemix.net/dilemmas


この URL にブラウザで GET アクセスしても何も起こりません(エラーメッセージが表示されるだけ)が、POST アクセスすると API として動きます。その際にはユーザー名: username &パスワード: password を指定してください(オリジナル同様 Basic 認証です)。


元の Tradeoff Analytics API 同様、/dilemma という POST API エンドポイント1つだけが定義されています。ポストする JSON 型インプットデータのフォーマットには互換性があります。

API の実行結果としての JSON データにも互換性をもたせました。ただ現状はオリジナルのサブセットになっています。現状、以下の3点の制約事項があります:
(1) preferable_solutions データは常にブランクになります
(2) 解析結果は solutions に含まれますが、'FRONT' ステータスを持つデータだけが含まれます
(3) map information を出力するようパラメータで指定しても map information は返されません



ただ1点、オリジナルにはなかった優先順位を考慮する機能も加えています。エンドポイント URL のパラメータに prioritised=1 を追加して実行(例: /dilemma?prioritised=1)すると、インプットデータの JSON データは優先順位順に解釈されます(先にある方が高い優先順位であると解釈されて実行されます。例えば「項目AとBを両方ともトレードオフの材料にする」のではなく、「項目AとBを両方ともトレードオフの材料にするが、Aの方をBよりも優先する」というトレードオフを可能にしています)。


そして、このパラメータを付けて実行した時の API 実行結果も優先順位順に返されます。先にある方がよりオススメな結果、ということになります。まあ preferable_solutions の代わりという位置付けです。


※実はこの機能を付けたくて自分で API を改良した、という経緯があります。


結果の JSON テキストの solutions 内がトレードオフの結果です。オリジナル API では全ての選択肢に対して 'FRONT' か 'EXCLUDE' かの結果を含めていましたが、現状この API では 'FRONT' のもの(トレードオフ判断の結果、選択肢の候補として残ったもの)だけが返される点に注意してください。


先日、IBM Watson Summit 2017 (内のユーザーグループイベント)の開催に併せてリリースした「いらすとや検索」のチューンナップに挑戦しました。



まず、このサービスの内容を簡単に解説します。自分自身も使っていますが、質の高いフリー素材イラストを数多く公開いただいている「いらすとや」様のイラストを、なんとなく覚えている手描きイラストから IBM Watson の類似画像検索機能を使って検索できるようにする、というものです。

この検索サービスでは、「いらすとや」様のイラスト画像を、そのイラストが紹介されているページの URL 情報と併せて IBM Watson の Visual Recognition インスタンスに学習させ、類似画像検索を可能にしています。 そして「いらすとや検索」サイトで描いた絵を画像化し、似たイラスト画像を探した上でイラスト紹介ページへのリンクを作る、という比較的シンプルなロジックで作成しています。ユーザー会の中で紹介し、そこそこの反響もいただきました:
2017050201
ユーザー会での説明資料より)


ただ自分で使っているうちに、作った当初は気付かなかった部分も見えてきました。その中の1つが「カラフルなイラスト画像が検索候補にあまり出てこない」というものでした。理由も明白で、検索時に描くイラストがモノクロなのだから、「類似した画像」を検索するとモノクロの(あるいはモノクロに近い)画像が大量に候補として出て来るのです。形が似ているかどうかというよりも、色の類似性で選ばれてしまっている感じでした。


この問題を解決しようとすると、方法は大きく2つ考えることができます。1つは「検索時に描くイラストに色を付けられるようにする」方法、もう1つは「学習時にモノクロ変換した画像を学習して、そのモノクロ変換した画像の中での類似画像を探す」方法です。要はカラー画像として類似画像を探すのか、モノクロ画像として類似画像を探すのか、という2つの方法です。

実装そのものはどちらでもできると思いますが、このうちの前者はあまりユーザーフレンドリーではないと思っています(手軽に描いたイラストで検索できることがサービスの価値であり、彩色の手間をかけてまでイラストを検索したいと思えない)。というわけで、後者の解決策を実装しました。 ただ画像のグレースケール化は(ロジックが確立されているという意味で)まだ簡単なのですが、モノクロ(白か黒かの2値)化となると、中間くらいの色を白と黒のどちらと判断すべきか、というイラストの特性によってもロジックが左右される問題があるので結構難しかったりします。そのあたりはいずれ詳しく紹介できればと思っています。


で、このチューンナップのビフォー&アフターがこちら:

【ビフォー】
2017050201


【アフター】
2017050202



チューンナップ前の類似画像検索の結果は全体的に白っぽかったと思いますが、チューンナップ後の結果がかなりカラフルになったと思います。つまりモノクロ画像で類似画像を検索した結果、現在はカラフルな画像もシンプルなイラストからの検索候補として得られるようになった、ということです。

IBM Watson Summit 2017 開催記念作品!


自分だけではないと思いますが、可愛らしいフリー素材を数多く公開していただいている「いらすとや」http://www.irasutoya.com/)さんには、大変お世話になっております。



僕の場合はプレゼンテーション内のイラストに多く使わせていただいています。中にはいらすとやさんの素材だけでサイトや資料を作ってしまう職人さんもいらっしゃるようです。

ある程度「いらすとや」を使っていて感じたことは「目的の素材をうまく見つけるのが難しい」ということです。「昔こんな感じのイラストを見た記憶があるんだけど、どのカテゴリーだったっけな?」とか、「この人が使ってるこのイラストと同じものを使いたい」とか、自分の記憶が曖昧だったり、これというキーワードが思いつかない時に目的のイラストをうまく検索できないことがたまにあるのでした。


で、その解決策になるかどうかわかりませんが、興味半分でこんなサイトを作ってみました:
「いらすとや検索」



↑見た通りのサイトです。「なんとなく」覚えているイラストをなんとなく描いて、search して、そのイラストに似た「いらすとや」画像を探す、というものです。PCであればマウスで、スマホの場合はタップで描きます。検索結果は最大100件表示され、その中に含まれていれば目的のページに(クリックで)移動できる、というものです:
2017042501

    ↓

2017042502


例えばこの↑例、「鳩」で検索すればすぐに見つかりますが、「鳥」で検索するとなかなか候補が出てきません。「鳩のイラスト」とまで認識できていればテキスト検索でも探せるのですが、そこまでハッキリを覚えていないようなケースでも「たしかこんな感じの・・・」というイラストが描ければ検索できるようになっています(たぶんw)。


今のところ描くイラストは黒線一本のみで描く必要があります。描き直しに消しゴムなどはなく、reset する必要があります。編集機能にはまだ制約が多いですが、シンプルさを重要視しました(ということにします)!
2017042503



なお、このサイトはコグニティブエンジンである IBM WatsonVisual Recognition(画像認識) API を使って、あらかじめ学習させたイラストからの類似画像を人工知能のテクノロジーを使って検索する、という仕組みで実装しています。いらすとや内の全ページをクロールする方法が分からなかったので、現在は「リクエスト」ラベルから辿れる画像を対象にしています。仕組みはシンプルですが、実はそこそこなテクノロジーが裏に潜んでいたりします。


・・・まあ、ネタにどうぞ(笑)。
 

また、このアプリを作る上で、以下の2つの情報を参考にしました。HTML5 の Canvas にマウス移動(とスマホのタッチ)で線を描画するワザと、特にスマホのタッチで描画をする際に画面のスクロールを強制的に止めるワザです:

JavaScript でマウス座標を取得し、Canvas上に線を描画


IBM SecureGateway は、プライベート環境内のデータをクラウド環境から利用する際のトンネリングを行う上で簡単かつセキュアに環境を用意することができて、ハイブリッドクラウドを実現する上で非常に便利なサービスです(詳しくはこちらも参照ください):
2017041804


このトンネリング環境を作る方法として3つのクライアント環境が用意されています。この3つの環境を比較してみました:
2017041900


まず1つ目は「IBM インストーラー」と名付けられている、専用ソフトウェアです。ハイブリッド化の対象となるプライベートネットワークに接続された Windows/Mac/RHEL/Ubuntu(z, PPC, x86_64) に、各システム向けにビルドされた軽量な専用モジュールからインストールして利用します:
2017041801


2つ目は「Docker」です。ハイブリッド化の対象となるプライベートネットワーク内に Docker 環境があれば(または用意して)、専用の Docker イメージをダウンロードしてコンテナ上で稼働させます:
2017041802


そして3つ目が「IBM DataPower」と呼ばれる専用アプライアンスサーバーです。ハイブリッド化の対象となるプライベートネットワークに直接接続して電源を入れると稼働する、専用サーバーおよびハードウェアです:
2017041803


ちなみに DataPower サーバーの実体の外見はこんな感じです。「ザ・サーバー」って感じ:
ibm datapowers



Secure Gateway のクライアントとして利用する場合、いずれも機能そのものとしての違いはないのですが、選択する上で考慮する要素はいくつかあるので考えてみました。

まずは配布形態と、その形態による依存条件です。IBM インストーラーの場合はソフトウェアとしての配布なので、(仮想)マシンと OS があれば導入できます。Docker の場合は Docker 環境が必要です。プライベートネットワーク内に Docker 環境が用意されていればいいのですが、新たに構築可能かどうか、という点は問題になるかもしれません。そして DataPower は専用サーバーハードウェアなので、このハードウェア資産の購入とネットワークに新たに1サーバーを接続するという必要があります。

次に操作画面の違いです。IBM インストーラーと DataPower の場合はサービスとしてクライアントが実行され、その設定や操作は専用のウェブアプリケーションにアクセスして行うことになります。良く言えば詳しくなくてもウィザート通りにすすめていけるので便利、悪くいうとブラウザ環境必須(コマンドラインからは操作できないのでターミナルでリモートログインして・・というわけにはいかない)のです。Mac や Windows などの GUI 環境が用意されているマシンをネットワーク内で使える場合はいいですが、(現実的な)Linux でやろうとすると X Window まで用意された環境が必要になります:
2017041901


一方 Docker の場合は専用イメージを起動すると操作専用のコマンドラインが起動します。このコマンドラインから目的の操作を直接入力できるので、ターミナルを用いたリモート操作も可能です。Linux 環境前提で、ある程度コマンドライン操作に慣れた人が使うのであれば、こちらの方が便利かもしれません:
2017041902


まとめるとこんな感じですかね。トンネリング部分として同じ機能を提供するものなので、後は前提ネットワーク環境内のルールや操作する人のスキルを元にどれを選ぶかを判断することになると思います:
 IBM インストーラーDockerIBM DataPower
配布形態ソフトウェアDocker イメージアプライアンスサーバー
プライベート環境側に必要な事前準備このソフトウェアをインストール可能な Windows/Mac/RHEL/Ubuntu システムが同一ネットワーク内に存在している(或いは接続できる)こと同一ネットワーク内で Docker 環境が構築されていること特になし
クライアント起動形態サービスDocker コンテナ内で常に実行中サービス
クライアント操作画面GUI(ウェブブラウザ)専用のコマンドラインGUI(ウェブブラウザ)
メリットウィザード形式に沿って設定可能
既存環境の活用
コマンドラインから目的のコマンドを直接実行可能
新たにリソースを調達する場合のコスト
ウィザード形式に沿って設定可能
別途システムやハードウェア、ソフトウェアの準備準備不要
デメリット慣れてくると GUI が面倒
別途 OS が必要
Docker 環境必須
全てコマンドライン操作
(仮想環境なので)パフォーマンスの担保が難しい
専用アプライアンスサーバーの購入が必要


個人的な感想ですが、DataPower は「専用機を買う」という選択肢なので対象外。Docker 環境を用意できるなら Docker が一番楽で、用意できない場合は仮想サーバーの Linux に X Window と専用ソフトウェアをインストール、かな。


このページのトップヘ