ROIs to TrackMate

Hello @ekatrukha, cc @tinevez,

I have been playing around with @ekatrukha’s StarDist_Trackmate_v2_.py script to track ROIs (see also), and I have a couple of questions.

  1. It looks like there is some sort of shift between the actual particle and the “detection” (magenta circle)

To reproduce run this macro:

run("Set Measurements...", "area  center stack display redirect=None decimal=2");
run("Tracks for TrackMate (807K)");
run("Command From Macro", "command=[de.csbdresden.stardist.StarDist2D], args=['input':'FakeTracks.tif', 'modelChoice':'Versatile (fluorescent nuclei)', 'normalizeInput':'true', 'percentileBottom':'1.0', 'percentileTop':'99.8', 'probThresh':'0.5', 'nmsThresh':'0.4', 'outputType':'ROI Manager', 'nTiles':'3', 'excludeBoundary':'2', 'roiPosition':'Automatic', 'verbose':'false', 'showCsbdeepProgress':'false', 'showProbAndDist':'false'], process=[false]");
roiManager("Measure");

Then @ekatrukha’s StarDist_Trackmate_v2_.py script.

Is this a bug?


  1. I see that in lines 131 to 133 of the script one can change the LINKING_MAX_DISTANCE, GAP_CLOSING_MAX_DISTANCE and MAX_FRAME_GAP

image

But is it possible to change also change the tracker to allow segment spitting and merging?


  1. Is the usage of this script described in the wiki so I can point it out to collegues? I couldn’t find it.

Thank you very much!

1 Like

Hi @LPUoO
could it be that your overlays are shifted by one time point? It looks like it’s plotting the overlays from previous frame into this time frame.

1 Like

Hi @noreenw,
You are probably right. That being said, I can’t reproduce it any more :unamused:

I am getting this error message:

Started New_.py at Tue Feb 16 13:42:35 GMT 2021
Traceback (most recent call last):
  File "New_.py", line 277, in <module>
  File "New_.py", line 119, in create_trackmate
  File "New_.py", line 57, in spots_from_results_table
TypeError: 'NoneType' object is unsubscriptable

	at org.python.core.Py.TypeError(Py.java:236)
	at org.python.core.PyObject.__finditem__(PyObject.java:653)
	at org.python.core.PyObject.__getitem__(PyObject.java:717)
	at org.python.pycode._pyx6.spots_from_results_table$1(New_.py:65)
	at org.python.pycode._pyx6.call_function(New_.py)
	at org.python.core.PyTableCode.call(PyTableCode.java:173)
	at org.python.core.PyBaseCode.call(PyBaseCode.java:150)
	at org.python.core.PyFunction.__call__(PyFunction.java:426)
	at org.python.pycode._pyx6.create_trackmate$2(New_.py:137)
	at org.python.pycode._pyx6.call_function(New_.py)
	at org.python.core.PyTableCode.call(PyTableCode.java:173)
	at org.python.core.PyBaseCode.call(PyBaseCode.java:150)
	at org.python.core.PyFunction.__call__(PyFunction.java:426)
	at org.python.pycode._pyx6.f$0(New_.py:296)
	at org.python.pycode._pyx6.call_function(New_.py)
	at org.python.core.PyTableCode.call(PyTableCode.java:173)
	at org.python.core.PyCode.call(PyCode.java:18)
	at org.python.core.Py.runCode(Py.java:1687)
	at org.python.core.__builtin__.eval(__builtin__.java:497)
	at org.python.core.__builtin__.eval(__builtin__.java:501)
	at org.python.util.PythonInterpreter.eval(PythonInterpreter.java:255)
	at org.python.jsr223.PyScriptEngine.eval(PyScriptEngine.java:57)
	at org.python.jsr223.PyScriptEngine.eval(PyScriptEngine.java:31)
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
	at org.scijava.script.ScriptModule.run(ScriptModule.java:157)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:165)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:124)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:63)
	at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:225)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

No idea how to fix it :roll_eyes:

Does the script run okay for you?

