Example #1
0
    def test_constructor(self):
        # Parameters
        color_engine_interface = {
            'name': 'Name(Main, Secondary)',
            'type': 'categorical',
            'schema': {
                'ship': Color(255, 255, 255, ctype='sRGB255'),
                'car': Color(255, 128, 128, ctype='sRGB255')
            }
        }
        scale = 1
        axis = 0
        mosaic_size = (500, 500)
        background_color = (0, 0, 0)
        item_margins = (10, 10)
        main_axis_align = 'start'
        minor_axis_align = 'start'

        LegendPainter(color_engine_interface=color_engine_interface,
                      scale=scale,
                      axis=axis,
                      mosaic_size=mosaic_size,
                      background_color=background_color,
                      item_margins=item_margins,
                      main_axis_align=main_axis_align,
                      minor_axis_align=minor_axis_align)
Example #2
0
    def test_linear(self, ctype):
        color = Color(50, 100, 50, ctype='JCh')
        cm = LightnessColorMap(color, lightness_range=(0, 0), ctype=ctype)
        array = np.linspace(0, 1, 10)
        assert all(color == Color(50, 100, 50, ctype='JCh').astype(ctype)
                   for color in cm(array, keep_colors=True))

        cm = LightnessColorMap(color, ctype=ctype)
        self._base_color_map_test(cm, color=color, ctype=ctype)
        array = np.linspace(0, 1, 10)
        local_deriv = np.diff(np.linspace(0, 1, 10 - 1))[0] * np.diff(
            cm(array, keep_colors=True))
        local_deriv = np.diff(np.linspace(0, 1,
                                          10 - 2))[0] * np.diff(local_deriv)
        assert np.allclose(local_deriv.astype(np.float64), 0)

        cm = LightnessColorMap(color, chroma_range=(0.1, 0.1), ctype=ctype)
        self._base_color_map_test(cm,
                                  color=color,
                                  chroma_range=(0.1, 0.1),
                                  ctype=ctype)
        array = np.linspace(0, 1, 10)
        local_deriv = np.diff(np.linspace(0, 1, 10 - 1))[0] * np.diff(
            cm(array, keep_colors=True))
        local_deriv = np.diff(np.linspace(0, 1,
                                          10 - 2))[0] * np.diff(local_deriv)
        assert np.allclose(local_deriv.astype(np.float64), 0)
Example #3
0
    def test_add_title(self):
        import PIL.Image
        import numpy as np

        # Create data points
        records = [
            Record(
                [[[100, 100], [100, 150], [150, 150], [150, 100], [100, 100]]],
                ['car'],
                confidence=0.9),
        ]
        records_collection = RecordCollection(*records)
        annotation = Annotation(records_collection)
        tile = TileWrapper(np.zeros((100, 100, 3)), filename='test.png')
        data_point = DataPoint(tile, annotation)
        data_points = [data_point]

        # Color engine interface
        simple_categorical_interface = {
            'name': 'Name(Main, Secondary)',
            'type': 'categorical',
            'schema': {
                'Ship': Color(26, 188, 156, ctype='sRGB255'),
                'Car': Color(241, 196, 15, ctype='sRGB255'),
                'Truck': Color(41, 128, 185, ctype='sRGB255'),
                'Wind-turbines': Color(236, 240, 241, ctype='sRGB255')
            }
        }

        # Parameters
        width, height = (300, 300)
        background_color = (0, 0, 0)
        title_size = 25

        # Init compositor
        _compositor = Compositor(
            data_points=data_points,
            color_engine_interface=simple_categorical_interface)

        image = PIL.Image.fromarray(np.zeros((width, height)))

        # Add title
        final_image = _compositor._add_title(mosaic=image,
                                             title='',
                                             background_color=background_color,
                                             title_size=title_size)

        assert isinstance(final_image, PIL.Image.Image)
        assert final_image.width == width
        assert final_image.height == height + 2 * title_size
Example #4
0
    def test_draw_simple_category(self):
        # Parameters
        name = 'Test'
        fill_color = Color(255, 255, 255, ctype='sRGB255')
        margins = (15, 15)

        drawer = LegendItemDrawer((0, 0, 0), scale=1, margins=margins)
        item_1 = drawer.draw_simple_category(name=name, fill_color=fill_color)

        assert isinstance(item_1, PIL.Image.Image)
        assert item_1.width > 0
        assert item_1.height > 0

        # Change scale (> 1)
        drawer = LegendItemDrawer((0, 0, 0), scale=2, margins=margins)
        item_2 = drawer.draw_simple_category(name=name, fill_color=fill_color)

        assert isinstance(item_2, PIL.Image.Image)
        assert item_2.width > item_1.width
        assert item_2.height > item_1.height

        # Change scale (< 1)
        drawer = LegendItemDrawer((0, 0, 0), scale=0.5, margins=margins)
        item_3 = drawer.draw_simple_category(name=name, fill_color=fill_color)

        assert isinstance(item_3, PIL.Image.Image)
        assert item_1.width > item_3.width
        assert item_1.height > item_3.height
