/* C. Jeff Tucker -- tucker1@niehs.nih.gov Dr. Patricia Jensen -- patricia.jensen@nih.gov National Institute of Environmental Health Sciences ********************** BEFORE BEGINNING MACRO ********************** The DEFiNE macro was designed to run in FIJI 1.51w using Java 1.8.0_66. There is no guarantee that DEFiNE will work on any other version. How to check which version of FIJI is running: Help > About ImageJ… How to change to FIJI 1.51w: Help > Update ImageJ… > Upgrade to: v1.51 To install the macro, go to Plugins > Macros > Install… and select the DEFiNE file. ****** DEFiNE ****** When running either function in DEFiNE, all images to run should be saved in one folder. For the Clean Images function, all images should have the same channel order. —- Clean Images Function —- Purpose: To remove autofluorescence and fluorescent artifacts from stacked images of neuron fibers. Requirements:  • Images cannot contain more than six channels. • Images must all have the same channel order. • Images must be stacked. Maximum intensity projections cannot be processed. Recommendation: • Images should be acquired containing an 'autofluorescence' channel for optimal cleanup. —- Quantify Fibers Function —- Purpose: To quantify the amount of fibers present in an image, using the area of pixels at a certain intensity or higher as a proxy for the number of fibers in an image. Requirements: • Images generated using the 'Clean Images' function are always in the proper format. • Images must be maximum intensity projections. • Images must contain only one channel. */ //Main function variables var step1 = false var step2 = false //Directory variables var dirInput = ""; var dirParent = ""; var dirOutput = ""; //Channel information variables var numChannels = 2; var numTrueSig = 1; var AutoCh = 0; var TrueSig1 = 0; var Sig1Label = ""; var TrueSig2 = 0; var Sig2Label = ""; var TrueSig3 = 0; var Sig3Label = ""; var TrueSig4 = 0; var Sig4Label = ""; var TrueSig5 = 0; var Sig5Label = ""; //Particle subtraction variables var MinSize1 = 40; var MinCirc1 = 0.17; var MinSize2 = 25; var MinCirc2 = 0.32; var MinSize3 = 15; var MinCirc3 = 0.4; var MinSize4 = 10; var MinCirc4 = 0.7; var MinSize5 = 5; var MinCirc5 = 0.8; //Small particle subtraction var MIPmaxsize = 1; var MIPCmin = 0.99; var MIPCmax = 1; //Autofluorescence subtraction variables var sdauto = 1; //Guided optimization variable var continueOptimization = "Yes"; var selectROI = "Yes"; var count = 1; var not_an_image = false; //*************************************** macro "DEFiNE_Macro [F1]"{ //Closes everything open before running program. Necessary to prevent errors. run("Close All"); print("\\Clear"); run("Clear Results"); mainmenu_help = "" +"

DEFiNE Help

" +"

The DEFiNE macro performs two functions:

" +"

1. Clean images

" +"

Purpose: To remove autofluorescence and other non-fiber background noise from images of neuron fibers.

" +"

Method:

" +"" +"

Output:

" +"" +"

Requirements

" +"" +"

2. Quantify fibers 

" +"

Purpose: To quantify the amount of fibers present in an image, using the area of pixels at a certain intensity or higher as a proxy for the number of fibers in an image.

" +"

Method:

" +"" +"

Output:

" +"" +"

Requirements:

