Exemple #1
0
def augment_image(image_path, out_dir):
    """ This function augments the passed in image with three
    transformations. First it horizontally flips the image, then it rotates
    it by 20 degrees, and finally, it horizontally flips it, rotates it by 5
    degrees, and translates it on the y-axis by 50 units.
    
    The three resultant images are saved to hf_{image_name}, rt_{image_name},
    and tl_{image_name} in the provided directory, respectively."""

    # Setup ImageDataGenerator, the normal parameters don't matter since we will manually
    # apply transforms
    image_path = os.path.abspath(image_path)
    out_dir = os.path.abspath(out_dir)
    image_filename_pattern = r'[^/]+$'
    image_filename = re.search(image_filename_pattern, image_path)
    if not image_filename:
        print('Unable to extract filename from the provided path.')
        sys.exit(1)
    image_filename = image_filename.group(0)

    datagen = ImageDataGenerator(rescale=1. / 255)
    transform_params = {}

    # Load the image using OpenCV2
    img_array = cv2.imread(image_path, cv2.IMREAD_COLOR)
    _, width, _ = img_array.shape

    # Apply horizontal flip
    transform_params['flip_horizontal'] = True
    horizontal_image = datagen.apply_transform(img_array, transform_params)
    transform_params.clear()

    # Apply 20 degree rotation
    transform_params['theta'] = 20.0
    rotated_image = datagen.apply_transform(img_array, transform_params)
    transform_params.clear()

    # Apply translation
    transform_params['flip_horizontal'] = True
    transform_params['theta'] = 15.0
    transform_params['ty'] = width * 0.2
    translated_image = datagen.apply_transform(img_array, transform_params)
    transform_params.clear()

    # Save images
    did_succeed = True
    did_succeed = did_succeed and cv2.imwrite(
        os.path.join(out_dir, image_filename), img_array)
    did_succeed = did_succeed and cv2.imwrite(
        os.path.join(out_dir, f'hf_{image_filename}'), horizontal_image)
    did_succeed = did_succeed and cv2.imwrite(
        os.path.join(out_dir, f'rt_{image_filename}'), rotated_image)
    did_succeed = did_succeed and cv2.imwrite(
        os.path.join(out_dir, f'tl_{image_filename}'), translated_image)

    if did_succeed:
        print(f'Successfully saved images to {out_dir}')
    else:
        print(f'Unable to save images to {out_dir}')
Exemple #2
0
class LineDetectorModel(Model):
    """Model to detect lines of text in an image."""
    def __init__(
        self,
        dataset_cls: type = IamParagraphsDataset,
        network_fn: Callable = fcn,
        dataset_args: Dict = None,
        network_args: Dict = None,
    ):
        """Define the default dataset and network values for this model."""
        super().__init__(dataset_cls, network_fn, dataset_args, network_args)

        self.data_augmentor = ImageDataGenerator(**_DATA_AUGMENTATION_PARAMS)
        self.batch_augment_fn = self.augment_batch

    def loss(self):  # pylint: disable=no-self-use
        return "categorical_crossentropy"

    def optimizer(self):  # pylint: disable=no-self-use
        return Adam(0.001 / 2)

    def metrics(self):  # pylint: disable=no-self-use
        return None

    def augment_batch(self, x_batch: np.ndarray,
                      y_batch: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
        """Perform different random transformations on the whole batch of x, y samples."""
        x_augment, y_augment = zip(
            *[self._augment_sample(x, y) for x, y in zip(x_batch, y_batch)])
        return np.stack(x_augment, axis=0), np.stack(y_augment, axis=0)

    def _augment_sample(self, x: np.ndarray,
                        y: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
        """
        Perform the same random image transformation on both x and y.
        x is a 2d image of shape self.image_shape, but self.data_augmentor needs the channel image too.
        """
        x_3d = np.expand_dims(x, axis=-1)
        transform_parameters = self.data_augmentor.get_random_transform(
            x_3d.shape)
        x_augment = self.data_augmentor.apply_transform(
            x_3d, transform_parameters)
        y_augment = self.data_augmentor.apply_transform(
            y, transform_parameters)
        return np.squeeze(x_augment, axis=-1), y_augment

    def predict_on_image(self, x: np.ndarray) -> np.ndarray:
        """Predict on a single input."""
        return self.network.predict(np.expand_dims(x, axis=0))[0]

    def evaluate(self,
                 x: np.ndarray,
                 y: np.ndarray,
                 batch_size: int = 32,
                 verbose: bool = False) -> float:
        """Evaluate the model."""
        # pylint: disable=unused-argument
        return self.network.evaluate(x, y, batch_size=batch_size)
Exemple #3
0
class LineDetectModel(Model):
    """Model to detect lines of text in an image."""
    def __init__(self,
                 network_fn: Callable = lenetFCN,
                 dataset: type = IAMPara):
        """Define the default dataset and network values for this model."""
        super().__init__(network_fn, dataset)
        print('[INFO] Arguments passed to data augmentation...',
              DATA_AUGMENTATION_PARAMS)
        self.data_augmentor = ImageDataGenerator(**DATA_AUGMENTATION_PARAMS)
        self.batch_augment_fn = self.augment_batch

    def metrics(self):
        return None

    def augment_batch(self, x_batch: np.ndarray,
                      y_batch: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
        """Performs different random transformations on the whole batch of x, y samples."""
        x_augment, y_augment = zip(
            *[self.augment_sample(x, y) for x, y in zip(x_batch, y_batch)])
        return np.stack(x_augment, axis=0), np.stack(y_augment, axis=0)

    def augment_sample(self, x: np.ndarray,
                       y: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
        """
        Perform the same random image transformation on both x and y.
        x is a 2d image of shape self.image_shape, but self.data_augmentor needs the channel image too.
        """
        x_3d = np.expand_dims(x, axis=-1)
        transform_parameters = self.data_augmentor.get_random_transform(
            x_3d.shape)
        x_augment = self.data_augmentor.apply_transform(
            x_3d, transform_parameters)
        y_augment = self.data_augmentor.apply_transform(
            y, transform_parameters)
        return np.squeeze(x_augment, axis=-1), y_augment

    def predict_on_image(self, x: np.ndarray) -> np.ndarray:
        """Returns the network predictions on x."""
        return self.network.predict(np.expand_dims(x, axis=0))[0]
Exemple #4
0
def expand_data(data, labels):
    # Create data generator
    transforms = {'tx': 0.1, 'ty': 0.1, 'flip_horizontal': True}
    datagen = ImageDataGenerator()
    new_data = []
    new_labels = []
    for d, l in zip(data, labels):
        e = datagen.apply_transform(d, transforms)
        new_data.append(e)
        new_labels.append(l)

    new_data = np.array(new_data)
    new_labels = np.array(new_labels)
    all_data = np.concatenate((data, new_data), axis=0)
    all_labels = np.concatenate((labels, new_labels), axis=0)

    return (all_data, all_labels)
class DataGenerator(keras.utils.Sequence):
    def __init__(self,
                 list_IDs,
                 labels,
                 batch_size=32,
                 dim=(32, 32),
                 shuffle=True,
                 type_gen='train'):
        'Initialization'
        self.dim = dim
        self.batch_size = batch_size
        self.labels = labels
        self.list_IDs = list_IDs
        self.shuffle = shuffle
        self.type_gen = type_gen
        self.aug_gen = ImageDataGenerator()
        print("all:", len(self.list_IDs), " batch per epoch",
              int(np.floor(len(self.list_IDs) / self.batch_size)))
        self.on_epoch_end()

    def __len__(self):
        'Denotes the number of batches per epoch'
        return int(np.floor(len(self.list_IDs) / self.batch_size))

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate indexes of the batch
        indexes = self.indexes[index * self.batch_size:(index + 1) *
                               self.batch_size]
        # Find list of IDs
        list_IDs_temp = [self.list_IDs[k] for k in indexes]
        # Generate data
        X, y = self.__data_generation(list_IDs_temp)
        if self.type_gen == 'predict':
            return X
        else:
            return X, y

    def sequence_augment(self, img):
        name_list = [
            'rotate', 'width_shift', 'height_shift', 'brightness',
            'flip_horizontal', 'width_zoom', 'height_zoom'
        ]
        dictkey_list = [
            'theta', 'ty', 'tx', 'brightness', 'flip_horizontal', 'zy', 'zx'
        ]
        random_aug = np.random.randint(2, 5)  # random 2-4 augmentation method
        pick_idx = np.random.choice(len(dictkey_list),
                                    random_aug,
                                    replace=False)  #

        dict_input = {}
        for i in pick_idx:
            if dictkey_list[i] == 'theta':
                dict_input['theta'] = np.random.randint(-10, 10)

            elif dictkey_list[i] == 'ty':  # width_shift
                dict_input['ty'] = np.random.randint(-20, 20)

            elif dictkey_list[i] == 'tx':  # height_shift
                dict_input['tx'] = np.random.randint(-20, 20)

            elif dictkey_list[i] == 'brightness':
                dict_input['brightness'] = np.random.uniform(0.75, 1.25)

            elif dictkey_list[i] == 'flip_horizontal':
                dict_input['flip_horizontal'] = bool(random.getrandbits(1))

            elif dictkey_list[i] == 'zy':  # width_zoom
                dict_input['zy'] = np.random.uniform(0.75, 1.25)

            elif dictkey_list[i] == 'zx':  # height_zoom
                dict_input['zx'] = np.random.uniform(0.75, 1.25)
        img = self.aug_gen.apply_transform(img, dict_input)
        return img

    def albu_aug(self, image, tfms=albu_tfms):
        seed = random.randint(0, 99999)

        random.seed(seed)
        image = tfms(image=image.astype('uint8'))['image']
        return image

    def __data_generation(self, list_IDs_temp):
        'Generates data containing batch_size samples'
        # Initialization
        X = [
            np.empty((self.batch_size, self.dim[0], self.dim[1], 3)),
            np.empty((self.batch_size, self.dim[0], self.dim[1], 3))
        ]
        Y = np.empty((self.batch_size), dtype=int)

        for i, ID in enumerate(list_IDs_temp):  # ID is name of file
            img = cv2.imread(ID)
            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            img = cv2.resize(img, (self.dim[1], self.dim[0]))

            if self.type_gen == 'train':
                img = self.sequence_augment(img)

                new_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
                new_img = np.expand_dims(new_img, -1)
                new_img = automatedMSRCR(new_img, [10, 20, 30])
                new_img = cv2.cvtColor(new_img[:, :, 0], cv2.COLOR_GRAY2RGB)

                X[0][i] = img / 255.0
                X[1][i] = new_img / 255.0
            else:
                new_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
                new_img = np.expand_dims(new_img, -1)
                new_img = automatedMSRCR(new_img, [10, 20, 30])
                new_img = cv2.cvtColor(new_img[:, :, 0], cv2.COLOR_GRAY2RGB)

                X[0][i] = img / 255.0
                X[1][i] = new_img / 255.0

            Y[i] = self.labels[ID]

        return X, Y
Exemple #6
0
class DataGen(keras.utils.Sequence):
    
    def __init__(self, filepath, batch_size=4, target_size=(48,48)):
                
        with open(filepath, 'r') as f:
            lines = f.readlines()
        
        self.target_size = target_size
        self.data_dir = os.path.dirname(os.path.abspath(filepath))
        self.batch_size = batch_size
        self.class_num = 6
        self.fnames = [line.replace('\n', '') for line in lines]
        self.shuffle = True
        self.aug_gen = ImageDataGenerator() 
        self.on_epoch_end()
        
    def __len__(self):
        'Denotes the number of batches per epoch'
        return int(np.floor(len(self.fnames) / self.batch_size))

    def name(self):
        return 'human'
    
    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate indexes of the batch
        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]

        # Find list of IDs
        fnames = [self.fnames[k] for k in indexes]
#         print(fnames)

#         for fname in fnames:
#             imgs = cv2.imread(os.path.join(self.data_dir, fname))
            
        data = np.array([img_to_array(load_img(os.path.join(self.data_dir, fname.replace('pick','hat')), target_size=self.target_size))
                           for fname in fnames
                      ]).astype('float32')
        data = data/255.
        
        y_data = np.array([img_to_array(load_img(os.path.join(self.data_dir, fname), target_size=self.target_size))
                           for fname in fnames
                      ]).astype('float32')
        y_data = y_data/255.

#         data = self.img_augment(data)
#         y_data = data.copy()
#         data_len = y_data.shape[0]
#         w,h=self.target_size
#         for i in range(data_len):
#             y_data[i][0:10,0:w,0:3] = (0,0,0)
#             y_data[i][h-10:h,0:w,0:3] = (0,0,0)
#             y_data[i][0:h,0:10,0:3] = (0,0,0)
#             y_data[i][0:h,w-10:w,0:3] = (0,0,0)

        return data, y_data

    def img_augment(self, data):
        name_list = ['rotate','width_shift','height_shift',
                    'brightness','flip_horizontal','width_zoom',
                    'height_zoom']
        dictkey_list = ['theta','ty','tx',
                    'brightness','flip_horizontal','zy',
                    'zx']
        # dictkey_list = ['ty','tx','zy','zx']
        random_aug = np.random.randint(2, 5) # random 2-4 augmentation method
        pick_idx = np.random.choice(len(dictkey_list), random_aug, replace=False) #

        dict_input = {}
        for i in pick_idx:
            if dictkey_list[i] == 'theta':
                dict_input['theta'] = np.random.randint(-10, 10)

#             elif dictkey_list[i] == 'ty': # width_shift
#                 dict_input['ty'] = np.random.randint(-10, 10)

#             elif dictkey_list[i] == 'tx': # height_shift
#                 dict_input['tx'] = np.random.randint(-10, 10)

            elif dictkey_list[i] == 'brightness': 
                dict_input['brightness'] = np.random.uniform(0.15,1)

            elif dictkey_list[i] == 'flip_horizontal': 
                dict_input['flip_horizontal'] = True

            elif dictkey_list[i] == 'zy': # width_zoom
                dict_input['zy'] = np.random.uniform(0.5,1.5)

            elif dictkey_list[i] == 'zx': # height_zoom
                dict_input['zx'] = np.random.uniform(0.5,1.5)

        data_len = data.shape[0]
        for i in range(data_len):
            data[i] = self.aug_gen.apply_transform(data[i], dict_input)/255.0
                
        return data
        
    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.fnames))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)
            
