ROS講座62 Webカメラの画像をブラウザから見る

# 環境
この記事は以下の環境で動いています。

| 項目 | 値 |
|:-:|:-:|
| CPU | Core i5-8250U |
| Ubuntu | 20.04 |
| ROS | Noetic |

インストールについては[ROS講座02 インストール](https://qiita.com/srs/items/e0e0a9dc3f94c2d3348e)を参照してください。
またこの記事のプログラムはgithubにアップロードされています。[ROS講座11 gitリポジトリ](https://qiita.com/srs/items/25a56a6abda41dcf396e)を参照してください。

# 概要
例えばロボットのカメラの画像を遠隔から監視してロボットを動かしたいという場合があります。手元にubuntuやROSの載っているPCがあればよいのですが、タブレットやスマホから見たいとするとweb経由でカメラを見るのが便利です。

# web video server
web video serverはrosの中のimage形のトピックをwebに配信してくれるノードです。便利なことに、特にTopic名を指定しなくても自動でImage型のTopicを探して配信してくれます。
paramで変えられますが、デフォルトでは8080ポートで動作します。

```shell:インストール
sudo apt-get install -y ros-noetic-web-video-server
```

# ソースコード

## laucnch
wwwサーバーノード、カメラノードとImageの配信ノードの3つを立ち上げます。

```xml:web_lecture/launch/camera_stream.launch
<launch>
  <include file="$(find hard_lecture)/launch/usb_cam.launch" />

  <include file="$(find roswww)/launch/roswww.launch" />
  <node pkg="web_video_server" type="web_video_server" name="web_video_server" />
</launch>
```

## htmlファイル
カメラ画像を見るためのhtmlファイルです。

```html:web_lecture/www/camera.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
  <head>
    <title>ROS Image Web Viewer</title>
  </head>

  <body>
    <h1>/image_raw</h1>
    <script>
      document.write("<img src='http://"+location.hostname +":8080/stream?topic=/image_raw&type=ros_compressed'></img>");
    </script>
 </body>
</html>
```

# 実行
USBカメラをPCに刺します。`ls /dev/video0`があることを確認して、以下のコマンドでwebサーバー達を起動します。

```shell
roslaunch web_lecture camera_stream.launch 
```

## web_video_serverが生成するページから見る
この状態でブラウザを開いて`localhost:8080`にアクセスします。すると以下のようなページが出てきます。Image型でpublishされているTopicの一覧が出てくるので、目的のTopicをクリックします。
![web_camera2.png](https://qiita-image-store.s3.amazonaws.com/0/254442/8d23717a-c41d-9780-75df-48207f24a524.png)

クリックすると以下のようなページになって、動画のストリームが見れます。
![web_camera1.png](https://qiita-image-store.s3.amazonaws.com/0/254442/7b9648e4-1d69-2474-f75c-91fb543aee9a.png)

`http://localhost:8080/stream?topic=/image_raw`で`/image_raw`に流れている画像が見れます。
`http://localhost:8080/stream?topic=/image_raw&type=ros_compressed`だと`compressed`で圧縮されている画像が見れます。

## roswwwのページから見る
今までと同じように`http://localhost:8085`のサーバーから見る方法を考えます。
`http://localhost:8086/web_lecture/camera.html`にアクセスをします。このページでは`8086`のサーバーのhtmlから`8080`のサーバーの画像を取得するために少しjavascriptで小細工をしています。

```html:web_lecture/www/camera.htmlの一部
<script>
      document.write("<img src='http://"+location.hostname +":8080/stream?topic=/head_camera/image_raw&type=ros_compressed'></img>");
</script>
```

# 全画面で見る
スマホ等の画面にフルスクリーンのようにできる限り大きく映したいことがあります。

```html
<!doctype html>
<html lang="ja">
  <head>
    <title>ROS Image Web Viewer</title>  
    <style>
    *{
      margin: 0px;
      padding: 0px;
      border: 0px;
    }
    .full_picture{
      width: 100vw;
      height: 100vh;
      object-fit: contain;
    }
    </style>
  </head>

  <body>
    <script>
      var image_topic = "/head_camera/image_raw";
      document.write("<img class='full_picture' src='http://"+location.hostname +":8080/stream?topic=" + image_topic + "&type=ros_compressed'></img>");
    </script>
  </body>
</html>
```

これで`/head_camera/image_raw`のトピックがフルスクリーンで表示されます。
`<style>`要素内はCSSの記述です。`  *{margin: 0px; padding: 0px; border: 0px;}`は全ての要素について余白を無く表示するための指定です。これがないと余計な余白が表示されます。

上記のようにlocation変数を使うことでうまく画像のurlを生成しています。`  .full_picture{width: 100vw; height: 100vh; object-fit: contain;}`がフルスクリーン表示をしているところです。`vw`、`vh`はブラウザのサイズに対する大きさの指定で、ブラウザの画面と同じ大きさを指定しています。`object-fit: contain`は元の画像のアスペク比を保ったまま画像が収まるようにできる限り拡大するという指定です。

<img width="419" alt="web_camera_full.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254442/22af61a3-10e9-db39-f4db-91edb885abb2.png">

# 参考
[web video server](http://wiki.ros.org/web_video_server)
[javascript: locationについて](https://www.sejuku.net/blog/26999)

# 目次ページへのリンク
[ROS講座の目次へのリンク](https://qiita.com/srs/items/5f44440afea0eb616b4a)