cv_bridgeをpython3(virtualenv)で使いたい時の解決法

## 経緯
ROSを使って色々イジイジしていたときのことです。カメラの入力ノードからRGBデータが送られてくるので、それを別のノードで受け取りたいと思い、cv_bridgeを使おうとしていました。下のような感じです。

```python3
from cv_bridge import CvBridge

def prediction(msg):
    bridge = CvBridge()
    img = bridge.imgmsg_to_cv2(msg, "bgr8")
```
しかし、ビルドして実行してみたところ、以下のようなエラーが発生しました。

```
File "/opt/ros/melodic/lib/python2.7/dist-packages/cv_bridge/core.py", line 91, in encoding_to_cvtype2
    from cv_bridge.boost.cv_bridge_boost import getCvType
ImportError: dynamic module does not define module export function (PyInit_cv_bridge_boost)
```
調べてみると、cv_bridgeがpython2でビルドされていることが原因のようでした。自分は実行環境がpython3(virtualenv)だったので、cv_bridgeをソースコードからビルドする必要がありました。

## 環境
- ROS melodic
- python3.6(virtualenv)
- ubuntu18.04
- Jetson AGX Xavier

## 最初にやった方法
最初は[こちら](https://stackoverflow.com/questions/49221565/unable-to-use-cv-bridge-with-ros-kinetic-and-python3/50291787#50291787)の方法を参考にしてやってみました。ローカルのpython3が実行環境の場合は、上手く行くのかもしれませんが、virtualenvを使っていた自分の環境ではうまく行きませんでした。一応共有しておきます。

```bash
$ cd catkin_ws
$ catkin config -DPYTHON_EXECUTABLE=/usr/bin/python3 -DPYTHON_INCLUDE_DIR=/usr/include/python3.5m -DPYTHON_LIBRARY=/usr/lib/aarch64-linux-gnu/libpython3.5m.so
$ catkin config --install
$ git clone https://github.com/ros-perception/vision_opencv.git src/vision_opencv
$ apt-cache show ros-melodic-cv-bridge | grep Version
$ cd src/vision_opencv/
# たぶんの下のバージョンだった気がします。apt-cache showで出てきたものです。
$ git checkout 1.13.0
$ cd ../../
$ catkin build cv_bridge
$ source install/setup.bash --extend
```
virtualenvを使っていた自分の環境では、cv_bridgeは無事にビルドされるのですが、ビルド後に自前の他のノードを一緒のcatkin_wsでビルド実行すると下のようなエラーが発生してしまいました。

```
RLException: [sample.launch] is neither a launch file in package [sample_proc] nor is [sample_proc] a launch file name
```
ここから結構沼にハマってしまいました。犠牲者を減らすために、自分が解決した方法を共有します。

## 最終的な解決法
[こちら](https://github.com/Eruvae/yolact_ros)のリポジトリの環境が、自分と同じようにvirtualenv上のpython3でcv_bridgeを使っていたので、そこからヒントを得ました。
大事なことは、2つあります。1つは、cv_bridgeのビルドを自前のワークスペースとは別のワークスペースで行うことです。もう1つは、自分のスクリプトのcv_bridgeをimportしている行の前で、python2.7のパスを削除することです。具体的な手順は以下の通りです。

```bash
$ sudo apt install python-catkin-tools python3-dev python3-catkin-pkg-modules python3-numpy python3-yaml ros-melodic-cv-bridge
$ mkdir -p cv_bridge_ws/src && cd cv_bridge_ws
$ git clone https://github.com/ros-perception/vision_opencv.git src/vision_opencv
$ apt-cache show ros-melodic-cv-bridge | grep Version
$ cd src/vision_opencv/
# apt-cache showの結果のversionの値に切り替えてください
$ git checkout 1.13.0
$ cd ../../
# 環境により、DPYTHON_LIBRARYのaarch64-linux-gnuの部分は変わります
$ catkin config -DCMAKE_BUILD_TYPE=Release -DPYTHON_EXECUTABLE=/usr/bin/python3 -DPYTHON_INCLUDE_DIR=/usr/include/python3.6m -DPYTHON_LIBRARY=/usr/lib/aarch64-linux-gnu/libpython3.6m.so
$ catkin build
$ source devel/setup.bash --extend
$ cd ../catkin_ws
# 自前のノードをビルド
$ catkin build
$ source devel/setup.bash
```
さらに自分のスクリプトも変更します。sys.path.removeの文の下にはcv_bridgeのimportの文だけにしてあげてください。

```python3
import sys
sys.path.remove('/opt/ros/melodic/lib/python2.7/dist-packages')
from cv_bridge import CvBridge

def prediction(msg):
    bridge = CvBridge()
    img = bridge.imgmsg_to_cv2(msg, "bgr8")
```
これにより、python2のcv_bridgeではなく、python3のcv_bridgeが実行時に呼び出されるようになります。

## まとめ
もうmelodicはいやだ(笑)。noeticかROS2使いたい。

**間違いや質問、ご意見等ありましたらお気軽にコメントください。頑張って答えますので(笑)。**