How do I exclude certain regions of an image I want to analyze?

histology
fiji
imagej
macro
binary

#1

Hi all, so I have this binary image I want to draw a line across and measure lengths in. I have gotten that far (I am able to automate line drawing and measuring those lines). The issue I am having is that I want to EXCLUDE regions greater than a certain length (so if I have an image of 30 black circles in a row on a white background with arbitrary diameters ranging from 15 pixel units to 100 pixel units, but i do not know the distribution of these circles in my images, I want to be able to EXCLUDE any diameter >= 30). The only thing is I want a macro that does what I need because I have 100 images and i need to analyse 100 lines in each image and I don’t want to manually determine which distance is >=30 for each line in each image… So any help how to code this or approach this would be appreciated.

Note: the circles are just examples. I have a tissue histology section in which I want to exclude bronchiole lengths and just include alveolar wall lengths. In the image I have uploaded, I have shown example lines and the regions they intersect. I want to be able to exclude any black region >= 30um (~50 pixels I think…) that intersects with my line and then subtract that length out from the total length of the line (for each line, respectively) in an automated fashion. Please let me know if anyone has any suggestion


#3

Good day!

I’d think of at least two solutions:

The first acts directly on the image content and eliminates objects above a certain area, the second acts on the line profiles and excludes parts above a certain length which, however, needs more coding effort.

Here is a demo macro for the first approach:

run("Blobs (25K)");
setAutoThreshold("Default");
setOption("BlackBackground", true);
run("Convert to Mask");
run("Analyze Particles...", "size=600-Infinity show=Nothing add");
roiManager("Select", Array.getSequence(roiManager("count")) );
roiManager("Fill");
exit();

Paste the above macro code to an empty macro window (Plugins >> New >> Macro) and run it.
(You need an open internet connection to load the demo image.)

For your images you have to enter the appropriate area value area in
"size=area-Infinity".

Regards

Herbie


#4

Hi Herbie,

Thank you so much for your feedback. Unfortunately I do not know how to apply that to my histology section. I realised if it really was just circles it would be easy, but my image at hand is actually the tissue section. Since everything is interconnected it seems harder to use Analyze Particles. Any suggestions how to approach the tissue section issue?

Thanks,

Abi


#5

Hi Abi, if what you want is a measure of the distribution (average etc.) of alveolar thickness in your images, then I think the lines approach could be difficult - just one problem would be that parts of alveolar walls that are intersected longitudinally by your lines would be excluded.

I ran the “Local Thickness” plugin on your image and the result looks interesting. You could work with that to exclude “too thick” areas of the images automatically and then get the average alveolar wall thickness from the image histogram. That way you would also extract more information from each image. Good luck.

David


#6

I’m not clear about what you really want. I think the white objects are the signal and black is the background. Furthermore I understand that the large white areas are not of interest, so why not erase them?

I can’t apply the above macro approach to your sample image because of the drawn lines. Could you please post the sample image without the drawn horizontal lines? And please do not use the JPG-format, use PNG or TIF of the original binary image.

Regards

Herbie

ADDITION:

With these macro code lines

run("Analyze Particles...", "size=50000-Infinity show=Nothing add");
roiManager("Select", Array.getSequence(roiManager("count")) );
roiManager("Fill");
exit();

this

is what I get from your sample image after removal of the drawn lines and the surrounding white image border.


#7

Hi Dr. Bragason,

Thank you so much for your feedback. Where can I find the Local Thickness plugin? I don’t see it on the default plug-in drop down menu in ImageJ. Also, I looked up the function on the imageJ website (which I couldn’t find a download link for either), and it looks like something that would be really useful for me. Thank you for your suggestion.

Abi


#8

Hi Herbie,

Thank you so much for updating me with how the Analyze Particles would work on this. I have another big question now. So I when I draw a line across the image (my original image), I get essentially a square wave plot with minima (white) and maxima (black) when I run the command “Plot Profile”. Then I go to the BAR menu and run Data Analysis -> Find Peaks. That returns me the graph with the labeled minima and maxima, as well as a table of “Plot Values”.

A) Say that the graph has 15 minima and 16 maxima. How do I store the X1 (minima) and X2 (maxima) columns from the “Plot Values” table into arrays called “minima” and “maxima” respectively? I have had a very hard time exporting values from that table in ImageJ… I don’t want to have to manually copy and paste into excel, because I want to use it for bulk calculations on bulk images. Anyway I can go about this?

B) The plot also displays the number of minima and maxima on top in blue and red font respectively. How do I go about storing the number of minima and maxima in separate arrays called “numMin” and “numMax”? so that I can update it with values from images from the same data set.

