Help with groovy script: How to code excluding the edges of cells touching the borders

macro
groovy

#1

Hi all, the coding field and writing macros is still very new for me. I am struggling with my script, in which I want to exclude the cells that touch the border. I know how to do it, but I don’t succeed to code it and to make it work in the following script.

Can somebody help me out on this one? I would appreciate any help!

Julie

//@File(label=“Input directory”, description=“Select the directory with OIB images”, style=“directory”) inputDir
//@Integer(label=“Nuclei Channel”, value=1) nucleiChannel
//@Integer(label=“DNA Channel”, value=2) dnaChannel
//@Integer(label=“RNA Channel”, value=3) rnaChannel
//Double(label=“Min Particle size in um”, value=0.1) minParticleSizeInUnit
//String(label=“Threshold Method for Tissue Detection”,choices={‘Moments’,‘Huang’,‘Percentile’,‘Triangle’,‘IJ_IsoData’,‘Percentile’}) thresholdMethod

import ij.IJ
import ij.ImagePlus
import ij.gui.GenericDialog
import ij.Prefs
import ij.measure.Measurements
import ij.measure.Calibration
import ij.WindowManager

import ij.process.ImageConverter
import ij.process.ImageProcessor
import ij.process.ByteProcessor
import ij.process.ImageStatistics

import ij.plugin.Duplicator
import ij.plugin.ImageCalculator
import ij.plugin.RoiScaler
import ij.plugin.ZProjector
import ij.plugin.Thresholder
import ij.process.ImageStatistics
import ij.measure.ResultsTable
import ij.plugin.filter.ParticleAnalyzer
import ij.plugin.frame.RoiManager

import ij.gui.Roi
import ij.gui.ShapeRoi

import groovy.io.FileType
import groovy.time.TimeCategory
import groovy.time.TimeDuration

import loci.plugins.BF
import loci.formats.ChannelSeparator
import loci.formats.FormatException
import loci.formats.IFormatReader
import loci.formats.meta.IMetadata
import loci.formats.MetadataTools

import loci.common.Region
import loci.plugins.in.ImporterOptions

import loci.plugins.util.ImageProcessorReader
import loci.plugins.util.LociPrefs
import loci.common.Region

import java.awt.Rectangle
import java.io.File
import java.lang.Double
import java.nio.file.Paths
import java.util.Collections

import static groovy.io.FileType.FILES

rm = new RoiManager(true)
rm.reset()
rt = new ResultsTable()

//Clear the log window
IJ.log("\Clear")

folderName=inputDir.getAbsolutePath()
IJ.log('Analyze Dir '+inputDir.name)

minCellSize=0
maxCellSize=Double.POSITIVE_INFINITY

minParticleSize=0
maxParticleSize=Double.POSITIVE_INFINITY

fileNameList=
cellNumberList=
numberOfDNAParticleList=
numberOfRNAParticleList=
meanIntensityDNAParticleList=
areaDNAParticleList=
meanIntensityRNAParticleList=
areaRNAParticleList=

