Asked by Alex Feinman
on 12 Oct 2012

I'm trying to offset a matrix by a certain distance, like dragging an image partially out of frame.

The 'new' area gets filled with zeroes or NaNs, and the 'extra' area gets clipped, so you end up with a new matrix the same size as the original.

In one dimension this is easy--just add 0s to the size of the offset:

offset = 3;

dest = [zeros(1, offset), original(1:end-offset)];

But I'm having trouble generalizing this to n dimensions. Is there an algorithmic way to handle this, or a built-in I've missed?

EDIT: To clarify, in the N dimensional case, offset is a vector of N elements, some of which can be negative.

For example:

A = ones([3 3]);

offset = [1 1];

_function_(A, offset) =

0 0 0

0 1 1

0 1 1

offset = [1 -1];

_function_(A, offset) =

0 0 0

1 1 0

1 1 0

Answer by Matt J
on 12 Oct 2012

Edited by Matt J
on 12 Oct 2012

Accepted Answer

I think this might be the generalization you're looking for of Azzi's approach,

function B=noncircshift(A,offsets)

%Like circshift, but shifts are not circulant. Missing data are filled with

%zeros.

%

% B=noncircshift(A,offsets)

siz=size(A);

N=length(siz);

if length(offsets)<N

offsets(N)=0;

end

B=zeros(siz);

indices=cell(3,N);

for ii=1:N

for ss=[1,3]

idx=(1:siz(ii))+(ss-2)*offsets(ii);

idx(idx<1)=[];

idx(idx>siz(ii))=[];

indices{ss,ii}=idx;

end

end

src_indices=indices(1,:);

dest_indices=indices(3,:);

B(dest_indices{:})=A(src_indices{:});

Matt Fig
on 12 Oct 2012

Nice!

Pascal Loohuis
on 17 Sep 2019

What if the shifts are different for each layer?

Sign in to comment.

Answer by Azzi Abdelmalek
on 12 Oct 2012

Edited by Azzi Abdelmalek
on 12 Oct 2012

offset=3

A=rand(10,12);

[n,m]=size(A)

out=zeros(n,m)

out(:,offset+1:m)=A(:,1:m-offset)

If your matrix is nxmxp

offset=3

A=rand(10,12,3);

[n,m,p]=size(A)

out=zeros(n,m,p)

out(:,offset+1:m,:)=A(:,1:m-offset,:)

Azzi Abdelmalek
on 12 Oct 2012

for multidimension >3

A=randi(10,4,8,2,4,2) % example

siz=size(A)

out=zeros(siz)

i1=offset+1:siz(2)

i2=1:siz(2)-offset

out(:,i1,:)=A(:,i2,:)

Alex Feinman
on 12 Oct 2012

Azzi Abdelmalek
on 12 Oct 2012

Ok, I did'nt read your full comment. I have a second answer

Sign in to comment.

Answer by Matt J
on 12 Oct 2012

First, recognize that in 1D, this can be done by a sparse matrix multiplication

offset=3;

N=10;

x=(1:N).'

S=speye(N); %N is length of vector

S=circshift(S,[offset,0]);

S(1:offset,:)=0;

dest= S*x,

To generalize to 2D, multiply all the columns and rows by S

x=rand(N,N);

dest=S*x*S.';

Or, if you have different offsets in different dimensions, you'll need separate matrices Sx and Sy.

To generalize to 3D and higher, I recommend using my KronProd package

x=rand(N,N,N);

dest=KronProd({S},[1,1,1])*x;

where KronProd is available here

Alex Feinman
on 12 Oct 2012

Matt J
on 12 Oct 2012

Only change

S(end+1-(1:-offset),:)=0;

However, Azzi's method can be similarly generalized and is probably better, now that I think about it. That's assuming you're restricting yourself to integer shifts. If you need to do sub-pixel shifts, where you need to interpolate, then my approach is more easily generalized, I think.

Sign in to comment.

Answer by Azzi Abdelmalek
on 12 Oct 2012

A=randi(10,4,8,2,4,4,3);

offset=[2 2 1 2 1 2];

siz=size(A);

n=numel(siz);

out=zeros(siz);

idx1=sprintf('%d:%d,',[offset+1; siz]);

idx1(end)=[];

idx2=sprintf('%d:%d,',[ones(1,n); siz-offset]);

idx2(end)=[];

eval(['out(' idx1 ')=A(' idx2 ')'])

Alex Feinman
on 15 Oct 2012

I love the use of sprintf / eval...let me do some speed testing vs. Matt J.'s answer.

Alex Feinman
on 15 Oct 2012

Matt J
on 15 Oct 2012

Sign in to comment.

Opportunities for recent engineering grads.

Apply Today
## 0 Comments

Sign in to comment.