Beispiel #1
0
    def test_get_image_content_from_rgba_array(self):
        # given
        image_array = numpy.random.rand(200, 300, 4)*255
        expected_image = Image.fromarray(image_array.astype(numpy.uint8))

        # expect
        self.assertEqual(get_image_content(image_array), _get_pil_image_data(expected_image))
Beispiel #2
0
    def test_get_image_content_from_3d_grayscale_array(self):
        # given
        image_array = numpy.array([[[1], [2]], [[3], [4]], [[5], [6]]])
        expected_array = numpy.array([[1, 2], [3, 4], [5, 6]]) * 255
        expected_image = Image.fromarray(expected_array.astype(numpy.uint8))

        # expect
        self.assertEqual(get_image_content(image_array),
                         _get_pil_image_data(expected_image))
Beispiel #3
0
    def test_get_image_content_from_string(self):
        # given
        filename = "{}/image.png".format(self.TEST_DIR)
        image_array = numpy.random.rand(200, 300, 3)*255
        expected_image = Image.fromarray(image_array.astype(numpy.uint8))
        expected_image.save(filename)

        # expect
        self.assertEqual(get_image_content(filename), _get_pil_image_data(expected_image))
Beispiel #4
0
    def test_get_image_content_from_tensorflow_tensor(self):
        import tensorflow as tf  # pylint: disable=C0415
        # given
        image_tensor = tf.random.uniform(shape=[200, 300, 3])
        expected_array = image_tensor.numpy() * 255
        expected_image = Image.fromarray(expected_array.astype(numpy.uint8))

        # expect
        self.assertEqual(get_image_content(image_tensor),
                         _get_pil_image_data(expected_image))
Beispiel #5
0
    def test_get_image_content_from_torch_tensor(self):
        import torch  # pylint: disable=C0415
        # given
        image_tensor = torch.rand(200, 300, 3)
        expected_array = image_tensor.numpy() * 255
        expected_image = Image.fromarray(expected_array.astype(numpy.uint8))

        # expect
        self.assertEqual(get_image_content(image_tensor),
                         _get_pil_image_data(expected_image))
Beispiel #6
0
    def test_get_image_content_from_figure(self):
        # given
        pyplot.plot([1, 2, 3, 4])
        pyplot.ylabel('some interesting numbers')
        figure = pyplot.gcf()
        figure.canvas.draw()
        expected_image = Image.frombytes('RGB', figure.canvas.get_width_height(), figure.canvas.tostring_rgb())

        # expect
        self.assertEqual(get_image_content(figure), _get_figure_as_image(figure))
