Skip to content

Commit a493b3f

Browse files
committed
Add template script
1 parent e0470f8 commit a493b3f

2 files changed

Lines changed: 119 additions & 0 deletions

File tree

‎src/main/java/sc/fiji/snt/BookmarkManager.java‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,32 @@ public List<SNTPoint> getPositions(final boolean onlySelectedRows) {
16711671
return (List<SNTPoint>) (List<?>) pixelPoints; // spatially calibrated positions
16721672
}
16731673

1674+
/**
1675+
* Returns the position of the most recently added bookmark/marker, in spatially calibrated
1676+
* ("world") coordinates.
1677+
* <p>
1678+
* In viewer mode (BVV/BDV), this is the last marker placed with the {@code M} key (or added
1679+
* programmatically). In SNT-UI mode, this is the last entry added to the Bookmark Manager pane.
1680+
* Since new entries are always appended, this reflects placement order in the common case; it
1681+
* can become stale relative to placement order after an explicit list-reordering operation
1682+
* (e.g. the table's "Sort by Distance..." menu, or a Merge/Colocalize operation, both of which
1683+
* re-write the backing list).
1684+
* </p>
1685+
*
1686+
* @return the position of the last bookmark, or {@code null} if none have been added
1687+
*/
1688+
public SNTPoint getLastPosition() {
1689+
final List<Bookmark> data = model.getDataList();
1690+
if (data.isEmpty()) return null;
1691+
final Bookmark last = data.getLast();
1692+
if (viewer != null) {
1693+
return last; // viewer mode: already stored in world/calibrated coordinates
1694+
}
1695+
// SNT-UI mode: stored coordinates are in pixel space; convert to calibrated units
1696+
final ij.measure.Calibration cal = sntui.plugin.getPathAndFillManager().getBoundingBox(false).getCalibration();
1697+
return new PointInImage(cal.getX(last.getX()), cal.getY(last.getY()), cal.getZ(last.getZ()));
1698+
}
1699+
16741700
/**
16751701
* Adds the bookmark ROIs to the specified overlay. If no bookmarks are selected, all bookmarks are added,
16761702
* otherwise only the selected bookmarks are added.
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#@Double(label="Crop width/height (XY, calibrated units):", value=100, min=1) boxXY
2+
#@Double(label="Crop depth (Z, calibrated units):", value=100, min=0) boxZ
3+
#@boolean(label="Use secondary (filtered) layer, if loaded") useSecondary
4+
#@SNTService snt
5+
#@UIService ui
6+
7+
/**
8+
* file: Crop_Around_Marker.groovy
9+
* author: Tiago Ferreira
10+
* info: Carves out a small region around the last marked location in SNT's Stream-mode BigDataViewer/BigVolumeViewer
11+
* and materializes it as a regular, in-RAM ImagePlus. Streamed big-data sources (N5/OME-Zarr/IMS/BDV-XML) are
12+
* lazy by design, so most classic ImageJ/SNT operations that require full pixel access can't run on them
13+
* directly. This script bridges that gap for the case where only a small, local region is actually needed.
14+
*
15+
* Usage: Press 'M' in the BVV/BDV canvas to mark the location of interest (see the viewer's Markers pane), then run
16+
* this script: it crops around the most recently placed arker, however long ago it was placed.
17+
*
18+
* @see Locations_Montage.groovy, for batch-cropping many locations from a file on disk
19+
*/
20+
21+
snt.requireVersion("5.0.14") // SNT version required to run this script
22+
23+
if (!snt.isActive() || snt.getUI() == null) {
24+
ui.showDialog("SNT does not appear to be running.", "Error")
25+
return
26+
}
27+
plugin = snt.getInstance()
28+
viewer = snt.getUI().getActiveBigViewer()
29+
if (viewer == null) {
30+
ui.showDialog("This script requires SNT's Stream mode (BVV/BDV) to be active.", "No Big Viewer Active")
31+
return
32+
}
33+
if (useSecondary && !plugin.isSecondaryDataAvailable()) {
34+
ui.showDialog("No secondary (filtered) layer is currently loaded. Using the main image instead.",
35+
"Secondary Layer Unavailable")
36+
}
37+
data = (useSecondary && plugin.isSecondaryDataAvailable()) ? plugin.getSecondaryData() : plugin.getLoadedData()
38+
if (data == null) {
39+
ui.showDialog("No image data appears to be loaded.", "Error")
40+
return
41+
}
42+
43+
// Retrieve the last marker placed in the viewer (world/calibrated coordinates), then convert to pixels
44+
markerPos = viewer.getMarkerManager().getLastPosition()
45+
if (markerPos == null) {
46+
ui.showDialog("No marker has been placed yet. Press 'M' in the viewer to mark a location, "
47+
+ "then re-run this script.", "No Marker Found")
48+
return
49+
}
50+
cx = Math.round(markerPos.getX() / plugin.getPixelWidth())
51+
cy = Math.round(markerPos.getY() / plugin.getPixelHeight())
52+
cz = Math.round(markerPos.getZ() / plugin.getPixelDepth())
53+
54+
// Compute crop bounds (pixels), clamped to the data's extent
55+
ndims = data.numDimensions()
56+
hw = Math.round((boxXY / 2) / plugin.getPixelWidth())
57+
hd = Math.round((boxZ / 2) / plugin.getPixelDepth())
58+
min = new long[ndims]
59+
max = new long[ndims]
60+
min[0] = Math.max(0, cx - hw)
61+
max[0] = Math.min(data.dimension(0) - 1, cx + hw)
62+
min[1] = Math.max(0, cy - hw)
63+
max[1] = Math.min(data.dimension(1) - 1, cy + hw)
64+
if (ndims > 2) {
65+
min[2] = Math.max(0, cz - hd)
66+
max[2] = Math.min(data.dimension(2) - 1, cz + hd)
67+
}
68+
if (min[0] > max[0] || min[1] > max[1] || (ndims > 2 && min[2] > max[2])) {
69+
ui.showDialog("The last marker's position falls outside the current image data. Place a new "
70+
+ "marker (M key) over a valid location and try again.", "Invalid Position")
71+
return
72+
}
73+
74+
// Crop and materialize into a regular, in-RAM ImagePlus (inspired by n5-viewer's CropController:
75+
// https://github.com/saalfeldlab/n5-viewer/blob/master/src/main/java/org/janelia/saalfeldlab/n5/bdv/CropController.java)
76+
cropped = Views.zeroMin(Views.interval(data, min, max))
77+
title = "Crop_x${cx}_y${cy}_z${cz}"
78+
imp = ImgUtils.raiToImp(cropped, title)
79+
imp.setCalibration(plugin.getCalibration())
80+
imp.resetDisplayRange()
81+
imp.show()
82+
83+
dimsStr = (0..<ndims).collect { max[it] - min[it] + 1 }.join("x")
84+
posStr = (0..<ndims).collect { [cx, cy, cz][it] }.join(", ")
85+
println("Extracted ${dimsStr} crop centered at pixel (${posStr})")
86+
println("This crop is now regular, in-RAM data: feed it to Weka classifier training, Sholl "
87+
+ "analysis, or any command that requires full random access -- none of which run "
88+
+ "directly on streamed big data.")
89+
90+
91+
// Imports below
92+
import net.imglib2.view.Views
93+
import sc.fiji.snt.util.ImgUtils

0 commit comments

Comments
 (0)