OpenCVでHDR(High Dynamic Range Imaging)

以下を参考にした。ほぼ丸写し。
高ダイナミック・レンジ — OpenCV-Python Tutorials
画像は以下から。
High-dynamic-range imaging - Wikipedia


参考にしたサイトでは3種類の手法を紹介しているがここではmertens融合だけ。リストは露光時間の長い方から並べてある。

import cv2
import numpy as np

img_fn = ["img0.jpg", "img1.jpg", "img2.jpg", "img3.jpg"]
img_list = [cv2.imread(fn) for fn in img_fn]

merge_mertens = cv2.createMergeMertens()
res_mertens = merge_mertens.process(img_list)
res_mertens_8bit = np.clip(res_mertens*255, 0, 255).astype('uint8')
cv2.imwrite("hdr0.jpg", res_mertens_8bit)

https://kakasi.skr.jp/images/hdr0.jpg
各画像の位置がズレてる。位置ズレを修正してくれる関数があるのでそれを使う。

import cv2
import numpy as np

img_fn = ["img0.jpg", "img1.jpg", "img2.jpg", "img3.jpg"]
img_list = [cv2.imread(fn) for fn in img_fn]

mtb = cv2.createAlignMTB()
mtb.process(img_list, img_list)

merge_mertens = cv2.createMergeMertens()
res_mertens = merge_mertens.process(img_list)
res_mertens_8bit = np.clip(res_mertens*255, 0, 255).astype('uint8')
cv2.imwrite("hdr1.jpg", res_mertens_8bit)

https://kakasi.skr.jp/images/hdr1.jpg
更にズレが大きくなった。一番暗い画像を外してやってみる。
https://kakasi.skr.jp/images/hdr2.jpg
良さそう。

4枚全部使いたいのでphaseCorrelateで位置合わせしてみた。
はじめ一番明るい画像と残りの3枚を突き合わせてみたところ、一番暗い画像が大幅にずれてしまったので、以下のコードでは露光時間の近いもの同士で比較している。

import cv2
import numpy as np

img_fn = ["img0.jpg", "img1.jpg", "img2.jpg", "img3.jpg"]
img_list = [cv2.imread(fn) for fn in img_fn]

for i in range(len(img_fn) - 1):
    gry1 = cv2.cvtColor(img_list[i], cv2.COLOR_BGR2GRAY)
    gry2 = cv2.cvtColor(img_list[i+1], cv2.COLOR_BGR2GRAY)
    gry1 = np.array(gry1, 'float32')
    gry2 = np.array(gry2, 'float32')
    (x, y), z = cv2.phaseCorrelate(gry1, gry2)
    M = np.float32([[1, 0, -x], [0, 1, -y]])
    h, w = gry2.shape
    img_list[i+1] = cv2.warpAffine(img_list[i+1], M, (w, h))

merge_mertens = cv2.createMergeMertens()
res_mertens = merge_mertens.process(img_list)
res_mertens_8bit = np.clip(res_mertens*255, 0, 255).astype('uint8')
cv2.imwrite("hdr3.jpg", res_mertens_8bit)

https://kakasi.skr.jp/images/hdr3.jpg