Image and acquisition I/O#

Use quantem.gpu.io for 4D-STEM acquisitions and quantem.widget image readers for survey images. The QuantEM.GPU I/O guide owns the detector storage, supported formats, metadata, backend, and exactness contracts. For a walkthrough of uint8/uint16, memory estimates and the image readers, start with IO/GPU; GPU selection and cleanup are in Memory management.

Open an acquisition and inspect a pattern#

from quantem.gpu import detector, io
from quantem.widget import Show2D, Show4DSTEM

data = io.load("scan_master.h5")
Show4DSTEM(data)

data is a quantem.gpu.io.Dataset4dstemGPU, ANS encoded on the CUDA device or the Apple GPU at native detector sampling and count dtype: a 512 x 512 x 192 x 192 uint16 scan, 18 GiB as a dense array, occupies about 0.1 to 2 GiB. Keep it open while viewers or calculations use its encoded buffers. Array-style selection decodes only the selected region into a Torch tensor on the acquisition’s GPU; it does not unpack the complete acquisition:

Show2D(data[10, 12])

Expression

Selection

data[10, 12]

One diffraction pattern

data[8:12, 10:16]

A rectangular scan patch

data[10, 12, 64:128, 64:128]

A detector crop at one position

data[:, :, 95, 100]

One detector pixel across the scan

data.metadata

Scientific calibration and source metadata

Show2D([detector.bf(data), detector.adf(data)], labels=["BF", "ADF"])
io.save("scan.qem", data)

Call data.close() after the last use. Scripted jobs can use with io.load(path) as data: for automatic cleanup. A list of paths loads as a list of encoded acquisitions, one per file; Show4DSTEM(io.load(paths)) opens them as a comparison grid labelled by file, and Show4DSTEM(series[1]) opens one of them. io.load(path, backend="cuda", device=1) selects a CUDA device; a Mac loads onto MPS. See load for the function reference and the GPU guide for multi-device storage policies.

Read a scan region#

Reconstruction, denoise and ROI workflows read the rectangular scan region they need. read decodes that region into a Torch tensor on the acquisition’s GPU:

with io.load("scan_master.h5") as data:
    patch_t = data.read(scan_region=(160, 293, 234, 367))  # row_start, row_stop, col_start, col_stop
print(patch_t.shape)  # torch.Size([133, 133, 192, 192])

Stops are exclusive, and detector_region= bounds the detector pixels the same way. For a drift-corrected time series, derive scan_region from the shared specimen ROI, the frame shift and a small scan halo, then sample the final ROI from the local patch. The detector counts remain raw; drift stays as scan-position metadata.

Discover acquisitions#

from quantem.gpu import io
from quantem.widget import Show4DSTEM

files = io.discover("/data/session")
Show4DSTEM(io.load(files[0]))

io.discover(path, scan_shape=(512, 512)) keeps only matching acquisitions when a folder mixes scan sizes. io.inspect(path) reads readiness and calibration headers without decoding measurements. Use Show4DSTEM.from_folder(path) for a live acquisition viewer.

For named sample data, see Tutorial datasets. The IO/GPU notebook demonstrates a real Gold image session.

Read images and image stacks#

from quantem.widget import Show2D, Show3D, read_image, read_images, read_image_stack

image = read_image("overview.tif")
Show2D(image)
images = read_images("survey_images", workers=8)
Show2D(images)
stack = read_image_stack("frames", file_type="tif", workers=8)
Show3D(stack)

These format readers run on the host. Calibrated image inputs retain their sampling for viewer scale bars. This path is for individual images and image sequences, not compressed 4D-STEM detector acquisitions.

Share data and finished figures#

Use Contribute tutorial data for shared example datasets and HTML and file export for interactive figures. Acquisition export belongs to io.save, described in the GPU I/O guide; it is separate from exporting a viewer.

Image function reference#

quantem.widget.read_image(path: str | Path) → Dataset2d | RgbImage#

Return a single image from disk (grayscale or true-color RGB).

One reader for every survey-image format the lab produces:

  • .npy - raw array, no calibration.

  • .emd - Velox HAADF (image under Data/Image/<hash>/Data with a JSON metadata blob carrying the pixel size); falls back to the largest 2D dataset for non-Velox EMD layouts (e.g. a data/drift/data series).

  • .tif / .tiff / .png / .jpg / .bmp / .gif - via Pillow. Color PNG/JPEG/TIFF keep RGB (RgbImage with shape (H, W, 3)); they are not converted to a single gray channel. Pass the result to Show2D or Show3D to display true color.

  • .dm3 / .dm4 - Gatan, via ncempy.

Grayscale results are Dataset2d. Color results are RgbImage (duck-types the .array / .name / .sampling surface Show2D already unwraps). A multi-frame container is reduced to its first frame.

Examples

>>> from quantem.widget import Show2D, io  
>>> Show2D(io.read_image("figure_rgb.png"))  # true color, not gray  
quantem.widget.read_images(folder: str | Path, *, workers: int = 1, progress: bool = False) → list[Dataset2d]#

Read every image in a folder into a list of Dataset2d.

The folder analog of read_image() for a mixed set of survey images - different formats and different sizes that cannot stack into one cube (use read_image_stack() for a folder of same-size frames). Files are sorted by name; every supported extension is read, anything else is skipped. Lets a gallery be one line: Show2D([d.array for d in io.read_images(folder)]).

Parameters:
  • folder (str or Path) – Folder containing supported 2D image files.

  • workers (int, default 1) – Thread count for reading many files. Use workers=8 for large folders of independent EMD/TIFF/PNG survey images.

  • progress (bool, default False) – Show a tqdm bar while reading.

quantem.widget.read_image_stack(path: str | Path, *, file_type: str | None = None, pattern: str | None = None, workers: int = 8, progress: bool = True) → Dataset3d#

Decode a folder of image frames into a Dataset3d in parallel.

A directory of PNG/TIFF/EMD/DM/NPY frames - an in-situ time series, a tilt series, a reconstruction sweep - is read with a thread pool into one contiguous (N, H, W) float32 array, then wrapped so Show3D(read_image_stack(dir)) scrubs the frames with no extra arguments. Frames are sorted naturally (frame_2 before frame_10). Decode is threaded because PIL/tifffile release the GIL during the C decode, so N threads give near-linear speedup until I/O or memory bandwidth saturates; ~8 workers is optimal on most disks. When the first frame is a calibrated format (EMD/DM), its pixel sampling and units carry onto the stack’s spatial axes so Show3D draws a physical scale bar.

Parameters:
  • path (str or Path) – Folder containing the image frames.

  • file_type (str, optional) – Extension filter (e.g. "png", "tif"). When omitted every common image extension in the folder is taken.

  • pattern (str, optional) – Glob within the folder (e.g. "frame_*.png"); overrides file_type.

  • workers (int, default 8) – Thread count for parallel decompression.

  • progress (bool, default True) – Show a tqdm bar while decoding.

Returns:

Shape (N, H, W), dtype float32. Sampling defaults to pixels since a bare image folder carries no calibration.

Return type:

Dataset3d