Exemple #7
0
def augment_dataset(samples: list, augmented_dir:str, multiplier:int=2, register:bool=False, res:tuple=(120, 160)):
    """ 
    Augments a dataset. Will attempt to balance classes.

    Params
    ------
    samples: list
        List of sample annotation tuples (rgb path, lwir path, class label)
    augmented_dir: str
        Directory to store augmented data at
    multiplier: int
        Multiplication factor for number of new samples
    register: bool
        Whether to align RGB images with LWIR images

    Returns
    ------
    A list containing tuples of (rgb path, lwir path, class name) for new augmented dataset
    """

    if os.path.exists(augmented_dir):
        shutil.rmtree(augmented_dir)

    datagen = ImageDataGenerator(
        horizontal_flip=True,
        rotation_range=30,
        zoom_range=[0.5, 1],
    )

    classes = {}

    # Get classes
    for sample in samples:
        classes[sample[-1]] = classes.get(sample[-1], 0) + 1

    # Get maximum class samples
    max_class = max(classes.items(), key=lambda x: x[1])
    class_multipliers = {x: max_class[1] * multiplier // y for x, y in classes.items()}
    class_remainders = {x: (max_class[1] * multiplier) % y for x, y in classes.items()}

    # Generate output directory structure
    for label in classes:
        os.makedirs(os.path.join(augmented_dir, label, f"{label}_single_1", "lwir"))
        os.makedirs(os.path.join(augmented_dir, label, f"{label}_single_1", "rgb"))

    # Augment and copy
    augmented_samples = []
    for rgb_path, lwir_path, label in tqdm(samples, position=0):
        rgb = cv2.imread(rgb_path)

        if register:
            rgb = cv2.resize(rgb, tuple(cfg.large.res))
            rgb = cv2.warpAffine(rgb, cfg.large.matrix, tuple(cfg.large.res))
        rgb = cv2.resize(rgb, res)

        lwir = cv2.imread(lwir_path)
        lwir = cv2.resize(lwir, res)

        name = (rgb_path.split("/")[-1]).split(".")[0][4:]
        out_path = os.path.join(augmented_dir, label, f"{label}_single_1")

        # Copy original
        augmented_samples.append(save(out_path, name, rgb, lwir, label, extension=""))

        # Flipped
        if multiplier > 1:
            rgb_t = datagen.apply_transform(rgb, {"flip_horizontal": True})
            lwir_t = datagen.apply_transform(lwir, {"flip_horizontal": True})

            augmented_samples.append(save(out_path, name, rgb_t, lwir_t, label, extension=0))

        # Random transformations
        remainder = 1 if class_remainders[label] > 0 else 0
        class_remainders[label] -= 1
        for i in range(2, class_multipliers[label] + remainder):
            trans = datagen.get_random_transform(rgb.shape)
            rgb_t = datagen.apply_transform(rgb, trans)
            lwir_t = datagen.apply_transform(lwir, trans)

            augmented_samples.append(save(out_path, name, rgb_t, lwir_t, label, extension=i))

    return augmented_samples
Exemple #8
0
class Generate(Sequence, Prep): # Keras generator class
    def __init__(self, root, trainingmode, augmentation, nb_classes, batchsize,
                 rotation, translation_xy, scale_xy, flip_h, flip_v):
        Prep.__init__(self, root)
        self.train, self.validate = Prep.initializedatalist(self)
        self.trainingmode = trainingmode
        self.augmentation = augmentation
        self.nb_classes = nb_classes
        self.batchsize = batchsize
        self.rotation = rotation
        self.translation_xy = translation_xy
        self.scale_xy = scale_xy
        self.flip_h = flip_h
        self.flip_v = flip_v
        self.datagenI = ImageDataGenerator(fill_mode = "constant", cval = -1000)
        self.datagenL = ImageDataGenerator(fill_mode = "constant", cval = 0)
        with open (os.path.join(root, "0_sorted", "att_clswt.dat"), "rb") as outfile:
            self.clswt = pickle.load(outfile)
            
    def wImg(self, label): # Computes the weight matrix
        wImg = np.zeros(label.shape)
        for k in range(self.nb_classes):
            ind = np.where(label == k)
            wImg[ind] = self.clswt[k]
        return wImg

    def __len__(self):
        if self.trainingmode:
            return int(np.ceil(len(self.train)/self.batchsize))
        else:
            return int(np.ceil(len(self.validate)/self.batchsize))

    def __getitem__(self, counter):
        ### TRAINING GENERATOR ###
        if self.trainingmode:
            imagebatch = np.zeros((0,512,512,1))
            labelbatch = np.zeros((0,262144,self.nb_classes))
            weightmatrixbatch = np.zeros((0,262144))
            scans = self.train[counter*self.batchsize:(counter+1)*self.batchsize]
            
            for each in scans:
                with open (each, "rb") as outfile:
                    data = pickle.load(outfile)
                    image, label = data[0], data[1]
                    image, label = image.astype(np.float32), label.astype(np.float32)
                
                weightmatrix = self.wImg(label).flatten()
                weightmatrix = np.expand_dims(weightmatrix, axis = 0)
                label = to_categorical(label, self.nb_classes)
                
                # data augmentation
                flip_h, flip_v = 0, 0
                if self.flip_h:
                    flip_h = np.random.randint(2)
                if self.flip_v:
                    flip_v = np.random.randint(2)
                parameters = {"theta": np.random.randint(-self.rotation, self.rotation+1),
                              "tx": np.random.randint(-self.translation_xy, self.translation_xy+1),
                              "ty": np.random.randint(-self.translation_xy, self.translation_xy+1),
                              "shear": 0,
                              "zx": 1 + np.random.uniform(-self.scale_xy, self.scale_xy),
                              "zy": 1 + np.random.uniform(-self.scale_xy, self.scale_xy),
                              "flip_horizontal": flip_h, "flip_vertical": flip_v}
                image, label = self.datagenI.apply_transform(image, parameters), self.datagenL.apply_transform(label, parameters)

                image, label = image.astype(np.float32), label.astype(np.float32)
                image = np.expand_dims(image, axis = 0)
                label = np.expand_dims(label, axis = 0)
                label = label.reshape(1,262144,self.nb_classes)
                imagebatch = np.concatenate((imagebatch, image), axis=0)
                labelbatch = np.concatenate((labelbatch, label), axis=0)
                weightmatrixbatch = np.concatenate((weightmatrixbatch, weightmatrix), axis=0)
            
            return (imagebatch, labelbatch, weightmatrixbatch)
        
        ### VALIDATION GENERATOR ###
        else:
            imagebatch = np.zeros((0,512,512,1))
            labelbatch = np.zeros((0,262144,self.nb_classes))
            
            scans = self.validate[counter*self.batchsize:(counter+1)*self.batchsize]
            for each in scans:
                with open (each, "rb") as outfile:
                    data = pickle.load(outfile)
                    image, label = data[0], data[1]
                    image, label = image.astype(np.float32), label.astype(np.float32)
                    
                label = to_categorical(label, self.nb_classes)
                label = label.reshape(262144,self.nb_classes)
                image = np.expand_dims(image, axis = 0)
                label = np.expand_dims(label, axis = 0)

                imagebatch = np.concatenate((imagebatch, image), axis=0)
                labelbatch = np.concatenate((labelbatch, label), axis=0)
        
            return (imagebatch, labelbatch)
Exemple #9
0
class TextImageGenerator:
    def __init__(self,
                 img_dirpath,
                 labels_path,
                 img_w,
                 img_h,
                 batch_size,
                 downsample_factor,
                 idxs,
                 max_text_len=70,
                 training=True):
        self.img_h = img_h
        self.img_w = img_w
        self.batch_size = batch_size
        self.max_text_len = max_text_len
        self.training = training
        self.idxs = idxs
        self.downsample_factor = downsample_factor
        self.img_dirpath = img_dirpath  # image dir path
        self.labels = json.load(
            open(labels_path,
                 'rb'), encoding="utf8") if labels_path != None else None
        self.img_dir = []
        for img_file in os.listdir(self.img_dirpath):  # images list
            if img_file != 'labels.json' and '.ipynb' not in img_file:
                self.img_dir.append(img_file)
        random.shuffle(self.img_dir)
        if self.idxs is not None:
            self.img_dir = [self.img_dir[idx] for idx in self.idxs]

        self.n = len(self.img_dir)  # number of images
        self.indexes = list(range(self.n))
        self.cur_index = 0
        self.imgs = np.ones((self.n, self.img_h, self.img_w, 3),
                            dtype=np.float16)
        self.texts = []
        image_datagen_args = {
            'shear_range': 0.1,
            'zoom_range': 0.01,
            'width_shift_range': 0.001,
            'height_shift_range': 0.1,
            'rotation_range': 1,
            'horizontal_flip': False,
            'vertical_flip': False
        }
        self.image_datagen = ImageDataGenerator(**image_datagen_args)

    def build_data(self):
        print(self.n, " Image Loading start... ", self.img_dirpath)
        for i, img_file in enumerate(self.img_dir):

            img = image.load_img(self.img_dirpath + img_file,
                                 target_size=SIZE[::-1],
                                 interpolation='bicubic')
            img = image.img_to_array(img)
            img = preprocess_input(img)
            self.imgs[i] = img
            if self.labels != None:
                self.texts.append(self.labels[img_file][:MAX_LEN])
            else:
                #valid mode
                self.texts.append(img_file)
        print("Image Loading finish...")

    def next_sample(self):
        self.cur_index += 1
        if self.cur_index >= self.n:
            self.cur_index = 0
            random.shuffle(self.indexes)
        return self.imgs[self.indexes[self.cur_index]].astype(
            np.float32), self.texts[self.indexes[self.cur_index]]

    def next_batch(self):
        while True:
            X_data = np.zeros([self.batch_size, self.img_w, self.img_h, 3],
                              dtype=np.float32)  # (bs,2048, 64, 3)
            Y_data = np.zeros([self.batch_size, self.max_text_len],
                              dtype=np.float32)  # (bs, 70)
            input_length = np.ones((self.batch_size, 1), dtype=np.float32) * (
                self.img_w // self.downsample_factor - 2)  # (bs, 1)
            label_length = np.zeros((self.batch_size, 1),
                                    dtype=np.float32)  # (bs, 1)

            for i in range(self.batch_size):
                img, text = self.next_sample()

                if self.training:
                    params = self.image_datagen.get_random_transform(img.shape)
                    img = self.image_datagen.apply_transform(img, params)

                img = img.transpose((1, 0, 2))
                X_data[i] = img
                Y_data[i, :len(text)] = text_to_labels(text)
                label_length[i] = len(text)

            inputs = {
                'the_inputs': X_data,  # (bs,2048, 64, 1)
                'the_labels': Y_data,  # (bs,70)
                'input_length': input_length,  # (bs, 1)
                'label_length': label_length  # (bs, 1)
            }

            outputs = {'ctc': np.zeros([self.batch_size])}  # (bs, 1)
            yield (inputs, outputs)
def AugTrain_reg(in_vol_in, in_vol_out, num_out, minmax):
    new_vol_in = np.empty(
        [in_vol_in.shape[0], in_vol_in.shape[1], in_vol_in.shape[2], 1])
    new_vol_out = np.zeros((num_out, 1))
    print(in_vol_in.shape)
    sh = new_vol_in.shape
    Vols = [[], []]
    datagen = ImageDataGenerator()
    r_list = [-0.5, 0.25, 0.11]
    flip_list = [False, False, True]

    for i in range(len(r_list)):
        # prepare i different transformations
        r = r_list[i]
        flip = flip_list[i]
        # print("r= ", r)
        imageData = np.empty([sh[0], sh[1], sh[2]])
        image = np.zeros([sh[0], sh[1], 1])
        #print("Shape before augmentation: " + str(type(new_vol_in[1][1][45][0])))
        for j in range(sh[2]):
            # apply transformation on image
            image1 = np.expand_dims(in_vol_in[:, :, j], 2)

            #print(image1)
            image = datagen.apply_transform(
                image1,
                transform_parameters={
                    'flip_vertical': flip,
                    # vertical flip results in upside down image
                    'tx': r * 20,  # vertical translation
                    'ty': r * 10
                })  # horizontal translation

            # Do preprocess on input images and change gray level of images to [0 255] and eliminate nan and -inf values from image pixles value and active below process
            image = np.squeeze(image, axis=2)

            image = np.uint8(image)
            #print(image)
            image[image < 0] = 0
            image[image > 255] = 255
            image = image / 255
            #print("Val " + str(image[64,64]))
            #plt.imshow(image[:, :])
            #plt.show()
            #print("IMAGE " + str(image))
            #print("VAL: " + str(image[1][1]))
            imageData[:, :, j] = image  # (128,128,99)
            #plt.imshow(imageData[:, :, 45])
            #plt.show()
        imageData = imageData.reshape(sh[0], sh[1], sh[2], 1)
        Vols[0].append(imageData)

    # Add orgilal image in Vols[0]/ After preprocess of input images , active below process

    in_vol_in = np.uint8(in_vol_in)
    #in_vol_in = in_vol_in / 255
    in_vol_in[in_vol_in < 0] = 0
    in_vol_in[in_vol_in > 255] = 255
    in_vol_in = in_vol_in.reshape(sh[0], sh[1], sh[2], 1)
    Vols[0].append(in_vol_in)
    #print("Shape after augmentation: " + str(type(in_vol_in[1][1][45][0])))
    # Normalized coeff with total min and total max of all coefficients
    #print("voor"+ str(in_vol_out))
    new_vol_out = (in_vol_out - minmax[0]) / (minmax[1] - minmax[0])
    #print("na"+ str(new_vol_out))
    Vols[1].append(new_vol_out[:, 1])
    Vols[1].append(new_vol_out[:, 1])
    Vols[1].append(new_vol_out[:, 1])
    Vols[1].append(new_vol_out[:, 1])

    #    Vols.append(new_vol_in)
    #    Vols.append(new_vol_out)

    return Vols
Exemple #11
0
class DataGen(Sequence):
    def __init__(self,
                 filepath,
                 batch_size=8,
                 class_num=2,
                 target_size=(224, 224),
                 n_channels=3,
                 preprocess_input=None,
                 with_aug=True,
                 shuffle=True,
                 path_dataset=None,
                 type_gen='train',
                 option=None):

        data_dict = readfile_to_dict(filepath)
        data_keys = list(data_dict.keys())

        self.shuffle = shuffle
        self.batch_size = batch_size
        self.labels = data_dict
        self.list_IDs = data_keys
        self.target_size = target_size
        self.path_dataset = path_dataset
        self.type_gen = type_gen
        self.option = option
        self.n_channels = n_channels
        self.class_num = class_num
        self.preprocess_input = preprocess_input

        self.aug_gen = ImageDataGenerator()
        self.steps_per_epoch = len(self.list_IDs) // self.batch_size
        print("all:", len(self.list_IDs), " batch per epoch",
              self.steps_per_epoch)

        ww, hh = 704, np.floor(576 * 0.8)
        x0, y0 = 0, int(np.floor(576 * 0.1))
        #         ww,hh=target_size[0]+19+x0,target_size[1]+19+y0
        step = 70
        self.pos = []
        while True:
            if y0 + target_size[1] > hh:
                break
            x0 = 0
            while True:
                if x0 + target_size[0] > ww:
                    break
                self.pos.append((x0, y0))
                x0 += step
            y0 += step

        self.on_epoch_end()

    def __len__(self):
        'Denotes the number of batches per epoch'
        #         print(int(np.floor(len(self.list_IDs) / self.batch_size)), len(self.pos))
        return int(np.floor(len(self.list_IDs) / self.batch_size)) * len(
            self.pos)

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __getitem__(self, index):
        'Generate one batch of data'

        index_i = index // len(self.pos)
        pos_i = index % len(self.pos)

        # Generate indexes of the batch
        indexes = self.indexes[index_i * self.batch_size:(index_i + 1) *
                               self.batch_size]
        # Find list of IDs
        ids = [self.list_IDs[k] for k in indexes]
        # Generate data
        X, y = self.__data_generation(ids, self.pos[pos_i])
        if self.type_gen == 'predict':
            return X
        else:
            return X, y

    def sequence_augment(self, sequence):

        name_list = [
            'rotate', 'width_shift', 'height_shift', 'brightness',
            'flip_horizontal', 'width_zoom', 'height_zoom'
        ]
        dictkey_list = [
            'theta', 'ty', 'tx', 'brightness', 'flip_horizontal', 'zy', 'zx'
        ]
        # dictkey_list = ['ty','tx','zy','zx']
        random_aug = np.random.randint(2, 5)  # random 2-4 augmentation method
        pick_idx = np.random.choice(len(dictkey_list),
                                    random_aug,
                                    replace=False)  #

        dict_input = {}
        for i in pick_idx:
            if dictkey_list[i] == 'theta':
                dict_input['theta'] = np.random.randint(-10, 10)

            elif dictkey_list[i] == 'ty':  # width_shift
                dict_input['ty'] = np.random.randint(-5, 5)

            elif dictkey_list[i] == 'tx':  # height_shift
                dict_input['tx'] = np.random.randint(-5, 5)

            elif dictkey_list[i] == 'brightness':
                dict_input['brightness'] = np.random.uniform(0.15, 1)

            elif dictkey_list[i] == 'flip_horizontal':
                dict_input['flip_horizontal'] = True

            elif dictkey_list[i] == 'zy':  # width_zoom
                dict_input['zy'] = np.random.uniform(0.5, 1.5)

            elif dictkey_list[i] == 'zx':  # height_zoom
                dict_input['zx'] = np.random.uniform(0.5, 1.5)

        len_seq = sequence.shape[0]
        for i in range(len_seq):
            sequence[i] = self.aug_gen.apply_transform(sequence[i], dict_input)

        return sequence

    def __data_generation(self, ids, pos):
        'Generates data containing batch_size samples'
        # Initialization
        Y = np.zeros((self.batch_size, self.class_num))

        X = []
        x = None
        y = None
        for i, ID in enumerate(ids):  # ID is name of file
            path_file = os.path.join(self.path_dataset, ID)
            #             print(path_file)
            img = cv2.imread(path_file)

            # 取图像中间的0.8部分
            hh, ww, _ = img.shape
            xx, yy = int(0), int(hh * 0.1)
            ww, hh = int(ww), int(hh * 0.8)
            img = img[yy:yy + hh, xx:xx + ww]

            img = img[:, :, [2, 1, 0]]  # to RGB
            #             if self.preprocess_input is not None:
            #                 img = self.preprocess_input(img)

            if i < len(ids) / 2:
                x, y = pos[0], pos[1]
            else:
                # 随机切一块
                h, w, n = img.shape
                #                 print(img.shape)
                x = np.random.randint(0, w - self.target_size[0])
                y = np.random.randint(0, h - self.target_size[1])

            (w, h) = self.target_size
            #             print(x,y,w,h)
            X.append(img[y:y + h, x:x + w])
#             print(x,y,w,h)

        X = np.array(X)
        if self.type_gen == 'train':
            X = self.sequence_augment(X)  # apply the same rule
        else:
            X = X

#         X = X/255.
        X = X / 127.5
        X = X - 1.

        return X, Y
Exemple #12
0
class DataGenerator_segmentation(Sequence):
    def __init__(self,
                 list_IDs,
                 labels,
                 batch_size=8,
                 n_classes=3,
                 shuffle=True,
                 validation=False):
        'Initialization'
        self.batch_size = batch_size
        self.labels = labels
        self.list_IDs = list_IDs
        self.n_classes = n_classes
        self.shuffle = shuffle

        self.on_epoch_end()
        if validation:
            self.classe_weight = {0: 1.66666667, 1: 1.19047619, 2: 0.64102564}
            data_gen_args = dict()
            data_gen_args2 = dict()
        else:
            self.classe_weight = {0: 1.78253119, 1: 2.62467192, 2: 0.48590865}
            data_gen_args = dict(
                horizontal_flip=True,
                vertical_flip=True,
            )
            data_gen_args2 = dict(
                horizontal_flip=True,  #rescale=1./255,
                vertical_flip=True,
            )

        self.image_datagen = ImageDataGenerator(**data_gen_args)
        self.mask_datagen = ImageDataGenerator(**data_gen_args2)
        seed = 1

    def __len__(self):
        'Denotes the number of batches per epoch'
        return int(np.floor(len(self.list_IDs) / self.batch_size))

    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate indexes of the batch
        indexes = self.indexes[index * self.batch_size:(index + 1) *
                               self.batch_size]

        # Find list of IDs
        list_IDs_temp = [self.list_IDs[k] for k in indexes]

        # Generate data
        X, y = self.__data_generation(list_IDs_temp)

        return X, y

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __data_generation(self, list_IDs_temp):
        DATAPATH = 'ISIC2017/Tudojunto_r/imagens/'
        DATAPATH2 = 'ISIC2017/Tudojunto_r/segm/'
        #DATAPATH='ISIC2017/Tudojunto/imagens/'
        #DATAPATH2='ISIC2017/Tudojunto/segm/'
        'Generates data containing batch_size samples'  # X : (n_samples, *dim, n_channels)
        # Initialization
        X = np.empty((self.batch_size, 572, 572, 3))
        ys = np.empty((self.batch_size, 388, 388, 1))

        # Generate data
        for i, ID in enumerate(list_IDs_temp):
            # Generate Transform
            transform_i = self.image_datagen.get_random_transform(
                (572, 572, 3), seed=1)
            transform_s = self.mask_datagen.get_random_transform((388, 388, 1),
                                                                 seed=1)
            # Store sample
            img = imread(DATAPATH + ID + '.jpg')
            img = img / 255
            mask = np.expand_dims(imread(DATAPATH2 + ID + '.png'), axis=-1)
            mask = mask / 255

            X[i, ] = self.image_datagen.apply_transform(
                img, transform_parameters=transform_i).astype(np.float32)
            ys[i, ] = self.mask_datagen.apply_transform(
                mask, transform_parameters=transform_s).astype(np.float32)

        return X, ys
Exemple #13
0
class DataGenerator(Sequence):
    def __init__(self,
                 list_IDs,
                 labels,
                 batch_size=8,
                 n_classes=3,
                 shuffle=True,
                 validation=False):
        'Initialization'
        self.batch_size = batch_size
        self.labels = labels
        self.list_IDs = list_IDs
        self.n_classes = n_classes
        self.shuffle = shuffle

        self.on_epoch_end()

        if validation:
            self.classe_weight = {0: 1.66666667, 1: 1.19047619, 2: 0.64102564}
            data_gen_args = dict()
            data_gen_args2 = dict()
        else:
            self.classe_weight = {0: 1.78253119, 1: 2.62467192, 2: 0.48590865}
            data_gen_args = dict(
                horizontal_flip=True,
                vertical_flip=True,
            )
            data_gen_args2 = dict(
                horizontal_flip=True,  #rescale=1./255,
                vertical_flip=True,
            )

        self.image_datagen = ImageDataGenerator(**data_gen_args)
        self.mask_datagen = ImageDataGenerator(**data_gen_args2)
        seed = 1

    def __len__(self):
        'Denotes the number of batches per epoch'
        return int(np.floor(len(self.list_IDs) / self.batch_size))

    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate indexes of the batch
        indexes = self.indexes[index * self.batch_size:(index + 1) *
                               self.batch_size]

        # Find list of IDs
        list_IDs_temp = [self.list_IDs[k] for k in indexes]

        # Generate data
        X, y, sample_weight = self.__data_generation(list_IDs_temp)

        return X, y, sample_weight

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __data_generation(self, list_IDs_temp):
        DATAPATH = 'ISIC2017/Tudojunto_r/imagens/'
        DATAPATH2 = 'ISIC2017/Tudojunto_r/segm/'
        'Generates data containing batch_size samples'  # X : (n_samples, *dim, n_channels)
        # Initialization
        X = np.empty((self.batch_size, 572, 572, 3))
        #ys = np.empty((self.batch_size,388, 388, 1 ))
        ys = np.empty((self.batch_size, 150544, 1))
        yc = np.empty((self.batch_size, 3))

        # Generate data
        for i, ID in enumerate(list_IDs_temp):
            # Generate Transform
            transform_i = self.image_datagen.get_random_transform(
                (572, 572, 3), seed=1)
            #print(transform_i)
            transform_s = self.mask_datagen.get_random_transform((388, 388, 1),
                                                                 seed=1)
            #print(transform_s)
            # Store sample
            img = imread(DATAPATH + ID + '.jpg')
            img = img / 255
            #print(np.amax(img))
            mask = np.expand_dims(imread(DATAPATH2 + ID + '.png'), axis=-1)
            mask = mask / 255
            #img2 = self.image_datagen.apply_transform(img , transform_parameters=transform_i)
            #print(np.amax(img2))
            X[i, ] = self.image_datagen.apply_transform(
                img, transform_parameters=transform_i).astype(np.float32)
            #ys[i,] = self.mask_datagen.apply_transform(mask , transform_parameters=transform_s)
            mask2 = self.mask_datagen.apply_transform(
                mask, transform_parameters=transform_s).astype(np.float32)
            ys[i, ] = np.reshape(mask2, (150544, 1))
            #print((np.reshape(ys[i,], (150544,1))).shape)
            #imshow(img)
            #plt.show()
            #imshow(img2)
            #plt.show()
            #print(img.shape)
            #X[i,] = img
            #ys[i,] = np.expand_dims(imread(DATAPATH2 + ID + '.png'), axis=-1)
            # Store class
            yc[i] = to_categorical(self.labels[ID], 3)

        # Generate Weights
        rounded_train = np.argmax(yc, axis=1)
        #print("rounded_train:",rounded_train.shape,rounded_train)
        #print("yc",yc)
        weight_class = np.array(
            [self.classe_weight[cls] for cls in rounded_train])
        #print("weight_class",weight_class)
        #mask_ones = np.ones(388,388,1)
        #weight_segm = np.ones(((self.batch_size),388,388))
        #tf.expand_dims(weight_mask,axis=0)
        #weight_segm = np.ones(((self.batch_size),388,388,1))
        #weight_segm = tf.expand_dims(weight_segm,axis=0)
        #weight_segm = np.ones(((self.batch_size),1))
        # weight_segm = np.array([self.classe_weight[cls] for cls in rounded_train])
        weight_segm = np.ones(((self.batch_size), 150544))

        return X, [yc, ys], [weight_class, weight_segm]
class TripletGenerator(Sequence):
    def __init__(self,
                 file_path,
                 image_path,
                 image_test_path,
                 nb_classes_batch,
                 nb_images_per_class_batch,
                 target_size=TARGET_SIZE,
                 subset='training',
                 validation_split=0.0,
                 seed=42,
                 is_reptile=False,
                 shuffle=True,
                 excluded_classes=['new_whale'],
                 class_weight_type=None,
                 **kwargs):
        self.file_path = file_path
        self.shuffle = shuffle
        self.target_size = target_size
        self.nb_classes_batch = nb_classes_batch
        self.nb_images_per_class_batch = nb_images_per_class_batch
        self.batch_size = nb_classes_batch * nb_images_per_class_batch
        self.image_path = image_path
        self.image_test_path = image_test_path
        self.df = pd.read_csv(file_path)
        self.index_array = None
        self.lock = threading.Lock()
        self.is_reptile = is_reptile

        logger.info('exclude_class: {}'.format(excluded_classes))
        logger.info('class_weight_type: {}'.format(class_weight_type))

        blacklisted_class_ix = self.df['Id'].isin(excluded_classes)
        logger.info("{} instances excluded".format(
            np.sum(blacklisted_class_ix)))
        df = self.df[~blacklisted_class_ix]

        classes = list(df['Id'].unique())
        self.class_indices = dict(zip(classes, range(len(classes))))
        self.class_inv_indices = dict(zip(range(len(classes)), classes))

        train_classes, test_classes = train_test_split(
            classes, test_size=validation_split, random_state=seed)
        if subset == 'training':
            self.df = df[df['Id'].isin(train_classes)]
        else:
            self.df = df[df['Id'].isin(test_classes)]
        logger.info("data has shape: {}".format(self.df.shape))

        classes = self.df['Id'].values
        self.classes = np.array([self.class_indices[cls] for cls in classes])
        self.filenames = np.array(self.df['Image'])

        self.class_indices_subset = {
            k: v
            for k, v in self.class_inv_indices.items() if k in self.classes
        }

        kwargs.update({'preprocessing_function': _preprocess_input})
        logger.info(kwargs)
        self.image_generator = ImageDataGenerator(**kwargs)
        # test time generator
        self.image_generator_inference = ImageDataGenerator(
            preprocessing_function=_preprocess_input)

    def get_test_images_and_names(self):
        img_names = os.listdir(self.image_test_path)
        filepaths = [
            os.path.join(self.image_test_path, img_name)
            for img_name in img_names
        ]
        _x = np.zeros((len(filepaths), ) + self.target_size, dtype='float32')
        for i, _path in enumerate(filepaths):
            _img = load_img(_path, target_size=self.target_size)
            _x[i] = img_to_array(_img)
            if hasattr(_img, 'close'):
                _img.close()
        return _x, img_names

    def __len__(self):
        """
        number of steps per epoch
        number of classes in subet / nb_classes_batch
        :return: 
        """
        return len(self.class_indices_subset) // self.nb_classes_batch

    def get_nb_classes(self):
        """
        number of all classes
        :return: 
        """
        return len(self.class_indices)

    def _set_index_array(self):

        self.index_array = list(self.class_indices_subset.keys())
        if self.shuffle:
            self.index_array = np.random.permutation(self.index_array)

    def on_epoch_end(self):
        """
        shuffle at epoch end
        """
        self._set_index_array()

    def get_train_image_from_class_ix(self, ixs):
        return self._get_batches_of_transformed_samples(ixs)

    def __getitem__(self, idx):
        if self.index_array is None:
            self._set_index_array()
        # unique classes to pull
        index_array = self.index_array[idx * self.nb_classes_batch:self.
                                       nb_classes_batch * (idx + 1)]
        return self._get_batches_of_transformed_samples(index_array)

    def _get_batches_of_transformed_samples(self, index_array):
        """
        validation and training behaves the same way w.r.t. augmentation
        :param index_array: 
        :return: 
        """
        batch_x = []
        for i, class_ix in enumerate(index_array):
            _samples = np.zeros(tuple([self.nb_images_per_class_batch] +
                                      list(self.target_size)),
                                dtype='float32')
            filenames = self.filenames[self.classes == class_ix]
            if len(filenames) > self.nb_images_per_class_batch:
                np.random.shuffle(filenames)
                filenames = filenames[:self.nb_images_per_class_batch]
            logger.debug("{} files for class {}".format(
                len(filenames), class_ix))
            for j, filename in enumerate(filenames):
                img = load_img(os.path.join(self.image_path, filename),
                               target_size=self.target_size)
                x = img_to_array(img, data_format='channels_last')
                # Pillow images should be closed after `load_img`,
                # but not PIL images.
                if hasattr(img, 'close'):
                    img.close()
                _samples[j] = self.image_generator.standardize(x)

            # require at least `nb_images_per_class_batch` per class
            nb_missing = _samples.shape[0] - j - 1
            # select images to transform. No need to standardize again.
            img_ix_transformed = np.random.choice(j + 1, nb_missing)
            for img_ix, k in zip(img_ix_transformed, range(nb_missing)):
                x = _samples[img_ix]
                params = self.image_generator.get_random_transform(
                    self.target_size)
                x = self.image_generator.apply_transform(x, params)
                _samples[j + k + 1] = x
            logger.debug("{} transformations for class {}".format(
                nb_missing, class_ix))
            batch_x.append(_samples)
        batch_x = np.vstack(batch_x)
        # build batch of labels
        _labels = range(10) if self.is_reptile else index_array
        batch_y = np.repeat(_labels, self.nb_images_per_class_batch)
        if self.is_reptile:
            batch_y = to_categorical(batch_y, num_classes=10)
        assert len(batch_y), len(batch_x)
        return batch_x, batch_y

    def get_test_generator(self, x):
        """
        :param x: test data
        :return: NumpyArrayIterator
        """
        return self.image_generator_inference.flow(x=x,
                                                   shuffle=False,
                                                   batch_size=self.batch_size)
Exemple #15
0
class DataGenerator(Sequence):
    'Generates data for Keras'

    def __init__(self,
                 list_IDs,
                 labels,
                 batch_size=32,
                 dim=(32, 32),
                 n_channels=1,
                 n_sequence=4,
                 shuffle=True,
                 path_dataset=None,
                 type_gen='train',
                 option=None):
        'Initialization'
        self.dim = dim
        self.batch_size = batch_size
        self.labels = labels
        self.list_IDs = list_IDs
        self.n_channels = n_channels
        self.n_sequence = n_sequence + 1  # get n_sequence diff image
        self.shuffle = shuffle
        self.path_dataset = path_dataset
        self.type_gen = type_gen
        self.option = option
        self.aug_gen = ImageDataGenerator()
        print("all:", len(self.list_IDs), " batch per epoch",
              int(np.floor(len(self.list_IDs) / self.batch_size)))
        self.on_epoch_end()

    def __len__(self):
        'Denotes the number of batches per epoch'
        return int(np.floor(len(self.list_IDs) / self.batch_size))

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate indexes of the batch
        indexes = self.indexes[index * self.batch_size:(index + 1) *
                               self.batch_size]
        # Find list of IDs
        list_IDs_temp = [self.list_IDs[k] for k in indexes]
        # Generate data
        D, X, y = self.__data_generation(list_IDs_temp)
        if self.type_gen == 'predict':
            return {'input_1': D, 'input_2': X}
        elif self.type_gen == 'train' or self.type_gen == 'test':
            return ({'input_1': D, 'input_2': X}, y)
        elif self.type_gen == 'quantize':
            return np.concatenate((D, X), axis=3), y

    def get_sampling_frame(self, len_frames):
        '''
        Sampling n_sequence frame from video file
        Input: 
            len_frames -- number of frames that this video have
        Output: 
            index_sampling -- n_sequence frame indexs from sampling algorithm 
        '''
        # Define maximum sampling rate
        random_sample_range = 9
        if random_sample_range * self.n_sequence > len_frames:
            random_sample_range = len_frames // self.n_sequence
        # Randomly choose sample interval and start frame
        sample_interval = np.random.randint(3, random_sample_range + 1)
        start_i = np.random.randint(
            0, len_frames - sample_interval * self.n_sequence + 1)

        # Get n_sequence index of frames
        index_sampling = []
        end_i = sample_interval * self.n_sequence + start_i
        for i in range(start_i, end_i, sample_interval):
            if len(index_sampling) < self.n_sequence:
                index_sampling.append(i)

        return index_sampling

    def sequence_augment(self, sequence, rgb_img=None):
        name_list = [
            'rotate', 'width_shift', 'height_shift', 'brightness',
            'flip_horizontal', 'width_zoom', 'height_zoom'
        ]
        dictkey_list = [
            'theta', 'ty', 'tx', 'brightness', 'flip_horizontal', 'zy', 'zx'
        ]
        # dictkey_list = ['ty','tx','zy','zx']
        random_aug = np.random.randint(2, 5)  # random 2-4 augmentation method
        pick_idx = np.random.choice(len(dictkey_list),
                                    random_aug,
                                    replace=False)  #

        dict_input = {}
        for i in pick_idx:
            if dictkey_list[i] == 'theta':
                dict_input['theta'] = np.random.randint(-10, 10)

            elif dictkey_list[i] == 'ty':  # width_shift
                dict_input['ty'] = np.random.randint(-60, 60)

            elif dictkey_list[i] == 'tx':  # height_shift
                dict_input['tx'] = np.random.randint(-30, 30)

            elif dictkey_list[i] == 'brightness':
                dict_input['brightness'] = np.random.uniform(0.15, 1)

            elif dictkey_list[i] == 'flip_horizontal':
                dict_input['flip_horizontal'] = True

            elif dictkey_list[i] == 'zy':  # width_zoom
                dict_input['zy'] = np.random.uniform(0.5, 1.5)

            elif dictkey_list[i] == 'zx':  # height_zoom
                dict_input['zx'] = np.random.uniform(0.5, 1.5)
        len_seq = sequence.shape[0]
        for i in range(len_seq):
            sequence[i] = self.aug_gen.apply_transform(sequence[i], dict_input)

        if rgb_img is not None:
            rgb_img = self.aug_gen.apply_transform(rgb_img, dict_input)

        return sequence

    def __data_generation2(self, list_IDs_temp):
        'Generates data containing batch_size samples'
        # Initialization
        D = np.empty((self.batch_size, *self.dim,
                      self.n_channels))  # X : (n_samples, *dim, n_channels)
        X = np.empty((self.batch_size, self.n_sequence,
                      *self.dim))  # X : (n_samples, n_sequence, *dim)
        Y = np.empty((self.batch_size), dtype=int)

        for i, ID in enumerate(list_IDs_temp):  # ID is name of file
            path_file = self.path_dataset + ID + '.mp4'
            cap = cv2.VideoCapture(path_file)
            length_file = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)
                              )  # get how many frames this video have
            index_sampling = self.get_sampling_frame(
                length_file)  # get sampling index
            new_image = None
            for j, n_pic in enumerate(index_sampling):
                cap.set(cv2.CAP_PROP_POS_FRAMES, n_pic)  # jump to that index
                ret, frame = cap.read()
                new_image = cv2.resize(frame, self.dim)
                gray = cv2.cvtColor(new_image, cv2.COLOR_BGR2GRAY)
                X[i, j, :, :] = gray
                D[i, :, :, :] = new_image

            if self.type_gen == 'train':
                #                 X[i,] = self.sequence_augment(X[i,])/255.0
                X[i, ] = X[i, ] / 255.0
                D[i, ] = D[i, ] / 255.0
            else:
                X[i, ] = X[i, ] / 255.0
                D[i, ] = D[i, ] / 255.0

            if self.option == 'RGBdiff':
                X[i, ] = calculateRGBdiff(X[i, ])
