macro "Threshold by Selection or ROIs" { /* Applies auto-thresholds to using selected ares for sampling of to ROIs individually. v230822: 1st version, based on Threshold_Each_ROI_Individually_v230821.ijm Peter J. Lee, Florida State University v230824-5: Added a few more starting options. v230828: Replaced composite selection option with band selection. v230903: Fixed missing parenthesis and combined processing loop. v230904: Added center-circle option. Fixed 'newTItle' typo. v230908: Fixed function getTitleWOKnownExtension use. v231017-8: Attempts to fix some histogram plot issues. F1 : Replaced function: pad. */ macroL = "Threshold_by_selection_or_ROIs_v231018-f1.ijm"; oTitle = getTitle(); if (oTitle.length<=5){ rename(getString("Enter full name of image:",oTitle)); oTitle = getTitle(); if (oTitle.length<=5) exit("Try something longer than 5 characters"); } newTitle = "" + getTitleWOKnownExtension() + "_Thresh"; maxInt = 255; leq = fromCharCode(0x2264); geq = fromCharCode(0x2265); plusminus = fromCharCode(0x00B1); getPixelSize(unit, pixelWidth, pixelHeight); lcf=(pixelWidth+pixelHeight)/2; dup = false; selType = selectionType(); if ((selType>=0 && selType<5) || selType==9) selArea = true; else selArea = false; if (bitDepth==24){ if (is("grayscale")){ newTitle += "_Gray"; run("Select None"); run("Duplicate...", newTitle); dup = true; run("8-bit"); if (selArea){ run("Restore Selection"); selectWindow(oTitle); run("Restore Selection"); selectWindow(newTitle); } } else{ Dialog.create("Color threshold options: " + macroL); colorOptions = newArray("Channel threshold: red", "Channel threshold: green", "Channel threshold: blue", "Launch color thresholder"); Dialog.addRadioButtonGroup("This macro is designed for 8 and 16 bit images",colorOptions,5,1,colorOptions[0]); Dialog.show(); colorOption = Dialog.getRadioButton(); if (startsWith(colorOption,"Channel")){ cCol = substring(colorOption,lastIndexOf(colorOption,": ")+2); newTitle += "_Split"; run("Select None"); preID = getImageID(); run("Duplicate...", newTitle); dup = true; if (getTitle()!=newTitle) rename(newTitle); run("Split Channels"); if (cCol!="red") close(newTitle + " \(red*"); if (cCol!="green") close(newTitle + " \(green*"); if (cCol!="blue") close(newTitle + " \(blue*"); newTitle += " \(" + cCol + "\)"; if (selArea){ selectWindow(newTitle); run("Restore Selection"); selectImage(preID); run("Restore Selection"); selectWindow(newTitle); } } else if (startsWith(colorOption,"Launch")){ run("Record..."); /* You may want to record the color threshold action */ run("Color Threshold..."); exit; } } } bDepth = bitDepth; if (bDepth!=16 && bDepth!=8) exit("This macro has not been tested for bit depth: " + bDepth); if (bDepth==16) maxInt = 65535; nROIs = roiManager("count"); rangeOptions = newArray("Base threshold on entire image","Auto-select bounding box and base threshold on this area","Base threshold on center circle \(diam. 30% of image height\)"); if (selArea) rangeOptions = Array.concat("Auto-threshold all based on selection \(current\) *", rangeOptions); else rangeOptions = Array.concat("Select new area to base auto-threshold on \(new requester\)",rangeOptions); if (nROIs>1) rangeOptions = Array.concat("Threshold each ROI individually", rangeOptions); else if (nROIs==1){ rangeOptions = Array.concat(rangeOptions, "Try to split ROI for individual threshold","Base auto-threshold on ROI"); if (!selArea) roiManager("Select", 0); roiManager("Show All"); roiManager("Select", 0); } infoColor = "#0076B6"; infoWarningColor = "#ff69b4"; infoFontSize = 12; Dialog.create("Threshold selection range options: " + macroL); if (!dup){ Dialog.addMessage("Original image title: " + oTitle, infoFontSize-2, infoColor); Dialog.addString("New image name:", newTitle, minOf(50,newTitle.length+5)); } Dialog.setInsets(0, 50, -5); Dialog.addRadioButtonGroup("Threshold range options:", rangeOptions,rangeOptions.length,1,rangeOptions[0]); if (selArea){ Dialog.setInsets(0, 60, 15); Dialog.addMessage("* = Selected area can be modified later \(reapply 'Auto' in 'Threshold' window\)",infoFontSize,infoColor); } Dialog.addNumber("Expand/Contract selection for auto-threshold basis",0,0,3,"pixels"); Dialog.addNumber("Create hollow selection band about selection or ROI above: " + plusminus,0,0,5,"pixels \(leave blank for 'no'\)"); Dialog.addMessage("Band creation occurs after any enlargement or contraction",infoFontSize,infoColor); Dialog.show(); if (!dup) newTitle = Dialog.getString(); rangeOption = Dialog.getRadioButton(); expandSel = Dialog.getNumber(); bandN = Dialog.getNumber(); bandByUnit = 2 * bandN * lcf; if (!dup){ if (selType>=0) run("Select None"); run("Duplicate...", newTitle); if (getTitle()!=newTitle) rename(newTitle); if (selType>=0) run("Restore Selection"); dup = true; } selectWindow(newTitle); if (startsWith(rangeOption,"Select new")){ selectionTool = call("ij.Prefs.get", "asc.thresholdRange.selectionTool", "polygon"); setTool(selectionTool); waitForUser("Select (ideally 2-phase) area to base auto-threshold values on\nUse shift key to sample multiple areas"); selectionTool = call("ij.Prefs.set", "asc.thresholdRange.selectionTool", IJ.getToolName); rangeOption = "Auto-threshold all based on selection"; } else if (startsWith(rangeOption, "Base threshold on entire")){ run("Select None"); rangeOption = "Auto-threshold all based on selection"; } else if (startsWith(rangeOption, "Base threshold on center")){ run("Select None"); iH = Image.height; iW = Image.width; cX = iW /2 - 0.15 * iH; cY = 0.35 * iH; makeOval(cX, cY, 0.3 * iH, 0.3 * iH); rangeOption = "Auto-threshold all based on selection"; } else if (startsWith(rangeOption, "Auto-select")){ run("Select Bounding Box (guess background color)"); rangeOption = "Auto-threshold all based on selection"; } else if (rangeOption=="Base auto-threshold on ROI"){ roiManager("select", 0); rangeOption = "Auto-threshold all based on selection"; } else if (startsWith(rangeOption, "Try to split ROI")){ roiManager("Select", 0); compoName = Roi.getName; roiManager("Split"); nROIs = roiManager("count"); if (nROIs==1) rangeOption = "Auto-threshold all based on selection"; } selectWindow(newTitle); if (startsWith(rangeOption, "Auto-threshold all based on selection")){ if (expandSel!=0) run("Enlarge...", "enlarge=&expandSel pixel"); if (bandN!=0) run("Make Band...", "band=" + bandByUnit); run("Threshold..."); exit; } splitCompROIsFlag = false; if (nROIs>0){ selectedROIs = newArray(); if (nROIs==1){ splitCompo = getBoolean("There is only one ROI", "Attempt to split composite ROIs into individual ROIs", "Exit"); if (!splitCompo) exit; else { for (i=0; i0 && ((selTypeB>=0 && selTypeB<5) || selTypeB==9)){ bandByUnit = 2 * bandN * lcf; run("Enlarge...", "enlarge=" + 0-bandN + " pixel"); run("Make Band...", "band=" + bandByUnit); } selectWindow(newTitle); getStatistics(areaAll, meanAll, minAll, maxAll, stdAll,histogramAll); setAutoThreshold("Default"); getThreshold(lowerThresh, upperThresh); autoThreshMessage = "Default auto-threshold range for ROIs: " + lowerThresh + " - " + upperThresh; resetThreshold; } else { selTypeB = selectionType(); if (bandN>0 && ((selTypeB>=0 && selTypeB<5) || selTypeB==9)){ bandByUnit = 2 * bandN * lcf; run("Enlarge...", "enlarge=" + 0-bandN + " pixel"); run("Make Band...", "band=" + bandByUnit); } } if (bitDepth==16) multInt = maxAll / 256; else multInt = 1; maxLocs = Array.findMaxima(histogramAll, 500); if (maxLocs.length==0) maxMessage=" No histogram maxima found"; else { maxMessage="\(sorted with descending strength\) "; for (i=0; i0){ histogramAll = arrayTrimMaxEnds(maxLocs,histogramAll,0,255); xValues = arrayTrimMaxEnds(maxLocs,xValues,0,255); } if (expandSel!=0) previewExpand = abs(expandSel); else previewExpand = 10; run("Enlarge...", "enlarge=" + previewExpand + " pixel"); getStatistics(areaOutside, meanOutside, minOutside, maxOutside, stdOutside,histogramOutside); run("Select None"); xLabel = "Intensities"; if (xValues.length!=256) xLabel += " \(range end peaks ignored\)"; maxOutsideLocs = Array.findMaxima(histogramOutside, 500); if (maxLocs.length>0) histogramOutside = arrayTrimMaxEnds(maxLocs, histogramOutside,0,255); /* use maxLocs for "all" histogram for the axis legend to match */ for (i=0; i=0) Dialog.addMessage("For ROIs: Mean intensity = " + meanAll + "\nPeak locations:" + maxMessage + "\nValley locations: " + minMessage, infoFontSize, infoColor); Dialog.addNumber("Lower limit \("+leq+" set to white\)",round(minAll),0,8,"minimum shown"); Dialog.addNumber("Upper limit \("+geq+" set to black\)",round(maxAll),0,8,"maximum shown"); Dialog.setInsets(5, 20, 0); Dialog.addCheckbox("PreProcess each area with CLAHE?",false); Dialog.setInsets(5, 5, 0); Dialog.addNumber("CLAHE blocksize",127,0,6,"pixels"); Dialog.setInsets(5, 5, 0); Dialog.addNumber("CLAHE maximum",3,2,6,"slope"); Dialog.setInsets(10, 20, -5); Dialog.addCheckbox("Close all Histograms after running macro",true); if (splitCompROIsFlag) Dialog.addRadioButtonGroup("Composite ROI manager options:", newArray("Leave all ROIs", "Remove original composite ROI","Remove component ROIs"), 3,1,"Remove original composite ROI"); diagnosticOptions = newArray("Verbose output to log","Plot all ROI histograms"); diagnosticChecks = newArray(false,false); Dialog.addCheckboxGroup(1,2,diagnosticOptions,diagnosticChecks); Dialog.addCheckbox("Batchmode off", false); Dialog.show(); threshCommand = Dialog.getRadioButton(); newTitle2 = newTitle + "_" + threshCommand; percentile = Dialog.getNumber(); darkBackground = Dialog.getCheckbox(); expandSel = Dialog.getNumber(); lowerLimit = Dialog.getNumber; upperLimit = Dialog.getNumber; preCLAHE = Dialog.getCheckbox(); blockSize = Dialog.getNumber(); maxSlope = Dialog.getNumber(); if (Dialog.getCheckbox()) close("Histo*"); if (splitCompROIsFlag) splitOption = Dialog.getRadioButton(); verbose = Dialog.getCheckbox(); plotAll = Dialog.getCheckbox(); batchmodeOff = Dialog.getCheckbox(); if (verbose) IJ.log("Mean intensities: ROIs = " + meanAll + "; Outside of ROIs = " + meanOutside); if (darkBackground) threshCommand += " dark"; threshCommand += " light"; if (preCLAHE) newTitle2 += "RoiClahe-bs" + blockSize + "mS" + maxSlope; if (startsWith(threshCommand,"Percent") && percentile!=50){ if (round(percentile)!=percentile) newTitle2 += d2s(percentile,2); else newTitle2 += d2s(percentile,0); } if (!batchmodeOff) setBatchMode(true); if (!dup){ selectWindow(oTitle); // roiManager("Deselect"); run("Select None"); run("Duplicate...", "title=" + newTitle2); } else { selectWindow(newTitle); rename (newTitle2); } if (isOpen("Histogram of " + oTitle)){ selectWindow("Histogram of " + oTitle); close(); } if (bandN>0) bandByUnit = 2 * bandN * lcf; backupFlag = false; if (expandSel!=0 || bandN>0){ if (!splitCompROIsFlag){ /* Backup original ROIs to composite */ backupPath = getDir("temp") + "BkpRoiSet.zip"; tempROIs = File.exists(backupPath); if (tempROIs) null = File.delete(backupPath); roiManager("Save", getDir("temp") + "BkpRoiSet.zip"); backupFlag = true; } } nSelROIs = selectedROIs.length; selectWindow(newTitle2); run("Scale to Fit"); for (i=0; i0){ run("Enlarge...", "enlarge=" + 0-bandN + " pixel"); run("Make Band...", "band=" + bandByUnit); } roiManager("Update"); roiManager("Deselect"); run("Select None"); roiManager("Select", selectedROIs[i]); Roi.getContainedPoints(xPoints, yPoints); if (plotAll){ getStatistics(null, null, null, null, null, roiHistogram); roiHistogram = Array.trim(roiHistogram,255); roiHistogram = Array.deleteIndex(roiHistogram,0); eachROIHistTitle = "Histogram of each ROI_" + newTitle; if (i==0){ Plot.create(eachROIHistTitle, "Intensity", "Counts", roiHistogram); Plot.show() } else if (isOpen(eachROIHistTitle)){ selectWindow(eachROIHistTitle); Plot.add("bar",roiHistogram); Plot.setColor(randomHexColor()); } } selectWindow(newTitle2); nPoints = xPoints.length; ints = newArray; for(j=0; j=upperLimit) setPixel(xPoints[j],yPoints[j],0); } if (startsWith(threshCommand,"Percent") && percentile!=50){ rankedIs = Array.rankPositions(ints); iCutOff = round(nPoints * percentile / 100); for(j=0; j=lowerThresh) setPixel(xPoints[j],yPoints[j],maxInt); else setPixel(xPoints[j],yPoints[j],0); } } else { for(j=0; j0; i++){ newTitle = replace(newTitle, lcExtns[i], ""); newTitle = replace(newTitle, toUpperCase(lcExtns[i]), ""); } return newTitle; } function randomHexColor(){ /* v231207: Replaced function: pad*/ r = toHex(255 * random); g = toHex(255 * random); b = toHex(255 * random); hexName= "#" + "" + String.pad(r, 2) +""+ String.pad(g, 2) +""+ String.pad(b, 2); return hexName; } function arrayTrimMaxEnds(maximaLocs,inputArray,lowest,highest){ /* v230821: 1st version Peter J. Lee Applied Superconductivity Center */ if (maximaLocs[0]==lowest || maximaLocs[0]==highest){ if (maximaLocs[0]==lowest){ if (maximaLocs[1]==highest) inputArray = Array.deleteIndex(inputArray, inputArraylength-1); inputArray = Array.deleteIndex(inputArray, 0); } else { inputArray = Array.deleteIndex(inputArray, inputArray.length-1); if (maximaLocs[1]==lowest) inputArray = Array.deleteIndex(inputArray, 0); } } return inputArray; }