Hi,

Edit: The error seems to say that you are missing a column in your results table. Are you sure the Area column exists?

Regarding the shift, when we moved the script to Groovy, we had to change the line
frame = frames[ i ] to
frame = frames[ i ] -1

Best

Oli

3 Likes

Thank you @oburri,
you are absolutely right, I was missing the Area column. Thank you.

May I ask, why did you move the script to Groovy, and is it publicly available?
And you are correct, with this change now the overlay is correct:

frame = frames[ i ] to
frame = frames[ i ] -1

Thank you!

PS: How did you know that the area column was missing? I always try to read the error messages but they tend to be somewhat abstract for me

1 Like

Gad I could help!

We moved the script to Groovy because we are more comfortable with that language in my group. It’s closer to Java so finding the correspondences between the Java Code of TrackMate and our script is a bit more straightforward without having to translate between languages.

Sure! We made it available here

I checked your error log and saw the line
File "New_.py", line 57, in spots_from_results_table TypeError: 'NoneType' object is unsubscriptable

Assuming the line number was matching the line from the Gist you linked to, it meant that in the line area = areas[ i ] area was of type NoneType, finally meaning that when areas was defined in line 50:
areas = results_table.getColumnAsDoubles( results_table.getColumnIndex( 'Area' ) )

The getColumnAsDoubles must have returned a NoneType. So finally that meant that the column Area was undefined…

4 Likes

Hello everybody,

thank you for finding the mistake in my script (with frame index), I’ve updated my gist.

I am not very good in Python, just tried to adapt things a bit and hoped somebody will jump in (and you did).

I will post a link to this thread in the previous discussion.

Also, I saw some related work in a preprint (final paper) recently, can be helpful.

Cheers,
Eugene

3 Likes

Hello @oburri,

If I create ROIs straight from stardist then ijs-Run-TrackMate-Using-RoiManager-or-ResultsTable works perfectly fine:

run("Set Measurements...", "area  center stack display redirect=None decimal=2");
run("Tracks for TrackMate (807K)");
run("Command From Macro", "command=[de.csbdresden.stardist.StarDist2D], args=['input':'FakeTracks.tif', 'modelChoice':'Versatile (fluorescent nuclei)', 'normalizeInput':'true', 'percentileBottom':'1.0', 'percentileTop':'99.8', 'probThresh':'0.5', 'nmsThresh':'0.4', 'outputType':'ROI Manager', 'nTiles':'1', 'excludeBoundary':'2', 'roiPosition':'Automatic', 'verbose':'false', 'showCsbdeepProgress':'false', 'showProbAndDist':'false'], process=[false]");

// then run ijs-Run-TrackMate-Using-RoiManager-or-ResultsTable sript.

However, when I create myself the ROIs then it doesn’t work (no idea why ?):

run("Fresh Start");
run("Set Measurements...", "area  center stack display redirect=None decimal=2");
run("Tracks for TrackMate (807K)");
run("Command From Macro", "command=[de.csbdresden.stardist.StarDist2D], args=['input':'FakeTracks.tif', 'modelChoice':'Versatile (fluorescent nuclei)', 'normalizeInput':'true', 'percentileBottom':'1.0', 'percentileTop':'99.8', 'probThresh':'0.5', 'nmsThresh':'0.4', 'outputType':'Label Image', 'nTiles':'1', 'excludeBoundary':'2', 'roiPosition':'Automatic', 'verbose':'false', 'showCsbdeepProgress':'false', 'showProbAndDist':'false'], process=[false]");

roiManager("Associate", "true");
//loop over slices
for (i = 1; i <= nSlices; i++) {
    setSlice(i);

//convert label map to ROIs (alternative is run("LabelMap to ROI Manager (2D)"); // requires SCF plugin)
   					getStatistics(area, mean, min, max, std, histogram);
					for (k = 1; k <= max; k++) {
						setThreshold(k, k);
						run("Create Selection");
						
						if(selectionType()>0){
						roiManager("add");
						}
					}
}
// then run ijs-Run-TrackMate-Using-RoiManager-or-ResultsTable sript. (doesn't seem to work properly)

