3

I would like to have function doing this, but it doesn't exist:

from skimage.transform import shift

shifted = shift(image, translation=(15.2, 35.7),
                mode='wrap', preserve_range=True)

Could you help me writing a function using skimage.transform.AffineTransform?

from skimage.transform import AffineTransform

def shift(image, translation):
    transform = AffineTransform(translation=translation)
    # How to do it???
    shifted = transform(image)   # Does not work, documentation for usage present
                                 # of this class is not present...
    return shifted

However function scipy.ndimage.interpolation.shift does what i want, it is veeeeery slow - approximately even 10-20x slower than rotating. numpy.roll is off the table too, as it doesn't support fractional translations.


documentation is somewhat mean: http://scikit-image.org/docs/stable/api/skimage.transform.html#skimage.transform.AffineTransform

2 Answers 2

3

Seems like this is working. Yet if anyone knows simpler and faster way - please let me know.

from skimage.transform import AffineTransform, warp

def shift(image, vector):
    transform = AffineTransform(translation=vector)
    shifted = warp(image, transform, mode='wrap', preserve_range=True)

    shifted = shifted.astype(image.dtype)
Sign up to request clarification or add additional context in comments.

1 Comment

I also found AffineTransform to be very slow, especially for multi dimensional array. For simple shift all you theoretically need is for each translated pixel to be the weighted mean of four pixels in the original image. Apart from image borders, the weight coefficients are always the same so it should be extremely fast. I think the use of a more general matrix transformation slow this down.
0

You can do in 2D :

shift_matrix = np.array( [ [ 1, 0,  -15.2,], [0, 1, -35.7 ] , [0, 0, 1] ] ) 
shifted= scipy.ndimage.affine_transform( image, shift_matrix )

But it is still relatively slow. A home made function could be :

def shift_img_along_axis( img, axis=0, shift = 1 , constant_values=0):
    """ shift array along a specific axis. New value is taken as weighted by the two distances to the assocaited original pixels.
    CHECKED : Works for floating shift ! ok.
    NOTE: at the border of image, when not enough original pixel is accessible, data will be meaned with regard to additional constant_values. 
    constant_values: value to set to pixels with no association in original image img 
    RETURNS : shifted image. 
    A.Mau. """
    intshift = int(shift)
    remain0 = abs( shift - int(shift) )
    remain1 = 1-remain0 #if shift is uint : remain1=1 and remain0 =0
    npad = int( np.ceil( abs( shift ) ) )  #ceil relative to 0. ( 0.5=> 1 and -0.5=> -1 )
    # npad = int( abs( shift+ 0.5*[-1,1][shift>0] ) ) 
    
    pad_arg = [(0,0)]*img.ndim
    pad_arg[axis] = (npad,npad)
    bigger_image = np.pad( img, pad_arg, 'constant', constant_values=constant_values) 
    
    part1 = remain1*bigger_image.take( np.arange(npad+intshift, npad+intshift+img.shape[axis]) ,axis)
    if remain0==0:
        shifted = part1
    else:
        if shift>0:
            part0 = remain0*bigger_image.take( np.arange(npad+intshift+1, npad+intshift+1+img.shape[axis]) ,axis) #
        else:
            part0 = remain0*bigger_image.take( np.arange(npad+intshift-1, npad+intshift-1+img.shape[axis]) ,axis) #

        shifted = part0 + part1
    return shifted

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.