Given a matrix A(mxnxc) (c can be arbitrary), I want to sample patches(pxp) in sliding window scheme with stepsize d, and rearrange all the pxpxc patches into vectors. I can do it within nested for-loops, but it is very time consuming. How to do this quickly?
Asked
Active
Viewed 1,028 times
2

Divakar
- 218,885
- 19
- 262
- 358

Liang Xiao
- 1,490
- 2
- 14
- 21
-
So, the output would be `2D` with `number of rows = p*p*c`, right? – Divakar Apr 21 '16 at 08:05
-
Yes, you are right.@Divakar – Liang Xiao Apr 21 '16 at 09:23
-
I see. So, `im2col_3D_sliding_v2` from the posted solution below would work hopefully. I would keep the other version, future readers might be benefited from it. – Divakar Apr 21 '16 at 09:25
-
Yes, *im2col_3D_sliding_v2* is a good solution. Your effort is appreciated. – Liang Xiao Apr 21 '16 at 09:28
1 Answers
4
One can extend this solution to Efficient Implementation of im2col and col2im
again with bsxfun
for a 3D array case to solve your case.
Now, there are two possible interpretations to the question :
Extract blocks of size
p x p
and as vectors each, do this for entire first2D
slice and then repeat this for all slices in3D
, resulting in a3D
output.Gather blocks of size
p x p x c
as vectors each and do this in a sliding manner across the entire array, resulting in a2D
output.
These two interpretations are implemented as im2col_3D_sliding_v1
and im2col_3D_sliding_v2
respectively and listed next.
im2col_3D_sliding_v1 :
function out = im2col_3D_sliding_v1(A,blocksize,stepsize)
%// Store blocksizes
nrows = blocksize(1);
ncols = blocksize(2);
%// Store stepsizes along rows and cols
d_row = stepsize(1);
d_col = stepsize(2);
%// Get sizes for later usages
[m,n,r] = size(A);
%// Start indices for each block
start_ind = reshape(bsxfun(@plus,[1:d_row:m-nrows+1]',[0:d_col:n-ncols]*m),[],1); %//'
%// Row indices
lin_row = permute(bsxfun(@plus,start_ind,[0:nrows-1])',[1 3 2]); %//'
%// 2D linear indices
lidx_2D = reshape(bsxfun(@plus,lin_row,[0:ncols-1]*m),nrows*ncols,[]);
%// 3D linear indices
lidx_3D = bsxfun(@plus,lidx_2D,m*n*permute((0:r-1),[1 3 2]));
%// Get linear indices based on row and col indices and get desired output
out = A(lidx_3D);
return;
im2col_3D_sliding_v2 :
function out = im2col_3D_sliding_v2(A,blocksize,stepsize)
%// Store blocksizes
nrows = blocksize(1);
ncols = blocksize(2);
%// Store stepsizes along rows and cols
d_row = stepsize(1);
d_col = stepsize(2);
%// Get sizes for later usages
[m,n,r] = size(A);
%// Start indices for each block
start_ind = reshape(bsxfun(@plus,[1:d_row:m-nrows+1]',[0:d_col:n-ncols]*m),[],1); %//'
%// Row indices
lin_row = permute(bsxfun(@plus,start_ind,[0:nrows-1])',[1 3 2]); %//'
%// 2D linear indices
lidx_2D = reshape(bsxfun(@plus,lin_row,[0:ncols-1]*m),nrows*ncols,[]);
%// 3D linear indices
lidx_3D = bsxfun(@plus,permute(lidx_2D,[1 3 2]),m*n*(0:r-1));
%// Final 2D linear indices
lidx_2D_final = reshape(lidx_3D,[],size(lidx_2D,2));
%// Get linear indices based on row and col indices and get desired output
out = A(lidx_2D_final);
return;
Sample runs
(I) Input array :
>> A
A(:,:,1) =
23 109 63 1 37 153
110 31 201 57 69 230
66 127 19 1 45 240
76 181 101 49 36 57
A(:,:,2) =
124 18 244 2 141 95
96 112 110 174 56 228
134 45 246 181 197 219
68 7 195 165 59 103
(II) Input parameters :
>> blocksize = [2,3]; %// blocksize along rows, cols
>> stepsize = [2,2]; %// stepsize along rows, cols
(III) Outputs with two versions :
>> im2col_3D_sliding_v1(A,blocksize,stepsize)
ans(:,:,1) =
23 66 63 19
110 76 201 101
109 127 1 1
31 181 57 49
63 19 37 45
201 101 69 36
ans(:,:,2) =
124 134 244 246
96 68 110 195
18 45 2 181
112 7 174 165
244 246 141 197
110 195 56 59
>> im2col_3D_sliding_v2(A,blocksize,stepsize)
ans =
23 66 63 19
110 76 201 101
109 127 1 1
31 181 57 49
63 19 37 45
201 101 69 36
124 134 244 246
96 68 110 195
18 45 2 181
112 7 174 165
244 246 141 197
110 195 56 59
-
-
@kkuilla Yeah, I was sort of waiting for output size clarification from OP to incorporate stepsize. Just added that as param in the edits :) – Divakar Apr 21 '16 at 09:05
-
-
Can the process be reversed according? That is accumulate the patches at the sampled location and then divided by the accumulated times to get a probability output? – Liang Xiao Apr 21 '16 at 12:37
-
@LiangXiao I think it would make sense to post that as a separate question. – Divakar Apr 21 '16 at 12:40