Pepperで画像を撮影してタブレットに画像表示

Choregrapheには **Take Picture**というボックスがあり、Pepperが見ている画像をファイルとしてPepper内のファイルシステムに保存することができます。
このファイルをどう処理するかとしては、Eメール送信ボックスでの添付ファイルとしたり、タブレットに画像表示するボックスで参照するなどさまざまなことが考えられますが、それぞれのボックスでファイルを参照するときに重要になるのが、Pepper内でのパスの考え方です。

ここでは、画像を撮影して、それをタブレットに表示する例の作成を通じて、パスの考え方をいくつか説明していきます。

#Take Pictureボックスにおける画像保存先パス

Choregrapheの[ボックスライブラリ]パネルで、standardボックスライブラリ > Vision > Take Pictureボックスを選択すると、以下のような説明が表示されます。

![take-picture-desc.png](https://qiita-image-store.s3.amazonaws.com/0/54394/65a70ac0-a6e7-3f0b-86ee-7eb7aa2a9446.png)

`store it in his memory in ~/recordings/cameras.` とあるので、撮影された画像はPepper内のファイルシステムの `(ホームディレクトリ)/recordings/cameras/` に保存されます。画像ファイル名はパラメータに `File Name` という項目があり、ここで指定することができます。

![take-picture-param.png](https://qiita-image-store.s3.amazonaws.com/0/54394/9375064f-7cff-1c68-57ed-a59a43072390.png)


#タブレットShow Imageボックスにおける画像読み込み元パス

タブレットに画像を表示するためには tabletボックスライブラリ > tablet > Show Imageボックスが利用できますが、このボックスのImage Urlの説明は以下のようになっています。

![show-image-desc.png](https://qiita-image-store.s3.amazonaws.com/0/54394/7fc84b74-98aa-550a-fe4f-3bd0b9d39073.png)

[Pepperチュートリアル (5)：タブレットを使う](http://qiita.com/Atelier-Akihabara/items/87def938b6553ee9c1e9#%E7%94%BB%E5%83%8F%E3%81%AE%E5%87%BA%E5%8A%9B) で詳しく説明していますが、アプリケーションを構成するファイル([プロジェクトの内容]パネルで示されるファイル構成ツリ)ーのうち、 `html` ディレクトリ以下のファイルがタブレットに表示することができるようになっています。

![project-content-html.png](https://qiita-image-store.s3.amazonaws.com/0/54394/fbe5ac0d-e21e-498b-155e-838289aeaf3d.png)


つまり、Take Pictureボックスで撮影した内容を、アプリケーションの `html` ディレクトリに保存することができれば、Show Imageボックスで表示できるようになります。

#実装例

では、**Take Pictureボックスで画像を撮影し、Show Imageボックスでタブレットに表示**するアプリケーションを作ってみます。

なお、Pepperのタブレットに動的に作成したファイルを表示する際は、キャッシュを回避する工夫が必要になりますので、これは別に説明します。

##つくってみる

1. 以下のボックスを配置します
    * standardボックスライブラリ > Vision > Take Picture
    * tabletボックスライブラリ > tablet > Show Image

    ![boxes.png](https://qiita-image-store.s3.amazonaws.com/0/54394/f954a79e-b7d0-2b52-d4d9-a17ee1b87921.png)

2. ボックスを以下のように接続します

    ![connections.png](https://qiita-image-store.s3.amazonaws.com/0/54394/bcbde686-cab0-afd7-4ff0-6ef268462e8f.png)


3. Take Pictureボックスの保存先が、アプリケーションの `html` ディレクトリになるように変更します。Take Pictureボックスをダブルクリックし、以下のようにコードを変更します。
    a. `onLoad`メソッドの先頭に `ALFrameManager` へのアクセス用オブジェクトを生成するコードを追加します

    ```py
    def onLoad(self):
        # 追加コード: ここから
        self.framemanager = ALProxy("ALFrameManager")
        # 追加コード: ここまで
        self.bIsRunning = False
        ...
    ```

    b. `onInput_onStart`メソッドの先頭に、htmlディレクトリのパスを取得するコードを追加します
    
    ```py
    def onInput_onStart(self):
        # 追加コード: ここから
        import os
        self.recordFolder = os.path.join(
                    self.framemanager.getBehaviorPath(self.behaviorId), "../html")
        # 追加コード: ここまで
        if( self.bIsRunning ):
            return
        ...
    ```

4. [Show Imageボックスのパス問題](http://qiita.com/Atelier-Akihabara/items/87def938b6553ee9c1e9#%E8%A3%9C%E8%B6%B3show-image%E3%83%9C%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AE%E5%AE%9F%E8%A3%85%E3%82%92%E3%81%BF%E3%81%A6%E3%81%BF%E3%82%8B)回避のため、Show Imageボックスをダブルクリックし、`_getAppName`メソッドに以下のコードを追加します

    ```py
    def _getAppName(self):
        import os
        if self.frameManager:
            behaviorPath = os.path.normpath(self.frameManager.getBehaviorPath(self.behaviorId))
            appsFolderFragment = os.path.join("PackageManager", "apps")
            if not (appsFolderFragment in behaviorPath):
                self.logger.error("appsFolderFragment is not in behaviorPath")
            fragment = behaviorPath.split(appsFolderFragment, 1)[1]
            # 追加コード: ここから
            fragment = fragment.split('/')[1]
            # 追加コード: ここまで
            return fragment.lstrip("\\/")
        else:
            self.logger.warning("No ALFrameManager")
    ```    

5. 各ボックスの保存先ファイル名を設定します。Take Pictureボックスのほうは拡張子なし、Show Imageボックスのほうは拡張子あり(.jpg)である必要があります

    ![take-picture-box-param.png](https://qiita-image-store.s3.amazonaws.com/0/54394/999531ad-48c3-7245-07d1-6993b584997a.png)

    ![show-image-box-param.png](https://qiita-image-store.s3.amazonaws.com/0/54394/effb11f2-38e2-87ee-42f0-acc67a7ea67d.png)


6. 画像の保存先となる `html` ディレクトリを作成し、適当なダミーファイルをインポートしておきます
    a. プロジェクトの内容パネルの追加ボタンをクリックし、**[ディレクトリの作成...]** をクリックします
    ![create-html-directory.png](https://qiita-image-store.s3.amazonaws.com/0/28770/3ec1d660-1594-a332-46db-ada9473bc790.png)

    b. **[ファイルのインポート...]** をクリックすると、ファイル選択ダイアログが開きます。適当なダミーファイルを選択します。
    ![add-image.png](https://qiita-image-store.s3.amazonaws.com/0/28770/b47f0193-ce06-995b-a8b0-22f8875ca5b0.png)

    c. ダミーファイルをドラッグし、htmlディレクトリ内に移動します
    ![move-image.png](https://qiita-image-store.s3.amazonaws.com/0/28770/e20dd06c-d9e7-1551-f3e8-20014f94d4f0.png)
    これで画像ファイルがタブレットで表示可能な状態になりました。

これで、タブレット表示用の `html` ディレクトリに対して撮影したデータを保存するTake Pictureボックス、この撮影したデータを表示するShow Imageボックスの準備ができました。

##動作確認

Pepperに接続し、[ロボットにアップロードして再生]ボタンを押すと、Pepperのカメラが撮影した内容がタブレットに表示されます。

##タブレットのキャッシュの回避

このアプリケーションを複数回実行しても、タブレットの内容が更新されないという現象が発生します。

これは、タブレットのWebブラウザが画像をキャッシュしてしまっているためです。これを回避する方法としては、実行時の時間をURLのクエリに含めてあげる方法があります。
Show Imageボックスの `onInput_onStart` メソッドに以下のようなコードを追加することで、この問題を回避することができます。

```py
    def onInput_onStart(self):
        # 追加コード: ここから
        import time
        # 追加コード: ここまで
        # We create TabletService here in order to avoid
        # problems with connections and disconnections of the tablet during the life of the application
        tabletService = self._getTabletService()
        if tabletService:
            try:
                url = self.getParameter("ImageUrl")
                if url == '':
                    self.logger.error("URL of the image is empty")
                if not url.startswith('http'):
                    url = self._getAbsoluteUrl(url)
                # 追加コード: ここから
                url += "?" + str(time.time())
                # 追加コード: ここまで
                tabletService.showImage(url)

```