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))
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))
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))
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))
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))
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))
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)