From klayoutclaw
Aligns microscope stack images to GDS fabrication templates via lithographic marker detection, computes image-to-GDS transforms, and commits warped images plus contours to KLayout.
npx claudepluginhub caidish/klayoutclaw --plugin klayoutclawThis skill uses the workspace's default tool permissions.
Align microscope images to a GDS fabrication template by detecting lithographic markers in both domains and computing a similarity transform.
Aligns source microscope images like bottom_part or top_part to full_stack reference using SIFT (same-substrate) or Chamfer+DE (cross-substrate) for van der Waals stack detection.
Processes microscopy and bioimage images with scikit-image: read/write, filter (Gaussian, median, LoG), segment (thresholding, watershed, active contours), measure regions, detect features. NumPy/SciPy integration.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Share bugs, ideas, or general feedback.
Align microscope images to a GDS fabrication template by detecting lithographic markers in both domains and computing a similarity transform.
Coordinate system after gdsalign: Coordinates in
traces_gds.jsonare in the GDS reference frame (floating-point micrometers). When using them inexecute_script, convert to dbu viaint(value_um / layout.dbu). Do NOT apply the flakedetect_commit image-center transform — gdsalign already handles the coordinate mapping.
instrMCPdev with opencv, numpy, scipy, gdstktraces.json with material contours in pixel coordinatesconda run -n instrMCPdev python <script>If the user does not specify an output path, default to <stack_image_dir>/output/gdsalign/ (the directory containing the source images). Never use /tmp as the default output.
1. extract_markers — Parse GDS, find 4 innermost L5/0 marker pairs
→ gds_markers.json (pair centers + bounding boxes in um)
2. detect_markers — Find marker crosses in microscope image
→ image_markers.json (detected centers in pixel coordinates)
3. align_gds — Match GDS↔image marker pairs, compute reflected similarity
→ gds_warp.npy (2x3 affine), gds_alignment_report.json
4. commit_gds — Warp image + transform contours, commit to KLayout
→ full_stack_gds.png, traces_gds.json, image_placement.json
conda run -n instrMCPdev python skills/nanodevice_gdsalign/scripts/extract_markers.py \
--gds Template.gds --output-dir output/gdsalign/
Parses GDS, finds all L5/0 polygons, selects the 8 closest to grid center, groups into 4 pairs by proximity, labels NE/NW/SE/SW.
Outputs: gds_markers.json
conda run -n instrMCPdev python skills/nanodevice_gdsalign/scripts/detect_markers.py \
--image stack.png --pixel-size <um/px> \
--gds-markers output/gdsalign/gds_markers.json \
--output-dir output/gdsalign/
Renders marker-pair templates from gds_markers.json, then runs multi-method template matching (grayscale, inverted, CLAHE, edge) with geometric consistency filtering to find the 4 marker pairs.
Outputs: image_markers.json, 01_template.png, 03_detections.png
Verification: After running, view 03_detections.png. The 4 detected markers (colored circles) should form a roughly square pattern, ~300-400 um apart (a few thousand pixels at 0.087 um/px), centered in the image near the flake region. The pixel_size parameter is critical for correct template rendering — use the value specified in the task instructions (typically 0.087 um/px). If detections look wrong (markers on image edges, or only 2-3 found), check that pixel_size matches the actual microscope magnification.
conda run -n instrMCPdev python skills/nanodevice_gdsalign/scripts/align_gds.py \
--gds-markers output/gdsalign/gds_markers.json \
--image-markers output/gdsalign/image_markers.json \
--output-dir output/gdsalign/
Exhaustive enumeration over 2-point correspondences finds the best reflected similarity (image Y-down → GDS Y-up), then least-squares refinement over all inliers. Automatically resolves rotational ambiguity (90°/180°/270°) for symmetric marker patterns by preferring the solution closest to 0° rotation.
Outputs: gds_warp.npy (2×3 affine matrix), gds_alignment_report.json
conda run -n instrMCPdev python skills/nanodevice_gdsalign/scripts/commit_gds.py \
--warp output/gdsalign/gds_warp.npy \
--traces output/combine/traces.json \
--image full_stack_raw.jpg --pixel-size <um/px> \
--gds Template.gds --output-dir output/gdsalign/ [--warp-only]
Warps the microscope image and material contours into GDS coordinates using the affine from align_gds.py. Without --warp-only, also loads the GDS template into KLayout, adds the warped image as a background overlay, and inserts material polygons on layers 10–13.
| Flag | Description |
|---|---|
--warp | Path to gds_warp.npy (2×3 affine matrix) |
--traces | Path to traces.json from flakedetect (with contour_um fields) |
--image | Full-stack microscope image |
--pixel-size | Image pixel size in um/px |
--gds | Template GDS file (loaded into KLayout during commit) |
--output-dir | Optional output directory for warp results (default: current working directory). Set this to the agent's workspace directory to keep warp outputs scoped. Files written: traces_gds.json, full_stack_gds.png, image_placement.json |
--warp-only | Only produce warped files, skip KLayout commit |
--mcp-config | Path to MCP config JSON. Fallback chain: .mcp.json in CWD → mcp_config.json in project root → default 127.0.0.1:8765. In Docker, pass a config pointing to http://host.docker.internal:8765/mcp |
Outputs: full_stack_gds.png, traces_gds.json, image_placement.json
| Metric | Pass | Fail |
|---|---|---|
| Markers detected | >= 3 | < 3 |
| Inliers (align_gds) | >= 2 | < 2 |
| Mean residual | < 5.0 um | >= 5.0 um |
Fail on any metric: Do NOT commit to KLayout. Check diagnostic images and retry.
align_gds.py automatically tries all four companions and picks the one with rotation closest to 0°.full_stack_gds.png) is vertically flipped on save so that row 0 holds GDS-north data. KLayout's pya.Image renders PNG row 0 at the high-Y edge of the placement bbox, so the image ends up right-side-up when placed at origin_um = (x_min, y_min) with identity rotation. If you inspect the PNG in a file viewer it will already look correct (north at top).traces_gds.json) are produced from the same affine. If you re-run the alignment at a different pixel_size, you must also re-run commit_gds.py with the same pixel_size. Mixing a gds_warp.npy produced at one pixel size with commit_gds.py --pixel-size at another will place the image at the wrong scale (the scale factor in the warp matrix compensates for the pixel_size used during alignment).commit_gds.py calls layout.clear() before loading the template into KLayout, so any pre-existing geometry in the current tab is wiped. This is intentional — it avoids cell-name collisions in Layout.read() that otherwise leave orphaned cell indices. Run commit_gds.py against a fresh tab (or use the create_layout MCP tool first) if you have ongoing work you don't want to lose.The pixel_size parameter (um/px) is critical for correct template rendering in detect_markers.py and image placement in commit_gds.py. Always validate the pixel size before running the pipeline.
Common pixel_size values by objective magnification:
| Objective | Typical pixel_size (um/px) |
|---|---|
| 100x | 0.05 |
| 100x (alt) | 0.087 |
| 50x | 0.1 |
| 20x | 0.25 |
| 10x | 0.5 |
Use validate_pixel_size to confirm the value before running the alignment pipeline. If the pixel size is wrong, marker detection will fail or produce incorrect transforms.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Error (missing file, insufficient markers, transform failure) |