画像の平行移動位置あわせ(差の二乗を使用)の例
画像の平行移動位置あわせ(差の二乗を使用)の例
前準備
- Octave のインストールが済んでいること.
必見 Web ページ: http://www.csse.uwa.edu.au/~pk/Research/MatlabFns/
必見 Web ページ: http://www.eecs.berkeley.edu/Research/Projects/CS/vision/bsds/
* Octave のプロンプトを変えたいときは,次のように操作する.
PS1('> ')
* Octave のインストールによっては,Octave の起動時に毎回次の操作を行う必要があるかもしれない
pkg load image
プログラムのソースコード
# 2つの濃淡画像について,差の二乗の総和が最小になるように平行移動位置合わせ # 画像を平行移動し,2つの画像の重なる部分の全画素についての,差の二乗の総和を求め,それを画素数で割る.それが最小になるような平行移動量を求めたい. function err = compare_mat( A, B, dy, dx ) # 引数の並びは dy が先で dx が後 # dx > 0 かつ dy > 0 のときは, # A の右下部分と B の左上部分との比較. # 「A の右下部分」というのは,A の上 dy 行,左 dy 列を取り除いた残り # 「B の左下部分」と「A の右下部分」が同じサイズになるように # A, B から部分を取り出して比較に使う. # dx, dy が負のときは「A の右下部分」が左上、左下、左上に変わる # 縦と横を知る heightA = size(A)(1); widthA = size(A)(2); heightB = size(B)(1); widthB = size(B)(2); if ( ( dx >= 0 ) & (dy >= 0) ) # A 左上 から dx, dy 分は使わない.残りを AA へ. # dx = 0, dy = 0 ならば A と AA は等しい AA = A(1 + dy:heightA, 1 + dx:widthA); # BB は 左上 から AA と同じ分だけ使う BB = B(1:size(AA)(1), 1:size(AA)(2)); elseif ( ( dx >= 0 ) & (dy < 0) ) AA = A(1:heightA + dy, 1 + dx:widthA); BB = B(1 - dy:size(AA)(1) - dy, 1:size(AA)(2)); elseif ( ( dx < 0 ) & (dy >= 0) ) AA = A(1 + dy:heightA, 1:widthA + dx); BB = B(1:size(AA)(1), 1 - dx:size(AA)(2) - dx); elseif ( ( dx < 0 ) & (dy < 0) ) AA = A(1:heightA + dy, 1:widthA + dx); BB = B(1 - dy:size(AA)(1) - dy, 1 - dx:size(AA)(2) - dx); endif # 各要素の差を取り,その2乗の総和を求め、AA のサイズで割る Z = AA - BB; err = sum( sum( Z .* Z ) ) / ( size(AA)(1) * size(AA)(2) ); clear AA; clear BB; clear Z; endfunction function [x, y, val] = registration(gray1, gray2, y1, y2, x1, x2) # 画像の平行移動位置あわせ(総当たりによる方法) # x, y が移動量.val はそのときの「相違度」 # 2つの濃淡画像gray1, gray2 で,「相違度」が小さくなるように,画像をずらしたい. # 関数 compare_mat を補助的に使い, # y1, y2, x1, x2 は移動の範囲. # この範囲の中をすべて試し,最も「相違度」が小さいものを評価結果 [x, y, val] とする. # 結果の格納用の配列を作る d = ones(y2 - y1 + 1, x2 - x1 + 1) * 256; # rangeX, rangeY はずらす量 # 単純な総当たり rangeX = [x1:x2]; rangeY = [y1:y2]; for i = [1:size(rangeX)(2)] for j = [1:size(rangeY)(2)] # 行列 d には相違度の値を格納 d(j, i) = compare_mat( gray1, gray2, rangeY(j), rangeX(i) ); endfor endfor # 最も小さい値を持つのはどこか? [val_vec, index_vec] = min(d); [val, ix] = min(val_vec); iy = index_vec(ix); x = rangeX(ix); y = rangeY(iy); clear d; clear rangeX; clear rangeY; endfunction function [x, y, val] = registration_random(gray1, gray2, Nsamples, y1, y2, x1, x2) # 画像の平行移動位置あわせ(ランダムサンプリングによる方法) # x, y が移動量.val はそのときの「相違度」 # 2つの濃淡画像gray1, gray2 で,「相違度」が小さくなるように,画像をずらしたい. # 関数 compare_mat を補助的に使い, # ランダムに試してみる. # Nsample はサンプル数,y1, y2, x1, x2 は移動の範囲. # このサンプル数の試行の中で最も「相違度」が小さいものを評価結果 [x, y, val] とする. # 一様乱数 Nsamples 個ずつ.rx, ry は列ベクトル(N行1列のベクトル) rx = ceil( rand(Nsamples,1) * ((x2 - x1) + 1) ) + (x1 - 1); ry = ceil( rand(Nsamples,1) * ((y2 - y1) + 1) ) + (y1 - 1); # 試す for i = [1:Nsamples] similar(i) = compare_mat( gray1, gray2, ry(i), rx(i) ); endfor [val, index] = min(similar); x = rx(index(1)); y = ry(index(1)); endfunction function [x, y, v] = registration_pyramid(gray1, gray2, N ) # find the minimum using pyramid way # まず「小さい」画像を作って,それで位置あわせを行うことにしたい # その小さい画像のサイズを求める.N より小さくならないようにする MI = min( [size(gray1)(1) size(gray1)(2) size(gray2)(1) size(gray2)(2)] ); # REPEAT は,「1/2 に縮小する」処理を何回行うと「小さい」画像になるか REPEAT = floor( log2(MI) - log2(N) ) # 「小さい」画像 A, B を作る A = imresize( gray1, 1/(2^REPEAT), 'cubic' ); B = imresize( gray2, 1/(2^REPEAT), 'cubic' ); # せめて A, B の上下 1/3 が重なり,左右 1/3 が重なるように dy = floor( min( [size(A)(1) * 0.67 size(B)(1) * 0.67] ) ); dx = floor( min( [size(A)(2) * 0.67 size(B)(2) * 0.67] ) ); [rx, ry, val] = registration(A, B, -dy, dy, -dx, dx); clear A; clear B; for i = (REPEAT-1):-1:0 disp "." # 前回よりも縦横2倍大きい画像 A = imresize( gray1, 1/(2^i), 'cubic' ); B = imresize( gray2, 1/(2^i), 'cubic' ); # それほど広い範囲を探す必要は無い.2画素分でいいだろう [new_rx, new_ry, val] = registration(A, B, ry * 2 - 2, ry * 2 + 2, rx * 2 - 2, ry * 2 + 2); rx = new_rx; ry = new_ry; clear A; clear B; endfor x = rx; y = ry; v = val; endfunction # 画像ファイル 2つを読み込み rgb1 = imread("/tmp/441.png"); rgb2 = imread("/tmp/442.png"); gray1 = rgb2gray( rgb1 ); gray2 = rgb2gray( rgb2 ); [x y v] = registration_pyramid(gray1, gray2, 64); x y v # For debug and test of functions # compare_mat( gray1, gray2, 0, 1 ); # # [rx, ry, val] = registration(gray1, gray2, 0, 50, 0, 50); # rx # ry # val # # [rx2, ry2, val2] = registration_random(gray1, gray2, 1000, 0, 50, 0, 50); # rx # ry # val2
実行方法と実行結果の例
次の 2つの画像の平行移動位置あわせを行っている例です. (この画像は lena 標準画像から切り抜いて作ったもの). 1つ目の画像の変異量(左が正で、右が負で、上が正で、下が負)を求めます.
この種のソフトは,探せば同様のが見つかるとも思いますが, Octave の中に組み込んで使う(つまり,平行移動位置あわせの結果をさらにいろいろな用途に使う)とか, 平行移動位置あわせのやり方を細かく調整することをしたくて,Octave のソースコードプログラムを自前で書くことにした.
* この 2つの画像のファイルは,前準備として /tmp に保存しておくこと.
《1つ目》
《2つ目》
- (オプション)Cygwin からリモートログインする場合
startx xhost + ssh -X username@ipaddress
- ソースコードをファイルとして保存
- Octave を起動
- Octave の source コマンドを使って実行
cd <ソースコードのファイルを置いたディレクトリ> source "<ソースコードのファイル名>"
- 実行が終わるまで待つ