Example #5
0
    def test_draw_composite_category(self):
        # Parameters
        category_name = 'Test'
        color_engine_interface = {
            'ship': Color(255, 255, 255, ctype='sRGB255'),
            'car': Color(255, 128, 128, ctype='sRGB255')
        }
        max_category_height = 500
        margins = (10, 10)

        drawer = LegendItemDrawer((0, 0, 0), scale=1, margins=margins)
        item_1 = drawer.draw_composite_category(
            descriptor_name='Name',
            category_name=category_name,
            color_engine_interface=color_engine_interface,
            max_category_height=max_category_height)

        assert isinstance(item_1, PIL.Image.Image)
        assert item_1.width > 0
        assert item_1.height > 0

        # Change scale (> 1)
        drawer = LegendItemDrawer((0, 0, 0), scale=2, margins=margins)
        item_2 = drawer.draw_composite_category(
            descriptor_name='Name',
            category_name=category_name,
            color_engine_interface=color_engine_interface,
            max_category_height=max_category_height)

        assert isinstance(item_2, PIL.Image.Image)
        assert item_2.width > item_1.width
        assert item_2.height > item_1.height

        # Change scale (< 1)
        drawer = LegendItemDrawer((0, 0, 0), scale=0.5, margins=margins)
        item_3 = drawer.draw_composite_category(
            descriptor_name='Name',
            category_name=category_name,
            color_engine_interface=color_engine_interface,
            max_category_height=max_category_height)

        assert isinstance(item_3, PIL.Image.Image)
        assert item_1.width > item_3.width
        assert item_1.height > item_3.height
Example #6
0
    def test_key_point_cm(self, ctype):
        cm = KeyPointsColorMap(
            {
                1: 2 * Color(0, 255, 0),
                0: 2 * Color(0, 0, 255),
                2: 2 * Color(255, 0, 0)
            },
            ctype=ctype)
        self._base_color_map_test(cm,
                                  mapping={
                                      1: 2 * Color(0, 255, 0),
                                      0: 2 * Color(0, 0, 255),
                                      2: 2 * Color(255, 0, 0)
                                  },
                                  ctype=ctype)

        assert cm.get_color(0.5) == Color(0, 255, 255).astype(ctype)
        assert cm.get_color(1.5) == Color(255, 255, 0).astype(ctype)
Example #7
0
    def test_semi_circular(self, ctype):
        cm = SemiCircularColorMap(0, 3, 0.1, ctype=ctype)
        array = np.linspace(0, 1, 10)
        assert all(
            np.allclose(color._components,
                        Color(40, 0, 0, ctype='JCh')._components)
            for color in cm(array, keep_colors=True))

        cm = SemiCircularColorMap(0.3, 3, 0.1, ctype=ctype)
        self._base_color_map_test(cm,
                                  ray=0.3,
                                  period=3,
                                  intensity=0.1,
                                  ctype=ctype)

        # # Check periodicity
        for value in array:
            assert cm.get_color(value) == cm.get_color(value + 3.0)
Example #8
0
    def _make_color_maps(self):
        if self._main_interface['type'] == 'categorical':
            self._primary_color_map = CategoricalColorMap(len(self._main_interface['schema'].keys()) or 1,
                                                          ctype=self.ctype)

            _schema = self._main_interface['schema']

            if self._secondary_descriptor is not None:
                self._secondary_color_map = {
                    value: self._make_secondary_color_map(self._primary_color_map.get_color(_schema[key]), str(value))
                    for key, value in _schema.items()
                }

        if self._main_interface['type'] == 'continuous':
            self._primary_color_map = LightnessColorMap(Color(50, 78, 50, ctype='JCh'),
                                                        lightness_range=(0.8, 0.9),
                                                        chroma_range=(-0.3, -0.1),
                                                        data_range=self._main_interface['schema'],
                                                        ctype=self.ctype).discretize()
Example #9
0
    def test_circular(self, ctype):
        cm = CircularColorMap(0, ctype=ctype)
        array = np.linspace(0, 1, 10)
        assert all(
            np.allclose(color._components,
                        Color(50, 0, 0, ctype='JCh')._components)
            for color in cm(array, keep_colors=True))

        cm = CircularColorMap(0.3, ctype=ctype)
        self._base_color_map_test(cm, ray=0.3, ctype=ctype)

        # Check periodicity
        for value in array:
            assert cm.get_color(value) == cm.get_color(value + 1.0)

        array = np.linspace(0, 1, 10)
        local_deriv = np.diff(np.linspace(0, 1, 10 - 1))[0] * np.diff(
            cm(array, keep_colors=True))
        local_deriv = np.diff(np.linspace(0, 1,
                                          10 - 2))[0] * np.diff(local_deriv)
        assert np.allclose(local_deriv.astype(np.float64), 0)
