import random
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
#%matplotlib inline
import tensorflow as tf
import keras.backend as K
from keras.utils import to_categorical
from keras import metrics
from keras.models import Model, load_model
from keras.layers import Input, BatchNormalization, Activation, Dense, Dropout,Maximum
from keras.layers.core import Lambda, RepeatVector, Reshape
from keras.layers.convolutional import Conv2D, Conv2DTranspose,Conv3D,Conv3DTranspose
from keras.layers.pooling import MaxPooling2D, GlobalMaxPool2D,MaxPooling3D
from keras.layers.merge import concatenate, add
from keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau
from keras.optimizers import Adam
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img

from skimage.io import imread, imshow, concatenate_images
from skimage.transform import resize
from sklearn.utils import class_weight


from keras.callbacks import ModelCheckpoint
from keras.callbacks import CSVLogger
from keras.callbacks import EarlyStopping
from keras.layers.advanced_activations import PReLU

import os
from skimage.io import imread, imshow, concatenate_images
from skimage.transform import resize
# from medpy.io import load
import numpy as np

#import cv2
import nibabel as nib
from PIL import Image



def conv_block(input_mat,num_filters,kernel_size,batch_norm):
  X = Conv3D(num_filters,kernel_size=(kernel_size,kernel_size,kernel_size),strides=(1,1,1),padding='same')(input_mat)
  if batch_norm:
    X = BatchNormalization()(X)
  
  X = Activation('relu')(X)

  X = Conv3D(num_filters,kernel_size=(kernel_size,kernel_size,kernel_size),strides=(1,1,1),padding='same')(X)
  if batch_norm:
    X = BatchNormalization()(X)
  
  X = Activation('relu')(X)
    
  X = add([input_mat,X]);
  
  return X


def Vnet_3d(input_img, n_filters = 8, dropout = 0.2, batch_norm = True):

  #c1 = conv_block(input_img,n_filters,3,batch_norm)
  c1 = Conv3D(n_filters,kernel_size = (5,5,5) , strides = (1,1,1) , padding='same')(input_img)
  #c1 = add([c1,input_img])
  
  c2 = Conv3D(n_filters*2,kernel_size = (2,2,2) , strides = (2,2,2) , padding = 'same' )(c1)
  
  c3 = conv_block(c2 , n_filters*2,5,True)
  
  p3 = Conv3D(n_filters*4,kernel_size = (2,2,2) , strides = (2,2,2), padding = 'same')(c3)
  p3 = Dropout(dropout)(p3)
  
  c4 = conv_block(p3, n_filters*4,5,True)
  p4 = Conv3D(n_filters*8,kernel_size = (2,2,2) , strides = (2,2,2) , padding='same')(c4)
  p4 = Dropout(dropout)(p4)
    
  c5 = conv_block(p4, n_filters*8,5,True)
  p6 = Conv3D(n_filters*16,kernel_size = (2,2,2) , strides = (2,2,2) , padding='same')(c5)
  p6 = Dropout(dropout)(p6)
  #c6 = conv_block(p5, n_filters*8,5,True)
  #p6 = Conv3D(n_filters*16,kernel_size = (2,2,2) , strides = (2,2,2) , padding='same')(c6)

  p7 = conv_block(p6,n_filters*16,5,True)
    
  u6 = Conv3DTranspose(n_filters*8, (2,2,2), strides=(2, 2, 2), padding='same')(p7);
  u6 = concatenate([u6,c5]);
  c7 = conv_block(u6,n_filters*16,5,True)
  c7 = Dropout(dropout)(c7)
  u7 = Conv3DTranspose(n_filters*4,(2,2,2),strides = (2,2,2) , padding= 'same')(c7);

  
  u8 = concatenate([u7,c4]);
  c8 = conv_block(u8,n_filters*8,5,True)
  c8 = Dropout(dropout)(c8)
  u9 = Conv3DTranspose(n_filters*2,(2,2,2),strides = (2,2,2) , padding= 'same')(c8);
    
  u9 = concatenate([u9,c3]);
  c9 = conv_block(u9,n_filters*4,5,True)
  c9 = Dropout(dropout)(c9)
  u10 = Conv3DTranspose(n_filters,(2,2,2),strides = (2,2,2) , padding= 'same')(c9);
  
  
  u10 = concatenate([u10,c1]);
  c10 = Conv3D(n_filters*2,kernel_size = (5,5,5),strides = (1,1,1) , padding = 'same')(u10);
  c10 = Dropout(dropout)(c10)
  c10 = add([c10,u10]);
  
  

  #c9 = conv_block(u9,n_filters,3,batch_norm)
  outputs = Conv3D(4, (1,1,1), activation='softmax')(c10)

  model = Model(inputs=input_img, outputs=outputs)

  return model

