Simple Neurite Tracer import function as a script in ImageJ

So I have a lot of images that have .swc tracings done on an old version of the StereoInvestigator program.
I want to open the images associated with the tracings, open the tracing files and convert them to ROI’s, threshold the image and then run the Analyze particles on each individual ROI so that I can get the numbers of positive cells in each ROI.

Using the macro recorder, I have done a script in ImageJ that would, with the image where the tracing was done opened:
scale the image (since the tracings were done on a weird scale that didn’t correspond to the image), Open the image in SNT (simple neurite tracer),
Import the .swc tracings in SNT with specified parameters (since the StereoInvestigator tracings flipped and moved the traces)


Offset
Convert these traces to ROI’s and then save them. A different script will go through each ROI and threshold+analyze particles in them, and this one works.

I cannot record the import .swc tracings in the ImageJ MacroRecorder, and I can’t figure out how to script this. My current script looks like this:

macro "Flipped [f]" {
	       
	run("Rotate... ", "angle=180 grid=1 interpolation=Bilinear");
	run("Flip Horizontally");
	x=getWidth()*0.6215; 
	y=getHeight()*0.6215;
	run("Size...", "width=x height=y depth=1 constrain average interpolation=Bilinear");
	run("Set Scale...", "distance=1 known=1 unit=micrometer");
	run("SNT...", "imagechoice=ZADNJA_POTVRDA_Intensity_1Z_CH.ome uichoice=[Memory saving: Only XY view] channel=1");

*/
**This part here is where the tracings would be imported** 
Replace existing paths YES
File uses piel coordinates YES
Apply offset to file coordinates = x=0; **y=ImageHeight**; z=0
*/
	run("ROI Exporter", "roichoice=[path segments] viewchoice=[XY (default)] useswccolors=true avgwidth=false discardexisting=true");
	roiManager("Select", newArray(0,1,2,3));
	run("Select All");
	roiManager("Save", "C:/Users/smilo/Desktop/Testiranje_BANOVAC TRACING/Testiranje 2/RoiSet.zip");
}

I appreciate any help concerning this problem.

I have found a possible solution in another topic: Converting .swc traces to ROIs from a script

run(“Tracings (Traces/(e)SWC)…”, “open=C:\trace.swc apply_spatial voxel_width=1 voxel_height=1 voxel_depth=1 unit=pixel x_offset=0 y_offset=0 z_offset=0 x_scale=1 y_scale=1 z_scale=1 render=[2D ROIs (stored in ROI Manager)]”);

But when I try to apply this to my script it gives me a error that I am missing a “(” although all of the () are closed.

I think that you need to use two backlashes when giving paths. So instead of

open=C:\trace.swc

it should be

open=C:\\trace.swc

I changed the script in ImageJ to have 2 backlashes, but it didn’t help. Now I’m getting the “Undefined identifier in line X” error.
Could this be due to me using the ImageJ Plugin macro function and not the SNT - Scripts - New Script (Language - Python?).
So my thoughts are since the macro recorder does not record only this step of the workflow, is it because this step is done inside SNT? So it can open an image, It can convert traces to ROI’s, but it can’t do the function inside SNT (File-Import-e(SWC)…).
Does this mean I have to write this line in SNT scripts and then somehow make a function that the script in imageJ calls to?

Yes. By default the Macro Recorder only records calls from a GenericDialog (the default modal dialog in ImageJ). Typically, the recorder is not aware of plugins with their own GUI.

Yes. SNT does not support the IJ macro language directly but it has extensive scripting capabilities. You can browse more than 30 scripts in the Script Editor under Templates>Neuroanatomy>. (NB: there is already one script that extracts ROIs from a SWC: Templates>Neuroanatomy>Skeletons and ROIs>Convert_Reconstruction_To_ROIs (source code). It is also possible to run SNT commands using a ‘runCommand()’ call akin to the built-in run() macro function. E.g., in a python script you could run the following:

#@SNTService snt
if snt.getUI():
    snt.getUI().getPathManager().runCommand("Convert to ROIs...", "Tips")

Even if clumsy, there are ways to mix macro language with scripting languages. E.g.:1) IJ has built-in macro functions to call (j)python and BeanShell code; and 2) It is possible to register scripts in IJ’s menu structure. Once registered, such scripts can be recorded as regular commands.

@Dinko_Smilovic, I must say I am a bit confused about your macro. What are the “ROI Exporter” and “Tracings (Traces/(e)SWC)…" commands? Anyway, this is what I would do: 1) Write a single script that imports the file, applies the offset, and extracts the ROIs; Then I would complete the script by setting the built-in Macro Recorder to one of the supported languages, e.g., python.

To get you started, here is a minimal script in python:


from ij import IJ
from sc.fiji.snt import Tree
from sc.fiji.snt.analysis import RoiConverter

# Documentation Resources: https://imagej.net/SNT:_Scripting
# Latest SNT API: https://morphonets.github.io/SNT/

# Import tree and apply offset
tree = Tree("path/to/swc/file.swc")
tree.translate(0, 4308, 0)

# Access the image
imp = IJ.getImage()
### Run calibration, using recordable calls

# Extract ROIs and add them to the overlay of image
converter = RoiConverter(tree, imp)
converter.convertPaths()
converter.convertBranchPoints()
converter.convertTips()
imp.show()

