GIF / アニメーション 透明背景切り抜き
収集する入力情報
- ソースファイル:GIF、PNGシーケンス、または動画。動画の場合はffmpegでフレーム抽出(スクリプトに内蔵)
- 確認用背景色:ユーザーはどのような背景でこの画像を見ていますか? 暗いUIか白いページかで、残渣の見え方がまったく異なります。 不明な場合はデフォルトで全背景色の確認を行います(スクリプトに内蔵)。省略しないでください。
- 被写体に背景色に近い淡色パーツ(白手袋、白ブーツ、白い端など)が含まれていますか? これは能力の限界です。下記「可解性判断」を参照してください。
先に可解性判断を行う(このステップをスキップすると数十分無駄になることがあります)
切り抜きは情報復元の問題であり、アルゴリズムのチューニング問題ではありません。被写体の淡色パーツと背景の色が近い場合、後処理でそれらを分離することは不可能です——色度、平滑度、時間中央値、背景曲面フィッティングのすべてが被写体を傷つけます。
目視で色を推定せず、以下を実行してください:
.venv-bg\Scripts\python scripts\cutout.py --input <ソースファイル> --work work --stage solvability
これは「カメラ静止+被写体が動く」という前提で背景板と被写体を分離し、3つの数値を出力します:
- 背景板の中央色 / 被写体の最も明るい色調 / 両者の差
- 背景色の±25/255以内に収まる被写体ピクセルの割合 —— この数値が最も解釈しやすい
このロボット素材で実測した結果:背景 (212,207,210)、被写体の最も明るい部分 (250,251,250)、差 40.7、
しかし被写体ピクセルの32.6%が背景色の25以内に収まっていた → AMBIGUOUS と出力。
AMBIGUOUS が表示されたら、先にユーザーに伝えてください:
この素材は淡色パーツと背景色が非常に近いため、純粋な切り抜きではピクセルレベルのクリーンさは達成できません。せいぜい「拡大すると極細の残渣がある」程度です。 元のプロジェクトファイルがあれば、高彩度の純緑/マゼンタ背景で再レンダリングすれば、完全に残渣なしにできます。 完成ファイルしかない場合は、限りなくクリーンに近づけることしかできません。
その後ユーザーに続行するかどうかを尋ねてください。黙って20分間実行し続けないでください。
注意:このチェックは警告信号であり、決定ではありません。最終的には実行完了後の残渣の定量化を基準にしてください—— 「分離可能」でもモデルのエッジ精度が悪く残渣が出ることがあり、「分離不能」でも実際にはきれいに切り抜けることがあります。
手順
-
ワークスペースを作成し環境をセットアップ
python -m venv .venv-bg && .venv-bg\Scripts\python -m pip install rembg onnxruntime pillow scipy(scipyはrembgの依存チェーンからのもので、ガイド付きフィルタリングに使用します——下記参照) -
パイプラインを実行
.venv-bg\Scripts\python scripts\cutout.py --input <ソースファイル> --outdir out --scale 2--inputは動画ファイル、GIF/PNGファイル、または既にフレーム抽出済みのPNGシーケンスディレクトリを受け付けます。--scale 2は省略不可:手足と胴体の間の隙間はわずか5–15pxであり、720pではセグメンテーションモデルがそれを認識できません。 特定のフレームが頑固な場合は--stage matteでそのフレームだけを再実行し、--scale 3とします。CPUのみで70フレーム720pを2倍スケールで実行する場合、約20分かかります(約17.6秒/フレーム、onnxruntimeはGPU非対応)。 事前にユーザーにこの時間感覚を伝え、処理が止まったと思わせないようにしてください。
-
検収(次のセクション参照)。不合格の場合は、該当ステージを特定して再実行し、全体を再実行しないでください。
-
納品:GIF + WebP + APNGの3形式をすべて提供し、それぞれの適切な使用シーンを説明します。
ハードルール(違反すると多大なコストが発生します)
- トポロジ処理はopeningのみ使用し、closingは絶対に使用しない。
binary_closingは2px以下の背景の隙間を埋め、 腕と胴体の間の狭い隙間を溶接してしまいます。その後どんな処理を施しても修復できません。 実測では、このルールの違反が他のすべての問題を合わせたよりも多くの手戻りを発生させています。 - 穴埋め閾値は小さい値にする(60px程度、数百ではない)。本当の手足の隙間は数千ピクセルあり、ピンホールは数十ピクセルです。
- ガイド付きフィルタの半径は2以下、かつデフォルトでメディアンフィルタは使用しない。3×3のメディアンと半径4のガイド付きフィルタは、数ピクセル幅の隙間を消してしまいます。
- アルファに非線形圧縮を適用しない。以前
clip((clip((a-0.04)/0.92)-0.06)/0.88)のようなマッピングを記述し、 エッジを引き締める意図でしたが、実際には alpha≈0.7 でアルファを引き上げ、結果的に残渣をより濃くしてしまいました。 - GIFには秩序ディザ(Bayer)を使用しない。静止画ではエッジが柔らかくなりますが、その網点が画面座標系に固定されるため、 輪郭が動くと「沸騰」してちらつきます——アニメーションではむしろ悪化します。GIFはクリーンアップ後のハードしきい値とし、 ソフトエッジのアルファはWebP / APNGに任せます。
- モデルはBiRefNetを選択。isnet / u2netは床の鏡面反射を実体として切り抜いてしまいます。
birefnet-general-liteに変更すると、 ブーツ底のアルファが直接ゼロになります。 - 「よりクリーンにする」ために背景色を消去しない。背景曲面/色度基準で広範囲に残渣を消去しようとすると、 被写体の淡色パーツも一緒に消えてしまいます。残渣の正しい解決策はマット解像度を上げることであり、しきい値を変更することではありません。
出力契約
out/<名前>.gif—— 透明インデックス255、transparency=255、disposal=2、1ビットハードエッジ。 トポロジクリーンアップ(孤立点除去)はGIFにのみ適用out/<名前>.webp—— 連続アルファを保持、トポロジクリーンアップは行わないため、柔らかい暖色の毛羽立ちが残ります。 複雑な背景に重ねる場合はこちらを優先してください。この違いは意図的なものであり、バグと誤解しないでください。out/<名前>.png—— APNG、ブラウザ互換性が最も高い- 元のキャンバスサイズ、フレーム数、各フレームの持続時間、ループ設定を保持。応答にはこれらの実測値を記載してください。 (アニメーションWebPのフレームごとの持続時間はPILで読み取れません。その場合は「GIFの実測値を基準とする」と正直に述べ、嘘をつかないでください)
<media>タグでファイルを納品し、GIFとWebPのそれぞれの適切な使用シーンを説明します。
障害対応
- GIFがブラウザで灰色の背景で表示される:最初にファイルを変更しないでください。VP8XのALPHAビットとANIM背景色を確認します
(
verify.pyが表示します)。両方が正常であれば、ビューアが透明領域に背景色を敷いているだけです。verify.pyがANMF ... blend=0と報告した場合、それが本当の問題です——cutout.pyはエクスポート時に自動的にblend=1に変更します。このファイルのblendが0の場合、このスクリプトで生成されたものではないか、外部ツールを経由したものです。 - 被写体が削られている:ほとんどの場合、背景判定基準が広すぎます。
final/レイヤーに戻って再エクスポートし、消去ロジックのパラメータ調整を続けないでください。 - 特定のフレームの隙間が開いていない:
--stage matte --scale 3でそのフレームだけを再実行します。1フレームあたり約20秒です。 - rembgモデルのダウンロードが遅い:rembg 2.xはモデルを
~/.rembg/models/<model>/<model>.onnxに配置します (旧バージョンの~/.u2netではありません)。birefnet-general-liteは約214MBです。初回実行時はダウンロードを待つ必要があります。
検収(このステップは省略不可)
ユーザーが実際に表示する背景色でフレームごとに確認する必要があります。そうしないと確認したことになりません:
.venv-bg\Scripts\python scripts\verify.py out\<名前>.gif --backdrop grey --ref work\final
これにより出力されるもの:孤立点数、フレームごとの不透明ピクセル割合(ちらつきの有無を判断)、最低不透明行、GIFの元マットに対する色量子化誤差、WebPコンテナフラグ。さらに4背景色比較図+全フレーム接触表+指定領域拡大図を生成します。
判定基準:
| 指標 | 合格条件 |
|---|---|
| 孤立点数 | 0 |
| フレームごとの不透明割合の範囲 | < 0.05 |
| 最低不透明行 | 全フレームで一致(反射の残渣があると変動したり画面下部に達したりする) |
| 色量子化平均誤差 | < 3/255(サムネイルでは色相の喪失は見えないため、この数値に依存) |
| 4背景色比較 | 各背景色が透けて見え、一様な薄い灰色がないこと |
| 接触表 | フレームごとに残像、ノイズがなく、手足の隙間が透き通っていること |
単一フレームのみ、または黒背景のみでの目視確認では問題を見逃します——暖色の残渣は暗い灰色の背景に重ねて初めて顕著になります。
Windows (win32) プラットフォーム注意事項
- インタプリタは
pyまたはpythonを使用してください。Windowsではpython3は存在しません。PATH上のpythonは使用しないでください (pipのないhermes venvを指す可能性があります)。venv内の.venv-bg\Scripts\python.exeを優先的に使用してください。 - パスに日本語が含まれる場合、
Write/Readツールを使ってスクリプトファイルを書き込み、Set-Contentで内容を組み立てないでください。 - PILの
ImageFilter.GaussianBlurは mode"F"と float RGB をサポートしていません。浮動小数点画像のぼかしにはscipy.ndimage.gaussian_filterを使用してください(rembgがすでにscipyをインストールしています)。 Image.fromarray(float32_array, "RGB")は直接エラーになります。先に.astype(np.float32)してからチャンネルごとに処理してください。- クリーンアップに
Remove-Itemを使用しないでください。cutout.py --cleanがディレクトリのクリーンアップをラップしています。
例
入力:「このGIFの背景を透明にして」
→ cutout.py --input 動作.gif --outdir out --scale 2 を実行し、次に verify.py、
→ GIF/WebP/APNGの3形式を納品。720×720 / 70フレーム / 各フレーム100ms / 合計7000ms と記載。
入力:「もっと綺麗に切り抜いて。端にノイズがある。腕と体の間も切り抜けていないところがある」
→ しきい値を調整しないでください。最初に verify.py --zoom <枠選択座標> を実行して欠陥の位置を確認し、
→ 孤立点が多い場合は --median 3 を追加、隙間が通っていない場合は --stage matte --scale 3 で該当フレームを再実行し、
→ 再び検収。応答ではどの種類の欠陥で、どの修正を使用したかを明確に説明し、「最適化しました」とだけ言わないでください。