TJBot zero 再始動 (Node-RED de OpenCV (顔認識まで))

# この記事は
https://qiita.com/ssakaigawa/items/3e7ee0f2de421a3d9a39

2018 年ごろに発足した TJBot コミュニティ。ハンズオンイベントなどを通じて工作や IBM Cloud を体験できるステキなコミュニティです。
しかし、コロナ禍の影響でハンズオンイベントは休止...。さみしい時間を過ごしてるなかで遂に、TJBot zero コミュニティの活動が再開することになりました。

イベントなどを再開するにあたり、TJbot zero 用のSDカードイメージを見直すことになりました。
環境に関する課題は以下の通りです。

- Node-RED のバージョンが低い(Ver 1.0.1)
- すでに利用できない node や クラウドサービスがある 

わたしもコミュニティの一員として「 Node-RED のバージョンが低い」の解決にチャレンジしました。
その手順の備忘録になります。

# 準備
[コミュニティーのGitHubレポジトリ](https://github.com/tjbotfan/tjbotzero-raspbian/tree/master) から SDカードのイメージを取得します。この記事では、`TJBot Zero SD Card Image Release 2019-10-10(JPN)` をベースに作業しています。
SDカードイメージを取得したら、お手持ちのSDカードライターなどを使ってSDカードに書き込みます。
（SDカードへのイメージ書き込み手順は割愛します）

# Node-RED バージョンアップ
[Node-RED 公式ページ](https://nodered.jp/docs/getting-started/raspberrypi)を参考に、Node-RED をバージョンアップします。

## SSh でログイン
TJBot zero に ssh でログインします。
```
ssh xxx.xxx.xx.x -l pi
```

## Node-RED と Node.js のアップグレード
インストールされている Node-RED と Node.js をアップグレードします。
今回の手順では、Node.js のバージョンを16から20にアップグレードします。

**実行コマンド**
```
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered) --node20
```
(完了するまでに２０～３０分くらい掛かります）

アップグレードが完了すると、**「こんにちは、ぼくのなまえは てぃじぇいぼっとです」** とご挨拶してくれるはずです。

# Node-RED にアクセス
ブラウザを起動し、Node-RED のエディタを表示します。
```
http://xxx.xx.x.x:1880/
```
このとき、`OpenCV ノードが存在しない` というエラーが表示されるのは正しいです。
新しい Node.js では、既存のOpenCVノードが実行できないみたいです。

# OpenCV ノードの代替ノード作成
動かないなら作ればいいじゃない！の精神で、代替ノードを作成します。

## 参考記事
https://qiita.com/NWLab/items/0b7769a1289994dc53cf

## swap領域の拡張
初めに Swap領域のサイズを拡張しておきます。拡張しておかないと、途中でメモリエラーになります。
```
sudo vi /etc/dphys-swapfile
```

### 変更箇所
「CONF_SWAPSIZE=100」を「CONF_SWAPSIZE=2048」に変更して保存します。
設定を変更したら、 TJbot zero を再起動します。

## cmake インストール
OpenCV のモジュールをビルドするために`cmake`をインストールします。
```
sudo apt install cmake
```

## OpenCV ダウンロードとビルド準備
参考記事にならって、`OpenCV-4.5.3` をダウンロードします。もっと新しいバージョンがリリースされていますが、ビルドエラーになったので`先達はあらまほしき事なり`です。

```
wget https://github.com/opencv/opencv/archive/refs/tags/4.5.3.tar.gz
tar -xf 4.5.3.tar.gz
cd  opencv-4.5.3
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local
```

## OpenCV のビルドとインストール
実際にライブラリをビルドしていきます。TJBot zero(RaspberryPI Zero) の環境では、ビルドが完了するまでに`20時間以上`かかります。

```
make
sudo make install
```

## opencv4nodejs のインストール
Node-RED から OpenCV を利用するために Node.js のパッケージをインストールします。

### カレントディレクトの移動
これ以降の作業は下記ディレクトリで行います
```
cd ~/.node-red
```

### nan (2.18.0)
opencv4nodejs のライブラリをビルドするためにインストールします。このパッケージをインストールしないと、途中でビルドエラーになります。

```
npm install --save nan
```

### opencv4nodejs のインストール
opencv4nodejs パッケージの本体をインストールします。インストールスクリプトに自動ビルド処理が記載されていますがエラーになってしまうようなので、自動ビルドを実行しないように設定します。 

```
export OPENCV4NODEJS_DISABLE_AUTOBUILD=1
npm install --save opencv4nodejs
```

### opencv4nodejs のライブラリをリビルド

```
cd node_modules\opencv4noejs\build
export OPENCV_LIB_DIR=/usr/local/lib
make
```

## Node-RED で function node 定義
[Node-RedでOpenCVするまでのメモ](https://qiita.com/NWLab/items/0b7769a1289994dc53cf#%E8%A8%AD%E5%AE%9A) を参考に、`opencv4nodejs`をNode-RED で利用できるように設定します。

Node-RED 再起動後ブラウザで Node-RED エディタにアクセスし、もともと `opencv node` が配置されていた場所に `function node` を配置し、フローの接続を切り替えておきます。

そして、以下のスクリプトを貼り付けます。

```
function detectFace(img)
{
    const classifier = new cv.CascadeClassifier(cv.HAAR_FRONTALFACE_ALT2);

    const options = {
        minSize : new cv.Size(img.width,img.height),
        scaleFactor : 1.2,
        minNeighbors : 10,
    };
    const {
        objects,
        map
    } = classifier.detectMultiScale(
        img,
        options,
    );

    return objects.map(rect => (
        {
            rect,
            face : img.getRegion(rect).copy(),
        }
    ));
}

var image = cv.imdecode(msg.payload);
const ret = detectFace(image);
msg.payload = ret;
return msg;
```

## デプロイすると...
いままでの手順が正しく進んでいた場合、デプロイが完了すると TJBot zero のカメラに人が映り込むと、手を振って挨拶してくれるはずです💞

(後ほど、各種スクショを貼り付け予定)