def test_size_constructor2(self): """Check if the constructor can handle the singleton case, that is initializing from a `Size` object should return the same `Size` object. """ size = Size(3, 4) size2 = Size(size) self.assertEqual(size, size2) self.assertIs(size, size2)
def test_size_equal(self): """Test size equality between different types. """ # equality of size objects size1 = Size(3, 4) size2 = Size(3, 4) self.assertEqual(size1, size2) # equality of size objects and tuples size_tuple = (3, 4) self.assertEqual(size1, size_tuple) self.assertEqual(size_tuple, size1) # equality of size objects and lists size_list = [3, 4] self.assertEqual(size1, size_list) self.assertEqual(size_list, size1)
def test_size_type(self): """Test :py:class:`Size` type. """ size_tuple = (3, 4) size_list = [3, 4] size = Size(3, 4) self.assertNotIsInstance(size_tuple, Size) self.assertNotIsInstance(size_list, Size) self.assertIsInstance(size, Size)
def test_sizelike_type(self): """Test :py:class:`Sizelike` type. """ size_tuple = (3, 4) size_list = [3, 4] size_str = '3x4' size = Size(3, 4) # TypeError: Subscripted generics cannot be used with class # and instance checks sizelike_types = \ tuple(get_origin(arg) or arg for arg in get_args(Sizelike)) self.assertIsInstance(size_tuple, sizelike_types) self.assertIsInstance(size_list, sizelike_types) self.assertIsInstance(size, sizelike_types) self.assertIsInstance(size_str, sizelike_types)
class TestImage(unittest.TestCase): """Test the :py:class:`Image` type. """ example_image_filename = 'examples/dog.jpg' example_image_size = Size(1546, 1213) def test_supported_formats(self): """Test supported image formats. """ self.assertIn('array', Image.supported_formats()) self.assertIn('image', Image.supported_formats()) @unittest.skipUnless(os.path.isfile(example_image_filename), reason="Example image file is not available") def test_image_creation(self): """Test creation of `Image`. """ image = Image(self.example_image_filename) self.assertEqual(image.size(), self.example_image_size) @unittest.skipIf(importlib.util.find_spec("PyQt5") is None or not os.path.isfile(example_image_filename), reason="PyQt is not available") def test_qt(self): """Test :py:class:`Size` type. """ module = importlib.import_module('qtgui.widgets.image') self.assertIn('qimage', Image.supported_formats()) image = Image(self.example_image_filename) qimage = Image.as_qimage(image) self.assertIsInstance(qimage, module.QImage) @unittest.skipIf(importlib.util.find_spec("PIL") is None or not os.path.isfile(example_image_filename), reason="Python Image Library (PIL/pillow)" " is not available") def test_pillow(self): """Test :py:class:`Size` type. """ module = importlib.import_module('dltb.thirdparty.pil') self.assertIn('pil', Image.supported_formats()) image = Image(self.example_image_filename) pil = Image.as_pil(image) self.assertIsInstance(pil, module.PIL.Image.Image)
def warp(image: Imagelike, transformation: np.ndarray, size: Sizelike) -> np.ndarray: """Warp an image by applying a transformation. """ image = Image.as_array(image) size = Size(size) output_shape = (size[1], size[0]) # further argument: order (int, optional): # The order of interpolation. The order has to be in the range 0-5: # 0: Nearest-neighbor # 1: Bi-linear (default) # 2: Bi-quadratic # 3: Bi-cubic # 4: Bi-quartic # 5: Bi-quintic warped = warp(image, transformation, output_shape=output_shape, preserve_range=True) warped = warped.astype(image.dtype) return warped
def test_size_constructor(self): """Test the constructor with different aruments. """ # two arguments size = Size(3, 4) self.assertEqual(size.width, 3) self.assertEqual(size.height, 4) # pair of arguments size_tuple = (3, 4) size = Size(size_tuple) self.assertEqual(size.width, size_tuple[0]) self.assertEqual(size.height, size_tuple[1]) # list of two arguments size_list = [3, 4] size = Size(size_list) self.assertEqual(size.width, size_list[0]) self.assertEqual(size.height, size_list[1]) size_str1 = '3x4' size = Size(size_str1) self.assertEqual(size.width, 3) self.assertEqual(size.height, 4) size_str2 = '3,4' size = Size(size_str2) self.assertEqual(size.width, 3) self.assertEqual(size.height, 4) size = Size(5) self.assertEqual(size.width, 5) self.assertEqual(size.height, 5) size = Size('5') self.assertEqual(size.width, 5) self.assertEqual(size.height, 5)
class Detector(DetectorBase): """Torch-based implementation of the MTCNN detector from the face.evoLVe repository [1]. [1] https://github.com/ZhaoJ9014/face.evoLVe """ internal_arguments: Tuple[str, ...] = ('pil', ) # Default reference facial points for crop_size = (96, 112); (this # is taken from the the face_evoLVe repository, # applications/align/align_trans.py. Note: According to the # comments in that file, these landmarks are for a "facial points # crop_size = (112, 112)", however, the crop size is then # specified as (96, 112), and this actually seems to be more # appropriate). The coordinates are of the form (x, y), with the # origin located at the bottom left corner of the image. _reference_landmarks = Landmarks(points=np.asarray([ [30.29459953, 51.69630051], # left mouth [65.53179932, 51.50139999], # right mouth [48.02519989, 71.73660278], # nose [33.54930115, 92.3655014], # left eye [62.72990036, 92.20410156] # right eye ])) _reference_size = Size(96, 112) def __init__(self, **kwargs): super().__init__(**kwargs) self._face_evolve_repository = \ 'https://github.com/ZhaoJ9014/face.evoLVe' self._face_evolve_directory = config.github_directory / 'face.evoLVe' self._module_detector = None def _prepared(self) -> bool: return (self._module_detector is not None) and super()._prepared() def _preparable(self) -> bool: return self._face_evolve_directory.is_dir() and super()._preparable() def _prepare(self) -> None: super()._prepare() # (1) load the model align_code_directory = \ self._face_evolve_directory / 'applications' / 'align' self._module_detector = \ Importer.import_module_from('detector', directory=align_code_directory) def _preprocess_data(self, data: Data, **kwargs): print("Preprocessing data") # FIXME: is not called return PIL.Image.fromarray(data.array) def _preprocess(self, *args, **kwargs) -> Data: context = super()._preprocess(*args, **kwargs) context.add_attribute('pil', PIL.Image.fromarray(context.input_image)) return context def _detect(self, image: PIL.Image, **kwargs) -> Metadata: """Apply the MTCNN detector to detect faces in the given image. Arguments --------- image: The image to detect faces in. Expected is a RGB image with np.uint8 data. Returns ------ metadata: Metadata A Metadata structure in which BoundingBoxes and FacialLandmarks are provided, annotated with a numeric 'id' and a 'confidence' value. """ # FIXME[hack]: if isinstance(image, np.ndarray): image = PIL.Image.fromarray(image) # # (1) Run the MTCNN detector # try: # FIXME[question]: what is going on here? can this be done # in prepare? align_code_directory = \ self._face_evolve_directory / 'applications' / 'align' prev_cwd = os.getcwd() os.chdir(align_code_directory) LOG.info("MTCNN: detecting facess ...") bounding_boxes, landmarks = \ self._module_detector.detect_faces(image) LOG.info("MTCNN: ... found %d faces.", len(bounding_boxes)) finally: os.chdir(prev_cwd) # # (2) Create Metadata # self.detect_boxes = True self.detect_landmarks = True detections = Metadata( description='Detections by the Torch MTCNN detector') for face_id, (bbox, mark) in enumerate(zip(bounding_boxes, landmarks)): confidence = bbox[4] if self.detect_boxes: # The bounding boxes are reported as a 5-tuple: # (x1, y1, x2, y2, confidence) detections.add_region(BoundingBox(x1=bbox[0], y1=bbox[1], x2=bbox[2], y2=bbox[3]), confidence=confidence, id=face_id) if self.detect_landmarks: # landmarks are reported as array of length 10, consisting # of 5 consecutive x-coordinates followed by 5 corresponding # y-coordinates. The order of these pairs # is: left_mouth, right_mouth, nose, left_eye, right_eye # That is the array holds # [left_mouth_x, right_mouth_x, nose_x, # left_eye_x, right_eye_x, # left_mouth_y, right_mouth_y, nose_y, # left_eye_y, right_eye_y] points = mark.reshape(2, 5).T.astype(int) detections.add_region(Landmarks(points=points), confidence=confidence, id=face_id) return detections