//////////////////////////////////////////////////////////////// /* PIPSQUEAK! Perineuronal net Intensity Program for the Standardization and Quantification of ECM Analysis Written by John H. Harkness, PhD. >>> Contact: harknessjh@gmail.com >>> Copyright (C) 2017, John H. Harkness Washington State University, Vancouver Supported by: >>> Rewire Neuroscience (rewireneuroscience.com) >>> WSU Alcohol and Drug Abuse Research Program (ADARP) >>> The Translational Addiction Research Center (TARC) >>> NIH DA 033404 >>> Washington State Initiative Measure No. 171 Protocol based on Slaker, Harkness, and Sorg, 2016 >>> Special thanks to Megan Slaker, PhD >>> PLEASE CITE: Slaker, et al., 2016 <<< */ //////////////////////////////////////////////////////////////// //Global variables var TimeString = "BlankDate"; var scale_size = 1.194; var scale_known = 1; var scale_pixel = 1; var scale_unit = "um"; var background_setting = "Low"; var set_intensity_low_threshold = 1.165; var set_intensity_high_threshold = 5000; var set_low_particlesize = 70; var set_high_particlesize = 99999; var set_low_circularity = 0.02; var set_high_circularity = 1.00; var set_roi_enlargement_single = 6.00; var set_intensity_low_threshold_old = 1.165; var set_low_particlesize_old = 70; var set_high_particlesize_old = 99999; var ROI_type_SL = "Square"; var set_count_low_threshold = 0.5; var set_count_high_threshold = 5000; var set_count_low_particlesize = 20; var set_count_high_particlesize = 100000; var set_count_low_circularity = 0.02; var set_count_high_circularity = 1.00; var ROI_Dir = "/Users/John 1/Desktop/"; var ROI_Dir_path = "/Users/John 1/Desktop/"; var countWinROI = 1; var ROI_type_count = "Circle"; var first_image = 0; var second_image = 0; var series_name = 0; var subDir = 0; var first_suffix = 1; var second_suffix = 3; var merged_suffix = 2; var total_images = 3; var first_stain_type = "PV"; var DL1_set_intensity_low_threshold = 1.0; var DL1_set_intensity_high_threshold = 5000; var DL1_set_low_particlesize = 40; var DL1_set_high_particlesize = 1000; var DL1_set_low_circularity = 0.02; var DL1_set_high_circularity = 1.00; var DL1_set_roi_enlargement = -1.00; var SL1_set_intensity_low_threshold_old = 1.0; var SL1_set_low_particlesize_old = 40; var SL1_set_high_particlesize_old = 1000; //var DL1_set_intensity_low_threshold_old = 1.0; //var DL1_set_low_particlesize_old = 40; //var DL1_set_high_particlesize_old = 1000; var DL1_lower = 0; var ROI_type_DL1 = "Circle"; var second_stain_type = "WFA"; var DL2_set_intensity_low_threshold = 1.165; var DL2_set_intensity_high_threshold = 5000; var DL2_set_low_particlesize = 70; var DL2_set_high_particlesize = 99999; var DL2_set_low_circularity = 0.02; var DL2_set_high_circularity = 1.00; var DL2_set_roi_enlargement = 1.00; var SL2_set_intensity_low_threshold_old = 1.165; var SL2_set_low_particlesize_old = 70; var SL2_set_high_particlesize_old = 99999; //var DL2_set_intensity_low_threshold_old = 1.165; //var DL2_set_low_particlesize_old = 70; //var DL2_set_high_particlesize_old = 5000; var DL2_lower = 0; var ROI_type_DL2 = "Square"; var lower = 0; var import_type = 0; var first_open = 0; var last_open = 0; var name = 0; var full_name = 0; var dir = 0; var first_time = 0; var save_location = 0; var pipsqueakCount = 1; var countCount = 1; var countDouble = 0; var first_open_double = 0; var last_open_double = 0; var subject_id = 0; /////////////////////////// macro "PIPSQUEAK" { getDateAndTime(year, month, dayOfWeek, dayOfMonth, hour, minute, second, msec); TimeString ="_"+month+1+" "+dayOfMonth+" "+year+" at "+hour+" "+minute; if (pipsqueakCount==1){ ///call home tracking URL //UPDATE HERE (1/3)-> call_home_url = "http://www.google-analytics.com/__utm.gif?utmwv=5.1.7&utms=1&utmn=1894752493&utmhn=www.jabstracts.org/&utmcs=UTF-8&utmsr=1280×1024&utmsc=24-bit&utmul=en-us&utmje=1&utmfl=10.3%20r183&utmdt=Tracking%20QR%20Codes%20with%20Google%20Analytics&utmhid=1681965357&utmr=http%3A%2F%2Fwww.imagejnih.gov%2F&utmp=%2Fjabstracts.org%2Fpipsqueak%2Fcall_home%2Fv2-12%2F&utmac=UA-83183702-1&utmcc=__utma%3D230887938.1463229748.1317737798.1317737798.1317737798.1%3B%2B__utmz%3D230887938.1317737798.1.1.utmcsr%3Dgoogle%7Cutmccn%3D(organic)%7Cutmcmd%3Dorganic%7Cutmctr%3DPIPSQUEAK%2Fv2.12%3B&utmu=DC~"; File.openUrlAsString(call_home_url); wait(50); print("\\Clear"); /// //UPDATE HERE (2/3)-> print("PIPSQUEAK! v2.12 Perineuronal net Intensity Program for the Standardization and Quantification of ECM Analysis."); print("\n"+"Copyright (C) 2017, John H. Harkness, PhD."); print("Protocol by Megan Slaker, PhD."); print("Lab of Barb Sorg, PhD., Washington State University, Vancouver"); print("\n"+"\n"+"Distance in pixels: "+scale_size+"\n"+"Known distance: "+scale_known+"\n"+"Pixel aspect ratio: "+scale_pixel+"\n"+"Unit of length: "+scale_unit); print("\n"+"FOR ACCURATE RESULTS, IT IS CRITICAL THAT YOUR IMAGE DIMENSIONS ARE CORRECTLY ENTERED (i.e. pixels per known distance)."); print("Date on saved files will be '"+TimeString+"'"); //UPDATE HERE (3/3)-> waitForUser("PIPSQUEAK version 2.12, Mar 06, 2017 \n \n NOTE: Results from 2.00 and above should not be combined with earlier versions of PIPSQUEAK for statistical analysis. \n \n 2.01 CHANGE LOG: UI improvements in cell counting function. \n \n 2.02 and 2.021 CHANGE LOG: UI improvements in settings window.\n \n 2.12 CHANGE LOG: This is a big one. New background selection method to improve detection of faint staining, \n but it's your choice! See settings. Also, choose your fav ROI shape! See settings. \n UI improvements. Also, check out the instructional videos I made. I'm on YouTube, Mom! \n Squashed a pesky little bug that sometimes led to incorrect measurements during double-label analysis (Thanks Hayley Reeve!)"); wait(1000); pipsqueakCount = pipsqueakCount+1; } else { wait(50); } Dialog.create("Welcome."); items0 = newArray("Single label intensity analysis.", "->Settings.", "Double label intensity analysis.", "->Contact Us and/or Report a bug.", "Count cells."); Dialog.addRadioButtonGroup("What would you like to do?", items0, 3, 2, " "); Dialog.show; choice0 = Dialog.getRadioButton; if (choice0 =="Count cells.") { run("__sub_PIPSQUEAK_count"); } if (choice0 =="Single label intensity analysis.") { run("__sub_PIPSQUEAK_single"); } if (choice0 =="Double label intensity analysis.") { run("__sub_PIPSQUEAK_double"); } if (choice0 =="->Contact Us and/or Report a bug.") { //Dialog.addHelp("http://www.labs.wsu.edu/sorg/research-resources/") waitForUser("Thanks! Please log bugs as best you can (screen shot, description, etc) and send to john.harkness@wsu.edu . For questions or help, please use the same email address. Thanks for using PIPSQUEAK!"); run("PIPSQUEAK"); } //if (choice0 =="->Help") { // waitForUser("Sorry, feature coming soon... Please visit https://labs.wsu.edu/sorg/research-resources"); // run("PIPSQUEAK"); //} if (choice0 =="->Settings.") { Dialog.create("Settings Menu"); items1 = newArray("Image dimensions and scale settings", "Background calculation settings", "Single label intensity analysis settings", "Double label intensity analysis settings", "Count cells settings"); Dialog.addRadioButtonGroup("What would you like to do?", items1, 5, 1, " "); Dialog.show; choice1 = Dialog.getRadioButton; if (choice1 =="Image dimensions and scale settings") { Dialog.create("Image dimensions and scale settings"); Dialog.addMessage("**Image scale measurements (for both SINGLE and DOUBLE label analysis)**"); Dialog.addNumber("Distance in pixels:", scale_size); Dialog.addNumber("Known distance:", scale_known); Dialog.addNumber("Pixel aspect ratio:", scale_pixel); Dialog.addString("Unit of length:", scale_unit); Dialog.show; scale_size = Dialog.getNumber(); scale_known = Dialog.getNumber();; scale_pixel = Dialog.getNumber();;; scale_unit = Dialog.getString(); run("PIPSQUEAK"); } if (choice1 =="Background calculation settings") { Dialog.create("Background calculation settings"); Dialog.addMessage("Adjustments will alter cell determination and MAY reduce identification specificity."); Dialog.addMessage("Proceed with caution: here be dragons."); Dialog.addMessage(" "); Dialog.addMessage("High background subtraction: This is the original setting for v2.02 and below. It removes more background, but may miss lightly stained cells."); Dialog.addMessage("Low background subtraction: This is the improved background setting. It is more sensitive for lightly stained cells."); items2 = newArray("High", "Low"); Dialog.addRadioButtonGroup("Which background subtraction setting would you like to use?", items2, 2, 1, background_setting); Dialog.show; choice2 = Dialog.getRadioButton; if (choice2 =="High") { background_setting = "High"; run("PIPSQUEAK"); } if (choice2 =="Low") { background_setting = "Low"; run("PIPSQUEAK"); } } if (choice1 =="Single label intensity analysis settings") { Dialog.create("Single label intensity analysis settings"); Dialog.addMessage("Adjustments will alter cell determination and MAY reduce identification specificity."); Dialog.addMessage("Proceed with caution: here be dragons."); Dialog.addMessage(" "); Dialog.addNumber("Lower threshold multiplier:",set_intensity_low_threshold); Dialog.addNumber("Upper threshold limit:", set_intensity_high_threshold); Dialog.addNumber("Lower limit particle size:", set_low_particlesize); Dialog.addNumber("Upper limit particle size:", set_high_particlesize); Dialog.addNumber("Lower limit circularity:", set_low_circularity); Dialog.addNumber("Upper limit circularity:", set_high_circularity); Dialog.addNumber("ROI Enlargement (pixels):", set_roi_enlargement_single); items3 = newArray("As-detected", "Square", "Circle"); Dialog.addRadioButtonGroup("Shape of ROIs:", items3, 3, 1, ROI_type_SL); Dialog.show; set_intensity_low_threshold = Dialog.getNumber(); set_intensity_high_threshold = Dialog.getNumber();; set_low_particlesize = Dialog.getNumber();;; set_high_particlesize = Dialog.getNumber();;;; set_low_circularity = Dialog.getNumber();;;;; set_high_circularity = Dialog.getNumber();;;;;; set_roi_enlargement_single = Dialog.getNumber();;;;;;; choice3 = Dialog.getRadioButton; if (choice3 =="As-detected") { ROI_type_SL = "As-detected"; } if (choice3 =="Square") { ROI_type_SL = "Square"; } if (choice3 =="Circle") { ROI_type_SL = "Circle"; } run("PIPSQUEAK"); } if (choice1 =="Double label intensity analysis settings") { Dialog.create("Double label intensity analysis settings"); Dialog.addMessage("**Window 1 of 2**"); Dialog.addMessage(" "); Dialog.addMessage("Please enter the numbering suffixes of the image series you want to analyze in the space below."); Dialog.addMessage("eg: Exp42_SubA_example_1.tif and Exp42_SubA_example_3.tif = #1 and #3"); Dialog.addMessage(" "); Dialog.addNumber("First image (if possible, smaller volume stain):", first_suffix); Dialog.addNumber("Second image (if possible, larger volume stain):", second_suffix); Dialog.addNumber("Merged image:", merged_suffix); Dialog.addMessage(" "); Dialog.addMessage("*First stain parameters*"); Dialog.addString("Stain type:", first_stain_type); Dialog.addNumber("Lower threshold multiplier:", DL1_set_intensity_low_threshold); Dialog.addNumber("Upper threshold limit:", DL1_set_intensity_high_threshold); Dialog.addNumber("Lower limit particle size:", DL1_set_low_particlesize); Dialog.addNumber("Upper limit particle size:", DL1_set_high_particlesize); Dialog.addNumber("Lower limit circularity:", DL1_set_low_circularity); Dialog.addNumber("Upper limit circularity:", DL1_set_high_circularity); Dialog.addNumber("ROI Enlargement (pixels):", DL1_set_roi_enlargement); items4 = newArray("As-detected", "Square", "Circle"); Dialog.addRadioButtonGroup("Shape of ROIs:", items4, 3, 1, ROI_type_DL1); Dialog.show; first_suffix = Dialog.getNumber(); second_suffix = Dialog.getNumber();; merged_suffix = Dialog.getNumber();;; //total_images = Dialog.getNumber();;;; first_stain_type = Dialog.getString(); DL1_set_intensity_low_threshold = Dialog.getNumber();; DL1_set_intensity_high_threshold = Dialog.getNumber();;; DL1_set_low_particlesize = Dialog.getNumber();;;; DL1_set_high_particlesize = Dialog.getNumber();;;;; DL1_set_low_circularity = Dialog.getNumber();;;;;; DL1_set_high_circularity = Dialog.getNumber();;;;;;; DL1_set_roi_enlargement = Dialog.getNumber();;;;;;;; choice4 = Dialog.getRadioButton; if (choice4 =="As-detected") { ROI_type_DL1 = "As-detected"; } if (choice4 == "Square") { ROI_type_DL1 = "Square"; } if (choice4 == "Circle") { ROI_type_DL1 = "Circle"; } //next window Dialog.create("Double label intensity analysis settings"); Dialog.addMessage("**Window 2 of 2**"); Dialog.addMessage(" "); Dialog.addMessage("*Second stain parameters*"); Dialog.addString("Stain type:", second_stain_type); Dialog.addNumber("Lower threshold multiplier:", DL2_set_intensity_low_threshold); Dialog.addNumber("Upper threshold limit:", DL2_set_intensity_high_threshold); Dialog.addNumber("Lower limit particle size:", DL2_set_low_particlesize); Dialog.addNumber("Upper limit particle size:", DL2_set_high_particlesize); Dialog.addNumber("Lower limit circularity:", DL2_set_low_circularity); Dialog.addNumber("Upper limit circularity:", DL2_set_high_circularity); Dialog.addNumber("ROI Enlargement (pixels):", DL2_set_roi_enlargement); items5 = newArray("As-detected", "Square", "Circle"); Dialog.addRadioButtonGroup("Shape of ROIs:", items5, 3, 1, ROI_type_DL2); Dialog.show; second_stain_type = Dialog.getString(); DL2_set_intensity_low_threshold = Dialog.getNumber();; DL2_set_intensity_high_threshold = Dialog.getNumber();;; DL2_set_low_particlesize = Dialog.getNumber();;;; DL2_set_high_particlesize = Dialog.getNumber();;;;; DL2_set_low_circularity = Dialog.getNumber();;;;;; DL2_set_high_circularity = Dialog.getNumber();;;;;;; DL2_set_roi_enlargement = Dialog.getNumber();;;;;;;; choice5 = Dialog.getRadioButton; if (choice5 == "As-detected") { ROI_type_DL2 = "As-detected"; } if (choice5 == "Square") { ROI_type_DL2 = "Square"; } if (choice5 == "Circle") { ROI_type_DL2 = "Circle"; } run("PIPSQUEAK"); } if (choice1 =="Count cells settings") { Dialog.create("Count cells settings"); Dialog.addMessage(" "); Dialog.addMessage("**Cell counting function**"); Dialog.addString("Directory of ROI file:", "eg: /Users/John 1/Desktop/"); Dialog.addNumber("Lower threshold multiplier:", set_count_low_threshold); Dialog.addNumber("Upper threshold limit:", set_count_high_threshold); Dialog.addNumber("Lower limit particle size:", set_count_low_particlesize); Dialog.addNumber("Upper limit particle size:", set_count_high_particlesize); Dialog.addNumber("Lower limit circularity:", set_count_low_circularity); Dialog.addNumber("Upper limit circularity:", set_count_high_circularity); //items6 = newArray("As-detected", "Square", "Circle"); //Dialog.addRadioButtonGroup("Shape of ROIs:", items6, 3, 1, ROI_type_count); Dialog.show; ROI_Dir = Dialog.getString(); set_count_low_threshold = Dialog.getNumber(); set_count_high_threshold = Dialog.getNumber();; set_count_low_particlesize = Dialog.getNumber();;; set_count_high_particlesize = Dialog.getNumber();;;; set_count_low_circularity = Dialog.getNumber();;;;; set_count_high_circularity = Dialog.getNumber();;;;;; //choice6 = Dialog.getRadioButton; //if (choice6 == "As-detected") { // ROI_type_count = "As-detected"; //} //if (choice5 == "Square") { // ROI_type_count = "Square"; //} //if (choice5 == "Circle") { // ROI_type_count = "Circle"; //} run("PIPSQUEAK"); } } } ////////////////////////// macro "__sub_PIPSQUEAK_count" { //count labeled cells import_type=4; if(countCount == 1) { Dialog.create("Cell Count"); items = newArray("Open image to count", "Use ROI to confine cell count area", "Adjust cell detection parameters", "Return to main menu"); Dialog.addRadioButtonGroup("What would you like to do?", items, 4, 1, "Use ROI to confine cell count area"); Dialog.show; choice = Dialog.getRadioButton; if (choice=="Open image to count") { wait(100); } if (choice=="Return to main menu") { run("PIPSQUEAK"); } if (choice=="Adjust cell detection parameters") { Dialog.create("Settings"); Dialog.addMessage("**Cell count**"); //Dialog.addMessage(" "); Dialog.addNumber("Lower threshold multiplier:", set_count_low_threshold ); Dialog.addNumber("Upper threshold limit:", set_count_high_threshold); Dialog.addNumber("Lower limit particle size:", set_count_low_particlesize); Dialog.addNumber("Upper limit particle size:", set_count_high_particlesize); Dialog.addNumber("Lower limit circularity:", set_count_low_circularity); Dialog.addNumber("Upper limit circularity:", set_count_high_circularity); Dialog.show; set_count_low_threshold = Dialog.getNumber();;;;;;; set_count_high_threshold = Dialog.getNumber();;;;;;;; set_count_low_particlesize = Dialog.getNumber();;;;;;;;; set_count_high_particlesize = Dialog.getNumber();;;;;;;;;; set_count_low_circularity = Dialog.getNumber();;;;;;;;;;; set_count_high_circularity = Dialog.getNumber();;;;;;;;;;;; run("__sub_PIPSQUEAK_count"); } if (choice == "Use ROI to confine cell count area") { countWinROI = 1; } } open(); if(bitDepth != 32){ run("32-bit"); } run("Set Measurements...", "area mean standard min redirect=None decimal=3"); run("Set Scale...", "distance=scale_size known=scale_known pixel=scale_pixel unit=&scale_unit global"); dir = getDirectory("image"); name = getTitle; full_name = getTitle; index = lastIndexOf(name, "."); if (index!=-1) name = substring(name, 0, index); first_open = name; countCount = countCount+1; run("__sub_PIPSQUEAK_Background"); } ////////////////////////// macro "__sub_PIPSQUEAK_single" { Dialog.create("Import Type"); items = newArray("Semiautomated analysis of raw, non-summed, individual Tiffs", "Semiautomated analysis of summed Z-stacks", "Automatic analysis of summed Z-stacks"); Dialog.addRadioButtonGroup("What type of file do you want to import?", items, 3, 1, "Semiautomated analysis of summed Z-stacks"); Dialog.show; choice = Dialog.getRadioButton; if (choice=="Semiautomated analysis of raw, non-summed, individual Tiffs") { import_type=1; run("__sub_PIPSQUEAK_Import"); } else { if (choice=="Semiautomated analysis of summed Z-stacks") { import_type=2; run("__sub_PIPSQUEAK_Import_Summed"); } if (choice=="Automatic analysis of summed Z-stacks") { import_type=3; run("__sub_PIPSQUEAK_Auto_Import_Summed"); } } } ///////////////////////////// macro "__sub_PIPSQUEAK_Import" { // Importing stacks //import_type=1; run("Image Sequence...", "disable_global convert sort"); name = getTitle; dir = getDirectory("image"); selectWindow(name); run("Set Measurements...", "area mean standard min redirect=None decimal=3"); run("Z Project...", "projection=[Sum Slices]"); run("Set Scale...", "distance=scale_size known=scale_known pixel=scale_pixel unit=&scale_unit global"); full_name = "SUM_"+name; print("\n"+name+" loaded."); run("__sub_PIPSQUEAK_Background"); } ///////////////////////////// macro "__sub_PIPSQUEAK_Import_Summed" { // Importing image //import_type=2; open(); run("Set Measurements...", "area mean standard min redirect=None decimal=3"); run("Set Scale...", "distance=scale_size known=scale_known pixel=scale_pixel unit=&scale_unit global"); dir = getDirectory("image"); //print(dir); name = getTitle; full_name = getTitle; index = lastIndexOf(name, "."); if (index!=-1) name = substring(name, 0, index); print("\n"+name+" loaded."); first_open = name; run("__sub_PIPSQUEAK_Background"); } //////////////////////////////// macro "__sub_PIPSQUEAK_Auto_Import_Summed" { // Importing image //import_type=3; open(); run("Set Measurements...", "area mean standard min redirect=None decimal=3"); run("Set Scale...", "distance=scale_size known=scale_known pixel=scale_pixel unit=&scale_unit global"); dir = getDirectory("image"); name = getTitle; full_name = getTitle; index = lastIndexOf(name, "."); if (index!=-1) name = substring(name, 0, index); print("\n"+name+" loaded."); first_open = name; waitForUser("Please don't touch", "Please let the macro run without clicking windows. Disruption may cause the macro to stall."); run("__sub_PIPSQUEAK_Background"); } //////////////////////////////// macro "__sub_PIPSQUEAK_z-project" { //makes summed image from z-stack top_dir = getDirectory("Choose a Directory "); count = 1; listFiles(top_dir); function listFiles(top_dir) { list = getFileList(top_dir+"/.."); //child_list = getFileList(top_dir); parentlist = File.getParent(top_dir); for (i=0; i0) { roiManager("Delete"); } if (import_type==2) { selectWindow(name+".tif"); } if (import_type==1) { selectWindow("SUM_"+name); } roiManager("Show All"); roiManager("Show All with labels"); run("Clear Results"); wait(200); setAutoThreshold("Default dark"); run("Threshold..."); wait(200); setThreshold(lower*set_intensity_low_threshold, set_intensity_high_threshold); wait(200); makeRectangle(0, 0, 0, 0); run("Analyze Particles...", "size=set_low_particlesize-set_high_particlesize circularity=set_low_circularity-set_high_circularity clear include add"); wait(200); selectWindow("Threshold"); resetThreshold(); run("Close"); roiManager("Measure"); //Making ROIs from Particles wait(500); add_squares=roiManager("count"); if (add_squares==0) { roiManager("Show All"); roiManager("Show All with labels"); waitForUser("Oops", "We didn't see any staining here. Try adjusting the Cell Detection Threshold settings in the next step... "); setTool("point"); makePoint(0, 0); selectWindow(full_name); } else { array=newArray(add_squares); for(i=0; iMake summed double-labeled images from z-stacks."); Dialog.addRadioButtonGroup("What type of file do you want to import?", items, 3, 1, "Semiautomated analysis of summed double-labeled Z-stack"); Dialog.show; choice = Dialog.getRadioButton; if (choice=="Semiautomated analysis of summed double-labeled Z-stack") { import_type = 5; run("__sub_PIPSQUEAK_Open_Double"); } else { if (choice=="Automatic analysis of summed double-labeled Z-stacks") { import_type = 6; run("__sub_PIPSQUEAK_Open_Double"); } if (choice=="->Make summed double-labeled images from z-stacks.") { //Dialog.create("Stacks folder"); //Dialog.addMessage("Before using this function, please place z-stack images into a folder titled 'Stacks' within your experiment folder."); //Dialog.addMessage("ie, /Desktop/experiment folder/Stacks/image1... image20"); //Dialog.show(); run("__sub_PIPSQUEAK_double_sum"); } } } ///////////////////////////// macro "__sub_PIPSQUEAK_double_sum" { // summing images. if (countDouble == 0) { Ldest = getDirectory("Choose a Directory "); //load from name = getTitle; Sdest = Ldest+"/summed/"; //save to } countDouble++; if (countDouble == 1) { Dialog.create("Save location"); Dialog.addMessage("Select a place to save the summed image. ie, /Users/John/Desktop"); Dialog.addString("Save to: ", Sdest); Dialog.show(); Sdest = Dialog.getString(Ldest="/summed/"); print("Save location: "+Sdest); } else { wait(100); } if (File.exists(Sdest+name+"/")) { wait(100); } else { File.makeDirectory(Sdest+name+"/"); } sfold = Sdest + name; stackfold = getFileList(Ldest); for(i=0; i0){ selectImage(nImages); close(); } } ///////////////////////////// macro "__sub_PIPSQUEAK_Open_Double" { // opening previously summed images waitForUser("Select First Image", "Please open the first image of the subject series."); open(); Dialog.create("Subject ID"); Dialog.addMessage("Please enter the Subject ID name or number"); Dialog.addString("Subject ID:", "eg: 2B"); Dialog.show subject_id = Dialog.getString(); run("Set Measurements...", "area mean standard min center redirect=None decimal=3"); run("Set Scale...", "distance=scale_size known=scale_known pixel=scale_pixel unit=&scale_unit global"); first_image = getTitle; dir = getDirectory("image"); index = lastIndexOf(first_image, "."); if (index!=-1) first_image = substring(first_image, 0, index); print("\n"+first_image+" loaded."); series_name = substring(first_image, 0, index-2); first_open_double = series_name; subDir = dir+"/"+series_name+"/"; File.makeDirectory(subDir); if(endsWith(first_image,first_suffix)) { open(series_name+"_"+second_suffix+".tif"); second_image = getTitle; if (index!=-1) second_image = substring(second_image, 0, index); print(second_image+" loaded."); run("__sub_PIPSQUEAK_Double_Background"); } else { waitForUser("Please update Settings to match numbering suffixes of double-label image series"); run("PIPSQUEAK"); } } ////////////////////////////// macro "__sub_PIPSQUEAK_Double_Background" { //the meat of the pipsqueak. DL= double-label. SL= single-label. //First Image // Selecting Background first_image_tif = first_image+".tif"; //image names are consistently kept as "first_image_tif" and "second_image_tif" throughout the double-labeled macro(s) second_image_tif = second_image+".tif"; //even though the actual images are duplicated and named things like "first_image-2.tif" run("Clear Results"); //clearing the template run("ROI Manager..."); //opening ROI manager roiManager("reset"); // clearing ROI manager roiManager("Show All"); //turning on show all labels roiManager("Show All with labels"); selectWindow(first_image_tif); //grabbing first image height = getHeight; //getting dimensions in order to place background ROIs around images of any size width = getWidth; makeRectangle((6*(width-40)/6), (0.1*(height-40)/5), 30, 30); //placing 20 ROIs around the perimeter of the image roiManager("Add"); makeRectangle((6*(width-40)/6), (1*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((6*(width-40)/6), (2*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((6*(width-40)/6), (3*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((6*(width-40)/6), (4*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((6*(width-40)/6), (5*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((5*(width-40)/6), (5*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((4*(width-40)/6), (5*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((3*(width-40)/6), (5*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((2*(width-40)/6), (5*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((1*(width-40)/6), (5*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((0.1*(width-40)/6), (5*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((0.1*(width-40)/6), (4*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((0.1*(width-40)/6), (3*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((0.1*(width-40)/6), (2*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((0.1*(width-40)/6), (1*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((0.1*(width-40)/6), (0.1*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((1*(width-40)/6), (0.1*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((2*(width-40)/6), (0.1*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((3*(width-40)/6), (0.1*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((4*(width-40)/6), (0.1*(height-40)/5), 30, 30); roiManager("Add"); makeRectangle((5*(width-40)/6), (0.1*(height-40)/5), 30, 30); roiManager("Add"); run("Subtract Background...", "rolling=10"); //before measuring the image background for threshold, running rolling ball subtraction roiManager("Select", newArray(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,21)); //measuring all the ROIs in order to run stats and select the right ones roiManager("Measure"); // Calculating lower threshold background value in "Mean" column DL1_m=0; DL1_bkgd_mean=0; DL1_meanbkgd=0; DL1_std=0; DL1_bkgd_std=0; DL1_stdbkgd=0; DL1_m = nResults; //building an array for the ROI means. DL1_bkgd_mean = newArray(DL1_m); run("Select None"); for (i=0; i0) { //if yes ROIs, change the size of the ROIs based on global enlargement variable. array=newArray(DL1_add_circles); for(i=0; i0) { array=newArray(DL2_add_squares); for(i=0; ic_area){ // if the overlapping area is less 80% of the circle, no_co = no_co-1; //then, forget that an overlap was identified and move on (restart the loop). } else { co_roi_array = Array.concat(co_roi_array, b); //building an array to remember which circle ROIs overlap (for ROI selection) co_roi_array_UI = Array.concat(co_roi_array_UI, b2); //building an array to remember which circle ROIs overlap (for the human to understand) saved_squares_array = Array.concat(saved_squares_array, a); } } if((b2==double_label_first_type) && (no_co==0)){ //if we have checked every circle and still not found a circle that overlap (>80%) with the square, roiManager("deselect"); roiManager("Select", a2-1); //move back one spot and select that square, roiManager("Delete"); // then delete it because we know that it was a non-overlapping square and should no longer be considered for colabeling. no_overlap=no_overlap+1; // add one to the number of square not overlapping so that we can lower the total squares. a=a-1; //remove one square from the counted number of squares. Semi repetitive with last variable, but each serve a function in the top IF loop. } if(b2==(double_label_first_type) && (no_co==1)){ // if we have checked all circles and there was an overlap detected //print("Total circles checked: "+bTotal); //then, print # circles checked. (next step is to exit loop because a!<(double_label_all_types-no_overlap)). //print("loop = "+n+1); //print("\n"); //wait(10); } if(b2==(double_label_first_type) && (no_co>1)){ // if checked all circles and there were multiple overlaps, selectWindow(second_image_tif); //select the WFA image run("Clear Results"); roiManager("deselect"); roiManager("Select", a); //select the square ROI roiManager("Measure"); //measure the square ROI so we can... CoM_x_square=getResult("XM", 0); // grab the squares's center of mass x-coordinate from the results. CoM_y_square=getResult("YM", 0); // grab the squares's center of mass y-coordinate from the results. CoM_tot_square = CoM_x_square+CoM_y_square; //making the total value (number only used for comparison to circles). run("Clear Results"); selectWindow(first_image_tif); //select the PV image roiManager("deselect"); roiManager("Select", co_roi_array); //select the overlapping ROIs roiManager("Measure"); for(i=0; ico_area){ // if the overlapping area is less 80% of the square, no_co = no_co-1; //then, forget that an overlap was identified and move on (restart the loop). } else { co_roi_array2 = Array.concat(co_roi_array2, d); //building an array to remember which circle ROIs overlap (for ROI selection) co_roi_array2_UI = Array.concat(co_roi_array2_UI, d2); //building an array to remember which circle ROIs overlap (for the human to understand) saved_circles_array = Array.concat(saved_circles_array, c); //building an array to remember which circle ROIs overlap (for ROI selection) } } if((d2==double_label_second_type_b) && (no_co==0)){ //if we have checked every square and still not found a square that overlap (>80%) with the circle, roiManager("deselect"); roiManager("Select", c2-1); roiManager("Delete"); no_overlap=no_overlap+1; // add one to the number of circles not overlapping so that we can lower the total circles. c=c-1;//remove one circle from the counted number of circle. Semi repetitive with last variable, but each serve a function in the top IF loop. } } n=n+1; } roiManager("Select", double_label_second_type_b_array); roiManager("Delete"); //saving ROI overlay save_circleDL_ROIs=roiManager("count"); circle_DL_array=newArray(save_circleDL_ROIs); // saving the list of DL circle ROIs for(i=0; i0){ print("Removed circle ROIs (these were multiple overlaps with square ROIs):"); Array.print(removed_circles_array); } print("Circle DL ROIs = "+save_circleDL_ROIs); print("\n"+second_image); print("Square DL ROIs = "+save_squareDL_ROIs); roiManager("reset"); run("__sub_PIPSQUEAK_measure_Double_Background_DL1and2_ROIs"); } //\\//\\//\\//\\//\\//\\//\\ macro "__sub_PIPSQUEAK_measure_Double_Background_DL1and2_ROIs" { //this macro simply recalls the ROIs defined in the last macro in order to measure the values again. first_image_tif = first_image+"-2.tif"; second_image_tif = second_image+"-2.tif"; roiManager("Open", subDir+first_image+first_stain_type+"_double-label_ROIoverlay.zip"); roiManager("Open", subDir+second_image+second_stain_type+"_double-label_ROIoverlay.zip"); if (import_type==6) { //if run in automatic mode, no ROI check step offered. wait(300); } else { //otherwise, it opens the merge image and overlays the ROIs. open(series_name+"_"+merged_suffix+".tif"); merged_image = getTitle; roiManager("Show All"); roiManager("Show All with labels"); selectWindow(merged_image); Dialog.create("How Does That Look?"); //the first step is asking the user if they want to edit either ROI set. items = newArray(first_stain_type, second_stain_type, "Accept double labeling as is."); Dialog.addRadioButtonGroup("Here is your chance to adjust the ROIs to better identify PNNs. Which double-labeled cells would you like to adjust?", items, 3, 1, "Accept double labeling as is."); Dialog.show; choice = Dialog.getRadioButton; if (choice==first_stain_type) { setTool("oval"); roiManager("reset"); roiManager("Open", subDir+first_image+first_stain_type+"_double-label_ROIoverlay.zip"); waitForUser("How Does That Look?", "Here is your chance to adjust the double-labeling. Try moving, adding, or deleting ROIs. **THEN** press OK."); roiManager("deselect"); roiManager("Save", subDir+first_image+first_stain_type+"_double-label_ROIoverlay.zip"); wait(100); Dialog.create("Adjust the other stain?"); //then the second step is to ask the user if they want to edit the other stain's ROIs. items = newArray("Yes", "No, accept double labeling as is."); Dialog.addRadioButtonGroup("Do you want to also adjust "+second_stain_type+" double-labeling?", items, 2, 1, "Yes"); Dialog.show; choice = Dialog.getRadioButton; if (choice=="Yes") { setTool("rectangle"); roiManager("reset"); roiManager("Open", subDir+second_image+second_stain_type+"_double-label_ROIoverlay.zip"); waitForUser("How Does That Look?", "Here is your chance to adjust the double-labeling. Try moving, adding, or deleting ROIs. **THEN** press OK."); roiManager("deselect"); roiManager("Save", subDir+second_image+second_stain_type+"_double-label_ROIoverlay.zip"); wait(100); roiManager("reset"); selectWindow(merged_image); run("Close"); run("__sub_PIPSQUEAK_measure_Double_Background_DL1and2_ROIs"); } if (choice=="No, accept double labeling as is.") { //well, aren't you confident. } } if (choice==second_stain_type) { setTool("rectangle"); roiManager("reset"); roiManager("Open", subDir+second_image+second_stain_type+"_double-label_ROIoverlay.zip"); waitForUser("How Does That Look?", "Here is your chance to adjust the double-labeling. Try moving, adding, or deleting ROIs. **THEN** press OK."); roiManager("deselect"); roiManager("Save", subDir+second_image+second_stain_type+"_double-label_ROIoverlay.zip"); wait(100); Dialog.create("Adjust the other stain?"); //again, second step, but after starting with the alternative stain. items = newArray("Yes", "No, accept double labeling as is."); Dialog.addRadioButtonGroup("Do you want to also adjust "+first_stain_type+" double-labeling?", items, 2, 1, "Yes"); Dialog.show; choice = Dialog.getRadioButton; if (choice=="Yes") { setTool("oval"); roiManager("reset"); roiManager("Open", subDir+first_image+first_stain_type+"_double-label_ROIoverlay.zip"); waitForUser("How Does That Look?", "Here is your chance to adjust the double-labeling. Try moving, adding, or deleting ROIs. **THEN** press OK."); roiManager("deselect"); roiManager("Save", subDir+first_image+first_stain_type+"_double-label_ROIoverlay.zip"); wait(100); roiManager("reset"); selectWindow(merged_image); run("Close"); run("__sub_PIPSQUEAK_measure_Double_Background_DL1and2_ROIs"); } if (choice=="No, accept double labeling as is.") { //well, aren't you confident. } } if (choice=="Accept double labeling as is.") { //well, aren't you confident. } } if (import_type==5){ selectWindow(merged_image); run("Close"); } roiManager("reset"); //\\\\\\\\\\\\\ //actually measuring the double labeled ROIs (image 1) run("Clear Results"); selectWindow(first_image_tif); roiManager("Open", subDir+first_image+first_stain_type+"_double-label_ROIoverlay.zip"); DL_ROIs=0; DL_ROIs =roiManager("count"); array=newArray(DL_ROIs); for(i=0; i