Image analysis for histology images

Dear image.sc community,

I’m new here, but will ask anyhow.
In the included image, I can highlight all of the “pink” area in the jpg image (highlighted in red), and can also highlight the “black” nuclei, but I can’t figure out how to get ImageJ to “tell me” or list the highlighted areas so I can divide the pink are by the black area. I have 37 more images that I would like to process with the same filters.
Thanks, Bill

@Bill3madison

What you need to is write a short macro script using the Script Editor. Here is more-or-less what you need to do:

  1. Open Fiji and open the Macro Recorder
  2. In the Color Threshold window - there is a “Macro” button. That will record your settings as code in the recorder window (the code that you want begins with // Color Thresholder 2.0.0-rc-69/1.52n and ends with // Colour Thresholding-------------)
  3. you can copy/paste that code into the script examples I made at the bottom of this message… Take those scripts and copy/paste them (individually) into the Script Editor and select the IJ1 Macro language and then click ‘run’. You will have to do each one separately for now… but then you will have two Results tables generated with the information you need to do your calculations.

This code example can be adapted if you need… but it’s at least a start in the right direction to solve your issue. Perhaps others here have more ideas. But this is a quick way to get the data you need.

Script to calculate “pink” areas:

/*
 * Macro template to process multiple images in a folder to generate
 * color thresholded masks to calculate AREA.  Note: be sure to select
 * 'area' in Set Measurments option (Analyze > Set Measurements...).
 */

#@ File (label = "Input directory", style = "directory") input
#@ File (label = "Output directory", style = "directory") output
#@ String (label = "File suffix", value = ".tif") suffix


processFolder(input);

// function to scan folders/subfolders/files to find files with correct suffix
function processFolder(input) {
	list = getFileList(input);
	list = Array.sort(list);
	for (i = 0; i < list.length; i++) {
		if(File.isDirectory(input + File.separator + list[i]))
			processFolder(input + File.separator + list[i]);
		if(endsWith(list[i], suffix))
			processFile(input, output, list[i]);
	}
roiManager("Measure"); // measure area of all images
saveAs("Results", output + "/All_Results_Area.csv"); // save csv file
}

function processFile(input, output, file) {
	open(input+ File.separator + file);
	run("Color Threshold...");
	// Color Thresholder 2.0.0-rc-69/1.52n
	// Autogenerated macro, single images only!
	/// THIS IS THE BLOCK OF CODE THAT YOU HAVE TO REPLACE WITH YOUR OWN COLOR THRESHOLD PARAMETERS FOR YOUR PINK REGION 
		min=newArray(3);
		max=newArray(3);
		filter=newArray(3);
		a=getTitle();
		run("HSB Stack");
		run("Convert Stack to Images");
		selectWindow("Hue");
		rename("0");
		selectWindow("Saturation");
		rename("1");
		selectWindow("Brightness");
		rename("2");
		min[0]=0;
		max[0]=30;
		filter[0]="pass";
		min[1]=86;
		max[1]=255;
		filter[1]="pass";
		min[2]=120;
		max[2]=251;
		filter[2]="pass";
		for (i=0;i<3;i++){
		  selectWindow(""+i);
		  setThreshold(min[i], max[i]);
		  run("Convert to Mask");
		  if (filter[i]=="stop")  run("Invert");
		}
		imageCalculator("AND create", "0","1");
		imageCalculator("AND create", "Result of 0","2");
		for (i=0;i<3;i++){
		  selectWindow(""+i);
		  close();
		}
		selectWindow("Result of 0");
		close();
		selectWindow("Result of Result of 0");
		rename(a);
	// Colour Thresholding-------------
	run("Create Selection");
	roiManager("Add");
}

Script to count nuclei:

/*
 * Macro template to process multiple images in a folder to generate
 * color thresholded masks to calculate NUMBER OF NUCLEI. 
 */

#@ File (label = "Input directory", style = "directory") input
#@ File (label = "Output directory", style = "directory") output
#@ String (label = "File suffix", value = ".tif") suffix


processFolder(input);

// function to scan folders/subfolders/files to find files with correct suffix
function processFolder(input) {
	list = getFileList(input);
	list = Array.sort(list);
	for (i = 0; i < list.length; i++) {
		if(File.isDirectory(input + File.separator + list[i]))
			processFolder(input + File.separator + list[i]);
		if(endsWith(list[i], suffix))
			processFile(input, output, list[i]);
	}
roiManager("Measure"); // measure area of all images
saveAs("Results", output + "/All_Results_Nuclei.csv"); // save csv file
}

function processFile(input, output, file) {
	open(input+ File.separator + file);
	run("Color Threshold...");
	// Color Thresholder 2.0.0-rc-69/1.52n
	// Autogenerated macro, single images only!
	/// THIS IS THE BLOCK OF CODE THAT YOU HAVE TO REPLACE WITH YOUR OWN COLOR THRESHOLD PARAMETERS FOR YOUR NUCLEI
		min=newArray(3);
		max=newArray(3);
		filter=newArray(3);
		a=getTitle();
		run("HSB Stack");
		run("Convert Stack to Images");
		selectWindow("Hue");
		rename("0");
		selectWindow("Saturation");
		rename("1");
		selectWindow("Brightness");
		rename("2");
		min[0]=0;
		max[0]=30;
		filter[0]="pass";
		min[1]=86;
		max[1]=255;
		filter[1]="pass";
		min[2]=120;
		max[2]=251;
		filter[2]="pass";
		for (i=0;i<3;i++){
		  selectWindow(""+i);
		  setThreshold(min[i], max[i]);
		  run("Convert to Mask");
		  if (filter[i]=="stop")  run("Invert");
		}
		imageCalculator("AND create", "0","1");
		imageCalculator("AND create", "Result of 0","2");
		for (i=0;i<3;i++){
		  selectWindow(""+i);
		  close();
		}
		selectWindow("Result of 0");
		close();
		selectWindow("Result of Result of 0");
		rename(a);
	// Colour Thresholding-------------
	run("Analyze Particles...", "size=10-Infinity display exclude add");  // YOU WILL NEED TO ALSO PLAY WITH THE PARAMETERS FOR ANALYZE PARTICLES (open the macro recorder and do this manually... then you can copy/paste that code snippet and replace this line here)
	count=roiManager("count");
	print(file + "'s count = " + count);  // this information is also saved in the Results Table
	roiManager("Deselect");
	roiManager("Delete");
	run("Close All");
}

If you can share your code snippets for the Color Threshold and an original image file as an example - I could better refine this.

If you are more comfortable with point and click software, you could try the UnmixColors module in CellProfiler, then IdentifyPrimaryObjects to find and count nuclei in the black channel, then the MeasureImageAreaOccupied module to identify the pink areas then use ImageMath to divide pink area by nucleus count.

1 Like