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

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

タグ:image

ゆるキャラを画像で検索するサービスを作って公開してみました:
http://yuru.mybluemix.net/

まず最初に、自分はある程度ゆるキャラに詳しいと思っています。積極的な興味というよりは、マンホールに詳しくなっていると、最近はそのマンホールのデザインにゆるキャラが使われることが珍しくなくなってきたので、自然と(?)ゆるキャラにも詳しくなってしまうのでした。。
2017011500
 

さて、ゆるキャラに限らないのですが、イマドキ何かを調べようとした時にはまず『ググる』のが定番です。ただ、それは調べるためのキーワードが分かっている場合です。ゆるキャラの場合、名前が分かっていれば名前でググれば確実ですし、名前が分からなくても出身地とかが分かれば「ゆるキャラ 東京都」などで検索すればいくつか候補が見つかるのでそこから調べる方法もあります。

しかし問題は名前も出身地も分からず、検索するためのキーワードがない場合です。例えば目の前に着ぐるみそのゆるキャラ本体がいて、写真は撮れるんだけど、そのゆるキャラがなんという名前で、どこのゆるキャラで、どんな特徴を持っているのか、、、といった情報を調べる具体的な方法がなかったように感じていました。

といった背景もあり、「画像からゆるキャラを調べる」ことができるようなウェブサービスを作ってみた、という経緯です。いわゆる「類似画像検索」を行うため、コグニティブエンジンである IBM WatsonVisual Recognition API を使って実装してみました:
http://yuru.mybluemix.net/


使い方はシンプルで、ウェブサイトをPCかスマホのブラウザで開き、ファイル選択ボタンを押して、ローカルシステムやフォトライブラリ等から目的の画像を選択するだけです:
2017011501


PC の場合に限り、目的の画像ファイルを画面上部のこの辺りにドラッグ&ドロップしても構いません:
2017011502


例えばこの画像のゆるキャラを調べてみることにしました。まあ有名なヒトなので答はわかっているのですが、ちょっとトリッキーなアイテムも写っていて普段と違う画像になっているので、いいサンプルかな、と:
く


この画像を選択するか、画面内にドラッグ&ドロップすると画面が暗転して検索が始まります:
2017011503


暗転から戻ると、検索結果として候補キャラが画面下部に表示されているはずです。最大で100件表示されます:
2017011504


今回の画像の場合、下の方にそれっぽいのが見つかりました:
2017011505


該当する結果の画像をクリックすると、そのゆるキャラの情報がポップアップします。ご存知「くまモン」でした。なお PC であればマウスオーバーでも表示されます:
2017011506


まだまだ学習量が充分ではなく、第一候補となることはまだ珍しいとか、(着ぐるみの写真ではなく)絵の場合には精度が落ちるとか、横から写した画像に弱いとか、背景画像に左右されることが多いとか、まだまだ問題はありますが、一応動くものが作れたと思ってます。

実際の用途としてはある程度いけるかな、と思ってます。もちろん精度高く検索できることが理想ですが、上記で書いたように「名前が分かれば色々調べる方法はあるんだけど、肝心の名前が出てこない」のを解決するツールとして考えると、検索結果の候補の中に含まれていれば、それはそれでオッケーかな、と。


なお、今回のサービスは Visual Recognition の中では現時点でベータ版の /v3/collections/ で始まる API を使って開発しています。今後の仕様変更などがあった場合にサービスがどうなるか何とも言えませんが、なるべく対応させていく予定です。合わせてもう少し学習データの量を増やして検索精度を上げられないか、がんばってみます。


最近はスマホのカメラの性能が上がり、その結果として画像ファイルサイズが大きくなりました。解像度が上がったことは嬉しいのですが、画像ファイルをウェブアプリなどにアップロードしようとする際に時間がかかったり、パケット通信量が増えてしまったりします。また送信先の API やシステム設定によってはアップロードサイズに上限が設定されていて、そのままでは送れなかったりすることもあります。

そんな場合に「画像を小さくしてから処理する」方法が考えられますが、Java によるその一例を紹介します。画像ファイルデータが img 変数にバイト配列で格納できているという前提で、横幅を 800 ピクセル、縦横比を変えずに高さをそれにあわせる形で変更するような処理内容を記述しています(こうすると、大抵 1MB 以下になります):

byte[] img = null; //. この変数に画像データが byte 配列で格納されているものとする
   :
   :

