  # get pair of random warped images from aligened face image
  
  def random_warp(image):
      assert image.shape == (256, 256, 3)
      range_ = numpy.linspace(128 - 80, 128 + 80, 5)
      mapx = numpy.broadcast_to(range_, (5, 5))
      mapy = mapx.T
  
      mapx = mapx + numpy.random.normal(size=(5, 5), scale=5)
      mapy = mapy + numpy.random.normal(size=(5, 5), scale=5)
 
</s> remove # get pair of random warped images from aligened face image

 </s> add # get pair of random warped images from aligned face image
 </s> remove def get_training_data(images, batch_size):
    indices = numpy.random.randint(len(images), size=batch_size)
    for i, index in enumerate(indices):
        image = images[index]
        image = random_transform(image, **random_transform_args)
        warped_img, target_img = random_warp(image)

        if i == 0:
            warped_images = numpy.empty(
                (batch_size,) + warped_img.shape, warped_img.dtype)
            target_images = numpy.empty(
                (batch_size,) + target_img.shape, warped_img.dtype)

        warped_images[i] = warped_img
        target_images[i] = target_img

    return warped_images, target_images
 </s> add # GAN
# random_transform_args = {
#     'rotation_range': 20,
#     'zoom_range': 0.1,
#     'shift_range': 0.05,
#     'random_flip': 0.5,
#     }
def read_image(fn, random_transform_args=random_transform_args):
    image = cv2.imread(fn) / 255.0
    image = cv2.resize(image, (256,256))
    image = random_transform( image, **random_transform_args )
    warped_img, target_img = random_warp( image )
    
    return warped_img, target_img

# A generator function that yields epoch, batchsize of warped_img and batchsize of target_img
def minibatch(data, batchsize):
    length = len(data)
    epoch = i = 0
    shuffle(data)
    while True:
        size = batchsize
        if i+size > length:
            shuffle(data)
            i = 0
            epoch+=1        
        rtn = numpy.float32([read_image(data[j]) for j in range(i,i+size)])
        i+=size
        yield epoch, rtn[:,0,:,:,:], rtn[:,1,:,:,:]       

def minibatchAB(images, batchsize):
    batch = BackgroundGenerator(minibatch(images, batchsize), 1)
    for ep1, warped_img, target_img in batch.iterator():
        yield ep1, warped_img, target_img
 </s> remove 
        self.finalize()
 </s> add     
    def get_faces(self, image):
        faces_count = 0
        for face in detect_faces(image):
            if self.filter is not None and not self.filter.check(face):
                print('Skipping not recognized face!')
                continue

            yield faces_count, face

            self.faces_detected = self.faces_detected + 1
            faces_count +=1
        
        if faces_count > 0 and self.arguments.verbose:
            print('Note: Found more than one face in an image!')
            self.verify_output = True
    
    def load_filter(self):
        filter_file = "filter.jpg" # TODO Pass as argument
        if Path(filter_file).exists():
            print('Loading reference image for filtering')
            return FaceFilter(filter_file) </s> remove     for ((top, right, bottom, left), landmarks) in zip(face_locations, landmarks_as_tuples):
        x = left
        y = top
        w = right - left
        h = bottom - top
        yield DetectedFace(frame[y: y + h, x: x + w], x, w, y, h, landmarks)
 </s> add     for ((y, right, bottom, x), landmarks) in zip(face_locations, landmarks):
        yield DetectedFace(frame[y: bottom, x: right], x, right - x, y, bottom - y, landmarks) </s> remove     def save_model_weights(self):
        encoder.save_weights(self.arguments.model_dir + '/encoder.h5')
        decoder_A.save_weights(self.arguments.model_dir + '/decoder_A.h5')
        decoder_B.save_weights(self.arguments.model_dir + '/decoder_B.h5')
        print('save model weights')

    def show_sample(self, test_A, test_B):
        figure_A = numpy.stack([
            test_A,
            autoencoder_A.predict(test_A),
            autoencoder_B.predict(test_A),
        ], axis=1)
        figure_B = numpy.stack([
            test_B,
            autoencoder_B.predict(test_B),
            autoencoder_A.predict(test_B),
        ], axis=1)

        figure = numpy.concatenate([figure_A, figure_B], axis=0)
        figure = figure.reshape((4, 7) + figure.shape[1:])
        figure = stack_images(figure)

        figure = numpy.clip(figure * 255, 0, 255).astype('uint8')

        if self.arguments.preview is True:
            cv2.imshow('', figure)
        if not self.arguments.preview or self.arguments.write_image:
            cv2.imwrite('_sample.jpg', figure)

 </s> add 
    range_ = numpy.linspace(128 - coverage//2, 128 + coverage//2, 5)

  # get pair of random warped images from aligened face image
  
  def random_warp(image):
      assert image.shape == (256, 256, 3)
    range_ = numpy.linspace(128 - coverage//2, 128 + coverage//2, 5)
      mapx = numpy.broadcast_to(range_, (5, 5))
      mapy = mapx.T
  
      mapx = mapx + numpy.random.normal(size=(5, 5), scale=5)
      mapy = mapy + numpy.random.normal(size=(5, 5), scale=5)
keep keep keep keep replace keep keep keep keep keep
 Adding models as plugins + Face filtering (#53) + #39 + #43 + #44 + #49 (#61)

* Making Models as plugins

* Do not reload model on each image #39 + Adding FaceFilter #53

* Adding @lukaville PR for #43 and #44 (possibly)

* Training done in a separate thread

* Better log for plugin load

* Adding a prefetch to train.py #49
(Note that we prefetch 2 batches of images, due to the queue behavior)
+ More compact logging with verbose info included

* correction of DirectoryProcessor signature

* adding missing import

* Convert with parallel preprocessing of files

* Added coverage var for trainer

Added a var with comment. Feel free to add it as argument

* corrections

* Modifying preview and normalization of image + correction

* Cleanup 
lib/training_data.py