In the macro above I create ROIs by looping thought slices and create ROIs by thresholding 1 grey value at a time and creating selections.

Something else that perplexes me is that my section of the macro to convert the label map to ROIs misses 3/4 of the labels… :thinking:

Thank you very much for your help

Hi @oburri,
The examples I gave in my previous post weren’t very good. So please find below two new examples:

If I run the following macro then your BIOP/ijs-TrackMate - ijs-Run-TrackMate-Using-RoiManager-or-ResultsTable then it works perfectly fine.

newImage("HyperStack", "8-bit composite-mode", 100, 100, 1, 1, 10);
roiManager("Associate", "true");
for (i = 1; i <= nSlices; i++) {
    setSlice(i);
   	makeOval(42, i*8 , 7, 11);
	run("Invert", "slice");
}

run("Command From Macro", "command=[de.csbdresden.stardist.StarDist2D], args=['input':'HyperStack', 'modelChoice':'Versatile (fluorescent nuclei)', 'normalizeInput':'true', 'percentileBottom':'1.0', 'percentileTop':'99.8', 'probThresh':'0.5', 'nmsThresh':'0.4', 'outputType':'ROI Manager', 'nTiles':'1', 'excludeBoundary':'2', 'roiPosition':'Automatic', 'verbose':'false', 'showCsbdeepProgress':'false', 'showProbAndDist':'false'], process=[false]");

// then run BIOP/ijs-TrackMate - ijs-Run-TrackMate-Using-RoiManager-or-ResultsTable

But if I use ROIs that weren’t created with stardist then it doesn’t seem to work. Example below:

newImage("HyperStack", "8-bit composite-mode", 100, 100, 1, 1, 10);
roiManager("Associate", "true");
for (i = 1; i <= nSlices; i++) {
    setSlice(i);
   	makeOval(42, i*8 , 7, 11);
	run("Invert", "slice");
	roiManager("add");
}
// then run BIOP/ijs-TrackMate - ijs-Run-TrackMate-Using-RoiManager-or-ResultsTable

In both cases I run your ijs-Run-TrackMate-Using-RoiManager-or-ResultsTable groovy with the following settings:
image

Am I doing something wrong?
Thank you

It depends on how the rois are created in the roimanager. Like we say in our script, we need the too position available from the getposition() method which is rather contrived

The roimanager tends to store the position of Rois in their name rather than in the position. So you’d need to find a way to set the roi position from the roimanager from a macro. Perhaps @haesleinhuepf knows. Perhaps that’s it.

1 Like

Unfortunately, I can also just to hint to how I did this in Java:
assistant/AnnotationTool.java at 445125ff10b6f6631cc6ba33c80476eed662e59e · clij/assistant · GitHub

1 Like

Thank you both @oburri and @haesleinhuepf,

There are actually 2 macro commands that should set the position of a ROI

Roi.setPosition(slice); // - Sets the selection position. Requires 1.53b.
Roi.setPosition(channel, slice, frame); // - Sets the selection position. Requires 1.52r. 

But I don’t seem to manage to use them as no mater what

Roi.getPosition(channel, slice, frame);
print(slice);

always returns 0

I can reproduce the issue with this macro:

newImage("HyperStack", "8-bit composite-mode", 100, 100, 1, 1, 10);
roiManager("Associate", "true");
for (i = 1; i <= nSlices; i++) {
    setSlice(i);
   	makeOval(42, i*8 , 7, 11);
	run("Invert", "slice");
	//Roi.setPosition(1, i, 1);
	roiManager("add");
}

for (i = 0; i < roiManager("count"); i++) {
	roiManager("select", i);
	Roi.getPosition(channel, slice, frame);
	print("Slice " + slice);
}

It prints Slice 0 for each iteration.

If you un-comment the line Roi.setPosition(1, i, 1); in the first loop, it will work as expected, printing the slice numbers 1 to 10.


