alpha-cutout について
alpha-cutout は、被写体を単色の背景プレートで撮影し、フレームごとに背景を除去して透明な動画や画像を作るスキルです。ウェブページに動く被写体を合成する制作者向けで、再生やスクロール連動に使える形式を出力します。
主な機能
- 01キー背景色の選択
- 02フレーム単位の背景除去
- 03スタックMP4、アルファWebM、画像の出力
- 04canvasでのスタックアルファ動画再生
- 05複数背景での切り抜き確認
活用シーン
- 01キャラクターのウェブページへの合成
- 02透明なループ動画素材の作成
- 03スクロール連動アニメーション用フレームの作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ moh4696/ open-3d-skills --skill alpha-cutoutインストール後、Claude Code で/alpha-cutoutを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlassets/alpha-video.jsscripts/key.pyplate.py詳細
アルファ切り抜き
画像から動画を生成するモデルは、アルファチャンネルを返しません。巨大な見出しと太陽の円盤の間に立つキャラクターや、ページ上に浮かぶボトルには、すべてのフレームから背景を取り除く必要があります。どのページの色に重ねても縁が見えないほど、きれいに取り除かなければなりません。このスキルでは、映画スタジオと同じ方法を使います。被写体を単色のキー色の上で撮影し、フレームごとにマットを作成します。
ツール
| ファイル | 機能 |
|---|---|
scripts/plate.py | 切り抜いた被写体を余白のあるキープレートに配置し、被写体との色の衝突が最も少ないキー色を選びます |
scripts/key.py | 動画または静止画を、積み重ね形式の MP4、アルファ付き VP9 WebM、RGBA WebP フレームまたは PNG にキーイングします |
assets/alpha-video.js | 透明度に対応した積み重ねアルファ MP4 をキャンバス(WebGL)上で再生します。スクラブ用の seek() も使えます |
Python 3.9 以降、pip install numpy opencv-python-headless pillow、および PATH 上の ffmpeg が必要です。
パイプライン
-
静止画から被写体を切り抜きます。 背景除去ツールはどれでも使えます。除去されたものを確認してください。空中のボール、ラケットのストリング、髪など、細いものはよく消えてしまいます。手作業で戻してください。
-
プレートを作成します。
python3 scripts/plate.py subject.png plate.png --size 1350x1800 --fit 0.8スクリプトは、マゼンタ、緑、青それぞれについて、被写体のどの程度がそのキー色に近いかを報告し、最もきれいな色を選びます。通常はマゼンタが適しています。肌、衣服、製品、植物に純粋なマゼンタが含まれることはほとんどないためです。緑は植物や緑色の製品でうまくいかず、青はデニムや空でうまくいきません。被写体は意図的に輪郭を硬くして貼り付けます。プレートの色があらかじめ混ざった柔らかい輪郭は、モデルに縁取りを描くよう学習させてしまいます。
動きのための余白を残してください。サーブには頭上の空間が必要です。ターンには横の空間が必要です。何も切り取られないように、プレートのアスペクト比を動画モデルの出力アスペクト比に合わせてください。
-
プレート上で生成します。 プレートを開始フレームとして使います(シームレスなループにする場合は終了フレームとしても使います。
motion-assetsを参照してください)。プロンプトにプレートについて明記してください。そうしないと、モデルが背景を作り出します。背景は、フレーム全体を満たす完全に平坦で均一な純粋なクロマキー・マゼンタ(正確な RGB 255, 0, 255)のままにしてください。影、床、グラデーション、ビネット、風景は入れないでください。カメラは固定してください。
画像よりプロンプトが優先されます。 プロンプトに「白い背景で」という文言が残っていると、プレートが何色であっても白い背景になります。編集するたびに、プロンプトを読み直してください。
-
キーイングします。
python3 scripts/key.py clip.mp4 --png check/ --frame-list 0,40,80,120 # inspect first python3 scripts/key.py clip.mp4 --stacked hero-1080.mp4 --width 1080 python3 scripts/key.py clip.mp4 --stacked hero-720.mp4 --width 720 # phones python3 scripts/key.py clip.mp4 --frames serve/lg --width 960 --start 0 --end 78--pngは、各フレームで測定したプレートの色を出力します。モデルによってプレートの色は変化します。純粋なマゼンタが途中で淡いピンク(250, 178, 243)に変わる一方、被写体の色はそのまま保たれることがあります。そのため、キー色は一度だけ設定するのではなく、各フレームの端からフレームごとに測定します。被写体が上端に触れていると測定が失敗し、スクリプトがそのことを知らせます。次に、ピクセルごとに、ピクセルのキー色の過剰分がプレートのものからどれだけ離れているかを基にアルファを求め、輪郭のピクセルをプレート色に対して混色解除し(
F = (C - (1 - a) K) / a)、残った色かぶりを抑えます。混色解除は重要です。単純なカラーキーや中間色に向けた色の抑制では、マゼンタが混ざった輪郭が黄褐色になり、白いシャツにサーモン色の縁取りがあるように見えます。混色解除すれば、本来の輪郭の色に戻ります。 -
3種類の背景で確認します。 ほぼ黒、ページの明るい色、そして最も目立つブランドカラーに重ねます。
--pngの出力を合成し、100%と400%の表示倍率で輪郭を確認してください。髪、指、細い小道具、モーションブラー、プレートの色が最も変化したフレームを重点的に確認してください。
修正
| 症状 | 対処 |
|---|---|
| 被写体に沿った細い輪郭線が見える | --erode 1(まれに 2)を指定します。モデルがフリンジをアートワークにコピーしています |
| 明るい部分や光沢のある部分に穴が開く | その色がキーに近すぎます。別のキーで再生成します(plate.py --key) |
| 背景全体にピンクや緑の色かぶりがある | プレートのグラデーションが通常より強くなっています。測定したプレートの色を確認し、--solid を少し上げます |
| クリップの途中でディテールの色が変わる(キャップが緑色になるなど) | キーイングの問題ではなく、モデルのドリフトです。その色相を該当フレームで再着色するか、再生成します |
| 圧縮後に被写体の周囲に色の線が出る | 対処済みです。透明ピクセルの下にある色は、被写体自身のエッジカラーを外側に広げたものなので、クロマサブサンプリングで混入する異物はありません。--fill は被写体から離れた部分の色のみを設定します |
出力形式の選択
| 出力 | 再生環境 | 用途 |
|---|---|---|
--stacked MP4 + assets/alpha-video.js | Safari と iOS を含むすべてのブラウザー | ループするヒーロー動画、キャラクターなど、再生するコンテンツ全般 |
--webm VP9 アルファ | Chrome、Edge、Firefox。Safari は非対応 | Safari のサポートが不要な場合の、単純な <video> タグ |
--frames WebP シーケンス | すべての環境 | スクロールに合わせて再生するモーション(scroll-film を参照):シーク時の遅延がなく、スクロール位置ごとに正確なフレームを表示します |
スタック型アルファではフレームの高さが 2 倍になり(上がカラー、下がマット)、シェーダーで合成します。そのため通常の H.264 として扱われ、あらゆる環境でハードウェアデコードでき、カラー映像単体と比べてデータ量は約 1.3 倍です。幅 1080 と 720 の 2 種類を用意し、ビューポートに応じて選択してください。
import { AlphaVideo } from "./alpha-video.js";
const hero = new AlphaVideo(document.querySelector("canvas.hero"), innerWidth > 900 ? "hero-1080.mp4" : "hero-720.mp4");
hero.onready = () => document.body.classList.add("hero-ready");
function frame() { hero.draw(); requestAnimationFrame(frame); }
requestAnimationFrame(frame);
プレーヤーは画面外では自動的に一時停止し、動画が進んだときだけテクスチャをアップロードします。スクラブ再生では、{ loop: false, autoplay: false } を指定して作成し、スクロールハンドラーから hero.seek(seconds) を呼び出してください。
HTTP Range リクエストに応答するサーバーから動画を配信してください(frame-capture スキルの serve.py は対応していますが、python3 -m http.server は対応していません)。そうしないとシークが機能しません。
モーションの低減
prefers-reduced-motion: reduce の場合は、ループ再生の代わりにキー処理済みの静止画を 1 枚表示します(良いフレームを --png で出力し、WebP に変換してください)。