#                 X = np.absolute(X)
#                 X[i,] = np.delete(X[i,], 0, axis=0)    # remove first image

            Y[i] = self.labels[ID]
            cap.release()

        X = np.rollaxis(X, 1, 4)
        return D, X[:, :, :, 1:self.n_sequence], Y  # remove first image

    def __data_generation(self, list_IDs_temp):
        'Generates data containing batch_size samples'
        # Initialization
        X = np.empty((self.batch_size, self.n_sequence, *self.dim,
                      self.n_channels))  # X : (n_samples, *dim, n_channels)
        Y = np.empty((self.batch_size), dtype=int)

        D = np.empty((self.batch_size, *self.dim,
                      self.n_channels))  # X : (n_samples, *dim, n_channels)
        S = np.empty((self.batch_size, self.n_sequence,
                      *self.dim))  # X : (n_samples, n_sequence, *dim)

        for i, ID in enumerate(list_IDs_temp):  # ID is name of file
            path_file = os.path.join(self.path_dataset, ID + '.mp4')
            cap = cv2.VideoCapture(path_file)
            length_file = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)
                              )  # get how many frames this video have
            index_sampling = self.get_sampling_frame(
                length_file)  # get sampling index
            for j, n_pic in enumerate(index_sampling):
                cap.set(cv2.CAP_PROP_POS_FRAMES, n_pic)  # jump to that index
                ret, frame = cap.read()
                new_image = cv2.resize(frame, self.dim)
                X[i, j, :, :, :] = new_image

            if self.type_gen == 'train':
                X[i, ] = self.sequence_augment(X[i, ])  # apply the same rule
            else:
                X[i, ] = X[i, ]

            n = len(X[i, ])

            # always get the last image
            D[i, :, :, :] = X[i, n - 1, :, :, :]

            # convert to gray image and normalize to 0~1
            for k in range(n):
                gray = X[i, k, :, :]
                gray = np.array(gray, dtype=np.float32)
                gray = cv2.cvtColor(gray, cv2.COLOR_BGR2GRAY)
                S[i, k, :, :] = gray / 255.0
            D[i, :, :, :] = D[i, :, :, :] / 255.0

            if self.option == 'RGBdiff':
                S[i, ] = calculateRGBdiff(S[i, ])

            Y[i] = self.labels[ID]
            cap.release()

        S = np.rollaxis(S, 1, 4)
        return D, S[:, :, :, 1:self.n_sequence], Y  # remove first image
