在numpy/scipy中快速进行二维刚体变换

5

我想将刚体变换应用于一组大量的2D图像矩阵。理想情况下,我希望能够只提供一个仿射变换矩阵来指定平移和旋转,并在一次操作中应用它,然后对输出进行三次样条插值。

不幸的是,scipy.ndimage.interpolation 中的 affine_transform 不会执行平移。我知道我可以使用 shiftrotate 的组合,但这有点麻烦,还需要多次对输出进行插值。

我还尝试过使用通用的 geometric_transformation 实现:

import numpy as np
from scipy.ndimage.interpolation import geometric_transformation

# make the affine matrix
def maketmat(xshift,yshift,rotation,dimin=(0,0)):

    # centre on the origin
    in2orig = np.identity(3)
    in2orig[:2,2] = -dimin[0]/2.,-dimin[1]/2.

    # rotate about the origin
    theta = np.deg2rad(rotation)
    rotmat = np.identity(3)
    rotmat[:2,:2] = [np.cos(theta),np.sin(theta)],[-np.sin(theta),np.cos(theta)]

    # translate to new position
    orig2out = np.identity(3)
    orig2out[:2,2] = xshift,yshift

    # the final affine matrix is just the product
    tmat = np.dot(orig2out,np.dot(rotmat,in2orig))

# function that maps output space to input space
def out2in(outcoords,affinemat):
    outcoords = np.asarray(outcoords)
    outcoords = np.concatenate((outcoords,(1.,)))
    incoords = np.dot(affinemat,outcoords)
    incoords = tuple(incoords[0:2])
    return incoords

def rbtransform(source,xshift,yshift,rotation,outdims):

    # source --> target
    forward = maketmat(xshift,yshift,rotation,source.shape)

    # target --> source
    backward = np.linalg.inv(forward)

    # now we can use geometric_transform to do the interpolation etc.
    tformed = geometric_transform(source,out2in,output_shape=outdims,extra_arguments=(backward,))

    return tformed
这个方法可以实现,但是由于它基本上是在像素坐标上循环,所以速度非常慢!有什么好的方法可以解决这个问题?
2个回答

4

您是否可以使用skimage图像处理库?如果可以,您可以尝试应用一个单应性矩阵(homography)。单应性矩阵可以通过3x3的矩阵同时表示平移和旋转。您可以使用skimage.transform.fast_homography函数实现。

import numpy as np
import scipy
import skimage.transform
im = scipy.misc.lena()
H = np.asarray([[1, 0, 10], [0, 1, 20], [0, 0, 1]])
skimage.transform.fast_homography(im, H)
这个转换在我的旧Core 2 Duo上大约花费了30ms。 关于单应性矩阵:http://en.wikipedia.org/wiki/Homography

很好,几乎就是我想要的。唯一的缺点是 fast_homography 只支持双线性插值,但是普通的 homography 支持双三次插值,并且对于我的目的来说足够快了。 - ali_m

3

我认为 affine_transform 确实 可以进行平移操作 -- 这需要使用参数 offset


哈哈,你说得很对!让我困惑的是,我本来期望提供一个3阶矩阵,但它却不接受超过两行。我认为如果affine_transform接受单个矩阵进行变换,就像Nichola的建议一样,会更加直观易懂。 - ali_m
仿射不是刚性的。 - lesolorzanov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,