IJ.log(‘Start Analysis’)
inputDir.eachFile (FILES) {
if(it.name.endsWith(’.oif’)) {
IJ.log(it.name)
def baseName=it.getAbsolutePath()[0…-5]
def baseFileName=it.name[0…-5]
rm.reset()

def options = new ImporterOptions();
options.setId(Paths.get(it.getAbsolutePath()).toString());
options.setAutoscale(true);
//options.setCrop(true);
//options.setCropRegion(0, new Region(x, y, w. h));
options.setColorMode(ImporterOptions.COLOR_MODE_COMPOSITE);
def imps = BF.openImagePlus(options);
imp = imps[0]
//imp.show()
//lll
//IJ.run("Bio-Formats Importer", "open=["+Paths.get(it.getAbsolutePath()).toString()+"] color_mode=Composite rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT");
//imp = IJ.getImage()
//Z Sum Projection
imp = ZProjector.run(imp,"sum");
//Duplicate the nuclei channel
imp_nuclei=new Duplicator().run(imp, nucleiChannel.toInteger(), nucleiChannel.toInteger())
//Detect the Nuclei and store the matching ROIs
IJ.run(imp_nuclei, "Gaussian Blur...", "sigma=10");
IJ.setAutoThreshold(imp_nuclei, "Moments dark no-reset");
Prefs.blackBackground = false;
IJ.run(imp_nuclei, "Convert to Mask", "");
IJ.run(imp_nuclei, "Watershed", "");
particleAnalysisOptions = ParticleAnalyzer.ADD_TO_MANAGER
p  = new ParticleAnalyzer(particleAnalysisOptions, 0, rt, minCellSize, maxCellSize, 0.0, 1.0)
p.setRoiManager(rm)
p.analyze(imp_nuclei)
def cellRois=rm.getRoisAsArray()
rm.runCommand('Save', Paths.get(inputDir.getAbsolutePath(),baseFileName+'_cell_rois.zip').toString())
//Then for each cell we will count the number of particle and take their intensity
//Channel 2 is DNA
thresholdMethod="Yen dark no-reset"
imp_DNA=new Duplicator().run(imp, dnaChannel.toInteger(), dnaChannel.toInteger())
imp_DNA_binary = new Duplicator().run(imp, dnaChannel.toInteger(), dnaChannel.toInteger())
IJ.setAutoThreshold(imp_DNA_binary, thresholdMethod);
Prefs.blackBackground = false;
IJ.run(imp_DNA_binary, "Convert to Mask", "");
//imp_DNA_binary.show()
//lll
//Channel 3 is RNA
imp_RNA=new Duplicator().run(imp, rnaChannel.toInteger(), rnaChannel.toInteger())
imp_RNA_binary = new Duplicator().run(imp, rnaChannel.toInteger(), rnaChannel.toInteger())
IJ.setAutoThreshold(imp_RNA_binary, thresholdMethod);
Prefs.blackBackground = false;
IJ.run(imp_RNA_binary, "Convert to Mask", "");
for(int i=0;i<cellRois.size();i++)
{
  fileNameList.add(baseFileName)
  cellNumberList.add((i+1))
  rm.reset()
  roiCell=cellRois[i].clone()
  roiCell.setLocation(0, 0)
  //Measure on the DNA Channel
  imp_DNA.setRoi(cellRois[i])
  impCell = imp_DNA.duplicate();
  imp_DNA_binary.setRoi(cellRois[i])
  impCellMask=imp_DNA_binary.duplicate();
  //impCellMask.show()
  //lll
  (numberOfDNAParticleList,meanIntensityDNAParticleList,areaDNAParticleList)=analyzeCellParticle(impCell,impCellMask,roiCell,minParticleSize,maxParticleSize,
                                                                             numberOfDNAParticleList,meanIntensityDNAParticleList,areaDNAParticleList,rm,"Yen dark no-reset")
  //Measure on the RNA Channel
  imp_RNA.setRoi(cellRois[i])
  impCell = imp_RNA.duplicate();
  imp_RNA_binary.setRoi(cellRois[i])
  impCellMask=imp_RNA_binary.duplicate();
  (numberOfRNAParticleList,meanIntensityRNAParticleList,areaRNAParticleList)=analyzeCellParticle(impCell,impCellMask,roiCell,minParticleSize,maxParticleSize,
                                                                             numberOfRNAParticleList,meanIntensityRNAParticleList,areaRNAParticleList,rm,"Yen dark no-reset")

  /*
  IJ.setBackgroundColor(0, 0, 0);
  IJ.run(impCell, "Clear Outside", "");
  IJ.setAutoThreshold(impCell, "Yen dark no-reset");
  Prefs.blackBackground = false;
  IJ.run(impCell, "Convert to Mask", "");
  particleAnalysisOptions = ParticleAnalyzer.ADD_TO_MANAGER
  p  = new ParticleAnalyzer(particleAnalysisOptions, 0, rt, minParticleSize, maxParticleSize, 0.0, 1.0)
  p.setRoiManager(rm)
  p.analyze(impCell)
  def particleRois=rm.getRoisAsArray()
  def meanParticleIntensity=0
  numberOfDNAParticleList.add(particleRois.size())
  for(int p=0;p<particleRois.size();p++)
  {
    impCell.setRoi(particleRois[p])
    stats=impCell.getStatistics(Measurements.MEAN+Measurements.MEDIAN+Measurements.AREA+Measurements.STD_DEV )
    meanParticlesIntensity+=stats.@mean
    areaParticles+=stats.@area
  }
  meanParticlesIntensity=meanParticlesIntensity/particleRois.size()
  meanIntensityDNAParticleList.add(meanParticlesIntensity)
  areaParticles=areaParticles/particleRois.size()
  areaDNAParticleList.add(areaParticles)      
}   
*/
}

}
}
rt=populateResultTable(rt,fileNameList,cellNumberList,
numberOfDNAParticleList,meanIntensityDNAParticleList,areaDNAParticleList,
numberOfRNAParticleList,meanIntensityRNAParticleList,areaRNAParticleList)
rt.show(‘Result’)
rt.save(Paths.get(inputDir.getAbsolutePath(), ‘results.xls’).toString())
IJ.log('Result saved in '+Paths.get(inputDir.getAbsolutePath(), ‘results.xls’).toString())
IJ.log(‘Analysis Done!’)

def populateResultTable(rt,fileNameList,cellNumberList,
numberOfDNAParticleList,meanIntensityDNAParticleList,areaDNAParticleList,
numberOfRNAParticleList,meanIntensityRNAParticleList,areaRNAParticleList)
{
labels = [‘FileName’,‘Cell Number List’,
‘# DNA Particle’,‘DNA Particle Intensity Mean’,‘DNA Particle Area Mean’,
‘# RNA Particle’,‘RNA Particle Intensity Mean’,‘RNA Particle Area Mean’
];

rt.reset()
for(j=0;j<fileNameList.size();j++)
{
label=0;
//Values
rt.incrementCounter()
rt.addValue(labels[label++],fileNameList[j]) //
rt.addValue(labels[label++],cellNumberList[j]) //
rt.addValue(labels[label++],numberOfDNAParticleList[j])
rt.addValue(labels[label++],meanIntensityDNAParticleList[j])
rt.addValue(labels[label++],areaDNAParticleList[j])
rt.addValue(labels[label++],numberOfRNAParticleList[j])
rt.addValue(labels[label++],meanIntensityRNAParticleList[j])
rt.addValue(labels[label++],areaRNAParticleList[j])
}
return rt
}