Example #10
0
    def test_draw_colormap(self):
        # Parameters
        descriptor_name = 'Test'
        color_map = LightnessColorMap(Color(50, 78, 50, ctype='JCh'),
                                      lightness_range=(0.8, 0.8),
                                      chroma_range=(-0.3, -0.1),
                                      ctype="sRGB1").discretize(256)
        margins = (15, 15)

        drawer = LegendItemDrawer((0, 0, 0), scale=1, margins=margins)
        item_1 = drawer.draw_colormap(descriptor_name='Name',
                                      color_map=color_map,
                                      category_name=descriptor_name)

        assert isinstance(item_1, PIL.Image.Image)
        assert item_1.width > 0
        assert item_1.height > 0

        # Change scale (> 1)
        drawer = LegendItemDrawer((0, 0, 0), scale=2, margins=margins)
        item_2 = drawer.draw_colormap(descriptor_name='Name',
                                      color_map=color_map,
                                      category_name=descriptor_name)

        assert isinstance(item_2, PIL.Image.Image)
        assert item_2.width > item_1.width
        assert item_2.height > item_1.height

        # Change scale (< 1)
        drawer = LegendItemDrawer((0, 0, 0), scale=0.5, margins=margins)
        item_3 = drawer.draw_colormap(descriptor_name='Name',
                                      color_map=color_map,
                                      category_name=descriptor_name)

        assert isinstance(item_3, PIL.Image.Image)
        assert item_1.width > item_3.width
        assert item_1.height > item_3.height
Example #11
0
    def test_constructor(self):
        # Create data points
        records = [
            Record(
                [[[100, 100], [100, 150], [150, 150], [150, 100], [100, 100]]],
                ['car'],
                confidence=0.9),
        ]
        records_collection = RecordCollection(*records)
        annotation = Annotation(records_collection)
        tile = TileWrapper(np.zeros((100, 100, 3)), filename='test.png')
        tile_2 = TileWrapper(np.zeros((200, 200, 3)), filename='test_2.png')
        data_point = DataPoint(tile, annotation)
        data_point_2 = DataPoint(tile_2, annotation)

        # Color engine interface
        simple_categorical_interface = {
            'name': 'Name(Main, Secondary)',
            'type': 'categorical',
            'schema': {
                'Ship': Color(26, 188, 156, ctype='sRGB255'),
                'Car': Color(241, 196, 15, ctype='sRGB255'),
                'Truck': Color(41, 128, 185, ctype='sRGB255'),
                'Wind-turbines': Color(236, 240, 241, ctype='sRGB255')
            }
        }

        # Valid datapoints
        data_points_1 = [data_point]
        data_points_2 = [data_point, data_point_2]
        data_points_3 = (data_point_2, )
        data_points_4 = (data_point, data_point_2)
        data_points_5 = [data_points_1]
        data_points_6 = [data_points_3]
        data_points_7 = (data_points_2, )
        data_points_8 = (data_points_4, )

        # Invalid data points
        inv_data_points_1 = None
        inv_data_points_2 = ['test']
        inv_data_points_3 = ('test', data_point)

        # Checks
        Compositor(data_points=data_points_1,
                   color_engine_interface=simple_categorical_interface)
        Compositor(data_points=data_points_2,
                   color_engine_interface=simple_categorical_interface)
        Compositor(data_points=data_points_3,
                   color_engine_interface=simple_categorical_interface)
        Compositor(data_points=data_points_4,
                   color_engine_interface=simple_categorical_interface)
        Compositor(data_points=data_points_5,
                   color_engine_interface=simple_categorical_interface)
        Compositor(data_points=data_points_6,
                   color_engine_interface=simple_categorical_interface)
        Compositor(data_points=data_points_7,
                   color_engine_interface=simple_categorical_interface)
        Compositor(data_points=data_points_8,
                   color_engine_interface=simple_categorical_interface)

        with pytest.raises(AttributeError):
            Compositor(data_points=inv_data_points_1,
                       color_engine_interface=simple_categorical_interface)

        with pytest.raises(AttributeError):
            Compositor(data_points=inv_data_points_2,
                       color_engine_interface=simple_categorical_interface)

        with pytest.raises(AttributeError):
            Compositor(data_points=inv_data_points_3,
                       color_engine_interface=simple_categorical_interface)
