Automated 2D material flake detection system for the Sharpe Lab's Leica DM6M microscope. Scans silicon wafers, detects flakes (hBN, graphene, WSe₂), and uploads results to flakes.sharpelab.science.
The find-flakes command orchestrates the full scan-to-upload pipeline:
- Overview scan (2.5x) — continuous-motion snake scan of the full stage area
- Stitch + chip detection — assemble frames into panoramic image, find chip boundaries via Otsu thresholding
- Per-chip focus map — autofocus at grid points, fit tilt plane for Z tracking
- Chip scan (10x or 20x) — continuous-motion scan with real-time Z tracking along the focus plane
- Segmentation — per-frame flake detection, classification, and tiered scoring (runs in background)
- Revisit (50x) — re-image top-ranked flakes at higher magnification
- Upload — package results and POST to flakes.sharpelab.science
Two scan presets:
| Preset | Overview | Chip Scan | Speed | Use Case |
|---|---|---|---|---|
2.5_10 |
2.5x | 10x | 10 mm/s | Fast screening |
2.5_20 |
2.5x | 20x | 5 mm/s | Higher resolution |
Supports checkpointing — re-run with --resume <run_dir> to pick up where a previous run left off.
See docs/architecture.md for detailed system design and hardware specs.
Segmentation is configured per-material via DetectorConfig presets. Each preset defines contrast thresholds, calibration curves (R/G contrast → thickness), classification gates, and scoring functions.
| Preset | Material | Substrate | Calibration | Notes |
|---|---|---|---|---|
hbn_medium |
hBN | 90nm SiO₂ | AFM-verified | Primary hBN preset |
hbn_thick_90nm |
hBN | 90nm SiO₂ | AFM-verified | 30-40nm hBN |
hbn_medium_285nm |
hBN | 285nm SiO₂ | Transfer matrix model | Tighter R gate for tape rejection |
graphene_thin_90nm |
Graphene | 90nm SiO₂ | Per-layer contrast | Layer counting (0.335 nm/layer) |
graphene_thick_90nm |
Graphene | 90nm SiO₂ | Per-layer contrast | Thick graphene (~5-10 nm); cal TBD |
wse2_monolayer_90nm |
WSe₂ | 90nm SiO₂ | Point calibration | Single-layer reference |
Detections are classified by proximity to the calibration curve (thin/medium/thick) and assigned a tier (T1 = high confidence, T2 = possible, T3 = unlikely) plus a continuous score based on size, shape, and calibration distance.
Requirements: Python 3.13+, Windows (for Leica SDK), uv package manager.
git clone git@github.com:sharpelab/flakefinder.git
cd flakefinder
uv sync
git config core.hooksPath hooks/Leica SDK DLLs must be in src/flakefinder/dlls/ (already in place on the microscope PC). See docs/setup.md for details.
# Full pipeline with default preset (2.5x overview + 10x chip scan)
uv run find-flakes
# Higher resolution preset
uv run find-flakes --preset 2.5_20
# Graphene detection
uv run find-flakes --material graphene_thin_90nm
# Only scan specific chips
uv run find-flakes --chips 0,2,5
# Resume a previous run
uv run find-flakes --resume scans/run_20260301_1430
# Preview without running
uv run find-flakes --dry-runThe sls tool runs commands on the microscope PC over SSH:
sls find-flakes --dry-run # run a command
sls stage # check stage position
sls pull scans/run_20260301_1430/ # download scan data
sls push calibration/flatfield.npy # upload a file
sls git status # run git on the microscope| Command | Framework | Purpose |
|---|---|---|
uv run find-flakes-gui |
Tkinter | Form-based launcher for find-flakes (for collaborators) |
uv run run-viewer |
Tkinter | Browse completed runs, view detections with filters |
uv run quick-scan |
PySide6 | Interactive stage viewer with live camera feed |
All commands are registered as pyproject.toml entry points. Run with uv run <command> on the microscope or sls <command> remotely.
| Command | Purpose |
|---|---|
find-flakes |
Full pipeline orchestrator |
scan |
Multi-row snake scan with continuous motion |
stitch |
Stitch scan frames into 2D overview image |
find-chips |
Detect chips in stitched image via Otsu thresholding |
focus-map |
Autofocus grid sampling across a chip |
analyze-focus-map |
Analyze focus map, fit tilt plane |
chip-scan |
Chip scan with continuous Z tracking |
autofocus |
Single-point Z-scan autofocus |
capture |
Single image capture |
revisit |
Revisit stage points with autofocus and capture |
stage |
Stage position, objective, and lamp control |
upload |
Upload run results to flakes.sharpelab.science |
run-viewer |
GUI: browse completed runs |
find-flakes-gui |
GUI: form-based pipeline launcher |
quick-scan |
GUI: interactive stage viewer |
Post-processing and analysis tools in scripts/. Run with uv run python scripts/<script>.py.
| Script | Purpose |
|---|---|
process_overview.py |
Overview post-processing (rsync + stitch + chip detection) |
process_chip_scan.py |
Chip scan analysis (rsync + segmentation) |
segment_chip_scan.py |
Run segmentation on a completed chip scan |
segment_flakes.py |
Segment individual frames |
crop_mosaic.py |
Build detection mosaic grids with filtering (--tier, --where, --top) |
eval_detections.py |
Evaluate detection quality across runs |
rerank_detections.py |
Re-score detections with updated config |
build_flatfield.py |
Build flatfield calibration from blank frames |
analyze_chip_scan.py |
Scan quality analysis (Z tracking, frame pacing) |
analyze_autofocus.py |
Autofocus quality analysis |
hbn_contrast.py |
Transfer matrix hBN contrast model |
hbn_contrast_widget.py |
Interactive R/G contrast explorer with sliders |
download_flakes.py |
Download flake images from flakes.sharpelab.science |
| Tool | Purpose |
|---|---|
tools/sls |
Run commands on the microscope via SSH. Setup: ln -sf $(pwd)/tools/sls ~/.local/bin/sls |
tools/scan-nb |
Append timestamped entries to scan notebooks. Setup: ln -sf $(pwd)/tools/scan-nb ~/.local/bin/scan-nb |
├── src/flakefinder/
│ ├── leica/ # Hardware library: Stage, Camera, ZDrive, Lamp, etc.
│ ├── commands/ # CLI entry points (see Commands table)
│ ├── segmentation.py # Flake detection: presets, scoring, classification
│ ├── scan_utils.py # Geometry, interpolation, flatfield correction
│ ├── flakes_api.py # Client for flakes.sharpelab.science
│ ├── cli_utils.py # Argparse helpers, metadata builders
│ ├── data_utils.py # Scan data loading
│ └── types.py # NamedTuples (ScanMeta, FrameMeta, etc.)
├── src/quick_scan/ # PySide6 stage viewer GUI
├── scripts/ # Analysis and post-processing scripts
│ └── experiments/ # Hardware characterization experiments
├── tools/ # sls, scan-nb, subtask-launch
├── docs/ # Architecture, scan format, microscope reference, setup
├── calibration/ # Flatfield calibration images
├── scans/ # Scan output data (gitignored)
└── archive/ # Superseded scripts kept for reference
uv sync # install all deps
uv run ruff check --fix . && uv run ruff format . # lint + format
uv run ty check # type check
uv run pytest # testsPre-commit hooks run ruff and ty automatically. Enable with git config core.hooksPath hooks/.