//StarDist_With_Preprocessing macroName = "Macro_StarDist_With_Preprocessing"; macroShortDescription = "This macro runs StarDist, but allows several pre-processing steps before-hand."; macroDescription = "This macro reads single .tif images from the chosen folder (including subfolders)" + "
Pre-processing like log transformation, dimension scaling, and background subtraction are applicable." + "
StarDist will run on filteed images with adjustable parameters and saves them in StarDist folder of input folder." "
Label images or overlays can be exported."; macroRelease = "second release 18-11-2024 by Martin Stöter (stoeter(at)mpi-cbg.de)"; generalHelpURL = "https://github.com/stoeter/Fiji-Tools-for-HCS/wiki"; macroHelpURL = generalHelpURL + "/" + macroName; macroHtml = "" +"" + macroName + "\n" + macroRelease + "

" +"" + macroDescription + "

" +"Check for more help on this web page:
" +"" + macroHelpURL + "
" +"General info:
" +"" + generalHelpURL + "
" +"...get these URLs from Log window!
" +""; //print macro name and current time to Log window getDateAndTime(year, month, dayOfWeek, dayOfMonth, hour, minute, second, msec); month++; print("\\Clear"); print(macroName,"\nStart:",year+"-"+month+"-"+dayOfMonth+", "+hour+"-"+minute+"-"+second); print(macroHelpURL); print(generalHelpURL); //start macro Dialog.create("Fiji macro: " + macroName); Dialog.addMessage("Fiji macro: " + macroName + " (Fiji-Tools-for-HCS by TDS@MPI-CBG)\n \n" + macroShortDescription + "\n \nClick 'OK' to go on, 'Cancel' to quit or 'Help' for online description."); Dialog.addHelp(macroHtml); Dialog.show; //choose folders var inputPath = ""; var outputPath = "not available"; doLogTransformation = false; xyScale = 0.5; rollingBallRadius = 0; outputFileTag = "_label"; outputFileOverlayTag = "_overlay"; defaultOutputfolderName = "StarDist"; // run("Command From Macro", "command=[de.csbdresden.stardist.StarDist2D], args=['input':'" + imageNameToSD + "', 'modelChoice':'Versatile (fluorescent nuclei)', 'normalizeInput':'true', 'percentileBottom':'1.0', 'percentileTop':'98.8', 'probThresh':'0.75', 'nmsThresh':'0.02', 'outputType':'Label Image', 'nTiles':'1', 'excludeBoundary':'2', 'roiPosition':'Automatic', 'verbose':'false', 'showCsbdeepProgress':'false', 'showProbAndDist':'false'], process=[false]"); modelSD = "Versatile (fluorescent nuclei)"; normalizationSD = "true"; percentileBottomSD = 1.00; percentileTopSD = 98.80; probThreshSD = 0.40; nmsThreshSD = 0.15; outputTypeSD = "Both"; nTilesSD = 1; excludeBoundarySD = 2; inputPath = getDirectory("Choose image folder... "); Dialog.create("Set StarDist options"); Dialog.addMessage("====== Input image pre-processing ======"); Dialog.addCheckbox("Do intensity log transformation?", doLogTransformation); Dialog.addNumber("Pre-scaling factor of image", xyScale); Dialog.addNumber("Subtract Background? (0 = no bkg. subtraction)", rollingBallRadius); Dialog.addMessage("====== StarDist model ======"); Dialog.addChoice("Choose StarDist model:", newArray("Versatile (fluorescent nuclei)")); Dialog.addMessage("====== Normalization ======"); Dialog.addChoice("Do normalization?", newArray("true", "false")); Dialog.addSlider("Percentile low:", 0.0, 100.0, percentileBottomSD); Dialog.addSlider("Percentile high:", 0.0, 100.0, percentileTopSD); Dialog.addMessage("====== NMS Post-processing ======"); Dialog.addSlider("Probability/Score threshold:", 0.0, 1.0, probThreshSD); Dialog.addSlider("Overlap threshold:", 0.0, 1.0, nmsThreshSD); Dialog.addMessage("====== Advanced Options ======"); Dialog.addNumber("Number of tiles:", nTilesSD); Dialog.addNumber("Boundary exclusion:", excludeBoundarySD); Dialog.addMessage("====== Output settings ======"); Dialog.addString("StarDist output file tag:", outputFileTag); Dialog.addString("Change default output folder name?", defaultOutputfolderName); Dialog.addChoice("Output type of SD (Both=overlays, Label=label)?", newArray("Label Image", "Both"), outputTypeSD); Dialog.show(); doLogTransformation = Dialog.getCheckbox(); xyScale = Dialog.getNumber(); rollingBallRadius = Dialog.getNumber(); modelSD = Dialog.getChoice(); normalizationSD = Dialog.getChoice(); percentileBottomSD = Dialog.getNumber(); percentileTopSD = Dialog.getNumber(); probThreshSD = Dialog.getNumber(); nmsThreshSD = Dialog.getNumber(); nTilesSD = Dialog.getNumber(); excludeBoundarySD = Dialog.getNumber(); outputFileTag = Dialog.getString(); defaultOutputfolderName = Dialog.getString(); outputTypeSD = Dialog.getChoice(); print("log transformation:", doLogTransformation, "; scaling factor:", xyScale, "; subtract Background:", rollingBallRadius); print("StarDist model:", modelSD, "normalization:", normalizationSD, "percentile low:", percentileBottomSD, "percentile high:", percentileTopSD, "probability threshold:", probThreshSD, "overlap threshold:", nmsThreshSD, "tiles:", nTilesSD, "boundary exclusion:", excludeBoundarySD); print("output file tag:", outputFileTag, "output folder name", defaultOutputfolderName, "output type", outputTypeSD); //print("Default output folder was set to:", defaultOutputfolderName); // ===== organize output (folder) settings ===== //outputPath = substring(inputPaths[currentFolder], 0, lastIndexOf(inputPaths[currentFolder], File.separator)) + File.separator + "Zprojection" + File.separator; outputPath = inputPath + File.separator + defaultOutputfolderName + File.separator; //outputPath = getDirectory("Choose result image folder... or create a folder"); if (!File.exists(outputPath)) { File.makeDirectory(outputPath); print("New output folder -> made folder for StarDist files: " + outputPath); //to log window } printPaths = "inputPath = \"" + inputPath + "\";\noutputPath = \"" + outputPath + "\";"; print(printPaths); //set log file number tempLogFileNumber = 1; if(outputPath != "not available") while (File.exists(outputPath + "Log_temp_" + tempLogFileNumber +".txt")) tempLogFileNumber ++; //find last tempLog file to prevent overwriting of log //initialize => default settings run("Set Measurements...", "area mean standard min centroid center shape integrated median display redirect=None decimal=3"); run("Input/Output...", "jpeg=95 gif=-1 file=.txt copy_column copy_row save_column save_row"); //run("Close All"); run("Color Balance..."); //////////////////////////////// M A C R O C O D E /////////////////////////////// //set array variables batchMode = true; var fileExtension = ".tif"; //pre-definition of extension var filterStrings = newArray("C01.tif","",""); //pre-definition of strings to filter var availableFilterTerms = newArray("no filtering", "include", "exclude"); //dont change this var filterTerms = newArray("include", "no filtering", "no filtering"); //pre-definition of filter types var displayFileList = false; //shall array window be shown? setDialogImageFileFilter(); //get file list ALL fileList = getFileListSubfolder(inputPath, displayFileList); //read all files in subfolders fileList = getFileType(fileList, fileExtension, displayFileList); //filter for extension fileList = getFilteredFileList(fileList, false, displayFileList); //filter for strings //waitForUser("Do you really want to open " + fileList.length + " files?" + "\n\n" + "Otherwise press 'ESC' and check image list and filter text!"); //setBatchMode(batchMode); //go through all file for (currentFile = 0; currentFile < fileList.length; currentFile++) { showProgress(currentFile / fileList.length); showStatus("processing" + fileList[currentFile]); if (endsWith(fileList[currentFile], ".tif")) { //check if it is right file and handle error on open() IJ.redirectErrorMessages(); run("TIFF Virtual Stack...", "open=[" + fileList[currentFile] + "]"); } else { IJ.redirectErrorMessages(); open(fileList[currentFile]); } if (nImages > 0) { //if image is open fileName = getTitle(); print("opened (" + (currentFile + 1) + "/" + fileList.length + "):", fileList[currentFile]); //to log window imageName = getTitle(); getDimensions(width, height, channels, slices, frames); if (doLogTransformation) run("Log"); run("Scale...", "x=" + xyScale + " y=" + xyScale + " interpolation=Bilinear average create"); if (rollingBallRadius > 0) run("Subtract Background...", "rolling=" + rollingBallRadius); imageNameToSD = getTitle(); //run("Command From Macro", "command=[de.csbdresden.stardist.StarDist2D], args=['input':'" + imageNameToSD + "', 'modelChoice':'Versatile (fluorescent nuclei)', 'normalizeInput':'true', 'percentileBottom':'1.0', 'percentileTop':'98.8', 'probThresh':'0.05', 'nmsThresh':'0.15', 'outputType':'Both', 'nTiles':'1', 'excludeBoundary':'2', 'roiPosition':'Automatic', 'verbose':'false', 'showCsbdeepProgress':'false', 'showProbAndDist':'false'], process=[false]"); //run("Command From Macro", "command=[de.csbdresden.stardist.StarDist2D], args=['input':'" + imageNameToSD + "', 'modelChoice':'Versatile (fluorescent nuclei)', 'normalizeInput':'true', 'percentileBottom':'1.0', 'percentileTop':'98.8', 'probThresh':'0.75', 'nmsThresh':'0.02', 'outputType':'Label Image', 'nTiles':'1', 'excludeBoundary':'2', 'roiPosition':'Automatic', 'verbose':'false', 'showCsbdeepProgress':'false', 'showProbAndDist':'false'], process=[false]"); run("Command From Macro", "command=[de.csbdresden.stardist.StarDist2D], args=['input':'" + imageNameToSD + "', 'modelChoice':'" + modelSD + "', 'normalizeInput':'" + normalizationSD + "', 'percentileBottom':'" + percentileBottomSD + "', 'percentileTop':'" + percentileTopSD + "', 'probThresh':'" + probThreshSD + "', 'nmsThresh':'" + nmsThreshSD + "', 'outputType':'" + outputTypeSD + "', 'nTiles':'" + nTilesSD + "', '" + excludeBoundarySD + "':'2', 'roiPosition':'Automatic', 'verbose':'false', 'showCsbdeepProgress':'false', 'showProbAndDist':'false'], process=[false]"); if (outputTypeSD == "Both" || outputTypeSD == "Label Image") { selectImage("Label Image"); run("Scale...", "width=" + width + " height=" + height + " interpolation=None average create"); print("save:", outputPath + substring(imageName, 0, lengthOf(imageName) - 4) + outputFileTag + ".tif"); saveAs("Tiff", outputPath + substring(imageName, 0, lengthOf(imageName) - 4) + outputFileTag + ".tif"); } if (outputTypeSD == "Both") { selectWindow(imageNameToSD); setMinAndMax(0, 300); roiManager("Show All"); print("save:", outputPath + substring(imageName, 0, lengthOf(imageName) - 4) + outputFileOverlayTag + ".tif"); saveAs("Tiff", outputPath + substring(imageName, 0, lengthOf(imageName) - 4) + outputFileOverlayTag + ".tif"); roiManager("reset"); } close("*"); //waitForUser("check"); } else { //if no images open print("file (" + (currentFile + 1) + "/" + fileList.length + "): ", fileList[currentFile], " could not be opened."); //if open() error } } //print current time to Log window and save log getDateAndTime(year, month, dayOfWeek, dayOfMonth, hour, minute, second, msec); month++; print("Macro executed successfully.\nEnd:",year+"-"+month+"-"+dayOfMonth+", h"+hour+"-m"+minute+"-s"+second); selectWindow("Log"); if(outputPath != "not available") { saveAs("Text", outputPath + "Log_"+year+"-"+month+"-"+dayOfMonth+", h"+hour+"-m"+minute+"-s"+second+".txt"); if (File.exists(outputPath + "Log_temp_" + tempLogFileNumber +".txt")) File.delete(outputPath + "Log_temp_" + tempLogFileNumber + ".txt"); //delete current tempLog file } ///////////////////////////////////////////////////////////////////////////////////////////// //////// F U N C T I O N S ///////////// ///////////////////////////////////////////////////////////////////////////////////////////// //function opens a dialog to set text list for filtering a list //example: setDialogImageFileFilter(); //this function set interactively the global variables used by the function getFilteredFileList //this function needs global variables! (see below) /* //var fileExtension = ".tif"; //default definition of extension //var filterStrings = newArray("","",""); //default definition of strings to filter //var availableFilterTerms = newArray("no filtering", "include", "exclude"); //dont change this //var filterTerms = newArray(filterStrings.length); for (i = 0; i < filterStrings.length; i++) {filterTerms[i] = "no filtering";} //default definition of filter types (automatic) //var filterTerms = newArray("no filtering", "no filtering", "no filtering"); //default definition of filter types (manual) //var displayFileList = false; //shall array window be shown? */ function setDialogImageFileFilter() { Dialog.create("Image file filter..."); //enable use inveractivity Dialog.addMessage("Define the files to be processed:"); Dialog.addString("Files should have this extension:", fileExtension); //add extension Dialog.addMessage("Define filter for files:"); for (i = 0; i < filterStrings.length; i++) { Dialog.addString((i + 1) + ") Filter this text from file list: ", filterStrings[i]); Dialog.addChoice((i + 1) + ") Files with text are included/excluded?", availableFilterTerms, filterTerms[i]); } Dialog.addCheckbox("Check file lists?", displayFileList); //if check file lists will be displayed Dialog.show(); fileExtension = Dialog.getString(); for (i = 0; i < filterStrings.length; i++) { filterStrings[i] = Dialog.getString(); filterTerms[i] = Dialog.getChoice(); } displayFileList = Dialog.getCheckbox(); } //function gets all files from folders and subfolders //example: myFileList = getFileListSubfolder("/home/myFolder/", true); function getFileListSubfolder(inputPathFunction, displayList) { fileListFunction = getFileList(inputPathFunction); //read file list Array.sort(fileListFunction); returnedFileList = newArray(0); //this list stores all found files and is returned at the end of the function for (i=0; i < fileListFunction.length; i++) { if ((File.separator == "\\") && (endsWith(fileListFunction[i], "/"))) fileListFunction[i] = replace(fileListFunction[i],"/",File.separator); //fix windows/Fiji File.separator bug if (endsWith(fileListFunction[i], File.separator)) { //if it is a folder returnedFileListTemp = newArray(0); returnedFileListTemp = getFileListSubfolder(inputPathFunction + fileListFunction[i],displayList); returnedFileList = Array.concat(returnedFileList, returnedFileListTemp); } else { //if it is a file returnedFileList = Array.concat(returnedFileList, inputPathFunction + fileListFunction[i]); //print(i, inputPath + fileList[i]); //to log window } } if(inputPathFunction == inputPath) { //if local variable is equal to global path variable = if path is folder and NOT subfolder print(returnedFileList.length + " files found in selected folder and subfolders."); if (displayList) {Array.show("All files - all",returnedFileList);} } return returnedFileList; } //function filters all files with certain extension //example: myFileList = getFileType(myFileList, ".tif", true); function getFileType(fileListFunction, fileExtension, displayList) { returnedFileList = newArray(0); //this list stores all files found to have the extension and is returned at the end of the function if(lengthOf(fileExtension) > 0) { for (i = 0; i < fileListFunction.length; i++) { if (endsWith(fileListFunction[i],fileExtension)) returnedFileList = Array.concat(returnedFileList,fileListFunction[i]); } print(returnedFileList.length + " files found with extension " + fileExtension + "."); if (displayList) {Array.show("All files - filtered for " + fileExtension, returnedFileList);} } else { returnedFileList = fileListFunction; } return returnedFileList; } //function filters a file list for a certain strings //example: myFileList = getFilteredFileList(myFileList, false, true); //if filterOnInputList = true, then additional filtering is possible (e.g. file names containing "H08" and "D04" => H08 and D04 in list) //if filterOnInputList = false, then subsequent filtering is possible (e.g. file names containing "controls" and "positive" => positive controls, but not negative controls in list!) //this function needs global variables (see function setDialogImageFileFilter) //var filterStrings = newArray("","",""); //pre-definition of strings to filter //var availableFilterTerms = newArray("no filtering", "include", "exclude"); //dont change this //var filterTerms = newArray("no filtering", "no filtering", "no filtering"); function getFilteredFileList(fileListFunction, filterOnInputList, displayList) { skippedFilter = 0; for (i = 0; i < filterStrings.length; i++) { if (filterTerms[i] != availableFilterTerms[0]) { returnedFileList = newArray(0); //this list stores all files found to have the extension and is returned at the end of the function for (j = 0; j < fileListFunction.length; j++) { if (filterTerms[i] == "include" && indexOf(fileListFunction[j],filterStrings[i]) != -1) returnedFileList = Array.concat(returnedFileList,fileListFunction[j]); if (filterTerms[i] == "exclude" && indexOf(fileListFunction[j],filterStrings[i]) <= 0) returnedFileList = Array.concat(returnedFileList,fileListFunction[j]); } print(returnedFileList.length + " files found after filter: " + filterTerms[i] + " text " + filterStrings[i] + "."); if (displayList) {Array.show("List of files - after filtering for " + filterStrings[i], returnedFileList);} //see description above! default: filterOnInputList = false if(!filterOnInputList) fileListFunction = returnedFileList; } else skippedFilter++; } if (skippedFilter == filterStrings.length) returnedFileList = fileListFunction; //if no filter condition is selected return returnedFileList; } //////////////////////////////////////// E N D O F M A C R O ////////////////////////////