ROS講座66 カメラのキャリブレーションを行う

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

| 項目 | 値 |
|:-:|:-:|
| CPU | Core i5-8250U |
| Ubuntu | 16.04 |
| ROS | Kinetic |

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

# 概要
カメラで使用しているレンズには何であり「歪み」があります。これを測定して、ゆがんでいる分をソフトウェア的に補正することがキャリブレーションです。

# インストール
歪みの補正用と画像の補正用のパッケージをインストールします。

```shell
sudo apt-get install -y ros-kinetic-camera-calibration
sudo apt-get install -y ros-kinetic-image-proc 
```
# 歪みの測定
歪みの測定を行います。rosではカメラのノードは画像のトピック(/image_raw[sensor_msgs/Image])とカメラのプロファイルのトピック（/camera_info[sensor_msgs/CameraInfo]）をpublishしています。正しいcamera_infoをpublishするための設定ファイルを得ることが目的です。

## チェッカーボードの印刷
チェッカーボードは白黒のチェス盤のような市松模様のついた板のことです。例えば[ROSwikiのチェッカーボード](http://wiki.ros.org/camera_calibration/Tutorials/MonocularCalibration?action=AttachFile&do=get&target=check-108.pdf)を印刷して平らな板に貼って使用します。後々使うのでチェックの交点の数（≠四角形の数）と、各チェックの一辺のサイズを測ります。
このファイルをA4で印刷するとチェックの交点は8x6個、一辺は0.025m(=2.5cm)あたりになります。

## 歪の測定
まずUSBカメラをPCに繋ぎます。3つのターミナルで以下の3つのコマンドを打ってください。

```shell:1つ目のターミナル
roscore
```

```shell:2つ目のターミナル
rosrun uvc_camera uvc_camera_node 
```

```shell:3つ目のターミナル
rosrun camera_calibration cameracalibrator.py --size 8x6 --square 0.025 image:=/image_raw
```

3つ目のターミナルから歪みの測定用のGUIが生成されます。この画面が出た時から測定は開始しています。
![cam_calib2.png](https://qiita-image-store.s3.amazonaws.com/0/254442/660795cd-98fb-7113-8baf-5bc5cd7ef491.png)

チェッカーボードをいろいろな見せ方で見せて測定を行います。上の図のように虹色のマークがついている時に測定を行っています。うまくキャリブレーションするためのコツとしては

* 様々な距離で撮る
    * カメラいっぱいに写す。
    * カメラの遠くで写す。
* 隅々まで撮る。
    * カメラの遠くで全体をカバーするように動かす。
* チェッカーボードを斜めにして写す

右側の青い「CALIBRATE」ボタンが押せるようになったら測定は十分です。ボタンを押すと計算が始まります。この計算には数分～10分ほどかかります。

## camera.yamlの解凍
`/tmp/calibrationdata.tar.gz`に測定の結果がまとまっています。まず解凍して、リネームします。

```shell:設定ファイルの取り出し
tar -xvzf /tmp/calibrationdata.tar.gz
mv ost.yaml camera.yaml
```

camra.yamlを開いて以下のように修正します。

```text:camera.yamlの修正
camera_name: narrow_stereo  #この行を
camera_name: camera         #このように修正
```

camera.yamlを適当な場所（今回はcam_lecture/config/）に移してここは終わりです。今回だと以下のようなyamlの設定ファイルを得ることができました（もちろんパラメーターはカメラによって異なります。）。

```xml:cam_lecture/config/camera.yaml
image_width: 640
image_height: 480
camera_name: camera
camera_matrix:
  rows: 3
  cols: 3
  data: [318.898697, 0, 311.613177, 0, 319.855587, 291.248501, 0, 0, 1]
distortion_model: plumb_bob
distortion_coefficients:
  rows: 1
  cols: 5
  data: [0.016615, -0.025819, 0.002167, 0.003753, 0]
rectification_matrix:
  rows: 3
  cols: 3
  data: [1, 0, 0, 0, 1, 0, 0, 0, 1]
projection_matrix:
  rows: 3
  cols: 4
  data: [315.782593, 0, 314.915759, 0, 0, 318.99234, 293.472369, 0, 0, 0, 1, 0]
```


# カメラ画像の補正
カメラ画像の補正には`image_proc`というノードを使います。このノードは`/camera_info`と歪んでいる画像`/image_raw`をsubscribeして補正した画像`/image_proc`をpublishします。

# launchファイル

```xml:cam_lecture/launch/cam_proc.launch
<launch>
  <node name="uvc_camera_node" pkg="uvc_camera" type="uvc_camera_node" output="screen">
    <param name="camera_info_url" value="file://$(find cam_lecture)/config/camera.yaml"/>
  </node>
  <node name="image_proc" pkg="image_proc" type="image_proc" output="screen"/>

  <node name="image_raw_view" pkg="image_view" type="image_view" >
    <remap from="image" to="image_raw"/>
  </node>
  <node name="image_rect_view" pkg="image_view" type="image_view" >
    <remap from="image" to="image_rect_color"/>
  </node>
</launch>
```

3行目の`<param name="camera_info_url" value="file://$(find cam_lecture)/config/camera.yaml"/>`で先ほどの設定ファイルをロードしています。このように初めに`file://`を付ける必要があります。

# 実行

```shell
roslaunch cam_lecture cam_proc.launch
```

チェッカーボードを写して補正前と補正後の画像を比較してみました。使っているwebカメラが広角であったのもあって、四隅での歪みがだいぶあったことがわかりますね。
![cam_calib3.png](https://qiita-image-store.s3.amazonaws.com/0/254442/85f3b88d-2323-aeaa-7664-d5b0058a3a18.png)

# 参考
ここでカメラ系のトピックをまとめてみます。

* uvc_cameraがpublish
    * camera_info  
    カメラの画素数や歪みのデータ
    * image_raw  
    カメラの生画像
* image_procがpublish
    * image_rect  
    歪みが補正されている（白黒）
    * image_rect_color  
    歪みが補正されている（カラー）
    * image_color/image_mono  
    今回は使用していないが色味を修正したもの



# 参考
[ROS KineticでのUSBカメラ接続とキャリブレーションまで](https://qiita.com/proton_lattice/items/aa805b28700575ba5ed3)

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