7

位相相関を使用して、テンプレートに対するテスト画像の回転、スケーリング、および平行移動を復元するためのコードを作成しています。これは、Reddy&Chatterji1996です。倍率と回転角を見つけるために元のテスト画像のFFTを取得しますが、平行移動を取得するには、回転およびスケーリングされたテスト画像のFFTが必要です。

これで、空間領域で回転とスケーリングを適用してからFFTを取得できますが、それは少し非効率的です-回転/スケーリングされた画像のフーリエ係数を周波数領域で直接取得することは可能ですか?

編集1: OK、user1816548の提案に従って遊んだ。画像の極性に奇妙な変化がありますが、90°の倍数の角度で漠然と感覚的に見える回転を得ることができます。90°の倍数ではない角度は、かなりおかしな結果をもたらします。

編集2: 画像にゼロパディングを適用し、画像を回転させるときにFFTのエッジをラップしています。FFTのDC成分を中心に回転していることは確かですが、90°の倍数ではない角度でも奇妙な結果が得られます。

出力例:


10°回転角

実行可能Numpy/Scipyコード:


import numpy as np
from scipy.misc import lena
from scipy.ndimage.interpolation import rotate,zoom
from scipy.fftpack import fft2,ifft2,fftshift,ifftshift
from matplotlib.pyplot import subplots,cm

def testFourierRotation(angle):

    M = lena()
    newshape = [2*dim for dim in M.shape]
    M = procrustes(M,newshape)

    # rotate, then take the FFT
    rM = rotate(M,angle,reshape=False)
    FrM = fftshift(fft2(rM))

    # take the FFT, then rotate
    FM = fftshift(fft2(M))
    rFM = rotatecomplex(FM,angle,reshape=False)
    IrFM = ifft2(ifftshift(rFM))

    fig,[[ax1,ax2,ax3],[ax4,ax5,ax6]] = subplots(2,3)

    ax1.imshow(M,interpolation='nearest',cmap=cm.gray)
    ax1.set_title('Original')
    ax2.imshow(rM,interpolation='nearest',cmap=cm.gray)
    ax2.set_title('Rotated in spatial domain')
    ax3.imshow(abs(IrFM),interpolation='nearest',cmap=cm.gray)
    ax3.set_title('Rotated in Fourier domain')
    ax4.imshow(np.log(abs(FM)),interpolation='nearest',cmap=cm.gray)
    ax4.set_title('FFT')
    ax5.imshow(np.log(abs(FrM)),interpolation='nearest',cmap=cm.gray)
    ax5.set_title('FFT of spatially rotated image')
    ax6.imshow(np.log(abs(rFM)),interpolation='nearest',cmap=cm.gray)
    ax6.set_title('Rotated FFT')
    fig.tight_layout()

    pass

def rotatecomplex(a,angle,reshape=True):
    r = rotate(a.real,angle,reshape=reshape,mode='wrap')
    i = rotate(a.imag,angle,reshape=reshape,mode='wrap')
    return r+1j*i

def procrustes(a,target,padval=0):
    b = np.ones(target,a.dtype)*padval
    aind = [slice(None,None)]*a.ndim
    bind = [slice(None,None)]*a.ndim
    for dd in xrange(a.ndim):
        if a.shape[dd] > target[dd]:
            diff = (a.shape[dd]-target[dd])/2.
            aind[dd] = slice(np.floor(diff),a.shape[dd]-np.ceil(diff))
        elif a.shape[dd] < target[dd]:
            diff = (target[dd]-a.shape[dd])/2.
            bind[dd] = slice(np.floor(diff),target[dd]-np.ceil(diff))
    b[bind] = a[aind]
    return b
4

3 に答える 3

5

これがまだ解決されているかどうかはわかりませんが、3 番目の図で観察された効果に関する問題の解決策があると思います。

あなたが観察するこの奇妙な効果は、FFT を実際に計算する原点によるものです。基本的に、FFT は の配列の最初のピクセルから開始しM[0][0]ます。ただし、 を中心に回転を定義します。M[size/2+1,size/2+1]これは正しい方法ですが、間違っています :) 。フーリエ領域は から計算されましたM[0][0]! フーリエ領域で回転すると、 の周りM[0][0]ではなく、周りを回転していM[size/2+1,size/2+1]ます。ここで実際に何が起こっているのかを完全に説明することはできませんが、以前と同じ効果が得られます. フーリエ ドメインで元の画像を回転するには、最初に 2DfftShiftを元の画像 M に適用し、次に FFT、回転、IFFT を計算してから を適用する必要がありますifftShift。このようにして、画像の回転中心とフーリエ ドメインの中心が同期します。

AFAI は、実数成分と虚数成分を 2 つの別々の配列で回転させ、後でそれらをマージしたことを覚えています。また、複素数でさまざまな補間アルゴリズムをテストしましたが、あまり効果がありませんでした:)。それは私たちのパッケージpytomにあります。

ただし、これは非常に少ないかもしれませんが、いくつかのファンキーな配列インデックス演算を指定しない限り、2 つの追加のシフトで実際には高速ではありません。

于 2014-09-29T22:41:57.200 に答える
2

さて、回転およびスケーリングされた画像は、回転およびスケーリングされた (逆スケールの) フーリエ変換になります。

また、回転とスケーリングはどちらもピクセル数で線形ですが、FFT は O(w*logw*h*logh) であるため、実際にはそれほど高価ではないことに注意してください。

于 2012-12-06T13:26:11.407 に答える