Exemple #16
0
class VideoFrameGenerator(keras.utils.Sequence):
    def __init__(
        self,
        list_IDs,
        labels,
        batch_size=32,
        dim=(32, 32),
        n_channels=3,
        n_sequence=10,
        shuffle=True,
        type_gen="train",
    ):

        self.dim = dim
        self.batch_size = batch_size
        self.labels = labels
        self.list_IDs = list_IDs
        self.n_channels = n_channels
        self.n_sequence = n_sequence  # number of frames to extract
        self.shuffle = shuffle
        self.type_gen = type_gen
        self.sampl_mode = "2"
        self.aug_gen = ImageDataGenerator()
        print(f"Videos: {len(self.list_IDs)}, batches per epoch: "
              f"{int(np.floor(len(self.list_IDs) / self.batch_size))}")
        self.on_epoch_end()

    def __len__(self):
        # number of batches per epoch
        return int(np.floor(len(self.list_IDs) / self.batch_size))

    def on_epoch_end(self):
        # updating index after epoch
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __getitem__(self, index):

        # Generate indexes of the batch
        indexes = self.indexes[index * self.batch_size:(index + 1) *
                               self.batch_size]
        # Find list of IDs
        list_IDs_temp = [self.list_IDs[k] for k in indexes]
        # Generate data
        X, y = self.__data_generation(list_IDs_temp)

        return X, y

    def frame_sampling(self, len_frames):

        # create a list of frames
        frames = list(range(len_frames))

        # sampling choice
        if self.sampl_mode == "1":
            # create chunks
            chunks = list(self.get_chunks(frames, self.n_sequence))
            sampling = self.sampling_mode_1(chunks)
        elif self.sampl_mode == "2":
            sampling = self.sampling_mode_2(frames, self.n_sequence)
        else:
            raise ValueError

        return sampling

    def sampling_mode_1(self, chunks):

        sampling = []
        for i, chunk in enumerate(chunks):
            if i == 0 or i == 1:
                sampling.append(chunk[-1])  # get the last frame
            elif i == (len(chunks) - 1) or i == (len(chunks) - 2):
                sampling.append(chunk[0])  # get the first frame
            else:
                sampling.append(chunk[len(chunk) //
                                      2])  # get the central frame

        return sampling

    def sampling_mode_2(self, frames, n_sequence):

        # create 12 chunks
        chunks = list(self.get_chunks(frames, 12))

        # remove the first and the last chunk
        sub_chunks = chunks[1:-1]

        # get a the new list of frames
        sub_frame_list = list(itertools.chain.from_iterable(sub_chunks))

        # create n_sequence(10) chunks
        new_chunks = list(self.get_chunks(sub_frame_list, n_sequence))

        sampling = self.sampling_mode_1(new_chunks)

        return sampling

    def get_chunks(self, l, n):
        # divide indexes list in n chunks
        k, m = divmod(len(l), n)
        return (l[i * k + min(i, m):(i + 1) * k + min(i + 1, m)]
                for i in range(n))

    def __data_generation(self, list_IDs_temp):
        # Generating data with batch size samples
        # Initialization
        X = np.empty(
            (self.batch_size, self.n_sequence, *self.dim, self.n_channels))
        Y = np.empty((self.batch_size), dtype=int)

        for i, ID in enumerate(list_IDs_temp):  # ID: path to file
            path_file = ID
            cap = cv2.VideoCapture(path_file)
            # get number of frames
            length_file = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
            index_sampling = self.frame_sampling(length_file)  # sampling indxs

            for j, n_pic in enumerate(index_sampling):
                cap.set(cv2.CAP_PROP_POS_FRAMES, n_pic)  # jump to that index
                ret, frame = cap.read()
                new_image = cv2.resize(frame, self.dim)
                X[i, j, :, :, :] = new_image

            if self.type_gen == "train":
                X[i, ] = (self.sampling_augmentation(X[i, ]) / 255.0)
            else:
                X[i, ] = (X[i, ] / 255.0)

            Y[i] = self.labels[ID]
            cap.release()

            # for debugging
            # self.save_frame_sampling(X, i, ID, len(index_sampling))

        return X, Y

    def sampling_augmentation(self, sequence):
        """
        - theta: Float. Rotation angle in degrees.
        - tx: Float. Shift in the x direction. - vertical shift (height)
        - ty: Float. Shift in the y direction. - horizontal shift (width)
        - shear: Float. Shear angle in degrees.
        - zx: Float. Zoom in the x direction. - vertical zoom
        - zy: Float. Zoom in the y direction. - horizontal zoom
        - flip_horizontal: Boolean. Horizontal flip.
        - flip_vertical: Boolean. Vertical flip.
        - channel_shift_intensity: Float. Channel shift intensity.
        - brightness: Float. Brightness shift intensity.
        """
        transformations = [
            "theta",
            "tx",
            "ty",
            "zx",
            "zy",
            "flip_horizontal",
            "brightness",
        ]

        # random choice of number of transformations
        random_transforms = np.random.randint(2, 4)  # min 2 - max 3
        # random choice of transformations
        transforms_idxs = np.random.choice(len(transformations),
                                           random_transforms,
                                           replace=False)

        transfor_parameters = {}
        for idx in transforms_idxs:
            if transformations[idx] == "theta":
                transfor_parameters["theta"] = np.random.randint(-5, 5)

            elif transformations[idx] == "tx":
                transfor_parameters["tx"] = np.random.randint(-10, 10)

            elif transformations[idx] == "ty":
                transfor_parameters["ty"] = np.random.randint(-15, 15)

            elif transformations[idx] == "zx":
                transfor_parameters["zx"] = np.random.uniform(0.6, 1.05)

            elif transformations[idx] == "zy":
                transfor_parameters["zy"] = np.random.uniform(0.6, 1.05)

            elif transformations[idx] == "flip_horizontal":
                transfor_parameters["flip_horizontal"] = True

            elif transformations[idx] == "brightness":
                transfor_parameters["brightness"] = np.random.uniform(0.4, 0.6)

        len_seq = sequence.shape[0]
        for i in range(len_seq):
            sequence[i] = self.aug_gen.apply_transform(sequence[i],
                                                       transfor_parameters)

        return sequence

    def save_frame_sampling(self, samp_imgs, i, img_path, n_frames):
        # concatenate all frames
        train_frame = ()
        for n_f in range(n_frames):
            train_frame = (
                *train_frame,
                samp_imgs[i, n_f, ] * 255.0,
            )

        # get the train of frame in one image
        full_img = np.concatenate(train_frame, axis=1)

        # info
        img_name = (os.path.split(img_path)[1])[:-4]
        img_label = os.path.split(os.path.split(img_path)[0])[1]

        # save the image
        if not os.path.isdir("./sampling_test/"):
            os.mkdir("./sampling_test/")

        name_file = self.type_gen + "_" + img_label + "_" + img_name
        cv2.imwrite("./sampling_test/" + name_file + ".jpg", full_img)
Exemple #17
0
class DataGenerator(keras.utils.Sequence):
    'Generates data for Keras'

    def __init__(self,
                 list_IDs,
                 labels,
                 batch_size=32,
                 dim=(32, 32),
                 n_channels=1,
                 n_sequence=4,
                 shuffle=True,
                 path_dataset=None,
                 type_gen='train',
                 option=None):
        'Initialization'
        self.dim = dim
        self.batch_size = batch_size
        self.labels = labels
        self.list_IDs = list_IDs
        self.n_channels = n_channels
        self.n_sequence = n_sequence
        self.shuffle = shuffle
        self.path_dataset = path_dataset
        self.type_gen = type_gen
        self.option = option
        self.aug_gen = ImageDataGenerator()
        print("all:", len(self.list_IDs), " batch per epoch",
              int(np.floor(len(self.list_IDs) / self.batch_size)))
        self.on_epoch_end()

    def __len__(self):
        'Denotes the number of batches per epoch'
        return int(np.floor(len(self.list_IDs) / self.batch_size))

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate indexes of the batch
        indexes = self.indexes[index * self.batch_size:(index + 1) *
                               self.batch_size]
        # Find list of IDs
        list_IDs_temp = [self.list_IDs[k] for k in indexes]
        # Generate data
        X, y = self.__data_generation(list_IDs_temp)
        if self.type_gen == 'predict':
            return X
        else:
            return X, y

    def get_sampling_frame(self, len_frames):
        '''
        Sampling n_sequence frame from video file
        Input: 
            len_frames -- number of frames that this video have
        Output: 
            index_sampling -- n_sequence frame indexs from sampling algorithm 
        '''

        # Define maximum sampling rate
        random_sample_range = 9
        if random_sample_range * self.n_sequence > len_frames:
            random_sample_range = len_frames // self.n_sequence
        #Randomly choose sample interval and start frame
        sample_interval = np.random.randint(3, random_sample_range + 1)

        start_i = np.random.randint(
            0, len_frames - sample_interval * self.n_sequence + 1)

        # Get n_sequence index of frames
        index_sampling = []
        end_i = sample_interval * self.n_sequence + start_i
        for i in range(start_i, end_i, sample_interval):
            if len(index_sampling) < self.n_sequence:
                index_sampling.append(i)

        return index_sampling

    def sequence_augment(self, sequence):
        name_list = [
            'rotate', 'width_shift', 'height_shift', 'brightness',
            'flip_horizontal', 'width_zoom', 'height_zoom'
        ]
        dictkey_list = [
            'theta', 'ty', 'tx', 'brightness', 'flip_horizontal', 'zy', 'zx'
        ]
        # dictkey_list = ['ty','tx','zy','zx']
        random_aug = np.random.randint(2, 5)  # random 2-4 augmentation method
        pick_idx = np.random.choice(len(dictkey_list),
                                    random_aug,
                                    replace=False)  #

        dict_input = {}
        for i in pick_idx:
            if dictkey_list[i] == 'theta':
                dict_input['theta'] = np.random.randint(-10, 10)

            elif dictkey_list[i] == 'ty':  # width_shift
                dict_input['ty'] = np.random.randint(-60, 60)

            elif dictkey_list[i] == 'tx':  # height_shift
                dict_input['tx'] = np.random.randint(-30, 30)

            elif dictkey_list[i] == 'brightness':
                dict_input['brightness'] = np.random.uniform(0.15, 1)

            elif dictkey_list[i] == 'flip_horizontal':
                dict_input['flip_horizontal'] = True

            elif dictkey_list[i] == 'zy':  # width_zoom
                dict_input['zy'] = np.random.uniform(0.5, 1.5)

            elif dictkey_list[i] == 'zx':  # height_zoom
                dict_input['zx'] = np.random.uniform(0.5, 1.5)
        len_seq = sequence.shape[0]
        for i in range(len_seq):
            sequence[i] = self.aug_gen.apply_transform(sequence[i], dict_input)

        return sequence

    def __data_generation(self, list_IDs_temp):
        'Generates data containing batch_size samples'
        # Initialization
        X = np.empty((self.batch_size, self.n_sequence, *self.dim,
                      self.n_channels))  # X : (n_samples, *dim, n_channels)
        Y = np.empty((self.batch_size), dtype=int)

        for i, ID in enumerate(list_IDs_temp):  # ID is name of file
            path_file = self.path_dataset + ID
            print(path_file)
            cap = cv2.VideoCapture(path_file)
            print(cap.get(5))
            length_file = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)
                              )  # get how many frames this video have
            index_sampling = self.get_sampling_frame(
                length_file)  # get sampling index
            for j, n_pic in enumerate(index_sampling):
                cap.set(cv2.CAP_PROP_POS_FRAMES, n_pic)  # jump to that index
                ret, frame = cap.read()
                new_image = cv2.resize(frame, self.dim)
                X[i, j, :, :, :] = new_image

            if self.type_gen == 'train':
                X[i, ] = self.sequence_augment(X[i, ]) / 255.0
            else:
                X[i, ] = X[i, ] / 255.0

            if self.option == 'RGBdiff':
                X[i, ] = calculateRGBdiff(X[i, ])

            Y[i] = self.labels[ID]
            cap.release()

        return X, Y
