{"cells":[{"metadata":{"_cell_guid":"e61ef2d8-f315-4f7f-b07e-1de0f4e8441a","_uuid":"1677fddbb95f7545b6540e9201f3339a0fdbfc5d"},"cell_type":"markdown","source":"# Intro\n* This kernel shows how to generate small patches from the original images and generate a custo generator\n* Make sure you do part by part prediction if using this kind of generator\n* Also no need to resize the orignial image just get patches from original image and have a batch generator\n"},{"metadata":{"trusted":true,"_uuid":"709e3ff76ba0d08dbff3729c72aed760bde5cca5"},"cell_type":"code","source":"import os\nimport sys\nimport random\nimport warnings\nimport numpy as np\nimport pandas as pd\nimport h5py\n\n\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\nfrom itertools import chain\nfrom skimage.io import imread, imshow, imread_collection, concatenate_images\nfrom skimage.transform import resize\nfrom skimage.morphology import label\nfrom skimage import img_as_uint\n\n\n\nfrom keras.models import Model, load_model\nfrom keras.layers import Input, Dense, Activation, ZeroPadding2D, BatchNormalization, Flatten, Conv2D, UpSampling2D\nfrom keras.layers.core import Dropout, Lambda\nfrom keras.layers.convolutional import Conv2D, Conv2DTranspose\nfrom keras.layers.pooling import MaxPooling2D\nfrom keras.layers.merge import concatenate\nfrom keras.callbacks import EarlyStopping, ModelCheckpoint\nfrom keras import backend as K\nimport keras\nfrom keras import optimizers\n\n%matplotlib inline\n\nimport tensorflow as tf\nimport sklearn\nimport skimage\nfrom skimage import transform\nfrom os import environ\n\nseed = 42\n\nwarnings.filterwarnings('ignore', category=UserWarning, module='skimage')\nprint('Python       :', sys.version.split('\\n')[0])\nprint('Numpy        :', np.__version__)\nprint('Skimage      :', skimage.__version__)\nprint('Scikit-learn :', sklearn.__version__)\nprint('Keras        :', keras.__version__)\nprint('Tensorflow   :', tf.__version__)","execution_count":1,"outputs":[]},{"metadata":{"collapsed":true,"trusted":true,"_uuid":"83c6e8299ea14866b23778842f6785d00680ad9d"},"cell_type":"code","source":"IMG_WIDTH = 512\nIMG_HEIGHT = 512\nIMG_CHANNELS = 3\nimg_rows = 64\nimg_cols = 64\n\nTRAIN_PATH = '../input/stage1_train/'\nTEST_PATH = '../input/stage1_test/'\nIMG_TYPE = '.png'         # Image type\nIMG_DIR_NAME = 'images'   # Folder name including the image\nMASK_DIR_NAME = 'masks'   # Folder name including the masks\nLOGS_DIR_NAME = 'logs'    # Folder name for TensorBoard summaries \nSAVES_DIR_NAME = 'saves'  # Folder name for storing network parameters","execution_count":6,"outputs":[]},{"metadata":{"_uuid":"e3a6121804eb428a44f5e0d40c7b475c6fa8af68","trusted":true},"cell_type":"code","source":"from tensorflow.python.client import device_lib\nprint(device_lib.list_local_devices())","execution_count":7,"outputs":[]},{"metadata":{"_cell_guid":"59c4a25d-645f-4b74-9c53-145ac78cc481","_uuid":"875af74f980236825de3a650825b46e25632422c"},"cell_type":"markdown","source":"# Get the data\nLet's first import all the images and associated masks. \n\nI downsample both the training and test images to keep things light and manageable, but we need to keep a record of the original sizes of the test images to upsample our predicted masks and create correct run-length encodings later on. There are definitely better ways to handle this, but it works fine for now!"},{"metadata":{"_cell_guid":"ca0cc34b-c26f-41ee-88d7-975aebdb634e","_uuid":"9e389ba8bdb5b6fc03b231b6a6c84a8bde634053","collapsed":true,"trusted":true},"cell_type":"code","source":"# Collection of methods for data operations. Implemented are functions to read  \n# images/masks from files and to read basic properties of the train/test data sets.\nimport cv2\n\ndef read_image(filepath, color_mode=cv2.IMREAD_COLOR, target_size=None):\n    \"\"\"Read an image from a file and resize it.\"\"\"\n    img = cv2.imread(filepath, color_mode)\n    if target_size: \n        img = cv2.resize(img, target_size, interpolation = cv2.INTER_AREA)\n    return img\n\ndef read_mask(directory, target_size=None):\n    \"\"\"Read and resize masks contained in a given directory.\"\"\"\n    for i,filename in enumerate(next(os.walk(directory))[2]):\n        mask_path = os.path.join(directory, filename)\n        mask_tmp = read_image(mask_path, cv2.IMREAD_GRAYSCALE, target_size)\n        if not i: mask = mask_tmp\n        else: mask = np.maximum(mask, mask_tmp)\n    return mask \n\ndef read_train_data_properties(train_dir, img_dir_name, mask_dir_name):\n    \"\"\"Read basic properties of training images and masks\"\"\"\n    tmp = []\n    for i,dir_name in enumerate(next(os.walk(train_dir))[1]):\n\n        img_dir = os.path.join(train_dir, dir_name, img_dir_name)\n        mask_dir = os.path.join(train_dir, dir_name, mask_dir_name) \n        num_masks = len(next(os.walk(mask_dir))[2])\n        img_name = next(os.walk(img_dir))[2][0]\n        img_name_id = os.path.splitext(img_name)[0]\n        img_path = os.path.join(img_dir, img_name)\n        img_shape = read_image(img_path).shape\n        tmp.append(['{}'.format(img_name_id), img_shape[0], img_shape[1],\n                    img_shape[0]/img_shape[1], img_shape[2], num_masks,\n                    img_path, mask_dir])\n\n    train_df = pd.DataFrame(tmp, columns = ['img_id', 'img_height', 'img_width',\n                                            'img_ratio', 'num_channels', \n                                            'num_masks', 'image_path', 'mask_dir'])\n    return train_df\n\ndef read_test_data_properties(test_dir, img_dir_name):\n    \"\"\"Read basic properties of test images.\"\"\"\n    tmp = []\n    sizes_test = []\n    for i,dir_name in enumerate(next(os.walk(test_dir))[1]):\n\n        img_dir = os.path.join(test_dir, dir_name, img_dir_name)\n        img_name = next(os.walk(img_dir))[2][0]\n        img_name_id = os.path.splitext(img_name)[0]\n        img_path = os.path.join(img_dir, img_name)\n        img_shape = read_image(img_path).shape\n        sizes_test.append([img_shape[0], img_shape[1]])\n\n        tmp.append(['{}'.format(img_name_id), img_shape[0], img_shape[1],\n                    img_shape[0]/img_shape[1], img_shape[2], img_path])\n\n    test_df = pd.DataFrame(tmp, columns = ['img_id', 'img_height', 'img_width',\n                                           'img_ratio', 'num_channels', 'image_path'])\n    return test_df, sizes_test\n\ndef imshow_args(x):\n    \"\"\"Matplotlib imshow arguments for plotting.\"\"\"\n    if len(x.shape)==2: return x, cm.gray\n    if x.shape[2]==1: return x[:,:,0], cm.gray\n    return x, None\n\ndef load_raw_data(image_size=(IMG_HEIGHT, IMG_WIDTH)):\n    \"\"\"Load raw data.\"\"\"\n    # Python lists to store the training images/masks and test images.\n    x_train, y_train, x_test = [],[],[]\n\n    # Read and resize train images/masks. \n    print('Loading and resizing train images and masks ...')\n    sys.stdout.flush()\n    for i, filename in tqdm(enumerate(train_df['image_path']), total=len(train_df)):\n        #img = read_image(train_df['image_path'].loc[i], target_size=image_size)\n        #mask = read_mask(train_df['mask_dir'].loc[i], target_size=image_size)\n        img = read_image(train_df['image_path'].loc[i]) # dont resize\n        mask = read_mask(train_df['mask_dir'].loc[i]) # dont resize\n        \n        x_train.append(img)\n        y_train.append(mask)\n\n    # Read and resize test images. \n    print('Loading and resizing test images ...')\n    sys.stdout.flush()\n    for i, filename in tqdm(enumerate(test_df['image_path']), total=len(test_df)):\n        #img = read_image(test_df['image_path'].loc[i], target_size=image_size)\n        img = read_image(test_df['image_path'].loc[i]) #dont resize\n        x_test.append(img)\n\n    # Transform lists into 4-dim numpy arrays.\n    x_train = np.array(x_train)\n    #y_train = np.expand_dims(np.array(y_train), axis=4)\n    y_train = np.array(y_train)\n    x_test = np.array(x_test)\n\n    #print('x_train.shape: {} of dtype {}'.format(x_train.shape, x_train.dtype))\n    #print('y_train.shape: {} of dtype {}'.format(y_train.shape, x_train.dtype))\n    #print('x_test.shape: {} of dtype {}'.format(x_test.shape, x_test.dtype))\n    \n    return x_train, y_train, x_test","execution_count":8,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5984b0c83c32ceeb740a767437d68415c0370547"},"cell_type":"code","source":"# Basic properties of images/masks. \ntrain_df = read_train_data_properties(TRAIN_PATH, IMG_DIR_NAME, MASK_DIR_NAME)\ntest_df, sizes_test = read_test_data_properties(TEST_PATH, IMG_DIR_NAME)\nprint('train_df:')\nprint(train_df.describe())\nprint('')\nprint('test_df:')\nprint(test_df.describe())\nprint(sizes_test[0])","execution_count":9,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"21b01a05418cd55b86eb4efd47b4233dd0e95530"},"cell_type":"code","source":"X_train, Y_train, X_test = load_raw_data()","execution_count":10,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"51609c25fae40ef5a6dc5b6068ec948799c80484"},"cell_type":"code","source":"print('X_Train={} , Y_train={}, X_test={}'.format(X_train.shape, Y_train.shape, X_test.shape))","execution_count":11,"outputs":[]},{"metadata":{"collapsed":true,"trusted":true,"_uuid":"ab672943ca9ee4e88d531ab0fb2129b170dce300"},"cell_type":"code","source":"def flip_axis(x, axis):\n    x = np.asarray(x).swapaxes(axis, 0)\n    x = x[::-1, ...]\n    x = x.swapaxes(0, axis)\n    return x\n\ndef form_batch(X, Y, batch_size):\n    X_batch = np.zeros((batch_size, img_rows, img_cols, IMG_CHANNELS))\n    Y_batch = np.zeros((batch_size, img_rows, img_cols, 1))\n    \n\n    for i in range(batch_size):\n        #Every batch consists of images from multiple random image\n        #Other way of doing it is to make eatch batch consists of patch from same image\n        random_image_idx = np.random.randint(len(X))\n        x = X[random_image_idx]\n        y = Y[random_image_idx]\n        X_height = x.shape[0]\n        X_width = x.shape[1]\n\n        random_width = random.randint(0, X_width - img_cols - 1)\n        random_height = random.randint(0, X_height - img_rows - 1)\n        \n        Y_batch[i] = np.expand_dims(y[random_height: random_height + img_rows, random_width: random_width + img_cols]\n                                   , axis=3)\n        X_batch[i] = np.array(x[random_height: random_height + img_rows, \n                                random_width: random_width + img_cols, : ])\n    return X_batch, Y_batch\n\ndef batch_generator(X, Y, batch_size, horizontal_flip=True, vertical_flip=True, swap_axis=True):\n    #count = 0\n    while True:\n        #count += 1\n        X_batch, Y_batch = form_batch(X, Y, batch_size)\n\n        for i in range(X_batch.shape[0]):\n            xb = X_batch[i]\n            yb = Y_batch[i]\n\n            if horizontal_flip:\n                if np.random.random() < 0.5:\n                    xb = flip_axis(xb, 1)\n                    yb = flip_axis(yb, 1)\n\n            if vertical_flip:\n                if np.random.random() < 0.5:\n                    xb = flip_axis(xb, 2)\n                    yb = flip_axis(yb, 2)\n\n            if swap_axis:\n                if np.random.random() < 0.5:\n                    xb = xb.swapaxes(0, 1)\n                    yb = yb.swapaxes(0, 1)\n\n            X_batch[i] = xb\n            Y_batch[i] = yb\n        #change this to yield when using as generator\n        return X_batch, Y_batch","execution_count":12,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a8ecf0d253aea3e438ccbad3b7f52dc13f97a48a"},"cell_type":"code","source":"batch_size = 16\nno_cols = 4\nX_batch, Y_batch = batch_generator(X_train, Y_train, batch_size)\nplt.close('all')\nno_rows = int(batch_size/no_cols)\n\nfig, axes = plt.subplots(no_rows*2, no_cols, figsize = (20, 20))\n\ncount = 0\nfor i in range(no_rows):\n    for j in range(no_cols):\n        axes[2*i, j].imshow(X_batch[count])\n        axes[2*i, j].axis('off')\n\n        axes[2*i+1, j].imshow(np.squeeze(Y_batch[count]))\n        axes[2*i+1, j].axis('off')\n        axes[2*i+1, j].set_title('{}{} th True Y patch'.format(i,j))\n        count +=1\n","execution_count":15,"outputs":[]},{"metadata":{"_cell_guid":"222475b9-3171-461a-90f0-a820a6bd2634","_uuid":"fb5e6f8cca872f1bd7036f6d9ac2ed2cab615536","collapsed":true},"cell_type":"markdown","source":"* Make sure to predict patch by patch and merge the results when using this approch\n* using following code you can fit the generator\n* model.fit_generator(generator=train_gen, epochs=200, verbose=1, steps_per_epoch=len(train_df) / batch_size, validation_data=valid_gen, validation_steps=v_steps, callbacks=callbacks)\n"},{"metadata":{"collapsed":true,"trusted":false,"_uuid":"f3f06465216f9119f8fb32144942124bc983c154"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}