IBM Bluemix を通じて提供されている Watson API の1つ Visual Recognition(画像認識) API に「類似イメージ検索」というベータ版の新機能が追加されました:
https://new-console.ng.bluemix.net/catalog/services/visual-recognition/


2016101101


この API はその名の通り、「ある画像に似た画像を(あらかじめ登録しておいた画像群の中から)探す」というものです。個々の REST API としては画像の登録や削除、そして類似検索といった機能が用意されており、それらを組み合わせて実装することになります。また他の Watson API 同様、検索した結果に対してはスコアという検索結果に対する自信の数値根拠が合わせて返される、という特徴があります。


またこの類似画像検索 API のデモサイトも公開されています。選択した画像に似た画像が表示される、というものです。一度使ってみると、どういったことが可能になるのか、というイメージが付きやすくなると思います:
https://similarity-search-demo.mybluemix.net/

2016101201


このブログは公私混同を売りにしている(笑)こともあるので、実際に自分のサービスを使って試してみた様子を以下に紹介します。自分の場合は(お約束ですが)マンホールマップの画像を使わせていただきました。複数の種類のマンホール画像をあらかじめ登録しておいて、後から登録していないマンホール画像を指定して類似検索した時に同じ絵柄のマンホールを見つけることができるかどうか!? という挑戦です。

実はこの挑戦はかなりハードルの高い挑戦でもあります。なぜなら「単にマンホールとして認識」されてしまうと、登録画像は全てマンホールなので「似た絵柄のマンホール」を探すことができないと思われるからです。またマンホールの外側にある部分の類似性は無視してほしいわけですが、その辺りの所、ワトソンはどうなのよ!? ということを確認するための実験的要素の強い作業です。

なおこちらのページのマンホール画像はあらかじめ登録しておく画像の1つとしています:
2016101202


詳しくは API Reference を参照いただきたいのですが、あらかじめ画像を登録する際には画像データに加えて、JSON 形式のメタデータファイルを用意する必要があります。このメタデータに登録された内容は検索結果に含まれて返されることになるものです。そのため ID や作成日時、作成ユーザーといった情報をこのメタデータに加えておくと、画像検索した結果から作成ユーザー情報まで取り出す、ということも可能になります。

今回は登録するデータとしてこの画像と、



画像に加えて、こんな内容のメタデータを用意しておきました:
{
  "id":120002,
  "username":"morimo_t",
  "created":"2010-08-17 22:03:26",
  "text":"川崎市の色蓋。よく通る道路だったのにはじめて気がつきました。",
  "address":"神奈川県川崎市幸区堀川町",
  "lat":35.53229904174805,
  "lng":139.697998046875,
  "nice":5
}

↑細かい説明は省きますが、画像検索した結果にこの画像が含まれていた場合に、これらのメタデータと合わせて結果が取得できる、というためのものです(なのでメタデータが不要であれば空オブジェクトでも構いません)。このように画像とメタデータの組み合わせを登録する画像全てに対して用意しておきます。

実際に画像を登録する前にいくつか準備が必要です。まず当たりまえですが、IBM Bluemix にログインし、Visual Recognition サービスを追加しておきます:
2016101203


サービス追加後、「サービス資格情報」の「資格情報の表示」を選択して、認証情報の "api_key" の値を確認しておいてください(この後で使います):
2016101204


ここからは curl を使って REST API を実行するので、Linux か Mac のユーザーはターミナルを開いてください。Windows ユーザーの場合、curl は別途インストールする必要があります。以下のサイトから環境にあった Windows 用 curl をダウンロードし、インストールしてください:
https://curl.haxx.se/download.html

2016101205


curl コマンドを使う準備ができたら実際に REST API を実行してみましょう。画像を登録するにはまず入れ物(「コレクション」といいます)を用意します。ちなみに類似画像検索はこのコレクション単位で実行して、回答を取得することになります。上記デモサイトのようにショッピング用の商品画像から類似画像を探す、という使い方であれば商品の画像を登録するコレクションを作って、そこに商品画像をまとめて登録して検索する、という使い方をすることになります。