Exemple #18
0
class DataGenerator2(DataGenerator):
    """Generates data for Keras
    Sequence based data generator. Suitable for building data generator for training and prediction.
    """
    def __init__(self,
                 list_IDs,
                 image_path,
                 mask_path,
                 to_fit=True,
                 batch_size=32,
                 dim=(512, 512),
                 dimy=(512, 512),
                 n_channels=1,
                 n_classes=10,
                 shuffle=True,
                 data_gen_args=None):
        super().__init__(list_IDs,
                         image_path,
                         mask_path,
                         to_fit=to_fit,
                         batch_size=batch_size,
                         dim=dim,
                         dimy=dimy,
                         n_channels=n_channels,
                         n_classes=n_classes,
                         shuffle=shuffle)
        """Initialization
        :param list_IDs: list of all 'label' ids to use in the generator
        :param image_path: path to images location
        :param mask_path: path to masks location
        :param to_fit: True to return X and y, False to return X only
        :param batch_size: batch size at each iteration
        :param dim: tuple indicating image dimension
        :param n_channels: number of image channels
        :param n_classes: number of output masks
        :param shuffle: True to shuffle label indexes after every epoch
        """
        self.bool = False
        if data_gen_args != None:
            self.trans = ImageDataGenerator(**data_gen_args)

    def __next__(self):
        if self.n >= self.max:
            self.n = 0
        result = self.__getitem__(self.n)
        self.n += 1
        return result

    def _generate_X(self, list_IDs_temp):
        """Generates data containing batch_size images
        :param list_IDs_temp: list of label ids to load
        :return: batch of images
        """
        # Initialization
        X = np.empty((self.batch_size, *self.dim, self.n_channels))
        self.param = self.trans.get_random_transform(self.dim)

        if random.uniform(0, 1) >= 0.5:
            self.bool = True
        else:
            self.bool = False
        # Generate data
        for i, ID in enumerate(list_IDs_temp):
            # Store sample
            X[i, ] = self._load_dicom_image(self.image_path + '/' + ID)
            # X[i,] = self.apply_transform(X[i,],self.get_random_transform((1,512,512)))
            if self.bool:
                X[i, ] = self.trans.apply_transform(X[i, ], self.param)

        # X=np.expand_dims(X, 4)

        return X

    def _generate_y(self, list_IDs_temp):
        """Generates data containing batch_size masks
        :param list_IDs_temp: list of label ids to load
        :return: batch if masks
        """
        y = np.empty((self.batch_size, *self.dimy, self.n_channels))

        # Generate data
        for i, ID in enumerate(list_IDs_temp):
            # Store sample
            y[i, ] = self._load_grayscale_image_VTK(self.mask_path + '/' +
                                                    'label_' + ID[6:15] +
                                                    '.png')
            if self.bool:
                y[i, ] = self.trans.apply_transform(y[i, ], self.param)

        return y
Exemple #19
0
class generator3da(generator3d):
    def __init__(self,
                 list_IDs,
                 image_path,
                 mask_path,
                 to_fit=True,
                 batch_size=32,
                 patch_size=8,
                 dim=(512, 512),
                 dimy=(512, 512),
                 n_channels=1,
                 n_classes=10,
                 shuffle=True,
                 data_gen_args=None):
        super().__init__(list_IDs,
                         image_path,
                         mask_path,
                         to_fit=to_fit,
                         batch_size=batch_size,
                         patch_size=patch_size,
                         dim=dim,
                         dimy=dimy,
                         n_channels=n_channels,
                         n_classes=n_classes,
                         shuffle=shuffle)
        """Initialization
        :param list_IDs: list of all 'label' ids to use in the generator
        :param image_path: path to images location
        :param mask_path: path to masks location
        :param to_fit: True to return X and y, False to return X only
        :param batch_size: batch size at each iteration
        :param dim: tuple indicating image dimension of the input
        :param dimy: tuple indicating image dimension of the output
        :param n_channels: number of image channels
        :param n_classes: number of output masks
        :param shuffle: True to shuffle label indexes after every epoch
        """
        if data_gen_args != None:
            self.trans = ImageDataGenerator(**data_gen_args)

    def _generate_y(self, list_IDs_temp):
        """Generates data containing batch_size images
        :param list_IDs_temp: list of label ids to load
        :return: batch of images
        """
        Y = np.zeros(
            (self.batch_size, *self.dimy, self.patch_size, self.n_channels))
        # Generate data

        for patch in list_IDs_temp:
            for i, ID in enumerate(patch[1]):
                path = self.mask_path + '/' + patch[0] + '/' + 'label_' + ID[
                    6:15] + '.png'
                img = self._load_grayscale_image_VTK(path)[:, :, 0]
                Y[0, :, :, i, 0] = img
                if self.bool:
                    Y[0, :, :, i, :] = self.trans.apply_transform(
                        Y[0, :, :, i, :], self.param)
        return Y

    def _generate_X(self, list_IDs_temp):
        """Generates data containing batch_size images
        :param list_IDs_temp: list of label ids to load
        :return: batch of images
        """
        X = np.zeros(
            (self.batch_size, *self.dim, self.patch_size, self.n_channels))
        self.param = self.trans.get_random_transform(self.dim)

        if random.uniform(0, 1) >= 0.5:
            self.bool = True
        else:
            self.bool = False
        # Generate data

        for patch in list_IDs_temp:
            for i, ID in enumerate(patch[1]):
                path = self.image_path + '/' + patch[0] + '/' + ID
                img = self._load_grayscale_image_VTK(path)[:, :, 0]
                X[0, :, :, i, 0] = img
                if self.bool:
                    X[0, :, :, i, :] = self.trans.apply_transform(
                        X[0, :, :, i, :], self.param)
        return X
Exemple #20
0
class OmniglotLoader():
    '''
        A class which handles operations for loading and transforming images from Omniglot dataset. 
    '''
    def __init__(self,
                 path='./Omniglot',
                 rotation_range=[-10, 10],
                 shear_range=[-15, 15],
                 scale_range=[0.8, 1.2],
                 shift_range=[-2, 2],
                 batch_size=20,
                 use_transformations=True):
        '''
            Basic constructor which creates the class and sets up all the parameters necessary for running the training
            Params:
                - path = path to root folder of omniglot dataset
                - rotation_range = range of rotations to be applied to the images
                - shear_range = range of degrees to be applied for shearing
                - scale_range = range of factor for scaling by x and y
                - shift_range = range of factor for shifting by x and y
                - batch_size = amount of pairs to be sent in one batch
                - use_transformations = should OmniglotLoader apply random transformations to images
        '''
        self.path = path
        self.rotation_range = rotation_range
        self.shear_range = shear_range
        self.scale_range = scale_range
        self.shift_range = shift_range
        self.batch_size = batch_size

        # Directories for training and evaluation dataset
        self.background_dir = 'images_background'
        self.evaluation_dir = 'images_evaluation'
        self.use_transformations = use_transformations

        # Reading alphabets and creating dictinaries
        self.training_alphabets, self.evaluation_alphabets = self._create_alphabets(
        )
        self.training_keys, self.testing_keys = self._split_train_sets()

        # Creating a series of lists and indexes that will be used during sending batches
        # Because it is important to go through entire dataset for each epoch,
        # it is necessary to  keep track of where we are for each batch.
        self._current_alphabet_index = 0
        self._training_alphabet_list = list(self.training_alphabets.keys())
        self._symbols_list = list(self.training_alphabets[
            self._training_alphabet_list[self._current_alphabet_index]].keys())
        self._current_symbol_index = 0

        # Flag to indicate if the current epoch is done
        self._epoch_done = False
        self._training_alphabet_num = len(self.training_alphabets.keys())
        self._evaluation_alphabet_list = list(self.evaluation_alphabets.keys())
        self._evaluation_alphabet_num = len(self._evaluation_alphabet_list)
        self._evaluation_done = False

        self._tp_batches_done = False
        self._tn_batches_done = False

        self._training = False
        self._testing = False

        self.img_transformer = ImageDataGenerator()

    ####################################################################
    # Getters and setters                                              #
    ####################################################################
    def set_training_evaluation_symbols(self, training):
        if training:
            self._symbols_list = list(
                self.training_alphabets[self._training_alphabet_list[
                    self._current_alphabet_index]].keys())
        else:
            self._symbols_list = list(
                self.evaluation_alphabets[self._evaluation_alphabet_list[
                    self._current_alphabet_index]].keys())

    def get_alphabet_index(self, alphabet, training):
        if training:
            return self._training_alphabet_list.index(alphabet)
        else:
            return self._evaluation_alphabet_list.index(alphabet)

    ####################################################################
    # Various public functions                                         #
    ####################################################################
    def create_pairs(self, directory, alphabets, keys):
        image_alphabets = {}
        for alphabet in keys:
            symbol_dict = {}
            for symbol in alphabets[alphabet]:
                symbol_paths = [
                    os.path.join(self.path, directory, alphabet, symbol, img)
                    for img in os.listdir(
                        os.path.join(self.path, directory, alphabet, symbol))
                ]
                symbol_dict[symbol] = [
                    self._get_image(img_path) for img_path in symbol_paths
                ]

            image_alphabets[alphabet] = symbol_dict

        pairs = []
        labels = []
        for alphabet in image_alphabets:
            for symbol in image_alphabets[alphabet].keys():
                for img in image_alphabets[alphabet][symbol]:
                    same_imgs = random.sample(range(0, 20), 10)

                    test_case = img
                    for i in same_imgs:
                        image = image_alphabets[alphabet][symbol][i]
                        if self.use_transformations:
                            image = self._transform_image(image)
                        pairs += [[test_case, image]]

                        random_img = self._get_random_image(
                            alphabet, image_alphabets, self.background_dir)
                        pairs += [[test_case, random_img]]
                        labels += [1, 0]

        return np.array(pairs), np.array(labels)

    ####################################################################
    # Functions for getting various batches                            #
    ####################################################################
    def get_training_batch(self):
        '''
            Returns one batch from training dataset. Alternate between positive (1) and negative samples (0).
        '''
        directory = self.background_dir
        pairs = []
        labels = []

        images = random.sample(range(0, 20), int((self.batch_size / 2) + 1))
        current_alphabet = self._training_alphabet_list[
            self._current_alphabet_index]
        current_symbol = self._symbols_list[self._current_symbol_index]
        current_image = self._get_image(
            os.path.join(
                self.path, directory, current_alphabet, current_symbol,
                self.training_alphabets[current_alphabet][current_symbol][0]))

        for img in images[1:]:
            second_image = self._get_image(
                os.path.join(
                    self.path, directory, current_alphabet, current_symbol,
                    self.training_alphabets[current_alphabet][current_symbol]
                    [img]))
            pairs += [[current_image, second_image]]

            random_img = self._get_random_image(current_alphabet,
                                                self.training_alphabets,
                                                self.background_dir)
            pairs += [[current_image, random_img]]
            labels += [1, 0]

            if self.use_transformations:
                pairs += [[current_image, self._transform_image(second_image)]]
                pairs += [[current_image, self._transform_image(random_img)]]
                labels += [1, 0]

        self._change_symbol()

        return np.array(pairs), np.array(labels)

    def get_random_batch(self):
        '''
            Gets one random batch with images and their labels. Alternate between positive and negative labels.

            Returns:
                - pairs = pairs of images
                - labels = labels for pairs
        '''

        pairs = []
        labels = []

        images = random.sample(range(0, 20), int((self.batch_size / 2) + 1))

        # Get one random image of a current symbol, whether it is training or evaluation symbol.
        if self._testing:
            random_alphabet_idx = random.randint(
                0,
                len(self._evaluation_alphabet_list) - 1)
            random_alphabet = self._evaluation_alphabet_list[
                random_alphabet_idx]
            symbols_list = list(
                self.evaluation_alphabets[random_alphabet].keys())
            random_symbol_idx = random.randint(0, len(symbols_list) - 1)
            random_symbol = symbols_list[random_symbol_idx]
            current_image = self._get_image(
                os.path.join(
                    self.path, self.evaluation_dir, random_alphabet,
                    random_symbol, self.evaluation_alphabets[random_alphabet]
                    [random_symbol][0]))
        else:
            random_alphabet_idx = random.randint(
                0,
                len(self._training_alphabet_list) - 1)
            random_alphabet = self._training_alphabet_list[random_alphabet_idx]
            symbols_list = list(
                self.training_alphabets[random_alphabet].keys())
            random_symbol_idx = random.randint(0, len(symbols_list) - 1)
            random_symbol = symbols_list[random_symbol_idx]
            current_image = self._get_image(
                os.path.join(
                    self.path, self.background_dir, random_alphabet,
                    random_symbol, self.training_alphabets[random_alphabet]
                    [random_symbol][0]))

        for img in images[1:]:

            # Get one of the other images and create positive pair.
            if self._testing:
                second_image = self._get_image(
                    os.path.join(
                        self.path, self.evaluation_dir, random_alphabet,
                        random_symbol,
                        self.evaluation_alphabets[random_alphabet]
                        [random_symbol][img]))
            else:
                second_image = self._get_image(
                    os.path.join(
                        self.path, self.background_dir, random_alphabet,
                        random_symbol, self.training_alphabets[random_alphabet]
                        [random_symbol][img]))

            pairs += [[current_image, second_image]]

            # Get one random image to create negative pair.
            if self._testing:
                random_img = self._get_random_image(random_alphabet,
                                                    self.evaluation_alphabets,
                                                    self.evaluation_dir)
            else:
                random_img = self._get_random_image(random_alphabet,
                                                    self.training_alphabets,
                                                    self.background_dir)
            pairs += [[current_image, random_img]]
            labels += [1, 0]

            if self.use_transformations:
                pairs += [[current_image, self._transform_image(second_image)]]
                pairs += [[current_image, self._transform_image(random_img)]]
                labels += [1, 0]

        return np.array(pairs), np.array(labels)

    def get_positive_batch(self):
        '''
            Gets a batch of positive pairs from dataset.

            Arguments:
                - training = flag indicating should the training or evaluation dataset be used.

            Returns:
                - pairs = pairs of images
                - labels = labels for pairs
        '''
        pairs = []
        labels = []

        random_pairs = [(random.randint(0, self.batch_size - 1),
                         random.randint(0, self.batch_size - 1))
                        for k in range(self.batch_size)]
        if self._training:
            current_alphabet = self._training_alphabet_list[
                self._current_alphabet_index]
            current_symbol = self._symbols_list[self._current_symbol_index]
            directory = self.background_dir
            img_names = self.training_alphabets[current_alphabet][
                current_symbol]
        else:
            current_alphabet = self._evaluation_alphabet_list[
                self._current_alphabet_index]
            current_symbol = self._symbols_list[self._current_symbol_index]
            directory = self.evaluation_dir
            img_names = self.evaluation_alphabets[current_alphabet][
                current_symbol]

        for pair in random_pairs:
            left_image = self._get_image(
                os.path.join(self.path, directory, current_alphabet,
                             current_symbol, img_names[pair[0]]))
            right_image = self._get_image(
                os.path.join(self.path, directory, current_alphabet,
                             current_symbol, img_names[pair[1]]))

            if self.use_transformations:
                left_image = self._transform_image(left_image)
                right_image = self._transform_image(right_image)

            pairs += [[left_image, right_image]]
            labels += [1]

            if self.use_transformations:
                pairs += [[
                    self._transform_image(left_image),
                    self._transform_image(right_image)
                ]]
                labels += [1]

        self._change_symbol(training)

        return np.array(pairs), np.array(labels)

    def get_negative_batch(self):
        '''
            Gets a batch of negative pairs from dataset.

            Arguments:
                - training = flag indicating should the training or evaluation dataset be used.

            Returns:
                - pairs = pairs of images
                - labels = labels for pairs
        '''
        pairs = []
        labels = []

        image_idx = random.randint(0, self.batch_size - 1)
        if self._training:
            current_alphabet = self._training_alphabet_list[
                self._current_alphabet_index]
            current_symbol = self._symbols_list[self._current_symbol_index]
            directory = self.background_dir
            img_names = self.training_alphabets[current_alphabet][
                current_symbol]
            alphabet_dict = self.training_alphabets
        else:
            current_alphabet = self._evaluation_alphabet_list[
                self._current_alphabet_index]
            current_symbol = self._symbols_list[self._current_symbol_index]
            directory = self.evaluation_dir
            img_names = self.evaluation_alphabets[current_alphabet][
                current_symbol]
            alphabet_dict = self.evaluation_alphabets

        for _ in range(0, self.batch_size - 1):
            left_image = self._get_image(
                os.path.join(self.path, directory, current_alphabet,
                             current_symbol, img_names[image_idx]))
            right_image = self._get_random_image(current_alphabet,
                                                 alphabet_dict, directory)

            pairs += [[left_image, right_image]]
            labels += [0]

            if self.use_transformations:
                pairs += [[
                    self._transform_image(left_image),
                    self._transform_image(right_image)
                ]]
                labels += [0]

        self._change_symbol(training)

        return np.array(pairs), np.array(labels)

    def get_test_batch(self):
        '''
            Gets one batch from evaluation set.

            Returns:
                - pairs = pairs of images
                - labels = labels for pairs
        '''
        directory = self.evaluation_dir
        pairs = []
        labels = []

        images = random.sample(range(0, 20), 11)
        current_alphabet = self._evaluation_alphabet_list[
            self._current_alphabet_index]
        current_symbol = self._symbols_list[self._current_symbol_index]
        current_image = self._get_image(
            os.path.join(
                self.path, directory, current_alphabet, current_symbol,
                self.evaluation_alphabets[current_alphabet][current_symbol]
                [0]))

        for img in images[1:]:
            second_image = self._get_image(
                os.path.join(
                    self.path, directory, current_alphabet, current_symbol,
                    self.evaluation_alphabets[current_alphabet][current_symbol]
                    [img]))

            pairs += [[current_image, second_image]]

            random_img = self._get_random_image(current_alphabet,
                                                self.evaluation_alphabets,
                                                self.evaluation_dir)
            pairs += [[current_image, random_img]]
            labels += [1, 0]

            if self.use_transformations:
                pairs += [[current_image, self._transform_image(second_image)]]
                pairs += [[current_image, self._transform_image(random_img)]]
                labels += [1, 0]

        self._change_symbol(False)
        if self._epoch_done:
            self._evaluation_done = True

        return np.array(pairs), np.array(labels)

    def get_tp_batch(self, alphabet_name):
        '''
            Helper function to get true positive pairs from alphabet of interest in.
            

            Arguments:
                - training = flag indicating should the training or evaluation dataset be used.

            Returns:
                - pairs = pairs of images
                - labels = labels for pairs
        '''
        pairs = []
        labels = []

        random_pairs = [(random.randint(0, self.batch_size - 1),
                         random.randint(0, self.batch_size - 1))
                        for k in range(self.batch_size)]
        if self._training:
            current_symbol = self._symbols_list[self._current_symbol_index]
            directory = self.background_dir
            img_names = self.training_alphabets[alphabet_name][current_symbol]
        else:
            current_symbol = self._symbols_list[self._current_symbol_index]
            directory = self.evaluation_dir
            img_names = self.evaluation_alphabets[alphabet_name][
                current_symbol]

        for pair in random_pairs:
            left_image = self._get_image(
                os.path.join(self.path, directory, alphabet_name,
                             current_symbol, img_names[pair[0]]))
            right_image = self._get_image(
                os.path.join(self.path, directory, alphabet_name,
                             current_symbol, img_names[pair[1]]))

            pairs += [[left_image, right_image]]
            labels += [1]

            if self.use_transformations:
                pairs += [[
                    self._transform_image(left_image),
                    self._transform_image(right_image)
                ]]
                labels += [1]

        self._current_symbol_index += 1
        if self._training:
            if self._current_symbol_index == len(
                    self.training_alphabets[alphabet_name]):
                self._tp_batches_done = True
        else:
            if self._current_symbol_index == len(
                    self.evaluation_alphabets[alphabet_name]):
                self._tp_batches_done = True

        return np.array(pairs), np.array(labels)

    def get_tn_batch(self, alphabet_name):
        '''
            Gets a batch of negative pairs from dataset.

            Arguments:
                - training = flag indicating should the training or evaluation dataset be used.

            Returns:
                - pairs = pairs of images
                - labels = labels for pairs
        '''
        pairs = []
        labels = []

        image_idx = random.randint(0, self.batch_size - 1)
        if self._training:
            current_symbol = self._symbols_list[self._current_symbol_index]
            directory = self.background_dir
            img_names = self.training_alphabets[alphabet_name][current_symbol]
            alphabet_dict = self.training_alphabets
        else:
            current_symbol = self._symbols_list[self._current_symbol_index]
            directory = self.evaluation_dir
            img_names = self.evaluation_alphabets[alphabet_name][
                current_symbol]
            alphabet_dict = self.evaluation_alphabets

        for _ in range(0, self.batch_size - 1):
            left_image = self._get_image(
                os.path.join(self.path, directory, alphabet_name,
                             current_symbol, img_names[image_idx]))
            right_image = self._get_random_image(alphabet_name, alphabet_dict,
                                                 directory)

            pairs += [[left_image, right_image]]
            labels += [0]

            if self.use_transformations:
                pairs += [[
                    self._transform_image(left_image),
                    self._transform_image(right_image)
                ]]
                labels += [0]

        self._current_symbol_index += 1
        if self._training:
            if self._current_symbol_index == len(
                    self.training_alphabets[alphabet_name]):
                self._tn_batches_done = True
        else:
            if self._current_symbol_index == len(
                    self.evaluation_alphabets[alphabet_name]):
                self._tn_batches_done = True

        return np.array(pairs), np.array(labels)

    ####################################################################
    # Various private functions                                        #
    ####################################################################
    def _transform_image(self, img):
        '''
            Function that performs random affine transformations for given image.
            Transformation will occur with probability of 50%.
            
            Arguments:
                - img = image to be transformed
            
            Returns:
                - transformed = transformed image
        '''

        transformations = {}
        if np.random.uniform(low=0, high=1) < 0.5:
            theta = np.random.uniform(low=self.rotation_range[0],
                                      high=self.rotation_range[1])
            transformations['theta'] = theta
        if np.random.uniform(low=0, high=1) < 0.5:
            tx = np.random.uniform(low=self.shift_range[0],
                                   high=self.shift_range[1])
            transformations['tx'] = tx
        if np.random.uniform(low=0, high=1) < 0.5:
            ty = np.random.uniform(low=self.shift_range[0],
                                   high=self.shift_range[1])
            transformations['ty'] = ty
        if np.random.uniform(low=0, high=1) < 0.5:
            zx = np.random.uniform(low=self.scale_range[0],
                                   high=self.scale_range[1])
            transformations['zx'] = zx
        if np.random.uniform(low=0, high=1) < 0.5:
            zy = np.random.uniform(low=self.scale_range[0],
                                   high=self.scale_range[1])
            transformations['zy'] = zy
        if np.random.uniform(low=0, high=1) < 0.5:
            shear = np.random.uniform(low=self.shear_range[0],
                                      high=self.shear_range[1])
            transformations['shear'] = shear

        transformed = self.img_transformer.apply_transform(
            img, transformations)
        return transformed

    def _get_image(self, path):
        '''
            Gets image from given path. Since Omniglot images are black with white background, 
            image will be inverted to be easier to use with affine transformations
            
            Arguments:
                - path = path to image
            
            Returns:
                - inverted = transformed image
        '''

        img = plt.imread(path)
        img = img.reshape(105, 105, 1)
        return img

    def _change_symbol(self):
        '''
            Private function to be used for selecting next symbol after all the data for batch has been prepared.

            Arguments:
                - training = flag indicating should the training or evaluation dataset be used.
        '''

        self._current_symbol_index += 1
        if self._training:
            current_alphabet = self._training_alphabet_list[
                self._current_alphabet_index]
            if self._current_symbol_index == len(
                    self.training_alphabets[current_alphabet]):
                # If we reached last symbol, it is neccessary to reset the counter and change the alphabet.
                self._current_symbol_index = 0
                self._current_alphabet_index += 1
                print(
                    str(
                        round((self._current_alphabet_index /
                               self._training_alphabet_num) * 100.00, 2)) +
                    ' %% of alphabets done')
                if self._current_alphabet_index == len(
                        self.training_alphabets):
                    # If we reached last alphabet, it is neccessary to reset the counter and start a new epoch.
                    self._current_alphabet_index = 0
                    self._epoch_done = True
                self._symbols_list = list(
                    self.training_alphabets[self._training_alphabet_list[
                        self._current_alphabet_index]].keys())
        else:
            current_alphabet = self._evaluation_alphabet_list[
                self._current_alphabet_index]
            if self._current_symbol_index == len(
                    self.evaluation_alphabets[current_alphabet]):
                # If we reached last symbol, it is neccessary to reset the counter and change the alphabet.
                self._current_symbol_index = 0
                self._current_alphabet_index += 1
                print(
                    str(
                        round((self._current_alphabet_index /
                               self._evaluation_alphabet_num) * 100.00, 2)) +
                    ' %% of alphabets done')
                if self._current_alphabet_index == len(
                        self.evaluation_alphabets):
                    # If we reached last alphabet, it is neccessary to reset the counter and start a new epoch.
                    self._current_alphabet_index = 0
                    self._epoch_done = True
                self._symbols_list = list(
                    self.evaluation_alphabets[self._evaluation_alphabet_list[
                        self._current_alphabet_index]].keys())

    def _get_random_image(self, current_alphabet, alphabet_dict, directory):
        """
            Gets a random image of a random symbol from a random alphabet.
            Current alphabet is excluded.
            Params:
                - current_alphabet = name of current alphabet
                - alphabet_dict = dictionary of alphabets
                - directory = string that points to the evaluation or training directory 
        """

        keys = set(alphabet_dict.keys())
        keys.remove(current_alphabet)
        alphabet_sample = keys
        random_alphabet = random.choice(list(alphabet_sample))
        random_symbol = random.choice(list(alphabet_dict[random_alphabet]))
        random_idx = random.randint(0, 19)

        random_img = self._get_image(
            os.path.join(
                self.path, directory, random_alphabet, random_symbol,
                alphabet_dict[random_alphabet][random_symbol][random_idx]))

        return random_img

    def _create_alphabets(self):
        '''
            Arrange all the images of symbols into lists and dictionaries.
            The function reads all the images sorted by folders.
            The folder structure for Omniglot dataset should look like this
            Omniglot
                |-images_background
                    |-Arcadian
                        |-character01
                            |-img01.png
                            |-img02.png
                            ...
                |-images_evaluation
        '''

        training_path = os.path.join(self.path, self.background_dir)
        training_alphabets = {}
        for alphabet in os.listdir(training_path):

            print('Processing: ' + alphabet)
            characters = {}
            for char in os.listdir(os.path.join(training_path, alphabet)):
                characters[char] = [
                    img for img in os.listdir(
                        os.path.join(training_path, alphabet, char))
                ]
            training_alphabets[alphabet] = characters

        evaluation_path = os.path.join(self.path, self.evaluation_dir)
        evaluation_alphabets = {}
        for alphabet in os.listdir(evaluation_path):

            print('Processing: ' + alphabet)
            characters = {}
            for char in os.listdir(os.path.join(evaluation_path, alphabet)):
                characters[char] = [
                    img for img in os.listdir(
                        os.path.join(evaluation_path, alphabet, char))
                ]

            evaluation_alphabets[alphabet] = characters

        return (training_alphabets, evaluation_alphabets)

    def _split_train_sets(self):
        """
            Perform training and testing split at 80% - 20%"
        """

        alphabet_indices = list(range(len(self.training_alphabets)))
        training_indices = random.sample(
            range(0,
                  len(self.training_alphabets) - 1),
            k=int(0.8 * len(self.training_alphabets)))
        testing_indices = set(alphabet_indices) - set(training_indices)

        training_keys = [
            list(self.training_alphabets.keys())[i] for i in training_indices
        ]
        testing_keys = [
            list(self.training_alphabets.keys())[i] for i in testing_indices
        ]
        return (training_keys, testing_keys)