Beispiel #7
0
    def send_image(self, channel_name, x, y=None, name=None, description=None, timestamp=None):
        x, y = self._get_valid_x_y(x, y)

        input_image = dict(
            name=name,
            description=description,
            data=base64.b64encode(get_image_content(y)).decode('utf-8')
        )

        value = ChannelValue(x, dict(image_value=input_image), timestamp)
        self._channels_values_sender.send(channel_name, 'image', value)
    def log_image(self,
                  log_name,
                  x,
                  y=None,
                  image_name=None,
                  description=None,
                  timestamp=None):
        """Log image data in Neptune

        | If a log with provided ``log_name`` does not exist, it is created automatically.
        | If log exists (determined by ``log_name``), then new value is appended to it.

        Args:
            log_name (:obj:`str`): The name of log, i.e. `bboxes`, `visualisations`, `sample_images`.
            x (:obj:`double`): Depending, whether ``y`` parameter is passed:

                * ``y`` not passed: The value of the log (data-point). See ``y`` parameter.
                * ``y`` passed: Index of log entry being appended. Must be strictly increasing.

            y (multiple types supported, optional, default is ``None``):

                The value of the log (data-point). Can be one of the following types:

                * :obj:`PIL image`
                  `Pillow docs <https://pillow.readthedocs.io/en/latest/reference/Image.html#image-module>`_
                * :obj:`matplotlib.figure.Figure`
                  `Matplotlib 3.1.1 docs <https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.figure.Figure.html>`_
                * :obj:`str` - path to image file
                * 2-dimensional :obj:`numpy.array` - interpreted as grayscale image
                * 3-dimensional :obj:`numpy.array` - behavior depends on last dimension

                    * if last dimension is 1 - interpreted as grayscale image
                    * if last dimension is 3 - interpreted as RGB image
                    * if last dimension is 4 - interpreted as RGBA image

            image_name (:obj:`str`, optional, default is ``None``): Image name
            description (:obj:`str`, optional, default is ``None``): Image description
            timestamp (:obj:`time`, optional, default is ``None``):
                Timestamp to be associated with log entry. Must be Unix time.
                If ``None`` is passed, `time.time() <https://docs.python.org/3.6/library/time.html#time.time>`_
                (Python 3.6 example) is invoked to obtain timestamp.

        Example:
            Assuming that `experiment` is an instance of :class:`~neptune.experiments.Experiment`:

            .. code:: python3

                # path to image file
                experiment.log_image('bbox_images', 'pictures/image.png')
                experiment.log_image('bbox_images', x=5, 'pictures/image.png')
                experiment.log_image('bbox_images', 'pictures/image.png', image_name='difficult_case')

                # PIL image
                img = PIL.Image.new('RGB', (60, 30), color = 'red')
                experiment.log_image('fig', img)

                # 2d numpy array
                array = numpy.random.rand(300, 200)*255
                experiment.log_image('fig', array)

                # 3d grayscale array
                array = numpy.random.rand(300, 200, 1)*255
                experiment.log_image('fig', array)

                # 3d RGB array
                array = numpy.random.rand(300, 200, 3)*255
                experiment.log_image('fig', array)

                # 3d RGBA array
                array = numpy.random.rand(300, 200, 4)*255
                experiment.log_image('fig', array)

                # matplotlib figure example 1
                from matplotlib import pyplot
                pyplot.plot([1, 2, 3, 4])
                pyplot.ylabel('some numbers')
                experiment.log_image('plots', plt.gcf())

                # matplotlib figure example 2
                from matplotlib import pyplot
                import numpy

                numpy.random.seed(19680801)
                data = numpy.random.randn(2, 100)

                figure, axs = pyplot.subplots(2, 2, figsize=(5, 5))
                axs[0, 0].hist(data[0])
                axs[1, 0].scatter(data[0], data[1])
                axs[0, 1].plot(data[0], data[1])
                axs[1, 1].hist2d(data[0], data[1])

                experiment.log_image('diagrams', figure)

        Note:
            For efficiency, logs are uploaded in batches via a queue.
            Hence, if you log a lot of data, you may experience slight delays in Neptune web application.
        Note:
            Passing ``x`` coordinate as NaN or +/-inf causes this log entry to be ignored.
            Warning is printed to ``stdout``.
        Warning:
            Only images up to 2MB are supported. Larger files will not be logged to Neptune.
        """
        x, y = self._get_valid_x_y(x, y)

        if x is not None and is_nan_or_inf(x):
            x = None

        image_content = get_image_content(y)
        if len(image_content) > self.IMAGE_SIZE_LIMIT:
            _logger.warning(
                'Your image is larger than 2MB. Neptune supports logging images smaller than 2MB. '
                'Resize or increase compression of this image')
            image_content = None

        input_image = dict(name=image_name, description=description)
        if image_content:
            input_image['data'] = base64.b64encode(image_content).decode(
                'utf-8')

        if x is not None and is_nan_or_inf(x):
            _logger.warning(
                'Invalid metric x-coordinate: %s for channel %s. '
                'Metrics with nan or +/-inf x-coordinates will not be sent to server',
                x, log_name)
        else:
            value = ChannelValue(x, dict(image_value=input_image), timestamp)
            self._channels_values_sender.send(log_name,
                                              ChannelType.IMAGE.value, value)