フォトショになりたい
- 画像加工系の機能を一つづつ実装するだけ
概要
- トーンカーブ
- LUT
- 露出
- ガンマ
- 両対数スケール
- コントラスト
注: この記事はPython3 & OpenCV で画像処理を学ぶ[3] 〜 トーンカーブ と LUT を理解する実装実験と内容が鬼ほど被っています
トーンカーブ
要するに$[0, 255] \rightarrow [0, 255]$の関数
LUT
全ピクセルに毎回演算してたら重すぎてたまったもんじゃない
→$[0, 255] \rightarrow [0, 255]$で、基本的には整数値なのだから256×256の表があればいい
→LUT(Look Up Table)
トーンカーブ編集系のエフェクトは、全て「LUTをいじる→LUTに従って画像を変換する」とすると良い
function editLUT(img) {
const lut = new Array(256);
for (let i = 0; i < 256; i += 1) {
let val = hoge(i); //ここでエフェクトをかける
lut[i] = val;
}
LUT(img, lut);
return img;
}
露出
k倍するだけ
f(v) = kv
ただ、kが1を超える時に明るいところがクリップするので対処する
function exposure(x, t) {
return Math.min(x * t, 255);
}
ガンマ
正規化してγ乗するだけ
f(v) = v^\gamma
(詳しくはガンマ補正のうんちくを参照)
const gammaFunc = (val, gamma) => 255 * Math.pow(val / 255, 1 / gamma);
両対数スケール
ガンマよりも両端に関して滑らからしい
(詳しくはスケール対数曲線をトーンカーブとする画像補正を参照)
f(v) = \frac{{\rm log}(1+Cv)}{{\rm log}(1+C)}\\
逆関数:
f^{-1}(v) = \frac{e^{v{\rm log}(1+C)}-1}{C}
const log_log_scale = (v, C) =>
C == 0 ? v
: C > 0 ? 255*Math.log(1+v/255*C)/Math.log(1+C)
: -255*(Math.exp(v/255*Math.log(1-C))-1)/C;
コントラスト
暗いところをより暗く、明るいところをより明るく→S字カーブ
基本的にはシグモイドでいい
(詳しくはシグモイド関数でコントラスト強調を参照)
でも定義域が有界じゃないので少し修正してもいい
(詳しい議論はSigmoid曲線の定義域と値域を[0,1]にしたいだけを参照)
const pseudoSigmoid (x, t, MAX) => // Maxは255とか
t === 0 ? x
: t > 0 ? (Math.asinh((2 * x / MAX - 1) * Math.sinh(t)) / 2 / t + 0.5) * MAX
: (Math.sinh(t * (2 * x / MAX - 1)) / 2 / Math.sinh(t) + 0.5) * MAX;
中心の値をいじりたければシグモイド関数でコントラスト強調の実装が良さそう
まとめ
- トーンカーブはLUTを使って実装する
- この辺りの関数は後に他でも用いるので覚えておく