class HeadPoseDataGenerator(Sequence):
    '''
    This class implements a basic Keras data generator overriding methods from its parent class Sequence. The purpose
    of this data generator is to deliver in each batch a set of images from the subset used to initalize this generator
    containing an equal number of members per class.
    '''

    def __init__(self, pose_dataframe, img_array, batch_size,
                 normalize=False, input_norm=None, tilt_norm=None, pan_norm=None,
                 augment=False, shift_range=None, zoom_range=None, brightness_range=None,
                 img_rescale=1, out_rescale=1):
        '''
        Initializes the data generator with the data from a given subset from the original dataset, and the values to
        use when doing data augmentation.

        Arguments:
            pose_dataframe: Dataframe containing a list of each picture in the given subset and its pose values.
            img_array: Numpy array containing the images from the given subset.
            batch_size: Number of pictures per batch.
            normalize: If the data shall be normalized or not.
            input_norm: Tuple containing mean and std values for normalizing pictures in the dataset.
            tilt_norm: Tuple containing mean and std values for normalizing tilt values in the dataset.
            pan_norm: Tuple containing mean and std values for normalizing pan values in the dataset.
            augment: If data augmentation shall be applied or not.
            shift_range: Value (between 0 and 1) indicating the portion of the length of the side of each picture that
            can be used to shift the picture (in both axes).
            zoom_range: Tuple containing the minimum and maximum values used to apply zoom to each picture.
            brightness_range: Tuple containing the minimum and maximum values used to apply a brightness transformation
            to each picture.
            img_rescale: Each pixel from every picture in the subset will be multiplied by this value.
            out_rescale: Tilt and pan values for every picture in the subset will be multiplied by this value.
        '''

        # Create empty arrays for pictures and labels from the subset.
        self.pics = []
        self.labels = []

        # Initialize batch size.
        self.batch_size = batch_size

        # Initialize normalization parameters.
        self.normalize = normalize
        self.input_norm = input_norm

        '''
        Initialize the parameter controlling if data augmentation shall be applied or not, and data augmentation 
        parameters.
        '''
        self.augment = augment

        if self.augment == True:
            self.generator = ImageDataGenerator(width_shift_range=shift_range, height_shift_range=shift_range,
                                                brightness_range=brightness_range, zoom_range=zoom_range)

        # Initialize scaling parameters.
        self.img_rescale = img_rescale
        self.out_rescale = out_rescale

        '''
        Initialize the iterator used to control the position of the next picture from every class that will be included
        in a batch.
        '''
        self.common_iterator = 0

        # Sort dataframe by class.
        df = pose_dataframe.sort_values('class')

        # Initialize the number of pictures in the dataset.
        self.total_size = len(df.index)

        # Load images and pose values into the previously created arrays.
        prev_class = -1
        class_index = -1

        # For each image in the (ordered) dataset:
        for index, row in df.iterrows():

            '''
            If the class for the current picture is different from the last class recorded, append an empty list for the
            new class.
            '''
            if row['class'] != prev_class:
                prev_class = row['class']
                self.pics.append([])
                self.labels.append([])
                class_index = class_index + 1

            # Append picture to corresponding class array.
            self.pics[class_index].append(np.squeeze(img_array[index]))

            # Append labels to corresponding class array (normalized and rescaled).
            self.labels[class_index].append([((row['tilt'] * out_rescale) - tilt_norm[0]) / tilt_norm[1] , ((row['pan'] * out_rescale) - pan_norm[0]) / pan_norm[1]])

        # Assert batch size is a multiple of the number of classes.
        assert(batch_size % len(self.pics) == 0)

    def __data_generation(self):
        '''
        Outputs a batch of pictures.

        Returns:
            X: Pictures in the batch.
            y: Labels for each picture in the batch.
        '''

        # Create empty lists for pictures and labels.
        X = []
        y = []

        # For each picture-per-class:
        for i in range(int(self.batch_size / len(self.pics))):

            # For each class:
            for j in range(len(self.pics)):

                # Select the next picture in the class list (start from beginning after the last picture).
                pic = self.pics[j][int(self.common_iterator % len(self.pics[j]))]
                pic = np.expand_dims(pic, axis=2)

                # Apply data augmentation.
                if self.augment == True:
                    transformation = self.generator.get_random_transform(pic.shape)
                    transformation['zx'] = transformation['zy']
                    pic = self.generator.apply_transform(pic, transformation)

                # Rescale each pixel value in image.
                pic = pic * self.img_rescale

                # Normalize image.
                if self.normalize == True:
                    pic = (pic - self.input_norm[0]) / self.input_norm[1]

                # Add image and labels to the batch.
                X.append(pic)
                y.append(self.labels[j][int(self.common_iterator % len(self.labels[j]))])

            # Update iterator.
            self.common_iterator = self.common_iterator + 1

        # Transform lists into Numpy arrays.
        X = np.array(X)
        y = np.array(y)

        # Return images and labels.
        return X, y

    def __len__(self):
        '''
        Outputs the length (number of batches) that the data generator can provide.

        Returns:
            l: The length of the data generator.
        '''

        '''
        Calculate the length of the data generator as the relation between the total number of images and the size of
        each batch; in order to function properly with uneven class lengths the number is rounded to the smaller integer 
        bigger or equal to the obtained result.
        '''
        l = ceil(self.total_size / self.batch_size)

        return l

    def __getitem__(self, index):
        '''
        Outputs a new batch given the batch index.

        Returns:
            X: Pictures in the batch.
            y: Labels for each picture in the batch.
        '''

        # Set the class iterator in the correct position for obtaining the requested batch.
        self.common_iterator = index * int(self.batch_size / len(self.pics))

        # Generate the batch.
        X, y = self.__data_generation()

        # Return images and labels for the requested batch.
        return X, y

    def reset(self):
        '''
        Resets the class iterator to its initial position.
        '''

        self.common_iterator = 0
Exemple #22
0
                               width_shift_range=0.1,
                               height_shift_range=0.1,
                               shear_range=0.01,
                               zoom_range=[0.9, 1.25],
                               horizontal_flip=True,
                               vertical_flip=False,
                               fill_mode='reflect',
                               data_format='channels_last',
                               brightness_range=[0.5, 1.5])

cv2.imwrite(
    '/Users/denisrangulov/Google Drive/EmotionRecognition/figures/origin.png',
    image)
datagen = ImageDataGenerator()

aug_brightness = datagen.apply_transform(
    x=image, transform_parameters={'brightness': 1.5})
cv2.imwrite(
    '/Users/denisrangulov/Google Drive/EmotionRecognition/figures/aug_brightness.png',
    aug_brightness)

