Algorithm & UI/UX
AIが描く理想の曲線。
小顔補正を支えるグリッドワープの数学
AIが顔を検知するだけでは不自然な「加工感」が出てしまいます。本ツールがどのようにして、背景の歪みを抑えつつ滑らかなフェイスラインを実現しているのか、その裏側の数学的アルゴリズムを公開します。
1. サイン関数(正弦波)を用いた非線形ワープアルゴリズム
小顔補正において、画像を単に内側へ押し込むだけでは、アゴのラインが尖りすぎたり、頬が不自然に凹んだりします。本ツールでは、垂直方向の変形強度を制御するために**サイン関数(Math.sin)**を採用しています。
アゴの下から耳の付け根までの範囲を 0 から π と定義し、その中央部で最も変形が強く、端にいくほど滑らかに減衰する「非線形な重み付け」を行うことで、人間が「美しい」と感じる自然な曲線を実現しています。
// 垂直方向の変形重み付け(サイン曲線による減衰)
const warpTop = landmarks[TOP_INDEX].y - // 独自のチューニング値;
const warpBottom = landmarks[BOTTOM_INDEX].y + // 独自のチューニング値;
if (normY > warpTop && normY < warpBottom) {
// 0からπの範囲でサイン値を計算し、中央付近の変形を最大化
const vFactor = Math.sin(Math.PI * (normY - warpTop) / (warpBottom - warpTop));
// ここに水平方向の距離に応じた計算処理が入ります
dx -= distToCenter * canvasW * strengthFactor * vFactor * hFactor;
} 2. 30x30グリッドメッシュによる局所歪み制御
画像全体を一度に変形させると、計算コストが高くなるだけでなく、関係のない背景まで大きく歪んでしまいます。本ツールでは、顔周辺の領域を**30x30の細かいグリッド(メッシュ)**に分割して処理しています。
Canvasの drawImage を活用し、各グリッドセルごとに計算された「移動後の座標」へ断片的に転送することで、変形が必要な「顔の境界線付近」のみをピンポイントで動かしています。この手法により、背景の直線を可能な限り維持したまま、フェイスラインだけを「シュッ」とさせることが可能になりました。
// 顔周辺に限定したグリッド分割処理
const gridRows = // 独自のチューニング値;
const gridCols = // 独自のチューニング値;
for (let r = 0; r < gridRows; r++) {
for (let c = 0; c < gridCols; c++) {
// セルの元座標(sx, sy)と変形後の座標(dx, dy)を計算
// ここにグリッドごとの座標変換ロジックが入ります
// 0.8pxのオーバーラップを持たせることでセルの隙間を防止
ctx.drawImage(offscreenCanvas, sx, sy, cellW, cellH, dx, dy, cellW + 0.8, cellH + 0.8);
}
} 3. オンデマンドなAI初期化とLCP改善ハック
MediaPipeのような重量級のAIエンジンは、ページロード時に即座にロードすると、サイトの表示速度(LCP)を著しく悪化させます。本ツールでは、**「ユーザーが画像をアップロードした瞬間」**に初めてエンジンのダウンロードと初期化を開始する戦略をとっています。
これにより、初期化を待たずにページが瞬時に表示され、ユーザーが画像を選んでいる間にバックグラウンドでWASMの展開を完了させる、UXを損なわないロード設計を実現しています。
// 画像選択時に初めてAIをトリガー
async function handleFile(file) {
if (!isAiReady) {
initAI(); // ここで初めてWASMやモデルのロードを開始
updateLoadingMessage("AIエンジンを準備中...");
}
// 画像のデコードと並行してAIの準備完了を待機
await waitForAi();
executeFaceAnalysis();
} Developer's Note
小顔補正ツールの最大の敵は「背景の歪み」です。壁のタイルやドアの枠が曲がってしまうと、一気に「加工しました」という違和感が出てしまいます。
開発段階では、いかにして「顔の輪郭の内側だけを動かし、外側の背景への影響を 0 に近づけるか」という点に最も時間を費やしました。最終的には、AIが検知した顔の横幅に基づき、変形の影響範囲(hFactor)を動的に絞り込むアルゴリズムに辿り着きました。
数学的な厳密さよりも、ブラウザ上での「滑らかさ」と「見た目の自然さ」を優先したチューニングを施しています。ぜひ、スライダーを動かした際の変化の心地よさを体感してみてください。