Essentially in the end, for each line I draw across the image, I want to temporarily store the X1 and X2 columns in arrays so I can run analysis on it and store the numMin and numMax as global variables that I can keep updating. I would really appreciate your and anyone else’s help on these if possible.

Thanks!

Abi


#9


#10

I have no experience with “BAR” (I never used it).

I still assume that you are interested in the white areas of the binary sample image and that you like to see the intersection lengths of these white areas with 100 equidistantly arranged horizontal lines.

Do you like to see the intersection lengths ordered according to the horizontal lines or all lengths per image?

In any case, an Imagej macro would help.

Regards

Herbie


#11

Hi Abi,

The Local Thickness plugin is actually under the “Analyze” menu item. As with any command in ImageJ, you can easily find it by hitting “L” on the keyboard, which gives you the “Command Finder” that you can use to find any command (plugin).

But the problem is that we don’t know what you want! You’ve written about lines, intersections etc., but we don’t know what you are after in biological terms. I’ve been assuming you are studying the thickness of alveolar tissue (BLACK in your image) where Local Thickness would be great, whereas @Herbie is focusing on the WHITE, which I know are air-filled spaces and could indeed be studied using Analyze Particles to give you e.g. information on alveolar diameter.

D


#12

Here is an ImageJ-macro that starts with your binary image, does the pre-processing, and writes the summed length of objects (in pixels) per horizontal line to the log-window:

requires("1.51w");
n = 100;
maxArea = 15000;
setBatchMode(true);
run("Canvas Size...", "width="+(getWidth()-6)+" height="+(getHeight()-6)+" position=Center");
run("Analyze Particles...", "size="+maxArea+"-Infinity show=Nothing add");
roiManager("Select", Array.getSequence(roiManager("count")) );
roiManager("Fill");
close("ROI Manager");
print("\\Clear");
w = getWidth();
h = getHeight();
n--;
d = floor( h / n );
y = round( ( h - n * d ) * 0.5 );
bot = h - d;
idx = 0;
do {
	makeRectangle(0, y, w, 1);
	totZeros = zeroLengths();
	y += d;
	idx++;
	//print( ""+idx+"\t"+totZeros );
	print( totZeros );
} while ( y<bot );
run("Select None");
setBatchMode(false);
exit();
function zeroLengths() {
	p = getProfile();
	totLength = 0;
	for ( i=0; i<p.length; i++ ) { 
		if (p[i]==0) totLength++;
	}
	return totLength;
}

Paste the above macro code to an empty macro window (Plugins >> New >> Macro) and run it.

Consequently and for n = 100, hundred numbers are written to the log-window.

If you need the individual lengths per horizontal line, i.e. not their sum, then a corresponding macro becomes slightly more complicated.

HTH

Herbie


#13

Hi Herbie and Dr. Bragason,

I am interested in actually the alveolar wall thickness (I am looking at the mean linear intercept) and I want to exclude the bronchiolar regions (the thick black regions). The extra information that you provided, Herbie for the air space is useful as well, because I will need that information, but I am also in need of the mean linear intercept (the intersection of the horizontal line with the black lines in the image). But the only issue is for each line drawn in the image, I need to subtract out the lengths of the bronchiolar region (thick black) and not count those intercepts.

https://imagej.net/BAR#Installation – Here is the link to BAR.

Also, here is my code that I have for making the line and measuring the number of intercepts:

l = getWidth();
//---- VARIABLE: Depends how many lines you want -----//
k = 5;
// ---------------------------------------------------//    
h = getHeight()/k;
for (i = 0; i < k; i++){
	selectWindow("binary");
	makeLine(0,h*i+h/2,l,h*i+h/2,1);
	// you can start measuring from any altitude you want by modifying the "+h/2" part. 
	//If you want to start at altitude of "0", simply delete the "+" portion
	run("Plot Profile");
    run("Find Peaks", "min._peak_amplitude=254.99 min._peak_distance=0 min._value=[] max._value=[]");
}

In the earlier posted image, Any minimum is my intercept with black and any maximum is intercept with white. This is where the “Plot Values” table comes in. I am not sure how to store the values in arrays as I mentioned in my earlier post. Any help with that would be appreciated as well.

Thank You,

Abi


#14

I think my macro does what you want.
Do you understand its function and the meaning of the output numbers?

If you need the mean, it can be computed quite easily.
Do you need the mean per line or per image?

Regards

Herbie


#15

Hi Herbie,

