// Jan Wisniewski, Experimental Immunology Branch, NCI/NIH, Bethesda MD // This is macro uses tif or proprietary image formats // recognizes Z-stacks and and applies MaxIP or custom projection options // user can rename channels, specify display color, brightness range, cropping etc. // it automatically inserts scale bar // then images are saved as 16-bit tif, RGB color and RGB montage // scaling and other parameters are saved in the Log file print("Multichannel Image Display\nJan Wisniewski, Experimental Immunology Branch\nNational Cancer Institute, NIH, Bethesda, Maryland"); getDateAndTime(year, month, dayOfWeek, dayOfMonth, hour, minute, second, msec); print(""); print("run: ", month, "/", dayOfMonth, "/", year, " at ", hour, ":", minute); print(""); run("Set Measurements...", "area mean min bounding integrated median display redirect=None decimal=2"); //functions function maxStack() {rename("z"); run("Z Project...", "projection=[Max Intensity]"); close("z"); } function findCenter() {run("Duplicate...", "title=z duplicate"); run("Median...", "radius=1 stack"); run("Measure Stack..."); selectWindow("Results"); Table.sort("Max"); close("z"); } function getCenter() {rename("z"); setSlice(maxc); run("Duplicate...", " "); close("z"); } function getRange() {zup=slcs-maxc-sup; zlo=maxc-slo-1; rename("z1"); run("Stack to Images"); for (i = 0; i < zup; i++) {close(); } run("Images to Stack", "name=z2 title=[] use"); run("Reverse"); run("Stack to Images"); for (j = 0; j < zlo; j++) {close(); } run("Images to Stack", "name=zz title=[] use"); } function getManual() {mup=slcs-zz-rng; mlo=zz-1; run("Stack to Images"); for (i = 0; i < mup; i++) {close(); } run("Images to Stack", "name=Stack title=[] use"); run("Reverse"); run("Stack to Images"); for (j = 0; j < mlo; j++) {close(); } run("Images to Stack", "name=zz title=[] use"); } function autodic() {run("Bandpass Filter...", "filter_large=10 filter_small=3 suppress=None tolerance=5"); run("Enhance Contrast", "saturated=0.35"); run("Gamma...", "value=0.99"); } // specify folders Dialog.create("Output and Input Folders"); itv=newArray("No stacks", "Only stacks", "Mix"); Dialog.addRadioButtonGroup("Are Z-stacks present in the source folder?", itv, 1, 3, "Mix"); Dialog.addCheckbox("Crop images", false); itx=newArray("RGB montage", "16-bit Tiff + RGB montage"); Dialog.addRadioButtonGroup("Save Processed Image as:", itx, 2, 1, "RGB montage"); items=newArray("Max Intensity Projection", "Brightest slice only", "A subset of slices around the brightest slice", "Manually-selected subset only"); Dialog.addRadioButtonGroup("Projection method for Z-stacks (if present)", items, 4, 1, "Max Intensity Projection"); Dialog.show(); stks=Dialog.getRadioButton(); crp=Dialog.getCheckbox(); tif16=Dialog.getRadioButton(); stp=Dialog.getRadioButton(); if(stks=="No stacks") {mix=0; } else {mix=1; } print("General settings: Z-Stacks=", mix, " Image cropping+=", crp, " Saved output=", tif16, " Z-stack projection=", stp); res=getDirectory("Choose a Directory to store Results"); myDir1 = res+year+"-"+month+"-"+dayOfMonth+" "+hour+"_"+minute+" Montage"+File.separator; File.makeDirectory(myDir1); myDir3 = res+year+"-"+month+"-"+dayOfMonth+" "+hour+"_"+minute+" RGB sets"+File.separator; File.makeDirectory(myDir3); if(tif16=="16-bit Tiff + RGB montage") {myDir2 = res+year+"-"+month+"-"+dayOfMonth+" "+hour+"_"+minute+" 16-bit tiff"+File.separator; File.makeDirectory(myDir2); } input=getDirectory("Select a Source Directory"); NAMES=getFileList(input); //get parameters //create custom table title1 = "Parameters"; title2 = "["+title1+"]"; f=title2; run("New... ", "name="+title2+" type=Table"); print(f,"\\Headings:Label\tChannel\tLUT\tMin\tMax\tExclusion\tFFT"); //open sample image if(mix==0) {waitForUser("Open sample images"); } else {waitForUser("Open a Z-stack"); } run("Bio-Formats (Windowless)"); sttl=File.nameWithoutExtension; getDimensions(width, height, channels, slices, frames); chns=channels; slcs=slices; print("Setup image:", sttl, " size=", width, "x", height, " channels=", chns, " slices=", slcs, " frames=", frames); if(chns==1) {rename("C1-x"); master="C1-x"; } else {rename("x"); run("Split Channels"); //run("Tile"); waitForUser("Select master channel for setup"); master=getTitle(); } print("master channel=", master); //set up projection if(slcs>1) {if(stp=="Max Intensity Projection") { } else {findCenter(); maxc=getResult("Slice"); close("Results"); if(stp=="A subset of slices around the brightest slice") {setSlice(maxc); waitForUser("Inspect stack to decide how many slices to include on each side of the brightest one"); Dialog.create("Specify subset"); Dialog.addMessage("Same number of slices will be used for all images\nbut substack position will depend on the brightest slice in a given stack !"); Dialog.addMessage("(Enter negative number if you want to move start past the brightest slice)"); Dialog.addNumber("How many slices do you want to include before center slice:", 0); Dialog.addNumber("How many slices do you want to include after center slice:", 0); Dialog.show(); slo=Dialog.getNumber(); sup=Dialog.getNumber(); print("substack range=", sup+slo); } if(stp=="Manually-selected subset only") {setSlice(maxc); waitForUser("Inspect stack to decide how many slices to include"); Dialog.create("Specify subset"); Dialog.addNumber("How many slices do you want to include:", 0); Dialog.addMessage("(Same number of slices will be used for all images,\nthough you would need to specify start slice in eachcase)"); Dialog.show(); rng=Dialog.getNumber(); print("manual substack range=", rng); } } for (i = 0; i < chns; i++) {j=i+1; selectWindow("C"+j+"-x"); wtl=File.nameWithoutExtension; if(slcs>1) {if(stp=="Max Intensity Projection") {maxStack(); } if(stp=="Brightest slice only") {getCenter(); } if(stp=="A subset of slices around the brightest slice") {getRange(); } if(stp=="Manually-selected subset only") {if(i==0) {waitForUser("Select the first slide to include in a substack\n(any channel will work at this step)"); zz=getSliceNumber(); } getManual(); } } rename("C"+j+"-x"); } if(stp=="A subset of slices around the brightest slice") {for (i = 0; i < chns; i++) {j=i+1; selectWindow("C"+j+"-x"); rename("z"); run("Z Project...", "projection=[Max Intensity]"); close("z"); rename("C"+j+"-x"); } } if(stp=="Manually-selected subset only") {for (i = 0; i < chns; i++) {j=i+1; selectWindow("C"+j+"-x"); rename("z"); run("Z Project...", "projection=[Max Intensity]"); close("z"); rename("C"+j+"-x"); } } } if(crp==1) {selectWindow(master); setTool("rectangle"); waitForUser("Select crop area"); run("Select None"); for (i = 0; i < chns; i++) {j=i+1; selectWindow("C"+j+"-x"); run("Restore Selection"); run("Crop"); } } //channel setup for (i = 0; i < chns; i++) {j=i+1; selectWindow("C"+j+"-x"); Dialog.create(" "); Dialog.addString("Enter Dye and/or Target ID", " "); items = newArray("Grays", "Blue", "Cyan", "Green", "Yellow", "Red", "Magenta"); Dialog.addRadioButtonGroup("Display This Channel as:", items, 1, 7, "Grays"); itemz=newArray("N/A", "Exclude This Channel From Color Composite (It will be still shown separately)", "Include This Channel in Color Composite but do not show separately"); Dialog.addChoice("Channel exclusion?", itemz) Dialog.addCheckbox("Highlight Cell Details in Tramsmitted / DIC Image", false); Dialog.addCheckbox("Use same brightness/contrast scaling for all images in this folder (so they can be compared visually)", true) Dialog.show(); chNm=Dialog.getString(); chCo=Dialog.getRadioButton(); chEx=Dialog.getChoice(); chTr=Dialog.getCheckbox(); chBC=Dialog.getCheckbox(); if(chBC==1) {run("Brightness/Contrast..."); waitForUser("Adjust Brightness/Contrast Using B&C Tool Before Proceeding !"); getMinAndMax(min, max); vmin=min; vmax=max; } else {vmin=-1; vmax="auto"; } print("Channel=", "C"+j+"-x", chNm, chCo, " Exclusion=", chEx, " FFT=", chTr, " Fixed brightness/contrast scaling=", chBC); selectWindow("Parameters"); print(f,chNm+"\t"+j+"\t"+chCo+"\t"+vmin+"\t"+vmax+"\t"+chEx+"\t"+chTr); close("C"+j+"-x"); } selectWindow("Parameters"); saveAs("Text", res+"Results.csv"); close("Parameters"); //process images //separate and adjust channels for (k = 0; k < NAMES.length; k++) {open(input+NAMES[k]); ttl=File.nameWithoutExtension; getDimensions(width, height, channels, slices, frames); slcs=slices; print(" "); print(ttl, " slices=", slcs); if(chns==1) {rename("C1-x"); } else {rename("x"); run("Split Channels"); run("Tile"); } if(slcs>1) {if(stp=="Max Intensity Projection") { } else {selectWindow(master); findCenter(); maxc=getResult("Slice"); close("Results"); if(stp=="Manually-selected subset only") {waitForUser("Select the first slide to include in a substack\n(range is already specified!)"); zz=getSliceNumber(); } } if(stp=="Max Intensity Projection") {print(stp); } if(stp=="Brightest slice only") {print(stp, " slice=", maxc); } if(stp=="A subset of slices around the brightest slice") {print(stp, " slices=", maxc-slo, "-", maxc+sup); } if(stp=="Manually-selected subset only") {print(stp, " slices=", zz, "-", zz+rng); } //project stacks for (i = 0; i < chns; i++) {j=i+1; selectWindow("C"+j+"-x"); if(stp=="Max Intensity Projection") {maxStack(); } if(stp=="Brightest slice only") {getCenter(); } if(stp=="A subset of slices around the brightest slice") {getRange(); } if(stp=="Manually-selected subset only") {getManual(); } rename("C"+j+"-x"); } if(stp=="A subset of slices around the brightest slice") {for (i = 0; i < chns; i++) {j=i+1; selectWindow("C"+j+"-x"); rename("z"); run("Z Project...", "projection=[Max Intensity]"); close("z"); rename("C"+j+"-x"); } } if(stp=="Manually-selected subset only") {for (i = 0; i < chns; i++) {j=i+1; selectWindow("C"+j+"-x"); rename("z"); run("Z Project...", "projection=[Max Intensity]"); close("z"); rename("C"+j+"-x"); } } } if(crp==1) {selectWindow(master); run("Restore Selection"); waitForUser("Adjust size/position of crop box"); run("Duplicate...", "title=y"); getDimensions(width, height, channels, slices, frames); print("cropped size=", width, "x", height); close("y"); run("Select None"); for (i = 0; i < chns; i++) {j=i+1; selectWindow("C"+j+"-x"); run("Restore Selection"); run("Crop"); } } open(res+"Results.csv"); for (i = 0; i < chns; i++) {j=i+1; CC=getResultString("LUT", i); vmin=getResult("Min", i); vmax=getResult("Max", i); CFFT=getResultString("FFT", i); selectWindow("C"+j+"-x"); run(CC); if(CFFT==1) {autodic(); } else {if(vmin==-1) {scBC="auto"; run("Enhance Contrast", "saturated=0.10"); getMinAndMax(min, max); vmin=min; vmax=max; } else {scBC="fixed"; setMinAndMax(vmin, vmax); } } print("C"+j+"-x", CC, scBC, vmin, "-", vmax); } if(tif16=="16-bit Tiff + RGB montage") {if(chns==1) { } if(chns==2) {run("Merge Channels...", "c1=C1-x c2=C2-x create keep"); } if(chns==3) {run("Merge Channels...", "c1=C1-x c2=C2-x c3=C3-x create keep"); } if(chns==4) {run("Merge Channels...", "c1=C1-x c2=C2-x c3=C3-x c4=C4-x create keep"); } if(chns==5) {run("Merge Channels...", "c1=C1-x c2=C2-x c3=C3-x c4=C4-x c5=C5-x create keep"); } if(chns==6) {run("Merge Channels...", "c1=C1-x c2=C2-x c3=C3-x c4=C4-x c5=C5-x c6=C6-x create keep"); } if(chns==7) {run("Merge Channels...", "c1=C1-x c2=C2-x c3=C3-x c4=C4-x c5=C5-x c6=C6-x C7-x create keep"); } saveAs("Tif", myDir2+ttl); close(); } excl=0; incl=0; for (i = 0; i < chns; i++) {j=i+1; CN=getResultString("Label", i); CEx=getResultString("Exclusion", i); selectWindow("C"+j+"-x"); run("Apply LUT"); run("RGB Color"); if(CEx=="N/A") {rename(CN); } else {if(CEx=="Exclude This Channel From Color Composite (It will be still shown separately)") {rename("excluded"); TMP1=CN; excl=1; } if(CEx=="Include This Channel in Color Composite but do not show separately") {rename("included"); TMP1=CN; incl=1; } } } close("Results"); if(chns==1) {saveAs("Tif", myDir1+ttl); close();} if(chns>1) { if(chns==2) {run("Images to Stack", "name=All title=[] use keep"); run("Images to Stack", "name=Stack title=[] use"); } if(chns>2) {run("Images to Stack", "name=All title=[] use keep"); if(excl==1) {close("excluded"); } run("Images to Stack", "name=Stack title=[] use"); if(incl==1) {selectWindow("All"); run("Stack to Images"); close("included"); run("Images to Stack", "name=All title=[] use"); selectWindow"Stack"); } } run("Z Project...", "projection=[Sum Slices]"); rename(ttl); close("Stack"); selectWindow("All"); run("Stack to Images"); run("Images to Stack", "name=ttl title=[] use"); saveAs("Tif", myDir3+ttl); close(); } } ok = File.delete(res+"Results.csv"); selectWindow("Log"); saveAs("Text", res+year+"-"+month+"-"+dayOfMonth+" "+hour+"_"+minute+" Log"+".txt"); close("Log"); LIST=getFileList(myDir3); for (h = 0; h < LIST.length; h++) {open(myDir3+LIST[0]); getDimensions(width, height, channels, slices, frames); imgwdt=width; ratio=height/width; pnls=slices; close(); } for (h = 0; h < LIST.length; h++) {open(myDir3+LIST[h]); ttz=File.nameWithoutExtension; if(ratio>0.6) {if(imgwdt<600) { if(pnls==2) {run("Reverse"); run("Make Montage...", "columns=2 rows=1 scale=1 border=1 font=25 label"); } if(pnls==3) {run("Make Montage...", "columns=3 rows=1 scale=1 border=1 font=25 label"); } if(pnls==4) {run("Make Montage...", "columns=2 rows=2 scale=1 border=1 font=25 label"); } if(pnls==5) {run("Make Montage...", "columns=3 rows=2 scale=1 border=1 font=25 label"); } if(pnls==6) {run("Make Montage...", "columns=3 rows=2 scale=1 border=1 font=25 label"); } if(pnls==7) {run("Make Montage...", "columns=4 rows=2 scale=1 border=1 font=25 label"); } if(pnls==8) {run("Make Montage...", "columns=4 rows=2 scale=1 border=1 font=25 label"); } run("Scale Bar...", "width=10 height=4 font=15 color=White background=None location=[Upper Right] bold"); } else {if(imgwdt<1200) { if(pnls==2) {run("Reverse"); run("Make Montage...", "columns=2 rows=1 scale=1 border=2 font=35 label"); } if(pnls==3) {run("Make Montage...", "columns=3 rows=1 scale=1 border=2 font=35 label"); } if(pnls==4) {run("Make Montage...", "columns=2 rows=2 scale=1 border=2 font=35 label"); } if(pnls==5) {run("Make Montage...", "columns=3 rows=2 scale=1 border=2 font=35 label"); } if(pnls==6) {run("Make Montage...", "columns=3 rows=2 scale=1 border=2 font=35 label"); } if(pnls==7) {run("Make Montage...", "columns=4 rows=2 scale=1 border=2 font=35 label"); } if(pnls==8) {run("Make Montage...", "columns=4 rows=2 scale=1 border=2 font=35 label"); } run("Scale Bar...", "width=25 height=4 font=20 color=White background=None location=[Upper Right] bold"); } else { if(pnls==2) {run("Reverse"); run("Make Montage...", "columns=2 rows=1 scale=0.5 border=2 font=50 label"); } if(pnls==3) {run("Make Montage...", "columns=3 rows=1 scale=0.5 border=2 font=50 label"); } if(pnls==4) {run("Make Montage...", "columns=2 rows=2 scale=0.5 border=2 font=50 label"); } if(pnls==5) {run("Make Montage...", "columns=3 rows=2 scale=0.5 border=2 font=50 label"); } if(pnls==6) {run("Make Montage...", "columns=3 rows=2 scale=0.5 border=2 font=50 label"); } if(pnls==7) {run("Make Montage...", "columns=4 rows=2 scale=0.5 border=2 font=50 label"); } if(pnls==8) {run("Make Montage...", "columns=4 rows=2 scale=0.5 border=2 font=50 label"); } run("Scale Bar...", "width=50 height=4 font=35 color=White background=None location=[Upper Right] bold"); } } } else {if(imgwdt<600) { if(pnls==2) {run("Reverse"); run("Make Montage...", "columns=1 rows=2 scale=1 border=1 font=25 label"); } if(pnls==3) {run("Make Montage...", "columns=1 rows=3 scale=1 border=1 font=25 label"); } if(pnls==4) {run("Make Montage...", "columns=2 rows=2 scale=1 border=1 font=25 label"); } if(pnls==5) {run("Make Montage...", "columns=2 rows=3 scale=1 border=1 font=25 label"); } if(pnls==6) {run("Make Montage...", "columns=2 rows=3 scale=1 border=1 font=25 label"); } if(pnls==7) {run("Make Montage...", "columns=2 rows=4 scale=1 border=1 font=25 label"); } if(pnls==8) {run("Make Montage...", "columns=2 rows=4 scale=1 border=1 font=25 label"); } run("Scale Bar...", "width=10 height=4 font=15 color=White background=None location=[Upper Right] bold"); } else {if(imgwdt<1200) { if(pnls==2) {run("Reverse"); run("Make Montage...", "columns=1 rows=2 scale=1 border=2 font=35 label"); } if(pnls==3) {run("Make Montage...", "columns=1 rows=3 scale=1 border=2 font=35 label"); } if(pnls==4) {run("Make Montage...", "columns=2 rows=2 scale=1 border=2 font=35 label"); } if(pnls==5) {run("Make Montage...", "columns=2 rows=3 scale=1 border=2 font=35 label"); } if(pnls==6) {run("Make Montage...", "columns=2 rows=3 scale=1 border=2 font=35 label"); } if(pnls==7) {run("Make Montage...", "columns=2 rows=4 scale=1 border=2 font=35 label"); } if(pnls==8) {run("Make Montage...", "columns=2 rows=4 scale=1 border=2 font=35 label"); } run("Scale Bar...", "width=25 height=4 font=20 color=White background=None location=[Upper Right] bold"); } else { if(pnls==2) {run("Reverse"); run("Make Montage...", "columns=1 rows=2 scale=0.5 border=2 font=50 label"); } if(pnls==3) {run("Make Montage...", "columns=1 rows=3 scale=0.5 border=2 font=50 label"); } if(pnls==4) {run("Make Montage...", "columns=2 rows=2 scale=0.5 border=2 font=50 label"); } if(pnls==5) {run("Make Montage...", "columns=2 rows=3 scale=0.5 border=2 font=50 label"); } if(pnls==6) {run("Make Montage...", "columns=2 rows=3 scale=0.5 border=2 font=50 label"); } if(pnls==7) {run("Make Montage...", "columns=2 rows=4 scale=0.5 border=2 font=50 label"); } if(pnls==8) {run("Make Montage...", "columns=2 rows=4 scale=0.5 border=2 font=50 label"); } run("Scale Bar...", "width=50 height=4 font=35 color=White background=None location=[Upper Right] bold"); } } } saveAs("Tiff", myDir1+ttz); close(); close(); }