class TestSchema:
    _valid_names = [
        'valid_name', '__valid_name__', 'valid__name', 'Valid_name'
    ]
    _invalid_names = ['invalid-name', 'invalid_name0']

    _valid_properties = ['valid_property', 'valid_property', 'valid__property']
    _invalid_properties = [
        'Invalid_property', 'invalid-property', 'invalid_property0',
        '_invalid_property', 'invalid_property_'
    ]

    _valid_type = ['categorical', 'continuous']
    _invalid_type = ['other']

    _valid_category = [
        {
            'category': 0
        },
        {
            'category': 0.0
        },
        {
            'category': Color(0, 0, 0)
        },
        {
            'category': CategoricalColorMap(10)
        },
        {
            'category': {
                'category': 0
            },
        },
        {
            'category': {
                'category': 0.0
            },
        },
        {
            'category': {
                'category': Color(0, 0, 0)
            },
        },
        {
            'category': {
                'category': CategoricalColorMap(10)
            },
        },
    ]
    _valid_continuous = [CategoricalColorMap(10), (0, 1)]

    _invalid_category = \
        [
            {
                'category': '0'
            },
            {
                'category': (0, )
            },
            {
                'category': Color(0, 0, 0).components
            },
            {
                'category': CategoricalColorMap(10).map_fn
            },
            {
                'category': {
                    'category': '0'
                },
            },
            {
                'category': {
                    'category': (0, )
                },
            },
            {
                'category': {
                    'category': Color(0, 0, 0).components
                },
            },
            {
                'category': {
                    'category': CategoricalColorMap(10).map_fn
                },
            },
        ] + _valid_continuous

    _invalid_continuous = [
        CategoricalColorMap(10).map_fn, [0, 1], '0, 1', 0, 0.0
    ] + _valid_category

    @staticmethod
    def _make_test(names, types, properties, schemas):
        for name in names:
            for type_ in types:
                for property_ in properties:
                    for schema in schemas:
                        with pytest.raises(SchemaError):
                            dictionary = {
                                'name': name,
                                'type': type_,
                                'property': property_,
                                'schema': schema
                            }
                            print(dictionary)
                            Descriptor.__interface_schema__.validate(
                                dictionary)

                        class DummyDescriptor(Descriptor):
                            def update(self, *record_collections):
                                pass

                            def compute(self, *record_collections):
                                pass

                            def reset(self):
                                pass

                            def _make_interface(self):
                                return dictionary

                            @property
                            def property_name(self):
                                return property_

                        with pytest.raises(ValueError):
                            descriptor = DummyDescriptor(name)
                            print(descriptor.__descriptor__)

    def test_schema(self):
        # Name
        self._make_test(self._invalid_names, ['categorical'],
                        self._valid_properties, self._valid_category)
        self._make_test(self._invalid_names, ['continuous'],
                        self._valid_properties, self._valid_continuous)

        # Type
        self._make_test(self._valid_names, self._invalid_type,
                        self._valid_properties, self._valid_category)
        self._make_test(self._valid_names, self._invalid_type,
                        self._valid_properties, self._valid_continuous)

        # Property
        self._make_test(self._valid_names, ['categorical'],
                        self._invalid_properties, self._valid_category)
        self._make_test(self._valid_names, ['continuous'],
                        self._invalid_properties, self._valid_continuous)

        # Schema
        self._make_test(self._valid_names, ['categorical'],
                        self._valid_properties, self._invalid_category)
        self._make_test(self._valid_names, ['continuous'],
                        self._valid_properties, self._invalid_continuous)

        # Dependency
        self._make_test(self._valid_names, ['continuous'],
                        self._valid_properties, self._valid_category)
        self._make_test(self._valid_names, ['categorical'],
                        self._valid_properties, self._valid_continuous)