" +""; //main menu Dialog.create("DEFiNE -- Digital Enhancement of Fibers with Noise Elimination"); Dialog.addMessage("Which function(s) would you like to perform?"); Dialog.addCheckbox("Clean images", false); Dialog.addCheckbox("Quantify fibers", false); Dialog.addHelp(mainmenu_help); Dialog.show(); step1 = Dialog.getCheckbox(); step2 = Dialog.getCheckbox(); if(step1 == true) DEFiNE(); if(step2 == true) quantify_Fibers(); print("DEFiNE Macro Complete");} //*************************************** //*************************************** function set_Directory(comment){ /* * Purpose: This function prompts the user to select an input directory. * All subsequent output directories are generated from this selection. * * Use: This function is used at the beginning of both the ‘Clean Images’ * and ‘Quantify Fibers’ functions. * * Var comment: A string used in the two DEFiNE functions to remind user * of which function is initiating. */ run("Input/Output...", "jpeg=100 gif=-1 file=.txt copy_row save_column save_row"); waitForUser(comment+"Please select the folder containing all images to be processed. "); dirInput = getDirectory("Choose Input Directory"); } //*************************************** function optimize_Settings(){ //Open image, go to next if not an image setBatchMode("hide"); //speeds up program x = 0; list = getFileList(dirInput); count = list.length; while (continueOptimization == "Yes"){ pathIn = dirInput+list[x]; if (endsWith(pathIn, ".txt") || endsWith(pathIn, "/")) { print(list[x]+" is not an image."); x = x + 1; } else{ run("Bio-Formats Importer", "open=pathIn autoscale color_mode=Default rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT"); getDimensions(w, h, channels, slices, frames); if(slices == 1) x = x + 1; else{ waitForUser("If this is the first time optimizing settings, use default settings when prompted."); if(AutoCh !=0) waitForUser("Now beginning the optimization of the autofluorescence channel subtraction"); if(AutoCh != 0) optimize_Auto(x); waitForUser("Now beginning the optimization of the large particle subtraction"); optimize_Large(x); waitForUser("Now beginning the optimization of the small particle subtraction"); optimize_Small(x); next_Image(); nextimage = Dialog.getChoice(); if(nextimage == "Yes - test settings on next image"){ x = x + 1;} else continueOptimization = "No";}} if( x >= count) { waitForUser("There are no more images in the folder."); continueOptimization = "No";}}} function optimize_Small(y) { list = getFileList(dirInput); pathIn = dirInput+list[y]; keeptesting = "Yes"; define_Small(); setBatchMode("hide"); run("Bio-Formats Importer", "open=pathIn autoscale color_mode=Default rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT"); for(i = 0; i < numTrueSig; i++) { keeptesting = "Yes"; if (i == 0){ coi = TrueSig1; colorchoice = Sig1Label;} else if (i == 1){ coi = TrueSig2; colorchoice = Sig2Label;} else if (i == 2){ coi = TrueSig3; colorchoice = Sig3Label;} else if (i == 3){ coi = TrueSig4; colorchoice = Sig4Label;} else if (i == 4){ coi = TrueSig5; colorchoice = Sig5Label;} while(keeptesting == "Yes"){ name = getTitle(); if(numChannels > 1) run("Split Channels"); if(numChannels == 1) rename("C1-"+name); remove_ParticlesOpt(coi, name, 1.5); remove_ParticlesOpt(coi, name, 2); remove_ParticlesOpt(coi, name, 2.5); remove_ParticlesOpt(coi, name, 3); removal_Image(coi); if(AutoCh != 0) autochannel_Subtraction(coi, name, colorchoice); selectWindow("C"+coi+"-"+name); run("Duplicate...", "title=NewStack duplicate"); rename("Processed Stack - C"+coi+"-"+name); run(colorchoice); MIP(coi, name); RemoveParticlesMIPOpt(coi,name); run(colorchoice); rename("Small Particles Removed - C"+coi+"-"+name); if(AutoCh != 0) select_Close("Autofluorescence_Channel_Particles"); select_Close("ParticlesRemoved_channel"+coi); for(b = 0; b < numChannels; b++) { c = b +1; if(coi != c) select_Close("C"+c+"-"+name);} selectWindow("Processed Stack - C"+coi+"-"+name); run("Z Project...", "projection=[Max Intensity]"); rename("Before_Small_Particle_Subtraction_C"+coi+"-"+name); select_Close("Processed Stack - C"+coi+"-"+name); setBatchMode("exit and display"); waitForUser("Compare the images before and after small particle subtraction.\n"+ " Check for:\n"+ " 1. Removed fibers\n"+ " 2. Remaining autofluorescent particles in final image"); Dialog.create(""); Dialog.addChoice("Did these settings work?", newArray("Yes","No")); Dialog.show(); is_it_good = Dialog.getChoice(); if(is_it_good == "Yes") { keeptesting = "No"; run("Close All"); if(i < numTrueSig - 1) { waitForUser("Now applying settings to next channel"); setBatchMode("hide"); run("Bio-Formats Importer", "open=pathIn autoscale color_mode=Default rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT"); } } else { Dialog.create("")' Dialog.addChoice("What went wrong?", newArray("A fiber was removed","Autofluorescence was not removed")); Dialog.show(); problem = Dialog.getChoice(); if(problem == "A fiber was removed") { waitForUser("Decrease the maximum size of particles to remove\n"+ " OR \n"+ "increase the minimum circularity"); define_Small(); } else { waitForUser("Increase the maximum size of particles to remove\n"+ " OR \n"+ "decrease the minimum circularity"); define_Small();} run("Close All"); setBatchMode("hide"); run("Bio-Formats Importer", "open=pathIn autoscale color_mode=Default rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT");} }}} function RemoveParticlesMIPOpt(channel, title){ selectWindow("C"+channel+"-"+title); Create2SDParticleMaskMIP(1); CreateParticleMaskMIP(); selectWindow("ParticlesToRemove"); run("Duplicate...", "title=New duplicate"); rename("Small_Particles"); selectWindow("ParticlesToRemove"); SubtractParticlesMIP(channel); run("Clear Results"); } function optimize_Large(y) { list = getFileList(dirInput); pathIn = dirInput+list[y]; keeptesting = "Yes"; setBatchMode("hide"); define_Particles(); if(AutoCh != 0) run("Bio-Formats Importer", "open=pathIn autoscale color_mode=Default rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT"); for(i = 0; i < numTrueSig; i++) { keeptesting = "Yes"; if (i == 0){ coi = TrueSig1; colorchoice = Sig1Label;} else if (i == 1){ coi = TrueSig2; colorchoice = Sig2Label;} else if (i == 2){ coi = TrueSig3; colorchoice = Sig3Label;} else if (i == 3){ coi = TrueSig4; colorchoice = Sig4Label;} else if (i == 4){ coi = TrueSig5; colorchoice = Sig5Label;} while(keeptesting == "Yes"){ name = getTitle(); if(numChannels > 1) run("Split Channels"); if(numChannels == 1) rename("C1-"+name); remove_ParticlesOpt(coi, name, 1.5); remove_ParticlesOpt(coi, name, 2); remove_ParticlesOpt(coi, name, 2.5); remove_ParticlesOpt(coi, name, 3); removal_Image(coi); if(AutoCh != 0) autochannel_Subtraction(coi, name, colorchoice); selectWindow("C"+coi+"-"+name); run("Duplicate...", "title=NewStack duplicate"); rename("Processed Stack - C"+coi+"-"+name); run(colorchoice); for(b = 0; b < numChannels; b++) { c = b +1; if(coi != c) select_Close("C"+c+"-"+name);} if(AutoCh != 0) select_Close("Autofluorescence_Channel_Particles"); select_Close("C"+coi+"-"+name); run("Bio-Formats Importer", "open=pathIn autoscale color_mode=Default rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT"); selectWindow(name); if(numChannels > 1) run("Split Channels"); if(numChannels == 1) rename("C1-"+name); for(b = 0; b < numChannels; b++) { c = b +1; if(coi != c) select_Close("C"+c+"-"+name);} selectWindow("C"+coi+"-"+name); rename("Uprocessed-C"+coi+"-"+name); run(colorchoice); setBatchMode("exit and display"); waitForUser("Compare the processed channel to the unprocessed image.\n"+ " Check for:\n"+ " 1. Removed fibers\n"+ " 2. Remaining autofluorescent particles in processed image"); Dialog.create(""); Dialog.addChoice("Did these settings work?", newArray("Yes","No")); Dialog.show(); is_it_good = Dialog.getChoice(); if(is_it_good == "Yes") { keeptesting = "No"; run("Close All"); if(i < numTrueSig - 1) { waitForUser("Now applying settings to next channel"); setBatchMode("hide"); run("Bio-Formats Importer", "open=pathIn autoscale color_mode=Default rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT"); } } else { Dialog.create("")' Dialog.addChoice("What went wrong?", newArray("A fiber was removed","Autofluorescence was not removed")); Dialog.show(); problem = Dialog.getChoice(); if(problem == "A fiber was removed") { fiber_Particle(); } else { remove_Particle();} run("Close All"); setBatchMode("hide"); run("Bio-Formats Importer", "open=pathIn autoscale color_mode=Default rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT"); } }} } function optimize_Auto(y){ keeptesting = "Yes"; setBatchMode("hide"); define_Auto(); while(keeptesting == "Yes"){ name = getTitle(); run("Split Channels"); for(b = 0; b < numChannels; b++) { c = b +1; if(AutoCh != c) select_Close("C"+c+"-"+name); } selectWindow("C"+AutoCh+"-"+name); Create2SDParticleMask(sdauto); selectWindow("OriginalMask"); rename("Binary_of_Autofluorescence_Channel"); run("Clear Results"); setBatchMode("exit and display"); waitForUser("Please compare the original autofluorescence channel to the binary mask.\n"+ "Look for autofluoresence that was not captured in the binary mask\n"+ "OR\n"+ "fibers that were captured in the binary mask."); Dialog.create(""); Dialog.addChoice("Did these settings work?", newArray("Yes","No")); Dialog.show(); is_it_good = Dialog.getChoice(); if(is_it_good == "Yes") { keeptesting = "No"; run("Close All"); } else { Dialog.create("")' Dialog.addChoice("What went wrong?", newArray("A fiber was captured in the binary image","Autofluorescence was not captured in the binary mask")); Dialog.show(); problem = Dialog.getChoice(); if(problem == "A fiber was captured in the binary image") { waitForUser("Increase the number of standard deviations."); print("Increase the number of standard deviations."); } else { waitForUser("Decrease the number of standard deviations."); print("Decrease the number of standard deviations."); } run("Close All"); setBatchMode("hide"); define_Auto(); list = getFileList(dirInput); pathIn = dirInput+list[y]; run("Bio-Formats Importer", "open=pathIn autoscale color_mode=Default rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT"); } }} function define_Channels(){ /* *Purpose: This generates a dialog box that prompts users to input information *about images to be processed. * *Use: This function is called in the optimize_Settings() function *and the DEFiNE() function. */ channelinformation_help = "" +"