//. 画像のサイズを変更
if( img != null ){
  BufferedImage src = null;
  BufferedImage dst = null;
  AffineTransformOp xform = null;

  InputStream is = new ByteArrayInputStream( img );
  src = ImageIO.read( is );

  int width = src.getWidth();    //. オリジナル画像の幅
  int height = src.getHeight();  //. オリジナル画像の高さ

  int w = 800; //. 幅をこの数値に合わせて調整する

int new_height = w * height / width; int new_width = w;
//. 画像変換 xform = new AffineTransformOp( AffineTransform.getScaleInstance( ( double )new_width / width, ( double )new_height / height ), AffineTransformOp.TYPE_BILINEAR ); dst = new BufferedImage( new_width, new_height, src.getType() ); xform.filter( src, dst );
//. 変換後のバイナリイメージを byte 配列に再格納 ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write( dst, "jpeg", baos ); img = baos.toByteArray(); }

上記のように ImageIO と java.awt のアフィン変換を使って画像サイズに変換をかけて実装しています。

 

業務に関係して、ちょっとした画像アップローダーが欲しくなったので、IBM Bluemix でも動くようなものを作って一般化したものを公開します:
https://github.com/dotnsf/ImgUploader


PHP + MySQL + HTTP サーバー環境で動きます。Bluemix であれば PHP ランタイムClearDB試験提供の MySQL サービスを組み合わせた環境を想定しています:
2016061000


中身は非常にシンプルで、画像をアップロードして一覧で表示したり、プレビューしたり、というものです。画像データは BLOB 型にして MySQL 内に格納しているので、MySQL のバックアップを取ると画像データがバックアップされます。ここにアップロードした画像は URL でアクセスできるようになります。

アップロードに際しては PHP 設定の制約などを受けます。Bluemix 環境であれば最大 2MB です。PHP の設定を変更するなどしてください。必要に応じて認証を付けて運用してください。

その他、シンプルなので普通に使えると思っていますが、詳しくは GitHub の README を参照ください。


IBM Bluemix から使える Node-RED 環境内には AlchemyAPI の画像解析機能を持ったノードがあります。analysis カテゴリ内にある "Image Analysis" と書かれたノードがそれです:
2015120810


このノードを Node-RED 内で使うと比較的簡単に画像認識機能を実装することができます。実際に使ってみましょう。まずはこのノードをキャンバスにドラッグ&ドロップします:
2015120817


同様にして input カテゴリの inject ノードと、output カテゴリの debug ノードをドラッグ&ドロップでキャンバスに貼り付け、以下のように線で結びます:
2015120811


各ノードの属性を順に指定していきます。まずは inject ノードです。ここでは画像解析する画像の URL を文字列で指定します。というわけで種類には "string" を選択し、その下のフィールドには解析したい画像の URL を指定します。ここでは以下の画像(の URL)を指定することにしましょう:
http://news-de-smile.com/wp-content/uploads/2015/02/america-obama.jpg

↑これが何の画像なのか、は普通の人間であればわかるはず。これがコンピュータにわかるか??


"Payload" の種類に "string" を、その下に画像 URL を入力します:
2015120812


次に Image Analysis ノードの属性を指定します。ここでは AlchemyAPI を使うため、AlchemyAPI の API Key を指定します(未取得の方はここから登録して取得してください、無料です)。また解析内容は顔認識機能を使うことにしましょう。Detect の種類には "Faces" を選択します:
2015120813


最後に debug ノードの属性を指定します。この Image Analysis ノードの結果はメッセージ内に "result" という名前が付いた状態で返されます(一般的な "payload" ではありません)。というわけで、debug ノードでは debug タブに msg.result を表示するよう指定します:
2015120814


これで準備は完了です。右上の "Deploy" ボタンでデプロイします。また解析結果は debug タブに出力されるため、debug タブが表示されるよう選択しておきます:
2015120815


では解析を実行してみましょう。inject ノードの左にあるボタン部分をクリックすると、指定した画像 URL が AlchemyAPI の FaceDetection API によって解析され、その解析結果が debug タブに出力されるはずです:
2015120816


おそらくこんな感じの JSON テキストが実行結果として得られるはずです:
[
 {
  "age": {
   "ageRange": "55-64",
   "score": "0.447907"
  }, 
  "gender": {
   "gender": "MALE",
   "score": "0.993307"
  },
  "height": "389",
  "identity": {
   "disambiguated": {
    "dbpedia": "http://dbpedia.org/resource/Barack_Obama",
    "freebase": "http://rdf.freebase.com/ns/m.02mjmr",
    "name": "Barack Obama",
    "subType": [ "Person", "Politician", "President", "Appointer", "AwardWinner", "Celebrity", "PoliticalAppointer", "U.S.Congressperson", "USPresident", "TVActor" ],
    "website": "http://www.whitehouse.gov/",
    "yago": "http://yago-knowledge.org/resource/Barack_Obama"
   },
   "name": "Barack Obama",
   "score": "0.960834"
  },
  "positionX": "223",
  "positionY": "125",
  "width": "389"
 }
]

この中を見ると、画像に写っているのは1人の男性でその確率は 99.3307% 、年齢層は 55-64 歳でその確率は 44.7907%。そしてその人が "Barak Obama" である確率が 96.0834% である、という結果になっていることがわかります。それ以外の情報も含まれていますが、ともあれ Node-RED と Image Analysis ノードを使って簡単に画像認識 API を呼び出すアプリが作れてしまいました。

このページのトップヘ