粗大メモ置き場

個人用,たまーに来訪者を意識する雑記メモ

OpenCV Python でHDR画像を合成してみよう

趣味全開です。趣味と実益とごっちゃになってきてます。
良いんだか悪いんだか。

Google PhotoのHDRレンダリング

Google PhotoにはHDRレンダリング機能があります。
feb29.org

つまりこんなかんじのこと。
f:id:ossyaritoori:20170918165509p:plain

これスマホの写真でやりたい!という記事になります。

追記:iPhoneを始め多くのカメラにはHDR機能が搭載されているそうな。知りませんでした…。
しかし以前手ブレの問題はあるのでかろうじて意義はあります。

以下説明

通常カメラが取る画像には明るさの幅に限界があって(ダイナミックレンジといいます)明るい所と暗い所を同時にきれいにとれないという問題が有ります。
結果、人間が見てきれいだと思う風景もカメラで取るとなんだか物足りない、ということになります。

そこで暗い画像と明るい画像を合成して人間が見た風景に近づけるのがこのHDRという技術です。

残念ながらGooglePhotoでは現状はスマホで取った画像ではHDR合成をしてくれないようです。
OpenCVにはHDR合成のサンプルコードがあるのでこれをうまく使って合成を試みてみようという試みになります。
OpenCV: High Dynamic Range (HDR)

レッツゴー!

1.手ぶれ補正

手で取るので必ずしも同じ画像とは限りませんね。このブレをなんとか補正したいです。
手ブレを微小回転と仮定し、SIFT特徴点を用いて回転を補正するコードを書けばいいんでなかろうか。

この論文とかそれっぽい。
A study on the compensation of image rotation for optical three-dimensional microscope - IEEE Conference Publication

追記1

OpenCV3ではSIFTが使えないのでAKAZEを使いました。
また,画像の変形はとりあえずホモグラフィー変換を用いましたがきちんとした式を建てると解くのが大変そうです。
これってちょっとした技術誌書けるんではないだろうか?

オプティカルフローからワープを推定してうまいこと処理する必要がありそうですがアイデアとしては既にどこかがやっているかと思われます。

追記2

訂正。並進要素のない微小回転とホモグラフィーワープは計算してみたら等価でした。

image stabilization(手ぶれ補正)で調べると結構関連記事が出てきます。
matlabの情報は古くAffineワープを使っていますが
Video Stabilization Using Point Feature Matching - MATLAB & Simulink
IEEEにもそれっぽい記事があります。うーん流石にちゃんと研究されていますね笑。
Video stabilization using classification-based homography estimation for consumer video camera - IEEE Conference Publication

ソース?

対応点から微小回転の射影変換行列を求めるmファイル。
三軸回転と焦点距離に関して式がでるので本当は4変数ですが線形方程式で解きたかったので5変数で解きます。ホモグラフィーの9変数より変数が少ないのでノイズには多少強いはず。ニッチなプログラムだなぁ。

function H = solveHomo_2(pts1,pts2)
%	H is 3*3, H*[pts1(:,i);1] ~ [pts2(:,i);1], H(3,3) = 1
%	the solving method see "projective-Seitz-UWCSE.ppt"

n = size(pts1,2);
x1 = pts1(1,:)';
x2 = pts2(1,:)';
y1 = pts1(2,:)';
y2 = pts2(2,:)';
zero = zeros(n,1);
one = ones(n,1);

A = [zero,-one, y1, x2.*y1, -x2.*x1, x2-x1;
    one, zero, -x1, y2.*y1, -y2.*x1, y2-y1];

%[evec,fuga] = eig(A'*A);
[U W V] = svd(A);
evec = V(:,6);

evec = evec/evec(end);
H = [1 -evec(3) evec(2); evec(3) 1 -evec(1); -evec(5) evec(4) 1];

end


でもよく考えたら中心点がわからないから正規化もできないし、その分も未知変数にすると結局8変数を推定することになるので普通に射影変換を求めれば良いという結論になりうる…

2.レンダリング

これはOpenCVのソースみれば書けそうな気がします。あとで書く。
OpenCV: High Dynamic Range (HDR)

やるよ。

追記1

よくみたら露光時間とかいう要素がありました。
なるほど携帯のカメラではまだそこまでやってくれませんね。

ゆくゆくは輝度値からうまく推定すべきでしょうが割りと適当でもそれなりにうまくいくようです。

やってみた

元画像はこちら。

暗い画像

明るい画像

どうしても空などと一緒に撮るとこういうことになっちゃいます。

位置ズレ補正

三脚ではなく手で連写するのでそのまま重ねると位置があわずに死にます。

ダブるでしょ。これを補正したいわけです。

AKAZEのマッチング結果と補正結果
f:id:ossyaritoori:20170918163755p:plain
遅くて今まで使ってなかったけど結構出来るやつですね。
重いので小さい画像で勘弁。

ちょっと回転とかが補正された後です。
f:id:ossyaritoori:20170918163807p:plain
わりと綺麗に補正されていますがより複雑なシーンだとホモグラフィーワープでは綺麗にいかないでしょう。
追記:極端な近景やカメラの並進がない限りはホモグラフィーで平気そうです。

重ねた結果

なんか複数手法があるらしく,よくわからないけど一番それっぽいのを一個見せます。


波とか動く部分があると粗はでますがわりと綺麗になったのではないでしょうか。

なるほど,意外といろいろ気を遣う部分があって製品?として公開してくれないというのはそういうことなのかなぁと思いました。

コード

現在修正中。来週の休みにでもGitにあげておきます。

今のところこんな感じ。
github.com

改善点

  • ワープ推定の数式の改良。
  • 露光時間比推定アルゴリズム実装
  • 色鮮やかにするフィルタの適用

がメインの課題でしょうか。3つ目はおまけですが。