/* Author: Ahsen Chaudhry Last updated: July 1, 2019 This macro performs a threshold on a 3D stack using local threshold algorithms based on variants of mean-based thresholding. It takes two important parameters: block size (expressed as a diameter for Weighted Mean and as radius for the rest), and C-value. These parameters can be chosen using the Optimize Threshold macros. */ macro Threshold3D { macroFolder = getDirectory("plugins") + "MitochondriaAnalyzer\\Macros\\"; regularMode=true; batchMode = false; optimizeMode = false; preProcessOnly = false; if (getArgument()=="Batch") batchMode=true; if (getArgument()=="Optimize") optimizeMode=true; if (getArgument()=="PrePro") preProcessOnly=true; if (getArgument()!="") regularMode=false; input = getTitle(); //The default block size is set to 1.25um, which is slightly larger than the upper-range of mitochondrial sizes getPixelSize(unit, pixelWidth, pixelHeight); baseSize = 1.25;//(1.25 / pixelWidth); adaptiveSize = baseSize; baseSubtract = 10; adaptiveSubtract = baseSubtract; //Pre-process command variables, see futher explaination later. canSubtract = true; rolling = 1.25; //corresponds to a value of 1.25 microns. canSigma = true; canEnhance = true; canScaleEnhance = false; slope = 1.4; //use a higher slope if want to capture more dim mitochondria scaleSlopeTo = 2.6; scaleBegin = 0.5; //means the position corresponding to 60% of stack's height scaleEnd = 0.8; canGamma = true; gamma = 0.9; //Post-process command variables canDespeckle = true; canRemove = true; canFill = true; //Show comparison will produce a combined stack with both the raw and thresholded image in seperate channels. showComparison = false; //Perform automatic analysis? canAnalyze = false; methodChoices = newArray("Weighted Mean","Mean","Median","MidGrey"); method = methodChoices[0]; if (regularMode) { Dialog.create("3D Threshold"); Dialog.setInsets(-5, 0, 0); Dialog.addMessage("This function will perform a threshold on a 3D stack."); Dialog.setInsets(-5, 15, 0); Dialog.addMessage("The selected image is: " + input); Dialog.addMessage("Pre-processing commands:"); Dialog.setInsets(0, 30, 0); Dialog.addCheckbox("Subtract Background", canSubtract); Dialog.addToSameRow() ; Dialog.addSlider("Rolling (microns):",0.02,2.5,rolling); Dialog.setInsets(-5, 30, 0); Dialog.addCheckbox("Sigma Filter Plus", canSigma); Dialog.setInsets(-5, 30, 0); Dialog.addCheckbox("Enhance Local Contrast", canEnhance); Dialog.addToSameRow() ; Dialog.addSlider("Max Slope:",1.0,3.0,slope); Dialog.setInsets(-5, 50, 0); Dialog.addCheckbox("Scale Max Slope through stack", canScaleEnhance); Dialog.setInsets(0, 30, 0); Dialog.addNumber("Scale to",scaleSlopeTo); Dialog.setInsets(0, 30, 0); Dialog.addNumber("From slice",scaleBegin,2,2,"(fraction of max slice)"); Dialog.addToSameRow() ; Dialog.addNumber("To slice",scaleEnd,2,2,"(fraction of max slice)"); Dialog.setInsets(0, 30, 0); Dialog.addCheckbox("Adjust Gamma", canGamma); Dialog.addToSameRow() ; Dialog.addSlider("Gamma:",0.1,1.0,gamma); Dialog.addMessage("Please select the local threshold method:"); Dialog.setInsets(0, 30, 0); Dialog.addChoice("Method:",methodChoices,method); Dialog.setInsets(5, 30, 0); Dialog.addNumber("Block Size", baseSize,3,4,"microns"); Dialog.addToSameRow() ; Dialog.addNumber("C-Value", baseSubtract,0,3,""); Dialog.setInsets(20, 20, 0); Dialog.addMessage("Post-processing commands:"); labels = newArray("Despeckle","Remove Outliers ", "Fill 3D Holes"); defaults = newArray(canDespeckle,canRemove,canFill); Dialog.setInsets(0, 30, 0); Dialog.addCheckboxGroup(1,3,labels,defaults); Dialog.addMessage(""); Dialog.addCheckbox("Show comparison of threshold to original?", showComparison) Dialog.addCheckbox("Automatically perform analysis?", canAnalyze); Dialog.setInsets(-5, 35, 0); Dialog.addMessage("(using default analysis settings)"); Dialog.show(); canSubtract = Dialog.getCheckbox(); rolling = Dialog.getNumber(); canSigma = Dialog.getCheckbox(); canEnhance = Dialog.getCheckbox(); slope = Dialog.getNumber(); canScaleEnhance = Dialog.getCheckbox(); scaleSlopeTo = Dialog.getNumber(); scaleBegin = Dialog.getNumber(); scaleEnd = Dialog.getNumber(); canGamma = Dialog.getCheckbox(); gamma = Dialog.getNumber(); method = Dialog.getChoice(); adaptiveSize = Dialog.getNumber(); adaptiveSubtract = Dialog.getNumber(); canDespeckle = Dialog.getCheckbox(); canRemove = Dialog.getCheckbox(); canFill = Dialog.getCheckbox(); showComparison = Dialog.getCheckbox(); canAnalyze = Dialog.getCheckbox(); } if (batchMode==true || optimizeMode==true || preProcessOnly==true) { parameters = File.openAsString(getDirectory("temp") + "3DBatchThresholdTemp.txt"); parLines = split(parameters,"\n"); canSubtract = parseInt(parLines[0]); rolling = parseFloat(parLines[1]); canSigma = parseInt(parLines[2]); canEnhance = parseInt(parLines[3]); slope = parseFloat(parLines[4]); canScaleEnhance =parseFloat(parLines[5]); scaleSlopeTo =parseFloat(parLines[6]); scaleBegin = parseFloat(parLines[7]); scaleEnd = parseFloat(parLines[8]); canGamma = parseInt(parLines[9]); method = parLines[10]; adaptiveSize = parseFloat(parLines[11]); adaptiveSubtract = parseFloat(parLines[12]); canDespeckle = parseInt(parLines[13]); canRemove = parseInt(parLines[14]); canFill = parseInt(parLines[15]); } setBatchMode(true); input = getTitle(); output = input + " thresholded"; Stack.getPosition(c,s,f); run("Duplicate...", "duplicate channels=" + c + "-" + c + "frames=" + f + "-" + f); rename(output); //Pre-processing steps //Convert values for pre-processing plugins to pixels getPixelSize(unit, pixelWidth, pixelHeight); sRadius = 2 * (0.06 / pixelWidth); //uses the default values of the sigma filter plugin, and scales to pixel size. rolling = rolling / pixelWidth; maxSlices = nSlices; adaptiveSize = (adaptiveSize / pixelWidth); //if (!preProcessOnly) round(adaptiveSize); if (optimizeMode==false) { //Reduces background noise. Adjust the rolling parameter if needed. if (canSubtract) run("Subtract Background...", "rolling=" + rolling + " stack sliding"); //Smooths object edges and improves contrast between signal and background noise. Essential for thresholding. if (canSigma) run("Sigma Filter Plus", "radius=" + sRadius + " use=2.0 minimum=0.2 outlier stack"); //Enhances signal-to-noise contrast, great for areas of mitochondria with heterogenous intensity if (canEnhance) { slopeValue = slope; startS = round(maxSlices*scaleBegin); endS = round(maxSlices*scaleEnd); if (startS<1 || endS<1 || startS>=endS) canScaleEnhance=false; for (i = 1;i<=maxSlices;i++) { setSlice(i); if (i>1 && canScaleEnhance && i>=startS && i<=endS) { slopeM = ( (scaleSlopeTo-slope) / ( endS - startS ) ); slopeValue = slope + ( (i-startS)*slopeM); } enhanceBS=64; width = getWidth(); height = getHeight(); if (width<33 || height<33) { if (width