Channel Information Help

" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"
InputDescription
Total channels" +"

This is the total number of channels present in each image file, including fiber channels, non-fiber channels, and the autofluorescence channel.

" +"

Each image must contain at least one and no more than six total channels.

" +"
Channels to cleanThis is the number of channels containing fibers that you would like to process. This number does not include the autofluorescence channel.
Autofluorescence channel numberInput the FIJI-defined channel number for the autofluorescence channel. It can be found at the top left corner of an image when open (#/total channels). Leave as 0 if not imaged.
# channel to clean" +"

Input the FIJI-defined channel number for each channel that will be cleaned. If you have less than four channels to clean, leave unused channel spaces defined as '0'.

" +"

Cleaned channels will be saved as name_Ch#.tif where # is your specified channel number.

" +"
# channel color" +"

Input the color of the channel to clean. Cleaned channels will be presented and saved using the specified color.

" +"

Each channel to clean must have a defined channel color. While it is not necessary to define unique colors for each channel, it is helpful to keep track of multiple fluorophores.

" +"
" +"

"; totalchannels = newArray("1","2","3","4","5","6"); totalprocess = newArray("1","2","3","4","5","6"); channel_numbers = newArray("0","1", "2", "3", "4", "5", "6"); channel_colors = newArray("NA","Fire","Grays", "Ice", "Spectrum", "3-3-2 RGB", "Red", "Green", "Blue", "Cyan", "Magenta","Yellow","Red/Green"); Dialog.create(" Channel Information "); Dialog.addHelp(channelinformation_help); Dialog.addChoice("Total channels:", totalchannels); Dialog.addChoice("Channels to clean:", totalprocess); Dialog.addMessage(""); Dialog.addMessage("When opening images in FIJI, channels are put in numerical order."); Dialog.addMessage("Below, please provide the FIJI-defined channel numbers, as well as"); Dialog.addMessage("a user-defined color for each channel."); Dialog.addMessage(""); Dialog.addMessage("If you are cleaning less than four total channels,"); Dialog.addMessage("define extra channels with 0 and colors with 'NA'."); Dialog.addMessage(""); Dialog.addMessage("If your images do not contain an autofluorescence"); Dialog.addMessage("channel, define it as 0."); Dialog.addChoice("Autofluorescence channel number:", channel_numbers); Dialog.addMessage(""); Dialog.addChoice("First channel to clean:", channel_numbers); Dialog.addChoice("First channel color:", channel_colors); Dialog.addMessage(""); Dialog.addChoice("Second channel to clean:", channel_numbers); Dialog.addChoice("Second channel color:", channel_colors); Dialog.addMessage(""); Dialog.addChoice("Third channel to clean:", channel_numbers); Dialog.addChoice("Third channel color:", channel_colors); Dialog.addMessage(""); Dialog.addChoice("Fourth channel to clean:", channel_numbers); Dialog.addChoice("Fourth channel color:", channel_colors); Dialog.show(); numChannels = Dialog.getChoice(); numTrueSig = Dialog.getChoice(); AutoCh = Dialog.getChoice(); TrueSig1 = Dialog.getChoice(); Sig1Label = Dialog.getChoice(); TrueSig2 = Dialog.getChoice();; Sig2Label = Dialog.getChoice(); TrueSig3 = Dialog.getChoice(); Sig3Label = Dialog.getChoice(); TrueSig4 = Dialog.getChoice(); Sig4Label = Dialog.getChoice(); numChannels = parseInt(numChannels); numTrueSig = parseInt(numTrueSig); AutoCh = parseInt(AutoCh); TrueSig1 = parseInt(TrueSig1); TrueSig2 = parseInt(TrueSig2); TrueSig3 = parseInt(TrueSig3); TrueSig4 = parseInt(TrueSig4); } function define_Particles(){ /* * Purpose: This generates a dialog box that prompts users to define the * minimum sizes and circularities for the five large particle subtractions. * * Use: This function is called in the optimize_Settings(), DEFiNE(), * remove_Particle() and fiber_Particle() functions. */ sizeinformation_help = "" +"

Size and Circularity Help

" +"

During the 'Clean Images' function, five types of particles will be
" +"removed based on their sizes and circularities. The first type of
" +"particle to remove is one that has a size greater than 'Minimum
" +"Size 1' and a circularity greater than 'Minimum Circularity 1'.

" +"

The size and circularity of fibers are inversely related. As fibers
" +"decrease in size, their circularities increase in value. A schematic
" +"of this relationship is displayed below.

" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"
 FiberCircularity
" +"

                      _________
_________/               

" +"
~0.1
" +"

 

" +"

               \\_/

" +"
~0.75
" +"

 

" +"

If you would like to remove less than five types of particles, reuse
" +"minimum size and minimum circularity values.

"; Dialog.create("Size and circularities of particles to remove"); Dialog.addHelp(sizeinformation_help); Dialog.addMessage("Non-fiber particles and fibers can be separated by their sizes and circularities."); Dialog.addMessage("DEFiNE will remove any particle that is larger and more circular than the values input below."); Dialog.addMessage(""); Dialog.addSlider("Minimum Size 1:", 0, 500, MinSize1); Dialog.addSlider("Minimum Circularity 1:", 0, 1, MinCirc1); Dialog.addMessage(""); Dialog.addSlider("Minimum Size 2:", 0, 500, MinSize2); Dialog.addSlider("Minimum Circularity 2:", 0, 1, MinCirc2); Dialog.addMessage(""); Dialog.addSlider("Minimum Size 3:", 0, 500, MinSize3); Dialog.addSlider("Minimum Circularity 3:", 0, 1, MinCirc3); Dialog.addMessage(""); Dialog.addSlider("Minimum Size 4:", 0, 500, MinSize4); Dialog.addSlider("Minimum Circularity 4:", 0, 1, MinCirc4); Dialog.addMessage(""); Dialog.addSlider("Minimum Size 5:", 0, 500, MinSize5); Dialog.addSlider("Minimum Circularity 5:", 0, 1, MinCirc5); Dialog.show(); MinSize1 = Dialog.getNumber(); MinCirc1 = Dialog.getNumber(); MinSize2 = Dialog.getNumber(); MinCirc2 = Dialog.getNumber(); MinSize3 = Dialog.getNumber(); MinCirc3 = Dialog.getNumber(); MinSize4 = Dialog.getNumber(); MinCirc4 = Dialog.getNumber(); MinSize5 = Dialog.getNumber(); MinCirc5 = Dialog.getNumber(); } function define_Auto(){ /* * Purpose: This generates a dialog box that prompts users to select the * number of standard deviations above average pixel intensity at which to * threshold the autofluorescence channel. * * Use: This function is called in the optimize_Settings() function and * the DEFiNE() function. */ autoinformation_help = "" +"

Autofluorescence Channel Help

" +"

The autofluorescence channel is converted to a binary image with a
" +"threshold at X standard deviation(s) above the average intensity of the
" +"image. All pixels above the threshold are removed from the fiber
" +"channel.

" +"

Depending on the fluorophore(s) used, there can be cross-talk into the
" +"autofluorescence channel. If this occurs, you will want to raise the
" +"threshold to ensure that a fiber is not accidentally removed.

"; Dialog.create("Stringency of autofluorescence channel subtraction"); Dialog.addHelp(autoinformation_help); Dialog.addMessage("Below, set the number of standard deviations above the average\n" +"intensity of pixels at which to threshold the autofluorescence channel."); Dialog.addSlider("# of SD",0,10,sdauto); Dialog.show(); sdauto = Dialog.getNumber(); } function define_Small(){ Dialog.create("Small Particle Subtraction"); Dialog.addMessage("Below, define the maximum size and circularity of particles"); Dialog.addMessage("to remove from MIP of processed image."); Dialog.addNumber("Maximum Size (micron^2): ", 1); Dialog.addNumber("Minimum Circularity:",0.99); Dialog.addNumber("Maximum Circularity:", 1); Dialog.show(); MIPmaxsize = Dialog.getNumber(); MIPCmin = Dialog.getNumber(); MIPCmax = Dialog.getNumber(); } function remove_ParticlesOpt(channel, title, stan){ /* * Purpose: This function performs one large particle subtraction, * using a threshold of ‘stan’ standard deviations above average pixel intensity. * * Use: This function is called in the display_Images(y) function. * * Var channel: A number representing the channel to process * Var title: A string, the name of the original image * Var stan: A number, the number of standard deviations above average * intensity at which to threshold the image */ selectWindow("C"+channel+"-"+title); Create2SDParticleMask(stan); CreateParticleMask(); CombineMasks(); selectWindow("ParticlesToRemove"); run("Duplicate...", "title=NewStack duplicate"); rename("ParticlesToRemove_"+stan); SubtractParticles(channel); CloseParticleMasks(); run("Clear Results");} function removal_Image(coi1) { /* * Purpose: This function combines the binary masks of the particles * removed during the four particle subtractions. * * Use: This function is called in the display_Images(y) function. * * Var coi1: A number, the channel number of the processed image */ image_Invert("1.5"); image_Invert("2"); image_Invert("2.5"); image_Invert("3"); add_Particles("1.5","2","b"); add_Particles("2.5","3","combo"); imageCalculator("Add create stack", "combo","b"); selectWindow("Result of combo"); rename("ParticlesRemoved_channel"+coi1); select_Close("combo"); select_Close("b"); selectWindow("ParticlesRemoved_channel"+coi1); run("Invert LUT");} function image_Invert(sd){ /* * Purpose: This function inverts the binary mask of removed particles. * * Use: This function is called in the removal_Image(coi1) function. * * Var sd: A number, the number of standard deviations used for the * large particle subtraction */ selectWindow("ParticlesToRemove_"+sd); run("Invert","stack"); run("Invert LUT");} function add_Particles(sd1, sd2, title){ /* * Purpose: To combine and close two of the masks generated from the * large particle subtraction. * * Use: This function is called in the removal_Image(coi1) function. * * Var sd1: The standard deviation used in the first large particle subtraction * Var sd2: The standard deviation used in the second large particle subtraction * Var title: The name of the original image */ imageCalculator("Add create stack", "ParticlesToRemove_"+sd1,"ParticlesToRemove_"+sd2); rename(title); select_Close("ParticlesToRemove_"+sd1); select_Close("ParticlesToRemove_"+sd2);} function autochannel_Subtraction(coi2, name2, colorchoice2){ /* * Purpose: This function converts the autofluorescence channel to a * binary image and subtracts the particles from the fiber channel. * * Use: This function is called in the display_Images(y) function. * * Var coi2: The channel number to be processed * Var name2: The name of the original image * Var colorchoice2: The color of the channel to be processed */ selectWindow("C"+AutoCh+"-"+name2); Create2SDParticleMask(sdauto); selectWindow("OriginalMask"); rename("ParticlesToRemove"); run("Invert", "stack"); SubtractParticles(coi2); run("Clear Results"); selectWindow("ParticlesToRemove"); rename("Autofluorescence_Channel_Particles"); selectWindow("C"+coi2+"-"+name2); run(colorchoice);} function select_Close(channel){ /* * Purpose: To select and close specific windows. * * Use: This function is called in the display_Images(y), removal_Image(coi1), * DEFiNE(), SubtractParticles(channel2), * RemoveAutoParticles(channel, title, autoch), MIP(channel, title), * and add_Particles(sd1, sd2, title) functions. * * Var channel: The name of the window to close. */ selectWindow(channel); close();} function settings_Check(){ /* * Purpose: This function asks the user if the settings worked. * * Use: This function is called in the optimize_Settings() function. */ Dialog.create(""); Dialog.addChoice("Did these settings work?", newArray("Yes","No")); Dialog.show(); } function next_Image(){ /* * Purpose: This function ends the optimize settings function and prompts * the user if they would like to try the settings on another image from * the input folder. * * Use: This function is called in the optimize_Settings() function. */ run("Close All"); Dialog.create(""); Dialog.addChoice("Would you like to test these settings on the next image?", newArray("Yes - test settings on next image","No - apply settings and run 'Clean Images' function")); Dialog.show(); } function fiber_Particle(){ /* * Purpose: To identify the size and circularity of a removed fiber from * the large particle subtraction and print recommended settings updates. * * Use: This function is called in the optimize_Settings() function. */ selectROI = "Yes"; while (selectROI == "Yes"){ waitForUser("Using the rectangle tool, draw an ROI over ONE fiber in the 'ParticlesRemoved' window. Then press okay."); run("Duplicate...", " "); rename("IncludedFiber"); run("Analyze Particles...", "display add"); roiManager("reset"); close("ROI Manager"); contiguousFiberCheck(); } av = getResult("Area",0); cir = getResult("Circ.",0); run("Clear Results"); run("Close All"); if(MinSize1 < av && MinCirc1 < cir) error1 = "Increase Minimum Circularity 1 to a value of "+cir+" or greater"; else if(MinSize2 < av && MinCirc2 < cir) error1 = "Increase Minimum Circularity 2 to a value of "+cir+" or greater"; else if(MinSize3 < av && MinCirc3 < cir) error1 = "Increase Minimum Circularity 3 to a value of "+cir+" or greater"; else if(MinSize4 < av && MinCirc4 < cir) error1 = "Increase Minimum Circularity 4 to a value of "+cir+" or greater"; else if(MinSize5 < av && MinCirc5 < cir) error1 = "Increase Minimum Circularity 5 to a value of "+cir+" or greater"; if(MinSize1 < av && MinCirc1 < cir) error2 = "Increase Minimum Size 1 to a value of "+av+" or greater"; else if(MinSize2 < av && MinCirc2 < cir) error2 = "Increase Minimum Size 2 to a value of "+av+" or greater"; else if(MinSize3 < av && MinCirc3 < cir) error2 = "Increase Minimum Size 3 to a value of "+av+" or greater"; else if(MinSize4 < av && MinCirc4 < cir) error2 = "Increase Minimum Size 4 to a value of "+av+" or greater"; else if(MinSize5 < av && MinCirc5 < cir) error2 = "Increase Minimum Size 5 to a value of "+av+" or greater"; print("Recommended update to not remove selected fiber:"); print(error1); print("OR"); print(error2); waitForUser("Refer to the FIJI log for recommended settings."); define_Particles();} function contiguousFiberCheck(){ /* * Purpose: To ensure that only one contiguous fiber was selected when * optimizing settings. Only one particle should be selected because settings * are best updated incrementally. * * Use: This function is called in the fiber_Particle() and remove_Particle() * functions. */ numParticles = nResults(); if( numParticles > 1) { select_Close("IncludedFiber"); run("Clear Results"); Dialog.create(""); Dialog.addMessage("ROI contains more than one contiguous particle."); Dialog.addMessage("Press okay to select new ROI."); Dialog.show(); selectROI = "Yes";} else selectROI = "No";} function remove_Particle(){ /* * Purpose: To identify the size and circularity of retained autofluorescence * or fluorescent artifacts and print recommended settings updates. * * Use: This function is called in the optimize_Settings() function. */ selectROI = "Yes"; while (selectROI == "Yes"){ waitForUser("Using the rectangle tool, draw an ROI over only ONE autofluorescent particle on the processed image. Then press okay."); run("Duplicate...", " "); rename("Autofluorescence_included"); waitForUser("1. Select the 'Autofluorescence_included' image \n2. Go to Image --> Adjust --> Threshold"+ "\n3. Set a threshold that captures the autofluorescence you wish to remove."+ "\n4. Press Apply."+ "\n5. Close the threshold window."+ "\n6. Press Okay."); selectWindow("Autofluorescence_included"); rename("IncludedFiber"); run("Analyze Particles...", "display add"); roiManager("reset"); close("ROI Manager"); contiguousFiberCheck(); } av = getResult("Area",0); cir = getResult("Circ.",0); run("Clear Results"); run("Close All"); error1 = ""; error2 = ""; error3 = ""; if(MinSize5 > av && MinCirc5 < cir) error1 = "Decrease Minimum Size 5 to "+av+" or less"; else if(MinSize4 > av && MinCirc4 < cir) error1 = "Decrease Minimum Size 4 to "+av+" or less OR decrease Minumum Circularity 5 to "+cir+" or less"; else if(MinSize3 > av && MinCirc3 < cir) error1 = "Decrease Minimum Size 3 to "+av+" or less OR decrease Minumum Circularity 4 to "+cir+" or less"; else if(MinSize2 > av && MinCirc2 < cir) error1 = "Decrease Minimum Size 2 to "+av+" or less OR decrease Minumum Circularity 3 to "+cir+" or less"; else if(MinSize1 > av && MinCirc1 < cir) error1 = "Decrease Minimum Size 1 to "+av+" or less OR decrease Minumum Circularity 2 to "+cir+" or less"; else if(MinSize1 < av && MinCirc1 > cir) error2 = "Decrease Minimum Circularity 1 to "+cir+" or less"; else if(MinSize2 < av && MinCirc2 > cir) error2 = "Decrease Minimum Circularity 2 to "+cir+" or less OR decrease Minumum Size 1 to "+av+" or less"; else if(MinSize3 < av && MinCirc3 > cir) error2 = "Decrease Minimum Circularity 3 to "+cir+" or less OR decrease Minumum Size 2 to "+av+" or less"; else if(MinSize4 < av && MinCirc4 > cir) error2 = "Decrease Minimum Circularity 4 to "+cir+" or less OR decrease Minumum Size 3 to "+av+" or less"; else if(MinSize5 < av && MinCirc5 > cir) error2 = "Decrease Minimum Circularity 5 to "+cir+" or less OR decrease Minumum Size 4 to "+av+" or less"; else if(MinSize5 > av && MinCirc5 > cir) error3 = "Decrease Minimum Size 5 to "+av+" or less AND decrease Minimum Circularity 5 to "+cir+" or less"; else if(MinSize4 > av && MinCirc4 > cir) error3 = "Decrease Minimum Size 4 to "+av+" or less AND decrease Minimum Circularity 4 to "+cir+" or less"; else if(MinSize3 > av && MinCirc3 > cir) error3 = "Decrease Minimum Size 3 to "+av+" or less AND decrease Minimum Circularity 3 to "+cir+" or less"; else if(MinSize2 > av && MinCirc2 > cir) error3 = "Decrease Minimum Size 2 to "+av+" or less AND decrease Minimum Circularity 2 to "+cir+" or less"; else if(MinSize1 > av && MinCirc1 > cir) error3 = "Decrease Minimum Size 1 to "+av+" or less AND decrease Minimum Circularity 1 to "+cir+" or less"; print("Recommended update to remove selected autofluorescence:"); print(error1); print(error2); print(error3); waitForUser("Refer to the FIJI log for recommended settings."); define_Particles();} //*************************************** function DEFiNE(){ /* * Purpose: The main function to remove autofluorescence and fluorescent * artifacts from images of fibers. * * Use: This function is called in the macro. */ set_Directory("Initializing 'Clean Images' function. "); define_Channels(); Dialog.create("DEFiNE Settings"); items = newArray("Proceed with default settings", "Manually input custom settings", "Guided optimization of custom settings"); Dialog.addRadioButtonGroup("Settings options:", items, 3, 1, "Proceed with presets"); Dialog.show(); settingchange = Dialog.getRadioButton(); if(settingchange == "Manually input custom settings") { define_Particles(); if(AutoCh != 0) define_Auto(); define_Small();} if(settingchange == "Guided optimization of custom settings") optimize_Settings(); //save processed images list = getFileList(dirInput); count = list.length; x = 0; setBatchMode("hide"); getDateAndTime(year, month, dayOfWeek, dayOfMonth, hour, minute, second, msec); dirOutput = dirInput + "/DEFiNE_Processed_Images_"+month+"-"+dayOfMonth+"-"+year+"/"; File.makeDirectory(dirOutput); saveMacroSettingsFileDEF = dirOutput+File.separator+"DEFiNE_Clean_Images_Settings_"+month+"_"+dayOfMonth+"_"+year+".txt"; settingsFile = File.open(saveMacroSettingsFileDEF); print(settingsFile,"DEFiNE Clean Images Settings "); print(settingsFile,"Input Directory: "+dirInput); print(settingsFile,"output Directory: "+dirOutput); print(settingsFile,"Number of Channels: "+numChannels); print(settingsFile, "Number of True Signal Channels: "+numTrueSig); print(settingsFile, "Autofluorescence Channel: "+AutoCh); print(settingsFile,"First Channel: "+TrueSig1); print(settingsFile, "First Channel Color:"+Sig1Label); print(settingsFile,"Second Channel: "+TrueSig2); print(settingsFile, "Second Channel Color:"+Sig2Label); print(settingsFile,"Third Channel: "+TrueSig3); print(settingsFile, "Third Channel Color:"+Sig3Label); print(settingsFile,"Fourth Channel: "+TrueSig4); print(settingsFile, "Fourth Channel Color:"+Sig4Label); print(settingsFile,"Fifth Channel: "+TrueSig5); print(settingsFile, "Fifth Channel Color:"+Sig5Label); print(settingsFile, "Subtraction 1 minimum size:"+MinSize1); print(settingsFile, "Subtraction 1 minimum circularity:"+MinCirc1); print(settingsFile, "Subtraction 2 minimum size:"+MinSize2); print(settingsFile, "Subtraction 2 minimum circularity:"+MinCirc2); print(settingsFile, "Subtraction 3 minimum size:"+MinSize3); print(settingsFile, "Subtraction 3 minimum circularity:"+MinCirc3); print(settingsFile, "Subtraction 4 minimum size:"+MinSize4); print(settingsFile, "Subtraction 4 minimum circularity:"+MinCirc4); print(settingsFile, "Subtraction 5 minimum size:"+MinSize5); print(settingsFile, "Subtraction 5 minimum circularity:"+MinCirc5); print(settingsFile, "Number of standard deviations:"+sdauto); print(settingsFile, "Maximum size of small particle subtraction:"+MIPmaxsize); print(settingsFile, "Maximum circularity of small particle subtraction:"+MIPCmin); print(settingsFile, "Minimum circularity of small particle subtraction:"+MIPCmax); for (j=0; j 1) { if(channels > 1) run("Split Channels"); if(channels == 1) rename("C1-"+name); for(b = 0; b < numTrueSig; b++) { if (b == 0){ coi = TrueSig1; colorchoice = Sig1Label;} else if (b == 1){ coi = TrueSig2; colorchoice = Sig2Label;} else if (b == 2){ coi = TrueSig3; colorchoice = Sig3Label;} else if (b == 3){ coi = TrueSig4; colorchoice = Sig4Label;} else if (b == 4){ coi = TrueSig5; colorchoice = Sig5Label;} RemoveParticles(coi, name, 1.5); RemoveParticles(coi, name, 2); RemoveParticles(coi, name, 2.5); RemoveParticles(coi, name, 3); if(AutoCh != 0) RemoveAutoParticles(coi, name, AutoCh); MIP(coi, name); RemoveParticlesMIP(coi,name); selectWindow("C"+coi+"-"+name); run(colorchoice); namelength = lengthOf(name); name2 = substring(name, 0, namelength - 4); pathOut = dirOutput+name2+"_Ch"+coi; saveAs(".tif", pathOut); close(); }} run("Close All"); } x = x + 1; } if(getInfo("log") != "") { selectWindow("Log"); saveAs("Text", dirOutput+"CleanImages_Log_"+month+"_"+dayOfMonth+"_"+year+".txt");} waitForUser("'Clean Images' is complete. Images are saved in folder 'DEFiNE_Processed_Images_"+month+"-"+dayOfMonth+"-"+year+"' located in your selected input folder.");} function RemoveParticles(channel, title, stan) { /* * Purpose: To perform a large particle subtraction at a threshold of ‘stan’ * standard deviations above average pixel intensity. * * Use: This function is called in the DEFiNE() function. * * Var channel: The channel number to be processed * Var title: The name of the original image * Var stan: The number of standard deviations */ selectWindow("C"+channel+"-"+title); Create2SDParticleMask(stan); CreateParticleMask(); CombineMasks(); SubtractParticles(channel); CloseParticleMasks(); run("Clear Results"); } function Create2SDParticleMask(mult) { /* * Purpose: To create a binary mask of the channel at ‘mult’ standard deviations * above average pixel intensity. * * Use: This function is called in the remove_ParticlesOpt(channel, title, stan), * autochannel_Subtraction(coi2, name2, colorchoice2), * RemoveAutoParticles(channel, title, autoch), * and RemoveParticles(channel, title, stan) functions. * * Var mult: The number of standard deviations */ run("Duplicate...", "title=NewStack duplicate"); run("Set Measurements...", "area mean standard min shape limit display redirect=None decimal=3"); run("8-bit"); setAutoThreshold("Default dark"); zstacks = nSlices(); for( z = 0; z < zstacks; z++){ run("Measure"); averagepx = getResult("Mean",z); stdv = getResult("StdDev",z); setThreshold(averagepx + mult*stdv,100000); setOption("BlackBackground", false); run("Convert to Mask", "method=Default background=Dark only"); run("Next Slice [>]"); } rename("OriginalMask"); run("Clear Results"); } function CreateParticleMask(){ /* * Purpose: To create masks of particles that meet the five minimum * size/circularity combinations. * * Use: This function is called in the remove_ParticlesOpt(channel, title, stan) * and RemoveParticles(channel, title, stan) functions. */ selectWindow("OriginalMask"); run("Invert", "stack"); run("Analyze Particles...", "size=MinSize1-Infinity circularity=MinCirc1-1.00 show=Masks stack"); rename("a"); selectWindow("OriginalMask"); run("Analyze Particles...", "size=MinSize2-Infinity circularity=MinCirc2-1.00 show=Masks stack"); rename("b"); selectWindow("OriginalMask"); run("Analyze Particles...", "size=MinSize3-Infinity circularity=MinCirc3-1.00 show=Masks stack"); rename("c"); selectWindow("OriginalMask"); run("Analyze Particles...", "size=MinSize4-Infinity circularity=MinCirc4-1.00 show=Masks stack"); rename("d"); selectWindow("OriginalMask"); run("Analyze Particles...", "size=MinSize5-Infinity circularity=MinCirc5-1.00 show=Masks stack"); rename("e"); } function CombineMasks() { /* * Purpose: To combine the masks containing the five types of large particles * to subtract. * * Use: This function is called in the remove_ParticlesOpt(channel, title, stan) * and RemoveParticles(channel, title, stan) functions. */ imageCalculator("Add create stack", "a","b"); imageCalculator("Add create stack", "c","d"); imageCalculator("Add create stack", "Result of a","Result of c"); rename("combo"); imageCalculator("Add create stack", "combo","e"); rename("ParticlesToRemove"); run("Invert", "stack");} function SubtractParticles(channel2) { /* * Purpose: Subtracts large particles from the specified channel. * * Use: This function is called in the remove_ParticlesOpt(channel, title, stan), * autochannel_Subtraction(coi2, name2, colorchoice2), * RemoveAutoParticles(channel, title, autoch), * and RemoveParticles(channel, title, stan) functions. * * Var channel2: The channel number to be processed */ imageCalculator("AND create stack","ParticlesToRemove","C"+channel2+"-"+name); select_Close("C"+channel2+"-"+name); selectWindow("Result of ParticlesToRemove"); rename("C"+channel2+"-"+name);} function CloseParticleMasks() { /* * Purpose: To close the individual particle masks. * * Use: This function is called in the remove_ParticlesOpt(channel, title, stan) * and RemoveParticles(channel, title, stan) functions. */ select_Close("OriginalMask"); select_Close("a"); select_Close("b"); select_Close("c"); select_Close("d"); select_Close("e"); select_Close("Result of a"); select_Close("Result of c"); select_Close("combo"); select_Close("ParticlesToRemove");} //---------------------- Remove Auto Particles ---------------------- function RemoveAutoParticles(channel, title, autoch) { /* * Purpose: To convert the autofluorescence channel to a binary mask * and remove particles from the fiber channel. * * Use: This function is called in the DEFiNE() function. * * Var channel: The fiber channel number * Var title: The name of the original image * Var autoch: The autofluorescence channel number */ selectWindow("C"+autoch+"-"+title); Create2SDParticleMask(sdauto); selectWindow("OriginalMask"); rename("ParticlesToRemove"); run("Invert", "stack"); SubtractParticles(channel); run("Clear Results"); select_Close("ParticlesToRemove"); } //---------------------- MIP ---------------------- function MIP(channel, title){ /* * Purpose: To convert the stacked image to a maximum intensity projection. * * Use: This function is called in the DEFiNE() function. * * Var channel: The channel number of the processed channel * Var title: The name of the original image */ selectWindow("C"+channel+"-"+title); run("Z Project...", "projection=[Max Intensity]"); select_Close("C"+channel+"-"+title); selectWindow("MAX_C"+channel+"-"+title); rename("C"+channel+"-"+title); } //---------------------- Remove Particles MIP ---------------------- function RemoveParticlesMIP(channel, title){ /* * Purpose: To subtract <1 µm2 noise from images. * * Use: This function is called in the DEFiNE() function. * * Var channel: The channel numberVar title: The name of the original image */ selectWindow("C"+channel+"-"+title); Create2SDParticleMaskMIP(1); CreateParticleMaskMIP(); SubtractParticlesMIP(channel); run("Clear Results"); } function Create2SDParticleMaskMIP(mult) { /* * Purpose: To create a binary mask of the MIP at 1 sd above average intensity. * * Use: This function is called in the RemoveParticlesMIP(channel, title) function. * * Var mult: The number of standard deviations */ run("Duplicate...", "title=NewStack"); run("Set Measurements...", "area mean standard min shape limit display redirect=None decimal=3"); run("Measure"); averagepx=getResult("Mean",0); stdv=getResult("StdDev",0); setAutoThreshold("Default dark"); setThreshold(averagepx + mult*stdv,100000); setOption("BlackBackground", false); run("Convert to Mask", "method=Default background=Dark"); rename("OriginalMask"); } function CreateParticleMaskMIP(){ /* * Purpose: Creates a mask containing only small particles. * * Use: This function is called in the RemoveParticlesMIP(channel, title) function. */ selectWindow("OriginalMask"); run("Analyze Particles...", "size=0-MIPmaxsize circularity=MIPCmin-MIPCmax show=Masks display"); ///// rename("ParticlesToRemove"); } function SubtractParticlesMIP(channel2) { /* * Purpose: This function subtracts the small particles from the MIP. * * Use: This function is called in the RemoveParticlesMIP(channel, title) function. * * Var channel2: The channel number of the processed image */ run("Invert"); imageCalculator("AND create","ParticlesToRemove","C"+channel2+"-"+name); select_Close("C"+channel2+"-"+name); selectWindow("Result of ParticlesToRemove"); rename("C"+channel2+"-"+name); select_Close("OriginalMask"); select_Close("ParticlesToRemove"); } //*************************************** function quantify_Fibers(){ /* * Purpose: To create a binary image at 4 standard deviations above * the average background intensity and measure the number of pixels * above that threshold. * * Use: This function is called by the macro. */ setBatchMode("exit and display"); getDateAndTime(year, month, dayOfWeek, dayOfMonth, hour, minute, second, msec); if(step1 == false) { set_Directory("Initializing 'Quantify Fibers' function. "); dirParent = File.getParent(dirInput); dirOutput = dirInput + "/DEFiNE_Quantified_Fibers_"+month+"-"+dayOfMonth+"-"+year+"/"; File.makeDirectory(dirOutput);} if(step1 == true) { print("Initializing 'Quantify fiber area' function."); wait(3000); dirOutput = dirInput + "/DEFiNE_Quantified_Fibers_"+month+"-"+dayOfMonth+"-"+year+"/"; File.makeDirectory(dirOutput); dirInput = dirInput+"/DEFiNE_Processed_Images_"+month+"-"+dayOfMonth+"-"+year+"/";} print("\\Clear"); list = getFileList(dirInput); count = list.length; x = 0; y = 0; z = 0; Dialog.create("Background Selection Box"); Dialog.addMessage("Average background intensity will be determined by"); Dialog.addMessage("measuring ten background regions of equal size."); Dialog.addNumber("Length of side of selection box (µm)", 12); Dialog.show(); side_length = Dialog.getNumber(); run("Set Measurements...", "area mean standard limit display redirect=None decimal=3"); //Open one image for (i = 0; i < count; i ++) { pathIn = dirInput+list[x]; if (endsWith(pathIn, ".txt") || endsWith(pathIn, "/")) { print(list[x]+" is not an image.");} else { run("Bio-Formats Importer", "open=pathIn autoscale color_mode=Default rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT"); name = getTitle(); run("Specify...", "width=side_length height=side_length x=40.68 y=200.09 scaled"); waitForUser("Measure 10 "+side_length+"x"+side_length+" micron background regions, then hit OK\n" +" \n" +"Move rectangle by clicking center and drag to region with no fibers.\n" +" \n" +"Measure shortcuts:\n" +"Mac - 'command' + 'm'\n" +"PC - 'ctrl' + 'm'\n" +" \n" +"If ROI is lost or resized:\n" +"1. Draw a new ROI with rectangle tool\n" +"2. Edit --> Selection --> Specifiy...\n" +"3. Input "+side_length+" as width and height with 'Scaled Units' selected"); //if there are the wrong number of measurements, return error that doesn't crash the program resultcount = nResults(); while ( resultcount != 10*(z+1)+z*1) { waitForUser("Number of measurements is incorrect. Add missing measurements or clear extra measurements. Then press OK"); resultcount = nResults(); } run("Select None"); averagepx=(getResult("Mean",y)+getResult("Mean",y+1)+getResult("Mean",y+2)+getResult("Mean",y+3)+getResult("Mean",y+4)+getResult("Mean",y+5)+getResult("Mean",y+6)+getResult("Mean",y+7)+getResult("Mean",y+8)+getResult("Mean",y+9))/10; stdv=(getResult("StdDev",y)+getResult("StdDev",y+1)+getResult("StdDev",y+2)+getResult("StdDev",y+3)+getResult("StdDev",y+4)+getResult("StdDev",y+5)+getResult("StdDev",y+6)+getResult("StdDev",y+7)+getResult("StdDev",y+8)+getResult("StdDev",y+9))/10; setAutoThreshold("Default dark"); setThreshold(averagepx + 4*stdv,100000); run("Measure"); setOption("BlackBackground", false); run("Convert to Mask"); pathOut = dirOutput+"Binary_"+name; saveAs("Tiff", pathOut); close(); y = y + 11; z = z + 1;} x = x+1; } getDateAndTime(year, month, dayOfWeek, dayOfMonth, hour, minute, second, msec); pathOut = dirOutput+"Threshold_and_Background_Measurements_"+month+"_"+dayOfMonth+"_"+year+".txt"; saveAs("Results", pathOut); for(j = 0; j < count; j++) { IJ.deleteRows(y-11, y-2); y = y - 11; } pathOut = dirOutput+"Fiber_Quantification_Data_"+month+"_"+dayOfMonth+"_"+year+".txt"; run("Set Measurements...", "area limit display redirect=None decimal=3"); saveAs("Results", pathOut); run("Clear Results"); print("Quantification Complete"); waitForUser("Fiber quantification complete.\n"+ "Fiber area data is saved as a text file named Fiber_Quantification_Data_"+month+"_"+dayOfMonth+"_"+year+".txt\n"+ "and binary images of processed images are saved in folder named 'Quantified_fibers'."); }