マガジン

生成画像の背景を消す:境界の粗さをどう扱うか

遊びをつくる

執筆にClaudeを使用しています。

丸や四角の色紙と色見本を使ってゲームの画面を検討する机。
記事のテーマをもとに制作したAI生成イメージ。実際のゲーム画面ではありません。

生成画像でキャラクターやアイテムを作り、ゲームに載せようとすると、背景を消した瞬間に縁がざらつくことがあります。白い縁が残る、髪の毛の先が欠ける、輪郭がギザギザに見える、といった状態です。これを見て「切り抜きが失敗した」と考える人は多いのですが、本当に直すべきかどうかは、その画像をゲーム内でどの大きさ、どんな背景の上に出すかで変わります。 この記事で確かめる問いは二つです。ひとつは、単色背景の生成画像を切り抜くとき、しきい値とぼかし幅をどう動かすと縁の見え方が変わるのかです。もうひとつは、残った粗さを「消す」以外に、縁取りやサイズの調整で「活かす」ことができるかです。結果は書きません。読者が自分の画像で測り、自分のゲームの条件で判断できるように、準備・手順・記録・読み方を設計書の形で示します。

この記事の目次
  1. 問いを分ける:切り抜きの精度と、粗さの扱い
  2. 準備するもの
  3. 手順と記録の取り方
  4. 結果の読み方と、誤りやすい点
  5. 粗さを活かす方法を試す
  6. 次の行動

問いを分ける:切り抜きの精度と、粗さの扱い

「背景を消す」作業は、実は二つの別の判断が混ざっています。

  1. 精度の判断:被写体と背景をどこで分けるか(境界の位置)
  2. 粗さの判断:分けた境界をどれだけ滑らかに、あるいは硬く見せるか(境界の質感)

精度は、背景色との色の距離で決めます。背景色に近い色を透明にする方法では、距離の「しきい値」を大きくすると背景が多く消え、被写体の縁や背景色に近い部分まで削れます。小さくすると背景が残ります。

粗さは、境界で不透明から透明へ移る幅で決まります。幅がゼロなら境界は硬くなり、ギザギザ(ジャギー)が目立ちます。幅を取りすぎると、縁がにじんで背景色の混ざった帯(フリンジ)が見えやすくなります。

この二つは独立に動かせる軸です。しきい値とぼかし幅を別々に変えて記録すれば、「削れた」のか「にじんだ」のかを切り分けられます。

準備するもの

  • 単色に近い背景の生成画像を2〜3枚。被写体の違う画像を混ぜます。たとえば、輪郭がはっきりしたもの(道具や建物)と、細かい縁を持つもの(髪、毛皮、葉)です。
  • 次の最小ツール。保存した1つのHTMLファイルをブラウザで開くだけで動きます。外部ライブラリも通信も使いません。画像はブラウザ内で読み込むだけです。
  • 記録用の表(紙でも表計算でも構いません)。
  • ゲーム内の表示サイズがわかっていること。分からなければ、実際に使う予定の大きさ(たとえば幅64pxや幅256px)を先に決めます。
html
<input type="file" id="f" accept="image/*">
<label>しきい値<input type="range" id="t" max="200" value="40"></label>
<label>ぼかし幅<input type="range" id="s" max="100" value="30"></label>
<select id="b"><option>#ffffff</option><option>#222222</option><option>#2a6f97</option></select><br>
<canvas id="c"></canvas>
<script>
const $=i=>document.getElementById(i),c=$('c'),x=c.getContext('2d');
let src=null,key=[255,255,255];
$('f').onchange=e=>{const im=new Image();im.onload=()=>{c.width=im.width;c.height=im.height;x.drawImage(im,0,0);src=x.getImageData(0,0,c.width,c.height);draw()};im.src=URL.createObjectURL(e.target.files[0])};
c.onclick=e=>{if(!src)return;const r=c.getBoundingClientRect(),px=Math.floor((e.clientX-r.left)*c.width/r.width),py=Math.floor((e.clientY-r.top)*c.height/r.height),i=(py*c.width+px)*4;key=[src.data[i],src.data[i+1],src.data[i+2]];draw()};
function draw(){
 if(!src)return;
 const o=new ImageData(new Uint8ClampedArray(src.data),src.width,src.height),d=o.data,t=+$('t').value,s=+$('s').value;
 for(let i=0;i<d.length;i+=4){
  const dist=Math.hypot(d[i]-key[0],d[i+1]-key[1],d[i+2]-key[2]);
  d[i+3]=Math.round(d[i+3]*Math.min(1,Math.max(0,(dist-t)/(s||1))));
 }
 const m=document.createElement('canvas');m.width=c.width;m.height=c.height;
 m.getContext('2d').putImageData(o,0,0);
 x.fillStyle=$('b').value;x.fillRect(0,0,c.width,c.height);x.drawImage(m,0,0);
}
['t','s','b'].forEach(k=>$(k).oninput=draw);
</script>

使い方は次のとおりです。画像を選び、背景部分をクリックすると、その色が「消す色」になります。しきい値は、その色からどれだけ離れた色まで完全に透明にするかを決めます。ぼかし幅は、しきい値の外側で、透明から不透明へ移る距離の幅です。下のプルダウンは、切り抜いた画像の後ろに敷く色です。

このツールは単色背景向けです。背景にグラデーションや模様がある画像では、1点の色だけでは分けられません。その場合は、先に生成時の指示で背景を単色にそろえるか、画像編集ソフトの選択ツールを併用してください。

手順と記録の取り方

条件を格子にする

