こんにちはジョージです。Create ML で作成したアクション分類器(アクションクラシファイア)を題材としたウェブセミナーの準備を進めているのですが、Create ML が「訓練データが足りねえ、何でもイイ、.mp4 ジャンジャン持ってこい!」とおっしゃているので、じゃんじゃん作ります。
アクション分類器
アクション分類器とは、カメラや映像内の人物の体の動きを識別する機械学習モデルです。カスタムアクション分類器をアプリケーションに統合すると、動画やカメラ内の動きをリアルタイムに認識、理解することができます。アクション分類器については以下の記事が参考になりますので興味のある方はアクセスしてみてください、本ブログでは訓練データを大量につくる方法について解説します。
https://developer.apple.com/jp/videos/play/wwdc2020/10043
さて、Create ML アクション分類器に必要な映像ファイルは iPhone や PC 内臓カメラで動画を撮影すればよいだけなのですが、とにかく大量に映像ファイルが必要になります。識別したいアクションの数にもよりますが、目安としては 1 アクション分類器の作成に対して 150 〜 250 ファイル以上、1 アクション最低 50 ファイルを準備することが理想とされています。
映像クリップに対して、以下のような JSON 形式のアノテーション (annotation) ファイルを準備する方法もあるようですが、正直面倒くさいです。
[
{
"video" : "lunge23.mov",
"label" : "Lunge",
"start" : 0,
"end" : 3.1
},
{
"video" : "squats_13.mov",
"label" : "Squat",
"start" : 0,
"end" : 5
},
{
"video" : "Jumping Jacks 1.mov",
"label" : " Jumping Jacks",
"start" : 0,
"end" : 4.7
}
]
https://developer.apple.com/documentation/createml/building-an-action-classifier-data-source
そこで発想を転換して、あらかじめテンポを決めて撮影し問答無用で切り刻む方法を紹介します。
映像クリップの尺(継続時間)とテンポ
Create ML に必要な映像クリップの尺(継続時間)は、識別したいアクションの複雑さで変わります。ジャンピングジャックやランジといったエクササイズであれば 2 秒もあれば充分でしょう。そこで撮影を開始する前に正確なテンポをアプリケーション GarageBand で準備します。
まずは、新規プロジェクトを作成してテンポを 60 に合わせます、このテンポでメトロノームを有効にすると 1 秒に一回音がなります。このテンポにあわせて識別したいアクションの尺(継続時間)に収まるように動作をおこない撮影をします。
映像の頭出し
メトロノーム付きでアクションの撮影をしたら、録画した映像の頭出しをします。作業は iMovie でおこないます。
まずは音声波形を見やすいようにしたいので、オーディオを切り離します。
メトロノームの波形が最大になるところでクリップを分割します。先頭の映像は不要なので削除します。
これで正しいテンポでアクションさえしていれば、以降の映像クリップは Crete ML で必要な尺(継続時間)で分割していくだけで、訓練データの大量生産が可能ということになります。
映像ファイルの分割
映像ファイルの分割は ffmpeg で行います。ffmpeg は python で制御します。ChatGPT を使えば一瞬で開発できます。「ffmpeg で sample.mp4 を 3 秒(指定秒数)で分割するスクリプトを python で考えて!」いい時代です。できあがったスクリプトを少し改造して扱いやすいようにします。最終的に以下のスクリプトが完成しました。
import subprocess
import os
import argparse
# コマンドライン引数を解析
parser = argparse.ArgumentParser(description="FFmpegを使用して動画を N 秒ごとに分割")
parser.add_argument("input_file", help="入力動画ファイル")
parser.add_argument("segment_time", type=int, nargs="?", default=5, help="分割する秒数(整数、デフォルト: 5)")
args = parser.parse_args()
# 分割秒数
segment_time = str(args.segment_time) # str に変換
# 入力ファイル
input_file = args.input_file # 引数から取得
# 拡張子を除いたファイル名を取得
base_name, ext = os.path.splitext(input_file) # ('JumpingJack#1', '.mov')
# 出力ファイルのパターン(拡張子無しのファイル名+連番)
output_pattern = f"{base_name}_%03d{ext}"
# 出力ディレクトリを作成(存在しない場合)
output_dir = "split_videos"
os.makedirs(output_dir, exist_ok=True)
# ffmpeg コマンド
command = [
"ffmpeg",
"-i", input_file, # 入力ファイル
"-c", "copy", # エンコードせずコピー
"-map", "0", # すべてのストリームを保持
"-segment_time", segment_time, # N 秒ごとに分割
"-f", "segment", # セグメント出力フォーマット
"-reset_timestamps", "1", # 各セグメントのタイムスタンプをリセット
os.path.join(output_dir, output_pattern)
]
# 実行
subprocess.run(command, check=True)
print(f"動画を{segment_time}秒ごとに分割しました。また、つまらぬ物を斬ってしまった。。。")
実行します。「また、つまらぬ物を斬ってしまった。。。」と声がきこえてきそうです。
直接アクションに関係のない映像(休憩や撮影終了時)は、陰性クラス「Other(その他)」に使って有効利用します。
ファイル名が気になる場合は、連番にしておきます。これで訓練データの作成完了です。
Create ML で アクション分類器の作成
訓練データが準備できたので、手順に沿って Create ML のプロジェクトを作成します。
訓練データを設定します。中身を確認したら訓練開始です。* 訓練データのファイル数が全然たりてませんが、本ブログ記事の方法で大量に作成可能です。Create ML の使い方は、冒頭で紹介した WWDC 2020 の記事を参照してみてください。
アクション分類器が完成したら、ライブカメラや手元の映像ファイルで検証します。問題なければ .mlmodel ファイルを書き出します。あとは完成したアクション分類器を自分のアプリケーションに組み込むだけです。
まとめ
今回は Create ML で必要になる訓練データの大量生産の方法を考えてみました。完成したアクション分類器をどうやってカスタム App に組み込むかは、来月に Web セミナーでご紹介させて頂きますのでお楽しみに!
https://content.claris.com/ja/webinar-250314