星空写真を撮影する際、カメラのレンズの特性によって写真の四隅が暗くなる「周辺減光」が発生することがあります。この問題を解決するために、様々な補正手段がありますが、今回はPythonを使用して効果的に補正する方法を紹介します。
必要な準備
まず、補正を行いたい星空写真を用意します。今回は次の写真を使います。写真の四隅にいくほど暗くなっています。

Lightroomでの補正
一般的に使われる補正ツールとして、Adobe Lightroomがあります。Lightroomを使用すると、四隅の減光を均等に補正できますが、自然さを欠く場合があります。以下の画像は、Lightroomで強調補正した例です。風景も四隅が白っぽくなり、不自然に見えるかもしれません。

Pythonによるカスタム補正
Lightroomに代わり、Pythonを使ったカスタム補正を試してみましょう。以下の手順で補正を行います:
- 画像の中心からの距離の2乗に比例して明るさを強くする。
- 右上と左上の明るさを強く補正し、右下と左下は弱く補正する。
import cv2
import numpy as np
# 画像読み込みと32bit表示
img = cv2.imread("filename").astype(np.float32) / 255.0
# 画像のサイズ取得
h, w = img.shape[:2]
size = max(h, w) # 幅と高さのうち、大きい方を取得
# 画像の中心からの距離で画像を作成
x = np.linspace(-w / size, w / size, w)
y = np.linspace(-h / size, h / size, h) # 長辺が1になるように正規化
xx, yy = np.meshgrid(x, y)
r = np.sqrt(xx**2 + yy**2)
# 距離画像にゲインを乗じ、ゲインマップを作成
gain = 1.0 * r**2 + 1
gainmap = np.dstack([gain] * 3) # RGBに同じゲインマップを適用
# 上下左右の補正強度マップを作成
vertical_gradient = np.linspace(1.0, 0.5, h).reshape(h, 1)
horizontal_gradient = np.linspace(1.0, 0.5, w).reshape(1, w)
gradient_map = np.minimum(vertical_gradient, horizontal_gradient)
gradient_map = np.maximum(gradient_map, vertical_gradient[:, ::-1])
gradient_map = np.maximum(gradient_map, horizontal_gradient[::-1, :])
# 右下と左下の補正を弱くするために調整
for i in range(h):
for j in range(w):
if i > h / 2 and j < w / 2: # 左下
gradient_map[i, j] = np.maximum(gradient_map[i, j], 0.2)
elif i > h / 2 and j > w / 2: # 右下
gradient_map[i, j] = np.maximum(gradient_map[i, j], 0.2)
# RGBに適用
gradient_map_rgb = np.dstack([gradient_map] * 3)
# ゲインマップに補正強度マップを適用
gainmap *= gradient_map_rgb
# 逆ガンマ補正(2.2乗)
img = img ** 2.2
# 画像にゲインマップを乗じる
img = np.clip(img * gainmap, 0., 1.0)
# ガンマ補正(1/2.2乗)
img = img ** (1 / 2.2)
# 8bit化して保存
cv2.imwrite("modified_image.jpg", (img * 255).astype(np.uint8))
周辺減光の原理に基づいて、コサインカーブの逆数に比例させて明るさを調整する方法も考えられます。下記は補正前後の比較画像です(上が補正前、下が補正後)。かなり自然な仕上がりになったのではないでしょうか。


結論
星空写真の周辺減光を効果的に補正する方法として、Pythonを活用することで自由度の高い補正が可能です。写真全体のバランスを保ちながら、美しい星空を表現するための一例として参考にしてください。