## See Convert_Reconstruction_To_ROIs.groovy for other options

Of course you could also use the tips above to insert such script into your IJM macro…

Thank you for your help!

I haven’t gotten your python script to work since I need the ROI’s in the ROI manager and not as a overlay of the image. I have then decided to work on the Convert_Reconstruction_To_ROIs.groovy script.
I am not a programmer by trade so this is all a bit confusing. This script works so far, but I want to adapt the tree.translate function so that for height it isn’t hard coded at 4308, but that it puts the value of the image height in pixels there (this specific image is 4308 pixels high, others differ). I tried to search how to get the height property of an image file in groovy, but was unlucky so far.

#@ File (label="Tracings file :", style="file", required=false) recFile
#@ File (label="Original image:", style="file", required=false) impFile

#@ SNTService snt

import ij.IJ
import sc.fiji.snt.Tree
import sc.fiji.snt.analysis.RoiConverter
import ij.gui.Overlay
import ij.plugin.frame.RoiManager

    tree = new Tree(recFile.getAbsolutePath())
    tree.translate(0, 4308, 0)
    if (impFile) {
        imp = IJ.openImage(impFile.getAbsolutePath())
    } else {
        // Use skeleton image so that
        // drawn ROIs are visible
        imp = tree.getSkeleton2D()
    }
    tree.assignImage(imp)


// Option 2: Store ROIs in the ROI Manager
converter = new RoiConverter(tree)
holdingOverlay = new Overlay()
converter.convertPaths(holdingOverlay)


rm = RoiManager.getInstance2()
if (rm == null) rm = new RoiManager()
for (roi in holdingOverlay.toArray()) rm.addRoi(roi)
rm.runCommand("sort")
rm.setVisible(true)

After this works, and I have the script ready in SNT, how do I connect it to the rest of the script in ImageJ macro’s? Do I have to have the ImageJ Macro Recorder set to Java language (because the SNT script is in .groovy) and then call this script in SNT into the script in ImageJ? How do you call a script from SNT to ImageJ?

Great! Don’t be bogged down by the language being used (Python, Groovy, etc.). These type of simple scripts will for the most part look the same across languages, because they only make calls to the ImageJ/SNT API. Generally speaking, at this level everything looks ‘the same’ across languages, with just the required differences to accommodate the syntax of the scripting language. Typically with these <20line scripts, this means minor tweaks in for loops, if conditions, etc.

In the script, the variable ‘imp’ is your reference to the Image (an ImagePlus object). If you look at the ImagePlus API, you will find that you can access its width using:

width = imp.getWidth()

from that point on, you can translate the tree using width. I would sincerely encourage you to read a scripting tutorial. imagej.net has links to several resources, including to the superb tutorials by albertcardona. E.g., do read this introductory tutorial. It will be the most productive half-an-hour of your time, and you will understand clearly what imp is.

See my suggestions above. But I’m convinced you don’t need it, now that you started modifying the script.

Latest versions of ImageJ record in BeanShell, Python, JavaScript and Java. For Groovy, BeanShell recording is perfect: You can simply copy and paste contents from the recorder.

Once you are done with your changes, don’t forget to post here your final script, so that others can re-use it!

Thank you! These 2 days I learned a lot. As requested, I am leaving the final script here.

This script is written in Groovy, and it has 2 parts.
The first part does changes to the open image, flipping, rotating, resizing and applying scale to it, so that it is identical to the image used for tracings in an old version of StereoInvestigator.
The second part opens the tracings file of the image, transposes the tracings so they fit the image, and then exports the tracings as ROI’s to the ROI manager.


#@ SNTService snt
import ij.IJ
import sc.fiji.snt.Tree
import sc.fiji.snt.analysis.RoiConverter
import ij.gui.Overlay
import ij.plugin.frame.RoiManager
import ij.ImagePlus

// Adjust image (NB: this could be simplified)
imp = IJ.getImage();
IJ.run(imp, "Rotate... ", "angle=180 grid=1 interpolation=Bilinear");
IJ.run(imp, "Flip Horizontally", "");
x = imp.getWidth()*0.6215;
x = x.intValue();
y = imp.getHeight()*0.6215;
y = y.intValue();
imp.resize(x.intValue(), y.intValue(), "bilinear");
IJ.run(imp, "Size...", "width=${x} height=${y} depth=1 constrain average interpolation=Bilinear"); 
IJ.run(imp, "Set Scale...", "distance=1 known=1 unit=micrometers");

// Load reconstruction and apply offset to it
#@ File (label="Tracings file :", style="file", required=false) recFile
tree = new Tree(recFile.getAbsolutePath())
height = imp.getHeight()
tree.translate(0, height, 0)

// Store ROIs in the ROI Manager
tree.assignImage(imp)
converter = new RoiConverter(tree)
holdingOverlay = new Overlay()
converter.convertPaths(holdingOverlay)
rm = RoiManager.getInstance2()
if (rm == null) rm = new RoiManager()
for (roi in holdingOverlay.toArray()) rm.addRoi(roi)
rm.runCommand("sort")
rm.setVisible(true)

Great! I did some minor corrections for improved readability and marked it as solution. Eagerly awaiting your next script!