aug_rotation = datagen.apply_transform(x=image,
                                       transform_parameters={'theta': 15})
cv2.imwrite(
    '/Users/denisrangulov/Google Drive/EmotionRecognition/figures/aug_rotation.png',
    aug_rotation)

aug_shift = datagen.apply_transform(x=image,
                                    transform_parameters={
                                        'tx': 5,
                                        'ty': 5
                                    })
class DataGeneratorBKB(keras.utils.Sequence):
    'Generates data for Keras'

    def __init__(self,
                 list_IDs,
                 labels,
                 batch_size=32,
                 dim=(32, 32),
                 n_channels=1,
                 n_sequence=4,
                 shuffle=True,
                 path_dataset=None,
                 select_joint=[],
                 type_gen='train',
                 type_model='rgb',
                 option=None):
        'Initialization'
        self.dim = dim
        self.batch_size = batch_size
        self.labels = labels
        self.list_IDs = list_IDs
        self.n_channels = n_channels
        self.n_sequence = n_sequence
        self.shuffle = shuffle
        self.path_dataset = path_dataset
        self.select_joint = select_joint
        self.n_joint = len(select_joint)
        self.option = option
        self.type_gen = type_gen
        self.type_model = type_model
        print("all:", len(self.list_IDs), " batch per epoch",
              int(np.floor(len(self.list_IDs) / self.batch_size)))

        # execution_path = os.getcwd()
        # self.detector = ObjectDetection()
        # self.detector.setModelTypeAsYOLOv3()
        # self.detector.setModelPath( os.path.join(execution_path , "pretrain/yolo.h5"))
        # self.detector.loadModel(detection_speed="fast")#detection_speed="fast"
        # self.execution_path = execution_path
        # self.detector = detector

        # sometimes = lambda aug: va.Sometimes(0.5, aug) # Used to apply augmentor with 50% probability
        # self.seq = va.SomeOf([ #va.Sequential([
        #     # va.RandomCrop(size=(300, 300)), # randomly crop video with a size of (240 x 180)
        #     va.RandomRotate(degrees=10), # randomly rotates the video with a degree randomly choosen from [-10, 10]
        #     va.RandomTranslate(x=60,y=30),
        #     # sometimes(va.Add(value=-100)),
        #     # sometimes(va.Pepper(ratio=40)),
        #     sometimes(va.Add(value=-60)),
        #     sometimes(va.HorizontalFlip()) # horizontally flip the video with 50% probability
        # ], 2)

        self.aug_gen = ImageDataGenerator()

        self.on_epoch_end()

    def __len__(self):
        'Denotes the number of batches per epoch'
        return int(np.floor(len(self.list_IDs) / self.batch_size))

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate indexes of the batch
        indexes = self.indexes[index * self.batch_size:(index + 1) *
                               self.batch_size]
        # Find list of IDs
        list_IDs_temp = [self.list_IDs[k] for k in indexes]
        # Generate data
        X, y = self.__data_generation(list_IDs_temp)
        if self.type_gen == 'predict':
            return X
        else:
            return X, y

    def get_sampling_frame(self, len_frames, path_video):
        '''
        Sampling n_sequence frame from video file
        Input: 
            len_frames -- number of frames that this video have
        Output: 
            index_sampling -- n_sequence frame indexs from sampling algorithm 
        '''

        # Define maximum sampling rate
        # sample_interval = len_frames//self.n_sequence
        # start_i = 0 #np.random.randint(0, len_frames - sample_interval * self.n_sequence + 1)

        if True:  #self.type_gen =='train':
            random_sample_range = 10
            if random_sample_range * self.n_sequence > len_frames:
                random_sample_range = len_frames // self.n_sequence

            if random_sample_range <= 0:
                print('test:', random_sample_range, len_frames, path_video)
            # Randomly choose sample interval and start frame
            if random_sample_range < 3:
                sample_interval = np.random.randint(1, random_sample_range + 1)
            else:
                sample_interval = np.random.randint(3, random_sample_range + 1)

            # sample_interval = np.random.randint(1, random_sample_range + 1)

            # temp = len_frames - sample_interval * self.n_sequence + 1
            # if temp <= 0:
            #     print(temp, len_frames)
            start_i = np.random.randint(
                0, len_frames - sample_interval * self.n_sequence + 1)

        # Get n_sequence index of frames
        index_sampling = []
        end_i = sample_interval * self.n_sequence + start_i
        for i in range(start_i, end_i, sample_interval):
            if len(index_sampling) < self.n_sequence:
                index_sampling.append(i)

        return index_sampling

    def get_crop_img(self, frame):
        # detect_image, detections, extract_picture = self.detector.detectObjectsFromImage(input_type="array", input_image=frame, output_type='array',
        #                                          minimum_percentage_probability=10, extract_detected_objects=True )
        print('#################', self.execution_path)
        detections = self.detector.detectObjectsFromImage(
            input_image=os.path.join(self.execution_path, "room.jpg"),
            output_image_path=os.path.join(self.execution_path,
                                           "image2new.jpg"),
            minimum_percentage_probability=30)
        max_prob = 0
        max_idx = 0
        for i, eachObject in enumerate(detections):
            if eachObject["name"] == 'person' and eachObject[
                    "percentage_probability"] > max_prob:
                max_prob = eachObject["percentage_probability"]
                max_idx = i
        if max_idx > len(detections):
            # if no detection, use black array
            crop_img = np.zeros((*self.dim, self.n_channels))
        else:
            crop_img = extract_picture[max_idx]
        return crop_img

    # def calculateRGBdiff(self, sequence_img):
    #     'keep first frame as rgb data, other is use RGBdiff for temporal data'
    #     length = len(sequence_img)
    #     new_sequence = np.zeros((length,self.dim[0],self.dim[1],self.n_channels))

    #     # find RGBdiff frame 1 to last frame
    #     for i in range(length-1,3,-1): # count down
    #         new_sequence[i] = cv2.subtract(sequence_img[i],sequence_img[i-1])

    #     new_sequence[:4] = sequence_img[:4] # first frame as rgb data

    #     return new_sequence

    def sequence_augment(self, sequence):
        name_list = [
            'rotate', 'width_shift', 'height_shift', 'brightness',
            'flip_horizontal', 'width_zoom', 'height_zoom'
        ]
        dictkey_list = [
            'theta', 'ty', 'tx', 'brightness', 'flip_horizontal', 'zy', 'zx'
        ]
        # dictkey_list = ['ty','tx','zy','zx']
        random_aug = np.random.randint(2, 5)  # random 0-4 augmentation method
        pick_idx = np.random.choice(len(dictkey_list),
                                    random_aug,
                                    replace=False)  #

        dict_input = {}
        for i in pick_idx:
            if dictkey_list[i] == 'theta':
                # dict_input['theta'] = np.random.randint(-10, 10)
                dict_input['theta'] = np.random.randint(-5, 5)

            elif dictkey_list[i] == 'ty':  # width_shift
                # dict_input['ty'] = np.random.randint(-60, 60)
                dict_input['ty'] = np.random.randint(-20, 20)

            elif dictkey_list[i] == 'tx':  # height_shift
                # dict_input['tx'] = np.random.randint(-30, 30)
                dict_input['tx'] = np.random.randint(-10, 10)

            elif dictkey_list[i] == 'brightness':
                dict_input['brightness'] = np.random.uniform(0.15, 1)

            elif dictkey_list[i] == 'flip_horizontal':
                dict_input['flip_horizontal'] = True

            elif dictkey_list[i] == 'zy':  # width_zoom
                # dict_input['zy'] = np.random.uniform(0.5,1.5)
                dict_input['zy'] = np.random.uniform(0.9, 1.3)

            elif dictkey_list[i] == 'zx':  # height_zoom
                # dict_input['zx'] = np.random.uniform(0.5,1.5)
                dict_input['zx'] = np.random.uniform(0.9, 1.3)

        sh = sequence.shape
        new_sequence = np.zeros((sh[0], sh[1], sh[2], sh[3]))
        for i in range(sh[0]):
            new_sequence[i] = self.aug_gen.apply_transform(
                sequence[i], dict_input)

        return new_sequence

    def __data_generation(self, list_IDs_temp):
        'Generates data containing batch_size samples'
        # Initialization
        X1 = np.empty(
            (self.batch_size, self.n_sequence, *self.dim,
             self.n_channels))  # X : (n_samples, timestep, *dim, n_channels)
        X2 = np.empty((self.batch_size, self.n_sequence, self.n_joint * 3))
        Y = np.empty((self.batch_size), dtype=int)

        for i, ID in enumerate(list_IDs_temp):  # ID is name of file (2 batch)
            path_video = self.path_dataset + ID + '.mp4'
            # print(path_video)
            path_skeleton = self.path_dataset + ID + '.npy'

            # print(path_video)

            if self.type_model == '2stream' or self.type_model == 'rgb':
                cap = cv2.VideoCapture(path_video)
                length_file = int(
                    cap.get(cv2.CAP_PROP_FRAME_COUNT)
                )  # get how many frames this video have ,-1 because some bug

            if self.type_model == '2stream' or self.type_model == 'skeleton':
                skeleton_data = np.load(path_skeleton)
                length_file = skeleton_data.shape[0]

            index_sampling = self.get_sampling_frame(
                length_file, path_video)  # get sampling index
            # print(index_sampling)
            if self.type_model == '2stream' or self.type_model == 'rgb':
                # Get RGB sequence
                for j, n_pic in enumerate(index_sampling):
                    cap.set(cv2.CAP_PROP_POS_FRAMES,
                            n_pic)  # jump to that index
                    ret, frame = cap.read()
                    # frame = self.get_crop_img(frame)
                    new_image = cv2.resize(frame, self.dim)
                    # new_image = frame
                    # new_image = new_image/255.0
                    X1[i, j, :, :, :] = new_image

                if self.type_gen == 'train':
                    X1[i, ] = self.sequence_augment(X1[i, ]) / 255.0 * 2 - 1
                else:
                    X1[i, ] = X1[i, ] / 255.0 * 2 - 1

                # cv2.imshow('imgae',X1[i,0])
                # cv2.waitKey(2000)

                if self.option == 'RGBdiff':
                    # print("dddddddddddd")
                    X1[i, ] = calculateRGBdiff(X1[i, ], 0)

            if self.type_model == '2stream' or self.type_model == 'skeleton':
                # Get skeleton sequence
                skeleton_data = skeleton_data[index_sampling]
                skeleton_data = skeleton_data[:, :, self.select_joint]
                skeleton_data = skeleton_data.reshape(self.n_sequence,
                                                      self.n_joint * 3)
                X2[i] = skeleton_data

            # Get label
            Y[i] = self.labels[ID]
            if self.type_model == '2stream' or self.type_model == 'rgb':
                cap.release()

            # for i_frame in range(self.n_sequence):
            #     cv2.imshow('Frame', X1[i,i_frame])
            #     cv2.waitKey(1000)

        if self.type_model == 'rgb':
            X = X1
        elif self.type_model == 'skeleton':
            X = X2
        elif self.type_model == '2stream':
            X = [X1, X2]

        return X, Y
Exemple #24
0
class UnetDataGenerator(Sequence):
    """
    Inspired on this thread: https://github.com/keras-team/keras/issues/12120
    """
    def __init__(self,
                 features,
                 targets,
                 image_size,
                 label_size,
                 classes,
                 batch_size,
                 repeats=1,
                 shuffle=True,
                 validation=False):
        self._features = features
        self._targets = targets
        self._image_size = image_size
        self._label_size = label_size
        self._classes = classes
        self._batch_size = batch_size
        self._shuffle = shuffle
        self._repeats = repeats
        self._verification = validation

        self._ids = list(self._list_files())

        self._indexes = np.arange(len(self._ids))
        if self._shuffle:
            np.random.shuffle(self._indexes)
        self._indexes = np.repeat(self._indexes, self._repeats)

        self._augmenter = ImageDataGenerator(rotation_range=30,
                                             zoom_range=0.2,
                                             width_shift_range=0.01,
                                             height_shift_range=0.01,
                                             horizontal_flip=True,
                                             vertical_flip=True,
                                             samplewise_std_normalization=True)

    def _list_files(self):
        feature_files = os.listdir(self._features)
        target_files = os.listdir(self._targets)
        return zip(feature_files, target_files)

    def _encode_one_hot(self, label):
        x = np.zeros(
            (self._label_size[0] * self._label_size[1], self._classes))
        for c in range(1, self._classes + 1):
            a = label == c
            x[(label == c).squeeze(), c - 1] = 1
        return x

    def __len__(self):
        return int(np.floor(len(self._ids) / self._batch_size)) * self._repeats

    def __getitem__(self, item):
        indexes = self._indexes[item * self._batch_size:(item + 1) *
                                self._batch_size]
        ids_temp = [self._ids[idx] for idx in indexes]

        X = [
            cv2.resize(
                cv2.imread(os.path.join(self._features, ids_temp[k][0]),
                           cv2.IMREAD_COLOR), self._image_size,
                cv2.INTER_NEAREST).astype(np.float64) / 255.0
            for k in range(len(ids_temp))
        ]
        y = [
            cv2.resize(
                cv2.imread(os.path.join(self._targets, ids_temp[k][1]),
                           cv2.IMREAD_COLOR), self._image_size,
                cv2.INTER_NEAREST) for k in range(len(ids_temp))
        ]

        params = self._augmenter.get_random_transform(self._image_size)

        if not self._verification:
            X = np.array([
                self._augmenter.apply_transform(self._augmenter.standardize(x),
                                                params) for x in X
            ])
            y = np.array([
                self._encode_one_hot(
                    cv2.resize(
                        self._augmenter.apply_transform(_y, params)[:, :, 0],
                        self._label_size, cv2.INTER_NEAREST).reshape(-1, 1))
                for _y in y
            ])
        else:
            X = np.array([self._augmenter.standardize(x) for x in X])
            y = np.array([
                self._encode_one_hot(
                    cv2.resize(_y[:, :, 0], self._label_size,
                               cv2.INTER_NEAREST).reshape(-1, 1)) for _y in y
            ])
        return np.array(X), np.array(y)

    def on_epoch_end(self):
        self._indexes = np.arange(len(self._ids))
        if self._shuffle:
            np.random.shuffle(self._indexes)
        self._indexes = np.repeat(self._indexes, self._repeats)
