パリオリンピックに備えてブレイクダンスの練習風景をピクトグラム化してみた

朝はトラックスで起きるべし
2021.07.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

CX事業本部@大阪の岩田です。先日社内の雑談チャンネルでこんなツイートが共有されました。

ツイートを見に行くと、なんとご丁寧にGitHubでソースコードを公開してくれていました。

https://github.com/Kazuhito00/Tokyo2020-Pictogram-using-MediaPipe

こ、これはパリオリンピックの種目にブレイクダンスが追加されるのに備えて、ブレイクダンスのピクトグラムを作るしかない!!と思い立ってやってみました。

環境

今回利用した環境です

  • OS : Mac OS X 10.15
  • Python: 3.7.8
  • opencv-python : 4.5.2.54
  • numpy : 1.21.1
  • mediapipe : 0.8.6.2
  • Tokyo2020-Pictogram-using-MediaPipe : コミットハッシュ 2c3e713def3d8b6d4450fab61180cf7ea7787c46

やってみる(カメラ編)

さっそくやってみます。まずはGitHubのリポジトリをクローンします。

$ git clone https://github.com/Kazuhito00/Tokyo2020-Pictogram-using-MediaPipe.git
$ cd Tokyo2020-Pictogram-using-MediaPipe

Pythonの仮想環境を作成し、必要なライブラリをインストールします

$ python -m venv .venv
$ source .venv/bin/activate
$ pip install mediapipe opencv-python

これで準備完了なのですが、私の環境だとGitHubのコードそのままでは正常動作しませんでした。VideoCaptureの幅と高さを以下のように調整しました。

-    parser.add_argument("--width", help='cap width', type=int, default=640)
-    parser.add_argument("--height", help='cap height', type=int, default=360)
+    parser.add_argument("--width", help='cap width', type=int, default=960)
+    parser.add_argument("--height", help='cap height', type=int, default=540)

これで準備完了したので、プログラムを起動します。

$ python main.py

こんな感じでカメラが認識した画像をピクトグラム化してくれます。

ここからが本番です。カメラに向かってピクトグラム化したら「映え」そうな技を練習します。今回は片肘で逆立ちしながらピョンピョン跳ねる「肘ステッピン」をやってみました。もし実際に試される場合は、肘を痛めないように肘パットを着けることをオススメします。

さて、コロナの影響で全く練習できていなかったので数ヶ月ぶりの挑戦です。体は動いてくれるのでしょうか

ダメでした。加齢による退化に加えて練習不足も重なり、すぐに潰れてしまいました。とはいえ10回ぐらいはピョンピョンしているので、ブレイクダンスをピクトグラム化するとどうなるかのイメージは掴めたのではないでしょうか?

やってみる(動画編)

体が動かないので、カメラを回しながらリアルタイムでピクトグラム化するのを諦め、プログラムに動画を読み込ませてピクトグラム化してみます。クローンしたプログラムを以下のように修正し、コマンドライン引数で渡された動画ファイルをピクトグラム化するように作り変えます。ついでに動画を反転させるロジックも消しておきます。

-    parser.add_argument("--device", type=int, default=0)
+    parser.add_argument('--file', type=str, required=True, help="video file path")
     parser.add_argument("--width", help='cap width', type=int, default=960)
     parser.add_argument("--height", help='cap height', type=int, default=540)

@@ -43,7 +43,7 @@ def main():
     # 引数解析 #################################################################
     args = get_args()

-    cap_device = args.device
+    cap_file = args.file
     cap_width = args.width
     cap_height = args.height

@@ -55,7 +55,7 @@ def main():
     rev_color = args.rev_color

     # カメラ準備 ###############################################################
-    cap = cv.VideoCapture(cap_device)
+    cap = cv.VideoCapture(cap_file)
     cap.set(cv.CAP_PROP_FRAME_WIDTH, cap_width)
     cap.set(cv.CAP_PROP_FRAME_HEIGHT, cap_height)

@@ -86,7 +86,7 @@ def main():
         ret, image = cap.read()
         if not ret:
             break
-        image = cv.flip(image, 1)  # ミラー表示
+        #image = cv.flip(image, 1)  # ミラー表示
         debug_image01 = copy.deepcopy(image)
         debug_image02 = np.zeros((image.shape[0], image.shape[1], 3), np.uint8)
         cv.rectangle(debug_image02, (0, 0), (image.shape[1], image.shape[0]),

適当な動画をチョイスして実行してみましょう

$ python main.py --file <適当な動画ファイル>

いい感じですね。

やってみる(ピクトグラム動画保存編)

せっかくなのでピクトグラム化した動画を別途mp4ファイルとして保存するロジックを追加しましょう。こんな感じでコマンドライン引数で渡された動画ファイルを読み込む際の初回ループ時に、<UTCのタイムスタンプ>-pictgram-output.mp4というファイル名で動画ファイルを作成し、ループ毎にピクトグラム化した画像を書き出す処理を追加しました。

 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 import copy
+from datetime import datetime
 import math
 import argparse

@@ -79,6 +80,8 @@ def main():
         color = (100, 33, 3)
         bg_color = (255, 255, 255)

+    is_first = True
+    output_video = None
     while True:
         display_fps = cvFpsCalc.get()

@@ -86,6 +89,7 @@ def main():
         ret, image = cap.read()
         if not ret:
             break
+
         #image = cv.flip(image, 1)  # ミラー表示
         debug_image01 = copy.deepcopy(image)
         debug_image02 = np.zeros((image.shape[0], image.shape[1], 3), np.uint8)
@@ -125,7 +129,18 @@ def main():
         cv.imshow('Tokyo2020 Debug', debug_image01)
         cv.imshow('Tokyo2020 Pictogram', debug_image02)

+        if is_first:
+            fmt = cv.VideoWriter_fourcc('m', 'p', '4', 'v')
+            fps = cap.get(cv.CAP_PROP_FPS)
+            now = datetime.now().strftime('%Y-%m-%d-%H%M%S')
+            output_video = cv.VideoWriter(f'{now}-pictgram-output.mp4', fmt, fps, (debug_image02.shape[1], debug_image02.shape[0]))
+            is_first = False
+
+        output_video.write(debug_image02)
+
     cap.release()
+    if output_video:
+        output_video.release()
     cv.destroyAllWindows()

この状態で再度プログラムを実行すると、ピクトグラム化した動画が出力できます。 最終的に出力された動画をいくつかつなぎ合わせた動画がこちらです。

まとめ

GitHubのプログラムをクローンしてちょっと修正しただけで色々遊べました。素材に使えそうな動画をあまり持っていなかったことが悔やまれます。若い頃にもっと動画撮っとけば良かったです。