Anacondaでtf-pose-estimation(openpose)を動した話 on Windows10

#背景
cpuしかないへっぽこPCで姿勢推定のプログラムを動かしたい！できればTensorflowとか今どきのやつを使いたい！と思いました。

[OpenPose](https://github.com/CMU-Perceptual-Computing-Lab/openpose)という姿勢推定のプロジェクトがあります。(Windowsで動かすだけならbatファイルを実行すればいいだけなので楽です。)

[tensorflowを使ったCPUで動かせる軽量版のOpenPose](https://github.com/ildoonet/tf-pose-estimation)があります。

[Windows10で動かしてみた](https://qiita.com/kayu0516/items/754c6719fb55d2a6d563)記事があります。

上記の記事を参考にしたが、わりと躓いたので、すべての記憶を失っているであろう未来の僕に対して記録を残す。
(本当はDockerとか使ってみたかったけど、僕には早かった。)

ちなみに、GoogleColabで用意してくれている方もいるので、Colabを使いたいという方は[こちら](https://colab.research.google.com/drive/1VO4TGJHKXnRKgiSAsNEeQcEHRgzUFFv9)を使うといいと思います。とても楽ちんです。
tensorflowのバージョンだけ1.15に変更にすれば私は動かせました。

# 環境
OS:Windows 10 
実行環境：conda 4.8.2　
Anaconda Poweshell Prompt

# 躓きポイント
基本は[Windowsで姿勢推定(tf pose estimation)](https://qiita.com/kayu0516/items/754c6719fb55d2a6d563)の手順通りやっていくので、躓いたら今回の記事を参考にするとよいでしょう。

##1. ライブラリはどうやってインストールするの？？？
Anacondaで仮想環境を作ってから、ライブラリをcondaでインストールする。

```AnacondaPowershellPrompt
conda install cython=0.29.13
conda install numpy=1.16.4
conda install git=2.20.1
conda install swig=3.0.12
conda install opencv=3.3.1
conda install tensorflow=1.14.0
```
tensorflowはCPU版を使うので、tensorflow-gpuではなくtensorflowだけ。
tf-pose-estimationはtensorflowのバージョンにも結構影響されるので、たぶんtensorflowのバージョン2.0だと動かない。

インストールの仕方でcondaとpipを混同すると環境が壊される可能性があるので注意。
次項でpipするけど今回は大丈夫そう。ほかのアプリケーション用に別のライブラリ入れる場合はcondaにするように注意して。

##2. bash download.sh でエラーがでる！！
bash download.sh でエラーがでるが、ここの手順は無視しても姿勢推定の実行はできるので、無視する。
実行時にモデルを指定するが、cmuというのを使わなければ問題ナシ！
ちなみに、bashが無いといわれる場合はWindows Subsystem for Linuxを[インストール](https://qiita.com/Aruneko/items/c79810b0b015bebf30bb)する。
なお、bashが使えるようになってもdownload.shに不正な文字がありますみたいエラーを言われるので、結局無理でした。.

追記) GitBashで実行できました

##3. 試しに実行させたらなんかエラーでたけど！？！？

```
python run.py --model=mobilenet_thin --image=./images/p1.jpg
```
試しに実行させると記事通りtensorRTのエラーがでるので下記をコメントアウト
tf_pose/estimator.py
- 14行目　import文
- 315行目~328行目　if文

##4. エラーは出なくなったけど、何も表示されないよっ！！！
手順通りpython run.py ~~~ を実行してもエラーは出ないが、何も表示されない。

matplotlibがちゃんと動かず、実行してもなにも表示されていないぽいので、run.pyの56~57行目(import matplotlib.pyplot as pltの上あたり)に下記を追加する。
AggだとダメでTkAggならいけるらしいけどよく分かりません。

```run.py
...
import matplotlib
matplotlib.use('TkAgg')
...
```

##5. 実行結果はどこに出力されたの！？
出ないので、画像を保存するようにrun.pyに記述する。

>run.py 54行目imageがデータですのでcv2.imwrite(出力名.jpg, image)で保存できます。

とあるので55行目に

```run.py
...
cv2.imwrite('test.jpg', image)
...

```
を追加して実行するとルートにtest.jpgができる。

##6. 横向きの人の画像を試したらちゃんと姿勢推定出来てないんなんだけど？？
自転車に乗っている人のように横向きの人写真は変な感じになってしまうが、本家のREADMEと同じように--resize=432x368を入れればおK。

```
$ python run.py --model=mobilenet_thin --resize=432x368 --image=./images/p1.jpg
```

##7. 動画とかWebカメラは？？
そちらは、スコープ外です。

##8. OpenPoseみたいにjsonに書き出せないの？
tf-pose-estimation単体ではないようなので下記を参考にプログラムを書き換えよう。

[MMD自動トレースで OpenPose の代わりに tf‐pose‐estimation を使う](https://github.com/errno-mmd/tf-pose-estimation/wiki/MMD%E8%87%AA%E5%8B%95%E3%83%88%E3%83%AC%E3%83%BC%E3%82%B9%E3%81%A7-OpenPose-%E3%81%AE%E4%BB%A3%E3%82%8F%E3%82%8A%E3%81%AB-tf%E2%80%90pose%E2%80%90estimation-%E3%82%92%E4%BD%BF%E3%81%86)

具体的には、tf_pose/estimaotr.pyのdraw_humansメソッドに、座標データ、信頼性データを入れる配列flatを作って、dcというキーバリュー型のリストに追加しているようですね。最後に、json書き出しの処理を書く。import os とjsonも忘れずに
また、run.pyの方もそれに対応して、書き換える。

```tf_pose/estimaotr.py

...
import json
import os
...

    @staticmethod
    def draw_humans(npimg, humans, imgcopy=False,frame=0, output_json_dir=None): #引数追加
        if imgcopy:
            npimg = np.copy(npimg)
        image_h, image_w = npimg.shape[:2]
        centers = {}
        #json用のリスト追加
        dc = {"version":1.2, "people":[], "face_keypoints_2d":[], "hand_left_keypoints_2d":[],
              "hand_right_keypoints_2d":[], "pose_keypoints_3d":[], "face_keypoints_3d":[],
              "hand_left_keypoints_3d":[], "hand_right_keypoints_3d":[]}
        for human in humans:
            flat = [0.0 for i in range(54)]
            # draw point
            for i in range(common.CocoPart.Background.value):
                if i not in human.body_parts.keys():
                    continue

                body_part = human.body_parts[i]
                center = (int(body_part.x * image_w + 0.5), int(body_part.y * image_h + 0.5))
                centers[i] = center
                #flatにx座標、y座標、信頼度を追加
                #add x
                flat[i*3] = body_part.x * image_w
                #add y
                flat[i*3+1] = body_part.y * image_h
                #add score
                flat[i*3+2] = body_part.score

                cv2.circle(npimg, center, 3, common.CocoColors[i], thickness=3, lineType=8, shift=0)

            # draw line
            for pair_order, pair in enumerate(common.CocoPairsRender):
                if pair[0] not in human.body_parts.keys() or pair[1] not in human.body_parts.keys():
                    continue

                # npimg = cv2.line(npimg, centers[pair[0]], centers[pair[1]], common.CocoColors[pair_order], 3)
                cv2.line(npimg, centers[pair[0]], centers[pair[1]], common.CocoColors[pair_order], 3)
            
            #dcリストに追加
            dc["people"].append({"pose_keypoints_2d" : flat})

        #jsonに書き出し
        if output_json_dir:
            with open(os.path.join(output_json_dir, '{0}_keypoints.json'.format(str(frame).zfill(12))), 'w') as outfile:
                json.dump(dc, outfile)

        return npimg
...
```

```run.py
...
    parser.add_argument('--resize-out-ratio', type=float, default=4.0,
                        help='if provided, resize heatmaps before they are post-processed. default=1.0')
    parser.add_argument('--output_json', type=str, default='/tmp/', help='writing output json dir') #追加

    args = parser.parse_args()

    w, h = model_wh(args.resize)
...
image = TfPoseEstimator.draw_humans(image, humans, imgcopy=False, frame=0, output_json_dir=args.output_json) #draw_humansに渡す引数を追加
...
```


#あとがき
仮想環境作って環境をいくらでもぶち壊せるのは楽だなぁ！！！
でもWindowsだといろいろエラーがでてうざいなぁ！！やっぱMacか！？