class DataGenerator(keras.utils.Sequence):
    'Generates data for Keras'

    def __init__(self,
                 list_IDs,
                 labels,
                 batch_size=32,
                 dim=(32, 32),
                 n_channels=1,
                 n_sequence=4,
                 shuffle=True,
                 path_dataset=None,
                 type_gen='train',
                 option=None):
        'Initialization'
        self.dim = dim
        self.batch_size = batch_size
        self.labels = labels
        self.list_IDs = list_IDs
        self.n_channels = n_channels
        self.n_sequence = n_sequence
        self.shuffle = shuffle
        self.path_dataset = path_dataset
        self.type_gen = type_gen
        self.option = option
        self.aug_gen = ImageDataGenerator()
        print("all:", len(self.list_IDs), " batch per epoch",
              int(np.floor(len(self.list_IDs) / self.batch_size)))
        self.on_epoch_end()

        self.n = 0
        self.max = self.__len__()

    def __next__(self):
        if self.n >= self.max:
            self.n = 0
        result = self.__getitem__(self.n)
        self.n += 1
        return result

    def __len__(self):
        return int(np.floor(len(self.list_IDs) / self.batch_size))

    def on_epoch_end(self):
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __getitem__(self, index):
        indexes = self.indexes[index * self.batch_size:(index + 1) *
                               self.batch_size]
        list_IDs_temp = [self.list_IDs[k] for k in indexes]
        X, y = self.__data_generation(list_IDs_temp)
        if self.type_gen == 'predict':
            return X
        else:
            return X, y

    def get_sampling_frame(self, len_frames):
        return range(self.n_sequence)
        # return np.linspace(1, len_frames-2, self.n_sequence, dtype='int') # last frame gives error sometimes, skip it

    def sequence_augment(self, sequence):
        name_list = [
            'rotate', 'width_shift', 'height_shift', 'brightness',
            'flip_horizontal', 'width_zoom', 'height_zoom'
        ]
        dictkey_list = [
            'theta', 'ty', 'tx', 'brightness', 'flip_horizontal', 'zy', 'zx'
        ]

        random_aug = np.random.randint(2, 5)  # random 2-4 augmentation method
        pick_idx = np.random.choice(len(dictkey_list),
                                    random_aug,
                                    replace=False)  #

        dict_input = {}
        for i in pick_idx:
            if dictkey_list[i] == 'theta':
                dict_input['theta'] = np.random.randint(-10, 10)

            elif dictkey_list[i] == 'ty':  # width_shift
                dict_input['ty'] = np.random.randint(-10, 10)

            elif dictkey_list[i] == 'tx':  # height_shift
                dict_input['tx'] = np.random.randint(-10, 10)

            elif dictkey_list[i] == 'brightness':
                dict_input['brightness'] = np.random.uniform(0.8, 1.2)

            elif dictkey_list[i] == 'flip_horizontal':
                dict_input['flip_horizontal'] = True

            elif dictkey_list[i] == 'zy':  # width_zoom
                dict_input['zy'] = np.random.uniform(0.75, 1.25)

            elif dictkey_list[i] == 'zx':  # height_zoom
                dict_input['zx'] = np.random.uniform(0.75, 1.25)
        len_seq = sequence.shape[0]
        for i in range(len_seq):
            sequence[i] = self.aug_gen.apply_transform(sequence[i], dict_input)

        return sequence

    def albu_aug(self, sequence, tfms=albu_tfms):
        seed = random.randint(0, 99999)

        for index, x in enumerate(sequence):
            random.seed(seed)
            sequence[index] = tfms(image=x.astype('uint8'))['image']
        return sequence

    def __data_generation(self, list_IDs_temp):
        'Generates data containing batch_size samples'
        # Initialization

        if self.option == "Fuse":
            X = np.empty((self.batch_size, self.n_sequence * 2 - 1, *self.dim,
                          self.n_channels))  # (bs, 127, 224, 224, 3)
        elif self.option == "Flow":
            X = np.empty((self.batch_size, self.n_sequence - 1, *self.dim,
                          self.n_channels))  # (bs, 63, 224, 224, 3)
        else:
            X = np.empty((self.batch_size, self.n_sequence, *self.dim,
                          self.n_channels))  # (bs, 64, 224, 224, 3)
        Y = np.empty((self.batch_size), dtype=int)

        for i, ID in enumerate(list_IDs_temp):  # ID is name of file
            path_file = self.path_dataset + ID + '.avi'
            cap = cv2.VideoCapture(path_file)
            length_file = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)
                              )  # get how many frames this video have
            index_sampling = self.get_sampling_frame(
                length_file)  # get sampling index, returns 64 index

            if self.option == "Flow":
                cap.set(cv2.CAP_PROP_POS_FRAMES, 1)
            for j, n_pic in enumerate(range(self.n_sequence)):
                # cap.set(cv2.CAP_PROP_POS_FRAMES, n_pic) # jump to that index
                ret, frame = cap.read()

                try:
                    frame = cv2.cvtColor(frame,
                                         cv2.COLOR_BGR2RGB)  # forgot to do it
                    frame = cv2.resize(frame, self.dim[::-1])
                except:
                    print(frame, length_file, path_file, "Using old image")
                X[i, j, :, :, :] = frame

            if self.option != 'RGB':  # for fuse and flow
                cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
                ret, frame = cap.read()
                frame = cv2.cvtColor(frame,
                                     cv2.COLOR_BGR2RGB)  # forgot to do it
                frame = cv2.resize(frame, self.dim[::-1])

                temp = (X[i, ]).astype('uint8')
                temp = np.insert(temp, 0, frame, axis=0)
                if self.option == 'Flow':
                    X[i, ] = compute_flow(temp)
                elif self.option == 'Fuse':  # using both RGB + Flow => X will have shape of (BS, 2*n_sequnece, 224, 224, 3)
                    X[i, ] = np.concatenate(
                        (X[i, :self.n_sequence],
                         compute_flow(temp[:self.n_sequence])),
                        axis=0)

            # augmentation and retrieving labels
            if self.type_gen == 'train':
                X[i, ] = (self.sequence_augment(
                    X[i, ]
                )) / 255.0  # each sample undergoes the same transformation
            else:
                X[i, ] = X[i, ] / 255.0
            Y[i] = self.labels[ID]
            cap.release()

        if self.option == "Fuse":
            return [
                X[:, :self.n_sequence, :, :, :], X[:,
                                                   self.n_sequence:, :, :, :]
            ], Y
        else:
            if self.option == "Grey":
                X = X * 255
                X = X.astype('uint8')
                X = create_outline(X)
            return X, Y
def AugVal_reg(in_vol_in, in_vol_out, num_out, minmax):

    new_vol_in = np.empty(
        [in_vol_in.shape[0], in_vol_in.shape[1], in_vol_in.shape[2], 1])
    new_vol_out = np.zeros((num_out, 1))

    sh = new_vol_in.shape
    Vols = [[], []]
    datagen = ImageDataGenerator()
    r_list = [-0.5, 0.25, 0.11]
    flip_list = [False, False, True]

    for i in range(len(r_list)):
        # prepare i different transformations
        r = r_list[i]
        flip = flip_list[i]
        # print("r= ", r)
        imageData = np.empty([sh[0], sh[1], sh[2]])
        image = np.zeros([sh[0], sh[1], 1])

        for j in range(sh[2]):

            # apply transformation on image
            image1 = np.expand_dims(in_vol_in[:, :, j], 2)
            image = datagen.apply_transform(
                image1,
                transform_parameters={
                    'flip_vertical': flip,
                    # vertical flip = upside down image
                    'tx': r * 10,  # vertical translation
                    'ty': r * 10
                })  # horizontal translation

            # Do preprocess on input images and change gray level of images to [0 255] and eliminate
            # nan and -inf values from image pixels value and active below process
            image = np.squeeze(image, axis=2)
            #        image = np.uint8(image)
            #        image = image / 255
            #        image[image < 0] = 0
            #        image[image > 1] = 1

            imageData[:, :, j] = image  # (128, 128, 99)

        imageData = imageData.reshape(sh[0], sh[1], sh[2], 1)
        new_vol_in[:, :, :, :] = imageData
        Vols[0].append(new_vol_in)

    # Add original image in Vols[0]/ After preprocess of input images , active below process

#    in_vol_in = np.uint8(in_vol_in)
#    in_vol_in = in_vol_in / 255
#    in_vol_in[in_vol_in < 0] = 0
#    in_vol_in[in_vol_in > 1] = 1
    in_vol_in = in_vol_in.reshape(sh[0], sh[1], sh[2], 1)
    Vols[0].append(in_vol_in)

    # Normalized coefficients with total min and total max of all coefficients
    new_vol_out = (in_vol_out - minmax[0]) / (minmax[1] - minmax[0])
    Vols[1].append(new_vol_out[:, 1])
    Vols[1].append(new_vol_out[:, 1])
    Vols[1].append(new_vol_out[:, 1])
    Vols[1].append(new_vol_out[:, 1])

    #    Vols.append(new_vol_in)
    #    Vols.append(new_vol_out)

    return Vols
Exemple #27
0
class HPatches():
    def __init__(self,
                 train=True,
                 transform=None,
                 download=False,
                 train_fnames=[],
                 test_fnames=[],
                 denoise_model=None,
                 use_clean=False):
        self.train = train
        self.transform = transform
        self.train_fnames = train_fnames
        self.test_fnames = test_fnames
        self.denoise_model = denoise_model
        self.use_clean = use_clean
        self.imgaug = ImageDataGenerator(
            # featurewise_center=True,
            # featurewise_std_normalization=True,
            rotation_range=20,
            width_shift_range=0.2,
            height_shift_range=0.2,
            horizontal_flip=True)

    def set_denoise_model(self, denoise_model):
        self.denoise_model = denoise_model

    def denoise_patches(self, patches):
        batch_size = 100
        for i in tqdm(range(int(len(patches) / batch_size)), file=sys.stdout):
            batch = patches[i * batch_size:(i + 1) * batch_size]
            batch = np.expand_dims(batch, -1)
            batch = np.clip(
                self.denoise_model.predict(batch).astype(int), 0,
                255).astype(np.uint8)[:, :, :, 0]
            patches[i * batch_size:(i + 1) * batch_size] = batch
        batch = patches[i * batch_size:]
        batch = np.expand_dims(batch, -1)
        batch = np.clip(self.denoise_model.predict(batch).astype(int), 0,
                        255).astype(np.uint8)[:, :, :, 0]
        patches[i * batch_size:] = batch
        return patches

    def read_image_file(self, data_dir, train=1):
        """Return a Tensor containing the patches
        """
        if self.denoise_model and not self.use_clean:
            print('Using denoised patches')
        elif not self.denoise_model and not self.use_clean:
            print('Using noisy patches')
        elif self.use_clean:
            print('Using clean patches')
        sys.stdout.flush()
        patches = []
        labels = []
        counter = 0
        hpatches_sequences = [x[1] for x in os.walk(data_dir)][0]
        if train:
            list_dirs = self.train_fnames
        else:
            list_dirs = self.test_fnames

        for directory in tqdm(hpatches_sequences, file=sys.stdout):
            if (directory in list_dirs):
                for tp in tps:
                    if self.use_clean:
                        sequence_path = os.path.join(data_dir, directory,
                                                     tp) + '.png'
                    else:
                        sequence_path = os.path.join(data_dir, directory,
                                                     tp) + '_noise.png'
                    image = cv2.imread(sequence_path, 0)
                    h, w = image.shape
                    n_patches = int(h / w)
                    n_aug = 3
                    for i in range(n_patches):
                        patch = image[i * (w):(i + 1) * (w), 0:w]
                        patch = cv2.resize(patch, (32, 32))
                        patch = np.array(patch, dtype=np.uint8)
                        patches.append(patch)
                        labels.append(i + n_aug * i + counter)
                        for j in range(0, n_aug):
                            params = self.imgaug.get_random_transform(
                                patch.shape)
                            patch_aug = self.imgaug.apply_transform(
                                self.imgaug.standardize(patch), params)
                            patches.append(patch_aug)
                            labels.append(i + j + counter)

                counter += n_patches

        patches = np.array(patches, dtype=np.uint8)
        if self.denoise_model and not self.use_clean:
            print('Denoising patches...')
            patches = self.denoise_patches(patches)
        return patches, labels
Exemple #28
0
class DataGenerator(tensorflow.keras.utils.Sequence):
    'Generates data for Keras'

    def __init__(self,
                 data_type='train',
                 dim=(84, 84),
                 n_channels=3,
                 way=5,
                 shot=1,
                 query=5,
                 num_batch=500):
        'Initialization'
        self.type = data_type
        # if self.type == 'train':
        #     self.is_training = np.array([True for _ in range(batch_size)])
        # else:
        #     self.is_training = np.array([False for _ in range(batch_size)])
        self.dim = dim
        #self.batch_size = batch_size
        self.n_channels = n_channels
        self.num_per_class = 600
        self.num_batch = num_batch
        #self.y_target = np.zeros(self.batch_size)
        self.build_data(self.type)
        self.on_epoch_end()
        self.way = way
        self.shot = shot
        self.query = query
        self.transformer = ImageDataGenerator(width_shift_range=0.1,
                                              height_shift_range=0.1,
                                              zoom_range=0.2,
                                              rotation_range=30,
                                              horizontal_flip=True,
                                              shear_range=0.1)
        #TODO!!!!
        #self.hard_batch = np.zeros(batch_size, *dim, n_channels)

    def build_data(self, data_type):
        if data_type == 'train':
            self.class_data = np.load('python/mini_train.npy')
        elif data_type == 'val':
            self.class_data = np.load('python/mini_val.npy')
        else:
            self.class_data = np.load('python/mini_test.npy')

        self.n_classes = len(self.class_data)

    def __len__(self):
        'Denotes the number of batches per epoch'
        return self.num_batch

    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate data
        X_sample, X_query, label = self.__data_generation()
        #way = np.ones((self.way * self.shot, 1)) * self.way

        return [X_sample, X_query], label

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        pass

    def __data_generation(self):
        'Generates data containing batch_size samples'  # X : (n_samples, *dim, n_channels)
        # Initialization
        X_sample = np.empty((self.way, self.shot, *self.dim, self.n_channels))
        X_query = np.empty((self.way, self.query, *self.dim, self.n_channels))
        chosen_class = random.sample(range(self.n_classes), self.way)
        label = np.empty(self.way * self.query)
        # print(pos, neg)
        # print(self.class_data[pos][0].shape)
        # Generate data
        for i in range(self.way):
            sample_idx = random.sample(range(self.num_per_class),
                                       self.shot + self.query)
            sample_data = self.class_data[chosen_class[i]][sample_idx] / 255.
            if True:
                #if self.type != 'train':
                X_sample[i] = sample_data[:self.shot]
                X_query[i] = sample_data[self.shot:self.shot + self.query]
            else:
                for j in range(self.shot):
                    params = self.transformer.get_random_transform(
                        self.dim + (self.n_channels, ))
                    x = self.transformer.apply_transform(
                        sample_data[j], params)
                    X_sample[i][j] = x

                for j in range(self.shot, self.shot + self.query):
                    params = self.transformer.get_random_transform(
                        self.dim + (self.n_channels, ))
                    x = self.transformer.apply_transform(
                        sample_data[j], params)
                    X_query[i][j - self.shot] = x

            label[i * self.query:(i + 1) * self.query] = i
        return X_sample, X_query, np_utils.to_categorical(label)
Exemple #29
0
def convert_nyu(path):
    if not os.path.isfile(path):
        print('File not exist: %s, starting download NYU dataset' %
              NYU_FILE_PATH)
        filename = wget.download(NYU_FILE_URL, out="data")
        print('\nDownloaded: ', filename)

    print('Loading dataset: %s' % (path))
    h5file = h5py.File(path, 'r')

    # # print all mat variabls:
    # # (u'depths', <HDF5 dataset "depths": shape (1449, 640, 480), type "<f4">)
    # # (u'images', <HDF5 dataset "images": shape (1449, 3, 640, 480), type "|u1">)
    # for item in h5file.items():
    #     print(str(item))
    # image = h5file['images'][0]

    # training example contain a list of rgb depth pairs.
    train_examples = []
    dev_examples = []

    if not os.path.isdir(TRAIN_FILE_PATH):
        os.mkdir(TRAIN_FILE_PATH)

    file_count = h5file['images'].shape[0]
    train_file_count = file_count * (1.0 - DEV_PERCENT)
    datagen = ImageDataGenerator()
    for i in range(file_count):
        image = np.transpose(h5file['images'][i], (2, 1, 0))
        depth = np.transpose(h5file['depths'][i], (1, 0))

        image_name = os.path.join(TRAIN_FILE_PATH, '%05d_c.png' % (i))
        depth_name = os.path.join(TRAIN_FILE_PATH, '%05d_d.png' % (i))

        # save to local png file.
        if not os.path.isfile(image_name):
            image_im = Image.fromarray(np.uint8(image))
            image_im.save(image_name)

        if not os.path.isfile(depth_name):
            scaled_depth = (depth / np.max(depth)) * 255.0
            depth_im = Image.fromarray(np.uint8(scaled_depth))
            depth_im.save(depth_name)

        for augment_count in range(AUGMENTATION_COUNT):
            brightness = random.uniform(0.7, 1.0)
            zoom_scale = random.uniform(0.7, 1.0)
            flip_horizontal = bool(random.getrandbits(1))

            augmented_im_bytes = datagen.apply_transform(x=image,
                                                         transform_parameters={
                                                             'brightness':
                                                             brightness,
                                                             'zx':
                                                             zoom_scale,
                                                             'zy':
                                                             zoom_scale,
                                                             'flip_horizontal':
                                                             flip_horizontal
                                                         })
            augmented_im = Image.fromarray(np.uint8(augmented_im_bytes))
            agumented_image_name = os.path.join(
                TRAIN_FILE_PATH, '%05d_c_aug_%d.png' % (i, augment_count))
            augmented_im.save(agumented_image_name)

            # expand depth to 3 channels, keras apply_transform can only tranform 3 channel images.
            depth_multi_channel = np.array([depth, depth, depth])
            # tranpose depth image to (height, width, channel)
            depth_multi_channel = np.transpose(depth_multi_channel, (1, 2, 0))

            augmented_depth_bytes = datagen.apply_transform(
                x=depth_multi_channel,
                transform_parameters={
                    'zx': zoom_scale,
                    'zy': zoom_scale,
                    'flip_horizontal': flip_horizontal
                })

            # get back single channel depth
            single_channel_aug_d = augmented_depth_bytes[:, :, 0]
            single_channel_aug_d = (single_channel_aug_d /
                                    np.max(single_channel_aug_d)) * 255.0
            augmented_depth = Image.fromarray(np.uint8(single_channel_aug_d))
            agumented_depth_name = os.path.join(
                TRAIN_FILE_PATH, '%05d_d_aug_%d.png' % (i, augment_count))
            augmented_depth.save(agumented_depth_name)
            train_examples.append((agumented_image_name, agumented_depth_name))

        if i < train_file_count:
            train_examples.append((image_name, depth_name))
        else:
            dev_examples.append((image_name, depth_name))

        print('Processed file: %i out of %d' % (i, file_count))

    random.shuffle(train_examples)
    # write train_examples to csv
    with open('data/train.csv', 'w') as output:
        for (image_name, depth_name) in train_examples:
            output.write("%s,%s" % (image_name, depth_name))
            output.write("\n")

    with open('data/dev.csv', 'w') as output:
        for (image_name, depth_name) in dev_examples:
            output.write("%s,%s" % (image_name, depth_name))
            output.write("\n")