图像旋转和缩放频域?

时间:2012-12-06 13:02:09

标签: math image-processing numpy fft transformation

我正在编写一些代码来使用相位相关a la Reddy & Chatterji 1996来恢复测试图像相对于模板的旋转,缩放和平移。我采用原始测试图像的FFT来查找比例因子和旋转角度,但我需要使用旋转和缩放测试图像的FFT来获得平移。

现在我可以在空间域中应用旋转和缩放然后进行FFT,但这似乎有点低效 - 是否有可能直接获得旋转/缩放图像的傅里叶系数频域?

编辑1: 好的,我按照用户1816548的建议玩了一下。虽然图像的极性发生了奇怪的变化,但对于90o倍数的角度,我可以得到模糊的合理旋转。不是90o的倍数的角度给我带来了非常好的结果。

编辑2: 我已经对图像应用了零填充,当我旋转它时,我正在包裹FFT的边缘。我很确定我正在围绕FFT的DC分量进行旋转,但对于不是90o倍数的角度,我仍然会得到奇怪的结果。

示例输出:


10o rotation angle

可执行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

3 个答案:

答案 0 :(得分: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]左右旋转。我不能完全解释这里发生了什么,但你也得到了同样的效果。要在傅里叶域中旋转原始图像,必须先将2D fftShift应用于原始图像M,然后计算FFT,旋转,IFFT,然后应用ifftShift。这样,您的图像旋转中心和傅立叶域的中心就会同步。

AFAI记得我们也在两个独立的阵列中旋转实部和虚部,然后将它们合并。我们还在复数上测试了各种插值算法,效果不大:)。它位于我们的包pytom

然而,这可能是超级减少,但是除非你指定一些时髦的数组索引算法,否则两个额外的移位并不是很快。

答案 1 :(得分:2)

嗯,旋转和缩放的图像会导致旋转和缩放(使用反比例)傅里叶变换。

另请注意,旋转和缩放在像素数量上都是线性的,而FFT是O(w * logw * h * logh),所以它实际上并不是那么昂贵。

答案 2 :(得分:1)

我意识到这很晚了,但我只是想回答这里的问题,因为我回顾了我对换档不变性的基本知识。问题是你在旋转之前扩展了傅立叶空间(如,考虑了别名)。查看旋转图像的FT:轴向尖峰(别名)出现在傅立叶旋转的IFT中不存在的边缘。

你应该旋转然后处理别名。因为您要考虑锯齿(以周期=像素数循环您的傅立叶空间)然后通过旋转丢弃该效果,您将导致锯齿出现在最终图像中。基本上,你正在扩展傅里叶别名,因此将图像空间别名拉到一起。

旋转可以平稳地进行90度旋转,因为没有锯齿; k空间的角落完美匹配。