def __init__(self, data_or_path, mode=None, caption=None, grouping=None): """ Accepts numpy array of image data, or a PIL image. The class attempts to infer the data format and converts it. If grouping is set to a number the interface combines N images. """ self._grouping = grouping self._caption = caption self._width = None self._height = None self._image = None if isinstance(data_or_path, six.string_types): super(Image, self).__init__(data_or_path, is_tmp=False) else: data = data_or_path PILImage = util.get_module( "PIL.Image", required= 'wandb.Image needs the PIL package. To get it, run "pip install pillow".' ) if util.is_matplotlib_typename(util.get_full_typename(data)): buf = six.BytesIO() util.ensure_matplotlib_figure(data).savefig(buf) self._image = PILImage.open(buf) elif isinstance(data, PILImage.Image): self._image = data elif util.is_pytorch_tensor_typename(util.get_full_typename(data)): vis_util = util.get_module( "torchvision.utils", "torchvision is required to render images") if hasattr(data, "requires_grad") and data.requires_grad: data = data.detach() data = vis_util.make_grid(data, normalize=True) self._image = PILImage.fromarray( data.mul(255).clamp(0, 255).byte().permute(1, 2, 0).cpu().numpy()) else: if hasattr(data, "numpy"): # TF data eager tensors data = data.numpy() if data.ndim > 2: data = data.squeeze( ) # get rid of trivial dimensions as a convenience self._image = PILImage.fromarray(self.to_uint8(data), mode=mode or self.guess_mode(data)) self._width, self._height = self._image.size tmp_path = os.path.join(MEDIA_TMP.name, util.generate_id() + '.png') self._image.save(tmp_path, transparency=None) super(Image, self).__init__(tmp_path, is_tmp=True)
def __init__(self, data, mode=None, caption=None, grouping=None): """ Accepts numpy array of image data, or a PIL image. The class attempts to infer the data format and converts it. If grouping is set to a number the interface combines N images. """ PILImage = util.get_module( "PIL.Image", required= "wandb.Image requires the PIL package, to get it run: pip install pillow" ) if util.is_matplotlib_typename(util.get_full_typename(data)): buf = six.BytesIO() util.ensure_matplotlib_figure(data).savefig(buf) self.image = PILImage.open(buf) elif isinstance(data, PILImage.Image): self.image = data elif util.is_pytorch_tensor_typename(util.get_full_typename(data)): vis_util = util.get_module( "torchvision.utils", "torchvision is required to render images") if hasattr(data, "requires_grad") and data.requires_grad: data = data.detach() data = vis_util.make_grid(data, normalize=True) self.image = PILImage.fromarray( data.mul(255).clamp(0, 255).byte().permute(1, 2, 0).cpu().numpy()) else: # Handle TF eager tensors if hasattr(data, "numpy"): data = data.numpy() data = data.squeeze( ) # get rid of trivial dimensions as a convenience self.image = PILImage.fromarray(self.to_uint8(data), mode=mode or self.guess_mode(data)) self.grouping = grouping self.caption = caption
def val_to_json(key, val, mode="summary", step=None): """Converts a wandb datatype to its JSON representation""" converted = val typename = util.get_full_typename(val) if util.is_matplotlib_typename(typename): # This handles plots with images in it because plotly doesn't support it # TODO: should we handle a list of plots? val = util.ensure_matplotlib_figure(val) if any(len(ax.images) > 0 for ax in val.axes): PILImage = util.get_module( "PIL.Image", required= "Logging plots with images requires pil: pip install pillow") buf = six.BytesIO() val.savefig(buf) val = Image(PILImage.open(buf)) else: converted = util.convert_plots(val) elif util.is_plotly_typename(typename): converted = util.convert_plots(val) if isinstance(val, IterableMedia): val = [val] if isinstance(val, collections.Sequence) and len(val) > 0: is_media = [isinstance(v, IterableMedia) for v in val] if all(is_media): cwd = wandb.run.dir if wandb.run else "." if step is None: step = "summary" if isinstance(val[0], Image): converted = Image.transform(val, cwd, "{}_{}.jpg".format(key, step)) elif isinstance(val[0], Audio): converted = Audio.transform(val, cwd, key, step) elif isinstance(val[0], Html): converted = Html.transform(val, cwd, key, step) elif isinstance(val[0], Object3D): converted = Object3D.transform(val, cwd, key, step) elif any(is_media): raise ValueError( "Mixed media types in the same list aren't supported") elif isinstance(val, Histogram): converted = Histogram.transform(val) elif isinstance(val, Graph): if mode == "history": raise ValueError("Graphs are only supported in summary") converted = Graph.transform(val) elif isinstance(val, Table): converted = Table.transform(val) return converted
def val_to_json(run, key, val, step='summary'): """Converts a wandb datatype to its JSON representation. """ converted = val typename = util.get_full_typename(val) if util.is_pandas_data_frame(val): assert step == 'summary', "We don't yet support DataFrames in History." return data_frame_to_json(val, run, key, step) elif util.is_matplotlib_typename(typename): # This handles plots with images in it because plotly doesn't support it # TODO: should we handle a list of plots? val = util.ensure_matplotlib_figure(val) if any(len(ax.images) > 0 for ax in val.axes): PILImage = util.get_module( "PIL.Image", required= "Logging plots with images requires pil: pip install pillow") buf = six.BytesIO() val.savefig(buf) val = Image(PILImage.open(buf)) else: converted = plot_to_json(val) elif util.is_plotly_typename(typename): converted = plot_to_json(val) elif isinstance(val, collections.Sequence) and all( isinstance(v, WBValue) for v in val): # This check will break down if Image/Audio/... have child classes. if len(val) and isinstance(val[0], BatchableMedia) and all( isinstance(v, type(val[0])) for v in val): return val[0].seq_to_json(val, run, key, step) else: # TODO(adrian): Good idea to pass on the same key here? Maybe include # the array index? # There is a bug here: if this array contains two arrays of the same type of # anonymous media objects, their eventual names will collide. # This used to happen. The frontend doesn't handle heterogenous arrays #raise ValueError( # "Mixed media types in the same list aren't supported") return [val_to_json(run, key, v, step=step) for v in val] if isinstance(val, WBValue): if isinstance(val, Media) and not val.is_bound(): val.bind_to_run(run, key, step) return val.to_json(run) return converted