How to annotate and save data for multiple ROI intersections for a given ROI

I’ve written a plugin that analyzes skeletal muscle fiber size, type, and
central nuclei. Below is an example of my code for how I analyze central
nuclei. It works perfectly for central nuclei, as there is ever only going
to be one central nuclei in a fiber and the end results is a results page
that lists fiber number, fiber type, area, and either “1” if there is a
central nuclei, and “0” if there isn’t one. The problem with regular nuclei
is that most of the fibers have more than one nuclei, so that fiber number
is simply listed multiple times, and I end up having a list that I can’t
simply put into an array and make it a column in my results. The code ends up printing a list of all ROIs that have an intersection, and when there are more than one intersection the code just prints that ROI multiple times. For example, if
fiber #35 has 3 nuclei, the program prints out “35” three times. How to I
get the program to denote that there are 3 intersections with fiber #35, and
not a list with “35” written 3 times?

for (i=0;i<counts; i++){ 
  for (j=0;j&lt;roiManager(&quot;count&quot;);j++){ 
    roiManager('select',newArray(i,j)); 
    roiManager(&quot;AND&quot;); 
    if ((i!=j)&amp;&amp;(selectionType>-1)) { 
    print(i); 
                logString = getInfo("log"); 
    } 
  } 
} 
if (isOpen("Log")) { 
   	run("Clear Results"); 
        roiManager("reset"); 
        roiManager("open", Results+"ROISet.zip"); 
        selectWindow("Fiber Borders"); 
        run("From ROI Manager"); 
        roiManager("multi-measure append"); 
        updateResults(); 
        setResult("Central Nuclei", logString, 1);

Hi @LyleB

I have taken the liberty of formatting your code for readability (which is probably you didn’t get much help here yet…).
Please look at how I edited your post so that you may format code properly next time, makes it easier for everyone :slight_smile:.
I also had an issue with the “quotes” that you used… you have what are called ‘smart quotes’ like “reset”, but code needs plain quotes like "reset". If you copied your code from Word or an equivalent program, be careful about that… copied from the script editor should not have this issue.

It is usually not very good practice to pick up results from the log so here is an attempt at using Results Tables. If you’d like further help, may I recommend that you post a ROISet.zip and image files so that your request becomes a bit more clear (Are you using stacks? Multichannel Images?)

What do you use this command for? It seems to currently have a bug with the code I have made, so I will notify @Wayne

This line should give you an error as it is not written properly. should be setResult("Central Nuclei", 1, logString);

A recommendation would be a code like this one:

// For ImageSc forum post: https://forum.image.sc/t/how-to-annotate-and-save-data-for-multiple-roi-intersections-for-a-given-roi/30416?u=oburri
// By Olivier Burri, BSD 3.0 License


// Get the number of elements to work on
counts = roiManager("Count");

// Create an Array that will contain the counts for each nucleus
nuclei_counts = newArray(counts);

// Loop and increment the count of there is an intersection
for (i=0; i<counts; i++){
	nuclei_counts[i] = 0;
	for (j=0; j<counts; j++){
		roiManager("select",newArray(i,j));
		roiManager("AND");
		
		if ( ( i != j ) && ( selectionType != -1 ) ) { // If the selection type is not -1 (-1 means no selection)
			
			// Increment the count, equivalent to nuclei_counts[i] = nuclei_counts[i] + 1;
			nuclei_counts[i]++;
		}
	}
}

// Know how many results are currently available, for appending
nr = nResults;

// No need to close the ROI manager, we can simply "deselect"
roiManager("Deselect");
selectWindow("Fiber Borders");
roiManager("Show All without labels");

roiManager("Measure");

// This adds a new column to the results table called 'Central Nuclei', which contains what you want I think
for (i = 0; i < counts; i++)
	setResult("Central Nuclei", nr+i, nuclei_counts[i]);

Please read the code I have provided and let me know if you have any questions.

Best

Oli

1 Like

Oli,

First off thank you so much for your help, time and effort. I am not using stacks (I don’t think) but I am using a multi-channel image (4 channels: membrane, fiber type 1, fiber type IIa, Nuclei), and the portion of the code I posted in a small part of the plugin I wrote.

"roiManager(“multi-measure append”); "

The reason I used this command is to recall all the ROIs from the muscle fibers and put them back into the results table. After the “setResult” command in the last line, the results table is completed and saved. Below is the fist part of this portion of the code that use to identify and count central nuclei, just in case this helps clarify what I’m trying to do.

if (isOpen(“DAPI”)) {
roiManager(“open”, Results+“ROISet.zip”);
counts=roiManager(“count”);
for(i=0; i<counts; i++) {
roiManager(“Select”, i);
run(“Enlarge…”, “enlarge=-5”);
roiManager(“Update”);
}
selectWindow(“DAPI”);
run(“Enhance Contrast…”, “saturated=3”);
setAutoThreshold(“Otsu dark”);
setOption(“BlackBackground”, true);
run(“Analyze Particles…”, “size=1.0–Infinity circularity=0-1.00 display exclude summarize add”);
roiManager(“Show All without labels”);

This command:
“setResult(“Central Nuclei”, logString, 1);”
actually works just fine for what I’m using it for, and adds the number “1” next to ROIs that have a central nuclei, and a “0” next to all ROIs with out one. If I switch the logString and number then the program’s output says that fiber #1 has 9 central nuclei (which is impossible), where its actually fiber #9 has 1 central nuclei. I agree that storing info in the Log isn’t what I should be doing and there is certainly a better way of doing this, but I am a novice. If there is more than one central nuclei though, my code would break down.

I am going to spend some time with your suggestions today, I will most likely have questions.

Again, thanks so much.

Oli,

Your suggestions worked perfectly and my plugin is now complete. Thank you so much.
I do have two questions, more for my own understanding of how IJ code works. First, in what I quoted below, what does “nuclei_counts[I] = 0” do? Why is this needed?

Also, in your suggestions, you suggested I use the code below:
for (i = 0; i < counts; i++) {
setResult(“Myonuclei”, nr+i, nuclei_counts[i]);
}

However, when I did this the program added all nuclei data to rows beyond my results (results in rows 1 through 71, nuclei data was put in rows 72 through 142). When I took the “nr+” out the data was placed in the correct rows. I’ve seen little things like this a lot through out writing this macro and still don’t really understand why sometimes something like that is needed, and other times it is not. Is there maybe something else in my code that makes “nr+” uneccessary?

Thanks!

To be fair that is a vestige of my old C programming days and you can omit it. But for completion’s sake here is the explanation.

The line nuclei_counts = newArray( counts ) creates a new array with count elements. In the macro language, this array is initialized with a value of zero for each element.

In C, what was happening is that the memory was allocated ( reserved in the RAM ) but not initialized, which means that the value could be 0 or could be anything. So we needed to make sure to initialize each element of the array to 0. In the current case, you can definitely omit that line :slight_smile:

Because I saw that you were using append with the multi-measure command, I thought that you were going to measure multiple images and append the results.

The idea was to first see how many results are in the table using nr = nResults before running your own measurements. This nr would then represent how many rows were present in a previous run.

But I am glad that it worked out for you. If you want further information or comments, feel free to share your code with me in a private message and I can help you figure out why it was not necessary for you.

Best

Oli