Example #13
0
    def test_plot(self):
        import PIL.Image
        import numpy as np

        # Create data points
        records = [
            Record(
                [[[100, 100], [100, 150], [150, 150], [150, 100], [100, 100]]],
                ['car'],
                confidence=0.9,
                confidence_confidence=0.9,
                color=Color(26, 188, 156)),
        ]
        records_collection = RecordCollection(*records)
        annotation = Annotation(records_collection)
        tile = TileWrapper(np.zeros((100, 100, 3), dtype=np.uint8),
                           filename='test.png')
        data_point = DataPoint(tile, annotation)
        data_points = []

        # Legend
        simple_categorical_interface = {
            'name': 'Name(Main, Secondary)',
            'type': 'categorical',
            'schema': {
                'Ship': Color(26, 188, 156, ctype='sRGB255'),
                'Car': Color(241, 196, 15, ctype='sRGB255'),
                'Truck': Color(41, 128, 185, ctype='sRGB255'),
                'Wind-turbines': Color(236, 240, 241, ctype='sRGB255')
            }
        }

        kwargs = {
            'plot_centers': False,
            'plot_confidences': True,
            'zoom': 1,
            'alpha': 128,
            'scale': 1,
            'axis': 0,
            'background_color': (48, 56, 68, 255),
            'item_margins': (10, 10),
            'main_axis_align': 'start',
            'minor_axis_align': 'start'
        }

        # Accumulates datapoints (flattened)
        nb_datapoints = 15
        for _ in range(nb_datapoints):
            data_points.append(data_point)

        # Parameters
        _compositor = Compositor(
            data_points=data_points,
            color_engine_interface=simple_categorical_interface)
        n_cols = 10
        margins = (5, 5)

        # Test with neither title nor legend (use AdaptiveImagePositionGenerator)
        final_image = _compositor.plot(n_cols=n_cols,
                                       margins=margins,
                                       title=None,
                                       center=True,
                                       **kwargs)

        assert isinstance(final_image, PIL.Image.Image)
        assert final_image.width > n_cols * (100 + 2 * margins[0])
        assert final_image.height > 2 * (100 + 2 * margins[1])  # 2 rows
        assert final_image.height < 3 * (100 + 2 * margins[1]
                                         )  # but less than 3 rows

        # Test with neither title nor legend (use SimpleImagePositionGenerator)
        final_image = _compositor.plot(n_cols=n_cols,
                                       margins=margins,
                                       title=None,
                                       center=False,
                                       **kwargs)

        assert isinstance(final_image, PIL.Image.Image)
        assert final_image.width > n_cols * (100 + 2 * margins[0])
        assert final_image.height > 2 * (100 + 2 * margins[1])  # 2 rows
        assert final_image.height < 3 * (100 + 2 * margins[1]
                                         )  # but less than 3 rows

        # Nested datapoints
        nested_data_points = [[data_point, data_point, data_point, data_point],
                              [data_point, data_point, data_point],
                              [data_point, data_point, data_point, data_point],
                              [
                                  data_point, data_point, data_point,
                                  data_point, data_point
                              ], [data_point, data_point]]

        _compositor = Compositor(
            data_points=nested_data_points,
            color_engine_interface=simple_categorical_interface)

        final_image = _compositor.plot(n_cols=n_cols,
                                       margins=margins,
                                       title=None,
                                       center=True,
                                       **kwargs)

        # Check 5 cols and 5 rows (plus each tile title)
        painter_title_height = 70
        assert isinstance(final_image, PIL.Image.Image)
        assert final_image.width > 5 * (100 + 2 * margins[0])
        assert final_image.height > 5 * (100 + 2 * margins[1])
        assert final_image.height < 5 * (100 + painter_title_height +
                                         2 * margins[1])

        # Add title
        final_image_with_title = _compositor.plot(n_cols=n_cols,
                                                  margins=margins,
                                                  title='Test',
                                                  center=True,
                                                  **kwargs)

        assert isinstance(final_image, PIL.Image.Image)
        assert final_image_with_title.width == final_image.width
        assert final_image_with_title.height > final_image.height

        # Add legend and title
        final_image_with_legend = _compositor.plot(n_cols=n_cols,
                                                   margins=margins,
                                                   title='Test',
                                                   center=True,
                                                   **kwargs)

        assert isinstance(final_image, PIL.Image.Image)
        assert final_image_with_legend.width == final_image_with_title.width
        assert final_image_with_legend.height == final_image_with_title.height
