1
votes

does anybody know how to crop an image with a sliding window in Matlab? e.g. I have an image of 1000x500 pixels, I would like to crop from this image blocks of 50x50 pixels... Of course I have to handle uneven divisions, but it is not necessary to have block of the same size.

2
If you don't find a way with Matlab, it is a simple one-liner with ImageMagick which is installed on most Linux distros and is available for OSX and Windows... convert -crop 50x50 in.png tile%d.png and your 200 tiles will be created as tile0.png through tile199.png. Feel free to change any png to jpg or tif or bmp or whatever you need. - Mark Setchell
I have to find a way in matlab ;D this is only a part of the problem I have to solve! Thank you... - Kevin
When you say, "crop", you mean you want to extract the 50x50 matrix of pixels and save it in a new matrix? Or do you want to keep the image size 1000x5000 and just zero all the pixels outside the region of interest? And does the sliding window overlap itself, or cover the image in blocks? - eigenchris
According to the example of an image of 1000x500 pixels and of blocks 50x50 pixels... It would be excellent to have (1000x500 )/( 50x50 )=200 images of 1000x500 pixels, with just zero all the pixels outside each block... - Kevin

2 Answers

1
votes

I would first look into the function blockproc to see if it can do what you want.


If you're sure you want to manually crop the image into blocks, you can use this script. It both writes the cropped images to .png files and saves the cropped images in the pages of a 3D array. You can modify it as you need.

This script assumes the image in evenly divisible by the block size. If it isn't, you'll need to pad it with zeros.

[rowstmp,colstmp]= size(myImage);
block_height     = 50;
block_width      = 50;

blocks_per_row   = rows/block_height;
blocks_per_col   = cols/block_width;
number_of_blocks = blocks_per_row*blocks_per_col;

%// pad image with zeros if needed
if ~(mod(rowstmp-1,block_height)==0)
    rows = ceil(rowstmp/block_height)*block_height;
end
if ~(mod(colstmp-1,block_width)==0)
    cols = ceil(colstmp/block_width)*block_width;
end
Im = uint8(zeros(rows,cols));
Im(1:rowstmp,1:colstmp) = myImage;

%// make sure these image have type uint8 so they save properly
cropped_image    = uint8(zeros(rows,cols));
img_stack        = uint8(zeros(rows,cols,number_of_blocks));

%// loop over the image blocks
for i = 1:blocks_per_row
    for j = 1:blocks_per_col
        %// get the cropped image from the original image
        idxI = 1+(i-1)*block_height:i*block_height;
        idxJ = 1+(j-1)*block_width :j*block_width;
        cropped_image(idxI,idxJ) = Im(idxI,idxJ);

        %//imshow(cropped_image)

        %// write the cropped image to the current folder
        filename = sprintf('block_row%d_col%d.png',i,j);
        imwrite(cropped_image,filename);
        cropped_image(idxI,idxJ) = 0;

        %// keep all the blocks in a 3D array if we want to use them later
        img_stack(:,:,(i-1)*blocks_per_col+j);
    end
end
2
votes

Some details that have helped me in the past related to (i) ways to divide an image while block processing and (ii) "uneven division", as mentioned by OP.

(i) Ways to divide/process an image:

1. Process non-overlapping blocks:

Using default parameter {'BorderSize',[0 0]}, this can be handled with blockproc as below.

Example for (i)-1: Note the blocked nature of the output. Here each non-overlapping block of size 32 x 32 is used to calculate the std2() and the output std2 value is used to fill that particular block. The input and output are of size 32 x 32.

fun = @(block_struct) std2(block_struct.data) * ones(size(block_struct.data));
I2 = blockproc('moon.tif',[32 32],fun);
figure; subplot(1, 2, 1);
imshow('moon.tif'); title('input');
subplot(1,2, 2)
imshow(I2,[]); title('output'); 

Input and Output Image:

(i)-1 Example: Crop an image with non-overlapping blocks

(i)-2: Process overlapping blocks:

Using parameter {'BorderSize',[V H]}: V rows are added above and below the block and H columns are added to the left and right of the block. The block that is processed has (N + 2*V) rows and (M + 2*H) columns. Using default parameter {'TrimBorder',true}, the border of the output is trimmed to the original input block size of N rows and M columns.

Example for (i)-2: Below code using blockproc uses {'BorderSize',[15 15]} with [N M] = [1 1]. This is similar to filtering each pixel of the image with a custom kernel. So the input to the processing unit is a block of size (1 + 2*15) rows and (1 + 2*15) columns. And since {'TrimBorder',true} by default, the std2 of the 31 rows by 31 columns block is provided as output for each pixel. The output is of size 1 by 1 after trimming border. Consequently, note that this example output is 'non-blocked' in contrast to the previous example. This code takes much longer time to process all the pixels.

fun = @(block_struct) std2(block_struct.data) * ones(size(block_struct.data));
I2 = blockproc('moon.tif',[1 1],fun,'BorderSize',[15 15]);
figure; subplot(1, 2, 1);
imshow('moon.tif'); title('input');
subplot(1,2, 2)
imshow(I2,[]); title('output');

Input and Output Image:

Example of overlapping block processing

(ii) "Uneven division":

1. Zero/replicate/symmetric padding:

Zero padding so that an integer multiple of the blocks (N rows by M cols sized) can cover the [image + bounding zeros] in the uneven dimension. This can be achieved by using the default parameter {'PadMethod', 0} along with {'PadPartialBlocks' , true} ( which is false by default ). If a bounding region of zeros causes a high discontinuity in values computed from the bounding blocks, {'PadMethod', 'replicate'} or {'PadMethod', 'symmetric'} can be used.

2. Assume an "Active Region" within the image for block processing

For the case of processing each pixel, as in case (i)-2, we could assuming a bounding region of floor(block_size/2) pixels on all sides along the periphery of the image that is used as "Dummy" region. The Active region for block processing is contained within the Dummy region.

Something similar is used in imaging sensors where Dummy Pixels located at the periphery of an imaging array of Active Pixels allow for an operation like the color interpolation of all active area pixels. As color interpolation usually needs a 5x5 pixel mask to interpolate the color values of a pixel a bounding Dummy periphery of 2 pixels can be used.

Assuming MATLAB indexing, the region ( floor(block_size/2) + 1 ) to ( Input_Image_Rows - floor(block_size)/2) ) Rows by ( floor(block_size/2) + 1 ) to ( Input_ImageCols - floor(block_size)/2) ) Columns is considered as Active region (assuming a square block of side, block_size) which undergoes block processing for each pixel as in (i)-2.

Assuming a square block size of 5 by 5, this is shown by the following:

block_size  = 5;
buffer_size = floor(block_size/2);
for i = (buffer_size+1):(image_rows-buffer_size)
    for j = (buffer_size+1):(image_cols-buffer_size)
        ...  % block processing for each pixel Image(i,j)
    end
end

Matlab ver: R2013a