非圧縮のRAWデータが好き勝手に書き換えられれば、
RAWと現像上がりのPC画像(8bit画像)との間のイロイロな関係が調べられる。
今回は14bitRAWの現像時に適用されるガンマ変換の特性について調べてみる。
・・・で、Excel VBAで非圧縮14bitRAWにグレイタイルを書き込むプログラムを作る。
まずはじめにワークシートに以下の入力データ欄を設ける。
ターゲットのRAWファイルをFolder欄とFile欄に分けて記入し、
ExifReaderの解析情報に基づいて画像幅・高さとStripOffset値を記入する。
(http://blog.goo.ne.jp/-odisama-/e/6aea7daa34b6afb111118a04c3dc5b6c参照)
Reference欄の値は後述するが、大抵は1120で対処できるだろう。
VBAプログラムは以下の通り。
Private Type Temp_Byte
TB(1) As Byte
End Type
Private Type Int_Data
ID As Integer
End Type
'--------------------
Sub GrayScale()
Dim DataMap(8, 6) As Integer
Dim LineData(899) As Integer
Dim MI As String * 2
Dim St_Offset As Long, Start_Ad As Long
Dim Y_Step As Long, Data_Ad As Long
Dim Ref As Integer
Dim N As Integer
Dim X As Integer, Y As Integer
'for Change Order
Dim A As Int_Data
Dim B As Temp_Byte
Dim C As Byte
Folder$ = Range("B2").Value
File$ = Range("B3").Value
Open Folder$ & "\" & File$ For Binary As #1
Get #1, , MI
Close #1
If MI <> "MM" And MI <> "II" Then End
FileCopy Folder$ & "\" & File$, Folder$ & "\GSc_" & File$
File$ = Folder$ & "\GSc_" & File$
Sr_Width% = Range("B5").Value '←センサ横Pix数
Sr_Height% = Range("B6").Value '←センサ縦Pix数
St_Offset = Range("B7").Value '←StripOffset
Offset_X% = (Sr_Width% - 900) \ 2
Offset_Y% = (Sr_Height% - 700) \ 2
Y_Step = Sr_Width% * 2
Start_Ad = St_Offset + Y_Step * Offset_Y% + Offset_X% * 2
Ref = Range("B4").Value
DataMap(0, 0) = 0
For N = 0 To 4
DataMap(N + 1, 0) = 2 ^ N
Next N
N = 6
Do
DataMap(N Mod 9, N \ 9) = Int(16 * 2 ^ ((N - 5) / 3) + 0.5)
N = N + 1
Loop While N < 35
DataMap(8, 3) = 16383
N = 36
Do
DataMap(N Mod 9, N \ 9) = Ref + 4 * (N - 36)
N = N + 1
Loop While N < 63
If MI = "MM" Then
For X = 0 To 8
For Y = 0 To 6
GoSub Change_Order
Next Y
Next X
End If
On Error GoTo Retry
Write_Data:
Y = 0
While Y < 700
For X = 0 To 899
LineData(X) = DataMap(X \ 100, Y \ 100)
Next X
Range("B8").Value = "Writing " & Y
Do
Data_Ad = Start_Ad + Y_Step * Y
Open File$ For Binary As #1
Put #1, Data_Ad + 1, LineData()
'Offset値は0~、VBのアクセスアドレスは1~
Close #1
Y = Y + 1
Loop While Y Mod 100 > 0
Wend
Range("B8").Value = "Finish"
Range("A1").Select
Exit Sub
'***** Sub-Routine ****************
Change_Order:
'Big Endianファイルの場合にデータのバイトオーダを入れ替える
A.ID = DataMap(X, Y)
LSet B = A
C = B.TB(0)
B.TB(0) = B.TB(1)
B.TB(1) = C
LSet A = B
DataMap(X, Y) = A.ID
Return
'------
Retry:
'FileCopy未完了で失敗した時はリトライする
Close #1
If Err.Number <> 75 Then
Range("B8").Value = "Error #" & Err.Number
Exit Sub
End If
DoEvents
Err.Clear
Resume Write_Data
End Sub
今回はターゲットRAWファイルを以下からD800の14bit FX Uncompressedを
入手して使用したが、14bitのベイヤー配列CFの非圧縮RAWならば他機種のNEFでも
DNGコンバータで非圧縮変換したDNGでも使用可能なように作ってある。
http://www.rawsamples.ch/index.php/en/
このプログラムを実行すると、元のファイル名に「GSc_」を冠したファイル名で
データが書き込まれたRAWが出来上がる。
コレを現像時にスポイト・ツールを使って書き込んだパターンのどこかを指定して
ホワイトバランスを取るとグレーのタイルパターンになる。
例えばCameraRAWで現像して、書き込んだパターンの部分だけを抜き出すと
こんなカンジになる。(タテ・ヨコともに1/2縮小)
タイル1マスの大きさは100 x 100 pixで横に9列、縦に7段配置されている。
上方の4段がグレースケールになっており、下方の3段が標準反射率18%に対応する
グレー濃度を探すためのスケールになっている。
具体的にはRAWファイルにRGB等値で以下の値を書きこんでいる。
まず上4段のグレースケールに関して・・・
最上段の1,2,4,8,16は2倍ずつの変化であり、露光量1EVずつの変化に相当する。
(RAWデータ値はこのシャドウ域でも受光量に正確に比例すると仮定した場合)
その後、16~13004までの変化は2の1/3乗(≒1.26)倍ずつの変化で、
露光量1/3EVずつの変化に相当する。
左上の0は倍数の系列にはなじまないが設定可能な最小値として作成した。
また最後端の16383は、本来の倍数系列なら16384になるべき場所だが14bitを
オーバーしてしまうので、1つ手前の16383としている。
下側3段(上表の黄色アミカケ)のスケールはReference欄の値(ここでは1120)を
左上にし、右下に向けて順次4ずつ値を(等差数列的に)増やしている。
さて、以上でRAWファイル上のデータの値は明らかになった。
これと現像後の各所のRGB値を画像ソフトのヒストグラムなどを駆使して見比べれば
その対応すなわちガンマ変換の様子を調べられる。
(ワタシはまたVBA使ってデータを自動で読取・整理させますけどね)
ガンマ変換を調べた結果はまた次回。