Python SDK
Imaging Capabilities
After attaching an ImagingDevice to a session, you can control the chamber,
acquire images, manage ROIs, move the stage, adjust focus parameters, and more. Each call blocks until
the device completes the operation (or reports failure).
Not every method is available on every SEM vendor. See the Capabilities reference for a full matrix with ✓ markers for TESCAN Mira 3 vs ZEISS Gemini.
Device types
ImagingDevice — Use for SEMs and other imaging instruments. Construct with ImagingDevice(client, device_slug="tescan-001") or device_id=.... Exposes .chamber, .imaging, and .stage.
DeformationDevice — Use for tensile stages, load frames, etc. Construct with DeformationDevice(client, device_slug="kammweis-001"). High-level APIs (load, displacement) can be extended later; for now you attach it to sessions and invoke capabilities as needed.
from semphony.systems import ImagingDevice, DeformationDevice
tescan = ImagingDevice(client, device_slug="tescan-001")
kamm = DeformationDevice(client, device_slug="kammweis-001")
with run.session() as s:
tescan.attach(s)
kamm.attach(s)
Chamber (vacuum)
The .chamber interface provides vacuum control for the SEM chamber.
Use chamber.vent() to vent the chamber (e.g. before loading a sample) and
chamber.pump() to evacuate it afterwards.
When guardrails are enabled, the SDK enforces safety rules automatically (e.g. beam must be off before venting).
tescan.chamber.vent()
# ... load sample, then ...
tescan.chamber.pump()
Image acquisition
Acquire an image with the given AcquisitionConfig.
Use download=True to fetch the image bytes via the API. Provide
target_path to save the file to disk. The call blocks until the device completes and
returns an AcquisitionResult.
You can call tescan.acquire(...) (convenience alias) or tescan.imaging.acquire(...).
The SDK retries up to 2 times on 504 (acquisition timeout), since timeouts can be transient.
from semphony.models import AcquisitionConfig
result = tescan.acquire(
AcquisitionConfig(fov_um=100, resolution=(1024, 1024)),
download=True,
target_path="acquired.png",
)
# result.image_id, result.local_path, result.correlation_id
Sample map (tiled acquisition)
Acquire a snake-ordered grid of tiles over a sample quadrilateral with
device.sample_map(config) or
device.imaging.sample_map(config).
Configure corners, tile FOV, overlap, and per-tile AcquisitionConfig.
Use get_time_estimate(config) for a wall-clock heuristic before starting.
✓ TESCAN
✓ ZEISS —
on ZEISS Gemini, resolution must exactly match allowed
DP_IMAGE_STORE sizes.
from semphony.models import SampleMapConfig
from semphony import get_time_estimate
config = SampleMapConfig(
corner_ul={"x": 0, "y": 0},
corner_ur={"x": 5000, "y": 0},
corner_lr={"x": 5000, "y": 5000},
corner_ll={"x": 0, "y": 5000},
tile_fov_um=200,
overlap_pct=10,
)
print(get_time_estimate(config))
result = tescan.sample_map(config)
Fix beam for EDS (point scan)
For EDS or other point analyses, fix the beam to a single pixel or small region, then collect the spectrum (e.g. via your EDS detector/software), then stop the scan.
fix_beam_at(x, y) uses scan/pixel coordinates for the current view; default 1×1 pixel, or use width=3, height=3 for a small region (better stability).
Always call stop_scan() when done.
✓ TESCAN only (SharkSEM point scan). Not available on ZEISS Gemini via the SDK.
# Fix beam at pixel (512, 512), then collect EDS for N seconds, then stop
tescan.imaging.fix_beam_at(512, 512)
# ... collect spectrum with EDS detector/software for N seconds ...
tescan.imaging.stop_scan()
# Optional: 3×3 region for stability
tescan.imaging.fix_beam_at(512, 512, width=3, height=3)
Save ROI
Capture a pyramidal ROI at the current stage position. The SDK acquires images at multiple zoom
levels per the RoiSpec (roi_fov_um, n_levels, l0_fov_um with geometric intermediate FOVs).
Optionally save the images and manifest to disk with target_dir.
from semphony.models import RoiSpec
spec = RoiSpec(name="my_roi", roi_fov_um=50, n_levels=3, l0_fov_um=1500)
saved = tescan.imaging.save_roi("my_roi", spec, target_dir="./rois")
# saved.name, saved.levels, saved.spec
Find ROI
Navigate the stage back to a previously saved ROI using correlative image matching.
The algorithm acquires live images at each zoom level and compares them to the saved pyramid
using template matching, iteratively correcting stage position, rotation, and field of view.
Requires semphony[find-roi].
result = tescan.imaging.find_roi(
"./rois/my_roi",
stage_mode="same_session",
)
# result.found, result.final_pose, result.iterations, result.level_history
Key parameters: stage_mode ("same_session" or "cross_session"),
max_iters, px_tol (pixel tolerance),
gain_xy / gain_rot / gain_fov (correction gains).
See the API reference for all parameters.
Autofocus
Two paths are available. Call imaging.autofocus() with no arguments to run the
vendor built-in routine (✓ ZEISS Gemini:
vendor_autofocus(mode="fine")). Or pass an
AutofocusConfig for DeepFocus ML autofocus
(✓ both vendors when focus params work).
DeepFocus acquires two perturbed images (WD ± sigma), predicts corrections with a trained CNN, and repeats until convergence.
Requires semphony[autofocus].
See the DeepFocus autofocus guide.
# Vendor autofocus (ZEISS)
tescan.imaging.autofocus()
# DeepFocus ML
from semphony.autofocus import AutofocusConfig
result = tescan.imaging.autofocus(AutofocusConfig(
model_path="./deepfocus_model.pt",
use_gpu=True,
))
# result.converged, result.iterations, result.final_wd_mm
Stage control
The .stage interface provides absolute and relative stage movement.
Coordinates are in µm (x, y, z) and degrees (r for rotation, t for tilt).
✓ Both TESCAN and ZEISS.
Get position
stage.get_pos() queries the device SDK for the live stage position.
stage.get_latest_pos() returns the last server-stored position (faster, but may be stale).
All linear axes are in µm (Semphony canonical), rotation/tilt in degrees — the device client converts vendor-native units (mm on TESCAN, m on ZEISS) at the SDK boundary.
pos = tescan.stage.get_pos()
# pos: {"x": 10500.0, "y": 8200.0, "z": 5000.0, "r": 0.0, "t": 0.0} # µm + degrees
Absolute move
stage.move_to(x, y, z=..., r=...) moves the stage to an absolute position.
Coordinates in µm; rotation in degrees. Only x and y are required.
tescan.stage.move_to(10500.0, 8200.0, r=45.0) # x, y in µm
Relative move (delta)
stage.move_delta(dx=..., dy=..., dz=..., dr=..., dt=...) moves the stage by a relative offset
(dx/dy/dz in µm, dr/dt in degrees).
When guardrails are active, the max move may be limited to a percentage of the current FOV.
tescan.stage.move_delta(dx=100.0, dy=-50.0) # 100 µm right, 50 µm down
Scan speed, rotation, detector, blanker & freeze
Scan speed
get_scan_speed() /
set_scan_speed(index) —
✓ both vendors.
ZEISS uses DP_SCANRATE indices 0–21.
Scan rotation
get_scan_rotation(),
rotate_scan(degrees),
rotate_scan_delta(delta),
disable_scan_rotation() —
✓ ZEISS Gemini only.
Detector selection
get_detector(),
set_detector(...),
list_detectors() —
✓ ZEISS Gemini only
(DP_DETECTOR_TYPE;
list returns fixed catalog 0–37 plus current selection).
Blanker & freeze
get_blanker() /
set_blanker(blanked) —
✓ both vendors.
get_freeze() /
set_freeze(frozen) —
✓ ZEISS only
(DP_FROZEN; used with grab_immediately on acquire).
High voltage
set_hv(kv) —
✓ both vendors.
tescan.imaging.set_scan_speed(8)
tescan.imaging.set_hv(15.0)
tescan.imaging.set_blanker(blanked=True)
tescan.imaging.set_freeze(frozen=True) # ZEISS only
Geometric transformations
The .imaging.geometric_transformations interface provides access to SharkSEM-style
geometry parameters (beam shift, tilt correction, rotation, etc.).
You can list, get, set, or reset all transformations.
✓ TESCAN only.
geoms = tescan.imaging.geometric_transformations.list()
value = tescan.imaging.geometric_transformations.get("tilt_correction")
tescan.imaging.geometric_transformations.set("tilt_correction", x=0.0)
tescan.imaging.geometric_transformations.reset() # zero all
Centerings
The .imaging.centerings interface provides access to SharkSEM-style
centering parameters (beam shift, aperture alignment, etc.).
The API mirrors geometric transformations: list(),
get(name_or_index), and set(name_or_index, x=..., y=...).
✓ TESCAN only.
centerings = tescan.imaging.centerings.list()
value = tescan.imaging.centerings.get("beam_shift")
tescan.imaging.centerings.set("beam_shift", x=0.0, y=0.0)
Focus parameters & beam control
Focus parameters
Read or write the working distance (mm) and stigmation values. These are also used internally by the autofocus algorithm.
focus = tescan.imaging.get_focus_params()
# {"wd_mm": 10.5, "stigm_x": 0.0, "stigm_y": 0.0}
tescan.imaging.set_focus_params(wd_mm=10.6, stigm_x=0.01)
View field
set_view_field(fov_um) —
✓ both vendors.
get_view_field_limits() returns min/max FOV from SmartSEM
GetLimits("AP_WIDTH")
(✓ ZEISS only; used for RoiSpec(l0_fov_um="max")).
tescan.imaging.set_view_field(fov_um=500)
min_um, max_um = tescan.imaging.get_view_field_limits()
Beam control
Turn the electron beam on or off. Guardrails enforce that vacuum must be present before enabling the beam.
tescan.imaging.set_beam(enabled=True)
tescan.imaging.set_beam(enabled=False)
Device metrics
Return the full device metrics snapshot (beam status, stage, vacuum, stigmator, etc.).
metrics = tescan.imaging.get_metrics()
Display feed (feed_snap)
Fast PiKVM live-view JPEG grab without a full SEM acquire. Use
client.feed_snap(system) or
imaging.feed_snap(system=...).
feed_snap_array() decodes to a grayscale float32 array for fast metric loops.
Configure crop via client.set_feed_snap_crop_settings().
System-level (not vendor-specific). Requires PiKVM display feed configured on the system. On ZEISS, unblank the beam and unfreeze before snapping.
snap = tescan.imaging.feed_snap(system="lab-sem")
gray = tescan.imaging.feed_snap_array(system="lab-sem")
Human-in-the-loop
Use imaging.await_human(message) to pause the workflow and display a message
in the Semphony UI. The call blocks until the operator clicks Continue. Use it for sample loading,
ROI selection, manual focus adjustments, or any step that requires human interaction.
tescan.imaging.await_human("Load sample and close chamber.")
# blocks until human clicks Continue in the UI
tescan.imaging.await_human("Navigate to ROI of interest, then continue.")