def test_lazylist_map_no_call(): mock_func = Mock() double_func = lambda x: x * 2 ll = LazyList([mock_func]) ll_mapped = ll.map(double_func) assert id(ll) != id(ll_mapped) mock_func.assert_not_called()
def test_lazylist_map(): two_func = lambda: 2 double_func = lambda x: x * 2 ll = LazyList([two_func]) ll_mapped = ll.map(double_func) assert id(ll) != id(ll_mapped) assert ll_mapped[0] == 4
def test_lazylist_multi_map(): two_func = lambda: 2 double_func = [lambda x: x * 2] * 2 ll = LazyList([two_func] * 2) ll_mapped = ll.map(double_func) assert len(ll_mapped) == 2 assert id(ll) != id(ll_mapped) assert all(x == 4 for x in ll_mapped)
def test_lazylist_copy_lazy(): mock_func = Mock() mock_func.return_value = 1 ll = LazyList([mock_func] * 10) copied_ll = ll.copy() assert len(copied_ll) == 10 assert id(ll._callables) != id(copied_ll._callables) mock_func.assert_not_called()
def test_lazylist_add_lazylist(): a = Mock() b = Mock() ll1 = LazyList([a]) ll2 = LazyList([b]) new_ll = ll1 + ll2 assert len(new_ll) == 2 assert new_ll._callables[0] is a assert new_ll._callables[1] is b
def test_lazylist_multi_map_iterable_and_callable(): class double_func(collections_abc.Iterable): def __call__(self, x, **kwargs): return x * 2 def __iter__(self): yield 1 f = double_func() two_func = lambda: 2 ll = LazyList([two_func]) with raises(ValueError): ll.map(f)
def test_lazylist_multi_map_iterable_and_callable(): class double_func(collections.Iterable): def __call__(self, x, **kwargs): return x * 2 def __iter__(self): yield 1 f = double_func() two_func = lambda: 2 ll = LazyList([two_func]) ll.map(f) assert 1
def test_lazylist_multi_map_iterable_and_callable(): class double_func(collections.Iterable): def __call__(self, x, **kwargs): return x * 2 def __iter__(self): yield 1 f = double_func() two_func = lambda: 2 ll = LazyList([two_func]) with raises(ValueError): ll.map(f)
def build(self): import imageio reader = imageio.get_reader(self.filepath, format='gif', mode='I') def imageio_to_menpo(imio_reader, index): pixels = imio_reader.get_data(index) pixels = channels_to_front(pixels) if pixels.shape[0] == 4: # If normalise is False, then we return the alpha as an extra # channel, which can be useful if the alpha channel has semantic # meanings! if self.normalise: p = normalize_pixels_range(pixels[:3]) return MaskedImage(p, mask=pixels[-1].astype(np.bool), copy=False) else: return Image(pixels, copy=False) # Assumed not to have an Alpha channel if self.normalise: return Image(normalize_pixels_range(pixels), copy=False) else: return Image(pixels, copy=False) index_callable = partial(imageio_to_menpo, reader) ll = LazyList.init_from_index_callable(index_callable, reader.get_length()) return ll
def test_lazylist_multiple_calls(): mock_func = Mock() mock_func.return_value = 1 ll = LazyList([mock_func] * 10) ll[0] ll[0] assert mock_func.call_count == 2
def _import_lazylist_attach_landmarks(built_objects, landmark_resolver, landmark_ext_map=None): # handle landmarks if landmark_ext_map is not None: for k in range(len(built_objects)): x = built_objects[k] # Use the users function to find landmarks lm_paths = partial(landmark_resolver, x.path) # Do a little trick where we compose the landmark resolution onto # the lazy list indexing - after the item has been indexed. def wrap_landmarks(f, index): obj = f() for group_name, lm_path in lm_paths(index).items(): lms = _import(lm_path, landmark_ext_map, asset=obj) if obj.n_dims == lms.n_dims: obj.landmarks[group_name] = lms return obj new_ll = LazyList([ partial(wrap_landmarks, c, i) for i, c in enumerate(x._callables) ]) built_objects[k] = new_ll
def imageio_gif_importer(filepath, asset=None, normalise=True, **kwargs): r""" Imports GIF images using freeimagemulti plugin from the imageio library. Returns a :map:`LazyList` that gives lazy access to the GIF on a per-frame basis. Parameters ---------- filepath : `Path` Absolute filepath of the video. asset : `object`, optional An optional asset that may help with loading. This is unused for this implementation. normalise : `bool`, optional If ``True``, normalise between 0.0 and 1.0 and convert to float. If ``False`` just return whatever imageio imports. \**kwargs : `dict`, optional Any other keyword arguments. Returns ------- image : :map:`LazyList` A :map:`LazyList` containing :map:`Image` or subclasses per frame of the GIF. """ import imageio reader = imageio.get_reader(str(filepath), format='gif', mode='I') def imageio_to_menpo(imio_reader, index): pixels = imio_reader.get_data(index) pixels = channels_to_front(pixels) if pixels.shape[0] == 4: # If normalise is False, then we return the alpha as an extra # channel, which can be useful if the alpha channel has semantic # meanings! if normalise: p = normalize_pixels_range(pixels[:3]) return MaskedImage(p, mask=pixels[-1].astype(np.bool), copy=False) else: return Image(pixels, copy=False) # Assumed not to have an Alpha channel if normalise: return Image(normalize_pixels_range(pixels), copy=False) else: return Image(pixels, copy=False) index_callable = partial(imageio_to_menpo, reader) ll = LazyList.init_from_index_callable(index_callable, reader.get_length()) return ll
def imageio_gif_importer(filepath, asset=None, normalize=True, **kwargs): r""" Imports GIF images using freeimagemulti plugin from the imageio library. Returns a :map:`LazyList` that gives lazy access to the GIF on a per-frame basis. Parameters ---------- filepath : `Path` Absolute filepath of the video. asset : `object`, optional An optional asset that may help with loading. This is unused for this implementation. normalize : `bool`, optional If ``True``, normalize between 0.0 and 1.0 and convert to float. If ``False`` just return whatever imageio imports. \**kwargs : `dict`, optional Any other keyword arguments. Returns ------- image : :map:`LazyList` A :map:`LazyList` containing :map:`Image` or subclasses per frame of the GIF. """ import imageio reader = imageio.get_reader(str(filepath), format='gif', mode='I') def imageio_to_menpo(imio_reader, index): pixels = imio_reader.get_data(index) pixels = channels_to_front(pixels) if pixels.shape[0] == 4: # If normalize is False, then we return the alpha as an extra # channel, which can be useful if the alpha channel has semantic # meanings! if normalize: p = normalize_pixels_range(pixels[:3]) return MaskedImage(p, mask=pixels[-1].astype(np.bool), copy=False) else: return Image(pixels, copy=False) # Assumed not to have an Alpha channel if normalize: return Image(normalize_pixels_range(pixels), copy=False) else: return Image(pixels, copy=False) index_callable = partial(imageio_to_menpo, reader) ll = LazyList.init_from_index_callable(index_callable, reader.get_length()) return ll
def _import_glob_lazy_list( pattern, extension_map, max_assets=None, landmark_resolver=same_name, shuffle=False, as_generator=False, landmark_ext_map=None, landmark_attach_func=None, importer_kwargs=None, verbose=False, ): filepaths = list(glob_with_suffix(pattern, extension_map, sort=(not shuffle))) if shuffle: random.shuffle(filepaths) if (max_assets is not None) and max_assets <= 0: raise ValueError( "Max elements should be positive" " ({} provided)".format(max_assets) ) elif max_assets: filepaths = filepaths[:max_assets] n_files = len(filepaths) if n_files == 0: raise ValueError("The glob {} yields no assets".format(pattern)) lazy_list = LazyList( [ partial( _import, f, extension_map, landmark_resolver=landmark_resolver, landmark_ext_map=landmark_ext_map, landmark_attach_func=landmark_attach_func, importer_kwargs=importer_kwargs, ) for f in filepaths ] ) if verbose and as_generator: # wrap the generator with the progress reporter lazy_list = print_progress( lazy_list, prefix="Importing assets", n_items=n_files ) elif verbose: print("Found {} assets, index the returned LazyList to import.".format(n_files)) if as_generator: return (a for a in lazy_list) else: return lazy_list
def ffmpeg_importer(filepath, normalize=True, exact_frame_count=True, **kwargs): r""" Imports videos by streaming frames from a pipe using FFMPEG. Returns a :map:`LazyList` that gives lazy access to the video on a per-frame basis. There are two important environment variables that can be set to alter the behaviour of this function: ================== ====================================== ENV Variable Definition ================== ====================================== MENPO_FFMPEG_CMD The path to the 'ffmpeg' executable. MENPO_FFPROBE_CMD The path to the 'ffprobe' executable. ================== ====================================== Parameters ---------- filepath : `Path` Absolute filepath of the video. normalize : `bool`, optional If ``True``, normalize between 0.0 and 1.0 and convert to float. If ``False`` just return whatever ffmpeg imports. exact_frame_count: `bool`, optional If ``True``, the import fails if ffprobe is not available (reading from ffmpeg's output returns inexact frame count) \**kwargs : `dict`, optional Any other keyword arguments. Returns ------- image : :map:`LazyList` A :map:`LazyList` containing :map:`Image` or subclasses per frame of the video. """ reader = FFMpegVideoReader(filepath, normalize=normalize, exact_frame_count=exact_frame_count) ll = LazyList.init_from_index_callable( lambda x: Image.init_from_channels_at_back(reader[x]), len(reader)) ll.fps = reader.fps return ll
def build(self): import imageio reader = imageio.get_reader(self.filepath, format='ffmpeg', mode='I') def imageio_to_menpo(imio_reader, index): pixels = imio_reader.get_data(index) pixels = channels_to_front(pixels) if self.normalise: return Image(normalise_pixels_range(pixels), copy=False) else: return Image(pixels, copy=False) index_callable = partial(imageio_to_menpo, reader) ll = LazyList.init_from_index_callable(index_callable, reader.get_length()) ll.fps = reader.get_meta_data()['fps'] return ll
def ffmpeg_importer(filepath, normalize=True, exact_frame_count=True, **kwargs): r""" Imports videos by streaming frames from a pipe using FFMPEG. Returns a :map:`LazyList` that gives lazy access to the video on a per-frame basis. There are two important environment variables that can be set to alter the behaviour of this function: ================== ====================================== ENV Variable Definition ================== ====================================== MENPO_FFMPEG_CMD The path to the 'ffmpeg' executable. MENPO_FFPROBE_CMD The path to the 'ffprobe' executable. ================== ====================================== Parameters ---------- filepath : `Path` Absolute filepath of the video. normalize : `bool`, optional If ``True``, normalize between 0.0 and 1.0 and convert to float. If ``False`` just return whatever ffmpeg imports. exact_frame_count: `bool`, optional If ``True``, the import fails if ffprobe is not available (reading from ffmpeg's output returns inexact frame count) \**kwargs : `dict`, optional Any other keyword arguments. Returns ------- image : :map:`LazyList` A :map:`LazyList` containing :map:`Image` or subclasses per frame of the video. """ reader = FFMpegVideoReader(filepath, normalize=normalize, exact_frame_count=exact_frame_count) ll = LazyList.init_from_index_callable(lambda x: Image.init_from_channels_at_back(reader[x]), len(reader)) ll.fps = reader.fps return ll
def test_lazylist_add_non_iterable_non_lazy_list_rases_value_error(): with raises(ValueError): LazyList([1]) + None
def kf_sequence_image_paths(i, expression): return LazyList.init_from_iterable( mio.image_paths(kf_sequence_path(i, expression)))
def test_lazylist_slice_with_ndarray(): index = np.array([1, 0, 3], dtype=np.int) l = LazyList.init_from_iterable(['a', 'b', 'c', 'd', 'e']) l_indexed = l[index] assert list(l_indexed) == ['b', 'a', 'd']
def test_lazylist_get(): mock_func = Mock() mock_func.return_value = 1 ll = LazyList([mock_func] * 10) assert len(ll) == 10 assert ll[0] == 1
def test_lazylist_repeat(): ll = LazyList.init_from_iterable([0, 1]) ll_repeated = ll.repeat(2) assert len(ll_repeated) == 4 assert all([a == b for a, b in zip([0, 0, 1, 1], ll_repeated)])
def test_lazylist_multi_map_unequal_lengths(): two_func = lambda: 2 double_func = [lambda x: x * 2] * 2 ll = LazyList([two_func]) with raises(ValueError): ll.map(double_func)
def imageio_ffmpeg_importer(filepath, asset=None, normalise=True, **kwargs): r""" Imports videos using the FFMPEG plugin from the imageio library. Returns a :map:`LazyList` that gives lazy access to the video on a per-frame basis. Parameters ---------- filepath : `Path` Absolute filepath of the video. asset : `object`, optional An optional asset that may help with loading. This is unused for this implementation. normalise : `bool`, optional If ``True``, normalise between 0.0 and 1.0 and convert to float. If ``False`` just return whatever imageio imports. \**kwargs : `dict`, optional Any other keyword arguments. Returns ------- image : :map:`LazyList` A :map:`LazyList` containing :map:`Image` or subclasses per frame of the video. """ import imageio reader = imageio.get_reader(str(filepath), format='ffmpeg', mode='I') index_callable = partial(_imageio_to_menpo, reader, normalise) ll = LazyList.init_from_index_callable(index_callable, reader.get_length()) ll.fps = reader.get_meta_data()['fps'] if len(ll) != 0: # TODO: Remove when imageio fixes the ffmpeg importer duration/start # This is a bit grim but the frame->timestamp logic in imageio at # the moment is not very accurate and so we really need to ensure # that the user is returned a list they can actually index into. So # we just remove all the frames that we can't actually index into. # Remove from the front for start in range(len(ll)): if start > 10: # Arbitrary but probably safe warnings.warn('Highly inaccurate frame->timestamp mapping ' 'returned by imageio - many frames are being ' 'dropped and thus importing may be very slow.' ' Please see the documentation.') try: ll[start] break except: pass else: # If we never broke out then ALL frames raised exceptions ll = LazyList([]) # Only take the frames after the initial broken ones ll = ll[start:] if len(ll) != 0: n_frames = len(ll) - 1 for end in range(n_frames, -1, -1): if end < n_frames - 10: # Arbitrary but probably safe warnings.warn('Highly inaccurate frame->timestamp mapping ' 'returned by imageio - many frames are being ' 'dropped and thus importing may be very slow.' ' Please see the documentation.') try: ll[end] break except: pass # Only take the frames before the broken ones ll = ll[:end+1] return ll
def test_lazylist_init_from_iterable_identity(): ll = LazyList.init_from_iterable([0, 1]) assert ll[0] == 0 assert ll[1] == 1
def test_lazylist_init_from_iterable_with_f(): double_func = lambda x: x * 2 ll = LazyList.init_from_iterable([0, 1], f=double_func) assert ll[0] == 0 assert ll[1] == 2
def test_lazylist_slice_with_ndarray(): index = np.array([1, 0, 3], dtype=int) l = LazyList.init_from_iterable(["a", "b", "c", "d", "e"]) l_indexed = l[index] assert list(l_indexed) == ["b", "a", "d"]
def kf_sequence_image_paths_with_landmarks(i, expression): return LazyList.init_from_iterable( sorted([ p.with_suffix('.png') for p in kf_sequence_path(i, expression).glob('*.pts') ]))
def test_lazylist_immutable(): ll = LazyList([]) ll[0] = 1
def test_lazylist_init_from_index_callable(): identity_func = lambda x: x ll = LazyList.init_from_index_callable(identity_func, 5) assert ll[0] == 0 assert ll[-1] == 4
def test_lazylist_multi_map_unequal_lengths(): two_func = lambda: 2 double_func = [lambda x: x * 2] * 2 ll = LazyList([two_func]) ll.map(double_func)
def test_lazylist_immutable(): ll = LazyList([]) with raises(TypeError): ll[0] = 1
def foo_importer(filepath, **kwargs): return LazyList([lambda: Image.init_blank((10, 10))])
def extract_save_features(self, files): r""" Uses the input files as train AAMs and store the resulting pickle on the disk Parameters ---------- files Returns ------- """ # 1. fetch all video frames, attach landmarks frames = mio.import_video(files[0], landmark_resolver=self._myresolver, normalize=True, exact_frame_count=True) # frames = frames.map(AAMFeature._preprocess) idx_above_thresh, idx_lip_opening = landmark_filter( files[0], self._landmarkDir, threshold=self._confidence_thresh, keep=self._kept_frames) frames = frames[idx_above_thresh] frames = frames[idx_lip_opening] frames = frames.map(attach_semantic_landmarks) if self._greyscale is True: frames = frames.map(convert_to_grayscale) # initial AAM training if self._warpType == 'holistic': aam = HolisticAAM(frames, group=self._landmarkGroup, holistic_features=self._features, reference_shape=None, diagonal=self._diagonal, scales=self._scales, max_shape_components=self._max_shape_components, max_appearance_components=self._max_appearance_components, verbose=False) elif self._warpType == 'patch': aam = PatchAAM(frames, group=self._landmarkGroup, holistic_features=self._features, diagonal=self._diagonal, scales=self._scales, max_shape_components=self._max_shape_components, max_appearance_components=self._max_appearance_components, patch_shape=self._extractOpts['patch_shape'], verbose=False) else: raise Exception('Unknown warp type. Did you mean holistic/patch ?') frame_buffer = LazyList.init_from_iterable([]) buffer_len = 256 for idx, file in enumerate(files[1:]): # useful to check progress with open('./run/log_' + self._outModelName + '.txt', 'w') as log: log.write(str(idx) + ' ' + file + '\n') frames = mio.import_video(file, landmark_resolver=self._myresolver, normalize=True, exact_frame_count=True) idx_above_thresh, idx_lip_opening = landmark_filter( file, landmark_dir=self._landmarkDir, threshold=self._confidence_thresh, keep=self._kept_frames) frames = frames[idx_above_thresh] frames = frames[idx_lip_opening] frames = frames.map(attach_semantic_landmarks) if self._greyscale is True: frames = frames.map(convert_to_grayscale) frame_buffer += frames if len(frame_buffer) > buffer_len: # 2. retrain AAM aam.increment(frame_buffer, group=self._landmarkGroup, shape_forgetting_factor=1.0, appearance_forgetting_factor=1.0, verbose=False, batch_size=None) del frame_buffer frame_buffer = LazyList.init_from_iterable([]) else: pass if len(frame_buffer) != 0: # # deplete remaining frames aam.increment(frame_buffer, group=self._landmarkGroup, shape_forgetting_factor=1.0, appearance_forgetting_factor=1.0, verbose=False, batch_size=None) del frame_buffer mio.export_pickle(obj=aam, fp=self._outDir + self._outModelName, overwrite=True, protocol=4)