LoginSignup
34
40

More than 5 years have passed since last update.

OpenCVとPythonでHigh Dynamic Range Image (HDR)を作ってみる(Mertens, Robertson, Debevec)

Last updated at Posted at 2016-09-26

はじめに

 スマホやデジカメで、夕暮れ、夜景、逆光、外光が差し込む暗い室内など、コントラストが強い環境で撮影すると、明るい部分が白くつぶれてしまったり、逆に、暗い部分が黒くつぶれてしまったりして、がっかりした経験はありませんか?
 これは、明るい部分や暗い部分の階調が足りなくなってしまうためにおこる現象です。
 今回は、明るい画像と暗い画像をいいとこどりで合成して、High Dynamic Range Imageを作ってみます。

環境

  • OpenCV: 3.1.0
  • Python: 3.5.2

これから環境構築をこちらを参考にしてください。
OpenCV 3とPython 3の環境構築

処理前の画像

サムネイル.png

露出を2段階づつ変えて撮影したJPEG画像が3枚。
綺麗に合成させるためには、カメラを固定して、絞りを同じにし、露光時間だけを変化させて、連続撮影するとよいです。

HDR処理後

OpenCVで処理した画像。

  • Mertens fusion_mertens.jpg  
  • Debevec ldr_debvec.jpg  
  • Robertson ldr_robertson.jpg

プログラム

hdr.py
# -*- coding: utf-8 -*-
import cv2
import numpy as np

# 3枚の画像ファイルを読み込む
img_fn = ["img1.jpg", "img2.jpg", "img3.jpg"]
img_list = [cv2.imread(fn) for fn in img_fn]

# 3枚の画像に対して露出時間をセット
exposure_times = np.array([0.2, 0.05, 0.0125], dtype=np.float32)

# Debevec法によるHDR合成
merge_debvec = cv2.createMergeDebevec()
hdr_debvec = merge_debvec.process(img_list, times=exposure_times.copy())
tonemap1 = cv2.createTonemapDurand(gamma=2.2)
res_debvec = tonemap1.process(hdr_debvec.copy())

# Robertson法によるHDR合成
merge_robertson = cv2.createMergeRobertson()
hdr_robertson = merge_robertson.process(img_list, times=exposure_times.copy())
tonemap2 = cv2.createTonemapDurand(gamma=2.2)
res_robertson = tonemap2.process(hdr_robertson.copy())

# Mertens法によるHDR合成
merge_mertens = cv2.createMergeMertens()
res_mertens = merge_mertens.process(img_list)

# 8ビットデータに変換
res_debvec_8bit = np.clip(res_debvec*255, 0, 255).astype('uint8')
res_robertson_8bit = np.clip(res_robertson*255, 0, 255).astype('uint8')
res_mertens_8bit = np.clip(res_mertens*255, 0, 255).astype('uint8')

# 画像をファイルに保存
cv2.imwrite("ldr_debvec.jpg", res_debvec_8bit)
cv2.imwrite("ldr_robertson.jpg", res_robertson_8bit)
cv2.imwrite("fusion_mertens.jpg", res_mertens_8bit)

写真の枚数が3枚、露出が-2, 0, +2の場合、次のようになります。
img_fn = ["img1.jpg", "img2.jpg", "img3.jpg"]
exposure_times = np.array([0.2, 0.05, 0.0125], dtype=np.float32)

写真の枚数が5枚、露出が-2, -1, 0, +1, +2だったら、この部分を次のように変更します。
img_fn = ["img1.jpg", "img2.jpg", "img3.jpg", "img4.jpg", "img5.jpg"]
exposure_times = np.array([0.2, 0.1, 0.05, 0.025, 0.0125], dtype=np.float32)

おわりに

 今回、パラーメータ調整を一切しなかったMartens法で、迫力のある画像を合成することができました。他のサンプル画像〔1〕でもいろいろと試しましたが、3つの中では、Martens法が見た目に優れていました。
 HDR関連の機能として、OpenCVにはトーンマップ調整用関数(Drago, Durand, Reinhard, Mantiuk)や、キャリブレーション用関数(Debevec, Robertson)なども用意されています。
 OpenCVを使えば、自動でかなりよい合成ができることが分かったので、何かの際には活用したいと思います。

34
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
40