rawpyの現像関数、postprocessの引数であるno_auto_brightと、auto_bright_thrに関して、値の意味を確認していきます。
postprocessに関しての詳細はこちら。
auto bright
自動明るさ補正ですね。やっていることはRGBの値にゲインをかけて、0~255(8bit)のレンジをフルに使うように補正をかけているものです。このオプションはデフォルトでON(no_auto_bright=False)なのでこれをキャンセルするパラメータはno_auto_bright=True。ややこしいです。
$$R_{out}=gain\times R_{in}\\ G_{out}=gain\times G_{in}\\ B_{out}=gain\times B_{in} $$
の計算をしているだけのように見えます。ポイントはgainはRGBすべてに対して同じ値。当然ですね。せっかくホワイトバランスを調整したのに、RGBバラバラにゲイン掛けたらせっかく調整したホワイトバランスが台無しですから。
auto_bright_thr
このgainを求める計算に使う閾値が、auto_bright_thrになります。これは全体の画素数の何%を255に張り付けるか?を指定するもので、デフォルトの0.01は全体の画素の1%が255になるようにgainを求めよ。との指定になります。
ここでの「255になるように」の意味ですが、どうやらRGBそれぞれで求めたgainの最小値を使う。というのが仕様のようです。つまり、一番明るい方に偏っている色で求めたgainを使うことで、この処理をした後、白飛びは最小限になるように考慮されているようです。
RGBのうち、どれかのチャンネルだけが1%の画素数だけ255に張り付く。という動きをするようです。
RGBからGray変換したいわゆる輝度でgainを求めているのかな?と予想しましたが、実験してみたところそうはなってませんでした。
実験
動きを確認してみます。現像後の画像のヒストグラムの最大値(255の画素数)が全画素数の何パーセントあるか、パラメータを振って確かめてみます。
コードはこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import rawpy import numpy as np raw = rawpy.imread(filename) img = raw.postprocess(half_size = True , no_auto_bright = False , auto_bright_thr = 0.01 ) histR, _ = np.histogram(img[:,:, 0 ], bins = 256 , range = ( 0 , 255 )) histG, _ = np.histogram(img[:,:, 1 ], bins = 256 , range = ( 0 , 255 )) histB, _ = np.histogram(img[:,:, 2 ], bins = 256 , range = ( 0 , 255 )) print ( "sumR:" , sum (histR), "lastR:" , histR[ 255 ], "rate:" , histR[ 255 ] / sum (histR)) print ( "sumG:" , sum (histG), "lastG:" , histG[ 255 ], "rate:" , histG[ 255 ] / sum (histG)) print ( "sumB:" , sum (histB), "lastB:" , histB[ 255 ], "rate:" , histB[ 255 ] / sum (histB)) |
np.histogramの使い方に関しては、別記事で詳細記述しました。
histR, histG, histBにそれぞれRGBのヒストグラムが格納されています。このhist[255]で得られるのが、画素値255の画素数。これが全体の何パーセントを占めるか?というのを検証してみます。
postprocessに与えているno_auto_brightとauto_bright_thrを動かして、結果を比較してみました。
no_auto_bright=True
補正OFFの場合です。結果は
sumR: 5287509 lastR: 10 rate: 1.8912497359342556e-06
sumG: 5287509 lastG: 3 rate: 5.673749207802767e-07
sumB: 5287509 lastB: 10 rate: 1.8912497359342556e-06
ヒストグラムは

でした。ほとんど255に行ってません。ややアンダーな感じの写真です。
no_auto_bright=False、auto_bright_thr=0.01
デフォルトです。結果は
sumR: 5287509 lastR: 54526 rate: 0.010312228310155122
sumG: 5287509 lastG: 14600 rate: 0.002761224614464013
sumB: 5287509 lastB: 5260 rate: 0.0009947973611014185
Rがおよそ0.01となってます。この場合gainはRedから求めたと思われます。ヒストグラムは

です。最小値は変わらず、右に引き延ばされている様子がわかります。この場合、BとGが255に張り付いている画素数は1%未満です。
no_auto_bright=False、auto_bright_thr=0.02
閾値を2%にしてみました。結果は
sumR: 5287509 lastR: 109691 rate: 0.020745307478436444
sumG: 5287509 lastG: 24263 rate: 0.004588739234297284
sumB: 5287509 lastB: 10629 rate: 0.0020102093443245205
です。Redの255の画素数がおよそ2倍にになってます。他のチャネルは必ずしも2倍にはなっていません。(Blueがおよそ2倍はたまたま)
想定通りです。(というか実験から仕様を推定しているので…)
まとめ
自動明るさ補正をつかさどるno_auto_brightおよびauto_bright_thrは、ガンマ補正する前のRGBのうち最も明るい方に偏ったチャネルの画素が全体のauto_bright_thrだけ255になるようにRGBそれぞれにgainを乗じる。
ということのようです。
追記
別のbright引数の検証の時に気づいたのですが、この処理はガンマ補正がされる前のRGB信号に対して行われていそうです。ガンマ補正をON(1/2.22乗)にした状態で、no_auto_brightのTrueを横軸、Falseを縦軸にグラフ(散布図)を書くと、

に対して、ガンマをOFF相当の
gam = [1.00, 0.00]
として
1 2 3 4 5 6 7 8 9 | off = raw.postprocess(half_size = True , no_auto_bright = True , gamma = gam, auto_bright_thr = 0.01 ) img = raw.postprocess(half_size = True , no_auto_bright = False , gamma = gam, auto_bright_thr = 0.01 ) |
の2つの画像の関係(散布図)を書いてみると、見事に直線になりました。

このことからも、ガンマ補正前の信号に対して掛け算してそうです。というかガンマ補正が最後の処理なのかな。
コメント