def _add_branches_recursively( self, layer_config: LayerConfig, layer_id: str, default_input_layer: ResolvedLayerConfig ): branches: Optional[List[dict]] = layer_config.get_list('branches') assert branches branch_layers = [] for branch_index, branch_config in enumerate(branches): branch_layer = self._add_branch_recursively( LayerConfig(branch_config), default_id=f'{layer_id}b{branch_index}', default_input_layer=default_input_layer ) if branch_layer: branch_layers.append(branch_layer) assert branch_layers if len(branch_layers) == 1: return branch_layers[0] resolved_layer_config = ResolvedLayerConfig({ **{key: value for key, value in layer_config.props.items() if key != 'branches'}, 'id': layer_id, 'filter': 'composite' }) resolved_layer_config.input_layers = branch_layers return self._add_resolved_layer(resolved_layer_config)
def test_should_skip_disabled_branch_layers(self): resolved_app_config = ResolvedAppConfig(AppConfig([ LayerConfig({ 'id': 'branches', 'branches': [{ 'layers': [{ 'id': 'in1', 'enabled': True, 'input_path': 'input_path_1' }] }, { 'layers': [{ 'id': 'in2', 'enabled': False, 'input_path': 'input_path_1' }] }] }), LayerConfig({ 'id': 'out', 'output_path': 'output_path_1' }) ])) assert resolved_app_config.layer_by_id['in1'] assert not resolved_app_config.layer_by_id.get('in2') assert resolved_app_config.layer_by_id['out'].input_layer_ids == ['in1']
def get_resolved_layer_type(layer_config: LayerConfig) -> ResolvedLayerType: if layer_config.get('filter'): return ResolvedLayerType.FILTER if layer_config.get('input_path'): return ResolvedLayerType.INPUT_SOURCE if layer_config.get('output_path'): return ResolvedLayerType.OUTPUT_SINK raise ValueError('unable to determine resolved layer type for: %s' % layer_config)
def parse_mp_selfie_segmentation_config(self, layer_config: LayerConfig) -> Config: config = BodyPixFilter.Config( threshold=layer_config.get_float('threshold', 0.1), model_selection=layer_config.get_int('model_selection', 1), cache_model_result_secs=( layer_config.get_float('cache_model_result_secs', 0.0) ) ) LOGGER.info('mp selfie segmentation filter config: %s', config) return config
def parse_fill_config(self, layer_config: LayerConfig) -> Config: color = layer_config.get('color') color_value: Optional[np.ndarray] = get_color_numpy_array(color) value = layer_config.get_int('value') poly_points_list = layer_config.get_list('poly_points') poly_points = (np.asarray(poly_points_list, dtype=np.float32) if poly_points_list else None) config = FillFilter.Config(color=color_value, value=value, poly_points=poly_points) LOGGER.info('fill config: %s', config) assert config.color is not None or config.value is not None return config
def __init__(self, layer_config: LayerConfig, **kwargs): super().__init__(layer_config, **kwargs) self.model_path = (layer_config.get('model_path') or BodyPixModelPaths.MOBILENET_FLOAT_50_STRIDE_16) self._bodypix_model = None self.threshold = float(layer_config.get('threshold') or 0.50) self.internal_resolution = float( layer_config.get('internal_resolution') or 0.50) self.cache_model_result_secs = float( layer_config.get('cache_model_result_secs') or 0.0) self.parts = list(layer_config.get('parts') or []) self._bodypix_result_cache = None self._bodypix_result_cache_time = None
def parse_warp_perspective_config(self, layer_config: LayerConfig) -> Config: config = WarpPerspectiveFilter.Config( target_points=np.asarray(layer_config.get_list( 'target_points', DEFAULT_POINTS), dtype=np.float32), source_points=np.array(layer_config.get_list( 'source_points', DEFAULT_POINTS), dtype=np.float32), add_alpha_channel=self.layer_config.get_bool( 'add_alpha_channel', True)) LOGGER.info('warp perspective config: %s', config) assert config.source_points.shape == (4, 2) assert config.target_points.shape == (4, 2) return config
def _add_branch_recursively( self, layer_config: LayerConfig, default_id: str, default_input_layer: Optional[ResolvedLayerConfig] ): layers: Optional[List[dict]] = layer_config.get_list('layers') assert layers resolved_layers = self._add_layers_recursively( [LayerConfig(props) for props in layers], default_id_prefix=default_id, default_input_layer=default_input_layer ) if not resolved_layers: return None return resolved_layers[-1]
def test_should_fill_area_using_poly_points(self, filter_context: FilterContext): layer_config = LayerConfig.from_json({ 'color': 'red', 'poly_points': [ (0.1, 0.1), (0.6, 0.1), # top left, top right (0.6, 0.4), (0.1, 0.4) # bottom right, bottom left ] }) image_filter = FillFilter(layer_config=layer_config, filter_context=filter_context) source_image = np.zeros((10, 10, 3), dtype=np.float32) result_image = image_filter.filter(source_image) LOGGER.debug('result_image:\n%s', result_image) mask = np.zeros(source_image.shape) mask[1:5, 1:7] = 1 masked_result_image: np.ndarray = ma.masked_array(result_image, mask) poly_area = result_image[1:5, 1:7] LOGGER.debug('poly_area:\n%s', poly_area) assert result_image.shape == source_image.shape assert np.all(poly_area == (255, 0, 0)) LOGGER.debug('mask:\n%s', mask) LOGGER.debug('masked_result_image:\n%s', masked_result_image) assert np.all(masked_result_image == (0, 0, 0))
def test_should_not_apply_empty_override_map(self): app_config = AppConfig( layers=[LayerConfig({ 'id': 'id1', 'prop': 'value1' })]) apply_config_override_map(app_config, {}) assert app_config.layers[0].get('prop') == 'value1'
def test_should_override_prop_of_root_layer(self): app_config = AppConfig( layers=[LayerConfig({ 'id': 'id1', 'prop': 'value1' })]) apply_config_override_map(app_config, {'id1': {'prop': 'new-value'}}) assert app_config.layers[0].get('prop') == 'new-value'
def test_should_fill_whole_image(self, filter_context: FilterContext): layer_config = LayerConfig.from_json({'color': 'red'}) image_filter = FillFilter(layer_config=layer_config, filter_context=filter_context) source_image = np.zeros((5, 4, 3), dtype=np.float32) result_image = image_filter.filter(source_image) LOGGER.debug('result_image:\n%s', result_image) assert result_image.shape == source_image.shape assert np.all(result_image == (255, 0, 0))
def test_should_connect_input_to_output_layer(self): resolved_app_config = ResolvedAppConfig(AppConfig([ LayerConfig({ 'id': 'in', 'input_path': 'input_path_1' }), LayerConfig({ 'id': 'out', 'output_path': 'output_path_1' }) ])) assert resolved_app_config.layer_by_id['in'].get('input_path') == ( 'input_path_1' ) assert resolved_app_config.layer_by_id['out'].get('output_path') == ( 'output_path_1' ) assert resolved_app_config.layer_by_id['out'].input_layer_ids == ['in']
def _add_layer_recursively( self, layer_config: LayerConfig, default_id: str, default_input_layer: Optional[ResolvedLayerConfig] ) -> ResolvedLayerConfig: layer_id = layer_config.get('id') or default_id branches = layer_config.get('branches') if branches: return self._add_branches_recursively( layer_config, layer_id=layer_id, default_input_layer=default_input_layer ) resolved_layer_config = ResolvedLayerConfig({ **layer_config.props, 'id': layer_id }, default_input_layer=default_input_layer) return self._add_resolved_layer(resolved_layer_config)
def test_should_raise_exception_if_id_was_not_found(self): app_config = AppConfig( layers=[LayerConfig({ 'id': 'id1', 'prop': 'value1' })]) with pytest.raises(ValueError): apply_config_override_map(app_config, {'other-id': { 'prop': 'new-value' }})
def test_should_connect_input_to_branch_layers(self): resolved_app_config = ResolvedAppConfig(AppConfig([ LayerConfig({ 'id': 'in', 'input_path': 'input_path_1' }), LayerConfig({ 'id': 'branches', 'branches': [{ 'layers': [{ 'id': 'branch_1_layer_1', 'filter': 'dummy' }] }, { 'layers': [{ 'id': 'branch_2_layer_1', 'filter': 'dummy' }] }] }), LayerConfig({ 'id': 'out', 'output_path': 'output_path_1' }) ])) assert resolved_app_config.layer_by_id['in'].get('input_path') == ( 'input_path_1' ) assert resolved_app_config.layer_by_id['out'].get('output_path') == ( 'output_path_1' ) assert resolved_app_config.layer_by_id['branch_1_layer_1'].input_layer_ids == ['in'] assert resolved_app_config.layer_by_id['branch_2_layer_1'].input_layer_ids == ['in'] assert resolved_app_config.layer_by_id['branches'].input_layer_ids == [ 'branch_1_layer_1', 'branch_2_layer_1' ] assert resolved_app_config.layer_by_id['out'].input_layer_ids == ['branches']
def test_should_override_prop_of_nested_layer(self): app_config = AppConfig(layers=[ LayerConfig({ 'id': 'id1', 'branches': [{ 'layers': [{ 'id': 'nested', 'prop': 'value1' }] }] }) ]) apply_config_override_map(app_config, {'nested': { 'prop': 'new-value' }}) assert app_config.layers[0].get( 'branches')[0]['layers'][0]['prop'] == 'new-value'