A little addition shows the inconsistency between adding via the UI (e.g. by pressing T) vs. using roiManager("add"):

newImage("HyperStack", "8-bit composite-mode", 100, 100, 1, 1, 10);
roiManager("Associate", "true");
for (i = 1; i <= nSlices; i++) {
    setSlice(i);
   	makeOval(42, i*8 , 7, 11);
	run("Invert", "slice");
	//Roi.setPosition(1, i, 1);
	//roiManager("add");
	waitForUser("Please add ROI to manager by pressing T");
}

for (i = 0; i < roiManager("count"); i++) {
	print(i);
	roiManager("select", i);
	Roi.getPosition(channel, slice, frame);
	print("Slice " + slice);
}

This script (in contrast to the version with roiManager("add")) will print the correct slice numbers.

(I tested this with ij-1.53c.jar.)


I’d consider this a bug in ImageJ1. @Wayne, any insight?

Some topics that might be related:

1 Like

The following version of the test macro works as expected. The original version created a hyperstack with 1 slice and 10 frames instead of 10 slices and 1 frame.

newImage("HyperStack", "8-bit composite-mode", 100, 100, 1, 10, 1);
roiManager("reset");
for (i = 1; i <= nSlices; i++) {
   setSlice(i);
   makeOval(42, i*8 , 7, 11);
   run("Invert", "slice");
   Roi.setPosition(1, i, 1);
   roiManager("add");
}

for (i = 0; i < roiManager("count"); i++) {
   roiManager("select", i);
   Roi.getPosition(channel, slice, frame);
   print("Slice " + slice);
}
1 Like

I still see the issue when commenting out the Roi.setPosition line:

newImage("HyperStack", "8-bit composite-mode", 100, 100, 1, 10, 1);
roiManager("reset");
for (i = 1; i <= nSlices; i++) {
   setSlice(i);
   makeOval(42, i*8 , 7, 11);
   run("Invert", "slice");
   //Roi.setPosition(1, i, 1);
   roiManager("add");
}

for (i = 0; i < roiManager("count"); i++) {
   roiManager("select", i);
   Roi.getPosition(channel, slice, frame);
   print("Slice " + slice);
}

prints Slice 0 ten times.

The Roi.setPosition(1, i, 1); seems to be required, but it’s counter-intuitive that it’s not needed when adding the ROIs via the UI, as shown in my post above.

In particular, because:

roiManager("Add");

… is all that gets recorded when performing the adding via UI.

1 Like

Hi @oburri,
I must be making something wrong somewhere but even with the positions available with the Roi.getPosition I can’t get the ijs-Run-TrackMate-Using-RoiManager-or-ResultsTable script to work.

The macro below works fine (using stardist):

//run("Fresh Start");

//create stack with ovals for Stardist
newImage("HyperStack", "8-bit composite-mode", 100, 100, 1, 1, 10);
roiManager("Associate", "true");
for (i = 1; i <= nSlices; i++) {
    setSlice(i);
   	makeOval(42, i*8 , 7, 11);
	run("Invert", "slice");
}

//Create ROIs with Stardist's help
run("Command From Macro", "command=[de.csbdresden.stardist.StarDist2D], args=['input':'HyperStack', 'modelChoice':'Versatile (fluorescent nuclei)', 'normalizeInput':'true', 'percentileBottom':'1.0', 'percentileTop':'99.8', 'probThresh':'0.5', 'nmsThresh':'0.4', 'outputType':'ROI Manager', 'nTiles':'1', 'excludeBoundary':'2', 'roiPosition':'Automatic', 'verbose':'false', 'showCsbdeepProgress':'false', 'showProbAndDist':'false'], process=[false]");

//Check ROIs properties
for (i = 0; i < roiManager("count"); i++) {
   roiManager("select", i);
   Roi.getPosition(channel, slice, frame);
   
   print("ROI " + i + "    is in channel :" + channel + "   ,Slice " + slice+ "    ,frame " + frame);
}

