Quiero aplicar transformaciones corporales rígidas a un gran conjunto de matrices de imágenes 2D. Idealmente, me gustaría poder proporcionar una matriz de transformación afín que especifique tanto la traducción como la rotación, aplicar esto de una vez, luego hacer una interpolación de spline cúbica en la salida.Transformaciones corporales rígidas 2D rápidas en numpy/scipy
Desafortunadamente parece que affine_transform
en scipy.ndimage.interpolation
no hace la traducción. Sé que podría usar una combinación de shift
y rotate
, pero esto es un poco complicado e implica la interpolación de la salida varias veces.
También he intentado usar el genérico geometric_transformation
así:
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
Esto funciona, pero es terriblemente lento, ya que es esencialmente un bucle sobre las coordenadas del pixel! ¿Cuál es una buena manera de hacer esto?
¡Hah, haz un buen punto! Lo que me sorprendió fue que esperaba suministrar una matriz de rango 3 y se negó a aceptar más de dos filas. Creo que sería mucho más sencillo si 'affine_transform' aceptara una matriz única para la transformación, como en la sugerencia de Nichola. –
Affine no es rígido –