猫の手ツール

Algorithm & UI/UX

ブラウザ完結型AIによる髪色認識と
ピクセルブレンドの実装

本ツールは、Googleの機械学習モデルをWebAssemblyでブラウザ上で動作させ、さらにCanvas APIを用いた高度なピクセル操作を組み合わせることで、インストール不要かつプライベートなヘアカラー体験を実現しています。

1. WebAssemblyによる「サーバーレスAI」の実現

従来の画像解析ツールは、画像を一度サーバーにアップロードして処理を待つ必要がありました。本ツールでは「Image Segmenter」モデルをWebAssembly (WASM) 技術を用いてブラウザ内で直接実行しています。

このアプローチの最大のメリットは、ユーザーの画像が一切ネットワークを介さないため、究極のプライバシー保護が達成される点、そして通信待ちのないリアルタイムな解析が可能になる点にあります。

// AIエンジンの初期化(機密パスや構造は抽象化)
async function initAI() {
    const vision = await FilesetResolver.forVisionTasks(WASM_ASSET_PATH);
    imageSegmenter = await ImageSegmenter.createFromOptions(vision, {
        baseOptions: { 
            modelAssetPath: AI_MODEL_BINARY_PATH,
            delegate: "GPU" // ハードウェアアクセラレーションを活用
        },
        runningMode: "IMAGE",
        outputCategoryMask: true
    });
}

2. 「仮想ブリーチ」アルゴリズムによる発色補正

単純に髪の毛領域に色を乗せるだけでは、日本人に多い黒髪の場合、色が沈んでしまい綺麗に発色しません。そこで本ツールでは、着色前にピクセル単位で「仮想的なブリーチ(脱色)」処理を施しています。

具体的には、髪の毛領域の各ピクセルの輝度を算出し、独自の係数を用いてベースの明るさを持ち上げてからターゲットカラーを乗算しています。これにより、黒髪からでも透明感のあるパステルカラーやハイトーンカラーへの自然なシミュレーションを可能にしました。

// 輝度ベースのカラーブレンディング(コアロジックの概要)
function renderCanvas() {
    // 1. 各ピクセルのRGB値を取得
    // 2. マスクデータに基づき、髪の毛領域か判定
    for (let i = 0; i < maskArray.length; i++) {
        if (isHairRegion(maskArray[i])) {
            let gray = calculateLuminance(r, g, b); // 独自の輝度計算
            
            // 仮想ブリーチ:ベースの輝度を補正
            let adjustedGray = gray + (MAX_BRIGHTNESS - gray) * // 独自のチューニング係数;
            
            // 着色:補正後の輝度にターゲット色を乗算ブレンド
            let coloredR = (adjustedGray * targetRgb.r) / DIVISOR;
            
            // 3. 元のピクセルデータと合成
        }
    }
}

3. requestAnimationFrameによる滑らかなプレビュー

スライダーを動かした際に、都度Canvasの重いピクセル演算を行うと、描画がカクつく原因になります。本ツールでは、スライダーの `input` イベント内で直接描画を呼ぶのではなく、`requestAnimationFrame` (RAF) を介してブラウザの更新タイミングに同期させています。

これにより、連続的なパラメータ変更時も描画の競合を抑え、ユーザーの操作に対して吸い付くようなUI体験を提供しています。

let renderRAF = null;
function requestRender() {
    // 実行待ちのフレームがあればキャンセルして最新の描画を予約
    if (renderRAF) cancelAnimationFrame(renderRAF);
    renderRAF = requestAnimationFrame(renderCanvas);
}

// UIイベントからの呼び出し
strengthSlider.addEventListener('input', (e) => {
    updateState(e.target.value);
    requestRender();
});

Developer's Note

髪の毛は一本一本が細く、境界線が非常に複雑です。汎用的な切り抜きAIではなく、Googleが公開している「Hair Segmenter」という特化型モデルを採用したことで、産毛や背景との境界も驚くほど正確に抽出できるようになりました。

最もこだわったのは、スライダーの「地毛の濃さ」の調整機能です。単なる不透明度ではなく、内部で輝度カーブを微調整することで、"美容室で実際に染めたときのような質感"をいかにCanvas上で再現するか、何度も数値のチューニングを繰り返しました。