Search code examples
pythonopencvscikit-learnscikit-image

How to get only possible non overlapping blocks from images of any given size and show them in Python


I have images of varying resolutions, and I would like to extract non-overlapping blocks from these images.

However, because the images have not fixed size and my block size is big (64x64), I would like to get only non-overlapping blocks that could be found in an image. If the block exceeds the image borders, I don't want to get them.

I tried the view_as_blocks function from scikit-image as below:

from skimage.util import view_as_blocks
for elem in listOfFiles:
    # Reading image
    print("Reading image "+elem)

    img = cv2.imread(elem)
    print(img.shape) #for example, one image is (2059, 2059, 3)

    Blocks = view_as_blocks(img, block_shape=(64, 64, 3))

The code returns the following error:

ValueError: 'block_shape' is not compatible with 'arr_in'

I also tried the Patch Extractor from scikit-learn, as follows:

from sklearn.feature_extraction import image
import cv2
import numpy 

for elem in listOfFiles:
    # Reading image
    print("Reading image "+elem)

    img = cv2.imread(elem)
    print(img.shape)

    pe = image.PatchExtractor(patch_size=(64,64))
    pe_fit = pe.fit(img)
    pe_trans = pe.transform(img)
    print('Patches shape: {}'.format(pe_trans.shape))

The error that returns to me is the following:

ValueError: negative dimensions are not allowed

the function image.extract_patches_2d from sklearns runs perfectly, but unfortunatelly it works only for overlapping blocks as you can see here.

These functions also don't help me because I also want to show the image with these blocks selected, so I also need another matrix with coordinates of such blocks and show the selected blocks.

Is that possible to that in Python?


Solution

  • Since you don't care about the incomplete blocks at the edges, you can manually check the number of blocks along each dimension, and crop your image to that shape:

    from skimage.util import view_as_blocks
    
    
    for elem in listOfFiles:
        # Reading image
        print("Reading image "+elem)
    
        img = cv2.imread(elem)
        print(img.shape) #for example, one image is (2059, 2059, 3)
        block_shape = np.array((64, 64, 3))
        nblocks = np.array(img.shape) // block_shape  # integer division
        crop_r, crop_c, crop_ch = nblocks * block_shape
        cropped_img = img[:crop_r, :crop_c, :crop_ch]
        Blocks = view_as_blocks(cropped_img, block_shape=(64, 64, 3))