video-processing について
OpenCVなどのコンピュータービジョンライブラリを使った動画処理と分析の手引きを提供するスキルです。まずフレームとメタデータを確認し、その後イベント検出や動作追跡のロジックを作成して検証します。
主な機能
- 01サンプルフレームとメタデータの確認
- 02イベント検出ワークフローの構築
- 03フレーム差分と輪郭検出の利用
- 04時間経過に沿った物体位置の追跡
- 05時間の妥当性と複数動画での検証
活用シーン
- 01動画内のイベント検出を調査
- 02動作追跡ロジックを開発
- 03既知のフレームと検出結果を照合
- 04不安定な動画分析をデバッグ
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ letta-ai/ skills --skill video-processingインストール後、Claude Code で/video-processingを入力して読み込まれたか確認します。
詳細
動画処理
概要
このスキルでは、OpenCV などのコンピュータービジョンライブラリを使用した、フレーム単位の分析、イベント検出、動作追跡などの動画処理タスクについて説明します。検証を優先するアプローチを重視し、動画分析のワークフローでよくある落とし穴を防ぎます。
基本方針:実装前に検証する
検出アルゴリズムを書く前に、動画の内容を正しく把握します。
- サンプルフレームを抽出して確認する - 重要なフレームを画像として保存し、特定のフレーム番号で何が起きているかを目視で確認します
- 動画のメタデータを把握する - フレーム数、FPS、再生時間、解像度
- 想定されるイベントをフレーム範囲に対応付ける - テストデータがある場合は、どのイベントがどのフレームに対応するかを把握します
- まず診断ツールを作成する - フレーム抽出や可視化のユーティリティは、重要な知見をもたらします
イベント検出タスクのワークフロー
フェーズ 1:動画の調査
# Essential first steps for any video analysis task
import cv2
cap = cv2.VideoCapture(video_path)
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = cap.get(cv2.CAP_PROP_FPS)
duration = frame_count / fps
print(f"Frames: {frame_count}, FPS: {fps}, Duration: {duration:.2f}s")
重要:想定されるイベントの位置でフレームを抽出し、理解が正しいか確認します。
def save_frame(video_path, frame_num, output_path):
cap = cv2.VideoCapture(video_path)
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_num)
ret, frame = cap.read()
if ret:
cv2.imwrite(output_path, frame)
cap.release()
# Save frames at expected event times for visual inspection
save_frame("video.mp4", 50, "frame_050.png")
save_frame("video.mp4", 60, "frame_060.png")
フェーズ 2:アルゴリズムの開発
検出アルゴリズムを開発する際は、次の点に留意してください。
- シンプルな方法から始める - 複雑な方法を使う前に、基本的なフレーム差分やしきい値処理を試します
- しきい値を設定可能にする - 根拠のないマジックナンバーをハードコードせず、データからしきい値を導き出します
- 既知のフレームでまずテストする - 正解データが既知のフレームで、アルゴリズムが期待どおりの結果を出すことを確認します
- 中間値をログに記録する - 各フレームの指標を追跡し、アルゴリズムの動作を把握します
フェーズ 3:検証
最終決定する前に、次の点を確認してください。
- 出力を健全性チェックする - 検出されたイベントの順序やタイミングは妥当ですか?
- 複数の動画でテストする - 入力が異なっても汎用性があることを確認します
- 想定される範囲と比較する - 正解データがある場合は、検出精度を確認します
よく使われる検出方法
フレーム差分
参照フレーム(最初のフレームまたは前のフレーム)と比較し、動きを検出します。
# Background subtraction approach
first_frame = cv2.cvtColor(first_frame, cv2.COLOR_BGR2GRAY)
first_frame = cv2.GaussianBlur(first_frame, (21, 21), 0)
# For each subsequent frame
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
diff = cv2.absdiff(first_frame, gray)
落とし穴:シーンが変わったりカメラが動いたりする場合、最初のフレームが適切な参照フレームとは限りません。
輪郭ベースの検出
しきい値処理した画像から輪郭を見つけ、オブジェクトを特定します。
_, thresh = cv2.threshold(diff, 25, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
落とし穴:しきい値(例:25)や輪郭の最小面積は、調整を行わなければ根拠のない値です。
時間経過に伴う位置の追跡
ジャンプやジェスチャーなどのイベントを検出する場合は、フレーム間でオブジェクトの位置を追跡します。
positions = [] # (frame_num, x, y, area) tuples
for frame_num in range(frame_count):
# ... detection code ...
if detected:
positions.append((frame_num, cx, cy, area))
落とし穴:座標系は重要です。画像座標では Y が下方向に増加するため、「フレーム内で高い位置」は Y 値が小さいことを意味します。
検証方法
1. 目視確認
検出されたイベントの時点でフレームを保存し、正しいか確認します。
# After detecting takeoff at frame N
save_frame(video_path, detected_takeoff, "detected_takeoff.png")
save_frame(video_path, detected_takeoff - 5, "before_takeoff.png")
save_frame(video_path, detected_takeoff + 5, "after_takeoff.png")
2. タイミングの妥当性
検出されたイベントの時間的な整合性を確認します。
duration_seconds = frame_count / fps
event_time = detected_frame / fps
# Example: A jump in a 4-second video shouldn't be detected in the last 0.5 seconds
if event_time > duration_seconds - 0.5:
print("WARNING: Event detected very late in video - verify correctness")
3. シーケンスの検証
イベントが論理的な順序で発生していることを確認します。
if detected_landing <= detected_takeoff:
print("ERROR: Landing cannot occur before or at takeoff")
4. 複数動画でのテスト
単一の動画の特徴に過剰適合していないか早期に確認するため、複数の入力でテストします。
よくある落とし穴
1. 正解データによる検証がない
問題:目視で確認せず、計算された指標だけに全面的に依存しています。
解決策:検出されたイベントの位置で必ずフレームを保存し、確認します。
2. データ解釈における確証バイアス
問題:データに想定外のパターンが現れたとき、前提を疑うのではなく、先入観に合う説明を作り出してしまいます。
解決策:検出結果が間違っているように見える場合、想定外の挙動を正当化するのではなく、根本原因を調査します。
3. マジックナンバーによるしきい値
問題:実測に基づかず、任意のしきい値(輪郭面積に 500、二値化のしきい値に 25 など)を使用しています。
解決策:実際の動画データからしきい値を導き出すか、妥当なデフォルト値を設定したうえで変更可能にします。
4. 検出の欠落を無視する
問題:ある範囲のフレームで検出に失敗したとき、調査せずに想定どおりの挙動だと判断します。
解決策:検出に失敗する理由を調査します。想定どおりの挙動ではなく、アルゴリズムの欠陥を示している可能性があります。
5. 座標系の混同
問題:Y 座標を誤って解釈しています(画像座標では、Y が小さいほどフレーム内で上になります)。
解決策:座標系の前提を明確に記述し、目視で確認します。
6. タイミングの妥当性を無視する
問題:時間的に不自然な検出結果を受け入れています(例:4 秒の動画の最後の 0.8 秒でイベントが検出される)。
解決策:出力タイミングの妥当性チェックを実装します。
7. 単一動画への過剰適合
問題:ある動画ではアルゴリズムが機能しても、ほかの動画では失敗します。
解決策:開発の早い段階で複数の動画を使ってテストします。
出力形式に関する考慮事項
結果を出力する場合(例:TOML、JSON):
import numpy as np
# Convert numpy types to Python native types for serialization
result = {
"takeoff_frame": int(takeoff_frame), # Not np.int64
"landing_frame": int(landing_frame),
}
デバッグチェックリスト
検出結果が正しくない場合:
- 想定されるイベント時刻のフレームを目視で確認しましたか?
- 検出されたイベント時刻のフレームを目視で確認しましたか?
- 動画の長さを踏まえて、検出された時刻は時間的に妥当ですか?
- 正解データが既知のフレームでアルゴリズムを検証しましたか?
- 座標系を正しく解釈していますか?
- 複数の動画でテストしましたか?
- しきい値はデータに基づいていますか、それとも恣意的に設定されていますか?
- 一部のフレームで検出に失敗した場合、その理由を理解していますか?