%%capture %%bash pip install -q kaggle mkdir -p ~/.kaggle echo '{"username":"KAGGLE_USERNAME","key":"KAGGLE_KEY"}' > ~/.kaggle/kaggle.json chmod 600 ~/.kaggle/kaggle.json %%capture %%bash kaggle datasets download andrewmvd/dog-and-cat-detection unzip -q dog-and-cat-detection.zip from google.colab import drive drive.mount('/content/drive') import os import pathlib from glob import glob from tqdm import tqdm import matplotlib.pyplot as plt import numpy as np from PIL import Image import tensorflow as tf from tensorflow.keras import Model from tensorflow.keras.layers import * from tensorflow.keras.optimizers import Adam from tensorflow.keras.preprocessing.image import * SEED = 31 np.random.seed(SEED) def resize_image(image_array, factor): original_image = Image.fromarray(image_array) new_size = np.array(original_image.size) * factor new_size = new_size.astype(np.int32) new_size = tuple(new_size) resized = original_image.resize(new_size) resized = img_to_array(resized) resized = resized.astype(np.uint8) return resized def downsize_upsize_image(image, scale): scaled = resize_image(image, 1.0 / scale) scaled = resize_image(scaled, scale / 1.0) return scaled def tight_crop_image(image, scale): height, width = image.shape[:2] width -= int(width % scale) height -= int(height % scale) return image[:height, :width] def crop_input(image, x, y): y_slice = slice(y, y + INPUT_DIM) x_slice = slice(x, x + INPUT_DIM) return image[y_slice, x_slice] def crop_output(image, x, y): y_slice = slice(y + PAD, y + PAD + LABEL_SIZE) x_slice = slice(x + PAD, x + PAD + LABEL_SIZE) return image[y_slice, x_slice] file_patten = (pathlib.Path('/content') / 'images' / '*.png') file_pattern = str(file_patten) dataset_paths = [*glob(file_pattern)] SUBSET_SIZE = 1000 dataset_paths = np.random.choice(dataset_paths, SUBSET_SIZE) path = np.random.choice(dataset_paths) img = plt.imread(path) plt.imshow(img) SCALE = 2.0 INPUT_DIM = 33 LABEL_SIZE = 21 PAD = int((INPUT_DIM - LABEL_SIZE) / 2.0) STRIDE = 14 %%bash mkdir -p data mkdir -p training for image_path in tqdm(dataset_paths): filename = pathlib.Path(image_path).stem image = load_img(image_path) image = img_to_array(image) image = image.astype(np.uint8) image = tight_crop_image(image, SCALE) scaled = downsize_upsize_image(image, SCALE) height, width = image.shape[:2] for y in range(0, height - INPUT_DIM + 1, STRIDE): for x in range(0, width - INPUT_DIM + 1, STRIDE): crop = crop_input(scaled, x, y) target = crop_output(image, x, y) np.save(f'data/{filename}_{x}_{y}_input.np', crop) np.save(f'data/{filename}_{x}_{y}_output.np', target) class PatchesDataset(tf.keras.utils.Sequence): def __init__(self, batch_size, *args, **kwargs): self.batch_size = batch_size self.input = [*glob('data/*_input.np.npy')] self.output = [*glob('data/*_output.np.npy')] self.input.sort() self.output.sort() self.total_data = len(self.input) def __len__(self): # returns the number of batches return int(self.total_data / self.batch_size) def __getitem__(self, index): # returns one batch indices = self.random_indices() input = np.array([np.load(self.input[idx]) for idx in indices]) output = np.array([np.load(self.output[idx]) for idx in indices]) return input, output def random_indices(self): return np.random.choice(list(range(self.total_data)), self.batch_size, p=np.ones(self.total_data)/self.total_data) BATCH_SIZE = 1024 train_ds = PatchesDataset(BATCH_SIZE) len(train_ds) input, output = train_ds[0] input.shape, output.shape def create_model(height, width, depth): input = Input(shape=(height, width, depth)) x = Conv2D(filters=64, kernel_size=(9, 9), kernel_initializer='he_normal')(input) x = ReLU()(x) x = Conv2D(filters=32, kernel_size=(1, 1), kernel_initializer='he_normal')(x) x = ReLU()(x) output = Conv2D(filters=depth, kernel_size=(5, 5), kernel_initializer='he_normal')(x) return Model(input, output) EPOCHS = 12 optimizer = Adam(learning_rate=1e-3, decay=1e-3 / EPOCHS) model = create_model(INPUT_DIM, INPUT_DIM, 3) model.compile(loss='mse', optimizer=optimizer) model.summary() tf.keras.utils.plot_model(model, show_shapes = True, rankdir='LR') checkpoint_path = "training/cp.ckpt" checkpoint_dir = os.path.dirname(checkpoint_path) cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path, save_weights_only=True, verbose=1) model.fit(train_ds, epochs=EPOCHS, callbacks=[cp_callback]) %%bash mkdir -p /content/drive/MyDrive/super_resolution cp -r training/* /content/drive/MyDrive/super_resolution path = '/content/drive/MyDrive/super_resolution/model.h5' model.save(path) new_model = tf.keras.models.load_model(path) path = np.random.choice(dataset_paths) image = load_img(path) image = img_to_array(image) image = image.astype(np.uint8) image = tight_crop_image(image, SCALE) scaled = downsize_upsize_image(image, SCALE) output = np.zeros(scaled.shape) height, width = output.shape[:2] for y in range(0, height - INPUT_DIM + 1, LABEL_SIZE): for x in range(0, width - INPUT_DIM + 1, LABEL_SIZE): crop = crop_input(scaled, x, y) image_batch = np.expand_dims(crop, axis=0) prediction = model.predict(image_batch) new_shape = (LABEL_SIZE, LABEL_SIZE, 3) prediction = prediction.reshape(new_shape) output_y_slice = slice(y + PAD, y + PAD + LABEL_SIZE) output_x_slice = slice(x + PAD, x + PAD + LABEL_SIZE) output[output_y_slice, output_x_slice] = prediction figure, axis = plt.subplots(1, 2, figsize=(15, 8)) axis[0].imshow(np.array(scaled,np.int32)) axis[0].set_title('Low resolution image (Downsize + Upsize)') axis[0].axis('off') axis[1].imshow(np.array(output,np.int32)) axis[1].set_title('Super resolution result (SRCNN output)') axis[1].axis('off')