Example #14
0
    def test_draw_items(self):
        # Parameters
        scale = 1
        axis = 0
        mosaic_size = (500, 500)
        background_color = (0, 0, 0)
        item_margins = (10, 10)
        main_axis_align = 'start'
        minor_axis_align = 'start'

        # Test invalid mapping schema
        invalid_color_engine_interface = {
            'name': 'Name(Main, Secondary)',
            'type': 'categorical',
            'schema': {
                'ship': 'Hello'
            }
        }

        painter = LegendPainter(
            color_engine_interface=invalid_color_engine_interface,
            scale=scale,
            axis=axis,
            mosaic_size=mosaic_size,
            background_color=background_color,
            item_margins=item_margins,
            main_axis_align=main_axis_align,
            minor_axis_align=minor_axis_align)

        drawer = LegendItemDrawer(background_color=background_color,
                                  scale=scale,
                                  margins=item_margins)

        # Draw items
        items = painter._draw_items(drawer)

        # Checks
        assert isinstance(items, list)
        assert len(items) == 0

        # Single descriptor - categorical
        simple_categorical_interface = {
            'name': 'Name(Main, Secondary)',
            'type': 'categorical',
            'schema': {
                'Ship': Color(26, 188, 156, ctype='sRGB255'),
                'Car': Color(241, 196, 15, ctype='sRGB255'),
                'Truck': Color(41, 128, 185, ctype='sRGB255'),
                'Wind-turbines': Color(236, 240, 241, ctype='sRGB255')
            }
        }
        painter = LegendPainter(
            color_engine_interface=simple_categorical_interface,
            scale=scale,
            axis=axis,
            mosaic_size=mosaic_size,
            background_color=background_color,
            item_margins=item_margins,
            main_axis_align=main_axis_align,
            minor_axis_align=minor_axis_align)

        drawer = LegendItemDrawer(background_color=background_color,
                                  scale=scale,
                                  margins=item_margins)

        # Draw items
        items = painter._draw_items(drawer)

        # Checks
        assert isinstance(items, list)
        assert len(items) == 4
        for item in items:
            assert isinstance(item, PIL.Image.Image)

        # Single descriptor - continuous - color map
        simple_continuous_interface_cm = {
            'name':
            'Name(Main, Secondary)',
            'type':
            'continuous',
            'schema':
            LightnessColorMap(Color(50, 78, 50, ctype='JCh'),
                              lightness_range=(0.8, 0.8),
                              chroma_range=(-0.3, -0.1),
                              ctype="sRGB1").discretize(256)
        }
        painter = LegendPainter(
            color_engine_interface=simple_continuous_interface_cm,
            scale=scale,
            axis=axis,
            mosaic_size=mosaic_size,
            background_color=background_color,
            item_margins=item_margins,
            main_axis_align=main_axis_align,
            minor_axis_align=minor_axis_align)

        drawer = LegendItemDrawer(background_color=background_color,
                                  scale=scale,
                                  margins=item_margins)

        # Draw items
        items = painter._draw_items(drawer)

        # Checks
        assert isinstance(items, list)
        assert len(items) == 1
        for item in items:
            assert isinstance(item, PIL.Image.Image)

        # Two descriptors - both categorical
        double_categorical_interface = {
            'name': 'Name(Main, Secondary)',
            'type': 'categorical',
            'schema': {
                'Ship size': {
                    'Small (< 26m)': Color(26, 188, 156, ctype='sRGB255'),
                    'Medium': Color(241, 196, 15, ctype='sRGB255'),
                    'Large (< 100m)': Color(41, 128, 185, ctype='sRGB255')
                },
                'Confidence': {
                    'Little (< 0.5)': Color(26, 188, 156, ctype='sRGB255'),
                    'Strong (>= 0.5)': Color(241, 196, 15, ctype='sRGB255')
                }
            }
        }
        painter = LegendPainter(
            color_engine_interface=double_categorical_interface,
            scale=scale,
            axis=axis,
            mosaic_size=mosaic_size,
            background_color=background_color,
            item_margins=item_margins,
            main_axis_align=main_axis_align,
            minor_axis_align=minor_axis_align)

        drawer = LegendItemDrawer(background_color=background_color,
                                  scale=scale,
                                  margins=item_margins)

        # Draw items
        items = painter._draw_items(drawer)

        # Checks
        assert isinstance(items, list)
        assert len(items) == 2
        for item in items:
            assert isinstance(item, PIL.Image.Image)

        # One descriptor - categorical / color map
        double_categorical_interface_cm = {
            'name': 'Name(Main, Secondary)',
            'type': 'categorical',
            'schema': {
                'Confidence':
                LightnessColorMap(Color(50, 78, 50, ctype='JCh'),
                                  lightness_range=(0.8, 0.8),
                                  chroma_range=(-0.3, -0.1),
                                  ctype="sRGB1").discretize(256),
                'Size':
                LightnessColorMap(Color(50, 78, 270, ctype='JCh'),
                                  lightness_range=(0.8, 0.8),
                                  chroma_range=(-0.3, -0.1),
                                  ctype="sRGB1").discretize(256)
            }
        }

        painter = LegendPainter(
            color_engine_interface=double_categorical_interface_cm,
            scale=scale,
            axis=axis,
            mosaic_size=mosaic_size,
            background_color=background_color,
            item_margins=item_margins,
            main_axis_align=main_axis_align,
            minor_axis_align=minor_axis_align)

        drawer = LegendItemDrawer(background_color=background_color,
                                  scale=scale,
                                  margins=item_margins)

        # Draw items
        items = painter._draw_items(drawer)

        # Checks
        assert isinstance(items, list)
        assert len(items) == 2
        for item in items:
            assert isinstance(item, PIL.Image.Image)
Example #15
0
    def test_add_legend(self):
        import PIL.Image
        import numpy as np

        # Create data points
        records = [
            Record(
                [[[100, 100], [100, 150], [150, 150], [150, 100], [100, 100]]],
                ['car'],
                confidence=0.9),
        ]
        records_collection = RecordCollection(*records)
        annotation = Annotation(records_collection)
        tile = TileWrapper(np.zeros((100, 100, 3)), filename='test.png')
        data_point = DataPoint(tile, annotation)
        data_points = [data_point]

        # Legend
        simple_categorical_interface = {
            'name': 'Name(Main, Secondary)',
            'type': 'categorical',
            'schema': {
                'Ship': Color(26, 188, 156, ctype='sRGB255'),
                'Car': Color(241, 196, 15, ctype='sRGB255'),
                'Truck': Color(41, 128, 185, ctype='sRGB255'),
                'Wind-turbines': Color(236, 240, 241, ctype='sRGB255')
            }
        }

        legend_config = {
            'scale': 1,
            'axis': 0,
            'item_margins': (10, 10),
            'main_axis_align': 'start',
            'minor_axis_align': 'start'
        }

        # Parameters
        width, height = (300, 300)
        background_color = (0, 0, 0)

        # Init compositor
        _compositor = Compositor(
            data_points=data_points,
            color_engine_interface=simple_categorical_interface)

        image = PIL.Image.fromarray(np.zeros((width, height)))

        # Add legend
        final_image = _compositor._add_legend(
            mosaic=image, background_color=background_color, **legend_config)

        # Checks (vertical mode)
        assert isinstance(final_image, PIL.Image.Image)
        assert final_image.height == height
        assert final_image.width > width

        # Checks horizontal mode
        legend_config['axis'] = 1
        final_image = _compositor._add_legend(
            mosaic=image, background_color=background_color, **legend_config)

        assert isinstance(final_image, PIL.Image.Image)
        assert final_image.width == width
        assert final_image.height > height
