猫の手ツール

Algorithm & UI/UX

服の明暗を使って色を重ねるブレンドの仕組み

衣服と推定した画素の明るさを取り出し、選択色へ掛け合わせて元画像と混ぜます。柄や陰影を手掛かりに色を変える方法と、黒い服や境界の推定が持つ限界を説明します。

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

現行コードの確認日:

入力
服が写った人物写真と色・濃さを指定します。
処理
複数カテゴリのImageSegmenterで衣服に対応する領域を取り、元の明暗に色を重ねます。
出力
入力の長辺は最大1500px、出力はJPEG品質0.95です。

まず確認する点:人物全体のマスクをそのまま服のマスクにしない点が要点です。柄、髪、肌との境界に色が漏れていないか見ます。

仕上がりの例

人物の服だけを、青色から紫色に変えた例です。

加工前・加工後
左は青いシャツを着た人物の写真。右は顔や背景を保ち、シャツを紫色に変えた写真。

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

加工前・加工後

左は青いシャツを着た人物の写真。右は顔や背景を保ち、シャツを紫色に変えた写真。

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

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

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

記録の入力画像
1788×2400px (JPEG)
記録の出力画像
1117×1500px (JPEG)
保存済み記録の主な操作・出力条件
画面の項目記録の値現行コードの初期値・範囲
変更するカラー#a855f7初期値 #a855f7
染める濃さ(ブレンド強度)100初期値 100 / 範囲 0〜100

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

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

仕組みを読み進めるときは、髪と服のセグメンテーション(目的に合うモデルとカテゴリの選び方)、Canvas APIと画像処理(画像寸法、drawImage、画素と透明度の扱い)が参考になります。

1. テクスチャを維持する「輝度抽出(Luminance)ブレンド」

服の色を変更する際、最も大きな課題は「影やシワをいかに残すか」です。単純に特定の色を重ねる(Overlay)だけでは、立体感が消えてベタ塗りのような不自然な仕上がりになります。

このツールでは、まず元の画像の各ピクセルから輝度(Luminance)を計算します。輝度とは、その点の「明るさの度合い」です。この値を抽出した上で、新しく指定されたカラーと乗算合成を行うことで、元の服の明暗を新しい色の濃淡へ反映します。ただし、選んだ色の明るさによって出力の輝度は変わり、元と完全に同じ明るさを保存する計算ではありません。

衣服の確信度を使って1画素を着色する式です。rgbとtargetはRGBの配列、strengthとconfidenceは0〜1です。実装では衣類の確信度マスク(インデックス4)をコピーした透明度からconfidenceに相当する値を使います。

function recolorCloth(rgb, target, strength, confidence) {
  const light = rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] * 0.114;
  const mix = strength * confidence;
  return rgb.map((value, channel) =>
    value * (1 - mix) + target[channel] * light / 255 * mix);
}

2. MediaPipe Wasmによるマルチクラス・セグメンテーション

「服だけ」を自動で選ぶためには、画像の中から衣服の領域を特定するAI(セグメンテーション)が必要です。本ツールでは、MediaPipeのSelfie Multiclassモデルを採用しています。

この実装のポイントは、サーバーを介さないブラウザ完結型であることです。WebAssembly(Wasm)を活用することで、1枚の画像をピクセル単位で解析し、「背景」「肌」「髪」「衣類」といったカテゴリに分類したマスク配列を高速に生成します。このマスク情報をCanvasのImageData操作に直接結びつけることで、低遅延なプレビューを可能にしています。

3. requestAnimationFrameによるレンダリングの最適化

カラーピッカーやスライダーを動かした際、Canvasの全ピクセル(数百万個)をループ処理して再描画すると、ブラウザのメインスレッドを占有し、UIがカクつく原因になります。

これを防ぐため、本ツールでは requestAnimationFrame を用いた間引き描画(Throttling)を実装しています。変更イベントが連続して発生しても、次の画面更新前に重なった描画要求をまとめます。画素の走査はメインスレッドで行うため、画像の大きさによっては操作が待たされる場合があります。

出力の仕様と確認する点

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

Selfie Multiclassモデルは6クラスで、衣類のカテゴリと確信度のインデックスは4です。衣類確信度を着色強度へ掛け、境界を連続的に混ぜます。背景や肌を手動で塗り分ける機能はありません。複数の服を別々の色へ指定することもできません。

強さ0では元画像を使い、100でも衣類確信度が1の画素でのみ計算した色へ完全に置き換えます。中間の確信度では元画像と混ぜます。黒い部分は輝度が低いため明るい色を指定しても暗く残ります。白い服・柄物・透ける素材で実物の染色結果を予測する機能ではありません。

入力の長辺は最大1500px、出力はJPEG品質0.95です。袖や襟、髪との境界を確認し、見た目の比較用として使用します。