getDimensions(width, height, channels, slices, frames);
print("This stack has " + channels + " channel, " + slices + " slice and " + frames + " frames");
print("The ROIs of this macro are compatible with BIOP/ijs-TrackMate - ijs-Run-TrackMate-Using-RoiManager-or-ResultsTable script")

// then run BIOP/ijs-TrackMate - ijs-Run-TrackMate

And this is the Roi.getPosition output for the ROIs created with Stardist.

However this one where I create myself the ROIs doesn’t work:

//run("Fresh Start");

newImage("HyperStack", "8-bit composite-mode", 100, 100, 1, 1, 10);
roiManager("reset");
for (i = 1; i <= nSlices; i++) {
   setSlice(i);
   makeOval(42, i*8 , 7, 11);
   run("Invert", "slice");
   Roi.setPosition(0, i, 0);
   roiManager("add");
}

for (i = 0; i < roiManager("count"); i++) {
   roiManager("select", i);
   Roi.getPosition(channel, slice, frame);
   print("ROI " + i + "    is in channel :" + channel + "   ,Slice " + slice+ "    ,frame " + frame);
}

getDimensions(width, height, channels, slices, frames);
print("This stack has " + channels + " channel, " + slices + " slices and " + frames + " frames");

//// Rename ROIs exactly like Stardist's output
n = roiManager("count");
for (i = 0; i < n; i++) {
    roiManager("select", i);
    
    name = Roi.getName;
    newname = substring(name,5,lengthOf(name));
    roiManager("Rename", newname);
	}

And this is the Roi.getPosition output for the ROIs not created with Stardist

image.

As far as I can tell the positions of the ROIs and the dimensions of the stack are identical… so I really don;t know what is going on :roll_eyes:

Thank you very much for your help

Roi.setPosition(c,s,f), or Roi.setPosition(s), is required to set the position of ROIs added to the ROI Manager in macros.

This is what is recorded when I press “t” (Edit>Selection>Add to Manager) to add an ROI on slice 64 of a stack to the ROI Manager using the UI:

Roi.setPosition(64);
roiManager("Add");

And this is recorded when I add an ROI on channel=2,slice=4,frame=7 of a hyperstack to the ROI Manager:

Roi.setPosition(2,4,7);
roiManager("Add");

Oh, I see, this behavior seems to have changed in ij.jar version 1.53e and later, whereas an up-to-date Fiji still ships ij-1.53c.jar.

@imagejan, @Wayne, I think I got it.

There are 3 commands to set the position of a ROI:

Roi.setPosition(slice) - Sets the selection position. Requires 1.53b.
Roi.setPosition(channel, slice, frame) - Sets the selection position. 

and

RoiManager.setPosition(i)

and we have also roiManager("Associate", "false"); or roiManager("Associate", "true");


I found that no mater if roiManager("Associate", "..."); is true or false the ROIs the ROIs in this macro are always associated to the correct C, Z or T.
Example macro that creates an HyperStack with 10 C, Z &T:

run("Fresh Start");
newImage("HyperStack", "8-bit composite-mode", 100, 100, 10, 10, 10);
roiManager("Associate", "false"); // or "true"
for (i = 1; i <= 10; i++) {
    Stack.setPosition(i, i, i);
   	makeOval(42, i*8 , 7, 11);
	run("Invert", "slice");
	roiManager("add");
	}

That being said there are cases where the ROIs are not associated with the slices but I can’t make it happen with a macro using the roiManager("Associate", "...") command.


I will use the macro below as the basis for more observations:

run("Fresh Start");
newImage("HyperStack", "8-bit composite-mode", 100, 100, 1, 1, 10);
roiManager("Associate", "false");
for (i = 1; i <= nSlices; i++) {
   setSlice(i);
   makeOval(42, i*8 , 7, 11);
   run("Invert", "slice");
      		//RoiManager.setPosition(i);
			//Roi.setPosition(i);
			//Roi.setPosition(0, i, 0);
   roiManager("add");
      		//RoiManager.setPosition(i);
			//Roi.setPosition(i);
			//Roi.setPosition(0, i, 0);
}
for (i = 0; i < roiManager("count"); i++) {
   roiManager("select", i);
				//RoiManager.setPosition(i);
				//Roi.setPosition(i);
				//Roi.setPosition(0, i, 0);
	//roiManager("update");
   Roi.getPosition(channel, slice, frame);
   print("ROI " + i + "    is in channel :" + channel + "   ,Slice " + slice+ "    ,frame " + frame);
}