I’m not sure it is quite what I’m looking for. Because with the code I have posted, the “Plot Values” gives a table (overridden each time by each new line drawn) of the position of intercepts (X1 being minima and X2 being maxima), which is what I am looking for. I want to be able to work with those values through a macro by storing in array.

Thanks,

Abi


#16

Presently my macro prints the sum values per line to the log-window but they can also be written to an array.

My question is, whether this is what you like to get because your explanations are still not quite clear and I want to avoid changing my approach after every exchange of posts.

Please clearly answer the following questions:

  1. Do you want the mean of the lengths of the intersections of the lines with the white objects?
  2. Do you want the mean lengths of the intersections of every line or that from all lines of an image.
  3. In which form do you like to get the mean values?
    (Presently you get the summed lengths per line as values in the log-window. You may get them as a column or row in the results window, or you may get them as a macro array. The same holds for the mean values when implemented.)

Regards

Herbie


Macro that lists the mean length per scan-line:

requires("1.51w");
n = 100;
maxArea = 15000;
setBatchMode(true);
run("Canvas Size...", "width="+(getWidth()-6)+" height="+(getHeight()-6)+" position=Center");
run("Analyze Particles...", "size="+maxArea+"-Infinity show=Nothing add");
roiManager("Select", Array.getSequence(roiManager("count")) );
roiManager("Fill");
close("ROI Manager");
print("\\Clear");
w = getWidth();
h = getHeight();
n--;
d = floor( h / n );
y = round( ( h - n * d ) * 0.5 );
bot = h - d;
idx = 0;
do {
	makeRectangle(0, y, w, 1);
	mn = meanZeroLength();
	y += d;
	idx++;
	//print( ""+idx+"\t"+ mn );
	print( mn );
} while ( y<bot );
run("Select None");
setBatchMode(false);
exit();
function meanZeroLength() {
	p = getProfile();
	totZeroL = 0;
	k = 0;
	m = p.length-1;
	for ( i=0; i<m; i++ ) { 
		if ( p[i]==0 ) { 
			totZeroL ++;
			if ( p[i+1]>0 )	k++;
		}
	}
	if ( p[m]==0 ) { totZeroL++; k++; }
	return totZeroL / k;
}

#17

Hi Herbie,

So the code I posted along with the use of the BAR toolbar gives me the positions of the intercepts with the black and white regions as maxima and minima respectively.

To answer your questions:

1) At the moment, I just want the lengths of intersections of the horizontal lines with the black objects individually for each horizontal line if possible. If this becomes too complicated, then I want to be able to address the following questions:

A) Say that the graph has 15 minima and 16 maxima. How do I store the X1 (minima) and X2 (maxima) columns from the “Plot Values” table into arrays called “minima” and “maxima” respectively? I have had a very hard time exporting values from that table in ImageJ… I don’t want to have to manually copy and paste into excel, because I want to use it for bulk calculations on bulk images. Anyway I can go about this?

B) The plot also displays the number of minima and maxima on top in blue and red font respectively. How do I go about storing the number of minima and maxima in separate arrays called “numMin” and “numMax”? so that I can update it with values from images from the same data set.

In which case, I can use the distance between the minima or maxima to calculate the relative lengths of the black objects. Which is why my emphasis is on figuring out how to store the values from my code in the arrays as I had asked in my previous post.

2) If your macro prints the means of intersections with white objects per line, then I can work with that value by subtracting it from the total length of the line and dividing it by the number of minima or maxima respectively, so the value your table provides is fine, but is it corresponding to white or black objects?

3) I want the results stored in an array in a macro which can be easily printed to window


#18

I’m out because you are not willing to understand that all this minima and maxima thing is irrelevant because my macro gives you the lengths already. More precisely and as I’ve written several times already, presently it gives you the sum of these length per line but you may get the mean or whatever you want.

Now you’re on your own.

Regards and good luck

Herbie


#19

I want the individual lengths of the black objects per line. Each black object is a different thickness. The really thick ones will throw off my mean because I intend to get rid of those lengths in my final calculation. What is the lengths it is giving? Because the length of the image is 2080 pixels length. The black objects are all different lengths. The mean will skew my results and will not give me a representative of the small black distances vs the large.

I think David may be able to help explain this better than I can.
so biologically the thick black regions are bronchioles and small black regions are alveolar walls. I am only interested in the alveolar walls and want to discount the bronchiolar region without having to do it manually. That is why I am after the minima and maxima as an alternate option.

Which is why my last request is just how to store values from “Plot Values” table in arrays in macro because that would give me atleast something much better to work with if working with the image becomes too dificult.

Thanks,

Abi


#20

as I’ve written, I’m out.

Good luck with your project

Herbie