def recompose_tensor(patches, full_height, full_width, overlap=10):
    (batch_size, channels, patch_size, _) = patches.size()
    effective_patch_size = (patch_size - overlap)
    n_patches_height = (full_height // effective_patch_size)
    n_patches_width = (full_width // effective_patch_size)
    if ((n_patches_height * effective_patch_size) < full_height):
        n_patches_height += 1
    if ((n_patches_width * effective_patch_size) < full_width):
        n_patches_width += 1
    n_patches = (n_patches_height * n_patches_width)
    if ((batch_size % n_patches) != 0):
        print('Error: The number of patches provided to the recompose function does not match the number of patches in each image.')
    final_batch_size = (batch_size // n_patches)
    blending_in = torch.linspace(0.1, 1.0, overlap)
    blending_out = torch.linspace(1.0, 0.1, overlap)
    middle_part = torch.ones((patch_size - (2 * overlap)))
    blending_profile = torch.cat([blending_in, middle_part, blending_out], 0)
    horizontal_blending = blending_profile[None].repeat(patch_size, 1)
    vertical_blending = blending_profile[:, None].repeat(1, patch_size)
    blending_patch = (horizontal_blending * vertical_blending)
    blending_image = torch.zeros(1, channels, full_height, full_width)
    for h in range(n_patches_height):
        for w in range(n_patches_width):
            patch_start_height = min((h * effective_patch_size), (full_height - patch_size))
            patch_start_width = min((w * effective_patch_size), (full_width - patch_size))
            blending_image[0, :, patch_start_height:(patch_start_height + patch_size), patch_start_width:(patch_start_width + patch_size)] += blending_patch[None]
    recomposed_tensor = torch.zeros(final_batch_size, channels, full_height, full_width)
    if patches.is_cuda:
        blending_patch = blending_patch.cuda()
        blending_image = blending_image.cuda()
        recomposed_tensor = recomposed_tensor.cuda()
    patch_index = 0
    for b in range(final_batch_size):
        for h in range(n_patches_height):
            for w in range(n_patches_width):
                patch_start_height = min((h * effective_patch_size), (full_height - patch_size))
                patch_start_width = min((w * effective_patch_size), (full_width - patch_size))
                recomposed_tensor[b, :, patch_start_height:(patch_start_height + patch_size), patch_start_width:(patch_start_width + patch_size)] += (patches[patch_index] * blending_patch)
                patch_index += 1
    recomposed_tensor /= blending_image
    return recomposed_tensor
def recompose_tensor(patches, full_height, full_width, overlap=10):
    (batch_size, channels, patch_size, _) = patches.size()
    effective_patch_size = (patch_size - overlap)
    n_patches_height = (full_height // effective_patch_size)
    n_patches_width = (full_width // effective_patch_size)
    if ((n_patches_height * effective_patch_size) < full_height):
        n_patches_height += 1
    if ((n_patches_width * effective_patch_size) < full_width):
        n_patches_width += 1
    n_patches = (n_patches_height * n_patches_width)
    if ((batch_size % n_patches) != 0):
        print('Error: The number of patches provided to the recompose function does not match the number of patches in each image.')
    final_batch_size = (batch_size // n_patches)
    blending_in = torch.linspace(0.1, 1.0, overlap)
    blending_out = torch.linspace(1.0, 0.1, overlap)
    middle_part = torch.ones((patch_size - (2 * overlap)))
    blending_profile = torch.cat([blending_in, middle_part, blending_out], 0)
    horizontal_blending = blending_profile[None].repeat(patch_size, 1)
    vertical_blending = blending_profile[:, None].repeat(1, patch_size)
    blending_patch = (horizontal_blending * vertical_blending)
    blending_image = torch.zeros(1, channels, full_height, full_width)
    for h in range(n_patches_height):
        for w in range(n_patches_width):
            patch_start_height = min((h * effective_patch_size), (full_height - patch_size))
            patch_start_width = min((w * effective_patch_size), (full_width - patch_size))
            blending_image[0, :, patch_start_height:(patch_start_height + patch_size), patch_start_width:(patch_start_width + patch_size)] += blending_patch[None]
    recomposed_tensor = torch.zeros(final_batch_size, channels, full_height, full_width)
    if patches.is_cuda:
        blending_patch = blending_patch.cuda()
        blending_image = blending_image.cuda()
        recomposed_tensor = recomposed_tensor.cuda()
    patch_index = 0
    for b in range(final_batch_size):
        for h in range(n_patches_height):
            for w in range(n_patches_width):
                patch_start_height = min((h * effective_patch_size), (full_height - patch_size))
                patch_start_width = min((w * effective_patch_size), (full_width - patch_size))
                recomposed_tensor[b, :, patch_start_height:(patch_start_height + patch_size), patch_start_width:(patch_start_width + patch_size)] += (patches[patch_index] * blending_patch)
                patch_index += 1
    recomposed_tensor /= blending_image
    return recomposed_tensor