はじめに
AI画像ツールに複数のスタイルを用意すると、各スタイルで最も見栄えのよい画像をプレビューに使いたくなります。
しかし、プレビューごとに人物や構図が異なると、ユーザーは次の点を判断できません。
- 元の顔立ちはどの程度残るのか
- 髪型や服装は維持されるのか
- スタイルによって構図が大きく変わらないか
- 単に作例が魅力的なだけではないか
そこで、同じBefore画像から生成した結果を並べ、スタイルカードにマウスを重ねたときだけ比較できるUIを試作しました。
変更前の問題
最初のスタイル選択画面では、それぞれ別の人物をプレビューに使用していました。
スタイル自体の雰囲気は伝わりますが、画像間に共通の基準がありません。たとえば「Manga」と「Y2K Doodle」を比較しても、違いがスタイルによるものなのか、元画像によるものなのか判断しにくい状態でした。
この問題は、生成品質を「見栄え」だけでなく「入力画像の保持」という観点で見せたい場合に特に大きくなります。
採用した方針
今回の比較UIでは、次のルールを設定しました。
- 複数のスタイルで同じBefore画像を使う
- BeforeとAfterのアスペクト比を揃える
- 通常時はスタイル画像だけを表示する
- Hover時にBeforeとAfterを並べて表示する
- モバイルでは従来どおりタップでスタイルを選択できるようにする
Hover表示は補助情報として扱い、スタイルを選択する操作自体には依存させません。これにより、タッチ端末でも基本機能が失われません。
比較データをスタイル定義から分離する
すべてのスタイルに比較画像が揃っているとは限らないため、比較用データは別のマップとして管理しました。
type StyleComparison = {
sourceImage: string;
sourceAlt: string;
resultImage: string;
resultAlt: string;
};
const styleComparisons: Record<string, StyleComparison> = {
"y2k-doodle": {
sourceImage: "/images/y2k-before.webp",
sourceAlt: "Original portrait used for the Y2K Doodle comparison",
resultImage: "/images/y2k-after.webp",
resultAlt: "Portrait transformed into the Y2K Doodle style",
},
};
この形なら、比較画像が用意できたスタイルから段階的に追加できます。
スタイル本体のモデル設定やプロンプトと、UI上の比較素材を密結合させずに済む点も扱いやすいところです。
Radix UIのHoverCardで比較を表示する
Hover表示にはRadix UIのHoverCardを使用しました。
<HoverCard openDelay={220} closeDelay={100}>
<HoverCardTrigger asChild>
<button
type="button"
onClick={() => setSelectedStyle(style)}
aria-pressed={selected}
className="rounded-xl text-left focus-visible:ring-2"
>
<Image
src={style.previewImage}
alt={style.label}
width={240}
height={190}
className="aspect-[1.25] w-full rounded-xl object-cover"
/>
<span className="mt-2 block text-xs font-medium">{style.label}</span>
</button>
</HoverCardTrigger>
<HoverCardContent
side="top"
sideOffset={10}
collisionPadding={16}
className="w-[340px] rounded-xl border bg-white p-3 shadow-xl"
>
<p className="pb-2 text-xs font-medium">{style.label}</p>
<div className="grid grid-cols-2 gap-2">
<ComparisonImage
src={comparison.sourceImage}
alt={comparison.sourceAlt}
label="Before"
/>
<ComparisonImage
src={comparison.resultImage}
alt={comparison.resultAlt}
label="After"
/>
</div>
</HoverCardContent>
</HoverCard>
画像部分は小さなコンポーネントに分けています。
function ComparisonImage({
src,
alt,
label,
}: {
src: string;
alt: string;
label: string;
}) {
return (
<figure>
<div className="relative aspect-[3/4] overflow-hidden rounded-lg border">
<Image
src={src}
alt={alt}
fill
sizes="150px"
className="object-cover"
/>
</div>
<figcaption className="mt-1.5 text-[11px] font-medium">
{label}
</figcaption>
</figure>
);
}
collisionPaddingを指定しておくと、画面端にあるカードでもHoverCardがビューポート外へはみ出しにくくなります。
Hoverの表示速度
すぐにポップアップを開くと、スタイル一覧を横切っただけで表示が切り替わり、操作が落ち着きません。
今回は次の値にしました。
<HoverCard openDelay={220} closeDelay={100}>
220ms程度なら、意図的に画像を見ようとしたときには素早く開き、単にカーソルが通過した場合は反応しにくくなります。
Before画像を選ぶ基準
比較用の元画像は、単にきれいな写真であればよいわけではありません。
今回重視した条件は次のとおりです。
- 1人の顔が十分な大きさで写っている
- 顔の輪郭が髪や手で隠れすぎていない
- 髪型に識別しやすい特徴がある
- 眼鏡やアクセサリーなど比較可能な要素がある
- 極端な逆光ではない
- 背景が主体より目立たない
- 画像の利用権を確認できる
特に髪型とアクセサリーは、スタイル変換後にも同一人物らしさが残っているかを判断しやすい要素でした。
画像を軽量化する
Hoverのたびに大きなJPEGやPNGを読み込むと、プレビュー表示が遅くなります。
そこで、表示サイズに合わせてWebPへ変換し、不要なメタデータも除去しました。
cwebp \
-q 82 \
-resize 432 576 \
-metadata none \
before.jpg \
-o before.webp
元画像が数百KBあっても、プレビュー用途なら画質を保ちながら数十KB程度に抑えられます。
また、BeforeとAfterで異なるクロップを使うと比較しにくいため、両方に同じアスペクト比とobject-fitを適用します。
実際のツールで検証する
このUIは、自作している写真をアニメ風に変換するツールのスタイル選択画面で検証しました。
最初は1つのスタイルだけにBeforeとAfterを追加し、表示サイズやHoverの遅延を確認しました。今後は同じ元画像から複数のスタイルを生成し、比較対象を段階的に増やす予定です。
すべてのスタイルを一度に揃えるより、まず3〜5種類の代表的なスタイルで比較が本当に役立つか確認する方が、画像生成コストと実装負担を抑えられます。
実装して分かったこと
スタイルプレビューでは、作例の多様性と比較のしやすさが競合します。
異なる人物を使うとギャラリーとしては華やかになります。一方、生成品質や人物保持を説明するには、同じ人物を使った方が明らかに伝わりやすくなります。
そのため、次のように役割を分けるのがよさそうです。
- スタイル選択画面:同じBefore画像で比較する
- 作例ギャラリー:人物、ペット、構図を変えて用途の幅を見せる
- 詳細な事例:大きなBeforeとAfterで細部を確認できるようにする
まとめ
AI画像ツールで複数のスタイルを見せる場合、魅力的な作例を並べるだけでは変換品質を比較できません。
同じBefore画像を基準にし、Hover時にBeforeとAfterを表示すると、一覧の密度を保ったまま次の情報を伝えられます。
- 顔立ちの保持
- 髪型や服装の保持
- スタイルごとの変化
- 構図の安定性
小さなUI変更ですが、ユーザーが生成前に結果を予測しやすくなり、スタイルを選ぶ根拠も明確になります。