猫の手ツール

Algorithm & UI/UX

人物マスクと背景の色加工:セグメンテーションとポスタリゼーション

人物と背景のマスクをAIで推定し、背景に分類した画素の彩度・明るさ・階調を変えてイラスト風に見せます。新しい風景を生成するAIではなく、元写真の背景の色を加工するツールです。

このツールの入力から出力まで

現行コードの確認日:

入力
人物写真を選び、背景加工の強さを指定します。
処理
背景側の彩度と青みを変えて色を段階化し、人物マスクで元の人物を重ね直します。
出力
入力は長辺1500px以下、出力はJPEG品質0.95です。

まず確認する点:テキストから新しい風景を生成する処理ではありません。元背景の輪郭がどう変わるかと、人物の境界の欠けを見ます。

仕上がりの例

人物を残し、背景をアニメ風に加工した例です。

加工前・加工後
左は屋外で2人が自撮りした写真。右は人物を残して風景をアニメ風にした写真。

サンプルにはAIで生成した架空の人物画像を使用しています。

加工前・加工後

左は屋外で2人が自撮りした写真。右は人物を残して風景をアニメ風にした写真。

掲載画像はサイトにある既存の公開作例です。保存済みの資料ではAIで作成した架空の人物・手の画像を使用しています。今回の確認日が、この作例を実行した日を表すわけではありません。

保存済み検証記録の条件を見る

資料の種類は「ツールの出力画像を保存した記録」です。公開作例と保存済み記録で素材や色などが異なる場合があるため、下の数値は保存済み検証記録の条件として読んでください。

記録の入力画像
1788×2400px (JPEG)
記録の出力画像
1117×1500px (JPEG)
保存済み記録の主な操作・出力条件
画面の項目記録の値現行コードの初期値・範囲
アニメ化の強さ50初期値 50 / 範囲 1〜100

記録では「この画像で保存へ進む」から完成表示へ進んでいます。初期値と記録値を比べてから、効果を1項目ずつ変えると作用を確認しやすくなります。

資料ファイルの作成日は実行日として扱っていません。個別端末の処理速度や、ほかの写真に対する検出・加工の精度を測定した資料でもありません。

実装の確認箇所:src/pages/ai/ima-seg/anime-bg/index.astro。以下のコード抜粋と出力条件は、この本番実装に基づいて説明します。

仕組みを読み進めるときは、MediaPipeの画像セグメンテーション(人物マスクの寸法、カテゴリと資源解放)、Canvas APIと画像処理(画像寸法、drawImage、画素と透明度の扱い)が参考になります。

1. MediaPipeによる人物セグメンテーション

このツールの最大の特徴は、人物と推定された領域を残し、背景と判断した領域を加工する点にあります。これを可能にしているのが、Googleの「MediaPipe Image Segmenter」を用いたリアルタイムセグメンテーションです。

WASM(WebAssembly)とGPUを活用することで、ブラウザ上でピクセル単位の「カテゴリマスク」を生成。これにより、髪や持ち物の境界を含めて領域を推定し、マスクを使って背景を操作する「レイヤー分離」と同等の処理を単一の画像に対して実行しています。

背景色の階調数と彩度を決める式です。strengthは1〜100で、大きいほど階調が粗く、色が強くなります。

function animeParameters(strength) {
  const levels = Math.max(3, 20 - Math.floor(strength / 6));
  return {step: 255 / levels, saturation: 1 + strength / 100 * 0.6,
    redGreenOffset: 10 + strength / 10, blueOffset: 20 + strength / 5};
}

2. ImageDataを使った背景の階調・彩度調整

アニメ風の「ベタ塗り感」は、背景の色を少ない階調へまとめることで作ります。本ツールではCanvasの filter に加工を任せず、読み出した各画素へ計算を行います。

getImageData で取得した画素配列へ、ポスタリゼーション(階調化)と青み・彩度の計算を1ピクセルずつ適用します。JavaScriptで画素を走査する負荷は残り、特定の端末での速度や安定動作を保証する方式ではありません。

3. requestAnimationFrame による動的プレビュー最適化

「アニメ化の強さ」スライダーを動かす際、膨大なピクセル計算が走ります。UIの反応を損なわないよう、描画処理は requestAnimationFrame (RAF) を用いてブラウザの更新サイクルと同期させています。

実行前の描画予約を取り消して最新の値で予約し直すことで、連続入力による描画の重複を抑えます。実行を開始した画素計算を途中で中止したり、別スレッドへ移したりする仕組みではありません。

出力の仕様と確認する点

マスクの大きさは返却されたwidth・heightを参照します。readMaskDataで処理Canvasの寸法へ合わせ、カテゴリは最近傍補間で所有配列へコピーします。コピー後にImageSegmenterResult.close()で元のマスク資源を解放し、編集と描画にはコピーを使います。

現行のMediaPipe Tasks Vision 0.10.34とselfie_segmenter.tfliteのカテゴリマスクは、人物が0、背景が255です。人物のカテゴリ0を残し、背景のカテゴリ255へ効果を掛けます。人物向けモデルのため、物やペットを必ず残せるわけではありません。

強さを上げると彩度を高め、青成分を赤・緑より多く足し、色を段階化します。線画を新しく描いたり、背景の物を消す処理はないため、元の部屋や看板などの形は残ります。

入力は長辺1500px以下、出力はJPEG品質0.95です。加工後も背景の情報が読めることがあるので、この効果だけで住所や場所を隠せるとは考えず、公開範囲を確認してください。