              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)
  
      # for now, we limit this class responsability to the read of files. images and faces are processed outside this class
 
</s> remove         self.encoding = face_recognition.face_encodings(image)[0] # Note: we take only first face, so the reference file should only contain one face. We could also keep all faces found and filter against multiple faces
 </s> add         self.encoding = face_recognition.face_encodings(image)[0] # Note: we take only first face, so the reference file should only contain one face.
 </s> remove         
 </s> add     def add_optional_arguments(self, parser):
        parser.add_argument('-D', '--detector',
                            type=str,
                            choices=("hog", "cnn"), # case sensitive because this is used to load a plugin.
                            default="hog",
                            help="Detector to use. 'cnn' detects much more angles but will be much more resource intensive and may fail on large files.")

        parser.add_argument('-f', '--filter',
                            type=str,
                            dest="filter",
                            default="filter.jpg",
                            help="Reference image for the person you want to process. Should be a front portrait"
                            )

        parser.add_argument('-j', '--processes',
                            type=int,
                            help="Number of processes to use.")
        return parser
 </s> remove         encodings = face_recognition.face_encodings(detected_face.image)[0] # we could use detected landmarks, but I did not manage to do so
        score = face_recognition.face_distance([self.encoding], encodings)
        print(score)
        return score <= self.threshold

 </s> add         encodings = face_recognition.face_encodings(detected_face.image) # we could use detected landmarks, but I did not manage to do so. TODO The copy/paste below should help
        if encodings is not None and len(encodings) > 0:
            score = face_recognition.face_distance([self.encoding], encodings[0])
            print(score)
            return score <= self.threshold
        else:
            print("No face encodings found")
            return False
 </s> remove coverage = 220 # Coverage of the face for training. Larger value will cover more features. @shaoanlu recommends 220. Original is 160

random_transform_args = {
    'rotation_range': 10,
    'zoom_range': 0.05,
    'shift_range': 0.05,
    'random_flip': 0.4,
}

# 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 )
 </s> add class TrainingDataGenerator():
    def __init__(self, random_transform_args, coverage):
        self.random_transform_args = random_transform_args
        self.coverage = coverage

    def minibatchAB(self, images, batchsize):
        batch = BackgroundGenerator(self.minibatch(images, batchsize), 1)
        for ep1, warped_img, target_img in batch.iterator():
            yield ep1, warped_img, target_img

    # A generator function that yields epoch, batchsize of warped_img and batchsize of target_img
    def minibatch(self, data, batchsize):
        length = len(data)
        assert length >= batchsize, "Number of images is lower than batch-size (Note that too few images may lead to bad training). # images: {}, batch-size: {}".format(length, batchsize)
        epoch = i = 0
        shuffle(data)
        while True:
            size = batchsize
            if i+size > length:
                shuffle(data)
                i = 0
                epoch+=1
            rtn = numpy.float32([self.read_image(img) for img in data[i:i+size]])
            i+=size
            yield epoch, rtn[:,0,:,:,:], rtn[:,1,:,:,:]       

    def color_adjust(self, img):
        return img / 255.0
 </s> remove             for filename in self.read_directory():
                image = cv2.imread(filename)
                for idx, face in self.get_faces(image):
                    resized_image = extractor.extract(image, face, 256)
                    output_file = self.output_dir / Path(filename).stem
                    cv2.imwrite(str(output_file) + str(idx) + Path(filename).suffix, resized_image)
                
 </s> add             return self.handleImage(filename)
        filter_file = self.arguments.filter
              print('Note: Found more than one face in an image!')
              self.verify_output = True
      
      def load_filter(self):
        filter_file = self.arguments.filter
          if Path(filter_file).exists():
              print('Loading reference image for filtering')
              return FaceFilter(filter_file)
  
      # for now, we limit this class responsability to the read of files. images and faces are processed outside this class
keep keep keep keep replace keep keep keep keep keep
 Misc updates on master before GAN. Added multithreading + mmod face detector (#109)

* Preparing GAN plugin

* Adding multithreading for extract

* Adding support for mmod human face detector

* Adding face filter argument

* Added process number argument to multiprocessing extractor.

Fixed progressbar for multiprocessing.

* Added tiff as image type.
compression artefacts hurt my feelings.

* Cleanup 
lib/cli.py