今回は「類似マンホール検索」が目的なので、マンホール画像だけを登録するコレクションをあらかじめ作っておくことにします(そしてそこにはマンホール画像以外は登録しないようにします)。新たにコレクションを作成するにはこの REST API を実行します:
# curl -X POST -F "name=XXXXXXXX" "https://gateway-a.watsonplatform.net/visual-recgnition/api/v3/collections?api_key=(apy_key)&version=2016-05-20"

メソッドは POST で、マルチパートフォームデータとして name パラメータでコレクションの名前(上の例では "XXXXXXXX")を指定します。また URL パラメータで Visual Recognition サービスを参照して確認した api_key と、version("2016-05-20")を指定して実行します。

この実行が成功すると、指定した名前のコレクションが作成され、以下のような実行結果 JSON が返ってきます:
{
  "collection_id": "XXXXXXXX_xxxxxx",
  "name": "XXXXXXXX",
  "status": "available",
  "created": "2016-10-11T05:58:47.129Z",
  "images": 0,
  "capacity": 1000000
}

"name" に指定したコレクション名が入っていて、その名称に "_xxxxxx" という形式が付いた "collection_id" が得られているはずです。この後からはこの collection_id を使って API を実行するので、この値をメモしておきましょう。またこのコレクションには現在 0 枚の画像が登録されており("images" の値)、最大で 1000000 枚の画像が登録できる、という状態になっているようです。

では入れ物ができたので、この入れ物に画像を登録します。画像ファイル名が image.png、対応するメタファイル名が image.json である場合、以下の API を実行します:
# curl -X POST -F "image_file=@image.png" -F "metadata=@image.json" "https://gateway-a.watsonplatform.net/visual-recgnition/api/v3/collections/XXXXXXXX_xxxxxx/images?api_key=(apy_key)&version=2016-05-20"

マルチパートフォームデータで画像ファイルとメタデータファイルを POST メソッドで送り、URL パラメータの中で collection_id を指定しています。この API の実行が成功すると、このような JSON が返ってきます:
{
  "images": [
    {
      "image_id": "mmmmmm",
      "image_file": "image.png",
      "created": "2016-10-11T16:12:16.435Z",
      "metadata": {
        "id":120002,
        "username":"morimo_t",
        "created":"2010-08-17 22:03:26",
        "text":"川崎市の色蓋。よく通る道路だったのにはじめて気がつきました。",
        "address":"神奈川県川崎市幸区堀川町",
        "lat":35.53229904174805,
        "lng":139.697998046875,
        "nice":5
      }
    }
  ],
  "images_processed": 1
}

実行結果として image_id などが生成されています。また metadata の中身は指定してメタデータファイルの中身になっているはずです。

この時点でコレクションの状態を確認してみることにします。コレクションの状態を確認するにはこの APIを実行します:
# curl "https://gateway-a.watsonplatform.net/visual-recgnition/api/v3/collections/XXXXXXXX_xxxxxx?api_key=(apy_key)&version=2016-05-20"

実行が成功すると、以下のような JSON が返ってきます。画像が1つ登録されたので "images" の値が 0 から 1 に変化しています:
{
  "collection_id": "XXXXXXXX_xxxxxx",
  "name": "XXXXXXXX",
  "status": "available",
  "created": "2016-10-11T05:58:47.129Z",
  "images": 1,
  "capacity": 1000000
}

こんな調子であらかじめ登録しておく画像(=検索対象となる画像)をすべて登録しておきます。なお、コレクションに追加できる画像は(API Reference によると) 2MB 以内にするべきとのこと。また1つのコレクションに 1000000 (100万)画像まで登録できることになっていますが、1つのファイルを登録するのに仮に1秒かかるとすると、100 万画像で 100 万秒、つまりノンストップで行っても約 11.5 日かかる計算になります。派手に使う場合は準備に2週間~程度かかる、という心づもりが必要になりますね。

