|
import numpy as np |
|
import torch |
|
from PIL import Image |
|
import os |
|
import io |
|
|
|
def pad_reflect(image, pad_size): |
|
imsize = image.shape |
|
height, width = imsize[:2] |
|
new_img = np.zeros([height+pad_size*2, width+pad_size*2, imsize[2]]).astype(np.uint8) |
|
new_img[pad_size:-pad_size, pad_size:-pad_size, :] = image |
|
|
|
new_img[0:pad_size, pad_size:-pad_size, :] = np.flip(image[0:pad_size, :, :], axis=0) |
|
new_img[-pad_size:, pad_size:-pad_size, :] = np.flip(image[-pad_size:, :, :], axis=0) |
|
new_img[:, 0:pad_size, :] = np.flip(new_img[:, pad_size:pad_size*2, :], axis=1) |
|
new_img[:, -pad_size:, :] = np.flip(new_img[:, -pad_size*2:-pad_size, :], axis=1) |
|
|
|
return new_img |
|
|
|
def unpad_image(image, pad_size): |
|
return image[pad_size:-pad_size, pad_size:-pad_size, :] |
|
|
|
|
|
def process_array(image_array, expand=True): |
|
""" Process a 3-dimensional array into a scaled, 4 dimensional batch of size 1. """ |
|
|
|
image_batch = image_array / 255.0 |
|
if expand: |
|
image_batch = np.expand_dims(image_batch, axis=0) |
|
return image_batch |
|
|
|
|
|
def process_output(output_tensor): |
|
""" Transforms the 4-dimensional output tensor into a suitable image format. """ |
|
|
|
sr_img = output_tensor.clip(0, 1) * 255 |
|
sr_img = np.uint8(sr_img) |
|
return sr_img |
|
|
|
|
|
def pad_patch(image_patch, padding_size, channel_last=True): |
|
""" Pads image_patch with with padding_size edge values. """ |
|
|
|
if channel_last: |
|
return np.pad( |
|
image_patch, |
|
((padding_size, padding_size), (padding_size, padding_size), (0, 0)), |
|
'edge', |
|
) |
|
else: |
|
return np.pad( |
|
image_patch, |
|
((0, 0), (padding_size, padding_size), (padding_size, padding_size)), |
|
'edge', |
|
) |
|
|
|
|
|
def unpad_patches(image_patches, padding_size): |
|
return image_patches[:, padding_size:-padding_size, padding_size:-padding_size, :] |
|
|
|
|
|
def split_image_into_overlapping_patches(image_array, patch_size, padding_size=2): |
|
""" Splits the image into partially overlapping patches. |
|
The patches overlap by padding_size pixels. |
|
Pads the image twice: |
|
- first to have a size multiple of the patch size, |
|
- then to have equal padding at the borders. |
|
Args: |
|
image_array: numpy array of the input image. |
|
patch_size: size of the patches from the original image (without padding). |
|
padding_size: size of the overlapping area. |
|
""" |
|
|
|
xmax, ymax, _ = image_array.shape |
|
x_remainder = xmax % patch_size |
|
y_remainder = ymax % patch_size |
|
|
|
|
|
x_extend = (patch_size - x_remainder) % patch_size |
|
y_extend = (patch_size - y_remainder) % patch_size |
|
|
|
|
|
extended_image = np.pad(image_array, ((0, x_extend), (0, y_extend), (0, 0)), 'edge') |
|
|
|
|
|
padded_image = pad_patch(extended_image, padding_size, channel_last=True) |
|
|
|
xmax, ymax, _ = padded_image.shape |
|
patches = [] |
|
|
|
x_lefts = range(padding_size, xmax - padding_size, patch_size) |
|
y_tops = range(padding_size, ymax - padding_size, patch_size) |
|
|
|
for x in x_lefts: |
|
for y in y_tops: |
|
x_left = x - padding_size |
|
y_top = y - padding_size |
|
x_right = x + patch_size + padding_size |
|
y_bottom = y + patch_size + padding_size |
|
patch = padded_image[x_left:x_right, y_top:y_bottom, :] |
|
patches.append(patch) |
|
|
|
return np.array(patches), padded_image.shape |
|
|
|
|
|
def stich_together(patches, padded_image_shape, target_shape, padding_size=4): |
|
""" Reconstruct the image from overlapping patches. |
|
After scaling, shapes and padding should be scaled too. |
|
Args: |
|
patches: patches obtained with split_image_into_overlapping_patches |
|
padded_image_shape: shape of the padded image contructed in split_image_into_overlapping_patches |
|
target_shape: shape of the final image |
|
padding_size: size of the overlapping area. |
|
""" |
|
|
|
xmax, ymax, _ = padded_image_shape |
|
patches = unpad_patches(patches, padding_size) |
|
patch_size = patches.shape[1] |
|
n_patches_per_row = ymax // patch_size |
|
|
|
complete_image = np.zeros((xmax, ymax, 3)) |
|
|
|
row = -1 |
|
col = 0 |
|
for i in range(len(patches)): |
|
if i % n_patches_per_row == 0: |
|
row += 1 |
|
col = 0 |
|
complete_image[ |
|
row * patch_size: (row + 1) * patch_size, col * patch_size: (col + 1) * patch_size,: |
|
] = patches[i] |
|
col += 1 |
|
return complete_image[0: target_shape[0], 0: target_shape[1], :] |