Example #16
0
 def __init__(self, type, coordinates):
     self.id = '1'
     self.type = type
     self.coordinates = coordinates
     self.labels = Label('test'),
     self.color = Color(255, 128, 128, ctype='sRGB255')
Example #17
0
    def test_draw(self):
        # Fake records
        invalid_records = [
            Record(
                [[[100, 100], [100, 150], [150, 150], [150, 100], [100, 100]]],
                ('car', ),
                confidence=0.9),
            Record([[[100, 100], [110, 110], [100, 100]]], ('car', ),
                   confidence=0.9),
        ]
        records = [
            Record(
                [[[100, 100], [100, 150], [150, 150], [150, 100], [100, 100]]],
                ('car', ),
                confidence=0.9,
                color=Color(255, 128, 128)),
            Record([[[100, 100], [100, 150], [100, 100]]], ('car', ),
                   confidence=0.9,
                   color=Color(128, 255, 255)),
            Record([100, 100], ('ship', ),
                   confidence=0.3,
                   color=Color(128, 255, 255)),
        ]

        # Create collection
        invalid_records_collection = RecordCollection(*invalid_records)
        records_collection = RecordCollection(*records)

        # Finally, the annotation
        invalid_annotation = Annotation(invalid_records_collection)
        annotation = Annotation(records_collection)

        # Instantiate a tile
        tile = TileWrapper(np.zeros((300, 300, 4), dtype=np.uint8),
                           filename='test.png')

        # Create a datapoint
        invalid_datapoint = DataPoint(tile, invalid_annotation)
        datapoint = DataPoint(tile, annotation)

        # Parameters
        _painter = Painter(fill=True)

        # Sanity check
        with pytest.raises(AttributeError):
            _painter.draw(invalid_datapoint)

        # Draw datapoint
        final_image = _painter.draw(datapoint)

        assert isinstance(final_image, PIL.Image.Image)
        assert final_image.width == 300
        assert final_image.height == 300 + _painter.TITLE_HEIGHT

        # With centers
        _painter = Painter(plot_centers=True)

        # Sanity check
        with pytest.raises(AttributeError):
            _painter.draw(invalid_datapoint)

        # Draw datapoint
        final_image = _painter.draw(datapoint)

        assert isinstance(final_image, PIL.Image.Image)
        assert final_image.width == 300
        assert final_image.height == 300 + _painter.TITLE_HEIGHT

        # Test zoom
        zoom = 2.5
        _painter = Painter(zoom=zoom)

        final_image = _painter.draw(datapoint)

        assert isinstance(final_image, PIL.Image.Image)
        assert final_image.width == 300 * zoom
        assert final_image.height == (300 + _painter.TITLE_HEIGHT) * zoom

        # Check invalid geometry
        class InvalidRecord(object):
            def __init__(self, type, coordinates):
                self.id = '1'
                self.type = type
                self.coordinates = coordinates
                self.labels = Label('test'),
                self.color = Color(255, 128, 128, ctype='sRGB255')

        records = [
            Record(
                [[[100, 100], [100, 150], [150, 150], [150, 100], [100, 100]]],
                ('car', ),
                confidence=0.9,
                color=Color(255, 128, 128)),
            Record([[[100, 100], [100, 150], [100, 100]]], ('car', ),
                   confidence=0.9,
                   color=Color(128, 255, 255)),
            InvalidRecord(type='Test', coordinates=[])
        ]

        # Create data point
        records_collection = RecordCollection(*records)
        annotation = Annotation(records_collection)
        tile = TileWrapper(np.zeros((300, 300, 4), dtype=np.uint8),
                           filename='test.png')
        data_point = DataPoint(tile, annotation)

        _painter = Painter(fill=True)

        with pytest.raises(ValueError):
            _painter.draw(data_point)
