Search code examples
pythonopencvimage-processingscikit-learnscikit-image

Cannot reconstruct decomposed image


I tried to reconstruct an image that I decomposed into patches. I tried either with sklearn.feature_extraction.image.reconstruct_from_patches_2d or with my custom function but the result is the same

enter image description here

Here is my try:

image_path=r'C:\Users\User\Desktop\Thesis-Diabetic Retinopathy\Datasets\DIARETDB1\SeeFar Project\Images\Processed images\image001.png'

os.mkdir(r'C:\Users\User\Desktop\Patched Image')

def create_patches_from_lesions(image_path,patch_widht,patch_height):
    im1=cv2.imread(image_path)
    im2 = cv2.cvtColor(im1, cv2.COLOR_BGR2RGB) 
    x1,y1=im2.shape[0]//50,im2.shape[1]//50
    x2,y2=x1*50,y1*50
    im3 = cv2.resize(im2, (x2,y2))
    print(im3.shape)
    patches=[]

    for row in range(0,im3.shape[0],50):
        for column in range(0,im3.shape[1],50):
            patch=im3[row:(row+patch_widht),column:(column+patch_height)]
            patches.append(patch)


    for i in tqdm(range(len(patches))): #### keep only the patches with non zero elememts

        cv2.imwrite(os.path.join(r'C:\Users\User\Desktop\Patched Image','{}.png'.format(i)),patches[i])

    return patches,x2,y2



patches,x2,y2=create_patches_from_lesions(image_path,50,50)


def reconstruct_image(patches,image_height,image_width):
    patches=np.asarray(patches)
    print(patches.shape)
    reshaped_patches=np.reshape(patches,(image_height,image_width,3))
    print([reshaped_patches.shape])
    cv2.imwrite(r'C:\Users\User\Desktop\Reconstructed Image.png',reshaped_patches)
reconstruct_image(patches,x2,y2)  

Solution

  • sklearn.feature_extraction.image.extract_patches_2d reshapes a 2D image into a collection of overlapping patches. To decompose your image into non-overlapping blocks you could use skimage.util.view_as_blocks.

    The following snippet is a possible implementation of your custom functions. Notice that create_patches gets rid of the bottom and right borders of the image if the image size is not an integer multiple of the patch size. I adopted this solution to avoid resizing of the image (an operation which is likely to introduce artifacts). The original image can be reconstructed either from the patch files (not implemented) or directly from the 4D array returned by create_patches.

    import os
    import numpy as np
    from skimage import io, util
    
    def create_patches(img, folder, patch_width, patch_height):
        # Trim right and bottom borders if image size is not 
        # an integer multiple of patch size
        nrows, ncols = patch_height, patch_width   
        trimmed = img[:img.shape[0]//nrows*nrows, :img.shape[1]//ncols*ncols]   
        
        # Create folder to store results if necessary
        patch_dir = os.path.join(folder, 'Patched Image')
        if not os.path.isdir(patch_dir):
            os.mkdir(patch_dir)
    
        # Generate patches and save them to disk           
        patches = util.view_as_blocks(trimmed, (nrows, ncols))
        for i in range(patches.shape[0]):
            for j in range(patches.shape[1]):
                patch = patches[i, j, :, :]
                patch_name = f'patch_{i:02}_{j:02}.png'
                io.imsave(os.path.join(patch_dir, patch_name), patch)
    
        return patches
    
    
    def reconstruct_image(patches):
        img_height = patches.shape[0]*patches.shape[2]
        img_width = patches.shape[1]*patches.shape[3]
        return patches.transpose(0, 2, 1, 3).reshape(img_height, img_width)
    

    Demo

    In [134]: import matplotlib.pyplot as plt
         ...: 
         ...: folder = r'C:\Users\User\path-to-your-folder'
         ...: filename = 'sample_image.png'
         ...: 
         ...: original = io.imread(os.path.join(folder, filename))
         ...: patches = create_patches(original, folder, 50, 50)
         ...: reconstructed = reconstruct_image(patches)
         ...: 
         ...: fig, (ax0, ax1) = plt.subplots(1, 2)
         ...: ax0.imshow(original, cmap='gray')
         ...: ax0.set_title('Original')
         ...: ax1.imshow(reconstructed, cmap='gray')
         ...: ax1.set_title('Reconstructed')
         ...: plt.show(fig)
         ...: 
         ...: for patch in os.listdir(os.path.join(folder, 'Patched Image')):
         ...:     print(patch)
         ...:     
    patch_00_00.png
    patch_00_01.png
    patch_00_02.png
    patch_00_03.png
    ...
    patch_07_05.png
    patch_07_06.png
    patch_07_07.png
    patch_07_08.png
    patch_07_09.png
    

    results

    The image used in the example above can be downloaded from here