Shifting an image in numpy

14,672

Solution 1

There's no other way, as to handle negative and positive shifts accordingly:

non = lambda s: s if s<0 else None
mom = lambda s: max(0,s)

ox, oy = 100, 20

shift_lena = numpy.zeros_like(lena)
shift_lena[mom(oy):non(oy), mom(ox):non(ox)] = lena[mom(-oy):non(-oy), mom(-ox):non(-ox)]

Solution 2

You can use roll function to circular shift x and y and then zerofill the offset

def shift_image(X, dx, dy):
    X = np.roll(X, dy, axis=0)
    X = np.roll(X, dx, axis=1)
    if dy>0:
        X[:dy, :] = 0
    elif dy<0:
        X[dy:, :] = 0
    if dx>0:
        X[:, :dx] = 0
    elif dx<0:
        X[:, dx:] = 0
    return X
Share:
14,672
Gert Gottschalk
Author by

Gert Gottschalk

Updated on July 16, 2022

Comments

  • Gert Gottschalk
    Gert Gottschalk over 1 year

    I have a image in a 2d numpy array. I want to shift the image by an X and Y offset and want the rest of the frame padded with zeros. I have seen discussions about the 'roll' function but that only works in 1 axis. (unless someone can point me to a 2d version with padding). I have tried slicing but I run into trouble when shifting offsets have all possible directions. I don't want to navigate through all X Y offset +/- permutations. Is there a simple general solution? I have the below code which works nice for X-offset=+100. But it crashes for X-offset=-100.

    Thanks, Gert

    import matplotlib.pyplot as plt
    import scipy.misc        as msc
    import numpy             as np
    
    lena = msc.lena()
    lena.dtype
    (imx,imy)= lena.shape
    ox= 100
    oy= 20
    shift_lena = np.zeros((imx,imy))
    shift_lena[0:imy-oy,0:imx-ox] = lena[oy:,ox:]
    shift_lena_m = shift_lena.astype(np.int64)
    shift_lena_m.dtype
    plt.figure(figsize=(10, 3.6))
    plt.subplot(131)
    plt.imshow(lena, cmap=plt.cm.gray)
    plt.subplot(132)
    plt.imshow(shift_lena_m, cmap=plt.cm.gray)
    plt.subplots_adjust(wspace=0, hspace=0., top=0.99, bottom=0.01, left=0.05, right=0.99)
    plt.show()