IBM Watson Visual Recognition Custom Class + Node-RED で簡単画像認識 2019年1月版

ブラウザだけで簡単に独自の画像認識モデルが作成できる、[ IBM Watson Visual Recognition ] と、ドラッグ&ドロップだけでサーバープログラムが作成できる[ Node-RED ]を使って画像認識のアプリを作ってみましょう。

---

というネタを2年くらい前からやってますが、
改めてqiita上でまとめます。
使い回すために。

ハンズオン用の流れになってます。

--- 

## 準備　画像を集める

今回は画像認識のモデルを作成するので、クラス分けしたい画像をGoogle検索やスマホのカメラの写真などで集めます。最低１０枚ずつになるようにしてください。

例）寿司認識機の場合
「とろ」と「サーモン」の認識をさせる場合は、
「toro」「salmon」のそれぞれのフォルダを作り、
フォルダの中に画像を入れます。
それぞれのフォルダをZIP圧縮してください。

<img width="575" alt="スクリーンショット 2019-01-29 2.11.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/45591/08bd5976-2b47-2b79-e3d6-97616740fc5d.png">
<img width="619" alt="スクリーンショット 2019-01-29 2.11.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/45591/1d7f82e6-70a5-5dd6-9c36-34cb9268477e.png">
<img width="257" alt="スクリーンショット 2019-01-29 2.12.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/45591/f1cc13ac-5139-6ae4-8fcf-7ec5ed68c974.png">




---

## IBM Cloud ライトアカウントの作成

---