RoiManager.setPosition(i); is the command that confuses me the most:
If I run it before roiManager("add"); then

Roi.getPosition(channel, slice, frame);
   print("ROI " + i + "    is in channel :" + channel + "   ,Slice " + slice+ "    ,frame " + frame);
}

always outputs the total number of slices for slice except for the last ROI:
image

and in the ROI properties it is image position 10 except for the last ROI image and the ROIs are no longer associated with a slice

If I run RoiManager.setPosition(i); immediately after roiManager(“add”);` then all the ROIs are set to 10:
image and the ROIs are no longer associated with a slice

If I run RoiManager.setPosition(i); immediately after roiManager("select", i); then Roi.getPosition(channel, slice, frame); outputs
image
but the ROI properties are set to the slice number but shifted by 1 and the ROI is associated to a slice but with a shift of 1 slice. I am guessing this is a bug.


If I run Roi.setPosition(slice) or Roi.setPosition(channel, slice, frame) before roiManager("add"); then everything works as expected:
Roi.getPosition(channel, slice, frame); outputs the expected values and the ROI properties are also as expected.

If I run Roi.setPosition(slice) or Roi.setPosition(channel, slice, frame) immediately after roiManager("add"); then nothing happens and Roi.getPosition(channel, slice, frame); outputs 0 and the ROI position in the properties are set to none.

If I run Roi.setPosition(slice) or Roi.setPosition(channel, slice, frame) immediately after roiManager("select", i); then Roi.getPosition(channel, slice, frame); outputs the correct values but the the ROI position in the properties are still set to none.


And to finish this, if I run roiManager("update"); immediately after roiManager("select", i); without doing anything else then Roi.getPosition(channel, slice, frame); outputs only 0 but the ROI position in the properties are set to the correct values. (if I don’t “update” the roi then the default ROI position in the properties is none )


@oburri,
Now, for BIOP/ijs-TrackMate - ijs-Run-TrackMate-Using-RoiManager-or-ResultsTable scrpt to work properly as far as I can see what matters is that ROI position in the properties are set to the correct values regardless of the Roi.getPosition(channel, slice, frame); outputs. Also in the ROIs properties only the slice should be set image without any information about the other dimensions image
So basically there are different ways of making it work, but in any case what matters is the the ROI properties to be set properly.


So to conclude, it appears to me that the best way to set the position of ROI is to do it after the selection is done but before adding it to the ROI manager using one of this two:

Roi.setPosition(slice) - Sets the selection position. Requires 1.53b.
Roi.setPosition(channel, slice, frame) - Sets the selection position ( //this one is not compatible with the ijs-Run-TrackMate-Using-RoiManager-or-ResultsTable script) . 

Attempting to set the position of the ROI after it was added to the manger may not set the properties properly.


All of this was done with Imagej 1.53g

This is it, I hope this will help others that need to set the correct properties to their ROIs.

The roiManager(“Associate”, boolean) macro function is obsolete. I recommend not using it.

Use

   Roi.setPosition(slice);
   roiManager(“add”);

To set the position of an ROI before adding it to the ROI Manager. This is the macro code that is recorded when you press ‘t’ (Edit>Selection>Add to Manager) to add an ROI to the ROI Manager.

Roi.setPosition(slice) sets the positions of all selected ROIs in the ROI Manager.

This code

   RoiManager.setPosition(slice);
   roiManager(“add”);

does not work because RoiManager.setPosition() only works with selected ROIs already in the ROI Manager.

This code

   roiManager(“add”);
   RoiManager.setPosition(slice);

does not work because the newly added ROI is not selected.