Shifting a multidimensional matrix
Show older comments
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
Accepted Answer
More Answers (3)
Azzi Abdelmalek
on 12 Oct 2012
Edited: 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,:)
4 Comments
Alex Feinman
on 12 Oct 2012
Edited: Alex Feinman
on 12 Oct 2012
Azzi Abdelmalek
on 12 Oct 2012
Edited: 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
Edited: 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
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
2 Comments
Alex Feinman
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.
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 ')'])
3 Comments
Alex Feinman
on 15 Oct 2012
Alex Feinman
on 15 Oct 2012
Matt J
on 15 Oct 2012
I think part of the compactness is due to the fact that this solution doesn't support negative offsets. It's interesting that you favor EVAL. Most TMW employees seem to discourage it
Categories
Find more on Logical in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!