/*
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:
"
+""
+"- Particles too large and/or circular to be fibers are identified using FIJI's 'Analyze Particles' function and removed using the 'Image Calculator' function.
"
+"- Particles that fluoresce outside of the commercial fluorophore's range are identified during imaging and are removed using the 'Image Calculator' function.
"
+"
"
+"Output:
"
+""
+"- Processed image channels are saved in the DEFiNE_Processed_Images_m-d-y folder, nested within the user-defined input folder.
"
+"- Each cleaned channel is saved as its own file following the naming convention name_Ch#.tif.
"
+"
"
+"Requirements:
"
+""
+"- Images MUST be imaged with the same channel order.
"
+"- Images must contain at least one channel and contain no more than six channels (including the autofluorescence channel).
"
+"- Images must be stacked. Maximum intensity projections cannot be processed.
"
+"
"
+"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:
"
+""
+"- Users select and measure ten background regions containing no fibers to determine the average background intensity of an image.
"
+"- A threshold is applied at four standard deviations above the average background intensity.
"
+"- The area of pixels above the threshold is measured, and a binary image containing only pixels above threshold is generated.
"
+"
"
+"Output:
"
+""
+"- All images and files are saved in the DEFiNE_Quantified_Fibers_m-d-y folder, nested within the user-defined input folder.
"
+"- Each image is saved as a binary image containing only pixels above the determined threshold following the naming convention binary_name.tif.
"
+"- A text file named Threshold_and_Background_Measurements_m-d-y is saved containing all measurements, both background and final.
"
+"- A text file named Fiber_Quantification_Data_m-d-y is saved containing only the final area measurements.
"
+"
"
+"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 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
"
+""
+""
+""
+"Input | "
+"Description | "
+"
"
+""
+""
+""
+"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 clean | "
+"This is the number of channels containing fibers that you would like to process. This number does not include the autofluorescence channel. | "
+"
"
+""
+"Autofluorescence channel number | "
+"Input 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.
"
+""
+""
+""
+" Fiber | "
+"Circularity | "
+"
"
+""
+""
+" _________ _________/ "
+" | "
+"~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'.");
}