【rawpy】PythonでRAW現像 -その1 : rawpy導入編-

カメラ・信号処理

この記事にはプロモーションが含まれています。

画像処理の勉強で、pythonでRAW画像の現像をすることがありました。

そのときに調べたことのいくつかを記録しておきます。

RAW画像ライブラリ rawpy

pythonでraw画像を読み出し・編集できるライブラリrawpyが便利なようなので、こちらでRAW現像していきます。

rawpy
RAW image processing for Python, a wrapper for libraw

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一覧表を転載しておきます。

PythonNumpy
3.71.14以上
3.81.17以上
3.91.19以上
3.101.21以上
3.111.23以上
rawpy動作に必要なnumpyのversion一覧

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)
コード解説
  • 6行目 : raw_filename = ‘.\test.ARW’
    • rawファイルを指定してます。必要に応じて、rawファイル側かコード側を修正して実行してください。
  • 8行目 : out_raw = in_raw.postprocess()
    • このコードのメインの処理で、rawpyで用意されているRAW現像処理。
    • 現像後の画像はnumpy配列、チャンネルの並びは『RGB』です。
  • 13行目 : out_raw = cv2.cvtColor(out_raw, cv2.COLOR_RGB2BGR)
    • OPENCVが画像のチャンネルの並びがBGRなので、RGB→BGRに再配列。

rawpyのAPI仕様は以下を参考にしてみてください。

API Reference — rawpy 0.19.1 documentation

このpythonファイルを実行すると、『***_out_00_postprocess.jpg』という名前で現像後のファイルができます。

rawpyのpostprocess()クラスで現像した画像ファイル
一眼カメラで同時保存されたjpgファイル

rawpyで現像できていることが確認できました。

rawpyとカメラ内の現像で何か違うのか

一眼で同時保存されたjpgと比較すると、今回のコードでRAWから現像した画像は少し違いがあります。

画像サイズが違う

画像サイズを比較すると、以下のようになります。

Raw画像サイズrawpyでの現像画像カメラ内での現像画像
8000 x 5320 pixel7968 x 5320 pixel7952 x 4472 pixel

まず、現像するとRaw画像のサイズより高さが小さくなります。

これは、おそらくレンズシェーディングが見えそうな画像領域は切り捨てられているためと思われます。 (Crop処理されている)

また、rawpyで現像するよりカメラ内で現像した画像の方が、幅は少しだけ小さく、高さはかなり小さくなってます。

この一つの理由はカメラ側でjpg保存する際の画像サイズのアスペクトを16:9にしているからになります。

ただ、これだけが理由なら、7968 ÷ 16 x 9 = 4482 pixelとなるため、幅を削る必要はないはずです。

数字のつじつまが合わない分は、レンズシェーディングが見えないように、より安全目にCrop処理しているということでしょうか。

逆に言うと、7968 – 7952 = 16 pixel分しかレンズシェーディングが激しく見える領域はない??、、、

ものによっては、明らかなレンズシェーディングのために切り捨てているようなものもあると思います。(スマホの広角カメラとかはそうかな?)

ただ削っている画素数が少ないですし、今回はどうでしょうね。少し違和感ありますが、他の理由が思いつかないです。

まとめると、以下がカメラ内現像画像との画像サイズの差の要因だと思われます。

画像サイズの差
  • 保存する画像サイズのアスペクト (16:9)
  • レンズシェーディング領域の切り捨て

ホワイトバランスが違う

白い領域の色味が明らかに違うので、適用されているホワイトバランス(White Balance)の値が違うと思われます。

では、なんでこのようなことになっているのでしょうか。

どうやら、rawpyのpostprocessクラスは何も指定していないと、昼光のホワイトバランスのパラメータを使用するそうです。

そこで、postprocessの実行を以下のように書き換えて、撮影時のホワイトバランス値を使用するようにします。

out_raw = in_raw.postprocess(use_camera_wb = True)

再実行してできた現像画像を比較すると、以下の通り。

rawpy現像 : オプション指定なし
rawpy現像 : use_camera_wb = True
カメラ内現像

色味がかなり近くなりました。

あれ?ホワイトバランスのパラメータっていくつも埋め込まれているの?と思った方。

この辺りは使っているカメラに依ると思いますので、こちらの記事を参考にExif情報を確認してみてください。

ガンマカーブ・白レベルが違う

ホワイトバランスをそろえても、画像の明るさに違います。

これは適用されているガンマカーブや白としてクリップする出力値に差があると思われます。

突き詰めていくと、カメラ内現像と同じ結果が得られるようになっていくはずですが、だんだん細かいところに入っていくので、これ以上の深入りは止めてきます。

まとめ

今回は、pythonでraw現像するためのライブラリrawpyについて、その導入について記載しました。

まずはお試しで、ライブラリで用意されているpostprocessクラスで現像しました。

別途、これから簡単な現像処理についても、記事を起こそうと思います。

コメント

タイトルとURLをコピーしました