How to convert a path ROI into individual points ROI

Background

Hello, so this is my problem. I managed to extract tracings from a very old version of Stereoinvestigator, I converted them to.swc files, opened them in Simple Neurite Tracer and then converted them to ROI’s in the ROI manager. However, I have now come to a new problem.

What I want to achieve is this 1 roi (Path 1-XY… in ROI manager), to be broken down into all individual points. The problem is that this is recognised as a path when in fact it was just a lot of markers done in Stereoinvestigator. So as you see in the image, a path is shown as a unique ROI, and I want to extract every single point in this path as each curve of this path is a individual neuron.
So how do I break down this ROI into around 400 single point roi’s that each have a X,Y coordinate from this path?

I have tried this script in SNT (Exporting x,y,z coordinates for every point along a path - #9 by tferr) and I get the output from every single in the console. Maybe it would be easier to extract the single points from here?


Thank you in advance for any help. I am not vell versed in macro’s (except the macro recorder) and I cannot figure out how to extract this information and convert it to single point ROI’s.

Kindest regards,
Dinko

@Dinko_Smilovic ,

Here is a version of that Python script that converts every node into a stand-alone point ROI:

#@File (label="SWC file (assumed to be in 'pixel coordinates')") traces_file
#@File (label="Image file (optional)", required=false) image_file
#@UIService ui

from sc.fiji.snt import Tree
from ij import IJ, ImagePlus
from ij.gui import PointRoi
from ij.plugin.frame import RoiManager as RM

'''Converts every node in a SWC file into a PointROI '''

imp = None if not image_file else IJ.openImage(str(image_file))
trees = Tree.listFromFile(str(traces_file))
if not trees:
    ui.showDialog("Could not retrieve coordinates. Not a valid file?")
else:
    rm = RM() if not RM.getInstance() else RM.getInstance()
    for tree in trees:
        for node in tree.getNodes():
            roi = PointRoi()
            roi.setPointType(PointRoi.DOT)
            roi.setSize(5)
            if (imp):
                imp.setPositionWithoutUpdate(imp.getC(), int(node.z), imp.getT())
            roi.addPoint(imp, node.x, node.y)
            rm.addRoi(roi)

    rm.runCommand("Show All")
    rm.setVisible(True)

Dear Tiago

Thank you for this script! It works - kindof. It converts all points to ROI’s, however, all of them are concentrated at 1 tiny spot on the top left of the image

.
Maybe the coordinates need to be multiplied by a 1000? (Wrong scale/measure?)
If it needs to be multiplied by a factor different than a 1000, if you put it in the script I can figure out where you put it and modify it accordingly.

Thank you!,
Dinko

Yes. it assumes the paths were defined in pixel coordinates (somehow I thought that was the case!?). You would have to scale each node by the pixel/voxel size. But if it is like this, the best is to convert within SNT, so that there is no need to keep track of spatial settings:

  1. Load the file and image into SNT
  2. In SNT, run Scripts → New… and choose ‘python’, then paste the following (a flavor of the script above):
#@SNTService snt
#@UIService ui

from sc.fiji.snt import Path
from ij.gui import PointRoi
from ij.plugin.frame import RoiManager as RM

'''Converts every single node of the all paths in the active SNT instance '''

if not snt.getUI():
    ui.showDialog("SNT does not seem to be running", "Error")

paths = snt.getPaths()
if not paths:
    ui.showDialog("There are no paths to convert", "Error")

rm = RM() if not RM.getInstance() else RM.getInstance()
imp = snt.getPlugin().getImagePlus()
for path in paths:
    for nodeidx in range(path.size()):
        roi = PointRoi()
        roi.setPointType(PointRoi.DOT)
        roi.setSize(5)
        if (imp):
            imp.setPositionWithoutUpdate(imp.getC(), path.getZUnscaled(nodeidx), imp.getT())
        roi.addPoint(imp, path.getXUnscaled(nodeidx), path.getYUnscaled(nodeidx))
        rm.addRoi(roi)

rm.runCommand("Show All")
rm.setVisible(True)

BTW, is this some sort of limitation of Stereoinvestigator?

Dear Tiago,

Thank you, it works perfectly now!

I think this is a limitation of Stereoinvestigator, it is really hard to use the data done in that program elsewhere.
This problem is done now, and I want to thank you all here that helped me with scripts to make it work.
The idea was to use tracings done in Stereoinvestigator (for which we have a around 15-20% of the brains used in the project, and they were done over 10 years ago) to train and check the automatic cell counting (using thresholding, binary functions and analyze particles) so that we can speed up this process.
I have to first convert the tracing files (.xml or .dat) to .swc, for which I use HBP Neuron Morphology Viewer to convert.

Next up, we have scripts that the community here helped me write and optimize!
I have to convert the tracings files for the ROI’s where we will analyze particles (brain layers), for which I use this script (the borders of the ROI, not the individual points) written in .groovy.
The rotation and resizing is because this Stereoinvestigator was connected to a motorized stage and it flips the image / tracings when you load both of them in SNT. Also, a wrong scale was set in stereoinvestigator (which I checked by looking at the original slides) so I have to downscale the image by 0.6215.

#@ 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
import ij.io.FileSaver

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”);

#@ File (label=“Tracings file :”, style=“file”, required=false) recFile

tree = new Tree(recFile.getAbsolutePath())

    imp = IJ.getImage();
height = imp.getHeight()

   tree.translate(0, height, 0)
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)

Then the problem with Stereoinvestigator is that even though the path files for the borders were closed, it does not close them when those traces are converted to .swc (I don’t get a closed polygon roi, but a open one). To go around this I use this script for each polygon area ROI

roiManager(“Select”, 0);
Roi.getCoordinates(xpoints, ypoints);
xstart=xpoints[0];
ystart=ypoints[0];
xend=xpoints[lengthOf(xpoints)-1];
yend=ypoints[lengthOf(ypoints)-1];
makeLine(xstart,ystart,xend,yend);
roiManager(“Add”);
roiManager(“Select”, newArray(0,4));
roiManager(“Combine”);
roiManager(“Add”);
roiManager(“Select”, 5);
run(“Create Mask”);
run(“Fill Holes”);
run(“Create Selection”);
roiManager(“Add”);
close();

Once I have this I can finally analyze particles to see how many neurons are in each layer, using this script:

selectWindow(“Flipped.tif (green)”);
run(“Duplicate…”, " ");
run(“Duplicate…”, " ");
run(“Duplicate…”, " ");
selectWindow(“Flipped.tif (green)”);
setAutoThreshold(“Default dark”);
//run(“Threshold…”);
setThreshold(50, 255);
run(“Convert to Mask”);
run(“Open”);
run(“Erode”);
run(“Fill Holes”);
roiManager(“Select”, 0);
run(“Analyze Particles…”, “size=15-150 display add”);
saveAs(“Results”, “C:/Users/smilo/Desktop/Testiranje_BANOVAC_TRACING/Testiranje_2/Skripte/AnalyzeParticles_Green_Layer1.csv”);
Table.deleteRows(0, 10000);
roiManager(“Delete”);

This script you helped me with here is to allow me to see the training data. The results that I get from the last script (analyze particles), I save as a mask and then check if the automatic counting is within 95% of neurons found by hand. Once the parameters (mostly the tresholding) are fine for multiple different slides of the same staining, I can be sure that the automatic counting will do a good job and will apply it to all of the around 300 slides.

Once again, thank you for your help!

1 Like