Example #18
0
    def draw(self):
        """Draw the legend, along the given axis.

        The generated legend is a grid with each cell having the dimensions of the biggest item to draw.
        The grid is then filled along the main axis first. The size of the legend along the
        main axis is fixed while the size along the minor one is variable.

        Returns:
            :class:`~PIL.Image.Image`: The output legend.

        """
        # Init legend item drawer
        drawer = LegendItemDrawer(background_color=self._background_color,
                                  scale=self._scale,
                                  margins=self._item_margins)

        margin = int(drawer.TEXT_SIZE * self._scale)
        # Draw all items
        items = self._draw_items(drawer)

        # No items to draw means empty legend
        if not items:
            return PIL.Image.new(mode='RGBA', size=(0, 0))

        # Compute position for each item
        position_generator = LegendItemPositionGenerator(
            items_sizes=[item.size for item in items],
            axis=self._axis,
            max_size_along_axis=self._max_size_along_axis - 2 * margin,
            main_axis_align=self._main_axis_align,
            minor_axis_align=self._minor_axis_align)
        items_with_position = [
            (items[i], position)
            for i, position in enumerate(list(position_generator))
        ]

        # Prepare tag if needed
        upper_margin = 0
        draw = None
        if self._plot_tag:
            upper_margin = int(
                (2 * 2 + 0.75 * drawer.TEXT_SIZE + 2 * 4) * self._scale)
            # Prepare record and descriptor
            tag_descriptor = CategoricalDescriptor(name='name')
            tag_record = Record(
                coordinates=[[[0.5 * margin,
                               int(upper_margin / 2)],
                              [0.5 * margin,
                               int(upper_margin / 2) + 1],
                              [0.5 * margin + 1,
                               int(upper_margin / 2) + 1],
                              [0.5 * margin + 1,
                               int(upper_margin / 2)],
                              [0.5 * margin,
                               int(upper_margin / 2)]]],
                labels=['Dummy'],
                name=self._tag_descriptor.__descriptor__['name'],
                categorical_descriptor_name=0.5,
                color=Color(*get_outline_color(self._background_color),
                            ctype='sRGB255'))
            tag_descriptor.update(RecordCollection(tag_record))
            # Prepare TagPainter and Draw
            tag_painter = TagPainter(tag_descriptor,
                                     text_margin=2 * self._scale,
                                     text_size=0.75 * drawer.TEXT_SIZE *
                                     self._scale)
            draw = Draw(size=(int(position_generator.legend_size[0] +
                                  2 * margin), upper_margin),
                        zoom=1,
                        mode='RGBA',
                        background_color=self._background_color)
            # Draw legend tag
            tag_painter.draw(tag_record, draw=draw)

        # Create legend
        legend = PIL.Image.new(
            mode='RGBA',
            size=(position_generator.legend_size[0] + 2 * margin,
                  position_generator.legend_size[1] + 2 * margin +
                  upper_margin),
            color=self._background_color)

        for item, position in items_with_position:
            legend.alpha_composite(im=item,
                                   dest=(position[0] + margin,
                                         position[1] + margin + upper_margin))

        if draw is not None:
            legend.alpha_composite(im=draw.overlay, dest=(0, 4))

        if self._color_engine_interface['type'] == 'categorical':
            bottom_margin = position_generator.legend_size[
                1] - position_generator.true_legend_size[1]
            drawer.draw_outline_with_title(self._primary_descriptor_name,
                                           legend,
                                           margins=(0, upper_margin, 0,
                                                    bottom_margin))

        return legend
Example #19
0
    def test_draw(self):
        # Parameters
        color_engine_interface = {
            'name': 'Name(Main, Secondary)',
            'type': 'categorical',
            'schema': {
                'size': {
                    'small': Color(255, 0, 0, ctype='sRGB255'),
                    'medium': Color(255, 0, 0, ctype='sRGB255'),
                    'large': Color(255, 0, 0, ctype='sRGB255')
                }
            }
        }
        scale = 1
        axis = 0
        mosaic_size = (500, 500)
        background_color = (0, 0, 0)
        item_margins = (10, 10)
        main_axis_align = 'start'
        minor_axis_align = 'start'

        painter = LegendPainter(color_engine_interface=color_engine_interface,
                                scale=scale,
                                axis=axis,
                                mosaic_size=mosaic_size,
                                background_color=background_color,
                                item_margins=item_margins,
                                main_axis_align=main_axis_align,
                                minor_axis_align=minor_axis_align)

        # Draw legend
        legend = painter.draw()

        # Checks
        assert isinstance(legend, PIL.Image.Image)
        assert legend.height == 500
        assert legend.width > 0

        # Empty Color Engine schema -> means empty RecordCollection

        # Parameters
        color_engine_interface = {
            'name': 'Name(Main, Secondary)',
            'type': 'categorical',
            'schema': {}
        }

        painter = LegendPainter(color_engine_interface=color_engine_interface,
                                scale=scale,
                                axis=axis,
                                mosaic_size=mosaic_size,
                                background_color=background_color,
                                item_margins=item_margins,
                                main_axis_align=main_axis_align,
                                minor_axis_align=minor_axis_align)

        # Draw legend
        legend = painter.draw()

        # Checks
        assert isinstance(legend, PIL.Image.Image)
        assert legend.height == 0
        assert legend.width == 0