しきい値を {20, 40, 80}、ぼかし幅を {0, 30, 80} の3段階ずつにして、9通りの組み合わせを作ります。数値は目安の出発点です。画像の色の幅によって適切な範囲は変わるため、9通りのすべてで極端な結果になる場合は、段階の幅を広げたり狭めたりして構いません。

各条件で見る場面を決める

1枚の画像につき、次の順で確認します。

  1. 背景を白、暗色、青系の3種に切り替えて、縁の見え方を見る
  2. 画像の縁を、等倍と、ブラウザの拡大機能で200%にした状態で見る
  3. ゲームでの実際の表示サイズ(先に決めたサイズ)に縮小した状態で見る

3種の背景を使うのは、フリンジが背景色との差で見え方を変えるためです。白背景で生成した画像を白の上で確認しても、白い縁は見えません。暗色の上に置いたときに初めて現れます。

記録する

下のような表を、画像ごとに1枚作ります。

  • 20、ぼかし幅:0、白背景:、暗色背景:、青系背景:、削れ(有/無):、フリンジ(有/無):、実寸での判断:
  • 20、ぼかし幅:30、白背景:、暗色背景:、青系背景:、削れ(有/無):、フリンジ(有/無):、実寸での判断:
  • …(9行)、ぼかし幅:、白背景:、暗色背景:、青系背景:、削れ(有/無):、フリンジ(有/無):、実寸での判断:

各セルの採点は、1〜5点の目視でそろえます。5が「縁が気にならない」、3が「近くで見ると分かる」、1が「実寸でも目立つ」という基準を先に書き、同じ基準で最後まで通してください。採点は、時間を空けて同じ条件を2回見直すと、基準のぶれに気づけます。

「削れ」は、被写体の内側や細い部分(髪の先、指の間など)が透明になっていないかの有無です。「フリンジ」は、被写体の外周に背景色寄りの帯が見えるかの有無です。2つを別の列にしておくと、後で原因を切り分けられます。

結果の読み方と、誤りやすい点

表が埋まったら、次のように読みます。

  • しきい値を上げると削れが増え、フリンジが減る傾向が表に出た場合:しきい値は精度の軸として働いています。削れが許容できる最大のしきい値を、その画像の上限とします。
  • ぼかし幅を上げるとジャギーは減るが、フリンジが増えた場合:粗さの軸として働いています。縁を柔らかくした代わりに、背景色の混ざる帯が広がっています。実寸の採点が良ければ、そのまま採用して構いません。
  • どの組み合わせでも暗色背景だけ採点が低い場合:背景色が縁に混ざっています。しきい値やぼかし幅では限界があり、切り抜き前の生成画像の背景色を、使う背景に近い色にする方が効く可能性があります。
  • 等倍と200%では低採点だが、実寸では差が出なかった場合:この画像は粗さを直す必要がありません。実寸の採点を優先してください。
  • 細かい縁を持つ画像だけ、どの設定でも削れが出た場合:単色キーでは限界です。髪や葉のような部分は、画像編集ソフトの手作業か、別の切り抜き手段の検討に進む合図になります。

誤りやすい点も挙げておきます。

  • 背景のクリック位置:クリックした点が、たまたま影やノイズの部分だと、キー色がずれます。背景の数か所でクリックし直して、結果が大きく変わらないかを確認してください。
  • 被写体に背景色に近い色がある場合:白い背景に白いシャツのキャラクターを置くと、内部まで透明になります。この場合は、しきい値を下げても改善しないことがあります。
  • 画像形式の取り違え:切り抜き結果を保存するときは、透明を保てるPNGやWebPを使います。JPEGは透明を持てません。
  • 生成画像の取り扱い:使った生成サービスの利用条件によって、商用利用や再配布の可否が異なります。公式の規約で確認してください。

粗さを活かす方法を試す

精度を詰めても粗さが残る場合は、「消す」以外の選択肢があります。同じ表の続きとして、次の3つを実寸で見比べてください。

縁取りを足す:被写体の外周に、白や濃色の細い輪郭線を重ねると、縁のばらつきが輪郭線に吸収されて見えにくくなります。CSSだけで試すなら、影を上下左右に重ねる方法があります。

css
img.sticker {
  filter: drop-shadow(2px 0 0 #fff) drop-shadow(-2px 0 0 #fff)
          drop-shadow(0 2px 0 #fff) drop-shadow(0 -2px 0 #fff);
}

表示サイズを下げる:実寸が小さいほど、縁の粗さは目に入りにくくなります。拡大して使う予定がないなら、元画像を最初から実寸の2倍程度に縮小して保存する方が、ファイルも軽くなります。アソバースにHTMLやZIPで作品を投稿する場合も、アップロードは20MiB以内という上限があるため、画像サイズの見直しは無駄になりません。

粗さを様式にする:ステッカーや切り紙のように、縁がやや不揃いなこと自体を絵柄の特徴にするやり方です。縁取りを太めにし、ぼかし幅を0にして輪郭を硬くする設定は、ここでは弱点ではなく狙いになります。

3つのうち、実寸の採点が最も上がるものを選び、さらに「手描きで修正する手間」に見合うかを判断します。縁の修正に使える時間が少ないなら、縁取りとサイズ調整で済ませる方が現実的な場合があります。逆に、主役のキャラクターのように画面に大きく長く映るものは、粗さを丁寧に詰める価値があります。画像ごとに、使う場面の重さで手間を配分する考え方です。

次の行動

まず、手元の生成画像を2枚選び、9通りの設定で実寸の採点表を埋めてみてください。次に、実寸で最も採点が低かった画像だけ、縁取りかサイズ調整を加えて採点し直します。この比較で、手作業で直すものと、そのまま使うものの線引きが、自分のゲームの条件で見えてきます。