How to crop arrays using a vector? (reverse of padarray)
5 views (last 30 days)
Show older comments
*Short version: I'm looking for the reverse of padarray, where you can do padarray(a,[2 2 2]), but instead have it crop [2 2 2] instead of pad [2 2 2]. (Or alternatively, imcrop for more then two dimensions); *
Long version: I have a cell arrays of unknown size K, each cell in the array contains an numerical array with dimensions (m,n,k,... )importantly:
1. I don't know beforehand how many dimensions there will be for the
numerical arrays in the different cell arrays, but I
know that within a cell array all the numerical arrays will have
the same number of dimensions.
2. While all the arrays have the same number of dimensions, they
differ in size.
Basically I want to make a functions that crops the numerical arrays to the smallest dimensions, and then concatenates them, i.e. if
a{1} = zeros(10,10)
a{2} = zeros(16,6)
a{3} = zeros(6,6)
I want the outcome to be an array c with size (6,6,3).
I guess the problem is that I don't know how to index the arrays for a variable amount of dimensions. That is, I can get the size to which I need to crop (or the number by which I need to crop) in vector form like [6 6] or [15 4 8], but I don't know how to use this vector to index my arrays.
Thanks in advance!
Edit: Just thought of something, but it's very ugly: if we know we want to crop to an array of size (30,30,30)
minSize = [30 30 30]
c = []
for ii = length(a);
temp = a{ii}(:);
mask = zeros(minSize)
padding = (minSize - size(a{ii})./2;
mask = padarray(mask,padding,1,'both');
mask = logical(mask);
temp(mask)= [];
temp = reshape(temp,minSize);
c = cat(ndim(a{ii})+1,c,temp);
end
2 Comments
Accepted Answer
Sean de Wolski
on 11 Jul 2012
Edited: Sean de Wolski
on 11 Jul 2012
So something along the lines of:
x = rand(10,6,8,9);
nd = ndims(x);
c = repmat({':'},nd-1,1);
for ii = 1:nd;
x = shiftdim(x,1);
x = x(3:end-2,c{:});
end
More Answers (1)
nanren888
on 13 Jul 2012
Edited: nanren888
on 13 Jul 2012
Sorry I do not know paddarray, so maybe I am answering the wrong question.
I can give you parts of a way to do it. There may be more elegant ways. Indexing any number of dimensions is supported by Matlab's cool mechanism of using cell arrays as parameters;
Short version:
(1) Find the size you want with size & min
(2) Create a cell array of the ranges you want indC = {1:4 1:5 1:6 1:2 ...}
(3) Use < for all cells k > c{k} = c{k}(indC{:});
Longer version:
It seems finding the size you want to crop to is easy, just go through all cells with some sort of min(), eg collect all sizes & use min(?,dim), or manually take minimum values.
Maybe for the indexing, this will help
gg = randn([2 3 4 2]);
szVec = size(gg);
nDim = length(szVec);
ind = {};
for k = 1:nDim
ind = [ind 1:cropSize(k)]; % I presume you want 1:cropSize
end
smallerGg = gg(ind{:});
Hope it helps
2 Comments
nanren888
on 14 Jul 2012
Edited: nanren888
on 14 Jul 2012
Yeah, Mine won't suffer to the same extent from the extremely slow moves, I guess.
Maybe you could profile them for us, on a reasonable number of trials?
I guess what you asked for "vectors for dimensions" I did with cells for dimensions.
%% timeMultiDimStuff.m
x = rand(10,6,8,9,5,6,4,5,5);
y = zeros(size(x));
nDim = ndims(x);
cropSize = [8,6,7,3,4,5,3,5,4];
ind = {};
for k = 1:nDim
ind = [ind 1:cropSize(k)];
end
nTrial = 1000;
tic();
for k = 1:nTrial
y = x(ind{:}); %#ok<NASGU>
end
toc();
Run with your solution & compare?
Elapsed time is 5.751869 seconds. (You have to run both on the same machine :))
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!