Image and acquisition I/O#
The quantem.widget readers return the dataset type of the machine, so the
same code runs on a GPU workstation, a laptop without a GPU and an Intel Mac.
The QuantEM.GPU I/O guide owns the detector
storage, supported formats, metadata, backend, and exactness contracts of the
GPU path. For a walkthrough of uint8/uint16, memory estimates and the image
readers, start with IO/GPU; GPU selection and
cleanup are in Memory management.
Read data on any machine#
from quantem.widget import Show2D, Show4DSTEM, io
ds = io.read_image(path)
arr = ds.array # the pixels; ds.sampling, ds.units and ds.name carry the rest
Show2D(ds)
data = io.read_4dstem("scan_master.h5")
Show4DSTEM(data)
Reader |
quantem.gpu and a GPU |
No GPU route ( |
Intel Mac, Windows on ARM |
|---|---|---|---|
|
|
quantem core |
stand-in, read densely |
|
quantem core |
quantem core |
stand-in |
|
quantem core |
quantem core |
stand-in |
read_4dstem loads through quantem.gpu.io.load when quantem.gpu is installed
and a CUDA or Metal GPU works; a list of paths returns one dataset per file. A
.npy file that quantem.gpu cannot hold exactly (signed counts, float64 that
float32 does not hold, a flat 3D array) is read densely instead, with one
printed line. A dense read keeps every count exactly, prints one line with the
time taken, and refuses rather than bins or crops above 80% of the available
memory. Counts keep uint8 or uint16, and wider counts become uint16 when every
count fits, on both routes. quantem core cannot install on an Intel Mac (torch
2.7, NumPy 2) or Windows on ARM (hdf5plugin 6); there the readers return the
widget’s stand-in, with the same array, name, sampling (a float64 array),
units (a list), metadata, shape, ndim and dtype as a quantem core
dataset. A color PNG, JPEG or TIFF reads as an RgbImage with array,
name, sampling and units, and a folder of color frames as an
(N, H, W, 3) array: quantem core has no color-image dataset. Every widget
accepts each of these, NumPy arrays and torch tensors on any device, and shows
the same numbers for each.
On a GPU, a 4D-STEM file is a Dataset4dstemGPU, not a torch tensor:
counts are unsigned (uint16, uint32), and torch cannot add, multiply or take the max of those;
the file stays compressed in GPU memory (the 512 x 512 x 192 x 192 gold scan: 5.6 GiB, against 18 GiB as dense uint16);
quantem.gpu’s CUDA and Metal kernels decode and sum it exactly in one pass.
Indexing and read(scan_region=...) still return torch tensors.
Every 4D dataset has shape, dtype, ndim, sampling, units and
metadata, and Show4DSTEM takes any of them, with scan_region= for part of
the scan. A Dataset4dstemGPU reports an uncalibrated axis as None in
sampling and units where a dense dataset has 1.0 and "pixels"; the
widgets read both as an axis without a calibration. A dense dataset’s
metadata names the file (source_path) and records the replacement of the
detector pixels the master flags (hot_pixel_correction). read_4dstem,
Show4DSTEM(path) and Show4DSTEM.from_folder replace them with the median of
their unflagged 3x3 neighbours by default (the smallest larger window inside a
flagged cluster, a .5 median rounded half to even, as quantem.gpu’s io.load
does) and print how many;
hot_pixel_correction="none" keeps the stored values and "zero" sets them
to 0. A Dataset4dstemGPU
holds a
float64 file that float32 holds exactly as float32. A dense Dataset4dstem
also has array (a NumPy array) and name; a Dataset4dstemGPU keeps its
counts on the GPU, returns them as torch tensors from indexing
(data[10, 12]) and read(scan_region=...), and has close().
Open an acquisition on the GPU and inspect a pattern#
from quantem.gpu import detector, io
from quantem.widget import Show2D, Show4DSTEM
data = io.load("scan_master.h5") # what read_4dstem does on a GPU
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 |
|---|---|
|
One diffraction pattern |
|
A rectangular scan patch |
|
A detector crop at one position |
|
One detector pixel across the scan |
|
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.
Function reference#
- quantem.widget.read_4dstem(path, device: str = 'auto', *, scan_shape: tuple[int, int] | None = None, max_bytes: int | None = None, verbose: bool = True, hot_pixel_correction: str = 'median')#
Read a 4D-STEM file: a
Dataset4dstemGPUon a GPU, a quantem coreDataset4dstemotherwise.With quantem.gpu installed (
quantem.widget[cuda]or[mps]) and a CUDA or Metal GPU working,quantem.gpu.io.loadkeeps the counts encoded on the GPU. Without that route the file is read whole into host memory (read_dense) and returned as a quantem coreDataset4dstem; on an Intel Mac or Windows on ARM, which cannot install quantem core, as the widget’s stand-in with the samearray,name,sampling,units,metadata,shapeanddtype.Show4DSTEMand the detector math give the same numbers for either. The dense dataset’smetadatanames the file (source_path) and, when the master flags detector pixels, records their replacement (hot_pixel_correction: method, pixel count and coordinates).- Parameters:
path –
*_master.h5, an HDF5 file withentry/data/data,.npy, or a list of them (a list of datasets is returned).device –
"auto"(quantem.gpu picks CUDA, then Metal, and prints which),"cuda","cuda:N"or"mps"place an acquisition on that GPU;"cpu"reads densely into host memory even where quantem.gpu runs. A dense dataset stays in host memory; a widget computes on it where its owndevice=says.scan_shape –
(rows, cols)of a flat(positions, det_row, det_col)file; a square scan is inferred when omitted.max_bytes – Largest dense array to allocate. Default:
MEMORY_FRACTIONof the available host memory.verbose – Print the dense read’s one-line summary.
hot_pixel_correction –
"median"(default),"zero"or"none": what becomes of the detector pixels the master flags, on either route; one line says how many were replaced or left as stored.
- Raises:
MemoryError – When a dense array would exceed
max_bytes. Nothing is reduced instead.
Examples
>>> from quantem.widget import Show4DSTEM, read_4dstem >>> data = read_4dstem("scan_master.h5") >>> Show4DSTEM(data)
- quantem.widget.read_image(path: str | Path)#
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 underData/Image/<hash>/Datawith a JSON metadata blob carrying the pixel size); falls back to the largest 2D dataset for non-Velox EMD layouts (e.g. adata/drift/dataseries)..tif/.tiff/.png/.jpg/.bmp/.gif- via Pillow. Color PNG/JPEG/TIFF keep RGB (RgbImagewith shape(H, W, 3)); they are not converted to a single gray channel. Pass the result toShow2DorShow3Dto display true color..dm3/.dm4- Gatan, via ncempy, with the pixel size and unit the file records.
Grayscale results are a quantem core
Dataset2d(on an Intel Mac or Windows on ARM, which cannot install quantem core, the widget’s stand-in with the samearray,name,sampling,unitsandmetadata). Color results areRgbImage. A multi-frame file gives its first frame and prints one line saying so. A Velox EMD keeps its metadata inmetadataand its scan rotation inscan_rotation_deg.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)#
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 (useread_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=8for 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)#
Decode a folder of image frames into a
Dataset3din 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 soShow3D(read_image_stack(dir))scrubs the frames with no extra arguments. Frames are sorted naturally (frame_2beforeframe_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 soShow3Ddraws 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"); overridesfile_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 (the widget’s stand-in where quantem core cannot install). Sampling defaults to pixels since a bare image folder carries no calibration. A folder of color frames returns an(N, H, W, 3)array: quantem core has no color-image dataset.- Return type:
Dataset3d