この記事にはプロモーションが含まれています。
画像処理の勉強で、pythonでRAW画像の現像をすることがありました。
そのときに調べたことのいくつかを記録しておきます。
RAW画像ライブラリ rawpy
pythonでraw画像を読み出し・編集できるライブラリrawpyが便利なようなので、こちらでRAW現像していきます。
Sony, Canon, Nikonなどの一眼カメラでは、RAW画像フォーマットで画像を保存することができます。
最近では、スマホでもRAWフォーマット保存できるようになってきて、RAW画像が身近になってきました。
こちらのライブラリは、そのようにして保存されたRAW画像をpython上で扱えるようにするライブラリになってます。
動作環境
今回動作させた環境を記載しておきます。
- OS : Windows11
- Python 3.10.7
rawpyのインストール
まずは、rawpyを使用するpython環境にインストールします。
> pip install rawpy
なお、rawpyを使用するには、numpyが必須ライブラリになってます。
pythonのversionに応じたnumpyのversion依存性もあるので、公式HPを参考にnumpyのversionを上げておきましょう。
参考までに、23/3/19現在のrawpy動作に必要な各pythonでのnumpyのversion一覧表を転載しておきます。
Python | Numpy |
---|---|
3.7 | 1.14以上 |
3.8 | 1.17以上 |
3.9 | 1.19以上 |
3.10 | 1.21以上 |
3.11 | 1.23以上 |
pythonとインストールしているモジュールの確認コマンドを記載がてら、私の環境を記録しておきます。
# pythonのversion確認
> python --version
Python 3.10.7
# インストールパッケージの確認
> pip freeze
argumentparser==1.2.1
imageio==2.26.0
numpy==1.24.2
opencv-python==4.7.0.72
rawpy==0.18.0
なお、私はパッケージ管理をしやすくするため、できるたけインストール済みパッケージを少ない環境でコード作成作業するようにしてます。
今回はvenvでの仮想環境を使用していますが、venv環境の立ち上げ方はこちらの記事を参照してください。
rawpyの標準クラスpostprocessでお試しRAW現像
raw画像を準備したら、まずは動作確認を兼ねて、rawpyで現像してみましょう。
適当なrawファイルを用意して、以下のコードと同一階層に置いて、実行してください。
私は、手持ちのsony α7R IIIで撮影したRAW画像をこのコードの処理にかけてます。
import rawpy
import cv2
import os
raw_filename = '.\\test.ARW'
in_raw = rawpy.imread(raw_filename)
out_raw = in_raw.postprocess()
# data save
out_dir = ".\\"
outfilename = raw_filename.rsplit('\\')[-1].split('.')[0]
out_raw = cv2.cvtColor(out_raw, cv2.COLOR_RGB2BGR)
cv2.imwrite(os.path.join(out_dir, outfilename) + "_out_00_postprocess.jpg", out_raw)
rawpyのAPI仕様は以下を参考にしてみてください。
このpythonファイルを実行すると、『***_out_00_postprocess.jpg』という名前で現像後のファイルができます。
rawpyで現像できていることが確認できました。
rawpyとカメラ内の現像で何か違うのか
一眼で同時保存されたjpgと比較すると、今回のコードでRAWから現像した画像は少し違いがあります。
画像サイズが違う
画像サイズを比較すると、以下のようになります。
Raw画像サイズ | rawpyでの現像画像 | カメラ内での現像画像 |
---|---|---|
8000 x 5320 pixel | 7968 x 5320 pixel | 7952 x 4472 pixel |
まず、現像するとRaw画像のサイズより高さが小さくなります。
これは、おそらくレンズシェーディングが見えそうな画像領域は切り捨てられているためと思われます。 (Crop処理されている)
また、rawpyで現像するよりカメラ内で現像した画像の方が、幅は少しだけ小さく、高さはかなり小さくなってます。
この一つの理由はカメラ側でjpg保存する際の画像サイズのアスペクトを16:9にしているからになります。
ただ、これだけが理由なら、7968 ÷ 16 x 9 = 4482 pixelとなるため、幅を削る必要はないはずです。
数字のつじつまが合わない分は、レンズシェーディングが見えないように、より安全目にCrop処理しているということでしょうか。
逆に言うと、7968 – 7952 = 16 pixel分しかレンズシェーディングが激しく見える領域はない??、、、
ものによっては、明らかなレンズシェーディングのために切り捨てているようなものもあると思います。(スマホの広角カメラとかはそうかな?)
ただ削っている画素数が少ないですし、今回はどうでしょうね。少し違和感ありますが、他の理由が思いつかないです。
まとめると、以下がカメラ内現像画像との画像サイズの差の要因だと思われます。
ホワイトバランスが違う
白い領域の色味が明らかに違うので、適用されているホワイトバランス(White Balance)の値が違うと思われます。
では、なんでこのようなことになっているのでしょうか。
どうやら、rawpyのpostprocessクラスは何も指定していないと、昼光のホワイトバランスのパラメータを使用するそうです。
そこで、postprocessの実行を以下のように書き換えて、撮影時のホワイトバランス値を使用するようにします。
out_raw = in_raw.postprocess(use_camera_wb = True)
再実行してできた現像画像を比較すると、以下の通り。
色味がかなり近くなりました。
あれ?ホワイトバランスのパラメータっていくつも埋め込まれているの?と思った方。
この辺りは使っているカメラに依ると思いますので、こちらの記事を参考にExif情報を確認してみてください。
ガンマカーブ・白レベルが違う
ホワイトバランスをそろえても、画像の明るさに違います。
これは適用されているガンマカーブや白としてクリップする出力値に差があると思われます。
突き詰めていくと、カメラ内現像と同じ結果が得られるようになっていくはずですが、だんだん細かいところに入っていくので、これ以上の深入りは止めてきます。
まとめ
今回は、pythonでraw現像するためのライブラリrawpyについて、その導入について記載しました。
まずはお試しで、ライブラリで用意されているpostprocessクラスで現像しました。
別途、これから簡単な現像処理についても、記事を起こそうと思います。
コメント