[IBM クラウド　ライトアカウントページ](https://www.ibm.com/cloud-computing/jp/ja/lite-account/)
すでに作っている方はIBM CLoudにログインしてください。

---

### 小ネタ
ログインするページによって画面が違う？

[https://console.bluemix.net/](https://console.bluemix.net/)
からログインする場合
![スクリーンショット 2019-01-29 1.16.58.png](https://qiita-image-store.s3.amazonaws.com/0/45591/9ab241fe-4ccb-f6b5-98fe-d41d43399739.png)
![スクリーンショット 2019-01-29 1.18.42.png](https://qiita-image-store.s3.amazonaws.com/0/45591/78f4bbbe-169d-6263-c871-82be84b0e1b4.png)

[https://cloud.ibm.com/login](https://cloud.ibm.com/login)
からログインする場合（旧 SoftLayer環境）
![スクリーンショット 2019-01-29 1.23.26.png](https://qiita-image-store.s3.amazonaws.com/0/45591/d8e794a5-1b1e-95ba-6192-1dc8f9af9d15.png)

今回は bluemix.net 環境の画面で説明します。

---

## Watson Studio から Visual Recognition Service を作成する

上部のメニューから「カタログ」を選択して、「AI」の中の「Watson Studio」を選びます。
![スクリーンショット 2019-01-28 20.10.42.png](https://qiita-image-store.s3.amazonaws.com/0/45591/b7f1b98f-a9a1-730c-1dc2-d4fc551271e4.png)
地域とサービス名を選択して「作成」
![スクリーンショット 2019-01-28 20.11.02.png](https://qiita-image-store.s3.amazonaws.com/0/45591/86438879-a51d-6902-b675-d2ce575878fa.png)
Get Started でツールを機動します。
![スクリーンショット 2019-01-28 20.11.40.png](https://qiita-image-store.s3.amazonaws.com/0/45591/c9b13f00-a2e3-369e-5212-89b85f185349.png)


![スクリーンショット 2019-01-28 20.12.16.png](https://qiita-image-store.s3.amazonaws.com/0/45591/a5193fe6-2e91-7b02-9de7-be4d6c9bbb3a.png)

プロジェクトを作成します。

![スクリーンショット 2019-01-28 20.12.25.png](https://qiita-image-store.s3.amazonaws.com/0/45591/a8206528-a270-7773-08c7-afb508fa6d9c.png)

各種プロジェクトのテンプレートが選べますが、今回は「Visual Recognition」を選択
![スクリーンショット 2019-01-28 20.13.13.png](https://qiita-image-store.s3.amazonaws.com/0/45591/75eaaec2-8b83-8bbe-777e-5c29fbcb284c.png)

Visual Recognition の Regionを選択します。
![スクリーンショット 2019-01-28 20.13.48.png](https://qiita-image-store.s3.amazonaws.com/0/45591/8742e4ce-d8bb-f0d7-f59e-f05c189a5349.png)

Visual Recognition の GUIツールです。
![スクリーンショット 2019-01-28 22.10.03.png](https://qiita-image-store.s3.amazonaws.com/0/45591/7a6e52b1-c2b4-d96d-5f3a-07ac4886391a.png)

画面右上の「Upload to Project」に準備しておいたZIPファイルをドラッグ&ドロップで渡します。
今回のデモは赤外線画像によるエアコン状態の取得モデルのために、エアコンがついている時と消えている時、および、エアコンの写っていない赤外線サーモグラフィーの画像を用意しました。
画像の準備ができると下の欄でファイル名の下にサイズが表示されるので、認識したい「On.zip」と「Off.zip」にチェックを入れて「Add to Model」をクリックします。
![スクリーンショット 2019-01-28 22.10.10.png](https://qiita-image-store.s3.amazonaws.com/0/45591/1e066e89-e09c-bc3a-30c2-c18c88f4c044.png)

画像が展開されます。
![スクリーンショット 2019-01-28 22.10.26.png](https://qiita-image-store.s3.amazonaws.com/0/45591/115550c1-5938-b917-636f-5f97f617d03d.png)

（オプション）「その他の画像」も学習させるので、「Negative」をクリックして、negative.zipをドラッグ&ドロップで渡します。
![スクリーンショット 2019-01-28 22.10.51.png](https://qiita-image-store.s3.amazonaws.com/0/45591/3e5860bc-a447-d6ab-6e46-625a6fe595d7.png)

上のメッセージが邪魔なので消してから、、、

わかりやすいようにモデル名を変更しておいてください。

ここまでくると学習準備完了。[Train Model]ボタンで学習をスタートします。
![スクリーンショット 2019-01-28 22.11.07.png](https://qiita-image-store.s3.amazonaws.com/0/45591/1ffe64b4-64bb-4168-3509-8e99dc6268c9.png)

緑のメッセージが表示されたら学習完了です。「Click here」で、結果確認画面に移動します。
![スクリーンショット 2019-01-28 22.17.49.png](https://qiita-image-store.s3.amazonaws.com/0/45591/a86d6b73-acfc-9c58-72d5-bd5cd45f11a4.png)

後ほど使うので、「Model ID」をコピーしておきます。（右側のアイコンをクリックするとクリップボードにコピーされます。）

Testをクリックして、検証画面に移動します。
![スクリーンショット 2019-01-28 22.18.02.png](https://qiita-image-store.s3.amazonaws.com/0/45591/3af02705-6db5-f3e2-601a-5b012b49f5c2.png)

学習に使っていない画像を使ってテストしてみます。
![スクリーンショット 2019-01-28 22.20.48.png](https://qiita-image-store.s3.amazonaws.com/0/45591/b82ffb74-f9cb-edeb-ac2e-f50a92633d27.png)

以上で、Visual Recognitionによる画像認識モデルの作成は完了です。
次は実際にWebアプリから使えるようにします。

Implementationのタブに各言語での実装方法が紹介されています。
iOSのCore MLへのエクスポートもできます。

## Node-REDと接続

Node-REDはGUIでロジックを作成できる開発環境です。
カタログの「スターターキット」から　Node-REDと検索し、Node-RED Starter を作成します。
![スクリーンショット 2019-01-29 2.31.27.png](https://qiita-image-store.s3.amazonaws.com/0/45591/64291ce6-b37c-4278-098c-f750ce3d080a.png)

「アプリ名」を決めると下の「ホスト名」が自動で決まります。サーバーのURLになるので、「世界にひーとーつだーけーの」名前をつけてください。地域を選んだら「作成」

![スクリーンショット 2019-01-28 22.49.29.png](https://qiita-image-store.s3.amazonaws.com/0/45591/868f2121-0d9d-84d6-b5ed-4102efce545f.png)

画面に切り替わったら「アプリURLにアクセス」。。。の前に、Watson Visual Recognitionと接続します。左メニューの「接続」をクリックします。

![スクリーンショット 2019-01-29 2.49.48.png](https://qiita-image-store.s3.amazonaws.com/0/45591/c0af1742-f337-83be-66cc-fffd97411e9a.png)

「接続の作成」をクリック
![スクリーンショット 2019-01-29 2.51.56.png](https://qiita-image-store.s3.amazonaws.com/0/45591/b0f45b8f-cbd9-1f74-d1ce-d5d2f3dc3725.png)


表示される一覧から「watson-visual-combined-dsx」にカーソルを移動して「接続」ボタンをクリックします。
![スクリーンショット 2019-01-29 1.48.39.png](https://qiita-image-store.s3.amazonaws.com/0/45591/1fdd5314-6509-89fb-bde4-c0a68d07a2d9.png)

デフォルトのまま「接続」
![スクリーンショット 2019-01-29 1.48.44.png](https://qiita-image-store.s3.amazonaws.com/0/45591/5f27dc0e-968c-a38e-aa34-0fd16208a20c.png)

アプリの再ステージをします。
![スクリーンショット 2019-01-29 1.49.06.png](https://qiita-image-store.s3.amazonaws.com/0/45591/bb3f2506-4a14-b384-51e8-79d9603ac5d5.png)

気長に待つ
![スクリーンショット 2019-01-29 1.49.18.png](https://qiita-image-store.s3.amazonaws.com/0/45591/6d2e217c-68e2-2b48-1e84-8ba4f587e4d3.png)

状態表示が「このアプリは稼働中です」になったら、「アプリURLにアクセス」をします。
![スクリーンショット 2019-01-29 2.39.42.png](https://qiita-image-store.s3.amazonaws.com/0/45591/a9feee63-7dd3-4815-b7df-b29e3a538db1.png)

Node-REDの初期設定をします。Next
![スクリーンショット 2019-01-29 2.56.14.png](https://qiita-image-store.s3.amazonaws.com/0/45591/8de11527-3071-5cd3-cf8a-95a20548e4bd.png)

ログインのためのユーザーパスワードを設定します。設定しないと誰でもエディターに入れちゃいます。
![スクリーンショット 2019-01-29 2.56.47.png](https://qiita-image-store.s3.amazonaws.com/0/45591/e2635a52-3327-0036-6ce2-4dd7ce78528e.png)

Next
![スクリーンショット 2019-01-29 2.57.18.png](https://qiita-image-store.s3.amazonaws.com/0/45591/1dc3df1c-557d-8c3e-cf98-375f92d75144.png)

Finish
![スクリーンショット 2019-01-29 2.58.25.png](https://qiita-image-store.s3.amazonaws.com/0/45591/c4f534fd-e1f1-2740-1928-b4e91d9fd6ec.png)

[Go to your Node-RED flow editor]ボタンでフローエディターを起動します。
![スクリーンショット 2019-01-29 2.58.47.png](https://qiita-image-store.s3.amazonaws.com/0/45591/27c4f429-2a47-1e9c-547b-cbb7a9710961.png)

先ほどのユーザーパスワードでログインします。
![スクリーンショット 2019-01-29 2.59.21.png](https://qiita-image-store.s3.amazonaws.com/0/45591/26a1bfbc-3ee5-2328-3b98-6a9b759ea9e7.png)

Node-REDフローエディターが起動します。
![スクリーンショット 2019-01-29 3.01.06.png](https://qiita-image-store.s3.amazonaws.com/0/45591/b2c90ebc-4b80-fb26-4d4d-f0a6d5d60b33.png)

Node-REDの使い方などについては、[https://nodered.jp](https://nodered.jp) へ。

今回はアップロード画面などのソースが用意してありますので、https://github.com/birdtomita/WatsonVisualRecognition-Node-RED-DEMO/blob/master/Node-RED_flow.json から、JSONデータをコピーします。
Githubのレポジトリにアクセスして、Rawボタンをクリックします。って下にも貼っておきます。
<img width="1069" alt="スクリーンショット 2019-01-29 3.06.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/45591/0415fd78-df00-1f84-d3d1-3dc5f57dac0f.png">

```raw.json
[{"id":"6f00444.4f730bc","type":"http in","z":"6e66393b.949ab8","name":"","url":"/upload","method":"get","upload":false,"swaggerDoc":"","x":150,"y":120,"wires":[["4fc1dff2.c44ef"]]},{"id":"4fc1dff2.c44ef","type":"template","z":"6e66393b.949ab8","name":"","field":"payload","fieldType":"msg","format":"html","syntax":"plain","template":"<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n    <title></title>\n\t<meta charset=\"utf-8\" />\n  <script type=\"text/javascript\">\n\n    function ExecUpload() {\n\n        var upload1 = document.getElementById(\"upload1\");\n        var file1 = upload1.files[0];\n        var formData = new FormData();\n        formData.append('file',file1);\n        fetch('postImage', {\n            method: 'POST',\n             headers: {\n            'Accept': 'application/json'\n            },\n          body: file1\n         }).then(res => res.json()\n          ).then(json => {\n              document.getElementById(\"result\").innerHTML = JSON.stringify(json)\n          })\n    }\n\n    var loadFile = function(event) {\n    var reader = new FileReader();\n    reader.onload = function(){\n      var output = document.getElementById('preview');\n      output.src = reader.result;\n    };\n    reader.readAsDataURL(event.target.files[0]);\n  };\n  </script>\n  <style>\n  #preview img{\n  width: 100px;\n}\n</style>\n</head>\n<body>\n  <div>File-01<input id=\"upload1\" type=\"file\"  onchange=\"loadFile(event)\"/></div>\n  <a href=\"javascript:void(0);\" onclick=\"ExecUpload();\">画像認識開始</a>\n  <span id=\"result\" style=\"color:blue\"></span>\n  <div>\n  <img id=\"preview\">\n  </div>\n</body>\n</html>","output":"str","x":300,"y":120,"wires":[["c31b967a.006248"]]},{"id":"c31b967a.006248","type":"http response","z":"6e66393b.949ab8","name":"","statusCode":"","headers":{},"x":470,"y":120,"wires":[]},{"id":"f260b141.08636","type":"http in","z":"6e66393b.949ab8","name":"","url":"/postImage","method":"post","upload":false,"swaggerDoc":"","x":150,"y":200,"wires":[["93c29154.828f6"]]},{"id":"73eb37fd.9e6c38","type":"http response","z":"6e66393b.949ab8","name":"","statusCode":"","headers":{},"x":810,"y":200,"wires":[]},{"id":"a472aaf2.e18758","type":"visual-recognition-v3","z":"6e66393b.949ab8","name":"","vr-service-endpoint":"https://gateway-a.watsonplatform.net/visual-recognition/api","image-feature":"classifyImage","lang":"en","x":510,"y":200,"wires":[["52cf4c61.b31fc4"]]},{"id":"93c29154.828f6","type":"change","z":"6e66393b.949ab8","name":"","rules":[{"t":"set","p":"params","pt":"msg","to":"{}","tot":"json"},{"t":"set","p":"params[\"classifier_ids\"]","pt":"msg","to":"AirCon_1101964590","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":200,"wires":[["a472aaf2.e18758"]]},{"id":"4252ee39.0a109","type":"debug","z":"6e66393b.949ab8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":790,"y":260,"wires":[]},{"id":"52cf4c61.b31fc4","type":"function","z":"6e66393b.949ab8","name":"","func":"var result = msg[\"result\"];\nmsg.payload = [];\nif (\"images\" in result && result.images.length > 0){\n    image = result.images[0]\n    if (\"classifiers\" in image && image.classifiers.length > 0){\n        classifier = image.classifiers[0]\n        if (\"classes\" in classifier && classifier[\"classes\"].length > 0){\n            msg.payload = classifier[\"classes\"][0]\n        }\n    }\n}\nreturn msg;","outputs":1,"noerr":0,"x":670,"y":200,"wires":[["73eb37fd.9e6c38","4252ee39.0a109"]]},{"id":"79fb6762.1f8f08","type":"comment","z":"6e66393b.949ab8","name":"html form","info":"","x":140,"y":80,"wires":[]},{"id":"5f0aafff.25a6a","type":"comment","z":"6e66393b.949ab8","name":"画像認識処理","info":"","x":150,"y":160,"wires":[]}]
```

Node-REDの右上のメニューから、読み込み→クリップボードを選択
![スクリーンショット 2019-01-29 3.10.33.png](https://qiita-image-store.s3.amazonaws.com/0/45591/b52a49ad-30bb-5c7a-df6d-484884bc3ae7.png)

入力欄に上記JSONを貼り付けて、「読み込み」
![スクリーンショット 2019-01-29 3.10.54.png](https://qiita-image-store.s3.amazonaws.com/0/45591/4932d67d-20ab-2d37-6ce7-a1172a550577.png)

適当なところでクリックすると、フローが貼り付けられます。
![スクリーンショット 2019-01-29 3.12.31.png](https://qiita-image-store.s3.amazonaws.com/0/45591/b2e23b87-9066-72ae-8065-b9d587645e10.png)

[change 2 rules] とあるノードをダブルクリック。一番下の段　msg.params["classifier_ids"] の値「AirCon_1101964590」を、Visual Recognitionで作ったモデルのModel IDと置き換えて「完了」をクリック。
![スクリーンショット 2019-01-29 3.13.17.png](https://qiita-image-store.s3.amazonaws.com/0/45591/3cab4203-dc26-7796-24f3-3ade4f23697a.png)

右上の「デプロイ」ボタンをクリックします。

デプロイが成功しました。
![スクリーンショット 2019-01-29 3.16.03.png](https://qiita-image-store.s3.amazonaws.com/0/45591/cb6f6867-ecca-eeed-ea18-ec556b1c1a09.png)

Node-REDフローエディターのURLを確認します。

フローエディターのURLが、
https://hogehoge.mybluemix.net/red/#flow/....
だった場合は、アクセスするアプリのURLは

https://hogehoge.mybluemix.net/upload
です。
（フロー、上の段の「http in」ノードで設定しています。）
上記URLにアクセスしてみましょう。
<img width="660" alt="スクリーンショット 2019-01-29 3.21.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/45591/1901f3f6-a760-b042-2b27-de0fdec42683.png">

画像を選択して、プレビューを確認した後「画像認識開始」をクリック、認識結果が表示されたら成功です。
<img width="510" alt="スクリーンショット 2019-01-29 3.23.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/45591/3fe7781e-46b3-3f37-00cf-514031c76a98.png">

### 参考1 Core MLへのエクスポート
https://medium.com/@taiponrock/watsonで作ったcore-mlモデルをiosアプリへデプロイする-e40d41cc59b2

### おまけ
Watson Visual Recognition ではなく、Watson StudioでApple の Turi Createを使って画像認識モデルを作成するチュートリアルも用意しました。おヒマな方はどうぞ。
https://github.com/birdtomita/TuriCreate-with-WatsonStudio/blob/master/notebook1.ipynb