imagematlabtiling

How can I tile an image into patches of (constant) arbitrary size at (constant) arbitrary stride in MATLAB?


I have an image of arbitrary dimensions ROWS and COLS. I want to tile this image into patches of arbitrary, but constant size blockSize = [blockSizeR, blockSizeC], given an arbitrary, but constant stride stride = [strideR, strideC]. When the number of patches in row or column direction times the respective block size doesn't equal the number of rows or columns, respectively (i.e. if there were spare rows or columns), I don't care about them (i.e. they can be ignored). It's sufficient if the image is tiled into all possible patches that fit completely into the image starting from the top left pixel.

There is a bunch of possible solutions floating around the web, but some don't allow overlap, some don't allow outputs if there are spare rows or columns, some are making inefficient use of for loops.

The closest thing to what I need is probably the solution posted on https://de.mathworks.com/matlabcentral/answers/330357-how-do-i-store-a-series-of-rgb-images-in-a-2d-array:

%img: source image
stride = [5, 5];       %height, width
blocksize = [11, 11];  %height, width
tilescount = (size(img(:, :, 1)) - blocksize - 1) / stride + 1;
assert(all(mod(tilescount, 1) == 0), 'cannot divide image into tile evenly')
tiles = cell(tilescount);
tileidx = 1;
for col = 1 : stride(2) : size(img, 2 ) - blocksize(2)
   for row = 1 : stride(1) : size(img, 1) - blocksize(1)
      tiles{tileidx} = img(row:row+stride(1)-1, col:col+stride(2)-1, :);
      tileidx = tileidx + 1;
   end
end

However, it also seems to work only if there are no spare rows or columns. How can I adapt that to an efficient solution for images with an arbitrary number of channels (I seek to apply it on both single-channel images and RGB images)?


Solution

  • The code above did not fully work, so I came up with the following solution based on it. Variable names are chosen such that they are self-explanatory.

    tilesCountR = floor((ROWS - rowBlockSize - 1) / rowStride + 1);
    tilesCountC = floor((COLS - colBlockSize - 1) / colStride + 1);
    
    tiles = cell(tilesCountR * tilesCountC,1);
    tileidx = 1;
    for col = 1 : colStride : COLS - colBlockSize
       for row = 1 : rowStride : ROWS - rowBlockSize
          tiles{tileidx} = img(row:row+rowBlockSize-1, col:col+colBlockSize-1, :);
          tileidx = tileidx + 1;
       end
    end