[(55, 'keras.layers.merge.add', 'add', False, 'from keras.layers.merge import concatenate, add\n'), (86, 'keras.layers.merge.concatenate', 'concatenate', False, 'from keras.layers.merge import concatenate, add\n'), (92, 'keras.layers.merge.concatenate', 'concatenate', False, 'from keras.layers.merge import concatenate, add\n'), (97, 'keras.layers.merge.concatenate', 'concatenate', False, 'from keras.layers.merge import concatenate, add\n'), (103, 'keras.layers.merge.concatenate', 'concatenate', False, 'from keras.layers.merge import concatenate, add\n'), (106, 'keras.layers.merge.add', 'add', False, 'from keras.layers.merge import concatenate, add\n'), (113, 'keras.models.Model', 'Model', False, 'from keras.models import Model, load_model\n'), (43, 'keras.layers.convolutional.Conv3D', 'Conv3D', False, 'from keras.layers.convolutional import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose\n'), (47, 'keras.layers.Activation', 'Activation', False, 'from keras.layers import Input, BatchNormalization, Activation, Dense, Dropout, Maximum\n'), (49, 'keras.layers.convolutional.Conv3D', 'Conv3D', False, 'from keras.layers.convolutional import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose\n'), (53, 'keras.layers.Activation', 'Activation', False, 'from keras.layers import Input, BatchNormalization, Activation, Dense, Dropout, Maximum\n'), (63, 'keras.layers.convolutional.Conv3D', 'Conv3D', False, 'from keras.layers.convolutional import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose\n'), (66, 'keras.layers.convolutional.Conv3D', 'Conv3D', False, 'from keras.layers.convolutional import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose\n'), (70, 'keras.layers.convolutional.Conv3D', 'Conv3D', False, 'from keras.layers.convolutional import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose\n'), (71, 'keras.layers.Dropout', 'Dropout', False, 'from keras.layers import Input, BatchNormalization, Activation, Dense, Dropout, Maximum\n'), (74, 'keras.layers.convolutional.Conv3D', 'Conv3D', False, 'from keras.layers.convolutional import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose\n'), (75, 'keras.layers.Dropout', 'Dropout', False, 'from keras.layers import Input, BatchNormalization, Activation, Dense, Dropout, Maximum\n'), (78, 'keras.layers.convolutional.Conv3D', 'Conv3D', False, 'from keras.layers.convolutional import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose\n'), (79, 'keras.layers.Dropout', 'Dropout', False, 'from keras.layers import Input, BatchNormalization, Activation, Dense, Dropout, Maximum\n'), (85, 'keras.layers.convolutional.Conv3DTranspose', 'Conv3DTranspose', False, 'from keras.layers.convolutional import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose\n'), (88, 'keras.layers.Dropout', 'Dropout', False, 'from keras.layers import Input, BatchNormalization, Activation, Dense, Dropout, Maximum\n'), (89, 'keras.layers.convolutional.Conv3DTranspose', 'Conv3DTranspose', False, 'from keras.layers.convolutional import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose\n'), (94, 'keras.layers.Dropout', 'Dropout', False, 'from keras.layers import Input, BatchNormalization, Activation, Dense, Dropout, Maximum\n'), (95, 'keras.layers.convolutional.Conv3DTranspose', 'Conv3DTranspose', False, 'from keras.layers.convolutional import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose\n'), (99, 'keras.layers.Dropout', 'Dropout', False, 'from keras.layers import Input, BatchNormalization, Activation, Dense, Dropout, Maximum\n'), (100, 'keras.layers.convolutional.Conv3DTranspose', 'Conv3DTranspose', False, 'from keras.layers.convolutional import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose\n'), (104, 'keras.layers.convolutional.Conv3D', 'Conv3D', False, 'from keras.layers.convolutional import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose\n'), (105, 'keras.layers.Dropout', 'Dropout', False, 'from keras.layers import Input, BatchNormalization, Activation, Dense, Dropout, Maximum\n'), (111, 'keras.layers.convolutional.Conv3D', 'Conv3D', False, 'from keras.layers.convolutional import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose\n'), (45, 'keras.layers.BatchNormalization', 'BatchNormalization', False, 'from keras.layers import Input, BatchNormalization, Activation, Dense, Dropout, Maximum\n'), (51, 'keras.layers.BatchNormalization', 'BatchNormalization', False, 'from keras.layers import Input, BatchNormalization, Activation, Dense, Dropout, Maximum\n')]