TimeSformer による人物動作認識(ソースコードと説明と利用ガイド)
プログラム利用ガイド
1. このプログラムの利用シーン
動画に映る人物の動作をリアルタイムで認識し分類するためのソフトウェアである。スポーツ動作の分析、監視システムでの行動検出、動画コンテンツの自動タグ付け、人間の行動研究等の用途に適用できる。400種類の動作クラスに対応し、楽器演奏や握手等の多様な人物動作を認識する。
2. 主な機能
- リアルタイム動作認識:動画再生と同時に人物動作を分析し、結果を画面に表示する
- 多様な入力対応:動画ファイル、ウェブカメラ、サンプル動画の3つの入力モードを選択可能
- 信頼度表示:認識結果の上位5クラスを信頼度とともに表示し、予測精度を把握できる
- 動作継続時間追跡:同一動作の継続時間を測定し、動作の持続性を分析する
- 結果保存機能:全ての認識結果をテキストファイル(result.txt)に自動保存する
- フレーム数設定:8フレームまたは16フレームの処理単位を選択可能(モデル設定に応じて自動調整)
3. 基本的な使い方
- プログラム起動:事前にPyTorchとTransformersライブラリをインストールし、プログラムを実行する
- フレーム数選択:0(8フレーム)または1(16フレーム)を入力してEnterキーを押す
- 入力モード選択:0(動画ファイル)、1(カメラ)、2(サンプル動画)のいずれかを選択する
- 動画処理開始:選択したモードに応じて動画処理が開始され、認識結果が表示される
- プログラム終了:qキーを押してプログラムを終了する
4. 便利な機能
- 処理統計表示:総処理フレーム数、使用デバイス、GPU情報等をファイルに記録する
- 時刻情報付与:カメラ入力時には認識結果に時刻情報を付与し、時系列分析を支援する
Python開発環境,ライブラリ類
ここでは、最低限の事前準備について説明する。機械学習や深層学習を行う場合は、NVIDIA CUDA、Visual Studio、Cursorなどを追加でインストールすると便利である。これらについては別ページ https://www.kkaneko.jp/cc/dev/aiassist.htmlで詳しく解説しているので、必要に応じて参照してください。
Python 3.12 のインストール
インストール済みの場合は実行不要。
管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要である。
REM Python をシステム領域にインストール
winget install --scope machine --id Python.Python.3.12 -e --silent
REM Python のパス設定
set "PYTHON_PATH=C:\Program Files\Python312"
set "PYTHON_SCRIPTS_PATH=C:\Program Files\Python312\Scripts"
echo "%PATH%" | find /i "%PYTHON_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_PATH%" /M >nul
echo "%PATH%" | find /i "%PYTHON_SCRIPTS_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_SCRIPTS_PATH%" /M >nul
【関連する外部ページ】
Python の公式ページ: https://www.python.org/
AI エディタ Windsurf のインストール
Pythonプログラムの編集・実行には、AI エディタの利用を推奨する。ここでは,Windsurfのインストールを説明する。
管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行して、Windsurfをシステム全体にインストールする。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要となる。
winget install --scope machine Codeium.Windsurf -e --silent
【関連する外部ページ】
Windsurf の公式ページ: https://windsurf.com/
必要なライブラリのインストール
コマンドプロンプトを管理者として実行(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する
前準備: pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
pip install transformers opencv-python pillow
人物動作認識プログラム(TimeSformer)
概要
このプログラムは、TimeSformerアーキテクチャを使用した動画からの人物動作認識システムである。動画ファイル、ウェブカメラ、またはサンプル動画から入力を受け取り、リアルタイムで人物の動作を400種類のクラスから分類する。
主要技術
TimeSformer (Time-Space Transformer)
TimeSformerは時空間分離注意機構を採用したTransformerベースの動画理解モデルである[1]。自己注意機構のみで動画分類を行う。空間注意と時間注意を分離して適用することで、動画フレーム間の時間的依存関係を学習する。
Kinetics-400データセット
事前訓練に使用される大規模動作認識データセットである[2]。400の人物動作クラスを含み、各クラスに最低400の動画クリップが含まれる。楽器演奏などの人物-物体間相互作用や握手などの人物間相互作用を幅広くカバーする。
実装の特色
- OpenCVとHuggingFace Transformersライブラリの統合
- フレームバッファ管理によるリアルタイム処理
- 動作継続時間の追跡機能
- Top-5予測結果の信頼度表示
- 処理結果の自動ファイル保存機能
- 3つの入力モード(動画ファイル、カメラ、サンプル動画)への対応
処理方式
入力動画から8フレームまたは16フレームのシーケンスを抽出し、224×224ピクセルにリサイズして正規化を行う。TimeSformerモデルがフレームシーケンスから時空間特徴を抽出し、400クラスの動作分類を実行する。softmax関数により各クラスの確率を算出し、上位5クラスを信頼度とともに出力する。
参考文献
[1] Bertasius, G., Wang, H., & Torresani, L. (2021). Is Space-Time Attention All You Need for Video Understanding? In Proceedings of the International Conference on Machine Learning (ICML), 139, 4102-4112. https://arxiv.org/abs/2102.05095
[2] Kay, W., Carreira, J., Simonyan, K., Zhang, B., Hillier, C., Vijayanarasimhan, S., ... & Zisserman, A. (2017). The Kinetics Human Action Video Dataset. arXiv preprint arXiv:1705.06950. https://arxiv.org/abs/1705.06950
ソースコード
# 人物動作認識プログラム(TimeSformer)
# 特徴技術名: TimeSformer
# 出典: Bertasius, G., Wang, H., & Torresani, L. (2021). Is space-time attention all you need for video understanding? Proceedings of the International Conference on Machine Learning (ICML)
# 特徴機能: 時空間分離注意機構による動作認識。空間注意と時間注意を分離適用し、動画フレーム間の時間的依存関係を効率的に学習してリアルタイム動作認識を実現
# 学習済みモデル: timesformer-base-finetuned-k400。Kinetics-400データセットで事前訓練された400動作クラス認識モデル。HuggingFace transformersライブラリにより自動ダウンロード
# 特徴技術および学習済モデルの利用制限: **Apache-2.0ライセンス(商用利用可能)。Facebook Research開発、HuggingFaceにて配布**
# 方式設計:
# 関連利用技術: OpenCV(動画処理、フレーム取得)、transformers(TimeSformerモデル)、torch(深層学習)、PIL(画像変換)
# 入力と出力: 入力: 動画(ユーザは「0:動画ファイル,1:カメラ,2:サンプル動画」のメニューで選択.0:動画ファイルの場合はtkinterでファイル選択.1の場合はOpenCVでカメラが開く.2の場合はhttps://raw.githubusercontent.com/opencv/opencv/master/samples/data/vtest.aviを使用);出力: OpenCV画面で動画再生、動作認識結果と信頼度をprint()で表示、result.txtファイルに保存
# 処理手順: 1.動画フレーム読み込み→2.フレームバッファ蓄積→3.TimeSformerモデル推論→4.動作クラス分類→5.信頼度算出→6.結果表示
# 前処理、後処理: 前処理:フレームリサイズ(224x224)、正規化、テンソル変換;後処理:softmax確率計算、上位5クラス抽出
# 追加処理: フレームバッファ管理、時間窓スライディング、重複フレーム削除
# 調整を必要とする設定値: フレーム数(8フレームまたは16フレーム選択可能)、信頼度閾値(デフォルト0.1)、フレームスキップ間隔(デフォルト2)
# 算出・計算処理の検証: 動作クラス確率は0-1範囲のsoftmax出力、上位5クラスの信頼度合計が正しく算出
# 将来方策: 複数人物対応、カスタム動作クラス追加、リアルタイム動作セグメンテーション
# その他の重要事項: フレーム蓄積後に推論実行のため初期遅延あり、GPU使用推奨
# 前準備: pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
# pip install transformers opencv-python pillow
import cv2
import torch
import numpy as np
from transformers import TimesformerForVideoClassification, AutoImageProcessor
from PIL import Image
import tkinter as tk
from tkinter import filedialog
import urllib.request
import time
from datetime import datetime
# グローバル変数
frame_count = 0
results_log = []
frame_buffer = []
current_action = None
action_start_time = None
# GPU/CPU自動選択
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f'デバイス: {str(device)}')
try:
print('TimeSformerモデル読み込み中...')
model = TimesformerForVideoClassification.from_pretrained("facebook/timesformer-base-finetuned-k400")
processor = AutoImageProcessor.from_pretrained("facebook/timesformer-base-finetuned-k400")
model.to(device)
model.eval()
print('モデル読み込み完了')
MODEL_NUM_FRAMES = int(getattr(model.config, "num_frames", 8))
print(f'モデル設定のフレーム数: {MODEL_NUM_FRAMES}')
except Exception as e:
print(f'モデル読み込みエラー: {e}')
exit()
def preprocess_frames(video_frames):
# AutoImageProcessorを使用した公式前処理
inputs = processor(images=video_frames, return_tensors="pt")
return inputs.pixel_values
def video_frame_processing(frame):
global frame_count, frame_buffer, current_action, action_start_time, FRAME_COUNT
current_time = time.time()
frame_count += 1
# フレームを224x224にリサイズ
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
pil_frame = Image.fromarray(rgb_frame)
# フレームバッファに追加
frame_buffer.append(pil_frame)
# 設定フレーム数蓄積後に推論実行
if len(frame_buffer) >= FRAME_COUNT:
try:
# 最新フレームを使用
video_frames = frame_buffer[-FRAME_COUNT:]
# AutoImageProcessorを使用した前処理
pixel_values = preprocess_frames(video_frames).to(device)
# 推論実行
with torch.no_grad():
outputs = model(pixel_values=pixel_values)
probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1)
# 上位5クラス取得
top5_prob, top5_indices = torch.topk(probabilities, 5)
# Top-1動作取得
top1_class_idx = top5_indices[0][0].item()
top1_confidence = top5_prob[0][0].item()
top1_action = model.config.id2label[top1_class_idx]
# 動作継続時間管理
if current_action != top1_action:
current_action = top1_action
action_start_time = current_time
duration = 0.0
else:
duration = current_time - action_start_time if action_start_time else 0.0
# 結果整形
predicted_actions = []
for i in range(5):
class_idx = top5_indices[0][i].item()
confidence = top5_prob[0][i].item()
class_name = model.config.id2label[class_idx]
predicted_actions.append(f"{class_name}({confidence:.3f})")
top5_sum = top5_prob[0].sum().item()
sum_ok = (0.0 <= top5_sum <= 1.0 + 1e-6)
result = f"Top5: {', '.join(predicted_actions)} | Top5Sum={top5_sum:.3f} valid={sum_ok}"
# OpenCV画面に表示する情報
display_text = f"{top1_action} ({top1_confidence:.3f}) - {duration:.1f}sec"
except Exception as e:
result = f"推論エラー: {str(e)[:50]}"
display_text = "推論エラー"
# フレームバッファサイズ制限
if len(frame_buffer) > FRAME_COUNT * 2:
frame_buffer = frame_buffer[-FRAME_COUNT:]
else:
result = f"フレーム蓄積中: {len(frame_buffer)}/{FRAME_COUNT}"
display_text = f"Loading... {len(frame_buffer)}/{FRAME_COUNT}"
# OpenCV画面にテキスト表示
display_frame = frame.copy()
cv2.putText(display_frame, display_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
return display_frame, result, current_time
print("人物動作認識プログラム(TimeSformer)")
print("フレーム数を選択してください:")
print("0: 8フレーム")
print("1: 16フレーム")
frame_choice = input("選択: ")
if frame_choice == '1':
requested = 16
else:
requested = 8
# モデル設定に必ず合わせる
FRAME_COUNT = MODEL_NUM_FRAMES
if requested != MODEL_NUM_FRAMES:
print(f"モデル設定に合わせてフレーム数を{MODEL_NUM_FRAMES}に統一します(選択値{requested}は無視)")
else:
print(f"モデル設定と一致: {MODEL_NUM_FRAMES}")
print(f"設定フレーム数: {FRAME_COUNT}")
print("\n動画ソースを選択してください:")
print("0: 動画ファイル")
print("1: カメラ")
print("2: サンプル動画")
choice = input("選択: ")
if choice == '0':
root = tk.Tk()
root.withdraw()
path = filedialog.askopenfilename()
if not path:
exit()
cap = cv2.VideoCapture(path)
elif choice == '1':
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
if not cap.isOpened():
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
else:
# サンプル動画ダウンロード・処理
SAMPLE_URL = 'https://raw.githubusercontent.com/opencv/opencv/master/samples/data/vtest.avi'
SAMPLE_FILE = 'vtest.avi'
try:
urllib.request.urlretrieve(SAMPLE_URL, SAMPLE_FILE)
cap = cv2.VideoCapture(SAMPLE_FILE)
except Exception as e:
print(f'サンプル動画ダウンロードエラー: {e}')
exit()
if not cap.isOpened():
print('動画ファイル・カメラを開けませんでした')
exit()
# メイン処理
print('\n=== 動画処理開始 ===')
print('操作方法:')
print(' q キー: プログラム終了')
try:
while True:
ret, frame = cap.read()
if not ret:
break
MAIN_FUNC_DESC = f"TimeSformer動作認識({FRAME_COUNT}フレーム)"
processed_frame, result, current_time = video_frame_processing(frame)
cv2.imshow(MAIN_FUNC_DESC, processed_frame)
if choice == '1': # カメラの場合
print(datetime.fromtimestamp(current_time).strftime("%Y-%m-%d %H:%M:%S.%f")[:-3], result)
else: # 動画ファイルの場合
print(frame_count, result)
results_log.append(result)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
finally:
print('\n=== プログラム終了 ===')
cap.release()
cv2.destroyAllWindows()
if results_log:
with open('result.txt', 'w', encoding='utf-8') as f:
f.write('=== TimeSformer動作認識結果 ===\n')
f.write(f'処理フレーム数: {frame_count}\n')
f.write(f'使用フレーム数: {FRAME_COUNT}\n')
f.write(f'使用デバイス: {str(device).upper()}\n')
if device.type == 'cuda':
f.write(f'GPU: {torch.cuda.get_device_name(0)}\n')
f.write('\n')
f.write('\n'.join(results_log))
print(f'\n処理結果をresult.txtに保存しました')