AI生成の動作例用写真 / 編集前
DEVELOPMENT JOURNAL / 06
Photoshot
GITHUB × AI
無料Photoshop代替の開発記

自然な彩度と彩度

色ごとに彩度の反応を変える実装は、すでにGitHubにありました。必要だったのは、その考え方を理解し、既存の調整エンジンで使える形にすることです。glfx.jsを読んだ後、AIと別のHSL計算を書き、測定した応答も同じ機能へつなぎました。

PHOTOSHOT DEVELOPMENT JOURNAL / 06

AI生成の動作例用写真。編集画面と出力画像は実際のPhotoshotで作成しました。

Photoshot無料Photoshop代替の開発記 / 06FOUNDATION

ソースから始める。

色を扱うコードも公開されていた

公開実装によって、どんな入力で色の反応を変えられるか確認でき、出発点を前へ進められました。AIと行ったのはコードをそのまま動かすだけでなく、Photoshotの色変換と調整レイヤーに合う実装を接続する作業です。

9月18日の開発セッションには、glfx.jsのvibrance.jsを実際に開いて読んだ記録があります。RGBの最大値と平均値を使い、入力色によって反応を変えるシェーダーです。色ごとに効き方を変える考え方を確認できました。

ポトショットには、このシェーダーをそのまま移植していません。当時の開発ノートにも、HSLの彩度に(1−S)の重みを付けた独自計算とあります。外部コードから学んだ部分と、AIと新しく実装した部分を分けて見ていきます。

低彩度の色に大きな重みを付ける

下はGitHubで公開しているポトショット自身のコードです。sは0〜1の彩度。自然な彩度の値に(1−s)を掛けるので、すでに彩度が高い色ほど追加の増加率が小さくなります。その後、彩度スライダーの倍率を別に掛けます。

これはHSL経路の説明です。公開版のすべての処理がこの2行を通るわけではありません。revision 2で保護を有効にした調整は、次の測定応答の経路を使います。

再利用したのは外部フィルター全体ではなく、実装で示された色処理の考え方と内部の調整基盤です。AIと書いた計算を同じエンジンにつなぐことで、他の調整と同様に設定を保存し、マスクを適用できました。

src/adjustments.ts · v0.16.0
L646–647
Photoshotの実装コード ↗
const gain = (v.vibrance / 100) * (1 - s) * (1 - 0.75 * skin);
fromHsl(h, clamp(s * (1 + gain) * (1 + v.saturation / 100)), l, out);
Photoshot無料Photoshop代替の開発記 / 06IMPLEMENTATION

計算の
内側へ。

測定した応答を既存のエンジンにつなぐ

後の実装では、合成RGBチャートをPhotoshopに入力して測定した応答をデータとして使います。ソースの注記は、Photoshop 27.3.1で測定した17×17×17のRGB格子と明記しています。Adobeのプリセットファイルでも、glfx.js由来の表でもありません。

AIと書いた接続コードは、自然な彩度の応答を先に適用し、その結果に彩度の応答を適用します。サンプル間の色とスライダー値は補間します。測定データとそれを呼び出す処理を分け、既存のレイヤー構造につなぎました。

保護オプションは顔を認識しない

保護という名前から顔認識を想像するかもしれません。しかし、この経路が受け取るのはRGB値と設定値です。肌なのか、似た色の壁や服なのかは判断していません。同じRGBには同じ計算を適用します。

このオプションは色の反応方式を選ぶ機能と説明するのが正確です。特定の人物だけを調整するならレイヤーマスクが必要です。また、測定点の間を補間するため、あらゆる写真でPhotoshopと同一になる保証はありません。

PHOTOSHOT / SOURCE NOTES06

コードを読む。

src/adjustments.ts · v0.16.0
L634–642
Photoshotの実装コード ↗
} else if (a.revision === 2 && v.skin) {
  scratch[0] = r;
  scratch[1] = g;
  scratch[2] = b;
  applyVibranceResponse(scratch, v.vibrance, 0, out);
  scratch[0] = out[0];
  scratch[1] = out[1];
  scratch[2] = out[2];
  applyVibranceResponse(scratch, v.saturation, 1, out);
src/vibrance-response.ts · v0.16.0
L60–67
Photoshotの実装コード ↗
const p = Math.max(0, Math.min(20, (value + 100) / 10)),
  lo = Math.floor(p),
  hi = Math.min(20, lo + 1),
  f = p - lo,
  a = data[mode * 21 + lo],
  b = data[mode * 21 + hi];
table = new Float32Array(a.length);
for (let i = 0; i < a.length; i++) table[i] = a[i] + (b[i] - a[i]) * f;
Photoshot無料Photoshop代替の開発記 / 06IN PRACTICE

エディターで見る。

実際のPhotoshot作業画面。設定と写真を一緒に確認できます。
実際のPhotoshot作業画面。設定と写真を一緒に確認できます。

写真例と確認範囲

保存済みの写真例は、自然な彩度+30、彩度−5、保護オンです。AI生成の人物画像をポトショットで編集した画面と結果であり、初期開発当日の失敗画面ではありません。

AIが新しい色理論を発明したから可能になった例ではありません。読める公開実装を出発点に、独自計算と測定データをAIと接続した例です。既存技術を組み合わせ、必要な箇所を修正できてこそ、編集機能として使えます。

公開リポジトリのtests/vibrance.mjsは、両モードの初期値、アルファ保持、極端な値、不正な入力を検査します。本稿ではそのコードを確認しており、製品全体のテストを再実行したという意味ではありません。次回は、青など特定の色範囲を選ぶ処理に進みます。

Photoshot無料Photoshop代替の開発記 / 06BEFORE / AFTER

写真で見る結果。

AI生成の動作例用写真 / 編集前
01 / AI生成の動作例用写真 / 編集前
Photoshotの出力 / 編集結果
02 / Photoshotの出力 / 編集結果

AI生成の動作例用写真。編集画面と出力画像は実際のPhotoshotで作成しました。