def analyzeCellParticle(impCell,impCellMask,roiCell,minParticleSize,maxParticleSize,numberOfParticleList,meanParticleIntensityList,areaParticleList,rm,thresholdMethod)
{
rm.reset()
impCellMask.setRoi(roiCell)
IJ.setBackgroundColor(255, 255, 255);
IJ.run(impCellMask, “Clear Outside”, “”);
particleAnalysisOptions = ParticleAnalyzer.ADD_TO_MANAGER
p = new ParticleAnalyzer(particleAnalysisOptions, 0, rt, minParticleSize, maxParticleSize, 0.0, 1.0)
p.setRoiManager(rm)
p.analyze(impCellMask)
def particleRois=rm.getRoisAsArray()
def meanParticlesIntensity=0
def areaParticles=0
numberOfParticleList.add(particleRois.size())
if(particleRois.size()>0)
{
for(int p=0;p<particleRois.size();p++)
{
impCell.setRoi(particleRois[p])
stats=impCell.getStatistics(Measurements.MEAN+Measurements.MEDIAN+Measurements.AREA+Measurements.STD_DEV )
meanParticlesIntensity+=stats.@mean
areaParticles+=stats.@area
}

meanParticlesIntensity=meanParticlesIntensity/particleRois.size()
meanParticleIntensityList.add(meanParticlesIntensity)
areaParticles=areaParticles/particleRois.size()
areaParticleList.add(areaParticles) 
//impCellMask.show()
//lll

}
else
{
meanParticleIntensityList.add(-1)
areaParticleList.add(-1)
}
rm.reset()
return[numberOfParticleList,meanParticleIntensityList,areaParticleList]
}


#2

Hi,
the particle analyzer has an option EXCLUDE_EDGE_PARTICLES. Since you also want to use the ADD_TO_MANAGER option, you have to know how to pass both in the same variable to the ParticleAnalyzer. The answer is:

particleAnalysisOptions = ParticleAnalyzer.ADD_TO_MANAGER + ParticleAnalyzer.EXCLUDE_EDGE_PARTICLES

Let me explain: The values of the different options are integers which are powers of 2. In the binary representation this means that each one has exactly one bit that is 1 and all the others are zero. For example:
0001 - 2
0010 - 4
0100 - 8
If we have a sum of different powers of two, we can still exactly know which numbers have been added. For example 4+2 = 6 which is 0011. So if the plugin gets 6 as an argument, it knows that the options coded by 1 and 2 should be used.

Best regards,
Volker


#3

Dear Volker,

Thank you very much for your reply. It is working!
Is it as well possible to remove cells from the analysis that are too small? Simply adding;

IJ.run(imp_nuclei, “Analyze Particles…”, “size=10.00-Infinity”); does not work on my script.

I would also like to set an intensity threshold of 6000 for my DNA counts, in which values under 6000 are considered as negative; the same for my RNA counts. I don’t succeed to write it in groovy…

I very appreciate any suggestion on this!

Thank you a lot for your time,

Best,
Julie


#4

Dear Julie,
the answer of how to remove small cells is already in your code. You pass the minimum and maximum cell size as a parameter to the constructor of the ParticleAnalyzer. You can set the threshold values you need on the processor of the image. Please check out the javadoc of the ImageJ api for information.

Here is an example that sets a threshold and applies the particle-analyzer:

import ij.plugin.filter.ParticleAnalyzer
import ij.plugin.filter.Analyzer
import ij.process.ImageProcessor

imp_nuclei = ij.IJ.getImage()

MIN_CELL_SIZE = 20
MAX_CELL_SIZE = 80
MIN_CIRCULATRY = 0
MAX_CIRCULATRY = 1
MIN_THRESHOLD = 150
MAX_TRESHOLD = 255

imp_nuclei.getProcessor().setThreshold(MIN_THRESHOLD, MAX_TRESHOLD, ImageProcessor.RED_LUT)
particleAnalysisOptions = ParticleAnalyzer.ADD_TO_MANAGER + ParticleAnalyzer.EXCLUDE_EDGE_PARTICLES
p  = new ParticleAnalyzer(particleAnalysisOptions, ParticleAnalyzer.NOTHING, Analyzer.getResultsTable(), MIN_CELL_SIZE, MAX_CELL_SIZE, MIN_CIRCULATRY, MAX_CIRCULATRY)
p.analyze(imp_nuclei)

Best regards,
Volker