Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

はじめに

 スマホやデジカメで、夕暮れ、夜景、逆光、外光が差し込む暗い室内など、コントラストが強い環境で撮影すると、明るい部分が白くつぶれてしまったり、逆に、暗い部分が黒くつぶれてしまったりして、がっかりした経験はありませんか?
 これは、明るい部分や暗い部分の階調が足りなくなってしまうためにおこる現象です。
 今回は、明るい画像と暗い画像をいいとこどりで合成して、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を使えば、自動でかなりよい合成ができることが分かったので、何かの際には活用したいと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away