YAML configuration templates for QPSC microscope systems.
Part of the QPSC (QuPath Scope Control) system. For complete installation and setup instructions, see the QPSC Installation Guide.
This repository contains configuration templates and examples for setting up QPSC with various microscope hardware configurations. These files define microscope-specific settings including hardware components, imaging modalities, autofocus parameters, and image processing settings.
Located in the templates/ folder:
templates/config_template.yml- Comprehensive microscope configuration template with examples for all modality typestemplates/autofocus_template.yml- Autofocus parameter template with detailed documentationtemplates/imageprocessing_template.yml- Image processing settings template (exposure, gain, white balance)
Located in the root directory:
config_PPM.yml- PPM (Polarized light) microscope example configurationconfig_CAMM.yml- CAMM (Multi-modal) microscope example configuration
resources/resources_LOCI.yml- LOCI hardware component lookup tables (objectives, cameras, etc.)
Recommended: Use the QPSC installation instructions which includes automated setup of configuration templates.
-
Clone this repository:
git clone https://github.com/uw-loci/microscope_configurations.git cd microscope_configurations -
Copy and customize a template:
# Copy the main configuration template cp templates/config_template.yml config_my_microscope.yml # Edit with your hardware settings nano config_my_microscope.yml # or use your preferred editor
-
Configure autofocus (optional):
cp templates/autofocus_template.yml autofocus_my_microscope.yml # Edit autofocus parameters for your objectives -
Configure image processing (optional):
cp templates/imageprocessing_template.yml imageprocessing_my_microscope.yml # Edit exposure and gain settings for your camera
Defines the complete microscope setup:
microscope:
name: "Your Microscope Name"
type: "Multimodal"
modalities:
ppm_20x:
type: "ppm"
angles: [0, 45, 90, 135]
exposure_ms: 50
hardware:
objectives:
- id: "LOCI_4x_001"
pixel_size_xy_um:
LOCI_CAMERA_001: 1.105The stage.inserts block (inside stage:) is optional. When it is absent,
the Stage Map utility synthesizes a single-slide insert at the center of
stage.limits using slide_size_um for the slide footprint. Simple setups
that only need a single slide in the middle of the stage can omit the
stage.inserts block entirely and rely on the fallback. Multi-slide holders
and scopes with offset apertures still need an explicit stage.inserts
calibration.
QPSC supports vendor-agnostic multi-channel widefield immunofluorescence
(IF) and combined brightfield + IF (BF+IF) acquisition on single-camera
scopes. The schema is driven by two Micro-Manager primitives: named
ConfigGroup presets and direct device-property writes. The QPSC base
layer reads the YAML and drives any vendor's illumination hardware
uniformly -- no vendor-specific code lives in the Java or Python loops.
For the full design narrative (pipeline, stitching, merge, PPM-parity),
see QPSC/docs/multichannel-if-overview.md. This section documents only
the YAML keys that the parser reads.
The canonical parser is
qupath-extension-qpsc/src/main/java/qupath/ext/qpsc/utilities/MicroscopeConfigManager.java
(parseChannel, getModalityChannels, getProfileChannelIds,
getProfileChannelOverrides, getChannelsForProfile,
mergeDevicePropertyOverrides). The Python side in
microscope_command_server/microscope_command_server/acquisition/workflow.py
(resolve_channel_plan, _merge_device_property_overrides) mirrors the
same rules.
The working example for everything below is config_OWS3.yml -- it has
both a full Fluorescence modality (4-channel library) and a full
BF_IF modality (5-channel library with BF as the first entry), plus
profile-level overrides including the extended
channel_overrides.BF.device_properties tuning on BF_IF_10x.
Channels live under modalities.<name>.channels as an ordered list.
Each entry is fully self-contained: everything that has to be in effect
for the channel to image correctly is listed inside the entry.
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Channel identifier. Used as the on-disk subdirectory name and as the CLI argument to the server. Must be unique within the modality. |
display_name |
string | no | Human-readable label shown in the channel picker UI. Defaults to id. |
exposure_ms |
number | yes | Default per-channel exposure in milliseconds. Must be numeric; non-numeric entries are skipped with a warning. |
mm_setup_presets |
list of maps | no | Ordered list of { group, preset } entries. Each applies a Micro-Manager ConfigGroup preset via core.setConfig(group, preset). Runs inside the tile loop, every tile. |
device_properties |
list of maps | no | Ordered list of { device, property, value } entries. Each applies a direct Micro-Manager device-property write via core.setProperty(device, property, value). value is always stringified on the Java side, so any MM property type round-trips. |
settle_ms |
number | no | Optional dumb-sleep after the presets and properties have been applied, for hardware whose isBusy() reports complete too early. Defaults to 0. |
Notes:
display_namedefaults to the channelidif omitted.- Channels with a missing or non-numeric
exposure_ms, or a missingid, are dropped at parse time and a warning is logged. - On scopes where the filter cube never actually changes (for example a multi-band dichroic), repeating the cube preset inside every channel is redundant but idempotent -- it keeps the schema uniform across instruments where the cube does change.
See the Fluorescence modality in config_OWS3.yml for a four-channel
DAPI / FITC / TRITC / Cy5 library driving a DLED multi-wavelength source.
Acquisition profiles consume the modality's channel library via two optional keys: a subset filter and per-channel overrides.
acquisition_profiles.<profile>.channels-- optional list of channel ids. When present, only the listed ids are acquired, in the order given. When absent, every channel from the modality library is used in library order. Ids not present in the modality library are dropped with a warning and the profile still proceeds with the remaining ids.acquisition_profiles.<profile>.channel_overrides-- optional map keyed by channel id. Each value is a sub-map that may contain:exposure_ms(number) -- straight scalar override of the library default exposure.device_properties(list of maps) -- per-channel device-property override list with the extended merge schema described below.
Overriding a channel id that is not in the effective selection is a silent no-op (the override map is only consulted for selected channels).
The override device_properties list is merged into the channel's
library device_properties list with "replace by (device, property),
append on miss" semantics. For each override entry, in order:
- Search the channel library's existing
device_propertiesfor a matching(device, property)tuple. - If matched, replace the value in place, preserving list order.
- If not matched, append the entry to the end of the list.
This lets a profile tune one property on one channel with a single YAML
line, without having to redeclare the whole channel entry. The exact
same rule is implemented in
MicroscopeConfigManager.mergeDevicePropertyOverrides (Java) and
_merge_device_property_overrides (Python) and is unit-test-backed on
both sides.
The load-bearing example is the BF_IF_10x profile in config_OWS3.yml:
BF_IF_10x:
modality: BF_IF
detector: HAMAMATSU_DCAM_01
channels: [BF, DAPI, FITC, TRITC, Cy5]
channel_overrides:
BF:
exposure_ms: 20
device_properties:
# Replaces the BF channel library's (DiaLamp, Intensity) entry
# in place. 10x uses a much lower transmitted-lamp intensity
# than 20x/40x/60x; this single line keeps the per-objective
# tuning out of the channel library itself.
- { device: DiaLamp, property: Intensity, value: 70 }type: bf_if marks a modality as combined brightfield + widefield
immunofluorescence on a single-camera scope. There is no separate code
path: BF is expressed as a regular entry in the channels: library
whose mm_setup_presets happen to switch the light path to the
transmitted port and whose device_properties happen to drive the
transmitted lamp. The acquisition loop, the stitcher, and the
multichannel merger treat it identically to every fluorescence channel.
The only thing the bf_if marker does today is give users a distinct,
discoverable entry in the acquisition UI and give future BF+IF-specific
behavior (image type defaults, background correction strategy) a clear
home without touching the pure-IF handler.
See the BF_IF modality and the BF_IF_10x / BF_IF_20x / BF_IF_40x
/ BF_IF_60x profiles in config_OWS3.yml for the working reference.
Note that BF is the first entry in the library and the BF_IF_10x
profile uses the extended channel_overrides.BF.device_properties to
drop the transmitted-lamp intensity for the 10x objective.
QPSC/docs/multichannel-if-overview.md-- cross-repo narrative, pipeline diagram, and end-to-end example.qupath-extension-qpsc/documentation/CHANNELS.md-- Java extension's user-facing reference for the channel UI, troubleshooting, and the in-process pipeline class names.config_OWS3.yml-- working reference for bothFluorescenceandBF_IFmodalities and for the extendedchannel_overrides.<id>.device_propertiesmerge.
Defines autofocus parameters per objective:
autofocus_settings:
LOCI_4x_001:
interp_strength: 3
score_metric: "NormalizedVariance"
num_images: 30
step_size_um: 50Defines camera settings per modality and camera:
imaging_settings:
ppm_4x:
LOCI_CAMERA_001:
exposure_ms: 50
gain_dB: 0- Do NOT commit your custom configurations to this repository - The
.gitignorefile excludes all.ymlfiles except templates - Templates are for reference - Copy and customize them for your specific hardware
- LOCI resources - The
resources/folder contains shared hardware definitions used across multiple microscopes
LLM_CONFIG_GUIDE.md is the primary reference an LLM (or a human
bootstrapping a new microscope) follows when producing a QPSC config
from scratch. When templates change and the guide doesn't, new scopes
get authored against stale examples and land with subtle schema
mismatches that only show up mid-acquisition.
This repo enforces "template changes must update the guide" in two layers:
.github/workflows/guide-sync.yml runs on every push to main and on
every pull request targeting main. It:
- Fails the check if any file under
templates/was modified withoutLLM_CONFIG_GUIDE.mdbeing touched in the same diff -- this blocks merging. - Warns (without failing) when real scope configs
(
config_OWS3.yml,autofocus_PPM.yml, etc.) are modified without a matching guide update.
No setup required -- this runs on GitHub for every contributor automatically.
githooks/pre-commit runs the same checks before each local commit so
developers get feedback without waiting for CI. It's opt-in per clone:
git config core.hooksPath githooksThe CI workflow is the line that actually blocks merges; the local hook
just catches the mistake a few seconds earlier. To bypass the local
hook for a single commit (rare), use git commit --no-verify. Bypassing
CI is not possible without admin override.
For detailed configuration instructions, see the QPSC Configuration Guide.
- Issues: https://github.com/uw-loci/microscope_configurations/issues
- QPSC Documentation: https://github.com/uw-loci/QPSC
- Micro-Manager: https://micro-manager.org/
MIT License