猫の手ツール

Algorithm & UI/UX

AI微笑み補正:バイリニア補間リキッド処理による自然な表情変形

口角と目元のランドマークを起点に、周囲のピクセルを少しずつ移動させるツールです。顔の筋肉を解析しているわけではなく、写真上の位置と口幅を基準に変形量を計算します。

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

現行コードの確認日:

入力
正面に近い人物写真を選び、口角と目元の強さを別々に調整します。
処理
FaceLandmarkerの口・目の座標から変形の中心と範囲を決め、周辺の画素を移動します。
出力
最大10人、入力は長辺1500px以下、保存はJPEG品質0.95です。

まず確認する点:口角と目元を同時に強めると変化の原因を見分けにくくなります。初期値0から片方ずつ試し、背景や輪郭の歪みも見ます。

仕上がりの例

人物の口元を、少しやわらかい表情に調整した例です。

加工前・加工後
左は人物の顔写真。右は口元の形を少し調整した顔写真。

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

加工前・加工後

左は人物の顔写真。右は口元の形を少し調整した顔写真。

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

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

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

記録の入力画像
1788×2400px (JPEG)
記録の出力画像
1117×1500px (JPEG)
保存済み記録の主な操作・出力条件
画面の項目記録の値現行コードの初期値・範囲
口角の上がり具合(笑顔の強さ)30初期値 0 / 範囲 0〜100
目元のやさしさ(頬のリフトアップ)15初期値 0 / 範囲 0〜100

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

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

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

仕組みを読み進めるときは、MediaPipeの顔ランドマーク(顔の点を使う描画と変形)、Canvas APIと画像処理(画像寸法、drawImage、画素と透明度の扱い)が参考になります。

1. 画素を移動させるリキッド処理

画像の特定部分を歪ませる「リキッド処理」は、ブラウザ標準のCSSフィルタでは実現できません。また、一部のブラウザでは高度なCanvas操作がフリーズの原因になることもあります。

本ツールでは、getImageData で取得したピクセル配列を、バイリニア補間(双線形補間)を用いて直接計算・再配置する独自のワープ関数を実装しました。参照座標の周囲4画素を混ぜることで、整数座標だけを使う場合の段差を抑えます。強い変形で画質が失われることや、境界が不自然になることまで防ぐものではありません。

参照座標の周囲4画素を混ぜる双線形補間です。fxとfyは0〜1の端数で、RGBAの各成分について同じ式を使います。

function bilinear(p00, p10, p01, p11, fx, fy) {
  return p00 * (1 - fx) * (1 - fy)
    + p10 * fx * (1 - fy)
    + p01 * (1 - fx) * fy
    + p11 * fx * fy;
}

2. 顔のスケールに追従する「動的エフェクト範囲」の計算

アップロードされる写真の解像度や、顔の大きさは千差万別です。「口角を50px上げる」といった固定値での処理は、顔が小さい場合に崩壊を招きます。

本ツールでは、AIが検出した左右の口角の距離(口幅)を基準単位(Unit)として採用しています。変形させる半径や移動ベクトルをこの距離に対する割合で計算することで、検出した口の大きさに応じて補正範囲を変えています。推定位置の正確さや表情の自然さは、顔の向き・照明・設定値によって変わります。

3. willReadFrequently による描画パフォーマンス最適化

本ツールはスライダーを動かすたびに、高解像度画像のピクセルデータを読み取り・計算・描画しています。これは本来、ブラウザにとって非常に重い処理です。

そこで、Canvasコンテキストの取得時に willReadFrequently: true オプションを明示的に指定しています。これは画素を頻繁に読み戻す用途をブラウザへ伝えるヒントです。どの描画方式を使うかはブラウザが判断し、必ず高速化するという指定ではありません。

出力の仕様と確認する点

「口角」は口幅を基準に上方向と外側へ、「目元」は目の下を上方向へ動かします。どちらも初期値0で、半径はそれぞれ口幅の0.45倍と0.35倍です。歯を新しく描いたり、閉じた口を開いた笑顔へ生成し直す処理ではありません。

変形用の矩形が画像の右端や下端を超えると、その変形を行わない実装です。端に寄った顔や複数の顔が近い写真では、左右で効果が違うことがあります。

最大10人、入力は長辺1500px以下、保存はJPEG品質0.95です。requestAnimationFrameは描画の予約を整理するもので、画素計算はメインスレッドで行います。