ML-Dash

Image Saving

save_image() writes a numpy array directly to PNG or JPEG — no manual conversion needed. Useful for MuJoCo/PyBullet renders, RL observations, model predictions, or any HxW / HxWxC array.

Requires Pillow: pip install Pillow.

Basic Usage

python
import numpy as np
from ml_dash import Experiment

with Experiment("vision/training").run as experiment:
    pixels = renderer.render()  # numpy array from MuJoCo, OpenCV, etc.

    experiment.files("frames").save_image(pixels, to="frame_001.png")  # lossless
    experiment.files("frames").save_image(pixels, to="frame_001.jpg")  # smaller

save() auto-detects numpy arrays and dispatches to save_image(), so these are equivalent:

python
experiment.files("images").save(pixels, to="frame.png")
experiment.files("images").save_image(pixels, to="frame.png")

Works with any numpy array — OpenCV frames (remember cv2.cvtColor(..., COLOR_BGR2RGB)), np.array(PIL.Image), model outputs, etc.

Array Types

  • uint8 — passed through directly. Shape HxW (grayscale), HxWx3 (RGB), or HxWx4 (RGBA).
  • float in [0.0, 1.0] — multiplied by 255 and cast to uint8.
  • float in any other range — normalized via (value - min) / (max - min) * 255.
python
experiment.files("images").save_image(np.random.rand(480, 640, 3), to="norm.png")
experiment.files("images").save_image(np.random.rand(480, 640) * 1000, to="scaled.png")

Format: PNG vs JPEG

AspectPNGJPEG
CompressionLosslessLossy
File SizeLargerSmaller
TransparencyYesNo
QualityPerfectConfigurable
Best ForGraphics, textPhotos, renders
SpeedSlowerFaster

The extension picks the encoder: .png, .jpg, and .jpeg all work. JPEG drops the alpha channel (transparent pixels composited onto white) and applies optimization.

Quality

JPEG only. Default is 95. Range 1–100.

python
experiment.files("frames").save_image(pixels, to="frame.jpg", quality=85)

Rough guide: 95–100 near-lossless, 85–90 balanced (recommended default for sequences), 70–80 visible compression, below 50 poor.

API Reference

save_image(array, *, to, quality=95)

Save a numpy array as an image file.

Parameters

  • array (numpy.ndarray) — image array, shape HxW or HxWxC.
  • to (str) — target filename with extension (.png, .jpg, .jpeg).
  • quality (int, optional) — JPEG quality 1–100. Default 95. Ignored for PNG.

Returns — dict with file metadata, or a queued-status dict when the write is buffered (see /buffering).

RaisesImportError if Pillow is missing; ValueError for invalid array or missing to.

Example: MuJoCo Renders

python
import mujoco
import numpy as np
from ml_dash import Experiment

with Experiment("robotics/mujoco-renders").run as experiment:
    model = mujoco.MjModel.from_xml_string(xml_content)
    data = mujoco.MjData(model)
    renderer = mujoco.Renderer(model, height=480, width=640)

    for i in range(1000):
        mujoco.mj_step(model, data)

        if i % 10 == 0:
            renderer.update_scene(data)
            pixels = renderer.render()  # (480, 640, 3) uint8

            experiment.files("robot/frames").save_image(
                pixels,
                to=f"frame_{i:05d}.jpg",
                quality=85,
            )

Image writes are buffered for non-blocking uploads — see /buffering. To align frames with numeric data, share a step index across save_image() and track() calls — see /tracks.