Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fast 2D rigid body transformations in numpy/scipy

I want to apply rigid body transformations to a large set of 2D image matrices. Ideally, I'd like to be able to just supply an affine transformation matrix specifying both the translation and rotation, apply this in one go, then do cubic spline interpolation on the output.

Unfortunately it seems that affine_transform in scipy.ndimage.interpolation doesn't do translation. I know I could use a combination of shift and rotate, but this is kind of messy and in involves interpolating the output multiple times.

I've also tried using the generic geometric_transformation like this:

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

This works, but it's horribly slow, since it's essentially looping over pixel coordinates! What's a good way to do this?

like image 850
ali_m Avatar asked Jul 13 '12 01:07

ali_m


2 Answers

I think affine_transform does do translation --- there's the offset parameter.

like image 106
pv. Avatar answered Nov 14 '22 22:11

pv.


Can you use the scikit image? If this is the case, you could try to apply an homography. An homography cab used to represent both translation and rotation at the same time through a 3x3 matrix. You can use the skimage.transform.fast_homography function.

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)

The transform took about 30 ms on my old Core 2 Duo.

About homography : http://en.wikipedia.org/wiki/Homography

like image 4
Nicolas Barbey Avatar answered Nov 14 '22 22:11

Nicolas Barbey