全ての画像が登録されたら、最後に類似画像認識を実行してみます。今回はこの画像を検索してみました(この画像はコレクションには登録していません):



↑上記で紹介した登録画像と同じ絵柄のマンホール画像です。この画像を search.png として保存し、以下の REST API を実行します:
# curl -X POST -F "image_file=@search.png" "https://gateway-a.watsonplatform.net/visual-recgnition/api/v3/collections/XXXXXXXX_xxxxxx/find_similar?api_key=(apy_key)&version=2016-05-20&limit=5"

collection_id を指定して、マルチパートフォームデータが画像ファイルを POST 送信しています。またこの例では URL パラメータに limit=5 を指定して、類似度の上位5つまでを取得するように指示しています。

この API が正しく実行されると、以下のような結果が取得できます:
{
  "image_file": "5137462154683827112.png",
  "similar_images": [
    {
      "image_id": "2f98c6",
      "image_file": "120002.png",
      "score": 0.7548828,
      "created": "2016-10-11T15:22:25.824Z",
      "metadata": {
        "address": "神奈川県川崎市幸区堀川町",
        "created": "2010-08-17 22:03:26",
        "id": 120002,
        "lat": 35.53229904174805,
        "lng": 139.697998046875,
        "nice": 5,
        "text": "川崎市の色蓋。よく通る道路だったのにはじめて気がつきました。€‚",
        "username": "morimo_t"
      }
    },
    {
      "image_id": "d20e86",
      "image_file": "804002.png",
      "score": 0.7416992,
      "created": "2016-10-11T15:59:02.442Z",
      "metadata": {
        "id": 804002,
           :
           :
      }
    },
    {
      "image_id": "b6f1e7",
      "image_file": "1594034.png",
      "score": 0.74121094,
      "created": "2016-10-11T15:17:22.733Z",
      "metadata": {
        "id": 1.594034e+06,
           :
           :
      }
    },
    {
      "image_id": "f0bb1f",
      "image_file": "1888484723171738767.png",
      "score": 0.73828125,
      "created": "2016-10-11T15:31:14.768Z",
      "metadata": {
        "id": 1.888484723171739e+18,
           :
           :
      }
    },
    {
      "image_id": "9f72ed",
      "image_file": "90003.png",
      "score": 0.72998047,
      "created": "2016-10-11T15:31:21.935Z",
      "metadata": {
        "id": 90003,
           :
           :
      }
    }
  ],
  "images_processed": 1
}

この形式だとわかりにくいので、実行結果を表&画像にしてみました:
#画像スコア
10.7548828
20.7416992
30.74121094
40.73828125
50.72998047


なんとも評価の難しい結果になりました。まず1位は期待通りに、事前に登録しておいた同じ絵柄のマンホールを取得することができました!これは素晴らしい!! そして問題は2位以下です。これらはマンホールの絵柄としては明らかに異なり、「類似画像」としてはふさわしくないのですが、そのスコアが1位の画像と大差ない、という結果になりました。

まず今回登録した画像には正解(というか、同じ絵柄のマンホール)が1つしかないので、それが1位になってることは評価に値すると思っています。ただ間違いである2位との差がほとんどないというのも実は厄介で、「似た画像はこの1つだけです」という判断をさせたり、正解が1個もないような検索時に「似た画像はありません」という判断をするのが難しくなってしまうのでした。うーむ・・・

一方で、今回は 500 枚のマンホール画像を事前に登録したのですが、この枚数が少なすぎた可能性はありますね。

とはいえ、最初に触れているように、今回の検証は「マンホールの絵柄の類似性を確認できるか?」というかなりハードルの高い検証をしたつもりでしたが、ある程度は判断できているようにも見えます。今後は登録画像枚数も増やした上で再度色んなパターンで検証することになると思ってます。



なお、この類似画像検索 API の詳細については API Reference を参照ください:
http://www.ibm.com/watson/developercloud/visual-recognition/api/v3/#collections